Compare commits

...

13 Commits

Author SHA1 Message Date
github-actions[bot]
a2b611253b Merge pull request #11029 from firefly-iii/release-1759908132
🤖 Automatically merge the PR into the develop branch.
2025-10-08 09:22:23 +02:00
JC5
252459c29b 🤖 Auto commit for release 'develop' on 2025-10-08 2025-10-08 09:22:12 +02:00
James Cole
b03ecab035 Move to another method here as well. 2025-10-08 09:17:56 +02:00
James Cole
62e33a51bd Better order for method arguments. 2025-10-08 08:54:26 +02:00
James Cole
8b0ee7e20a Support multi-currency accounts better, matches the old method. 2025-10-08 08:12:30 +02:00
James Cole
0e0ec89b26 Remove all uses of "finalAccountBalance", move towards one function to rule them all. 2025-10-08 07:09:42 +02:00
James Cole
ec08485c2b Clean up some code surrounding account balances. 2025-10-08 06:44:48 +02:00
James Cole
d91d30c8f0 Remove some debug logging, use Facade. 2025-10-08 06:31:47 +02:00
James Cole
634a43c361 Merge branch 'main' into develop 2025-10-08 06:31:34 +02:00
James Cole
f2f86e1139 Merge pull request #11024 from ctrl-f5/feat/improve-date-handling
improved balance range date handling
2025-10-08 06:30:56 +02:00
Nicky De Maeyer
a1c870c962 improved request and balance range date handling 2025-10-07 20:30:11 +02:00
github-actions[bot]
98be3a1414 Merge pull request #11023 from firefly-iii/release-1759860049
🤖 Automatically merge the PR into the develop branch.
2025-10-07 20:00:56 +02:00
JC5
e3c3a0a84b 🤖 Auto commit for release 'develop' on 2025-10-07 2025-10-07 20:00:49 +02:00
26 changed files with 224 additions and 237 deletions

View File

@@ -84,7 +84,7 @@ class AccountController extends Controller
$data = $request->getData();
$types = $data['types'];
$query = $data['query'];
$date = $data['date'] ?? today(config('app.timezone'));
$date = $data['date'];
$return = [];
$timer = Timer::getInstance();
$timer->start(sprintf('AC accounts "%s"', $query));

View File

@@ -589,8 +589,6 @@ class BasicController extends Controller
private function getNetWorthInfo(Carbon $end): array
{
$end->endOfDay();
/** @var User $user */
$user = auth()->user();
Log::debug(sprintf('getNetWorthInfo up until "%s".', $end->format('Y-m-d H:i:s')));

View File

@@ -48,10 +48,12 @@ class AutocompleteRequest extends FormRequest
// remove 'initial balance' from allowed types. its internal
$array = array_diff($array, [AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::RECONCILIATION->value]);
$date = $this->getCarbonDate('date') ?? today(config('app.timezone'));
return [
'types' => $array,
'query' => $this->convertString('query'),
'date' => $this->getCarbonDate('date'),
'date' => $date->endOfDay(),
];
}

View File

@@ -55,7 +55,6 @@ class DateRequest extends FormRequest
// sanity check on dates:
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
$start->startOfDay();
$end->endOfDay();
if ($start->diffInYears($end, true) > 5) {

View File

@@ -137,9 +137,12 @@ class MonthReportGenerator implements ReportGeneratorInterface
;
$journals = $collector->getExtractedJournals();
$journals = array_reverse($journals, true);
// this call is correct.
Log::debug(sprintf('getAuditReport: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$dayBeforeBalance = Steam::finalAccountBalance($account, $date);
Log::debug(sprintf('getAuditReport: Call accountsBalancesOptimized with date/time "%s"', $date->toIso8601String()));
// 2025-10-08 replace with accountsBalancesOptimized.
// $dayBeforeBalance = Steam::finalAccountBalance($account, $date);
$dayBeforeBalance = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id];
$startBalance = $dayBeforeBalance['balance'];
$primaryCurrency = app('amount')->getPrimaryCurrencyByUserGroup($account->user->userGroup);
$currency = $accountRepository->getAccountCurrency($account) ?? $primaryCurrency;
@@ -176,12 +179,14 @@ class MonthReportGenerator implements ReportGeneratorInterface
// call is correct.
Log::debug(sprintf('getAuditReport end: Call finalAccountBalance with date/time "%s"', $this->end->toIso8601String()));
// 2025-10-08 replace with accountsBalancesOptimized:
return [
'journals' => $journals,
'currency' => $currency,
'exists' => 0 !== count($journals),
'end' => $this->end->isoFormat((string) trans('config.month_and_day_moment_js', [], $locale)),
'endBalance' => Steam::finalAccountBalance($account, $this->end)['balance'],
// 'endBalance' => Steam::finalAccountBalance($account, $this->end)['balance'],
'endBalance' => Steam::accountsBalancesOptimized(new Collection()->push($account), $this->end)[$account->id]['balance'],
'dayBefore' => $date->isoFormat((string) trans('config.month_and_day_moment_js', [], $locale)),
'dayBeforeBalance' => $dayBeforeBalance,
];

View File

@@ -62,12 +62,13 @@ trait AccountCollection
if (null === $account) {
continue;
}
// 2025-10-08 replace with accountsBalancesOptimized
// the balance must be found BEFORE the transaction date.
// so sub one second. This is not perfect, but works well enough.
$date = clone $transaction['date'];
$date->subSecond();
Log::debug(sprintf('accountBalanceIs: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = Steam::finalAccountBalance($account, $date);
// so inclusive = false
Log::debug(sprintf('accountBalanceIs: Call accountsBalancesOptimized with date/time "%s"', $transaction['date']->toIso8601String()));
$balance = Steam::accountsBalancesOptimized(new Collection()->push($account), $transaction['date'], convertToPrimary: null, inclusive: false)[$account->id];
// $balance = Steam::finalAccountBalance($account, $date);
$result = bccomp((string) $balance['balance'], $value);
Log::debug(sprintf('"%s" vs "%s" is %d', $balance['balance'], $value, $result));

View File

@@ -25,8 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
use Deprecated;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\UserGroup;
@@ -130,55 +128,4 @@ class NetWorth implements NetWorthInterface
$this->accountRepository->setUserGroup($userGroup);
}
#[Deprecated]
public function sumNetWorthByCurrency(Carbon $date): array
{
/**
* Collect accounts
*/
$accounts = $this->getAccounts();
$return = [];
Log::debug(sprintf('SumNetWorth: accountsBalancesOptimized("%s")', $date->format('Y-m-d H:i:s')));
$balances = Steam::accountsBalancesOptimized($accounts, $date);
foreach ($accounts as $account) {
$currency = $this->accountRepository->getAccountCurrency($account);
$balance = $balances[$account->id]['balance'] ?? '0';
// always subtract virtual balance.
$virtualBalance = $account->virtual_balance;
if ('' !== $virtualBalance) {
$balance = bcsub($balance, (string) $virtualBalance);
}
$return[$currency->id] ??= [
'id' => (string) $currency->id,
'name' => $currency->name,
'symbol' => $currency->symbol,
'code' => $currency->code,
'decimal_places' => $currency->decimal_places,
'sum' => '0',
];
$return[$currency->id]['sum'] = bcadd($return[$currency->id]['sum'], (string) $balance);
}
return $return;
}
private function getAccounts(): Collection
{
$accounts = $this->accountRepository->getAccountsByType(
[AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value]
);
$filtered = new Collection();
/** @var Account $account */
foreach ($accounts as $account) {
if (1 === (int) $this->accountRepository->getMetaValue($account, 'include_net_worth')) {
$filtered->push($account);
}
}
return $filtered;
}
}

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
use Deprecated;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
@@ -49,12 +48,4 @@ interface NetWorthInterface
public function setUser(Authenticatable|User|null $user): void;
public function setUserGroup(UserGroup $userGroup): void;
/**
* TODO move to repository
*
* Same as above but cleaner function with less dependencies.
*/
#[Deprecated]
public function sumNetWorthByCurrency(Carbon $date): array;
}

View File

@@ -74,32 +74,30 @@ class IndexController extends Controller
*/
public function inactive(Request $request, string $objectType)
{
$inactivePage = true;
$subTitle = (string) trans(sprintf('firefly.%s_accounts_inactive', $objectType));
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
$types = config(sprintf('firefly.accountTypesByIdentifier.%s', $objectType));
$collection = $this->repository->getInactiveAccountsByType($types);
$total = $collection->count();
$page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$accounts = $collection->slice(($page - 1) * $pageSize, $pageSize);
$inactivePage = true;
$subTitle = (string) trans(sprintf('firefly.%s_accounts_inactive', $objectType));
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
$types = config(sprintf('firefly.accountTypesByIdentifier.%s', $objectType));
$collection = $this->repository->getInactiveAccountsByType($types);
$total = $collection->count();
$page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$accounts = $collection->slice(($page - 1) * $pageSize, $pageSize);
unset($collection);
/** @var Carbon $start */
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
/** @var Carbon $end */
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
// #10618 go to the end of the previous day.
$start->subSecond();
$ids = $accounts->pluck('id')->toArray();
Log::debug(sprintf('inactive start: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
Log::debug(sprintf('inactive end: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
$startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
$endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
$activities = Steam::getLastActivities($ids);
$ids = $accounts->pluck('id')->toArray();
Log::debug(sprintf('inactive start: accountsBalancesInRange("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
[
$startBalances,
$endBalances,
] = Steam::accountsBalancesInRange($accounts, $start, $end, $this->primaryCurrency, $this->convertToPrimary);
$activities = Steam::getLastActivities($ids);
$accounts->each(
@@ -119,7 +117,7 @@ class IndexController extends Controller
);
// make paginator:
$accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page);
$accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page);
$accounts->setPath(route('accounts.inactive.index', [$objectType]));
return view('accounts.index', compact('objectType', 'inactivePage', 'subTitleIcon', 'subTitle', 'page', 'accounts'));
@@ -169,14 +167,12 @@ class IndexController extends Controller
/** @var Carbon $end */
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
// #10618 go to the end of the previous day.
$start->subSecond();
$ids = $accounts->pluck('id')->toArray();
Log::debug(sprintf('index start: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
Log::debug(sprintf('index end: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
$startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
$endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
Log::debug(sprintf('index: accountsBalancesInRange("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
[
$startBalances,
$endBalances,
] = Steam::accountsBalancesInRange($accounts, $start, $end, $this->primaryCurrency, $this->convertToPrimary);
$activities = Steam::getLastActivities($ids);

View File

@@ -39,6 +39,7 @@ use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
@@ -113,13 +114,20 @@ class ReconcileController extends Controller
$start->startOfDay();
$end->endOfDay();
$startDate = clone $start;
$startDate->subDay()->endOfDay(); // this is correct, subday endofday ends at 23:59:59
// $startDate = clone $start;
// $startDate->subDay()->endOfDay(); // this is correct, subday endofday ends at 23:59:59
// both are validated and are correct.
Log::debug(sprintf('reconcile: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
Log::debug(sprintf('reconcile2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
$startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
$endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
// Log::debug(sprintf('reconcile: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
// Log::debug(sprintf('reconcile2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
// $startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
// $endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
// 2025-10-08 replace with accountsBalancesOptimized
// no longer need to do subday->endofday on $start, set inclusive = false for the same effect.
$startBalance = Steam::bcround(Steam::accountsBalancesOptimized(new Collection()->push($account), $start, convertToPrimary: null, inclusive: false)[$account->id]['balance'], $currency->decimal_places);
$endBalance = Steam::bcround(Steam::accountsBalancesOptimized(new Collection()->push($account), $end)[$account->id]['balance'], $currency->decimal_places);
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);

View File

@@ -169,8 +169,9 @@ class ShowController extends Controller
$now = $end;
}
Log::debug(sprintf('show: Call finalAccountBalance with date/time "%s"', $now->toIso8601String()));
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToPrimary, $accountCurrency);
// 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
$balances = Steam::accountsBalancesOptimized(new Collection()->push($account), $now)[$account->id];
// $balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToPrimary, $accountCurrency);
return view(
'accounts.show',
@@ -237,8 +238,12 @@ class ShowController extends Controller
$chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
$showAll = true;
// correct
Log::debug(sprintf('showAll: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
$balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToPrimary, $accountCurrency);
Log::debug(sprintf('showAll: Call accountsBalancesOptimized with date/time "%s"', $end->toIso8601String()));
// 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
// $balances = Steam::finalAccountBalance($account, $end);
// $balances = Steam::filterAccountBalance($balances, $account, $this->convertToPrimary, $accountCurrency);
$balances = Steam::accountsBalancesOptimized(new Collection()->push($account), $end)[$account->id];
return view(
'accounts.show',

View File

@@ -116,10 +116,11 @@ class AccountController extends Controller
$accountNames = $this->extractNames($accounts);
// grab all balances
Log::debug(sprintf('expenseAccounts: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
Log::debug(sprintf('expenseAccounts: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
$startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
$endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
Log::debug(sprintf('expenseAccounts: accountsBalancesInRange("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
[
$startBalances,
$endBalances,
] = Steam::accountsBalancesInRange($accounts, $start, $end, $this->primaryCurrency, $this->convertToPrimary);
Log::debug('Done collecting balances');
// loop the accounts, then check for balance and currency info.
foreach ($accounts as $account) {
@@ -521,9 +522,9 @@ class AccountController extends Controller
$range = Steam::filterAccountBalances($range, $account, $this->convertToPrimary, $accountCurrency);
Log::debug('Get and filter balance for entire range end');
// temp, get end balance.
Log::debug(sprintf('period: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
Steam::finalAccountBalance($account, $end);
Log::debug('END temp get end balance done');
// Log::debug(sprintf('period: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
// Steam::finalAccountBalance($account, $end);
// Log::debug('END temp get end balance done');
$previous = array_values($range)[0];
$accountCurrency ??= $this->primaryCurrency; // do this AFTER getting the balances.
@@ -666,10 +667,11 @@ class AccountController extends Controller
$accountNames = $this->extractNames($accounts);
// grab all balances
Log::debug(sprintf('revAccounts: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
Log::debug(sprintf('revAccounts: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
$startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
$endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
Log::debug(sprintf('revAccounts: accountsBalancesInRange("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
[
$startBalances,
$endBalances,
] = Steam::accountsBalancesInRange($accounts, $start, $end, $this->primaryCurrency, $this->convertToPrimary);
// loop the accounts, then check for balance and currency info.

View File

@@ -38,6 +38,7 @@ use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\DateCalculation;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class BoxController.
@@ -165,7 +166,7 @@ class BoxController extends Controller
$allAccounts = $accountRepository->getActiveAccountsByType(
[AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value]
);
app('log')->debug(sprintf('Found %d accounts.', $allAccounts->count()));
Log::debug(sprintf('Found %d accounts.', $allAccounts->count()));
// filter list on preference of being included.
$filtered = $allAccounts->filter(
@@ -173,7 +174,7 @@ class BoxController extends Controller
$includeNetWorth = $accountRepository->getMetaValue($account, 'include_net_worth');
$result = null === $includeNetWorth || '1' === $includeNetWorth;
if (false === $result) {
app('log')->debug(sprintf('Will not include "%s" in net worth charts.', $account->name));
Log::debug(sprintf('Will not include "%s" in net worth charts.', $account->name));
}
return $result;

View File

@@ -197,10 +197,16 @@ class ReconcileController extends Controller
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->primaryCurrency;
// correct
Log::debug(sprintf('transactions: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
Log::debug(sprintf('transactions2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
$startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
$endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
Log::debug(sprintf('transactions: Call accountsBalancesOptimized with date/time "%s"', $startDate->toIso8601String()));
Log::debug(sprintf('transactions2: Call accountsBalancesOptimized with date/time "%s"', $end->toIso8601String()));
// 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized
// $startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
// $endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
$startBalance = Steam::accountsBalancesOptimized(new Collection()->push($account), $startDate)[$account->id];
$endBalance = Steam::accountsBalancesOptimized(new Collection()->push($account), $end)[$account->id];
// get the transactions
$selectionStart = clone $start;

View File

@@ -37,6 +37,7 @@ use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Services\Internal\Update\JournalUpdateService;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\ModelInformation;
use FireflyIII\Transformers\TransactionGroupTransformer;
@@ -45,6 +46,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
@@ -228,11 +230,13 @@ class ConvertController extends Controller
foreach ($accountList as $account) {
$date = today()->endOfDay();
Log::debug(sprintf('getLiabilities: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = Steam::finalAccountBalance($account, $date)['balance'];
// 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
// $balance = Steam::finalAccountBalance($account, $date)['balance'];
$balance = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id]['balance'] ?? '0';
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->primaryCurrency;
$role = 'l_'.$account->accountType->type;
$key = (string) trans('firefly.opt_group_'.$role);
$grouped[$key][$account->id] = $account->name.' ('.app('amount')->formatAnything($currency, $balance, false).')';
$role = sprintf('l_%s', $account->accountType->type);
$key = (string) trans(sprintf('firefly.opt_group_%s', $role));
$grouped[$key][$account->id] = sprintf('%s (%s)', $account->name, Amount::formatAnything($currency, $balance, false));
}
return $grouped;
@@ -252,15 +256,18 @@ class ConvertController extends Controller
foreach ($accountList as $account) {
$date = today()->endOfDay();
Log::debug(sprintf('getAssetAccounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = Steam::finalAccountBalance($account, $date)['balance'];
// 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
// $balance = Steam::finalAccountBalance($account, $date)['balance'];
$balance = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id]['balance'] ?? '0';
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->primaryCurrency;
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
if ('' === $role) {
$role = 'no_account_type';
}
$key = (string) trans('firefly.opt_group_'.$role);
$grouped[$key][$account->id] = $account->name.' ('.app('amount')->formatAnything($currency, $balance, false).')';
$key = (string) trans(sprintf('firefly.opt_group_%s', $role));
$grouped[$key][$account->id] = sprintf('%s (%s)', $account->name, Amount::formatAnything($currency, $balance, false));
}
return $grouped;

View File

@@ -50,10 +50,11 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
$yesterday = clone $start;
$yesterday->subDay()->endOfDay(); // exactly up until $start but NOT including.
$end->endOfDay(); // needs to be end of day to be correct.
Log::debug(sprintf('getAccountReport: accountsBalancesOptimized("%s")', $yesterday->format('Y-m-d H:i:s')));
Log::debug(sprintf('getAccountReport: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
$startSet = Steam::accountsBalancesOptimized($accounts, $yesterday);
$endSet = Steam::accountsBalancesOptimized($accounts, $end);
Log::debug(sprintf('getAccountReport: accountsBalancesInRange("%s", "%s")', $yesterday->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
[
$startSet,
$endSet,
] = Steam::accountsBalancesInRange($accounts, $yesterday, $end);
Log::debug('Start of accountreport');
/** @var AccountRepositoryInterface $repository */

View File

@@ -375,7 +375,9 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
{
Log::debug(sprintf('leftOnAccount("%s","%s","%s")', $piggyBank->name, $account->name, $date->format('Y-m-d H:i:s')));
Log::debug(sprintf('leftOnAccount: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$balance = Steam::finalAccountBalance($account, $date)['balance'];
// 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
$balance = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id];
// $balance = Steam::finalAccountBalance($account, $date)['balance'];
Log::debug(sprintf('Balance is: %s', $balance));

View File

@@ -49,14 +49,14 @@ class RemoteUserGuard implements Guard
{
/** @var null|Request $request */
$request = $app->get('request');
Log::debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri()));
// Log::debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri()));
$this->application = $app;
$this->user = null;
}
public function authenticate(): void
{
Log::debug(sprintf('Now at %s', __METHOD__));
// Log::debug(sprintf('Now at %s', __METHOD__));
if ($this->user instanceof User) {
Log::debug(sprintf('%s is found: #%d, "%s".', $this->user::class, $this->user->id, $this->user->email));
@@ -104,21 +104,21 @@ class RemoteUserGuard implements Guard
public function check(): bool
{
Log::debug(sprintf('Now at %s', __METHOD__));
// Log::debug(sprintf('Now at %s', __METHOD__));
return $this->user() instanceof User;
}
public function guest(): bool
{
Log::debug(sprintf('Now at %s', __METHOD__));
// Log::debug(sprintf('Now at %s', __METHOD__));
return !$this->check();
}
public function hasUser(): bool
{
Log::debug(sprintf('Now at %s', __METHOD__));
// Log::debug(sprintf('Now at %s', __METHOD__));
throw new FireflyException('Did not implement RemoteUserGuard::hasUser()');
}
@@ -128,14 +128,14 @@ class RemoteUserGuard implements Guard
*/
public function id(): int|string|null
{
Log::debug(sprintf('Now at %s', __METHOD__));
// Log::debug(sprintf('Now at %s', __METHOD__));
return $this->user?->id;
}
public function setUser(Authenticatable|User|null $user): void // @phpstan-ignore-line
{
Log::debug(sprintf('Now at %s', __METHOD__));
// Log::debug(sprintf('Now at %s', __METHOD__));
if ($user instanceof User) {
$this->user = $user;
@@ -146,7 +146,7 @@ class RemoteUserGuard implements Guard
public function user(): ?User
{
Log::debug(sprintf('Now at %s', __METHOD__));
// Log::debug(sprintf('Now at %s', __METHOD__));
$user = $this->user;
if (!$user instanceof User) {
Log::debug('User is NULL');
@@ -164,14 +164,14 @@ class RemoteUserGuard implements Guard
*/
public function validate(array $credentials = []): bool
{
Log::debug(sprintf('Now at %s', __METHOD__));
// Log::debug(sprintf('Now at %s', __METHOD__));
throw new FireflyException('Did not implement RemoteUserGuard::validate()');
}
public function viaRemember(): bool
{
Log::debug(sprintf('Now at %s', __METHOD__));
// Log::debug(sprintf('Now at %s', __METHOD__));
return false;
}

View File

@@ -289,8 +289,10 @@ class AccountEnrichment implements EnrichmentInterface
{
$this->balances = Steam::accountsBalancesOptimized($this->collection, $this->getDate(), $this->primaryCurrency, $this->convertToPrimary);
if ($this->start instanceof Carbon && $this->end instanceof Carbon) {
$this->startBalances = Steam::accountsBalancesOptimized($this->collection, $this->start, $this->primaryCurrency, $this->convertToPrimary);
$this->endBalances = Steam::accountsBalancesOptimized($this->collection, $this->end, $this->primaryCurrency, $this->convertToPrimary);
[
$this->startBalances,
$this->endBalances,
] = Steam::accountsBalancesInRange($this->collection, $this->start, $this->end, $this->primaryCurrency, $this->convertToPrimary);
}
}

View File

@@ -402,21 +402,21 @@ trait ConvertsDataTypes
*/
protected function getCarbonDate(string $field): ?Carbon
{
$result = null;
$data = (string)$this->get($field);
Log::debug(sprintf('Date string is "%s"', $data));
Log::debug(sprintf('Date string is "%s"', (string)$this->get($field)));
if ('' === $data) {
return null;
}
try {
$result = '' !== (string)$this->get($field) ? new Carbon((string)$this->get($field), config('app.timezone')) : null;
return new Carbon($data, config('app.timezone'));
} catch (InvalidFormatException) {
// @ignoreException
Log::debug(sprintf('Exception when parsing date "%s".', $this->get($field)));
}
if (!$result instanceof Carbon) {
Log::debug(sprintf('Exception when parsing date "%s".', $this->get($field)));
Log::debug(sprintf('Exception when parsing date "%s".', $data));
}
return $result;
return null;
}
/**

View File

@@ -49,9 +49,9 @@ use function Safe\preg_replace;
*/
class Steam
{
public function accountsBalancesOptimized(Collection $accounts, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array
public function accountsBalancesOptimized(Collection $accounts, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null, bool $inclusive = true): array
{
Log::debug(sprintf('accountsBalancesOptimized: Called for %d account(s) with date/time "%s"', $accounts->count(), $date->toIso8601String()));
Log::debug(sprintf('accountsBalancesOptimized: Called for %d account(s) with date/time "%s" (inclusive: %s)', $accounts->count(), $date->toIso8601String(), var_export($inclusive, true)));
$result = [];
$convertToPrimary ??= Amount::convertToPrimary();
$primary ??= Amount::getPrimaryCurrency();
@@ -61,14 +61,15 @@ class Steam
$arrayOfSums = Transaction::whereIn('account_id', $accounts->pluck('id')->toArray())
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
->where('transaction_journals.date', $inclusive ? '<=' : '<', $date->format('Y-m-d H:i:s'))
->groupBy(['transactions.account_id', 'transaction_currencies.code'])
->get(['transactions.account_id', 'transaction_currencies.code', DB::raw('SUM(transactions.amount) as sum_of_amount')])->toArray()
;
Log::debug('Array of sums: ', $arrayOfSums);
/** @var Account $account */
foreach ($accounts as $account) {
// this array is PER account, so we wait a bit before we change code here.
$return = [
'pc_balance' => '0',
'balance' => '0', // this key is overwritten right away, but I must remember it is always created.
@@ -76,19 +77,19 @@ class Steam
$currency = $currencies[$account->id];
// second array
$accountSum = array_filter($arrayOfSums, fn ($entry) => $entry['account_id'] === $account->id);
if (0 === count($accountSum)) {
$accountSums = array_filter($arrayOfSums, fn ($entry) => $entry['account_id'] === $account->id);
if (0 === count($accountSums)) {
$result[$account->id] = $return;
continue;
}
$accountSum = array_values($accountSum)[0];
$sumOfAmount = (string)$accountSum['sum_of_amount'];
$sumOfAmount = $this->floatalize('' === $sumOfAmount ? '0' : $sumOfAmount);
$sumsByCode = [
$accountSum['code'] => $sumOfAmount,
];
$sumsByCode = [];
foreach ($accountSums as $accountSum) {
// $accountSum = array_values($accountSum)[0];
$sumOfAmount = (string)$accountSum['sum_of_amount'];
$sumOfAmount = $this->floatalize('' === $sumOfAmount ? '0' : $sumOfAmount);
$sumsByCode[$accountSum['code']] = $sumOfAmount;
}
// Log::debug('All balances are (joined)', $others);
// if there is no request to convert, take this as "balance" and "pc_balance".
$return['balance'] = $sumsByCode[$currency->code] ?? '0';
@@ -96,6 +97,7 @@ class Steam
unset($return['pc_balance']);
// Log::debug(sprintf('Set balance to %s, unset pc_balance', $return['balance']));
}
// if there is a request to convert, convert to "pc_balance" and use "balance" for whichever amount is in the primary currency.
if ($convertToPrimary) {
$return['pc_balance'] = $this->convertAllBalances($sumsByCode, $primary, $date);
@@ -119,12 +121,23 @@ class Steam
}
$final = array_merge($return, $sumsByCode);
$result[$account->id] = $final;
// Log::debug('Final balance is', $final);
Log::debug(sprintf('Final balance for account #%d is', $account->id), $final);
}
return $result;
}
/**
* Calls accountsBalancesOptimized for the given accounts and makes sure that inclusive is set to false, so it properly gets the balance of a range.
*/
public function accountsBalancesInRange(Collection $accounts, Carbon $start, Carbon $end, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array
{
return [
$this->accountsBalancesOptimized($accounts, $start, $primary, $convertToPrimary, inclusive: false),
$this->accountsBalancesOptimized($accounts, $end, $primary, $convertToPrimary),
];
}
/**
* https://stackoverflow.com/questions/1642614/how-to-ceil-floor-and-round-bcmath-numbers
*/
@@ -276,7 +289,9 @@ class Steam
}
/**
* Returns smaller than or equal to, so be careful with END OF DAY.
* @deprecated
* By default this method returns "smaller than or equal to", so be careful with END OF DAY.
* If you need end of day balance, use "inclusive = false".
*
* Returns the balance of an account at exact moment given. Array with at least one value.
* Always returns:
@@ -288,18 +303,17 @@ class Steam
* --> "pc_balance": balance in the user's primary currency, with all amounts converted to the primary currency.
* "EUR": balance in EUR (or whatever currencies the account has balance in)
*/
public function finalAccountBalance(Account $account, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array
public function finalAccountBalance(Account $account, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null, bool $inclusive = true): array
{
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty($date);
if ($cache->has()) {
Log::debug(sprintf('CACHED finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
Log::debug(sprintf('CACHED finalAccountBalance(#%d, %s, inclusive:%s)', $account->id, $date->format('Y-m-d H:i:s'), var_export($inclusive, true)));
// return $cache->get();
}
// Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
if (null === $convertToPrimary) {
$convertToPrimary = Amount::convertToPrimary($account->user);
}
@@ -312,7 +326,6 @@ class Steam
$accountCurrency = $account->meta['currency'];
}
if (!$currencyPresent) {
$accountCurrency = $this->getAccountCurrency($account);
}
$hasCurrency = null !== $accountCurrency;
@@ -325,11 +338,11 @@ class Steam
$array = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
->where('transaction_journals.date', $inclusive ? '<=' : '<', $date->format('Y-m-d H:i:s'))
->get(['transaction_currencies.code', 'transactions.amount'])->toArray()
;
$others = $this->groupAndSumTransactions($array, 'code', 'amount');
// Log::debug('All balances are (joined)', $others);
Log::debug('All balances are (joined)', $others);
// if there is no request to convert, take this as "balance" and "pc_balance".
$return['balance'] = $others[$currency->code] ?? '0';
if (!$convertToPrimary) {
@@ -338,7 +351,7 @@ class Steam
}
// if there is a request to convert, convert to "pc_balance" and use "balance" for whichever amount is in the primary currency.
if ($convertToPrimary) {
$return['pc_balance'] = $this->convertAllBalances($others, $primary, $date); // todo sum all and convert.
$return['pc_balance'] = $this->convertAllBalances($others, $primary, $date);
// Log::debug(sprintf('Set pc_balance to %s', $return['pc_balance']));
}
@@ -358,18 +371,21 @@ class Steam
// Log::debug(sprintf('Virtual balance makes the (primary currency) total %s', $return['balance']));
}
$final = array_merge($return, $others);
// Log::debug('Final balance is', $final);
Log::debug('Final balance is', $final);
$cache->store($final);
return $final;
}
/**
* Returns the balance for the given account in the range, with daily precision.
*/
public function finalAccountBalanceInRange(Account $account, Carbon $start, Carbon $end, bool $convertToPrimary): array
{
// expand period.
$start->startOfDay();
$end->endOfDay();
Log::debug(sprintf('finalAccountBalanceInRange(#%d, %s, %s)', $account->id, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
Log::debug(sprintf('called finalAccountBalanceInRange(#%d, %s, %s)', $account->id, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// set up cache
$cache = new CacheProperties();
@@ -379,28 +395,21 @@ class Steam
$cache->addProperty($convertToPrimary);
$cache->addProperty($end);
if ($cache->has()) {
return $cache->get();
Log::debug('Return cached finalAccountBalanceInRange');
// return $cache->get();
}
$balances = [];
$formatted = $start->format('Y-m-d');
/*
* To make sure the start balance is correct, we need to get the balance at the exact end of the previous day.
* Since we just did "startOfDay" we can do subDay()->endOfDay() to get the correct moment.
* THAT will be the start balance.
*/
$request = clone $start;
$request->subDay()->endOfDay();
Log::debug('Get first balance to start.');
Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String()));
$startBalance = $this->finalAccountBalance($account, $request);
// 2025-10-08 replaced finalAccountBalance with accountsBalancesOptimized:
$primaryCurrency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup);
$startBalance = $this->accountsBalancesOptimized(new Collection()->push($account), $start, $primaryCurrency, $convertToPrimary, false)[$account->id];
$accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = $accountCurrency instanceof TransactionCurrency;
$currency = $accountCurrency ?? $primaryCurrency;
Log::debug(sprintf('Currency is %s', $currency->code));
// set start balances:
$startBalance[$currency->code] ??= '0';
if ($hasCurrency) {
@@ -542,7 +551,7 @@ class Steam
try {
$hostName = gethostbyaddr($ipAddress);
} catch (Exception $e) {
app('log')->error($e->getMessage());
Log::error($e->getMessage());
$hostName = $ipAddress;
}
@@ -757,7 +766,7 @@ class Steam
$current = $converter->convert($currency, $primary, $date, $amount);
Log::debug(sprintf('Convert %s %s to %s %s', $currency->code, $amount, $primary->code, $current));
}
$total = bcadd((string) $current, $total);
$total = bcadd((string)$current, $total);
}
return $total;

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Support\System;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Crypt;
@@ -63,10 +64,10 @@ class OAuthKeys
$privateKey = '';
$publicKey = '';
// better check if keys are in the database:
if (app('fireflyconfig')->has(self::PRIVATE_KEY) && app('fireflyconfig')->has(self::PUBLIC_KEY)) {
if (FireflyConfig::has(self::PRIVATE_KEY) && FireflyConfig::has(self::PUBLIC_KEY)) {
try {
$privateKey = (string)app('fireflyconfig')->get(self::PRIVATE_KEY)?->data;
$publicKey = (string)app('fireflyconfig')->get(self::PUBLIC_KEY)?->data;
$privateKey = (string)FireflyConfig::get(self::PRIVATE_KEY)?->data;
$publicKey = (string)FireflyConfig::get(self::PUBLIC_KEY)?->data;
} catch (ContainerExceptionInterface|FireflyException|NotFoundExceptionInterface $e) {
app('log')->error(sprintf('Could not validate keysInDatabase(): %s', $e->getMessage()));
app('log')->error($e->getTraceAsString());
@@ -87,8 +88,8 @@ class OAuthKeys
*/
public static function restoreKeysFromDB(): bool
{
$privateKey = (string)app('fireflyconfig')->get(self::PRIVATE_KEY)?->data;
$publicKey = (string)app('fireflyconfig')->get(self::PUBLIC_KEY)?->data;
$privateKey = (string)FireflyConfig::get(self::PRIVATE_KEY)?->data;
$publicKey = (string)FireflyConfig::get(self::PUBLIC_KEY)?->data;
try {
$privateContent = Crypt::decrypt($privateKey);
@@ -98,8 +99,8 @@ class OAuthKeys
app('log')->error($e->getMessage());
// delete config vars from DB:
app('fireflyconfig')->delete(self::PRIVATE_KEY);
app('fireflyconfig')->delete(self::PUBLIC_KEY);
FireflyConfig::delete(self::PRIVATE_KEY);
FireflyConfig::delete(self::PUBLIC_KEY);
return false;
}
@@ -115,8 +116,8 @@ class OAuthKeys
{
$private = storage_path('oauth-private.key');
$public = storage_path('oauth-public.key');
app('fireflyconfig')->set(self::PRIVATE_KEY, Crypt::encrypt(file_get_contents($private)));
app('fireflyconfig')->set(self::PUBLIC_KEY, Crypt::encrypt(file_get_contents($public)));
FireflyConfig::set(self::PRIVATE_KEY, Crypt::encrypt(file_get_contents($private)));
FireflyConfig::set(self::PUBLIC_KEY, Crypt::encrypt(file_get_contents($public)));
}
public static function verifyKeysRoutine(): void

View File

@@ -30,6 +30,7 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Search\OperatorQuerySearch;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use League\CommonMark\GithubFlavoredMarkdownConverter;
@@ -155,9 +156,12 @@ class General extends AbstractExtension
}
/** @var Carbon $date */
$date = session('end', today(config('app.timezone'))->endOfMonth());
$date = now();
Log::debug(sprintf('twig balance: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
$info = Steam::finalAccountBalance($account, $date);
// 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
$info = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id];
// $info = Steam::finalAccountBalance($account, $date);
$currency = Steam::getAccountCurrency($account);
$primary = Amount::getPrimaryCurrency();
$convertToPrimary = Amount::convertToPrimary();

10
composer.lock generated
View File

@@ -1878,16 +1878,16 @@
},
{
"name": "laravel/framework",
"version": "v12.32.5",
"version": "v12.33.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "77b2740391cd2a825ba59d6fada45e9b8b9bcc5a"
"reference": "124efc5f09d4668a4dc13f94a1018c524a58bcb1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/77b2740391cd2a825ba59d6fada45e9b8b9bcc5a",
"reference": "77b2740391cd2a825ba59d6fada45e9b8b9bcc5a",
"url": "https://api.github.com/repos/laravel/framework/zipball/124efc5f09d4668a4dc13f94a1018c524a58bcb1",
"reference": "124efc5f09d4668a4dc13f94a1018c524a58bcb1",
"shasum": ""
},
"require": {
@@ -2093,7 +2093,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-09-30T17:39:22+00:00"
"time": "2025-10-07T14:30:39+00:00"
},
{
"name": "laravel/passport",

View File

@@ -78,8 +78,8 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag.
],
'version' => '6.4.2',
'build_time' => 1759824590,
'version' => 'develop/2025-10-08',
'build_time' => 1759908015,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used.

36
package-lock.json generated
View File

@@ -4075,9 +4075,9 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
"version": "2.8.12",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.12.tgz",
"integrity": "sha512-vAPMQdnyKCBtkmQA6FMCBvU9qFIppS3nzyXnEM+Lo2IAhG4Mpjv9cCxMudhgV3YdNNJv6TNqXy97dfRVL2LmaQ==",
"version": "2.8.13",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.13.tgz",
"integrity": "sha512-7s16KR8io8nIBWQyCYhmFhd+ebIzb9VKTzki+wOJXHTxTnV6+mFGH3+Jwn1zoKaY9/H9T/0BcKCZnzXljPnpSQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -4521,9 +4521,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001748",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001748.tgz",
"integrity": "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==",
"version": "1.0.30001749",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001749.tgz",
"integrity": "sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==",
"dev": true,
"funding": [
{
@@ -5736,9 +5736,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.232",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.232.tgz",
"integrity": "sha512-ENirSe7wf8WzyPCibqKUG1Cg43cPaxH4wRR7AJsX7MCABCHBIOFqvaYODSLKUuZdraxUTHRE/0A2Aq8BYKEHOg==",
"version": "1.5.233",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.233.tgz",
"integrity": "sha512-iUdTQSf7EFXsDdQsp8MwJz5SVk4APEFqXU/S47OtQ0YLqacSwPXdZ5vRlMX3neb07Cy2vgioNuRnWUXFwuslkg==",
"dev": true,
"license": "ISC"
},
@@ -10290,9 +10290,9 @@
}
},
"node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"dev": true,
"license": "ISC",
"bin": {
@@ -11836,9 +11836,9 @@
"license": "BSD-2-Clause"
},
"node_modules/webpack": {
"version": "5.102.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.0.tgz",
"integrity": "sha512-hUtqAR3ZLVEYDEABdBioQCIqSoguHbFn1K7WlPPWSuXmx0031BD73PSE35jKyftdSh4YLDoQNgK4pqBt5Q82MA==",
"version": "5.102.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.1.tgz",
"integrity": "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11850,7 +11850,7 @@
"@webassemblyjs/wasm-parser": "^1.14.1",
"acorn": "^8.15.0",
"acorn-import-phases": "^1.0.3",
"browserslist": "^4.24.5",
"browserslist": "^4.26.3",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.17.3",
"es-module-lexer": "^1.2.1",
@@ -11862,8 +11862,8 @@
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^4.3.2",
"tapable": "^2.2.3",
"schema-utils": "^4.3.3",
"tapable": "^2.3.0",
"terser-webpack-plugin": "^5.3.11",
"watchpack": "^2.4.4",
"webpack-sources": "^3.3.3"