🤖 Auto commit for release 'develop' on 2025-09-07

This commit is contained in:
JC5
2025-09-07 07:56:10 +02:00
parent 602df95f3c
commit 262f1bae34
93 changed files with 804 additions and 767 deletions

View File

@@ -402,16 +402,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.86.0", "version": "v3.87.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "4a952bd19dc97879b0620f495552ef09b55f7d36" "reference": "2f5170365e2a422d0c5421f9c8818b2c078105f6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/4a952bd19dc97879b0620f495552ef09b55f7d36", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2f5170365e2a422d0c5421f9c8818b2c078105f6",
"reference": "4a952bd19dc97879b0620f495552ef09b55f7d36", "reference": "2f5170365e2a422d0c5421f9c8818b2c078105f6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -422,39 +422,38 @@
"ext-hash": "*", "ext-hash": "*",
"ext-json": "*", "ext-json": "*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"fidry/cpu-core-counter": "^1.2", "fidry/cpu-core-counter": "^1.3",
"php": "^7.4 || ^8.0", "php": "^7.4 || ^8.0",
"react/child-process": "^0.6.6", "react/child-process": "^0.6.6",
"react/event-loop": "^1.5", "react/event-loop": "^1.5",
"react/promise": "^3.2", "react/promise": "^3.3",
"react/socket": "^1.16", "react/socket": "^1.16",
"react/stream": "^1.4", "react/stream": "^1.4",
"sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
"symfony/console": "^5.4.47 || ^6.4.13 || ^7.0", "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0",
"symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0",
"symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0",
"symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0",
"symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0",
"symfony/polyfill-mbstring": "^1.32", "symfony/polyfill-mbstring": "^1.33",
"symfony/polyfill-php80": "^1.32", "symfony/polyfill-php80": "^1.33",
"symfony/polyfill-php81": "^1.32", "symfony/polyfill-php81": "^1.33",
"symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2",
"symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0"
}, },
"require-dev": { "require-dev": {
"facile-it/paraunit": "^1.3.1 || ^2.6", "facile-it/paraunit": "^1.3.1 || ^2.7",
"infection/infection": "^0.29.14", "infection/infection": "^0.29.14",
"justinrainbow/json-schema": "^5.3 || ^6.4", "justinrainbow/json-schema": "^6.5",
"keradus/cli-executor": "^2.2", "keradus/cli-executor": "^2.2",
"mikey179/vfsstream": "^1.6.12", "mikey179/vfsstream": "^1.6.12",
"php-coveralls/php-coveralls": "^2.8", "php-coveralls/php-coveralls": "^2.8",
"php-cs-fixer/accessible-object": "^1.1",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
"phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", "phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34",
"symfony/polyfill-php84": "^1.32", "symfony/polyfill-php84": "^1.33",
"symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", "symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2",
"symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" "symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2"
}, },
"suggest": { "suggest": {
"ext-dom": "For handling output formats in XML", "ext-dom": "For handling output formats in XML",
@@ -495,7 +494,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.86.0" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.87.1"
}, },
"funding": [ "funding": [
{ {
@@ -503,7 +502,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-08-13T22:36:21+00:00" "time": "2025-09-02T15:27:36+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",

View File

@@ -200,18 +200,18 @@ class BudgetController extends Controller
return $return; return $return;
} }
// /** // /**
// * When no budget limits are present, the expenses of the whole period are collected and grouped. // * When no budget limits are present, the expenses of the whole period are collected and grouped.
// * This is grouped per currency. Because there is no limit set, "left to spend" and "overspent" are empty. // * This is grouped per currency. Because there is no limit set, "left to spend" and "overspent" are empty.
// * // *
// * @throws FireflyException // * @throws FireflyException
// */ // */
// private function noBudgetLimits(Budget $budget, Carbon $start, Carbon $end): array // private function noBudgetLimits(Budget $budget, Carbon $start, Carbon $end): array
// { // {
// $spent = $this->opsRepository->listExpenses($start, $end, null, new Collection([$budget])); // $spent = $this->opsRepository->listExpenses($start, $end, null, new Collection([$budget]));
// //
// return $this->processExpenses($budget->id, $spent, $start, $end); // return $this->processExpenses($budget->id, $spent, $start, $end);
// } // }
/** /**
* Shared between the "noBudgetLimits" function and "processLimit". Will take a single set of expenses and return * Shared between the "noBudgetLimits" function and "processLimit". Will take a single set of expenses and return
@@ -257,59 +257,59 @@ class BudgetController extends Controller
return $return; return $return;
} }
// /** // /**
// * Function that processes each budget limit (per budget). // * Function that processes each budget limit (per budget).
// * // *
// * If you have a budget limit in EUR, only transactions in EUR will be considered. // * If you have a budget limit in EUR, only transactions in EUR will be considered.
// * If you have a budget limit in GBP, only transactions in GBP will be considered. // * If you have a budget limit in GBP, only transactions in GBP will be considered.
// * // *
// * If you have a budget limit in EUR, and a transaction in GBP, it will not be considered for the EUR budget limit. // * If you have a budget limit in EUR, and a transaction in GBP, it will not be considered for the EUR budget limit.
// * // *
// * @throws FireflyException // * @throws FireflyException
// */ // */
// private function budgetLimits(Budget $budget, Collection $limits): array // private function budgetLimits(Budget $budget, Collection $limits): array
// { // {
// Log::debug(sprintf('Now in budgetLimits(#%d)', $budget->id)); // Log::debug(sprintf('Now in budgetLimits(#%d)', $budget->id));
// $data = []; // $data = [];
// //
// /** @var BudgetLimit $limit */ // /** @var BudgetLimit $limit */
// foreach ($limits as $limit) { // foreach ($limits as $limit) {
// $data = array_merge($data, $this->processLimit($budget, $limit)); // $data = array_merge($data, $this->processLimit($budget, $limit));
// } // }
// //
// return $data; // return $data;
// } // }
// /** // /**
// * @throws FireflyException // * @throws FireflyException
// */ // */
// private function processLimit(Budget $budget, BudgetLimit $limit): array // private function processLimit(Budget $budget, BudgetLimit $limit): array
// { // {
// Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__)); // Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
// $end = clone $limit->end_date; // $end = clone $limit->end_date;
// $end->endOfDay(); // $end->endOfDay();
// $spent = $this->opsRepository->listExpenses($limit->start_date, $end, null, new Collection([$budget])); // $spent = $this->opsRepository->listExpenses($limit->start_date, $end, null, new Collection([$budget]));
// $limitCurrencyId = $limit->transaction_currency_id; // $limitCurrencyId = $limit->transaction_currency_id;
// //
// /** @var array $entry */ // /** @var array $entry */
// // only spent the entry where the entry's currency matches the budget limit's currency // // only spent the entry where the entry's currency matches the budget limit's currency
// // so $filtered will only have 1 or 0 entries // // so $filtered will only have 1 or 0 entries
// $filtered = array_filter($spent, fn ($entry) => $entry['currency_id'] === $limitCurrencyId); // $filtered = array_filter($spent, fn ($entry) => $entry['currency_id'] === $limitCurrencyId);
// $result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end); // $result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end);
// if (1 === count($result)) { // if (1 === count($result)) {
// $compare = bccomp($limit->amount, (string)app('steam')->positive($result[$limitCurrencyId]['spent'])); // $compare = bccomp($limit->amount, (string)app('steam')->positive($result[$limitCurrencyId]['spent']));
// $result[$limitCurrencyId]['budgeted'] = $limit->amount; // $result[$limitCurrencyId]['budgeted'] = $limit->amount;
// if (1 === $compare) { // if (1 === $compare) {
// // convert this amount into the primary currency: // // convert this amount into the primary currency:
// $result[$limitCurrencyId]['left'] = bcadd($limit->amount, (string)$result[$limitCurrencyId]['spent']); // $result[$limitCurrencyId]['left'] = bcadd($limit->amount, (string)$result[$limitCurrencyId]['spent']);
// } // }
// if ($compare <= 0) { // if ($compare <= 0) {
// $result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, (string)$result[$limitCurrencyId]['spent'])); // $result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, (string)$result[$limitCurrencyId]['spent']));
// } // }
// } // }
// //
// return $result; // return $result;
// } // }
private function filterLimit(int $currencyId, Collection $limits): ?BudgetLimit private function filterLimit(int $currencyId, Collection $limits): ?BudgetLimit
{ {

View File

@@ -147,7 +147,7 @@ abstract class Controller extends BaseController
} }
if (null !== $value) { if (null !== $value) {
$value = (int)$value; $value = (int)$value;
$value = min(max(1, $value), 2 ** 16); $value = min(max(1, $value), 2 ** 16);
$bag->set($integer, $value); $bag->set($integer, $value);
} }
if (null === $value if (null === $value
@@ -165,7 +165,7 @@ abstract class Controller extends BaseController
// sort fields: // sort fields:
return $bag; return $bag;
//return $this->getSortParameters($bag); // return $this->getSortParameters($bag);
} }
/** /**

View File

@@ -36,7 +36,7 @@ use Illuminate\Http\JsonResponse;
/** /**
* Class TagController * Class TagController
*/ */
class TagController extends Controller class TagController extends Controller
{ {
private TagRepositoryInterface $repository; private TagRepositoryInterface $repository;

View File

@@ -114,8 +114,8 @@ class ShowController extends Controller
public function show(AvailableBudget $availableBudget): JsonResponse public function show(AvailableBudget $availableBudget): JsonResponse
{ {
$manager = $this->getManager(); $manager = $this->getManager();
// $start = $this->parameters->get('start'); // $start = $this->parameters->get('start');
// $end = $this->parameters->get('end'); // $end = $this->parameters->get('end');
/** @var AvailableBudgetTransformer $transformer */ /** @var AvailableBudgetTransformer $transformer */
$transformer = app(AvailableBudgetTransformer::class); $transformer = app(AvailableBudgetTransformer::class);
@@ -126,8 +126,8 @@ class ShowController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new AvailableBudgetEnrichment(); $enrichment = new AvailableBudgetEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
// $enrichment->setStart($start); // $enrichment->setStart($start);
// $enrichment->setEnd($end); // $enrichment->setEnd($end);
$availableBudget = $enrichment->enrichSingle($availableBudget); $availableBudget = $enrichment->enrichSingle($availableBudget);

View File

@@ -84,6 +84,7 @@ class ShowController extends Controller
$enrichment->setUser($admin); $enrichment->setUser($admin);
$enrichment->setStart($this->parameters->get('start')); $enrichment->setStart($this->parameters->get('start'));
$enrichment->setEnd($this->parameters->get('end')); $enrichment->setEnd($this->parameters->get('end'));
/** @var Budget $budget */ /** @var Budget $budget */
$budget = $enrichment->enrichSingle($budget); $budget = $enrichment->enrichSingle($budget);

View File

@@ -30,9 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Recurrence; use FireflyIII\Models\Recurrence;
use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\Rule; use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;

View File

@@ -156,7 +156,7 @@ class ConfigurationController extends Controller
} }
// fallback // fallback
$data = [ $data = [
'title' => $configKey, 'title' => $configKey,
'value' => config($shortKey), 'value' => config($shortKey),
'editable' => false, 'editable' => false,
@@ -176,7 +176,7 @@ class ConfigurationController extends Controller
*/ */
public function update(UpdateRequest $request, string $name): JsonResponse public function update(UpdateRequest $request, string $name): JsonResponse
{ {
$rules = ['value' => 'required']; $rules = ['value' => 'required'];
if (!$this->repository->hasRole(auth()->user(), 'owner')) { if (!$this->repository->hasRole(auth()->user(), 'owner')) {
$messages = ['value' => '200005: You need the "owner" role to do this.']; $messages = ['value' => '200005: You need the "owner" role to do this.'];
Validator::make([], $rules, $messages)->validate(); Validator::make([], $rules, $messages)->validate();

View File

@@ -77,6 +77,7 @@ class UpdateController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new WebhookEnrichment(); $enrichment = new WebhookEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
/** @var Webhook $webhook */ /** @var Webhook $webhook */
$webhook = $enrichment->enrichSingle($webhook); $webhook = $enrichment->enrichSingle($webhook);

View File

@@ -25,7 +25,6 @@ namespace FireflyIII\Api\V1\Requests\Models\Account;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Preference;
use FireflyIII\Rules\IsValidSortInstruction; use FireflyIII\Rules\IsValidSortInstruction;
use FireflyIII\Support\Facades\Preferences; use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
@@ -55,7 +54,7 @@ class ShowRequest extends FormRequest
return [ return [
'type' => $this->convertString('type', 'all'), 'type' => $this->convertString('type', 'all'),
'limit' => $limit, 'limit' => $limit,
'sort' => $this->convertSortParameters('sort',Account::class), 'sort' => $this->convertSortParameters('sort', Account::class),
'page' => $page, 'page' => $page,
]; ];
} }

View File

@@ -302,10 +302,10 @@ class CorrectsUnevenAmount extends Command
private function isBetweenAssetAndLiability(TransactionJournal $journal): bool private function isBetweenAssetAndLiability(TransactionJournal $journal): bool
{ {
/** @var Transaction|null $sourceTransaction */ /** @var null|Transaction $sourceTransaction */
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first(); $sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
/** @var Transaction|null $destinationTransaction */ /** @var null|Transaction $destinationTransaction */
$destinationTransaction = $journal->transactions()->where('amount', '>', 0)->first(); $destinationTransaction = $journal->transactions()->where('amount', '>', 0)->first();
if (null === $sourceTransaction || null === $destinationTransaction) { if (null === $sourceTransaction || null === $destinationTransaction) {
Log::warning('Either transaction is false, stop.'); Log::warning('Either transaction is false, stop.');

View File

@@ -60,6 +60,7 @@ class RecalculatesRunningBalance extends Command
return 0; return 0;
} }
$this->friendlyWarning('This command has been disabled.'); $this->friendlyWarning('This command has been disabled.');
return 0; return 0;
} }

View File

@@ -25,12 +25,13 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\System; namespace FireflyIII\Console\Commands\System;
use function Safe\file_put_contents;
use function Safe\json_encode;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Symfony\Component\Console\Command\Command as CommandAlias; use Symfony\Component\Console\Command\Command as CommandAlias;
use function Safe\file_put_contents;
use function Safe\json_encode;
class ResetsErrorMailLimit extends Command class ResetsErrorMailLimit extends Command
{ {
use ShowsFriendlyMessages; use ShowsFriendlyMessages;

View File

@@ -37,7 +37,7 @@ class ActuallyLoggedIn extends Event
public User $user; public User $user;
public function __construct(null|Authenticatable|User $user) public function __construct(Authenticatable|User|null $user)
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -35,7 +35,7 @@ class DisabledMFA extends Event
public User $user; public User $user;
public function __construct(null|Authenticatable|User $user) public function __construct(Authenticatable|User|null $user)
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -35,7 +35,7 @@ class EnabledMFA extends Event
public User $user; public User $user;
public function __construct(null|Authenticatable|User $user) public function __construct(Authenticatable|User|null $user)
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -35,7 +35,7 @@ class MFABackupFewLeft extends Event
public User $user; public User $user;
public function __construct(null|Authenticatable|User $user, public int $count) public function __construct(Authenticatable|User|null $user, public int $count)
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -35,7 +35,7 @@ class MFABackupNoLeft extends Event
public User $user; public User $user;
public function __construct(null|Authenticatable|User $user) public function __construct(Authenticatable|User|null $user)
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -35,7 +35,7 @@ class MFAManyFailedAttempts extends Event
public User $user; public User $user;
public function __construct(null|Authenticatable|User $user, public int $count) public function __construct(Authenticatable|User|null $user, public int $count)
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -35,7 +35,7 @@ class MFANewBackupCodes extends Event
public User $user; public User $user;
public function __construct(null|Authenticatable|User $user) public function __construct(Authenticatable|User|null $user)
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -35,7 +35,7 @@ class MFAUsedBackupCode extends Event
public User $user; public User $user;
public function __construct(null|Authenticatable|User $user) public function __construct(Authenticatable|User|null $user)
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -35,7 +35,7 @@ class UserAttemptedLogin extends Event
public User $user; public User $user;
public function __construct(null|Authenticatable|User $user) public function __construct(Authenticatable|User|null $user)
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -184,6 +184,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface
if ($model instanceof Budget) { if ($model instanceof Budget) {
$enrichment = new BudgetEnrichment(); $enrichment = new BudgetEnrichment();
$enrichment->setUser($model->user); $enrichment->setUser($model->user);
/** @var Budget $model */ /** @var Budget $model */
$model = $enrichment->enrichSingle($model); $model = $enrichment->enrichSingle($model);
$transformer = new BudgetTransformer(); $transformer = new BudgetTransformer();
@@ -197,6 +198,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface
$parameters = new ParameterBag(); $parameters = new ParameterBag();
$parameters->set('start', $model->start_date); $parameters->set('start', $model->start_date);
$parameters->set('end', $model->end_date); $parameters->set('end', $model->end_date);
/** @var BudgetLimit $model */ /** @var BudgetLimit $model */
$model = $enrichment->enrichSingle($model); $model = $enrichment->enrichSingle($model);
$transformer = new BudgetLimitTransformer(); $transformer = new BudgetLimitTransformer();

View File

@@ -140,10 +140,10 @@ class AdminEventHandler
break; break;
// case 'ntfy': // case 'ntfy':
// $class = OwnerTestNotificationNtfy::class; // $class = OwnerTestNotificationNtfy::class;
// //
// break; // break;
case 'pushover': case 'pushover':
$class = OwnerTestNotificationPushover::class; $class = OwnerTestNotificationPushover::class;

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Events; namespace FireflyIII\Handlers\Events;
use function Safe\json_encode;
use Exception; use Exception;
use FireflyIII\Events\Model\Bill\WarnUserAboutBill; use FireflyIII\Events\Model\Bill\WarnUserAboutBill;
use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscriptions; use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscriptions;
@@ -35,6 +34,8 @@ use FireflyIII\Support\Facades\Preferences;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification; use Illuminate\Support\Facades\Notification;
use function Safe\json_encode;
/** /**
* Class BillEventHandler * Class BillEventHandler
*/ */

View File

@@ -411,10 +411,10 @@ class UserEventHandler
break; break;
// case 'ntfy': // case 'ntfy':
// $class = UserTestNotificationNtfy::class; // $class = UserTestNotificationNtfy::class;
// //
// break; // break;
case 'pushover': case 'pushover':
$class = UserTestNotificationPushover::class; $class = UserTestNotificationPushover::class;

View File

@@ -128,6 +128,7 @@ class AttachmentHelper implements AttachmentHelperInterface
public function saveAttachmentFromApi(Attachment $attachment, string $content): bool public function saveAttachmentFromApi(Attachment $attachment, string $content): bool
{ {
Log::debug(sprintf('Now in %s', __METHOD__)); Log::debug(sprintf('Now in %s', __METHOD__));
try { try {
$resource = tmpfile(); $resource = tmpfile();
} catch (FilesystemException $e) { } catch (FilesystemException $e) {
@@ -144,6 +145,7 @@ class AttachmentHelper implements AttachmentHelperInterface
$path = stream_get_meta_data($resource)['uri']; $path = stream_get_meta_data($resource)['uri'];
Log::debug(sprintf('Path is %s', $path)); Log::debug(sprintf('Path is %s', $path));
try { try {
$result = fwrite($resource, $content); $result = fwrite($resource, $content);
} catch (FilesystemException $e) { } catch (FilesystemException $e) {
@@ -152,6 +154,7 @@ class AttachmentHelper implements AttachmentHelperInterface
return false; return false;
} }
Log::debug(sprintf('Wrote %d bytes to temp file.', $result)); Log::debug(sprintf('Wrote %d bytes to temp file.', $result));
try { try {
$finfo = finfo_open(FILEINFO_MIME_TYPE); $finfo = finfo_open(FILEINFO_MIME_TYPE);
} catch (FileinfoException $e) { } catch (FileinfoException $e) {
@@ -175,7 +178,7 @@ class AttachmentHelper implements AttachmentHelperInterface
$this->uploadDisk->put($file, $content); $this->uploadDisk->put($file, $content);
// update attachment. // update attachment.
$attachment->md5 = md5_file($path); $attachment->md5 = md5_file($path);
$attachment->mime = $mime; $attachment->mime = $mime;
$attachment->size = strlen($content); $attachment->size = strlen($content);
$attachment->uploaded = true; $attachment->uploaded = true;
@@ -237,7 +240,7 @@ class AttachmentHelper implements AttachmentHelperInterface
$attachment = new Attachment(); // create Attachment object. $attachment = new Attachment(); // create Attachment object.
$attachment->user()->associate($user); $attachment->user()->associate($user);
$attachment->attachable()->associate($model); $attachment->attachable()->associate($model);
$attachment->md5 = md5_file($file->getRealPath()); $attachment->md5 = md5_file($file->getRealPath());
$attachment->filename = $file->getClientOriginalName(); $attachment->filename = $file->getClientOriginalName();
$attachment->mime = $file->getMimeType(); $attachment->mime = $file->getMimeType();
$attachment->size = $file->getSize(); $attachment->size = $file->getSize();

View File

@@ -116,7 +116,7 @@ class NetWorth implements NetWorthInterface
return $netWorth; return $netWorth;
} }
public function setUser(null|Authenticatable|User $user): void public function setUser(Authenticatable|User|null $user): void
{ {
if (!$user instanceof User) { if (!$user instanceof User) {
return; return;

View File

@@ -46,7 +46,7 @@ interface NetWorthInterface
*/ */
public function byAccounts(Collection $accounts, Carbon $date): array; public function byAccounts(Collection $accounts, Carbon $date): array;
public function setUser(null|Authenticatable|User $user): void; public function setUser(Authenticatable|User|null $user): void;
public function setUserGroup(UserGroup $userGroup): void; public function setUserGroup(UserGroup $userGroup): void;

View File

@@ -70,7 +70,7 @@ class NotificationController extends Controller
} }
$forcedAvailability['ntfy'] = '' !== $ntfyTopic; $forcedAvailability['ntfy'] = '' !== $ntfyTopic;
$forcedAvailability['pushover'] = '' !== $pushoverAppToken && '' !== $pushoverUserToken; $forcedAvailability['pushover'] = '' !== $pushoverAppToken && '' !== $pushoverUserToken;
$forcedAvailability['slack'] = '' !== $slackUrl; $forcedAvailability['slack'] = '' !== $slackUrl;
return view( return view(
'settings.notifications.index', 'settings.notifications.index',

View File

@@ -33,8 +33,8 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\View\View; use Illuminate\View\View;
use Safe\Exceptions\UrlException; use Safe\Exceptions\UrlException;
use function Safe\parse_url; use function Safe\parse_url;
/** /**
@@ -107,12 +107,12 @@ class ForgotPasswordController extends Controller
try { try {
$configuredHost = parse_url((string)config('app.url'), PHP_URL_HOST); $configuredHost = parse_url((string)config('app.url'), PHP_URL_HOST);
} catch (UrlException $e) { } catch (UrlException $e) {
throw new FireflyException('Please set a valid and correct Firefly III URL in the APP_URL environment variable.',0, $e); throw new FireflyException('Please set a valid and correct Firefly III URL in the APP_URL environment variable.', 0, $e);
} }
if (!is_string( $configuredHost)) { if (!is_string($configuredHost)) {
throw new FireflyException('Please set a valid and correct Firefly III URL in the APP_URL environment variable.'); throw new FireflyException('Please set a valid and correct Firefly III URL in the APP_URL environment variable.');
} }
$host = request()->host(); $host = request()->host();
if ($configuredHost !== $host) { if ($configuredHost !== $host) {
Log::error(sprintf('Host header is "%s", APP_URL is "%s".', $host, $configuredHost)); Log::error(sprintf('Host header is "%s", APP_URL is "%s".', $host, $configuredHost));

View File

@@ -69,14 +69,14 @@ class CreateController extends Controller
*/ */
public function create(Request $request) public function create(Request $request)
{ {
$periods = []; $periods = [];
/** @var array $billPeriods */ /** @var array $billPeriods */
$billPeriods = config('firefly.bill_periods'); $billPeriods = config('firefly.bill_periods');
foreach ($billPeriods as $current) { foreach ($billPeriods as $current) {
$periods[$current] = (string) trans('firefly.repeat_freq_'.$current); $periods[$current] = (string) trans('firefly.repeat_freq_'.$current);
} }
$subTitle = (string) trans('firefly.create_new_bill'); $subTitle = (string) trans('firefly.create_new_bill');
// put previous url in session if not redirect from store (not "create another"). // put previous url in session if not redirect from store (not "create another").
if (true !== session('bills.create.fromStore')) { if (true !== session('bills.create.fromStore')) {

View File

@@ -117,7 +117,7 @@ class BudgetReportController extends Controller
]; ];
$amount = Steam::positive($journal['amount']); $amount = Steam::positive($journal['amount']);
$result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount);
} }
} }
} }
@@ -147,7 +147,7 @@ class BudgetReportController extends Controller
]; ];
$amount = Steam::positive($journal['amount']); $amount = Steam::positive($journal['amount']);
$result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount);
} }
} }
} }
@@ -235,7 +235,7 @@ class BudgetReportController extends Controller
]; ];
$amount = Steam::positive($journal['amount']); $amount = Steam::positive($journal['amount']);
$result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount);
} }
} }
} }

View File

@@ -95,8 +95,8 @@ abstract class Controller extends BaseController
View::share('logoutUrl', $logoutUrl); View::share('logoutUrl', $logoutUrl);
// upload size // upload size
$maxFileSize = Steam::phpBytes( ini_get('upload_max_filesize')); $maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = Steam::phpBytes( ini_get('post_max_size')); $maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
$uploadSize = min($maxFileSize, $maxPostSize); $uploadSize = min($maxFileSize, $maxPostSize);
View::share('uploadSize', $uploadSize); View::share('uploadSize', $uploadSize);

View File

@@ -175,8 +175,8 @@ class DebugController extends Controller
private function getSystemInformation(): array private function getSystemInformation(): array
{ {
$maxFileSize = Steam::phpBytes( ini_get('upload_max_filesize')); $maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = Steam::phpBytes( ini_get('post_max_size')); $maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
$drivers = DB::availableDrivers(); $drivers = DB::availableDrivers();
$currentDriver = DB::getDriverName(); $currentDriver = DB::getDriverName();
@@ -208,7 +208,7 @@ class DebugController extends Controller
try { try {
if (file_exists('/var/www/counter-main.txt')) { if (file_exists('/var/www/counter-main.txt')) {
$return['build'] = trim( file_get_contents('/var/www/counter-main.txt')); $return['build'] = trim(file_get_contents('/var/www/counter-main.txt'));
app('log')->debug(sprintf('build is now "%s"', $return['build'])); app('log')->debug(sprintf('build is now "%s"', $return['build']));
} }
} catch (Exception $e) { } catch (Exception $e) {
@@ -218,7 +218,7 @@ class DebugController extends Controller
try { try {
if (file_exists('/var/www/build-date-main.txt')) { if (file_exists('/var/www/build-date-main.txt')) {
$return['build_date'] = trim( file_get_contents('/var/www/build-date-main.txt')); $return['build_date'] = trim(file_get_contents('/var/www/build-date-main.txt'));
} }
} catch (Exception $e) { } catch (Exception $e) {
app('log')->debug('Could not check build date, but thats ok.'); app('log')->debug('Could not check build date, but thats ok.');

View File

@@ -82,6 +82,7 @@ class ShowController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new PiggyBankEnrichment(); $enrichment = new PiggyBankEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
/** @var PiggyBank $piggyBank */ /** @var PiggyBank $piggyBank */
$piggyBank = $enrichment->enrichSingle($piggyBank); $piggyBank = $enrichment->enrichSingle($piggyBank);

View File

@@ -65,8 +65,8 @@ class CreateController extends Controller
app('view')->share('title', (string) trans('firefly.recurrences')); app('view')->share('title', (string) trans('firefly.recurrences'));
app('view')->share('subTitle', (string) trans('firefly.create_new_recurrence')); app('view')->share('subTitle', (string) trans('firefly.create_new_recurrence'));
$this->repository = app(RecurringRepositoryInterface::class); $this->repository = app(RecurringRepositoryInterface::class);
$this->budgetRepos = app(BudgetRepositoryInterface::class); $this->budgetRepos = app(BudgetRepositoryInterface::class);
$this->attachments = app(AttachmentHelperInterface::class); $this->attachments = app(AttachmentHelperInterface::class);
$this->billRepository = app(BillRepositoryInterface::class); $this->billRepository = app(BillRepositoryInterface::class);
@@ -115,7 +115,7 @@ class CreateController extends Controller
return view( return view(
'recurring.create', 'recurring.create',
compact('tomorrow', 'oldRepetitionType', 'bills', 'weekendResponses', 'preFilled', 'repetitionEnds', 'budgets') compact('tomorrow', 'oldRepetitionType', 'bills', 'weekendResponses', 'preFilled', 'repetitionEnds', 'budgets')
); );
} }

View File

@@ -70,8 +70,8 @@ class EditController extends Controller
app('view')->share('title', (string) trans('firefly.recurrences')); app('view')->share('title', (string) trans('firefly.recurrences'));
app('view')->share('subTitle', (string) trans('firefly.recurrences')); app('view')->share('subTitle', (string) trans('firefly.recurrences'));
$this->repository = app(RecurringRepositoryInterface::class); $this->repository = app(RecurringRepositoryInterface::class);
$this->budgetRepos = app(BudgetRepositoryInterface::class); $this->budgetRepos = app(BudgetRepositoryInterface::class);
$this->attachments = app(AttachmentHelperInterface::class); $this->attachments = app(AttachmentHelperInterface::class);
$this->billRepository = app(BillRepositoryInterface::class); $this->billRepository = app(BillRepositoryInterface::class);
@@ -100,6 +100,7 @@ class EditController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new RecurringEnrichment(); $enrichment = new RecurringEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
/** @var Recurrence $recurrence */ /** @var Recurrence $recurrence */
$recurrence = $enrichment->enrichSingle($recurrence); $recurrence = $enrichment->enrichSingle($recurrence);

View File

@@ -86,6 +86,7 @@ class ShowController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new RecurringEnrichment(); $enrichment = new RecurringEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
/** @var Recurrence $recurrence */ /** @var Recurrence $recurrence */
$recurrence = $enrichment->enrichSingle($recurrence); $recurrence = $enrichment->enrichSingle($recurrence);

View File

@@ -60,6 +60,7 @@ class TriggerController extends Controller
} }
); );
} }
public function trigger(Recurrence $recurrence, TriggerRecurrenceRequest $request): RedirectResponse public function trigger(Recurrence $recurrence, TriggerRecurrenceRequest $request): RedirectResponse
{ {
$all = $request->getAll(); $all = $request->getAll();

View File

@@ -338,7 +338,7 @@ class ConvertController extends Controller
'type' => $transactionType->type, 'type' => $transactionType->type,
]; ];
/** @var Transaction|null $sourceTransaction */ /** @var null|Transaction $sourceTransaction */
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first(); $sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
$amount = $sourceTransaction->amount ?? '0'; $amount = $sourceTransaction->amount ?? '0';

View File

@@ -92,7 +92,7 @@ class ShowController extends Controller
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setUser($admin)->setTransactionGroup($transactionGroup)->withAPIInformation(); $collector->setUser($admin)->setTransactionGroup($transactionGroup)->withAPIInformation();
/** @var TransactionGroup|null $selectedGroup */ /** @var null|TransactionGroup $selectedGroup */
$selectedGroup = $collector->getGroups()->first(); $selectedGroup = $collector->getGroups()->first();
if (null === $selectedGroup) { if (null === $selectedGroup) {
throw new NotFoundHttpException(); throw new NotFoundHttpException();
@@ -119,6 +119,7 @@ class ShowController extends Controller
// enrich // enrich
$enrichment = new TransactionGroupEnrichment(); $enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
/** @var array $selectedGroup */ /** @var array $selectedGroup */
$selectedGroup = $enrichment->enrichSingle($selectedGroup); $selectedGroup = $enrichment->enrichSingle($selectedGroup);

View File

@@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Http\Requests; namespace FireflyIII\Http\Requests;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Rules\IsValidPositiveAmount;

View File

@@ -129,7 +129,7 @@ class MailError extends Job implements ShouldQueue
} }
if (file_exists($file)) { if (file_exists($file)) {
Log::debug(sprintf('Read file in "%s"', $file)); Log::debug(sprintf('Read file in "%s"', $file));
$limits = json_decode( file_get_contents($file), true); $limits = json_decode(file_get_contents($file), true);
} }
// limit reached? // limit reached?
foreach ($types as $type => $info) { foreach ($types as $type => $info) {

View File

@@ -171,6 +171,7 @@ class WarnAboutBills implements ShouldQueue
$enrichment->setUser($bill->user); $enrichment->setUser($bill->user);
$enrichment->setStart($start); $enrichment->setStart($start);
$enrichment->setEnd($end); $enrichment->setEnd($end);
/** @var Bill $single */ /** @var Bill $single */
$single = $enrichment->enrichSingle($bill); $single = $enrichment->enrichSingle($bill);

View File

@@ -45,9 +45,9 @@ class InvitationMail extends Mailable
*/ */
public function __construct(public string $invitee, public string $admin, public string $url) public function __construct(public string $invitee, public string $admin, public string $url)
{ {
$host = parse_url($this->url, PHP_URL_HOST); $host = parse_url($this->url, PHP_URL_HOST);
if(is_array($host)) { if (is_array($host)) {
$host =''; $host = '';
} }
$this->host = (string) $host; $this->host = (string) $host;
} }

View File

@@ -68,21 +68,21 @@ class UnknownUserLoginAttempt extends Notification
; ;
} }
// /** // /**
// * @SuppressWarnings("PHPMD.UnusedFormalParameter") // * @SuppressWarnings("PHPMD.UnusedFormalParameter")
// */ // */
// //
// public function toNtfy(OwnerNotifiable $notifiable): Message // public function toNtfy(OwnerNotifiable $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'owner', null); // $settings = ReturnsSettings::getSettings('ntfy', 'owner', null);
// $message = new Message(); // $message = new Message();
// $ip = Request::ip(); // $ip = Request::ip();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.unknown_user_subject')); // $message->title((string) trans('email.unknown_user_subject'));
// $message->body((string) trans('email.unknown_user_message', ['address' => $this->address, 'ip' => $ip])); // $message->body((string) trans('email.unknown_user_message', ['address' => $this->address, 'ip' => $ip]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -73,20 +73,20 @@ class UserInvitation extends Notification
; ;
} }
// /** // /**
// * @SuppressWarnings("PHPMD.UnusedFormalParameter") // * @SuppressWarnings("PHPMD.UnusedFormalParameter")
// */ // */
// public function toNtfy(OwnerNotifiable $notifiable): Message // public function toNtfy(OwnerNotifiable $notifiable): Message
// { // {
// Log::debug('Now in toNtfy() for UserInvitation'); // Log::debug('Now in toNtfy() for UserInvitation');
// $settings = ReturnsSettings::getSettings('ntfy', 'owner', null); // $settings = ReturnsSettings::getSettings('ntfy', 'owner', null);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.invitation_created_subject')); // $message->title((string) trans('email.invitation_created_subject'));
// $message->body((string) trans('email.invitation_created_body', ['email' => $this->invitee->user->email, 'invitee' => $this->invitee->email])); // $message->body((string) trans('email.invitation_created_body', ['email' => $this->invitee->user->email, 'invitee' => $this->invitee->email]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -72,20 +72,20 @@ class UserRegistration extends Notification
; ;
} }
// /** // /**
// * @SuppressWarnings("PHPMD.UnusedFormalParameter") // * @SuppressWarnings("PHPMD.UnusedFormalParameter")
// */ // */
// public function toNtfy(OwnerNotifiable $notifiable): Message // public function toNtfy(OwnerNotifiable $notifiable): Message
// { // {
// Log::debug('Now in toNtfy() for (Admin) UserRegistration'); // Log::debug('Now in toNtfy() for (Admin) UserRegistration');
// $settings = ReturnsSettings::getSettings('ntfy', 'owner', null); // $settings = ReturnsSettings::getSettings('ntfy', 'owner', null);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.registered_subject_admin')); // $message->title((string) trans('email.registered_subject_admin'));
// $message->body((string) trans('email.admin_new_user_registered', ['email' => $this->user->email, 'invitee' => $this->user->email])); // $message->body((string) trans('email.admin_new_user_registered', ['email' => $this->user->email, 'invitee' => $this->user->email]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -64,20 +64,20 @@ class VersionCheckResult extends Notification
; ;
} }
// /** // /**
// * @SuppressWarnings("PHPMD.UnusedFormalParameter") // * @SuppressWarnings("PHPMD.UnusedFormalParameter")
// */ // */
// public function toNtfy(OwnerNotifiable $notifiable): Message // public function toNtfy(OwnerNotifiable $notifiable): Message
// { // {
// Log::debug('Now in toNtfy() for VersionCheckResult'); // Log::debug('Now in toNtfy() for VersionCheckResult');
// $settings = ReturnsSettings::getSettings('ntfy', 'owner', null); // $settings = ReturnsSettings::getSettings('ntfy', 'owner', null);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.new_version_email_subject')); // $message->title((string) trans('email.new_version_email_subject'));
// $message->body($this->message); // $message->body($this->message);
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -28,7 +28,8 @@ use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use NotificationChannels\Pushover\PushoverChannel; use NotificationChannels\Pushover\PushoverChannel;
//use Wijourdil\NtfyNotificationChannel\Channels\NtfyChannel;
// use Wijourdil\NtfyNotificationChannel\Channels\NtfyChannel;
class ReturnsAvailableChannels class ReturnsAvailableChannels
{ {
@@ -58,16 +59,16 @@ class ReturnsAvailableChannels
} }
} }
// if (true === config('notifications.channels.ntfy.enabled', false)) { // if (true === config('notifications.channels.ntfy.enabled', false)) {
// // validate presence of of Ntfy settings. // // validate presence of of Ntfy settings.
// if ('' !== (string) app('fireflyconfig')->getEncrypted('ntfy_topic', '')->data) { // if ('' !== (string) app('fireflyconfig')->getEncrypted('ntfy_topic', '')->data) {
// Log::debug('Enabled ntfy.'); // Log::debug('Enabled ntfy.');
// $channels[] = NtfyChannel::class; // $channels[] = NtfyChannel::class;
// } // }
// if ('' === (string) app('fireflyconfig')->getEncrypted('ntfy_topic', '')->data) { // if ('' === (string) app('fireflyconfig')->getEncrypted('ntfy_topic', '')->data) {
// Log::warning('No topic name for Ntfy, channel is disabled.'); // Log::warning('No topic name for Ntfy, channel is disabled.');
// } // }
// } // }
// pushover // pushover
if (true === config('notifications.channels.pushover.enabled', false)) { if (true === config('notifications.channels.pushover.enabled', false)) {
@@ -99,17 +100,17 @@ class ReturnsAvailableChannels
} }
} }
// // validate presence of of Ntfy settings. // // validate presence of of Ntfy settings.
// if (true === config('notifications.channels.nfy.enabled', false)) { // if (true === config('notifications.channels.nfy.enabled', false)) {
// $ntfyTopic = (string) app('preferences')->getEncryptedForUser($user, 'ntfy_topic', '')->data; // $ntfyTopic = (string) app('preferences')->getEncryptedForUser($user, 'ntfy_topic', '')->data;
// if ('' !== $ntfyTopic) { // if ('' !== $ntfyTopic) {
// Log::debug(sprintf('Enabled ntfy, "%s"', $ntfyTopic)); // Log::debug(sprintf('Enabled ntfy, "%s"', $ntfyTopic));
// $channels[] = NtfyChannel::class; // $channels[] = NtfyChannel::class;
// } // }
// if ('' === (string) app('preferences')->getEncryptedForUser($user, 'ntfy_topic', '')->data) { // if ('' === (string) app('preferences')->getEncryptedForUser($user, 'ntfy_topic', '')->data) {
// Log::warning('No topic name for Ntfy, channel is disabled.'); // Log::warning('No topic name for Ntfy, channel is disabled.');
// } // }
// } // }
// pushover // pushover
if (true === config('notifications.channels.slack.enabled', false)) { if (true === config('notifications.channels.slack.enabled', false)) {

View File

@@ -65,16 +65,16 @@ class DisabledMFANotification extends Notification
return new MailMessage()->markdown('emails.security.disabled-mfa', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject); return new MailMessage()->markdown('emails.security.disabled-mfa', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject);
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.disabled_mfa_subject')); // $message->title((string) trans('email.disabled_mfa_subject'));
// $message->body((string) trans('email.disabled_mfa_slack', ['email' => $this->user->email])); // $message->body((string) trans('email.disabled_mfa_slack', ['email' => $this->user->email]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -65,16 +65,16 @@ class EnabledMFANotification extends Notification
return new MailMessage()->markdown('emails.security.enabled-mfa', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject); return new MailMessage()->markdown('emails.security.enabled-mfa', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject);
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.enabled_mfa_subject')); // $message->title((string) trans('email.enabled_mfa_subject'));
// $message->body((string) trans('email.enabled_mfa_slack', ['email' => $this->user->email])); // $message->body((string) trans('email.enabled_mfa_slack', ['email' => $this->user->email]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -65,16 +65,16 @@ class MFABackupFewLeftNotification extends Notification
return new MailMessage()->markdown('emails.security.few-backup-codes', ['user' => $this->user, 'count' => $this->count, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject); return new MailMessage()->markdown('emails.security.few-backup-codes', ['user' => $this->user, 'count' => $this->count, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject);
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.mfa_few_backups_left_subject')); // $message->title((string) trans('email.mfa_few_backups_left_subject'));
// $message->body((string) trans('email.mfa_few_backups_left_slack', ['email' => $this->user->email, 'count' => $this->count])); // $message->body((string) trans('email.mfa_few_backups_left_slack', ['email' => $this->user->email, 'count' => $this->count]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -65,16 +65,16 @@ class MFABackupNoLeftNotification extends Notification
return new MailMessage()->markdown('emails.security.no-backup-codes', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject); return new MailMessage()->markdown('emails.security.no-backup-codes', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject);
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.mfa_no_backups_left_subject')); // $message->title((string) trans('email.mfa_no_backups_left_subject'));
// $message->body((string) trans('email.mfa_no_backups_left_slack', ['email' => $this->user->email])); // $message->body((string) trans('email.mfa_no_backups_left_slack', ['email' => $this->user->email]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -62,16 +62,16 @@ class MFAManyFailedAttemptsNotification extends Notification
return new MailMessage()->markdown('emails.security.many-failed-attempts', ['user' => $this->user, 'count' => $this->count, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject); return new MailMessage()->markdown('emails.security.many-failed-attempts', ['user' => $this->user, 'count' => $this->count, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject);
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.mfa_many_failed_subject')); // $message->title((string) trans('email.mfa_many_failed_subject'));
// $message->body((string) trans('email.mfa_many_failed_slack', ['email' => $this->user->email, 'count' => $this->count])); // $message->body((string) trans('email.mfa_many_failed_slack', ['email' => $this->user->email, 'count' => $this->count]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -65,16 +65,16 @@ class MFAUsedBackupCodeNotification extends Notification
return new MailMessage()->markdown('emails.security.used-backup-code', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject); return new MailMessage()->markdown('emails.security.used-backup-code', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject);
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.used_backup_code_subject')); // $message->title((string) trans('email.used_backup_code_subject'));
// $message->body((string) trans('email.used_backup_code_slack', ['email' => $this->user->email])); // $message->body((string) trans('email.used_backup_code_slack', ['email' => $this->user->email]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -65,16 +65,16 @@ class NewBackupCodesNotification extends Notification
return new MailMessage()->markdown('emails.security.new-backup-codes', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject); return new MailMessage()->markdown('emails.security.new-backup-codes', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject);
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.new_backup_codes_subject')); // $message->title((string) trans('email.new_backup_codes_subject'));
// $message->body((string) trans('email.new_backup_codes_slack', ['email' => $this->user->email])); // $message->body((string) trans('email.new_backup_codes_slack', ['email' => $this->user->email]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -63,17 +63,17 @@ class UserFailedLoginAttempt extends Notification
return new MailMessage()->markdown('emails.security.failed-login', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject); return new MailMessage()->markdown('emails.security.failed-login', ['user' => $this->user, 'ip' => $ip, 'host' => $host, 'userAgent' => $userAgent, 'time' => $time])->subject($subject);
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $ip = Request::ip(); // $ip = Request::ip();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.failed_login_subject')); // $message->title((string) trans('email.failed_login_subject'));
// $message->body((string) trans('email.failed_login_message', ['ip' => $ip, 'email' => $this->user->email])); // $message->body((string) trans('email.failed_login_message', ['ip' => $ip, 'email' => $this->user->email]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -49,20 +49,20 @@ class OwnerTestNotificationNtfy extends Notification
]; ];
} }
// public function toNtfy(OwnerNotifiable $notifiable): Message // public function toNtfy(OwnerNotifiable $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'owner', null); // $settings = ReturnsSettings::getSettings('ntfy', 'owner', null);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.admin_test_subject')); // $message->title((string) trans('email.admin_test_subject'));
// $message->body((string) trans('email.admin_test_message', ['channel' => 'ntfy'])); // $message->body((string) trans('email.admin_test_message', ['channel' => 'ntfy']));
// $message->tags(['white_check_mark']); // $message->tags(['white_check_mark']);
// //
// return $message; // return $message;
// } // }
// public function via(OwnerNotifiable $notifiable): array // public function via(OwnerNotifiable $notifiable): array
// { // {
// return [NtfyChannel::class]; // return [NtfyChannel::class];
// } // }
} }

View File

@@ -49,20 +49,20 @@ class UserTestNotificationNtfy extends Notification
]; ];
} }
// public function toNtfy(User $user): Message // public function toNtfy(User $user): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $user); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $user);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.admin_test_subject')); // $message->title((string) trans('email.admin_test_subject'));
// $message->body((string) trans('email.admin_test_message', ['channel' => 'ntfy'])); // $message->body((string) trans('email.admin_test_message', ['channel' => 'ntfy']));
// $message->tags(['white_check_mark']); // $message->tags(['white_check_mark']);
// //
// return $message; // return $message;
// } // }
// public function via(User $user): array // public function via(User $user): array
// { // {
// return [NtfyChannel::class]; // return [NtfyChannel::class];
// } // }
} }

View File

@@ -73,16 +73,16 @@ class BillReminder extends Notification
return (string) trans(sprintf('email.bill_warning_subject_%s', $this->field), ['diff' => $this->diff, 'name' => $this->bill->name]); return (string) trans(sprintf('email.bill_warning_subject_%s', $this->field), ['diff' => $this->diff, 'name' => $this->bill->name]);
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title($this->getSubject()); // $message->title($this->getSubject());
// $message->body((string) trans('email.bill_warning_please_action')); // $message->body((string) trans('email.bill_warning_please_action'));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -68,16 +68,16 @@ class NewAccessToken extends Notification
; ;
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.access_token_created_subject')); // $message->title((string) trans('email.access_token_created_subject'));
// $message->body((string) trans('email.access_token_created_body')); // $message->body((string) trans('email.access_token_created_body'));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -65,15 +65,15 @@ class RuleActionFailed extends Notification
]; ];
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->body($this->message); // $message->body($this->message);
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -65,18 +65,18 @@ class UserLogin extends Notification
; ;
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $ip = Request::ip(); // $ip = Request::ip();
// $host = Steam::getHostName($ip); // $host = Steam::getHostName($ip);
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->title((string) trans('email.login_from_new_ip')); // $message->title((string) trans('email.login_from_new_ip'));
// $message->body((string) trans('email.slack_login_from_new_ip', ['ip' => $ip, 'host' => $host])); // $message->body((string) trans('email.slack_login_from_new_ip', ['ip' => $ip, 'host' => $host]));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -70,15 +70,15 @@ class UserNewPassword extends Notification
; ;
} }
// public function toNtfy(User $notifiable): Message // public function toNtfy(User $notifiable): Message
// { // {
// $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable); // $settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
// $message = new Message(); // $message = new Message();
// $message->topic($settings['ntfy_topic']); // $message->topic($settings['ntfy_topic']);
// $message->body((string) trans('email.reset_pw_message')); // $message->body((string) trans('email.reset_pw_message'));
// //
// return $message; // return $message;
// } // }
/** /**
* @SuppressWarnings("PHPMD.UnusedFormalParameter") * @SuppressWarnings("PHPMD.UnusedFormalParameter")

View File

@@ -478,18 +478,18 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
public function getAccountsByType(array $types, ?array $sort = []): Collection public function getAccountsByType(array $types, ?array $sort = []): Collection
{ {
$res = array_intersect([AccountTypeEnum::ASSET->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value], $types); $res = array_intersect([AccountTypeEnum::ASSET->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value], $types);
$query = $this->user->accounts(); $query = $this->user->accounts();
if (0 !== count($types)) { if (0 !== count($types)) {
$query->accountTypeIn($types); $query->accountTypeIn($types);
} }
// add sort parameters // add sort parameters
$allowed = config('firefly.allowed_db_sort_parameters.Account', []); $allowed = config('firefly.allowed_db_sort_parameters.Account', []);
$sorted = 0; $sorted = 0;
if (0 !== count($sort)) { if (0 !== count($sort)) {
foreach ($sort as $param) { foreach ($sort as $param) {
if(in_array($param[0], $allowed, true)) { if (in_array($param[0], $allowed, true)) {
$query->orderBy($param[0], $param[1]); $query->orderBy($param[0], $param[1]);
++$sorted; ++$sorted;
} }

View File

@@ -115,12 +115,13 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
public function getJournalLinks(?LinkType $linkType = null): Collection public function getJournalLinks(?LinkType $linkType = null): Collection
{ {
$query = TransactionJournalLink::with(['source', 'destination']) $query = TransactionJournalLink::with(['source', 'destination'])
->leftJoin('transaction_journals as source_journals', 'journal_links.source_id', '=', 'source_journals.id') ->leftJoin('transaction_journals as source_journals', 'journal_links.source_id', '=', 'source_journals.id')
->leftJoin('transaction_journals as dest_journals', 'journal_links.destination_id', '=', 'dest_journals.id') ->leftJoin('transaction_journals as dest_journals', 'journal_links.destination_id', '=', 'dest_journals.id')
->where('source_journals.user_id', $this->user->id) ->where('source_journals.user_id', $this->user->id)
->where('dest_journals.user_id', $this->user->id) ->where('dest_journals.user_id', $this->user->id)
->whereNull('source_journals.deleted_at') ->whereNull('source_journals.deleted_at')
->whereNull('dest_journals.deleted_at'); ->whereNull('dest_journals.deleted_at')
;
if ($linkType instanceof LinkType) { if ($linkType instanceof LinkType) {
$query->where('journal_links.link_type_id', $linkType->id); $query->where('journal_links.link_type_id', $linkType->id);
@@ -149,7 +150,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
$merged = $outward->merge($inward); $merged = $outward->merge($inward);
return $merged->filter( return $merged->filter(
static fn(TransactionJournalLink $link) => null !== $link->source && null !== $link->destination static fn (TransactionJournalLink $link) => null !== $link->source && null !== $link->destination
); );
} }
@@ -188,7 +189,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
return $existing; return $existing;
} }
$link = new TransactionJournalLink(); $link = new TransactionJournalLink();
$link->linkType()->associate($linkType); $link->linkType()->associate($linkType);
if ('inward' === $information['direction']) { if ('inward' === $information['direction']) {
app('log')->debug(sprintf('Link type is inwards ("%s"), so %d is source and %d is destination.', $linkType->inward, $inward->id, $outward->id)); app('log')->debug(sprintf('Link type is inwards ("%s"), so %d is source and %d is destination.', $linkType->inward, $inward->id, $outward->id));
@@ -229,8 +230,9 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
public function findSpecificLink(LinkType $linkType, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink public function findSpecificLink(LinkType $linkType, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink
{ {
return TransactionJournalLink::where('link_type_id', $linkType->id) return TransactionJournalLink::where('link_type_id', $linkType->id)
->where('source_id', $inward->id) ->where('source_id', $inward->id)
->where('destination_id', $outward->id)->first(); ->where('destination_id', $outward->id)->first()
;
} }
/** /**
@@ -292,7 +294,7 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
$journalLink->refresh(); $journalLink->refresh();
} }
$journalLink->link_type_id = $data['link_type_id'] ?? $journalLink->link_type_id; $journalLink->link_type_id = $data['link_type_id'] ?? $journalLink->link_type_id;
$journalLink->save(); $journalLink->save();
if (array_key_exists('notes', $data) && null !== $data['notes']) { if (array_key_exists('notes', $data) && null !== $data['notes']) {
$this->setNoteText($journalLink, $data['notes']); $this->setNoteText($journalLink, $data['notes']);

View File

@@ -241,7 +241,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
Log::debug(sprintf('Will add/remove %f to piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name)); Log::debug(sprintf('Will add/remove %f to piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name));
// if the amount is positive, make sure it fits in piggy bank: // if the amount is positive, make sure it fits in piggy bank:
if (1 === bccomp($amount, '0') && -1 === bccomp( $room, $amount)) { if (1 === bccomp($amount, '0') && -1 === bccomp($room, $amount)) {
// amount is positive and $room is smaller than $amount // amount is positive and $room is smaller than $amount
Log::debug(sprintf('Room in piggy bank for extra money is %f', $room)); Log::debug(sprintf('Room in piggy bank for extra money is %f', $room));
Log::debug(sprintf('There is NO room to add %f to piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name)); Log::debug(sprintf('There is NO room to add %f to piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name));
@@ -259,7 +259,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
return $compare; return $compare;
} }
return $amount; return $amount;
} }
/** /**

View File

@@ -272,9 +272,9 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
$amount = Steam::positive((string) $journal['amount']); $amount = Steam::positive((string) $journal['amount']);
$type = $journal['transaction_type_type']; $type = $journal['transaction_type_type'];
if (TransactionTypeEnum::WITHDRAWAL->value === $type) { if (TransactionTypeEnum::WITHDRAWAL->value === $type) {
$amount = bcmul( $amount, '-1'); $amount = bcmul($amount, '-1');
} }
$sums[$currencyId][$type] = bcadd((string) $sums[$currencyId][$type], $amount); $sums[$currencyId][$type] = bcadd((string) $sums[$currencyId][$type], $amount);
$foreignCurrencyId = $journal['foreign_currency_id']; $foreignCurrencyId = $journal['foreign_currency_id'];
if (null !== $foreignCurrencyId && 0 !== $foreignCurrencyId) { if (null !== $foreignCurrencyId && 0 !== $foreignCurrencyId) {
@@ -292,7 +292,7 @@ class TagRepository implements TagRepositoryInterface, UserGroupInterface
// add foreign amount to correct type: // add foreign amount to correct type:
$amount = Steam::positive((string) $journal['foreign_amount']); $amount = Steam::positive((string) $journal['foreign_amount']);
if (TransactionTypeEnum::WITHDRAWAL->value === $type) { if (TransactionTypeEnum::WITHDRAWAL->value === $type) {
$amount = bcmul( $amount, '-1'); $amount = bcmul($amount, '-1');
} }
$sums[$foreignCurrencyId][$type] = bcadd((string) $sums[$foreignCurrencyId][$type], $amount); $sums[$foreignCurrencyId][$type] = bcadd((string) $sums[$foreignCurrencyId][$type], $amount);
} }

View File

@@ -50,6 +50,7 @@ use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use function Safe\json_decode; use function Safe\json_decode;
/** /**
@@ -143,21 +144,22 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
{ {
$repository = app(AttachmentRepositoryInterface::class); $repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($this->user); $repository->setUser($this->user);
$journals = $group->transactionJournals->pluck('id')->toArray(); $journals = $group->transactionJournals->pluck('id')->toArray();
$set = Attachment::whereIn('attachable_id', $journals) $set = Attachment::whereIn('attachable_id', $journals)
->where('attachable_type', TransactionJournal::class) ->where('attachable_type', TransactionJournal::class)
->where('uploaded', true) ->where('uploaded', true)
->whereNull('deleted_at')->get(); ->whereNull('deleted_at')->get()
;
$result = []; $result = [];
/** @var Attachment $attachment */ /** @var Attachment $attachment */
foreach ($set as $attachment) { foreach ($set as $attachment) {
$journalId = $attachment->attachable_id; $journalId = $attachment->attachable_id;
$result[$journalId] ??= []; $result[$journalId] ??= [];
$current = $attachment->toArray(); $current = $attachment->toArray();
$current['file_exists'] = true; $current['file_exists'] = true;
$current['notes'] = $repository->getNoteText($attachment); $current['notes'] = $repository->getNoteText($attachment);
// already determined that this attachable is a TransactionJournal. // already determined that this attachable is a TransactionJournal.
$current['journal_title'] = $attachment->attachable->description; $current['journal_title'] = $attachment->attachable->description;
$result[$journalId][] = $current; $result[$journalId][] = $current;
@@ -173,8 +175,9 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
{ {
/** @var null|Note $note */ /** @var null|Note $note */
$note = Note::where('noteable_id', $journalId) $note = Note::where('noteable_id', $journalId)
->where('noteable_type', TransactionJournal::class) ->where('noteable_type', TransactionJournal::class)
->first(); ->first()
;
if (null === $note) { if (null === $note) {
return null; return null;
} }
@@ -195,13 +198,14 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
$q->orWhereIn('destination_id', $journals); $q->orWhereIn('destination_id', $journals);
} }
) )
->with(['source', 'destination', 'source.transactions']) ->with(['source', 'destination', 'source.transactions'])
->leftJoin('link_types', 'link_types.id', '=', 'journal_links.link_type_id') ->leftJoin('link_types', 'link_types.id', '=', 'journal_links.link_type_id')
->get(['journal_links.*', 'link_types.inward', 'link_types.outward', 'link_types.editable']); ->get(['journal_links.*', 'link_types.inward', 'link_types.outward', 'link_types.editable'])
;
/** @var TransactionJournalLink $entry */ /** @var TransactionJournalLink $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
$journalId = in_array($entry->source_id, $journals, true) ? $entry->source_id : $entry->destination_id; $journalId = in_array($entry->source_id, $journals, true) ? $entry->source_id : $entry->destination_id;
$return[$journalId] ??= []; $return[$journalId] ??= [];
// phpstan: the editable field is provided by the query. // phpstan: the editable field is provided by the query.
@@ -247,6 +251,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
if (TransactionTypeEnum::WITHDRAWAL->value === $type) { if (TransactionTypeEnum::WITHDRAWAL->value === $type) {
return Amount::formatAnything($currency, app('steam')->negative($amount)); return Amount::formatAnything($currency, app('steam')->negative($amount));
} }
return Amount::formatAnything($currency, $amount); return Amount::formatAnything($currency, $amount);
} }
@@ -262,13 +267,14 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
return ''; return '';
} }
$currency = $transaction->foreignCurrency; $currency = $transaction->foreignCurrency;
$type = $journal->transactionType->type; $type = $journal->transactionType->type;
$amount = app('steam')->positive($transaction->foreign_amount); $amount = app('steam')->positive($transaction->foreign_amount);
if (TransactionTypeEnum::WITHDRAWAL->value === $type) { if (TransactionTypeEnum::WITHDRAWAL->value === $type) {
return Amount::formatAnything($currency, app('steam')->negative($amount)); return Amount::formatAnything($currency, app('steam')->negative($amount));
} }
return Amount::formatAnything($currency, $amount);
return Amount::formatAnything($currency, $amount);
} }
public function getLocation(int $journalId): ?Location public function getLocation(int $journalId): ?Location
@@ -288,10 +294,11 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
public function getMetaDateFields(int $journalId, array $fields): NullArrayObject public function getMetaDateFields(int $journalId, array $fields): NullArrayObject
{ {
$query = DB::table('journal_meta') $query = DB::table('journal_meta')
->where('transaction_journal_id', $journalId) ->where('transaction_journal_id', $journalId)
->whereIn('name', $fields) ->whereIn('name', $fields)
->whereNull('deleted_at') ->whereNull('deleted_at')
->get(['name', 'data']); ->get(['name', 'data'])
;
$return = []; $return = [];
foreach ($query as $row) { foreach ($query as $row) {
@@ -307,10 +314,11 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
public function getMetaFields(int $journalId, array $fields): NullArrayObject public function getMetaFields(int $journalId, array $fields): NullArrayObject
{ {
$query = DB::table('journal_meta') $query = DB::table('journal_meta')
->where('transaction_journal_id', $journalId) ->where('transaction_journal_id', $journalId)
->whereIn('name', $fields) ->whereIn('name', $fields)
->whereNull('deleted_at') ->whereNull('deleted_at')
->get(['name', 'data']); ->get(['name', 'data'])
;
$return = []; $return = [];
foreach ($query as $row) { foreach ($query as $row) {
@@ -331,8 +339,9 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
$journals = $group->transactionJournals->pluck('id')->toArray(); $journals = $group->transactionJournals->pluck('id')->toArray();
$currency = Amount::getPrimaryCurrencyByUserGroup($this->user->userGroup); $currency = Amount::getPrimaryCurrencyByUserGroup($this->user->userGroup);
$data = PiggyBankEvent::whereIn('transaction_journal_id', $journals) $data = PiggyBankEvent::whereIn('transaction_journal_id', $journals)
->with('piggyBank', 'piggyBank.account') ->with('piggyBank', 'piggyBank.account')
->get(['piggy_bank_events.*']); ->get(['piggy_bank_events.*'])
;
/** @var PiggyBankEvent $row */ /** @var PiggyBankEvent $row */
foreach ($data as $row) { foreach ($data as $row) {
@@ -340,13 +349,14 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
continue; continue;
} }
// get currency preference. // get currency preference.
$currencyPreference = AccountMeta::where('account_id', $row->piggyBank->account_id) $currencyPreference = AccountMeta::where('account_id', $row->piggyBank->account_id)
->where('name', 'currency_id') ->where('name', 'currency_id')
->first(); ->first()
;
if (null !== $currencyPreference) { if (null !== $currencyPreference) {
$currency = TransactionCurrency::where('id', $currencyPreference->data)->first(); $currency = TransactionCurrency::where('id', $currencyPreference->data)->first();
} }
$journalId = $row->transaction_journal_id; $journalId = $row->transaction_journal_id;
$return[$journalId] ??= []; $return[$journalId] ??= [];
$return[$journalId][] = [ $return[$journalId][] = [
@@ -373,10 +383,11 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
public function getTags(int $journalId): array public function getTags(int $journalId): array
{ {
$result = DB::table('tag_transaction_journal') $result = DB::table('tag_transaction_journal')
->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id') ->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id')
->where('tag_transaction_journal.transaction_journal_id', $journalId) ->where('tag_transaction_journal.transaction_journal_id', $journalId)
->orderBy('tags.tag', 'ASC') ->orderBy('tags.tag', 'ASC')
->get(['tags.tag']); ->get(['tags.tag'])
;
return $result->pluck('tag')->toArray(); return $result->pluck('tag')->toArray();
} }

View File

@@ -229,7 +229,7 @@ class UserRepository implements UserRepositoryInterface
return $return; return $return;
} }
public function hasRole(null|Authenticatable|User $user, string $role): bool public function hasRole(Authenticatable|User|null $user, string $role): bool
{ {
if (!$user instanceof Authenticatable) { if (!$user instanceof Authenticatable) {
return false; return false;
@@ -270,7 +270,7 @@ class UserRepository implements UserRepositoryInterface
return $collection; return $collection;
} }
public function inviteUser(null|Authenticatable|User $user, string $email): InvitedUser public function inviteUser(Authenticatable|User|null $user, string $email): InvitedUser
{ {
if (!$user instanceof User) { if (!$user instanceof User) {
throw new FireflyException('User is not a User object.'); throw new FireflyException('User is not a User object.');

View File

@@ -105,9 +105,9 @@ interface UserRepositoryInterface
public function getUserGroups(User $user): Collection; public function getUserGroups(User $user): Collection;
public function hasRole(null|Authenticatable|User $user, string $role): bool; public function hasRole(Authenticatable|User|null $user, string $role): bool;
public function inviteUser(null|Authenticatable|User $user, string $email): InvitedUser; public function inviteUser(Authenticatable|User|null $user, string $email): InvitedUser;
public function redeemCode(string $code): void; public function redeemCode(string $code): void;

View File

@@ -1,4 +1,6 @@
<?php <?php
declare(strict_types=1);
/* /*
* IsValidSortInstruction.php * IsValidSortInstruction.php
* Copyright (c) 2025 james@firefly-iii.org * Copyright (c) 2025 james@firefly-iii.org
@@ -35,21 +37,24 @@ class IsValidSortInstruction implements ValidationRule
public function validate(string $attribute, mixed $value, Closure $fail): void public function validate(string $attribute, mixed $value, Closure $fail): void
{ {
$shortClass = str_replace('FireflyIII\\Models\\', '', $this->class); $shortClass = str_replace('FireflyIII\Models\\', '', $this->class);
if (!is_string($value)) { if (!is_string($value)) {
$fail('validation.invalid_sort_instruction')->translate(['object' => $shortClass]); $fail('validation.invalid_sort_instruction')->translate(['object' => $shortClass]);
return; return;
} }
$validParameters = config(sprintf('firefly.allowed_sort_parameters.%s', $shortClass)); $validParameters = config(sprintf('firefly.allowed_sort_parameters.%s', $shortClass));
if (!is_array($validParameters)) { if (!is_array($validParameters)) {
$fail('validation.no_sort_instructions')->translate(['object' => $shortClass]); $fail('validation.no_sort_instructions')->translate(['object' => $shortClass]);
return; return;
} }
$parts = explode(',', $value); $parts = explode(',', $value);
foreach ($parts as $i => $part) { foreach ($parts as $i => $part) {
$part = trim($part); $part = trim($part);
if (strlen($part) < 2) { if (strlen($part) < 2) {
$fail('validation.invalid_sort_instruction_index')->translate(['index' => $i, 'object' => $shortClass]); $fail('validation.invalid_sort_instruction_index')->translate(['index' => $i, 'object' => $shortClass]);
return; return;
} }
if ('-' === $part[0]) { if ('-' === $part[0]) {
@@ -57,6 +62,7 @@ class IsValidSortInstruction implements ValidationRule
} }
if (!in_array($part, $validParameters, true)) { if (!in_array($part, $validParameters, true)) {
$fail('validation.invalid_sort_instruction_index')->translate(['index' => $i, 'object' => $shortClass]); $fail('validation.invalid_sort_instruction_index')->translate(['index' => $i, 'object' => $shortClass]);
return; return;
} }
} }

View File

@@ -780,10 +780,10 @@ class JournalUpdateService
private function isBetweenAssetAndLiability(): bool private function isBetweenAssetAndLiability(): bool
{ {
/** @var Transaction|null $sourceTransaction */ /** @var null|Transaction $sourceTransaction */
$sourceTransaction = $this->transactionJournal->transactions()->where('amount', '<', 0)->first(); $sourceTransaction = $this->transactionJournal->transactions()->where('amount', '<', 0)->first();
/** @var Transaction|null $destinationTransaction */ /** @var null|Transaction $destinationTransaction */
$destinationTransaction = $this->transactionJournal->transactions()->where('amount', '>', 0)->first(); $destinationTransaction = $this->transactionJournal->transactions()->where('amount', '>', 0)->first();
if (null === $sourceTransaction || null === $destinationTransaction) { if (null === $sourceTransaction || null === $destinationTransaction) {
Log::warning('Either transaction is false, stop.'); Log::warning('Either transaction is false, stop.');

View File

@@ -139,14 +139,14 @@ class RemoteUserGuard implements Guard
/** /**
* @SuppressWarnings("PHPMD.ShortMethodName") * @SuppressWarnings("PHPMD.ShortMethodName")
*/ */
public function id(): null|int|string public function id(): int|string|null
{ {
Log::debug(sprintf('Now at %s', __METHOD__)); Log::debug(sprintf('Now at %s', __METHOD__));
return $this->user?->id; return $this->user?->id;
} }
public function setUser(null|Authenticatable|User $user): void // @phpstan-ignore-line public function setUser(Authenticatable|User|null $user): void // @phpstan-ignore-line
{ {
Log::debug(sprintf('Now at %s', __METHOD__)); Log::debug(sprintf('Now at %s', __METHOD__));
if ($user instanceof User) { if ($user instanceof User) {

View File

@@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Support\Facades; namespace FireflyIII\Support\Facades;
use Carbon\Carbon;
use Illuminate\Support\Facades\Facade; use Illuminate\Support\Facades\Facade;
class Navigation extends Facade class Navigation extends Facade

View File

@@ -144,9 +144,10 @@ class AccountEnrichment implements EnrichmentInterface
private function collectMetaData(): void private function collectMetaData(): void
{ {
$set = AccountMeta::whereIn('name', ['is_multi_currency', 'include_net_worth', 'currency_id', 'account_role', 'account_number', 'BIC', 'liability_direction', 'interest', 'interest_period', 'current_debt']) $set = AccountMeta::whereIn('name', ['is_multi_currency', 'include_net_worth', 'currency_id', 'account_role', 'account_number', 'BIC', 'liability_direction', 'interest', 'interest_period', 'current_debt'])
->whereIn('account_id', $this->ids) ->whereIn('account_id', $this->ids)
->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data'])->toArray(); ->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data'])->toArray()
;
/** @var array $entry */ /** @var array $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
@@ -172,9 +173,10 @@ class AccountEnrichment implements EnrichmentInterface
private function collectNotes(): void private function collectNotes(): void
{ {
$notes = Note::query()->whereIn('noteable_id', $this->ids) $notes = Note::query()->whereIn('noteable_id', $this->ids)
->whereNotNull('notes.text') ->whereNotNull('notes.text')
->where('notes.text', '!=', '') ->where('notes.text', '!=', '')
->where('noteable_type', Account::class)->get(['notes.noteable_id', 'notes.text'])->toArray(); ->where('noteable_type', Account::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
;
foreach ($notes as $note) { foreach ($notes as $note) {
$this->notes[(int)$note['noteable_id']] = (string)$note['text']; $this->notes[(int)$note['noteable_id']] = (string)$note['text'];
} }
@@ -184,14 +186,15 @@ class AccountEnrichment implements EnrichmentInterface
private function collectLocations(): void private function collectLocations(): void
{ {
$locations = Location::query()->whereIn('locatable_id', $this->ids) $locations = Location::query()->whereIn('locatable_id', $this->ids)
->where('locatable_type', Account::class)->get(['locations.locatable_id', 'locations.latitude', 'locations.longitude', 'locations.zoom_level'])->toArray(); ->where('locatable_type', Account::class)->get(['locations.locatable_id', 'locations.latitude', 'locations.longitude', 'locations.zoom_level'])->toArray()
;
foreach ($locations as $location) { foreach ($locations as $location) {
$this->locations[(int)$location['locatable_id']] $this->locations[(int)$location['locatable_id']]
= [ = [
'latitude' => (float)$location['latitude'], 'latitude' => (float)$location['latitude'],
'longitude' => (float)$location['longitude'], 'longitude' => (float)$location['longitude'],
'zoom_level' => (int)$location['zoom_level'], 'zoom_level' => (int)$location['zoom_level'],
]; ];
} }
Log::debug(sprintf('Enrich with %d locations(s)', count($this->locations))); Log::debug(sprintf('Enrich with %d locations(s)', count($this->locations)));
} }
@@ -206,19 +209,20 @@ class AccountEnrichment implements EnrichmentInterface
->setUserGroup($this->userGroup) ->setUserGroup($this->userGroup)
->setAccounts($this->collection) ->setAccounts($this->collection)
->withAccountInformation() ->withAccountInformation()
->setTypes([TransactionTypeEnum::OPENING_BALANCE->value]); ->setTypes([TransactionTypeEnum::OPENING_BALANCE->value])
$journals = $collector->getExtractedJournals(); ;
$journals = $collector->getExtractedJournals();
foreach ($journals as $journal) { foreach ($journals as $journal) {
$this->openingBalances[(int)$journal['source_account_id']] $this->openingBalances[(int)$journal['source_account_id']]
= [ = [
'amount' => Steam::negative($journal['amount']), 'amount' => Steam::negative($journal['amount']),
'date' => $journal['date'], 'date' => $journal['date'],
]; ];
$this->openingBalances[(int)$journal['destination_account_id']] $this->openingBalances[(int)$journal['destination_account_id']]
= [ = [
'amount' => Steam::positive($journal['amount']), 'amount' => Steam::positive($journal['amount']),
'date' => $journal['date'], 'date' => $journal['date'],
]; ];
} }
} }
@@ -236,9 +240,9 @@ class AccountEnrichment implements EnrichmentInterface
private function appendCollectedData(): void private function appendCollectedData(): void
{ {
$this->collection = $this->collection->map(function (Account $item) { $this->collection = $this->collection->map(function (Account $item) {
$id = (int)$item->id; $id = (int)$item->id;
$item->full_account_type = $this->accountTypes[(int)$item->account_type_id] ?? null; $item->full_account_type = $this->accountTypes[(int)$item->account_type_id] ?? null;
$meta = [ $meta = [
'currency' => null, 'currency' => null,
'location' => [ 'location' => [
'latitude' => null, 'latitude' => null,
@@ -285,30 +289,30 @@ class AccountEnrichment implements EnrichmentInterface
// add balances // add balances
// get currencies: // get currencies:
$currency = $this->primaryCurrency; // assume primary currency $currency = $this->primaryCurrency; // assume primary currency
if (null !== $meta['currency']) { if (null !== $meta['currency']) {
$currency = $meta['currency']; $currency = $meta['currency'];
} }
// get the current balance: // get the current balance:
$date = $this->getDate(); $date = $this->getDate();
// $finalBalance = Steam::finalAccountBalance($item, $date, $this->primaryCurrency, $this->convertToPrimary); // $finalBalance = Steam::finalAccountBalance($item, $date, $this->primaryCurrency, $this->convertToPrimary);
$finalBalance = $this->balances[$id]; $finalBalance = $this->balances[$id];
$balanceDifference = $this->getBalanceDifference($id, $currency); $balanceDifference = $this->getBalanceDifference($id, $currency);
Log::debug(sprintf('Call finalAccountBalance(%s) with date/time "%s"', var_export($this->convertToPrimary, true), $date->toIso8601String()), $finalBalance); Log::debug(sprintf('Call finalAccountBalance(%s) with date/time "%s"', var_export($this->convertToPrimary, true), $date->toIso8601String()), $finalBalance);
// collect current balances: // collect current balances:
$currentBalance = Steam::bcround($finalBalance[$currency->code] ?? '0', $currency->decimal_places); $currentBalance = Steam::bcround($finalBalance[$currency->code] ?? '0', $currency->decimal_places);
$openingBalance = Steam::bcround($meta['opening_balance_amount'] ?? '0', $currency->decimal_places); $openingBalance = Steam::bcround($meta['opening_balance_amount'] ?? '0', $currency->decimal_places);
$virtualBalance = Steam::bcround($item->virtual_balance ?? '0', $currency->decimal_places); $virtualBalance = Steam::bcround($item->virtual_balance ?? '0', $currency->decimal_places);
$debtAmount = $meta['current_debt'] ?? null; $debtAmount = $meta['current_debt'] ?? null;
// set some pc_ default values to NULL: // set some pc_ default values to NULL:
$pcCurrentBalance = null; $pcCurrentBalance = null;
$pcOpeningBalance = null; $pcOpeningBalance = null;
$pcVirtualBalance = null; $pcVirtualBalance = null;
$pcDebtAmount = null; $pcDebtAmount = null;
$pcBalanceDifference = null; $pcBalanceDifference = null;
// convert to primary currency if needed: // convert to primary currency if needed:
if ($this->convertToPrimary && $currency->id !== $this->primaryCurrency->id) { if ($this->convertToPrimary && $currency->id !== $this->primaryCurrency->id) {
@@ -347,7 +351,7 @@ class AccountEnrichment implements EnrichmentInterface
'pc_balance_difference' => $pcBalanceDifference, 'pc_balance_difference' => $pcBalanceDifference,
]; ];
// end add balances // end add balances
$item->meta = $meta; $item->meta = $meta;
return $item; return $item;
}); });
@@ -369,12 +373,13 @@ class AccountEnrichment implements EnrichmentInterface
private function collectObjectGroups(): void private function collectObjectGroups(): void
{ {
$set = DB::table('object_groupables') $set = DB::table('object_groupables')
->whereIn('object_groupable_id', $this->ids) ->whereIn('object_groupable_id', $this->ids)
->where('object_groupable_type', Account::class) ->where('object_groupable_type', Account::class)
->get(['object_groupable_id', 'object_group_id']); ->get(['object_groupable_id', 'object_group_id'])
;
$ids = array_unique($set->pluck('object_group_id')->toArray()); $ids = array_unique($set->pluck('object_group_id')->toArray());
foreach ($set as $entry) { foreach ($set as $entry) {
$this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id; $this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id;
@@ -426,8 +431,8 @@ class AccountEnrichment implements EnrichmentInterface
if (0 === count($startBalance) || 0 === count($endBalance)) { if (0 === count($startBalance) || 0 === count($endBalance)) {
return null; return null;
} }
$start = $startBalance[$currency->code] ?? '0'; $start = $startBalance[$currency->code] ?? '0';
$end = $endBalance[$currency->code] ?? '0'; $end = $endBalance[$currency->code] ?? '0';
return bcsub($end, $start); return bcsub($end, $start);
} }
@@ -440,22 +445,25 @@ class AccountEnrichment implements EnrichmentInterface
private function sortData(): void private function sortData(): void
{ {
$dbParams = config('firefly.allowed_db_sort_parameters.Account', []); $dbParams = config('firefly.allowed_db_sort_parameters.Account', []);
/** @var array $parameter */ /** @var array $parameter */
foreach ($this->sort as $parameter) { foreach ($this->sort as $parameter) {
if (in_array($parameter[0], $dbParams, true)) { if (in_array($parameter[0], $dbParams, true)) {
continue; continue;
} }
switch ($parameter[0]) { switch ($parameter[0]) {
default: default:
throw new FireflyException(sprintf('Account enrichment cannot sort on field "%s"', $parameter[0])); throw new FireflyException(sprintf('Account enrichment cannot sort on field "%s"', $parameter[0]));
case 'current_balance': case 'current_balance':
case 'pc_current_balance': case 'pc_current_balance':
$this->collection = $this->collection->sortBy(static function (Account $account) use ($parameter) { $this->collection = $this->collection->sortBy(static function (Account $account) use ($parameter) {
return $account->meta['balances'][$parameter[0]] ?? '0'; return $account->meta['balances'][$parameter[0]] ?? '0';
}, SORT_NUMERIC, 'desc' === $parameter[1]); }, SORT_NUMERIC, 'desc' === $parameter[1]);
break; break;
} }
} }
} }
} }

View File

@@ -55,10 +55,9 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
private readonly OperationsRepositoryInterface $opsRepository; private readonly OperationsRepositoryInterface $opsRepository;
private readonly BudgetRepositoryInterface $repository; private readonly BudgetRepositoryInterface $repository;
public function __construct() public function __construct()
{ {
//$this->primaryCurrency = Amount::getPrimaryCurrency(); // $this->primaryCurrency = Amount::getPrimaryCurrency();
$this->convertToPrimary = Amount::convertToPrimary(); $this->convertToPrimary = Amount::convertToPrimary();
$this->noBudgetRepository = app(NoBudgetRepositoryInterface::class); $this->noBudgetRepository = app(NoBudgetRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class); $this->opsRepository = app(OperationsRepositoryInterface::class);

View File

@@ -30,10 +30,8 @@ use FireflyIII\Models\AutoBudget;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
use FireflyIII\Models\ObjectGroup; use FireflyIII\Models\ObjectGroup;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup; use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -56,9 +54,7 @@ class BudgetEnrichment implements EnrichmentInterface
private array $objectGroups = []; private array $objectGroups = [];
private array $mappedObjects = []; private array $mappedObjects = [];
public function __construct() public function __construct() {}
{
}
public function enrich(Collection $collection): Collection public function enrich(Collection $collection): Collection
{ {

View File

@@ -55,8 +55,8 @@ class PiggyBankEnrichment implements EnrichmentInterface
private array $mappedObjects = []; private array $mappedObjects = [];
private TransactionCurrency $primaryCurrency; private TransactionCurrency $primaryCurrency;
private array $amounts = []; private array $amounts = [];
private array $accounts= []; private array $accounts = [];
private array $objectGroups= []; private array $objectGroups = [];
public function __construct() public function __construct()
{ {

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;
use function Safe\json_decode;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Enums\RecurrenceRepetitionWeekend; use FireflyIII\Enums\RecurrenceRepetitionWeekend;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
@@ -53,11 +52,13 @@ use Illuminate\Support\Arr;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use function Safe\json_decode;
class RecurringEnrichment implements EnrichmentInterface 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 = [];
@@ -122,10 +123,10 @@ class RecurringEnrichment implements EnrichmentInterface
{ {
/** @var Recurrence $recurrence */ /** @var Recurrence $recurrence */
foreach ($this->collection as $recurrence) { foreach ($this->collection as $recurrence) {
$id = (int)$recurrence->id; $id = (int)$recurrence->id;
// $typeId = (int)$recurrence->transaction_type_id; // $typeId = (int)$recurrence->transaction_type_id;
$this->ids[] = $id; $this->ids[] = $id;
//$this->transactionTypeIds[$id] = $typeId; // $this->transactionTypeIds[$id] = $typeId;
} }
$this->ids = array_unique($this->ids); $this->ids = array_unique($this->ids);
@@ -146,7 +147,7 @@ class RecurringEnrichment implements EnrichmentInterface
/** @var RecurrenceRepetition $repetition */ /** @var RecurrenceRepetition $repetition */
foreach ($set as $repetition) { foreach ($set as $repetition) {
$recurrence = $this->collection->filter(fn(Recurrence $item) => (int)$item->id === (int)$repetition->recurrence_id)->first(); $recurrence = $this->collection->filter(fn (Recurrence $item) => (int)$item->id === (int)$repetition->recurrence_id)->first();
$fromDate = clone ($recurrence->latest_date ?? $recurrence->first_date); $fromDate = clone ($recurrence->latest_date ?? $recurrence->first_date);
$id = (int)$repetition->recurrence_id; $id = (int)$repetition->recurrence_id;
$repId = (int)$repetition->id; $repId = (int)$repetition->id;

View File

@@ -28,7 +28,6 @@ namespace FireflyIII\Support\JsonApi\Enrichments;
use Carbon\Carbon; use Carbon\Carbon;
use Carbon\CarbonInterface; use Carbon\CarbonInterface;
use Carbon\Exceptions\InvalidFormatException; use Carbon\Exceptions\InvalidFormatException;
use Carbon\Exceptions\ParseErrorException;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
use FireflyIII\Models\ObjectGroup; use FireflyIII\Models\ObjectGroup;
@@ -87,11 +86,11 @@ class SubscriptionEnrichment implements EnrichmentInterface
$paidDates = $this->paidDates; $paidDates = $this->paidDates;
$payDates = $this->payDates; $payDates = $this->payDates;
$this->collection = $this->collection->map(function (Bill $item) use ($notes, $objectGroups, $paidDates, $payDates) { $this->collection = $this->collection->map(function (Bill $item) use ($notes, $objectGroups, $paidDates, $payDates) {
$id = (int)$item->id; $id = (int)$item->id;
$currency = $item->transactionCurrency; $currency = $item->transactionCurrency;
$nem = $this->getNextExpectedMatch($payDates[$id] ?? []); $nem = $this->getNextExpectedMatch($payDates[$id] ?? []);
$meta = [ $meta = [
'notes' => null, 'notes' => null,
'object_group_id' => null, 'object_group_id' => null,
'object_group_title' => null, 'object_group_title' => null,
@@ -102,7 +101,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
'nem' => $nem, 'nem' => $nem,
'nem_diff' => $this->getNextExpectedMatchDiff($nem, $payDates[$id] ?? []), 'nem_diff' => $this->getNextExpectedMatchDiff($nem, $payDates[$id] ?? []),
]; ];
$amounts = [ $amounts = [
'amount_min' => Steam::bcround($item->amount_min, $currency->decimal_places), 'amount_min' => Steam::bcround($item->amount_min, $currency->decimal_places),
'amount_max' => Steam::bcround($item->amount_max, $currency->decimal_places), 'amount_max' => Steam::bcround($item->amount_max, $currency->decimal_places),
'average' => Steam::bcround(bcdiv(bcadd($item->amount_min, $item->amount_max), '2'), $currency->decimal_places), 'average' => Steam::bcround(bcdiv(bcadd($item->amount_min, $item->amount_max), '2'), $currency->decimal_places),
@@ -155,9 +154,10 @@ class SubscriptionEnrichment implements EnrichmentInterface
private function collectNotes(): void private function collectNotes(): void
{ {
$notes = Note::query()->whereIn('noteable_id', $this->subscriptionIds) $notes = Note::query()->whereIn('noteable_id', $this->subscriptionIds)
->whereNotNull('notes.text') ->whereNotNull('notes.text')
->where('notes.text', '!=', '') ->where('notes.text', '!=', '')
->where('noteable_type', Bill::class)->get(['notes.noteable_id', 'notes.text'])->toArray(); ->where('noteable_type', Bill::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
;
foreach ($notes as $note) { foreach ($notes as $note) {
$this->notes[(int)$note['noteable_id']] = (string)$note['text']; $this->notes[(int)$note['noteable_id']] = (string)$note['text'];
} }
@@ -186,12 +186,13 @@ class SubscriptionEnrichment implements EnrichmentInterface
private function collectObjectGroups(): void private function collectObjectGroups(): void
{ {
$set = DB::table('object_groupables') $set = DB::table('object_groupables')
->whereIn('object_groupable_id', $this->subscriptionIds) ->whereIn('object_groupable_id', $this->subscriptionIds)
->where('object_groupable_type', Bill::class) ->where('object_groupable_type', Bill::class)
->get(['object_groupable_id', 'object_group_id']); ->get(['object_groupable_id', 'object_group_id'])
;
$ids = array_unique($set->pluck('object_group_id')->toArray()); $ids = array_unique($set->pluck('object_group_id')->toArray());
foreach ($set as $entry) { foreach ($set as $entry) {
$this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id; $this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id;
@@ -219,13 +220,13 @@ class SubscriptionEnrichment implements EnrichmentInterface
// 2023-07-18 this particular date is used to search for the last paid date. // 2023-07-18 this particular date is used to search for the last paid date.
// 2023-07-18 the cloned $searchDate is used to grab the correct transactions. // 2023-07-18 the cloned $searchDate is used to grab the correct transactions.
/** @var Carbon $start */ /** @var Carbon $start */
$start = clone $this->start; $start = clone $this->start;
$searchStart = clone $start; $searchStart = clone $start;
$start->subDay(); $start->subDay();
/** @var Carbon $end */ /** @var Carbon $end */
$end = clone $this->end; $end = clone $this->end;
$searchEnd = clone $end; $searchEnd = clone $end;
// move the search dates to the start of the day. // move the search dates to the start of the day.
$searchStart->startOfDay(); $searchStart->startOfDay();
@@ -234,13 +235,13 @@ class SubscriptionEnrichment implements EnrichmentInterface
Log::debug(sprintf('Search parameters are: start: %s, end: %s', $searchStart->format('Y-m-d H:i:s'), $searchEnd->format('Y-m-d H:i:s'))); Log::debug(sprintf('Search parameters are: start: %s, end: %s', $searchStart->format('Y-m-d H:i:s'), $searchEnd->format('Y-m-d H:i:s')));
// Get from database when bills were paid. // Get from database when bills were paid.
$set = $this->user->transactionJournals() $set = $this->user->transactionJournals()
->whereIn('bill_id', $this->subscriptionIds) ->whereIn('bill_id', $this->subscriptionIds)
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('transaction_currencies AS currency', 'currency.id', '=', 'transactions.transaction_currency_id') ->leftJoin('transaction_currencies AS currency', 'currency.id', '=', 'transactions.transaction_currency_id')
->leftJoin('transaction_currencies AS foreign_currency', 'foreign_currency.id', '=', 'transactions.foreign_currency_id') ->leftJoin('transaction_currencies AS foreign_currency', 'foreign_currency.id', '=', 'transactions.foreign_currency_id')
->where('transactions.amount', '>', 0) ->where('transactions.amount', '>', 0)
->before($searchEnd)->after($searchStart)->get( ->before($searchEnd)->after($searchStart)->get(
[ [
'transaction_journals.id', 'transaction_journals.id',
'transaction_journals.date', 'transaction_journals.date',
@@ -257,26 +258,27 @@ class SubscriptionEnrichment implements EnrichmentInterface
'transactions.amount', 'transactions.amount',
'transactions.foreign_amount', 'transactions.foreign_amount',
] ]
); )
;
Log::debug(sprintf('Count %d entries in set', $set->count())); Log::debug(sprintf('Count %d entries in set', $set->count()));
// for each bill, do a loop. // for each bill, do a loop.
$converter = new ExchangeRateConverter(); $converter = new ExchangeRateConverter();
/** @var Bill $subscription */ /** @var Bill $subscription */
foreach ($this->collection as $subscription) { foreach ($this->collection as $subscription) {
// Grab from array the most recent payment. If none exist, fall back to the start date and pretend *that* was the last paid date. // Grab from array the most recent payment. If none exist, fall back to the start date and pretend *that* was the last paid date.
Log::debug(sprintf('Grab last paid date from function, return %s if it comes up with nothing.', $start->format('Y-m-d'))); Log::debug(sprintf('Grab last paid date from function, return %s if it comes up with nothing.', $start->format('Y-m-d')));
$lastPaidDate = $this->lastPaidDate($subscription, $set, $start); $lastPaidDate = $this->lastPaidDate($subscription, $set, $start);
Log::debug(sprintf('Result of lastPaidDate is %s', $lastPaidDate->format('Y-m-d'))); Log::debug(sprintf('Result of lastPaidDate is %s', $lastPaidDate->format('Y-m-d')));
// At this point the "next match" is exactly after the last time the bill was paid. // At this point the "next match" is exactly after the last time the bill was paid.
$result = []; $result = [];
$filtered = $set->filter(function (TransactionJournal $journal) use ($subscription) { $filtered = $set->filter(function (TransactionJournal $journal) use ($subscription) {
return (int)$journal->bill_id === (int)$subscription->id; return (int)$journal->bill_id === (int)$subscription->id;
}); });
foreach ($filtered as $entry) { foreach ($filtered as $entry) {
$array = [ $array = [
'transaction_group_id' => (string)$entry->transaction_group_id, 'transaction_group_id' => (string)$entry->transaction_group_id,
'transaction_journal_id' => (string)$entry->id, 'transaction_journal_id' => (string)$entry->id,
'date' => $entry->date->toAtomString(), 'date' => $entry->date->toAtomString(),
@@ -352,7 +354,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
return $default; return $default;
} }
$latest = $filtered->first()->date; $latest = $filtered->first()->date;
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
foreach ($filtered as $journal) { foreach ($filtered as $journal) {
@@ -398,12 +400,12 @@ class SubscriptionEnrichment implements EnrichmentInterface
/** @var Bill $subscription */ /** @var Bill $subscription */
foreach ($this->collection as $subscription) { foreach ($this->collection as $subscription) {
$id = (int)$subscription->id; $id = (int)$subscription->id;
$lastPaidDate = $this->getLastPaidDate($this->paidDates[$id] ?? []); $lastPaidDate = $this->getLastPaidDate($this->paidDates[$id] ?? []);
$payDates = $this->calculator->getPayDates($this->start, $this->end, $subscription->date, $subscription->repeat_freq, $subscription->skip, $lastPaidDate); $payDates = $this->calculator->getPayDates($this->start, $this->end, $subscription->date, $subscription->repeat_freq, $subscription->skip, $lastPaidDate);
$payDatesFormatted = []; $payDatesFormatted = [];
foreach ($payDates as $string) { foreach ($payDates as $string) {
$date = Carbon::createFromFormat('!Y-m-d', $string, config('app.timezone')); $date = Carbon::createFromFormat('!Y-m-d', $string, config('app.timezone'));
if (!$date instanceof Carbon) { if (!$date instanceof Carbon) {
$date = today(config('app.timezone')); $date = today(config('app.timezone'));
} }

View File

@@ -57,7 +57,7 @@ class Preferences
; ;
} }
public function get(string $name, null|array|bool|int|string $default = null): ?Preference public function get(string $name, array|bool|int|string|null $default = null): ?Preference
{ {
/** @var null|User $user */ /** @var null|User $user */
$user = auth()->user(); $user = auth()->user();
@@ -71,7 +71,7 @@ class Preferences
return $this->getForUser($user, $name, $default); return $this->getForUser($user, $name, $default);
} }
public function getForUser(User $user, string $name, null|array|bool|int|string $default = null): ?Preference public function getForUser(User $user, string $name, array|bool|int|string|null $default = null): ?Preference
{ {
// Log::debug(sprintf('getForUser(#%d, "%s")', $user->id, $name)); // Log::debug(sprintf('getForUser(#%d, "%s")', $user->id, $name));
// don't care about user group ID, except for some specific preferences. // don't care about user group ID, except for some specific preferences.
@@ -135,7 +135,7 @@ class Preferences
Cache::put($key, '', 5); Cache::put($key, '', 5);
} }
public function setForUser(User $user, string $name, null|array|bool|int|string $value): Preference public function setForUser(User $user, string $name, array|bool|int|string|null $value): Preference
{ {
$fullName = sprintf('preference%s%s', $user->id, $name); $fullName = sprintf('preference%s%s', $user->id, $name);
$userGroupId = $this->getUserGroupId($user, $name); $userGroupId = $this->getUserGroupId($user, $name);
@@ -240,7 +240,7 @@ class Preferences
return $result; return $result;
} }
public function getEncryptedForUser(User $user, string $name, null|array|bool|int|string $default = null): ?Preference public function getEncryptedForUser(User $user, string $name, array|bool|int|string|null $default = null): ?Preference
{ {
$result = $this->getForUser($user, $name, $default); $result = $this->getForUser($user, $name, $default);
if ('' === $result->data) { if ('' === $result->data) {
@@ -265,7 +265,7 @@ class Preferences
return $result; return $result;
} }
public function getFresh(string $name, null|array|bool|int|string $default = null): ?Preference public function getFresh(string $name, array|bool|int|string|null $default = null): ?Preference
{ {
/** @var null|User $user */ /** @var null|User $user */
$user = auth()->user(); $user = auth()->user();
@@ -313,7 +313,7 @@ class Preferences
Session::forget('first'); Session::forget('first');
} }
public function set(string $name, null|array|bool|int|string $value): Preference public function set(string $name, array|bool|int|string|null $value): Preference
{ {
/** @var null|User $user */ /** @var null|User $user */
$user = auth()->user(); $user = auth()->user();

View File

@@ -37,7 +37,7 @@ interface UserGroupInterface
public function getUserGroup(): ?UserGroup; public function getUserGroup(): ?UserGroup;
public function setUser(null|Authenticatable|User $user): void; public function setUser(Authenticatable|User|null $user): void;
public function setUserGroup(UserGroup $userGroup): void; public function setUserGroup(UserGroup $userGroup): void;

View File

@@ -61,7 +61,7 @@ trait UserGroupTrait
/** /**
* @throws FireflyException * @throws FireflyException
*/ */
public function setUser(null|Authenticatable|User $user): void public function setUser(Authenticatable|User|null $user): void
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -31,6 +31,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use function Safe\preg_replace; use function Safe\preg_replace;
/** /**
@@ -105,14 +106,15 @@ trait ConvertsDataTypes
$parts = explode(',', $parameter); $parts = explode(',', $parameter);
$sortParameters = []; $sortParameters = [];
foreach ($parts as $part) { foreach ($parts as $part) {
$part = trim($part); $part = trim($part);
$direction = 'asc'; $direction = 'asc';
if ('-' === $part[0]) { if ('-' === $part[0]) {
$part = substr($part, 1); $part = substr($part, 1);
$direction = 'desc'; $direction = 'desc';
} }
$sortParameters[] = [$part, $direction]; $sortParameters[] = [$part, $direction];
} }
return $sortParameters; return $sortParameters;
} }
@@ -434,7 +436,7 @@ trait ConvertsDataTypes
if (!is_array($entry)) { if (!is_array($entry)) {
continue; continue;
} }
$amount = null; $amount = null;
if (array_key_exists('current_amount', $entry)) { if (array_key_exists('current_amount', $entry)) {
$amount = $this->clearString((string)($entry['current_amount'] ?? '0')); $amount = $this->clearString((string)($entry['current_amount'] ?? '0'));
if (null === $entry['current_amount']) { if (null === $entry['current_amount']) {

View File

@@ -137,7 +137,7 @@ class AccountSearch implements GenericSearchInterface
$this->types = $types; $this->types = $types;
} }
public function setUser(null|Authenticatable|User $user): void public function setUser(Authenticatable|User|null $user): void
{ {
if ($user instanceof User) { if ($user instanceof User) {
$this->user = $user; $this->user = $user;

View File

@@ -116,9 +116,10 @@ class AmountFormat extends AbstractExtension
'formatAmountBySymbol', 'formatAmountBySymbol',
static function (string $amount, ?string $symbol, ?int $decimalPlaces = null, ?bool $coloured = null): string { static function (string $amount, ?string $symbol, ?int $decimalPlaces = null, ?bool $coloured = null): string {
if(null === $symbol) { if (null === $symbol) {
$message = sprintf('formatAmountBySymbol("%s", %s, %d, %s) was called without a symbol. Please browse to /flush to clear your cache.', $amount,var_export($symbol, true), $decimalPlaces, var_export($coloured, true)); $message = sprintf('formatAmountBySymbol("%s", %s, %d, %s) was called without a symbol. Please browse to /flush to clear your cache.', $amount, var_export($symbol, true), $decimalPlaces, var_export($coloured, true));
Log::error($message); Log::error($message);
throw new FireflyException($message); throw new FireflyException($message);
} }

View File

@@ -38,6 +38,7 @@ use Override;
use Twig\Extension\AbstractExtension; use Twig\Extension\AbstractExtension;
use Twig\TwigFilter; use Twig\TwigFilter;
use Twig\TwigFunction; use Twig\TwigFunction;
use function Safe\parse_url; use function Safe\parse_url;
/** /**
@@ -70,14 +71,14 @@ class General extends AbstractExtension
} }
/** @var Carbon $date */ /** @var Carbon $date */
$date = session('end', today(config('app.timezone'))->endOfMonth()); $date = session('end', today(config('app.timezone'))->endOfMonth());
Log::debug(sprintf('twig balance: Call finalAccountBalance with date/time "%s"', $date->toIso8601String())); Log::debug(sprintf('twig balance: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$info = Steam::finalAccountBalance($account, $date); $info = Steam::finalAccountBalance($account, $date);
$currency = Steam::getAccountCurrency($account); $currency = Steam::getAccountCurrency($account);
$primary = Amount::getPrimaryCurrency(); $primary = Amount::getPrimaryCurrency();
$convertToPrimary = Amount::convertToPrimary(); $convertToPrimary = Amount::convertToPrimary();
$usePrimary = $convertToPrimary && $primary->id !== $currency->id; $usePrimary = $convertToPrimary && $primary->id !== $currency->id;
$currency ??= $primary; $currency ??= $primary;
$strings = []; $strings = [];
foreach ($info as $key => $balance) { foreach ($info as $key => $balance) {
if ('balance' === $key) { if ('balance' === $key) {
@@ -118,15 +119,15 @@ class General extends AbstractExtension
static function (int $size): string { static function (int $size): string {
// less than one GB, more than one MB // less than one GB, more than one MB
if ($size < (1024 * 1024 * 2014) && $size >= (1024 * 1024)) { if ($size < (1024 * 1024 * 2014) && $size >= (1024 * 1024)) {
return round($size / (1024 * 1024), 2) . ' MB'; return round($size / (1024 * 1024), 2).' MB';
} }
// less than one MB // less than one MB
if ($size < (1024 * 1024)) { if ($size < (1024 * 1024)) {
return round($size / 1024, 2) . ' KB'; return round($size / 1024, 2).' KB';
} }
return $size . ' bytes'; return $size.' bytes';
} }
); );
} }
@@ -140,7 +141,7 @@ class General extends AbstractExtension
{ {
return new TwigFilter( return new TwigFilter(
'mimeIcon', 'mimeIcon',
static fn(string $string): string => match ($string) { static fn (string $string): string => match ($string) {
'application/pdf' => 'fa-file-pdf-o', 'application/pdf' => 'fa-file-pdf-o',
'image/webp', 'image/png', 'image/jpeg', 'image/svg+xml', 'image/heic', 'image/heic-sequence', 'application/vnd.oasis.opendocument.image' => 'fa-file-image-o', 'image/webp', 'image/png', 'image/jpeg', 'image/svg+xml', 'image/heic', 'image/heic-sequence', 'application/vnd.oasis.opendocument.image' => 'fa-file-image-o',
'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'application/x-iwork-pages-sffpages', 'application/vnd.sun.xml.writer', 'application/vnd.sun.xml.writer.template', 'application/vnd.sun.xml.writer.global', 'application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.text-template', 'application/vnd.oasis.opendocument.text-web', 'application/vnd.oasis.opendocument.text-master' => 'fa-file-word-o', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'application/x-iwork-pages-sffpages', 'application/vnd.sun.xml.writer', 'application/vnd.sun.xml.writer.template', 'application/vnd.sun.xml.writer.global', 'application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.text-template', 'application/vnd.oasis.opendocument.text-web', 'application/vnd.oasis.opendocument.text-master' => 'fa-file-word-o',
@@ -213,7 +214,7 @@ class General extends AbstractExtension
{ {
return new TwigFunction( return new TwigFunction(
'phpdate', 'phpdate',
static fn(string $str): string => date($str) static fn (string $str): string => date($str)
); );
} }
@@ -269,7 +270,7 @@ class General extends AbstractExtension
'activeRoutePartialObjectType', 'activeRoutePartialObjectType',
static function ($context): string { static function ($context): string {
[, $route, $objectType] = func_get_args(); [, $route, $objectType] = func_get_args();
$activeObjectType = $context['objectType'] ?? false; $activeObjectType = $context['objectType'] ?? false;
if ($objectType === $activeObjectType if ($objectType === $activeObjectType
&& false !== stripos( && false !== stripos(
@@ -375,7 +376,7 @@ class General extends AbstractExtension
{ {
return new TwigFunction( return new TwigFunction(
'carbonize', 'carbonize',
static fn(string $date): Carbon => new Carbon($date, config('app.timezone')) static fn (string $date): Carbon => new Carbon($date, config('app.timezone'))
); );
} }
} }

62
composer.lock generated
View File

@@ -129,25 +129,25 @@
}, },
{ {
"name": "brick/math", "name": "brick/math",
"version": "0.13.1", "version": "0.14.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/brick/math.git", "url": "https://github.com/brick/math.git",
"reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04" "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/fc7ed316430118cc7836bf45faff18d5dfc8de04", "url": "https://api.github.com/repos/brick/math/zipball/113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2",
"reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04", "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^8.1" "php": "^8.2"
}, },
"require-dev": { "require-dev": {
"php-coveralls/php-coveralls": "^2.2", "php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^10.1", "phpstan/phpstan": "2.1.22",
"vimeo/psalm": "6.8.8" "phpunit/phpunit": "^11.5"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -177,7 +177,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/brick/math/issues", "issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.13.1" "source": "https://github.com/brick/math/tree/0.14.0"
}, },
"funding": [ "funding": [
{ {
@@ -185,7 +185,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-03-29T13:50:30+00:00" "time": "2025-08-29T12:40:03+00:00"
}, },
{ {
"name": "carbonphp/carbon-doctrine-types", "name": "carbonphp/carbon-doctrine-types",
@@ -3714,16 +3714,16 @@
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "3.10.2", "version": "3.10.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/CarbonPHP/carbon.git", "url": "https://github.com/CarbonPHP/carbon.git",
"reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
"reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3741,13 +3741,13 @@
"require-dev": { "require-dev": {
"doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/dbal": "^3.6.3 || ^4.0",
"doctrine/orm": "^2.15.2 || ^3.0", "doctrine/orm": "^2.15.2 || ^3.0",
"friendsofphp/php-cs-fixer": "^3.75.0", "friendsofphp/php-cs-fixer": "^v3.87.1",
"kylekatarnls/multi-tester": "^2.5.3", "kylekatarnls/multi-tester": "^2.5.3",
"phpmd/phpmd": "^2.15.0", "phpmd/phpmd": "^2.15.0",
"phpstan/extension-installer": "^1.4.3", "phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan": "^2.1.17", "phpstan/phpstan": "^2.1.22",
"phpunit/phpunit": "^10.5.46", "phpunit/phpunit": "^10.5.53",
"squizlabs/php_codesniffer": "^3.13.0" "squizlabs/php_codesniffer": "^3.13.4"
}, },
"bin": [ "bin": [
"bin/carbon" "bin/carbon"
@@ -3815,7 +3815,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-08-02T09:36:06+00:00" "time": "2025-09-06T13:39:36+00:00"
}, },
{ {
"name": "nette/schema", "name": "nette/schema",
@@ -5751,20 +5751,20 @@
}, },
{ {
"name": "ramsey/uuid", "name": "ramsey/uuid",
"version": "4.9.0", "version": "4.9.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/ramsey/uuid.git", "url": "https://github.com/ramsey/uuid.git",
"reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0" "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/4e0e23cc785f0724a0e838279a9eb03f28b092a0", "url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440",
"reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0", "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13", "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
"php": "^8.0", "php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0" "ramsey/collection": "^1.2 || ^2.0"
}, },
@@ -5823,9 +5823,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/ramsey/uuid/issues", "issues": "https://github.com/ramsey/uuid/issues",
"source": "https://github.com/ramsey/uuid/tree/4.9.0" "source": "https://github.com/ramsey/uuid/tree/4.9.1"
}, },
"time": "2025-06-25T14:20:11+00:00" "time": "2025-09-04T20:59:21+00:00"
}, },
{ {
"name": "rcrowe/twigbridge", "name": "rcrowe/twigbridge",
@@ -11924,16 +11924,16 @@
}, },
{ {
"name": "rector/rector", "name": "rector/rector",
"version": "2.1.5", "version": "2.1.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/rectorphp/rector.git", "url": "https://github.com/rectorphp/rector.git",
"reference": "1cd6abfb5976fd4ed728d5b73ebd67c7c810cd88" "reference": "729aabc0ec66e700ef164e26454a1357f222a2f3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/rectorphp/rector/zipball/1cd6abfb5976fd4ed728d5b73ebd67c7c810cd88", "url": "https://api.github.com/repos/rectorphp/rector/zipball/729aabc0ec66e700ef164e26454a1357f222a2f3",
"reference": "1cd6abfb5976fd4ed728d5b73ebd67c7c810cd88", "reference": "729aabc0ec66e700ef164e26454a1357f222a2f3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -11972,7 +11972,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/rectorphp/rector/issues", "issues": "https://github.com/rectorphp/rector/issues",
"source": "https://github.com/rectorphp/rector/tree/2.1.5" "source": "https://github.com/rectorphp/rector/tree/2.1.6"
}, },
"funding": [ "funding": [
{ {
@@ -11980,7 +11980,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-09-04T14:19:07+00:00" "time": "2025-09-05T15:43:08+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",

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-09-02', 'version' => 'develop/2025-09-07',
'build_time' => 1756787029, 'build_time' => 1757224461,
'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,
@@ -407,7 +407,7 @@ return [
], ],
'rule-actions' => [ 'rule-actions' => [
'set_category' => SetCategory::class, 'set_category' => SetCategory::class,
'clear_category' => ClearCategory::class, 'clear_category' => ClearCategory::class,
'set_budget' => SetBudget::class, 'set_budget' => SetBudget::class,
@@ -441,7 +441,7 @@ return [
// 'set_foreign_amount' => SetForeignAmount::class, // 'set_foreign_amount' => SetForeignAmount::class,
// 'set_foreign_currency' => SetForeignCurrency::class, // 'set_foreign_currency' => SetForeignCurrency::class,
], ],
'context-rule-actions' => [ 'context-rule-actions' => [
'set_category', 'set_category',
'set_budget', 'set_budget',
'add_tag', 'add_tag',
@@ -460,13 +460,13 @@ return [
'convert_transfer', 'convert_transfer',
], ],
'test-triggers' => [ 'test-triggers' => [
'limit' => 10, 'limit' => 10,
'range' => 200, 'range' => 200,
], ],
// expected source types for each transaction type, in order of preference. // expected source types for each transaction type, in order of preference.
'expected_source_types' => [ 'expected_source_types' => [
'source' => [ 'source' => [
TransactionTypeEnum::WITHDRAWAL->value => [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value], TransactionTypeEnum::WITHDRAWAL->value => [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value],
TransactionTypeEnum::DEPOSIT->value => [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::REVENUE->value, AccountTypeEnum::CASH->value], TransactionTypeEnum::DEPOSIT->value => [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::REVENUE->value, AccountTypeEnum::CASH->value],
@@ -511,7 +511,7 @@ return [
TransactionTypeEnum::LIABILITY_CREDIT->value => [AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value], TransactionTypeEnum::LIABILITY_CREDIT->value => [AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value],
], ],
], ],
'allowed_opposing_types' => [ 'allowed_opposing_types' => [
'source' => [ 'source' => [
AccountTypeEnum::ASSET->value => [ AccountTypeEnum::ASSET->value => [
AccountTypeEnum::ASSET->value, AccountTypeEnum::ASSET->value,
@@ -601,7 +601,7 @@ return [
], ],
], ],
// depending on the account type, return the allowed transaction types: // depending on the account type, return the allowed transaction types:
'allowed_transaction_types' => [ 'allowed_transaction_types' => [
'source' => [ 'source' => [
AccountTypeEnum::ASSET->value => [ AccountTypeEnum::ASSET->value => [
TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::WITHDRAWAL->value,
@@ -670,7 +670,7 @@ return [
], ],
// having the source + dest will tell you the transaction type. // having the source + dest will tell you the transaction type.
'account_to_transaction' => [ 'account_to_transaction' => [
AccountTypeEnum::ASSET->value => [ AccountTypeEnum::ASSET->value => [
AccountTypeEnum::ASSET->value => TransactionTypeEnum::TRANSFER->value, AccountTypeEnum::ASSET->value => TransactionTypeEnum::TRANSFER->value,
AccountTypeEnum::CASH->value => TransactionTypeEnum::WITHDRAWAL->value, AccountTypeEnum::CASH->value => TransactionTypeEnum::WITHDRAWAL->value,
@@ -735,7 +735,7 @@ return [
], ],
// allowed source -> destination accounts. // allowed source -> destination accounts.
'source_dests' => [ 'source_dests' => [
TransactionTypeEnum::WITHDRAWAL->value => [ TransactionTypeEnum::WITHDRAWAL->value => [
AccountTypeEnum::ASSET->value => [AccountTypeEnum::EXPENSE->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::CASH->value], AccountTypeEnum::ASSET->value => [AccountTypeEnum::EXPENSE->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::CASH->value],
AccountTypeEnum::LOAN->value => [AccountTypeEnum::EXPENSE->value, AccountTypeEnum::CASH->value], AccountTypeEnum::LOAN->value => [AccountTypeEnum::EXPENSE->value, AccountTypeEnum::CASH->value],
@@ -774,7 +774,7 @@ return [
], ],
], ],
// if you add fields to this array, don't forget to update the export routine (ExportDataGenerator). // if you add fields to this array, don't forget to update the export routine (ExportDataGenerator).
'journal_meta_fields' => [ 'journal_meta_fields' => [
// sepa // sepa
'sepa_cc', 'sepa_cc',
'sepa_ct_op', 'sepa_ct_op',
@@ -808,47 +808,47 @@ return [
'recurrence_count', 'recurrence_count',
'recurrence_date', 'recurrence_date',
], ],
'webhooks' => [ 'webhooks' => [
'max_attempts' => env('WEBHOOK_MAX_ATTEMPTS', 3), 'max_attempts' => env('WEBHOOK_MAX_ATTEMPTS', 3),
], ],
'can_have_virtual_amounts' => [AccountTypeEnum::ASSET->value], 'can_have_virtual_amounts' => [AccountTypeEnum::ASSET->value],
'can_have_opening_balance' => [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value], 'can_have_opening_balance' => [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value],
'dynamic_creation_allowed' => [ 'dynamic_creation_allowed' => [
AccountTypeEnum::EXPENSE->value, AccountTypeEnum::EXPENSE->value,
AccountTypeEnum::REVENUE->value, AccountTypeEnum::REVENUE->value,
AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::INITIAL_BALANCE->value,
AccountTypeEnum::RECONCILIATION->value, AccountTypeEnum::RECONCILIATION->value,
AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::LIABILITY_CREDIT->value,
], ],
'valid_asset_fields' => ['account_role', 'account_number', 'currency_id', 'BIC', 'include_net_worth'], 'valid_asset_fields' => ['account_role', 'account_number', 'currency_id', 'BIC', 'include_net_worth'],
'valid_cc_fields' => ['account_role', 'cc_monthly_payment_date', 'cc_type', 'account_number', 'currency_id', 'BIC', 'include_net_worth'], 'valid_cc_fields' => ['account_role', 'cc_monthly_payment_date', 'cc_type', 'account_number', 'currency_id', 'BIC', 'include_net_worth'],
'valid_account_fields' => ['account_number', 'currency_id', 'BIC', 'interest', 'interest_period', 'include_net_worth', 'liability_direction'], 'valid_account_fields' => ['account_number', 'currency_id', 'BIC', 'interest', 'interest_period', 'include_net_worth', 'liability_direction'],
// dynamic date ranges are as follows: // dynamic date ranges are as follows:
'dynamic_date_ranges' => ['last7', 'last30', 'last90', 'last365', 'MTD', 'QTD', 'YTD'], 'dynamic_date_ranges' => ['last7', 'last30', 'last90', 'last365', 'MTD', 'QTD', 'YTD'],
'allowed_sort_parameters' => [ 'allowed_sort_parameters' => [
'Account' => ['id', 'order', 'name', 'iban', 'active', 'account_type_id', 'Account' => ['id', 'order', 'name', 'iban', 'active', 'account_type_id',
'current_balance', 'current_balance',
'pc_current_balance', 'pc_current_balance',
'opening_balance', 'opening_balance',
'pc_opening_balance', 'pc_opening_balance',
'virtual_balance', 'virtual_balance',
'pc_virtual_balance', 'pc_virtual_balance',
'debt_amount', 'debt_amount',
'pc_debt_amount', 'pc_debt_amount',
'balance_difference', 'balance_difference',
'pc_balance_difference', 'pc_balance_difference',
], ],
], ],
'allowed_db_sort_parameters' => [ 'allowed_db_sort_parameters' => [
'Account' => ['id', 'order', 'name', 'iban', 'active', 'account_type_id'], 'Account' => ['id', 'order', 'name', 'iban', 'active', 'account_type_id'],
], ],
// preselected account lists possibilities: // preselected account lists possibilities:
'preselected_accounts' => ['all', 'assets', 'liabilities'], 'preselected_accounts' => ['all', 'assets', 'liabilities'],
// allowed to store a piggy bank in: // allowed to store a piggy bank in:
'piggy_bank_account_types' => [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value], 'piggy_bank_account_types' => [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value],
]; ];

229
package-lock.json generated
View File

@@ -13,20 +13,6 @@
"postcss": "^8.4.47" "postcss": "^8.4.47"
} }
}, },
"node_modules/@ampproject/remapping": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.27.1", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
@@ -43,9 +29,9 @@
} }
}, },
"node_modules/@babel/compat-data": { "node_modules/@babel/compat-data": {
"version": "7.28.0", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz",
"integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -53,22 +39,22 @@
} }
}, },
"node_modules/@babel/core": { "node_modules/@babel/core": {
"version": "7.28.3", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
"integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1", "@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3", "@babel/generator": "^7.28.3",
"@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-compilation-targets": "^7.27.2",
"@babel/helper-module-transforms": "^7.28.3", "@babel/helper-module-transforms": "^7.28.3",
"@babel/helpers": "^7.28.3", "@babel/helpers": "^7.28.4",
"@babel/parser": "^7.28.3", "@babel/parser": "^7.28.4",
"@babel/template": "^7.27.2", "@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.3", "@babel/traverse": "^7.28.4",
"@babel/types": "^7.28.2", "@babel/types": "^7.28.4",
"@jridgewell/remapping": "^2.3.5",
"convert-source-map": "^2.0.0", "convert-source-map": "^2.0.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",
@@ -402,27 +388,27 @@
} }
}, },
"node_modules/@babel/helpers": { "node_modules/@babel/helpers": {
"version": "7.28.3", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
"integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/template": "^7.27.2", "@babel/template": "^7.27.2",
"@babel/types": "^7.28.2" "@babel/types": "^7.28.4"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.28.3", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
"integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.28.2" "@babel/types": "^7.28.4"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@@ -693,9 +679,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-block-scoping": { "node_modules/@babel/plugin-transform-block-scoping": {
"version": "7.28.0", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz",
"integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", "integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -743,9 +729,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-classes": { "node_modules/@babel/plugin-transform-classes": {
"version": "7.28.3", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.3.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz",
"integrity": "sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==", "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -754,7 +740,7 @@
"@babel/helper-globals": "^7.28.0", "@babel/helper-globals": "^7.28.0",
"@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1",
"@babel/helper-replace-supers": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1",
"@babel/traverse": "^7.28.3" "@babel/traverse": "^7.28.4"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1147,9 +1133,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-object-rest-spread": { "node_modules/@babel/plugin-transform-object-rest-spread": {
"version": "7.28.0", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz",
"integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1157,7 +1143,7 @@
"@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1",
"@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-destructuring": "^7.28.0",
"@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-parameters": "^7.27.7",
"@babel/traverse": "^7.28.0" "@babel/traverse": "^7.28.4"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1284,9 +1270,9 @@
} }
}, },
"node_modules/@babel/plugin-transform-regenerator": { "node_modules/@babel/plugin-transform-regenerator": {
"version": "7.28.3", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.3.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz",
"integrity": "sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==", "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1622,9 +1608,9 @@
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.28.3", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
"integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1646,18 +1632,18 @@
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.28.3", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz",
"integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.27.1", "@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3", "@babel/generator": "^7.28.3",
"@babel/helper-globals": "^7.28.0", "@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.28.3", "@babel/parser": "^7.28.4",
"@babel/template": "^7.27.2", "@babel/template": "^7.27.2",
"@babel/types": "^7.28.2", "@babel/types": "^7.28.4",
"debug": "^4.3.1" "debug": "^4.3.1"
}, },
"engines": { "engines": {
@@ -1665,9 +1651,9 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.28.2", "version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
"integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -2149,9 +2135,9 @@
} }
}, },
"node_modules/@fortawesome/fontawesome-free": { "node_modules/@fortawesome/fontawesome-free": {
"version": "7.0.0", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.0.0.tgz", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.0.1.tgz",
"integrity": "sha512-X48nISrSOa89zu2VMljC4XaRf8NmgTwQBVHfS2Nu5G00ZwM31oOVrAtGxZF3b6wDYf9lJsf/Eq4cCSFKIkOWPQ==", "integrity": "sha512-RLmb9U6H2rJDnGxEqXxzy7ANPrQz7WK2/eTjdZqyU9uRU5W+FkAec9uU5gTYzFBH7aoXIw2WTJSCJR4KPlReQw==",
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
@@ -2181,6 +2167,17 @@
"@jridgewell/trace-mapping": "^0.3.24" "@jridgewell/trace-mapping": "^0.3.24"
} }
}, },
"node_modules/@jridgewell/remapping": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": { "node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
@@ -3162,9 +3159,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "24.3.0", "version": "24.3.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz",
"integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3270,57 +3267,57 @@
} }
}, },
"node_modules/@vue/compiler-core": { "node_modules/@vue/compiler-core": {
"version": "3.5.20", "version": "3.5.21",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.20.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.21.tgz",
"integrity": "sha512-8TWXUyiqFd3GmP4JTX9hbiTFRwYHgVL/vr3cqhr4YQ258+9FADwvj7golk2sWNGHR67QgmCZ8gz80nQcMokhwg==", "integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.28.3", "@babel/parser": "^7.28.3",
"@vue/shared": "3.5.20", "@vue/shared": "3.5.21",
"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.20", "version": "3.5.21",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.20.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz",
"integrity": "sha512-whB44M59XKjqUEYOMPYU0ijUV0G+4fdrHVKDe32abNdX/kJe1NUEMqsi4cwzXa9kyM9w5S8WqFsrfo1ogtBZGQ==", "integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-core": "3.5.20", "@vue/compiler-core": "3.5.21",
"@vue/shared": "3.5.20" "@vue/shared": "3.5.21"
} }
}, },
"node_modules/@vue/compiler-sfc": { "node_modules/@vue/compiler-sfc": {
"version": "3.5.20", "version": "3.5.21",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.20.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz",
"integrity": "sha512-SFcxapQc0/feWiSBfkGsa1v4DOrnMAQSYuvDMpEaxbpH5dKbnEM5KobSNSgU+1MbHCl+9ftm7oQWxvwDB6iBfw==", "integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==",
"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.20", "@vue/compiler-core": "3.5.21",
"@vue/compiler-dom": "3.5.20", "@vue/compiler-dom": "3.5.21",
"@vue/compiler-ssr": "3.5.20", "@vue/compiler-ssr": "3.5.21",
"@vue/shared": "3.5.20", "@vue/shared": "3.5.21",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"magic-string": "^0.30.17", "magic-string": "^0.30.18",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
} }
}, },
"node_modules/@vue/compiler-ssr": { "node_modules/@vue/compiler-ssr": {
"version": "3.5.20", "version": "3.5.21",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.20.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz",
"integrity": "sha512-RSl5XAMc5YFUXpDQi+UQDdVjH9FnEpLDHIALg5J0ITHxkEzJ8uQLlo7CIbjPYqmZtt6w0TsIPbo1izYXwDG7JA==", "integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-dom": "3.5.20", "@vue/compiler-dom": "3.5.21",
"@vue/shared": "3.5.20" "@vue/shared": "3.5.21"
} }
}, },
"node_modules/@vue/component-compiler-utils": { "node_modules/@vue/component-compiler-utils": {
@@ -3402,9 +3399,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vue/shared": { "node_modules/@vue/shared": {
"version": "3.5.20", "version": "3.5.21",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.20.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.21.tgz",
"integrity": "sha512-SoRGP596KU/ig6TfgkCMbXkr4YJ91n/QSdMuqeP5r3hVIYA3CPHUBCc7Skak0EAKV+5lL4KyIh61VA/pK1CIAA==", "integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -3755,9 +3752,9 @@
} }
}, },
"node_modules/alpinejs": { "node_modules/alpinejs": {
"version": "3.14.9", "version": "3.15.0",
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.14.9.tgz", "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.0.tgz",
"integrity": "sha512-gqSOhTEyryU9FhviNqiHBHzgjkvtukq9tevew29fTj+ofZtfsYriw4zPirHHOAy9bw8QoL3WGhyk7QqCh5AYlw==", "integrity": "sha512-lpokA5okCF1BKh10LG8YjqhfpxyHBk4gE7boIgVHltJzYoM7O9nK3M7VlntLEJGsVmu7U/RzUWajmHREGT38Eg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/reactivity": "~3.1.1" "@vue/reactivity": "~3.1.1"
@@ -4500,9 +4497,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001739", "version": "1.0.30001741",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001739.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz",
"integrity": "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==", "integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -5714,9 +5711,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.211", "version": "1.5.214",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.211.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.214.tgz",
"integrity": "sha512-IGBvimJkotaLzFnwIVgW9/UD/AOJ2tByUmeOrtqBfACSbAw5b1G0XpvdaieKyc7ULmbwXVx+4e4Be8pOPBrYkw==", "integrity": "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@@ -7066,9 +7063,9 @@
} }
}, },
"node_modules/i18next": { "node_modules/i18next": {
"version": "25.4.2", "version": "25.5.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.4.2.tgz", "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.5.2.tgz",
"integrity": "sha512-gD4T25a6ovNXsfXY1TwHXXXLnD/K2t99jyYMCSimSCBnBRJVQr5j+VAaU83RJCPzrTGhVQ6dqIga66xO2rtd5g==", "integrity": "sha512-lW8Zeh37i/o0zVr+NoCHfNnfvVw+M6FQbRp36ZZ/NyHDJ3NJVpp2HhAUyU9WafL5AssymNoOjMRB48mmx2P6Hw==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@@ -8442,9 +8439,9 @@
} }
}, },
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.19", "version": "2.0.20",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.20.tgz",
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "integrity": "sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -10229,9 +10226,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.91.0", "version": "1.92.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.91.0.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.92.1.tgz",
"integrity": "sha512-aFOZHGf+ur+bp1bCHZ+u8otKGh77ZtmFyXDo4tlYvT7PWql41Kwd8wdkPqhhT+h2879IVblcHFglIMofsFd1EA==", "integrity": "sha512-ffmsdbwqb3XeyR8jJR6KelIXARM9bFQe8A6Q3W4Klmwy5Ckd5gz7jgUNHo4UOqutU5Sk1DtKLbpDP0nLCg1xqQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -11034,14 +11031,14 @@
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.43.1", "version": "5.44.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz",
"integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.3", "@jridgewell/source-map": "^0.3.3",
"acorn": "^8.14.0", "acorn": "^8.15.0",
"commander": "^2.20.0", "commander": "^2.20.0",
"source-map-support": "~0.5.20" "source-map-support": "~0.5.20"
}, },
@@ -11172,14 +11169,14 @@
} }
}, },
"node_modules/tinyglobby": { "node_modules/tinyglobby": {
"version": "0.2.14", "version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fdir": "^6.4.4", "fdir": "^6.5.0",
"picomatch": "^4.0.2" "picomatch": "^4.0.3"
}, },
"engines": { "engines": {
"node": ">=12.0.0" "node": ">=12.0.0"