From 252459c29bf3db65ad8d3138cb99e195b7024745 Mon Sep 17 00:00:00 2001 From: JC5 Date: Wed, 8 Oct 2025 09:22:12 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Auto=20commit=20for=20release=20?= =?UTF-8?q?'develop'=20on=202025-10-08?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Autocomplete/AutocompleteRequest.php | 3 +- app/Api/V1/Requests/Data/DateRequest.php | 1 - .../Extensions/AccountCollection.php | 2 +- app/Helpers/Report/NetWorth.php | 2 - app/Helpers/Report/NetWorthInterface.php | 2 - .../Controllers/Account/IndexController.php | 30 +-- .../Account/ReconcileController.php | 16 +- .../Controllers/Account/ShowController.php | 4 +- .../Controllers/Chart/AccountController.php | 8 +- .../Controllers/Json/ReconcileController.php | 8 +- .../Transaction/ConvertController.php | 10 +- app/Repositories/Account/AccountTasker.php | 2 +- .../PiggyBank/PiggyBankRepository.php | 2 +- app/Support/Steam.php | 173 +++++++++--------- app/Support/Twig/General.php | 2 +- config/firefly.php | 4 +- package-lock.json | 18 +- 17 files changed, 144 insertions(+), 143 deletions(-) diff --git a/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php b/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php index 6e8432ef45..63cb22077d 100644 --- a/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php +++ b/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php @@ -48,7 +48,8 @@ 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')); + $date = $this->getCarbonDate('date') ?? today(config('app.timezone')); + return [ 'types' => $array, 'query' => $this->convertString('query'), diff --git a/app/Api/V1/Requests/Data/DateRequest.php b/app/Api/V1/Requests/Data/DateRequest.php index f5b37f7ca7..c112495d46 100644 --- a/app/Api/V1/Requests/Data/DateRequest.php +++ b/app/Api/V1/Requests/Data/DateRequest.php @@ -28,7 +28,6 @@ use FireflyIII\Exceptions\ValidationException; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; -use Illuminate\Validation\Validator; /** * Request class for end points that require date parameters. diff --git a/app/Helpers/Collector/Extensions/AccountCollection.php b/app/Helpers/Collector/Extensions/AccountCollection.php index 837c353b41..203cad80ab 100644 --- a/app/Helpers/Collector/Extensions/AccountCollection.php +++ b/app/Helpers/Collector/Extensions/AccountCollection.php @@ -67,7 +67,7 @@ trait AccountCollection // the balance must be found BEFORE the transaction 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::accountsBalancesOptimized(new Collection()->push($account), $transaction['date'], convertToPrimary: null, inclusive: false)[$account->id]; // $balance = Steam::finalAccountBalance($account, $date); $result = bccomp((string) $balance['balance'], $value); Log::debug(sprintf('"%s" vs "%s" is %d', $balance['balance'], $value, $result)); diff --git a/app/Helpers/Report/NetWorth.php b/app/Helpers/Report/NetWorth.php index 80c0171ad6..b45659415c 100644 --- a/app/Helpers/Report/NetWorth.php +++ b/app/Helpers/Report/NetWorth.php @@ -25,8 +25,6 @@ declare(strict_types=1); namespace FireflyIII\Helpers\Report; use Carbon\Carbon; -use Deprecated; -use FireflyIII\Enums\AccountTypeEnum; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Account; use FireflyIII\Models\UserGroup; diff --git a/app/Helpers/Report/NetWorthInterface.php b/app/Helpers/Report/NetWorthInterface.php index 8660ab4e4c..3870359766 100644 --- a/app/Helpers/Report/NetWorthInterface.php +++ b/app/Helpers/Report/NetWorthInterface.php @@ -25,7 +25,6 @@ declare(strict_types=1); namespace FireflyIII\Helpers\Report; use Carbon\Carbon; -use Deprecated; use FireflyIII\Models\UserGroup; use FireflyIII\User; use Illuminate\Contracts\Auth\Authenticatable; @@ -49,5 +48,4 @@ interface NetWorthInterface public function setUser(Authenticatable|User|null $user): void; public function setUserGroup(UserGroup $userGroup): void; - } diff --git a/app/Http/Controllers/Account/IndexController.php b/app/Http/Controllers/Account/IndexController.php index 64d8f37eb5..41ee6981b3 100644 --- a/app/Http/Controllers/Account/IndexController.php +++ b/app/Http/Controllers/Account/IndexController.php @@ -74,30 +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()); - $ids = $accounts->pluck('id')->toArray(); + $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); + ] = Steam::accountsBalancesInRange($accounts, $start, $end, $this->primaryCurrency, $this->convertToPrimary); + $activities = Steam::getLastActivities($ids); $accounts->each( @@ -117,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')); diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index 33da0dac0e..c78696f776 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -114,18 +114,18 @@ 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); + $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)); diff --git a/app/Http/Controllers/Account/ShowController.php b/app/Http/Controllers/Account/ShowController.php index 104caabefd..bcb0ba6a0e 100644 --- a/app/Http/Controllers/Account/ShowController.php +++ b/app/Http/Controllers/Account/ShowController.php @@ -170,7 +170,7 @@ class ShowController extends Controller } // 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized. - $balances = Steam::accountsBalancesOptimized(new Collection()->push($account), $now)[$account->id]; + $balances = Steam::accountsBalancesOptimized(new Collection()->push($account), $now)[$account->id]; // $balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToPrimary, $accountCurrency); return view( @@ -243,7 +243,7 @@ class ShowController extends Controller // 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]; + $balances = Steam::accountsBalancesOptimized(new Collection()->push($account), $end)[$account->id]; return view( 'accounts.show', diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index 5d09db1267..ada7f9014e 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -522,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. @@ -671,7 +671,7 @@ class AccountController extends Controller [ $startBalances, $endBalances, - ] = Steam::accountsBalancesInRange($accounts, $start, $end , $this->primaryCurrency, $this->convertToPrimary); + ] = Steam::accountsBalancesInRange($accounts, $start, $end, $this->primaryCurrency, $this->convertToPrimary); // loop the accounts, then check for balance and currency info. diff --git a/app/Http/Controllers/Json/ReconcileController.php b/app/Http/Controllers/Json/ReconcileController.php index b2d33c7fe9..763d306275 100644 --- a/app/Http/Controllers/Json/ReconcileController.php +++ b/app/Http/Controllers/Json/ReconcileController.php @@ -201,11 +201,11 @@ class ReconcileController extends Controller 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::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]; + $startBalance = Steam::accountsBalancesOptimized(new Collection()->push($account), $startDate)[$account->id]; + $endBalance = Steam::accountsBalancesOptimized(new Collection()->push($account), $end)[$account->id]; // get the transactions diff --git a/app/Http/Controllers/Transaction/ConvertController.php b/app/Http/Controllers/Transaction/ConvertController.php index 655aeeb594..5b26839211 100644 --- a/app/Http/Controllers/Transaction/ConvertController.php +++ b/app/Http/Controllers/Transaction/ConvertController.php @@ -232,10 +232,10 @@ class ConvertController extends Controller Log::debug(sprintf('getLiabilities: Call finalAccountBalance with date/time "%s"', $date->toIso8601String())); // 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'; + $balance = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id]['balance'] ?? '0'; $currency = $this->accountRepository->getAccountCurrency($account) ?? $this->primaryCurrency; - $role = sprintf('l_%s',$account->accountType->type); - $key = (string) trans(sprintf('firefly.opt_group_%s',$role)); + $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)); } @@ -258,7 +258,7 @@ class ConvertController extends Controller Log::debug(sprintf('getAssetAccounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String())); // 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'; + $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'); @@ -266,7 +266,7 @@ class ConvertController extends Controller $role = 'no_account_type'; } - $key = (string) trans(sprintf('firefly.opt_group_%s',$role)); + $key = (string) trans(sprintf('firefly.opt_group_%s', $role)); $grouped[$key][$account->id] = sprintf('%s (%s)', $account->name, Amount::formatAnything($currency, $balance, false)); } diff --git a/app/Repositories/Account/AccountTasker.php b/app/Repositories/Account/AccountTasker.php index 119ea48426..4278ac4183 100644 --- a/app/Repositories/Account/AccountTasker.php +++ b/app/Repositories/Account/AccountTasker.php @@ -54,7 +54,7 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface [ $startSet, $endSet, - ] = Steam::accountsBalancesInRange($accounts, $yesterday, $end); + ] = Steam::accountsBalancesInRange($accounts, $yesterday, $end); Log::debug('Start of accountreport'); /** @var AccountRepositoryInterface $repository */ diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php index 5ee5617130..2dbdda5dc3 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepository.php +++ b/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -377,7 +377,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte Log::debug(sprintf('leftOnAccount: Call finalAccountBalance with date/time "%s"', $date->toIso8601String())); // 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized. $balance = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id]; - //$balance = Steam::finalAccountBalance($account, $date)['balance']; + // $balance = Steam::finalAccountBalance($account, $date)['balance']; Log::debug(sprintf('Balance is: %s', $balance)); diff --git a/app/Support/Steam.php b/app/Support/Steam.php index 0078fdfdf1..586ecd4a7b 100644 --- a/app/Support/Steam.php +++ b/app/Support/Steam.php @@ -40,6 +40,7 @@ use Illuminate\Support\Str; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; use ValueError; + use function Safe\parse_url; use function Safe\preg_replace; @@ -51,45 +52,47 @@ class Steam 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" (inclusive: %s)', $accounts->count(), $date->toIso8601String(), var_export($inclusive, true))); - $result = []; + $result = []; $convertToPrimary ??= Amount::convertToPrimary(); $primary ??= Amount::getPrimaryCurrency(); - $currencies = $this->getCurrencies($accounts); + $currencies = $this->getCurrencies($accounts); // balance(s) in all currencies for ALL accounts. $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', $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(); + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id') + ->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) { - $return = [ + $return = [ 'pc_balance' => '0', 'balance' => '0', // this key is overwritten right away, but I must remember it is always created. ]; - $currency = $currencies[$account->id]; + $currency = $currencies[$account->id]; // second array - $accountSums = array_filter($arrayOfSums, fn($entry) => $entry['account_id'] === $account->id); + $accountSums = array_filter($arrayOfSums, fn ($entry) => $entry['account_id'] === $account->id); if (0 === count($accountSums)) { $result[$account->id] = $return; continue; } - $sumsByCode = []; - foreach($accountSums as $accountSum) { + $sumsByCode = []; + foreach ($accountSums as $accountSum) { // $accountSum = array_values($accountSum)[0]; - $sumOfAmount = (string)$accountSum['sum_of_amount']; - $sumOfAmount = $this->floatalize('' === $sumOfAmount ? '0' : $sumOfAmount); + $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'; + $return['balance'] = $sumsByCode[$currency->code] ?? '0'; if (!$convertToPrimary) { unset($return['pc_balance']); // Log::debug(sprintf('Set balance to %s, unset pc_balance', $return['balance'])); @@ -102,7 +105,7 @@ class Steam } // either way, the balance is always combined with the virtual balance: - $virtualBalance = (string)('' === (string)$account->virtual_balance ? '0' : $account->virtual_balance); + $virtualBalance = (string)('' === (string)$account->virtual_balance ? '0' : $account->virtual_balance); if ($convertToPrimary) { // the primary currency balance is combined with a converted virtual_balance: @@ -118,7 +121,7 @@ class Steam } $final = array_merge($return, $sumsByCode); $result[$account->id] = $final; - Log::debug(sprintf('Final balance for account #%d is',$account->id), $final); + Log::debug(sprintf('Final balance for account #%d is', $account->id), $final); } return $result; @@ -154,10 +157,10 @@ class Steam // Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision)); if (str_contains($number, '.')) { if ('-' !== $number[0]) { - return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision); + return bcadd($number, '0.'.str_repeat('0', $precision).'5', $precision); } - return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision); + return bcsub($number, '0.'.str_repeat('0', $precision).'5', $precision); } return $number; @@ -303,7 +306,7 @@ class Steam public function finalAccountBalance(Account $account, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null, bool $inclusive = true): array { - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($account->id); $cache->addProperty($date); if ($cache->has()) { @@ -318,26 +321,27 @@ class Steam $primary = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } // account balance thing. - $currencyPresent = isset($account->meta) && array_key_exists('currency', $account->meta) && null !== $account->meta['currency']; + $currencyPresent = isset($account->meta) && array_key_exists('currency', $account->meta) && null !== $account->meta['currency']; if ($currencyPresent) { $accountCurrency = $account->meta['currency']; } if (!$currencyPresent) { $accountCurrency = $this->getAccountCurrency($account); } - $hasCurrency = null !== $accountCurrency; - $currency = $hasCurrency ? $accountCurrency : $primary; - $return = [ + $hasCurrency = null !== $accountCurrency; + $currency = $hasCurrency ? $accountCurrency : $primary; + $return = [ 'pc_balance' => '0', 'balance' => '0', // this key is overwritten right away, but I must remember it is always created. ]; // balance(s) in all currencies. - $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', $inclusive ? '<=': '<', $date->format('Y-m-d H:i:s')) - ->get(['transaction_currencies.code', 'transactions.amount'])->toArray(); - $others = $this->groupAndSumTransactions($array, 'code', 'amount'); + $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', $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); // if there is no request to convert, take this as "balance" and "pc_balance". $return['balance'] = $others[$currency->code] ?? '0'; @@ -352,7 +356,7 @@ class Steam } // either way, the balance is always combined with the virtual balance: - $virtualBalance = (string)('' === (string)$account->virtual_balance ? '0' : $account->virtual_balance); + $virtualBalance = (string)('' === (string)$account->virtual_balance ? '0' : $account->virtual_balance); if ($convertToPrimary) { // the primary currency balance is combined with a converted virtual_balance: @@ -366,7 +370,7 @@ class Steam $return['balance'] = bcadd($return['balance'], $virtualBalance); // Log::debug(sprintf('Virtual balance makes the (primary currency) total %s', $return['balance'])); } - $final = array_merge($return, $others); + $final = array_merge($return, $others); Log::debug('Final balance is', $final); $cache->store($final); @@ -384,7 +388,7 @@ class Steam 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(); + $cache = new CacheProperties(); $cache->addProperty($account->id); $cache->addProperty('final-balance-in-range'); $cache->addProperty($start); @@ -395,15 +399,15 @@ class Steam // return $cache->get(); } - $balances = []; - $formatted = $start->format('Y-m-d'); + $balances = []; + $formatted = $start->format('Y-m-d'); Log::debug('Get first balance to start.'); // 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; + $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: @@ -415,7 +419,7 @@ class Steam Log::debug(sprintf('Also set start balance in %s', $primaryCurrency->code)); $startBalance[$primaryCurrency->code] ??= '0'; } - $currencies = [ + $currencies = [ $currency->id => $currency, $primaryCurrency->id => $primaryCurrency, ]; @@ -425,47 +429,48 @@ class Steam // sums up the balance changes per day. Log::debug(sprintf('Date >= %s and <= %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); - $set = $account->transactions() - ->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') - ->where('transaction_journals.date', '>=', $start->format('Y-m-d H:i:s')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s')) - ->groupBy('transaction_journals.date') - ->groupBy('transactions.transaction_currency_id') - ->orderBy('transaction_journals.date', 'ASC') - ->whereNull('transaction_journals.deleted_at') - ->get( - [ // @phpstan-ignore-line - 'transaction_journals.date', - 'transactions.transaction_currency_id', - DB::raw('SUM(transactions.amount) AS sum_of_day'), - ] - ); + $set = $account->transactions() + ->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d H:i:s')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s')) + ->groupBy('transaction_journals.date') + ->groupBy('transactions.transaction_currency_id') + ->orderBy('transaction_journals.date', 'ASC') + ->whereNull('transaction_journals.deleted_at') + ->get( + [ // @phpstan-ignore-line + 'transaction_journals.date', + 'transactions.transaction_currency_id', + DB::raw('SUM(transactions.amount) AS sum_of_day'), + ] + ) + ; - $currentBalance = $startBalance; - $converter = new ExchangeRateConverter(); + $currentBalance = $startBalance; + $converter = new ExchangeRateConverter(); /** @var Transaction $entry */ foreach ($set as $entry) { // get date object - $carbon = new Carbon($entry->date, $entry->date_tz); - $carbonKey = $carbon->format('Y-m-d'); + $carbon = new Carbon($entry->date, $entry->date_tz); + $carbonKey = $carbon->format('Y-m-d'); // make sure sum is a string: - $sumOfDay = (string)($entry->sum_of_day ?? '0'); + $sumOfDay = (string)($entry->sum_of_day ?? '0'); // #10426 make sure sum is not in scientific notation. - $sumOfDay = $this->floatalize($sumOfDay); + $sumOfDay = $this->floatalize($sumOfDay); // find currency of this entry, does not have to exist. $currencies[$entry->transaction_currency_id] ??= Amount::getTransactionCurrencyById($entry->transaction_currency_id); // make sure this $entry has its own $entryCurrency /** @var TransactionCurrency $entryCurrency */ - $entryCurrency = $currencies[$entry->transaction_currency_id]; + $entryCurrency = $currencies[$entry->transaction_currency_id]; Log::debug(sprintf('Processing transaction(s) on moment %s', $carbon->format('Y-m-d H:i:s'))); // add amount to current balance in currency code. - $currentBalance[$entryCurrency->code] ??= '0'; + $currentBalance[$entryCurrency->code] ??= '0'; $currentBalance[$entryCurrency->code] = bcadd($sumOfDay, (string)$currentBalance[$entryCurrency->code]); // if not requested to convert to primary currency, add the amount to "balance", do nothing else. @@ -483,7 +488,7 @@ class Steam } } // add to final array. - $balances[$carbonKey] = $currentBalance; + $balances[$carbonKey] = $currentBalance; Log::debug(sprintf('Updated entry [%s]', $carbonKey), $currentBalance); } $cache->store($balances); @@ -500,7 +505,7 @@ class Steam */ public function floatalize(string $value): string { - $value = strtoupper($value); + $value = strtoupper($value); if (!str_contains($value, 'E')) { return $value; } @@ -524,8 +529,8 @@ class Steam public function getAccountCurrency(Account $account): ?TransactionCurrency { - $type = $account->accountType->type; - $list = config('firefly.valid_currency_account_types'); + $type = $account->accountType->type; + $list = config('firefly.valid_currency_account_types'); // return null if not in this list. if (!in_array($type, $list, true)) { @@ -578,15 +583,15 @@ class Steam { $list = []; - $set = auth()->user()->transactions() - ->whereIn('transactions.account_id', $accounts) - ->groupBy(['transactions.account_id', 'transaction_journals.user_id']) - ->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line + $set = auth()->user()->transactions() + ->whereIn('transactions.account_id', $accounts) + ->groupBy(['transactions.account_id', 'transaction_journals.user_id']) + ->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line ; /** @var Transaction $entry */ foreach ($set as $entry) { - $date = new Carbon($entry->max_date, config('app.timezone')); + $date = new Carbon($entry->max_date, config('app.timezone')); $date->setTimezone(config('app.timezone')); $list[(int)$entry->account_id] = $date; } @@ -604,14 +609,14 @@ class Steam if (null !== $cached) { return $cached; } - $locale = app('preferences')->get('locale', config('firefly.default_locale', 'equal'))->data; + $locale = app('preferences')->get('locale', config('firefly.default_locale', 'equal'))->data; if (is_array($locale)) { $locale = 'equal'; } if ('equal' === $locale) { $locale = $this->getLanguage(); } - $locale = (string)$locale; + $locale = (string)$locale; // Check for Windows to replace the locale correctly. if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) { @@ -652,9 +657,9 @@ class Steam public function getSafeUrl(string $unknownUrl, string $safeUrl): string { // Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl)); - $returnUrl = $safeUrl; - $unknownHost = parse_url($unknownUrl, PHP_URL_HOST); - $safeHost = parse_url($safeUrl, PHP_URL_HOST); + $returnUrl = $safeUrl; + $unknownHost = parse_url($unknownUrl, PHP_URL_HOST); + $safeHost = parse_url($safeUrl, PHP_URL_HOST); if (null !== $unknownHost && $unknownHost === $safeHost) { $returnUrl = $unknownUrl; @@ -756,12 +761,12 @@ class Steam if (null === $preference) { $singleton->setPreference($key, $currency); } - $current = $amount; + $current = $amount; if ($currency->id !== $primary->id) { $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; @@ -775,8 +780,8 @@ class Steam $primary = Amount::getPrimaryCurrency(); $currencies[$primary->id] = $primary; - $ids = $accounts->pluck('id')->toArray(); - $result = AccountMeta::whereIn('account_id', $ids)->where('name', 'currency_id')->get(); + $ids = $accounts->pluck('id')->toArray(); + $result = AccountMeta::whereIn('account_id', $ids)->where('name', 'currency_id')->get(); /** @var AccountMeta $item */ foreach ($result as $item) { @@ -786,7 +791,7 @@ class Steam } } // collect those currencies, skip primary because we already have it. - $set = TransactionCurrency::whereIn('id', $accountPreferences)->where('id', '!=', $primary->id)->get(); + $set = TransactionCurrency::whereIn('id', $accountPreferences)->where('id', '!=', $primary->id)->get(); foreach ($set as $item) { $currencies[$item->id] = $item; } @@ -797,7 +802,7 @@ class Steam $currencyPresent = isset($account->meta) && array_key_exists('currency', $account->meta) && null !== $account->meta['currency']; if ($currencyPresent) { $currencyId = $account->meta['currency']->id; - $currencies[$currencyId] ??= $account->meta['currency']; + $currencies[$currencyId] ??= $account->meta['currency']; $accountCurrencies[$accountId] = $account->meta['currency']; } if (!$currencyPresent && !array_key_exists($accountId, $accountPreferences)) { diff --git a/app/Support/Twig/General.php b/app/Support/Twig/General.php index 9208875ed2..80d72a9f75 100644 --- a/app/Support/Twig/General.php +++ b/app/Support/Twig/General.php @@ -160,7 +160,7 @@ class General extends AbstractExtension Log::debug(sprintf('twig balance: Call finalAccountBalance with date/time "%s"', $date->toIso8601String())); // 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized. - $info = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id]; + $info = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id]; // $info = Steam::finalAccountBalance($account, $date); $currency = Steam::getAccountCurrency($account); $primary = Amount::getPrimaryCurrency(); diff --git a/config/firefly.php b/config/firefly.php index db7f7d8cb4..c2872fa1b5 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -78,8 +78,8 @@ return [ 'running_balance_column' => env('USE_RUNNING_BALANCE', false), // see cer.php for exchange rates feature flag. ], - 'version' => 'develop/2025-10-07', - 'build_time' => 1759859933, + '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. diff --git a/package-lock.json b/package-lock.json index 670e032192..af16b7af1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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": {