From d84405191f27d24a4a80111e4b2ddf15eabe683a Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 9 Mar 2025 09:53:19 +0100 Subject: [PATCH 1/6] Add debug timers. --- .../Controllers/Account/ShowController.php | 55 +++++++++++++------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/app/Http/Controllers/Account/ShowController.php b/app/Http/Controllers/Account/ShowController.php index 24ac82cea2..a2b7a027a9 100644 --- a/app/Http/Controllers/Account/ShowController.php +++ b/app/Http/Controllers/Account/ShowController.php @@ -29,10 +29,11 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Account; -use FireflyIII\Models\Transaction; use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Support\Debug\Timer; use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Http\Controllers\PeriodOverview; +use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment; use Illuminate\Contracts\View\Factory; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; @@ -82,7 +83,7 @@ class ShowController extends Controller public function show(Request $request, Account $account, ?Carbon $start = null, ?Carbon $end = null) { - $objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type)); + $objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type)); if (!$this->isEditableAccount($account)) { return $this->redirectAccountToAccount($account); @@ -114,33 +115,55 @@ class ShowController extends Controller $subTitle = (string) trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]); $chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]); $firstTransaction = $this->repository->oldestJournalDate($account) ?? $start; + + Log::debug('Start period overview'); + Timer::start('period-overview'); + $periods = $this->getAccountPeriodOverview($account, $firstTransaction, $end); + Log::debug('End period overview'); + Timer::stop('period-overview'); + // if layout = v2, overrule the page title. if ('v1' !== config('view.layout')) { $subTitle = (string) trans('firefly.all_journals_for_account', ['name' => $account->name]); } - + Log::debug('Collect transactions'); + Timer::start('collection'); /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); - $collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation()->setRange($start, $end); - + $collector = app(GroupCollectorInterface::class); + $collector + ->setAccounts(new Collection([$account])) + ->setLimit($pageSize) + ->setPage($page) + ->withAPIInformation() + ->setRange($start, $end); // this search will not include transaction groups where this asset account (or liability) // is just part of ONE of the journals. To force this: $collector->setExpandGroupSearch(true); + $groups = $collector->getPaginatedGroups(); + + Log::debug('End collect transactions'); + Timer::stop('collection'); + + // enrich data in arrays. + + // enrich +// $enrichment = new TransactionGroupEnrichment(); +// $enrichment->setUser(auth()->user()); +// $groups->setCollection($enrichment->enrich($groups->getCollection())); - $groups = $collector->getPaginatedGroups(); $groups->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')])); - $showAll = false; + $showAll = false; // correct - $now = today()->endOfDay(); + $now = today()->endOfDay(); if ($now->gt($end) || $now->lt($start)) { $now = $end; } Log::debug(sprintf('show: Call finalAccountBalance with date/time "%s"', $now->toIso8601String())); - $balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToNative, $accountCurrency); + $balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToNative, $accountCurrency); return view( 'accounts.show', @@ -184,7 +207,7 @@ class ShowController extends Controller $today = today(config('app.timezone')); $accountCurrency = $this->repository->getAccountCurrency($account); $start = $this->repository->oldestJournalDate($account) ?? today(config('app.timezone'))->startOfMonth(); - $subTitleIcon = config('firefly.subIconsByIdentifier.'.$account->accountType->type); + $subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type); $page = (int) $request->get('page'); $pageSize = (int) app('preferences')->get('listPageSize', 50)->data; $currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency; @@ -194,20 +217,20 @@ class ShowController extends Controller $end->endOfDay(); /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation(); // this search will not include transaction groups where this asset account (or liability) // is just part of ONE of the journals. To force this: $collector->setExpandGroupSearch(true); - $groups = $collector->getPaginatedGroups(); + $groups = $collector->getPaginatedGroups(); $groups->setPath(route('accounts.show.all', [$account->id])); - $chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]); - $showAll = true; + $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->convertToNative, $accountCurrency); + $balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToNative, $accountCurrency); return view( 'accounts.show', From db2cab3cef225f4a9ab24e160b6fba1d2fe8ad12 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 9 Mar 2025 09:53:27 +0100 Subject: [PATCH 2/6] Add custom method. --- .../Account/AccountRepository.php | 30 +++++++++++++++++++ .../Account/AccountRepositoryInterface.php | 2 ++ 2 files changed, 32 insertions(+) diff --git a/app/Repositories/Account/AccountRepository.php b/app/Repositories/Account/AccountRepository.php index 8a8cb8a908..26f3cc12f7 100644 --- a/app/Repositories/Account/AccountRepository.php +++ b/app/Repositories/Account/AccountRepository.php @@ -641,4 +641,34 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac return $factory->create($data); } + + #[\Override] public function periodCollection(Account $account, Carbon $start, Carbon $end): array + { + return $account->transactions() + ->leftJoin('transaction_journals','transaction_journals.id','=','transactions.transaction_journal_id') + ->leftJoin('transaction_types','transaction_types.id','=','transaction_journals.transaction_type_id') + ->leftJoin('transaction_currencies','transaction_currencies.id','=','transactions.transaction_currency_id') + ->leftJoin('transaction_currencies as foreign_currencies','foreign_currencies.id','=','transactions.foreign_currency_id') + ->where('transaction_journals.date','>=',$start) + ->where('transaction_journals.date','<=',$end) + ->get([ + // currencies + 'transaction_currencies.id as currency_id', + 'transaction_currencies.code as currency_code', + 'transaction_currencies.name as currency_name', + 'transaction_currencies.symbol as currency_symbol', + 'transaction_currencies.decimal_places as currency_decimal_places', + + // foreign + 'foreign_currencies.id as foreign_currency_id', + 'foreign_currencies.code as foreign_currency_code', + 'foreign_currencies.name as foreign_currency_name', + 'foreign_currencies.symbol as foreign_currency_symbol', + 'foreign_currencies.decimal_places as foreign_decimal_places', + + // fields + 'transaction_journals.date', 'transaction_types.type', 'transaction_journals.transaction_currency_id', 'transactions.amount']) + ->toArray(); + + } } diff --git a/app/Repositories/Account/AccountRepositoryInterface.php b/app/Repositories/Account/AccountRepositoryInterface.php index 006b2d7eed..6bfb568c28 100644 --- a/app/Repositories/Account/AccountRepositoryInterface.php +++ b/app/Repositories/Account/AccountRepositoryInterface.php @@ -71,6 +71,8 @@ interface AccountRepositoryInterface public function findByName(string $name, array $types): ?Account; + public function periodCollection(Account $account, Carbon $start, Carbon $end): array; + public function getAccountBalances(Account $account): Collection; public function getAccountCurrency(Account $account): ?TransactionCurrency; From fe2def968493112b54815a7a3cd60cd22c8b2b0b Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 9 Mar 2025 09:53:36 +0100 Subject: [PATCH 3/6] Fix nullpointer. --- .../PiggyBank/PiggyBankRepository.php | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php index cdf2e86837..e99fa16363 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepository.php +++ b/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -305,15 +305,21 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte public function getPiggyBanks(): Collection { - return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') - ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') - ->where('accounts.user_id', $this->user->id) - ->with( - [ - 'objectGroups', - ] - ) - ->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*']); + $query = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') + ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id'); + if (null === $this->user) { + $query->where('accounts.user_group_id', $this->userGroup->id); + } + if (null !== $this->user) { + $query->where('accounts.user_id', $this->user->id); + } + return $query + ->with( + [ + 'objectGroups', + ] + ) + ->orderBy('piggy_banks.order', 'ASC')->distinct()->get(['piggy_banks.*']); } public function getRepetition(PiggyBank $piggyBank, bool $overrule = false): ?PiggyBankRepetition From 26df1be871c67d507e913b7082ec45e88ff6280c Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 9 Mar 2025 09:53:52 +0100 Subject: [PATCH 4/6] Remove debug --- app/Support/Debug/Timer.php | 46 +++++++++++++++++++++++++++++++++++++ app/Support/Preferences.php | 4 ++-- 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 app/Support/Debug/Timer.php diff --git a/app/Support/Debug/Timer.php b/app/Support/Debug/Timer.php new file mode 100644 index 0000000000..f1930e2c75 --- /dev/null +++ b/app/Support/Debug/Timer.php @@ -0,0 +1,46 @@ +id, $name)); + //Log::debug(sprintf('getForUser(#%d, "%s")', $user->id, $name)); // don't care about user group ID, except for some specific preferences. $userGroupId = $this->getUserGroupId($user, $name); $query = Preference::where('user_id', $user->id)->where('name', $name); @@ -90,7 +90,7 @@ class Preferences } if (null !== $preference) { - Log::debug(sprintf('Found preference #%d for user #%d: %s', $preference->id, $user->id, $name)); + //Log::debug(sprintf('Found preference #%d for user #%d: %s', $preference->id, $user->id, $name)); return $preference; } From 08f13aebe3d18e37119eaf30abf59b9793ab14b0 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 9 Mar 2025 09:54:06 +0100 Subject: [PATCH 5/6] Fix period overview for account --- .../Http/Controllers/PeriodOverview.php | 309 ++++++++++-------- 1 file changed, 167 insertions(+), 142 deletions(-) diff --git a/app/Support/Http/Controllers/PeriodOverview.php b/app/Support/Http/Controllers/PeriodOverview.php index 5d4811d1fb..baeff70934 100644 --- a/app/Support/Http/Controllers/PeriodOverview.php +++ b/app/Support/Http/Controllers/PeriodOverview.php @@ -31,9 +31,12 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Models\Account; use FireflyIII\Models\Category; use FireflyIII\Models\Tag; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Support\CacheProperties; +use FireflyIII\Support\Debug\Timer; use Illuminate\Support\Collection; +use Illuminate\Support\Facades\Log; /** * Trait PeriodOverview. @@ -65,6 +68,7 @@ use Illuminate\Support\Collection; trait PeriodOverview { protected JournalRepositoryInterface $journalRepos; + protected AccountRepositoryInterface $accountRepository; /** * This method returns "period entries", so nov-2015, dec-2015, etc etc (this depends on the users session range) @@ -75,11 +79,13 @@ trait PeriodOverview */ protected function getAccountPeriodOverview(Account $account, Carbon $start, Carbon $end): array { - $range = app('navigation')->getViewRange(true); + Timer::start('account-period-total'); + $this->accountRepository = app(AccountRepositoryInterface::class); + $range = app('navigation')->getViewRange(true); [$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; // properties for cache - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty('account-show-period-entries'); @@ -89,56 +95,75 @@ trait PeriodOverview } /** @var array $dates */ - $dates = app('navigation')->blockPeriods($start, $end, $range); - $entries = []; + $dates = app('navigation')->blockPeriods($start, $end, $range); + $entries = []; - // collect all expenses in this period: - /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); - $collector->setAccounts(new Collection([$account])); - $collector->setRange($start, $end); - $collector->setTypes([TransactionTypeEnum::DEPOSIT->value]); - $earnedSet = $collector->getExtractedJournals(); - - // collect all income in this period: - /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); - $collector->setAccounts(new Collection([$account])); - $collector->setRange($start, $end); - $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); - $spentSet = $collector->getExtractedJournals(); - - // collect all transfers in this period: - /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); - $collector->setAccounts(new Collection([$account])); - $collector->setRange($start, $end); - $collector->setTypes([TransactionTypeEnum::TRANSFER->value]); - $transferSet = $collector->getExtractedJournals(); + // run a custom query because doing this with the collector is MEGA slow. + $transactions = $this->accountRepository->periodCollection($account, $start, $end); // loop dates foreach ($dates as $currentDate) { $title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']); - $earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']); - $spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']); - $transferredAway = $this->filterTransferredAway($account, $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end'])); - $transferredIn = $this->filterTransferredIn($account, $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end'])); + [$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']); + [$transactions, $earned] = $this->filterTransactionsByType(TransactionTypeEnum::DEPOSIT, $transactions, $currentDate['start'], $currentDate['end']); + [$transactions, $transferredAway] = $this->filterTransfers('away',$transactions, $currentDate['start'], $currentDate['end']); + [$transactions, $transferredIn] = $this->filterTransfers('in',$transactions, $currentDate['start'], $currentDate['end']); $entries[] - = [ - 'title' => $title, - 'route' => route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - - 'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn), - 'spent' => $this->groupByCurrency($spent), - 'earned' => $this->groupByCurrency($earned), - 'transferred_away' => $this->groupByCurrency($transferredAway), - 'transferred_in' => $this->groupByCurrency($transferredIn), - ]; + = [ + 'title' => $title, + 'route' => route('accounts.show', [$account->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + 'total_transactions' => count($spent) + count($earned) + count($transferredAway) + count($transferredIn), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred_away' => $this->groupByCurrency($transferredAway), + 'transferred_in' => $this->groupByCurrency($transferredIn), + ]; } $cache->store($entries); + Timer::stop('account-period-total'); return $entries; } + private function filterTransfers(string $direction, array $transactions, Carbon $start, Carbon $end): array + { + $result = []; + /** + * @var int $index + * @var array $item + */ + foreach ($transactions as $index => $item) { + $date = Carbon::parse($item['date']); + if ($date >= $start && $date <= $end) { + if ($direction === 'away' && bccomp($item['amount'], '0') === -1) { + $result[] = $item; + unset($transactions[$index]); + } + if ($direction === 'in' && bccomp($item['amount'], '0') === 1) { + $result[] = $item; + unset($transactions[$index]); + } + } + } + return [$transactions, $result]; + } + + private function filterTransactionsByType(TransactionTypeEnum $type, array $transactions, Carbon $start, Carbon $end): array + { + $result = []; + /** + * @var int $index + * @var array $item + */ + foreach ($transactions as $index => $item) { + $date = Carbon::parse($item['date']); + if($item['type'] === $type->value && $date >= $start && $date <= $end) { + $result[] = $item; + unset($transactions[$index]); + } + } + + return [$transactions, $result]; + } /** * Filter a list of journals by a set of dates, and then group them by currency. @@ -197,13 +222,13 @@ trait PeriodOverview /** @var array $journal */ foreach ($journals as $journal) { - $currencyId = (int) $journal['currency_id']; - $currencyCode = $journal['currency_code']; - $currencyName = $journal['currency_name']; - $currencySymbol = $journal['currency_symbol']; - $currencyDecimalPlaces = $journal['currency_decimal_places']; - $foreignCurrencyId = $journal['foreign_currency_id']; - $amount = $journal['amount'] ?? '0'; + $currencyId = (int) $journal['currency_id']; + $currencyCode = $journal['currency_code']; + $currencyName = $journal['currency_name']; + $currencySymbol = $journal['currency_symbol']; + $currencyDecimalPlaces = $journal['currency_decimal_places']; + $foreignCurrencyId = $journal['foreign_currency_id']; + $amount = $journal['amount'] ?? '0'; if ($this->convertToNative && $currencyId !== $this->defaultCurrency->id && $foreignCurrencyId !== $this->defaultCurrency->id) { $amount = $journal['native_amount'] ?? '0'; @@ -246,11 +271,11 @@ trait PeriodOverview */ protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array { - $range = app('navigation')->getViewRange(true); + $range = app('navigation')->getViewRange(true); [$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; // properties for entries with their amounts. - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty($range); @@ -262,32 +287,32 @@ trait PeriodOverview } /** @var array $dates */ - $dates = app('navigation')->blockPeriods($start, $end, $range); - $entries = []; + $dates = app('navigation')->blockPeriods($start, $end, $range); + $entries = []; // collect all expenses in this period: /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setCategory($category); $collector->setRange($start, $end); $collector->setTypes([TransactionTypeEnum::DEPOSIT->value]); - $earnedSet = $collector->getExtractedJournals(); + $earnedSet = $collector->getExtractedJournals(); // collect all income in this period: /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setCategory($category); $collector->setRange($start, $end); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); - $spentSet = $collector->getExtractedJournals(); + $spentSet = $collector->getExtractedJournals(); // collect all transfers in this period: /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setCategory($category); $collector->setRange($start, $end); $collector->setTypes([TransactionTypeEnum::TRANSFER->value]); - $transferSet = $collector->getExtractedJournals(); + $transferSet = $collector->getExtractedJournals(); foreach ($dates as $currentDate) { $spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']); $earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']); @@ -295,17 +320,17 @@ trait PeriodOverview $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $entries[] = [ - 'transactions' => 0, - 'title' => $title, - 'route' => route( - 'categories.show', - [$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')] - ), - 'total_transactions' => count($spent) + count($earned) + count($transferred), - 'spent' => $this->groupByCurrency($spent), - 'earned' => $this->groupByCurrency($earned), - 'transferred' => $this->groupByCurrency($transferred), - ]; + 'transactions' => 0, + 'title' => $title, + 'route' => route( + 'categories.show', + [$category->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')] + ), + 'total_transactions' => count($spent) + count($earned) + count($transferred), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred' => $this->groupByCurrency($transferred), + ]; } $cache->store($entries); @@ -321,11 +346,11 @@ trait PeriodOverview */ protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array { - $range = app('navigation')->getViewRange(true); + $range = app('navigation')->getViewRange(true); [$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty($this->convertToNative); @@ -336,28 +361,28 @@ trait PeriodOverview } /** @var array $dates */ - $dates = app('navigation')->blockPeriods($start, $end, $range); - $entries = []; + $dates = app('navigation')->blockPeriods($start, $end, $range); + $entries = []; // get all expenses without a budget. /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setRange($start, $end)->withoutBudget()->withAccountInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); - $journals = $collector->getExtractedJournals(); + $journals = $collector->getExtractedJournals(); foreach ($dates as $currentDate) { $set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']); $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $entries[] = [ - 'title' => $title, - 'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - 'total_transactions' => count($set), - 'spent' => $this->groupByCurrency($set), - 'earned' => [], - 'transferred_away' => [], - 'transferred_in' => [], - ]; + 'title' => $title, + 'route' => route('budgets.no-budget', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + 'total_transactions' => count($set), + 'spent' => $this->groupByCurrency($set), + 'earned' => [], + 'transferred_away' => [], + 'transferred_in' => [], + ]; } $cache->store($entries); @@ -374,38 +399,38 @@ trait PeriodOverview protected function getNoCategoryPeriodOverview(Carbon $theDate): array { app('log')->debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d'))); - $range = app('navigation')->getViewRange(true); - $first = $this->journalRepos->firstNull(); - $start = null === $first ? new Carbon() : $first->date; - $end = clone $theDate; - $end = app('navigation')->endOfPeriod($end, $range); + $range = app('navigation')->getViewRange(true); + $first = $this->journalRepos->firstNull(); + $start = null === $first ? new Carbon() : $first->date; + $end = clone $theDate; + $end = app('navigation')->endOfPeriod($end, $range); app('log')->debug(sprintf('Start for getNoCategoryPeriodOverview() is %s', $start->format('Y-m-d'))); app('log')->debug(sprintf('End for getNoCategoryPeriodOverview() is %s', $end->format('Y-m-d'))); // properties for cache - $dates = app('navigation')->blockPeriods($start, $end, $range); - $entries = []; + $dates = app('navigation')->blockPeriods($start, $end, $range); + $entries = []; // collect all expenses in this period: /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->withoutCategory(); $collector->setRange($start, $end); $collector->setTypes([TransactionTypeEnum::DEPOSIT->value]); - $earnedSet = $collector->getExtractedJournals(); + $earnedSet = $collector->getExtractedJournals(); // collect all income in this period: /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->withoutCategory(); $collector->setRange($start, $end); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); - $spentSet = $collector->getExtractedJournals(); + $spentSet = $collector->getExtractedJournals(); // collect all transfers in this period: /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->withoutCategory(); $collector->setRange($start, $end); $collector->setTypes([TransactionTypeEnum::TRANSFER->value]); @@ -419,13 +444,13 @@ trait PeriodOverview $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $entries[] = [ - 'title' => $title, - 'route' => route('categories.no-category', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - 'total_transactions' => count($spent) + count($earned) + count($transferred), - 'spent' => $this->groupByCurrency($spent), - 'earned' => $this->groupByCurrency($earned), - 'transferred' => $this->groupByCurrency($transferred), - ]; + 'title' => $title, + 'route' => route('categories.no-category', [$currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + 'total_transactions' => count($spent) + count($earned) + count($transferred), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred' => $this->groupByCurrency($transferred), + ]; } app('log')->debug('End of loops'); @@ -439,11 +464,11 @@ trait PeriodOverview */ protected function getTagPeriodOverview(Tag $tag, Carbon $start, Carbon $end): array // period overview for tags. { - $range = app('navigation')->getViewRange(true); + $range = app('navigation')->getViewRange(true); [$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; // properties for cache - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty('tag-period-entries'); @@ -453,37 +478,37 @@ trait PeriodOverview } /** @var array $dates */ - $dates = app('navigation')->blockPeriods($start, $end, $range); - $entries = []; + $dates = app('navigation')->blockPeriods($start, $end, $range); + $entries = []; // collect all expenses in this period: /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setTag($tag); $collector->setRange($start, $end); $collector->setTypes([TransactionTypeEnum::DEPOSIT->value]); - $earnedSet = $collector->getExtractedJournals(); + $earnedSet = $collector->getExtractedJournals(); // collect all income in this period: /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setTag($tag); $collector->setRange($start, $end); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value]); - $spentSet = $collector->getExtractedJournals(); + $spentSet = $collector->getExtractedJournals(); // collect all transfers in this period: /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setTag($tag); $collector->setRange($start, $end); $collector->setTypes([TransactionTypeEnum::TRANSFER->value]); - $transferSet = $collector->getExtractedJournals(); + $transferSet = $collector->getExtractedJournals(); // filer all of them: - $earnedSet = $this->filterJournalsByTag($earnedSet, $tag); - $spentSet = $this->filterJournalsByTag($spentSet, $tag); - $transferSet = $this->filterJournalsByTag($transferSet, $tag); + $earnedSet = $this->filterJournalsByTag($earnedSet, $tag); + $spentSet = $this->filterJournalsByTag($spentSet, $tag); + $transferSet = $this->filterJournalsByTag($transferSet, $tag); foreach ($dates as $currentDate) { $spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']); @@ -492,17 +517,17 @@ trait PeriodOverview $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $entries[] = [ - 'transactions' => 0, - 'title' => $title, - 'route' => route( - 'tags.show', - [$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')] - ), - 'total_transactions' => count($spent) + count($earned) + count($transferred), - 'spent' => $this->groupByCurrency($spent), - 'earned' => $this->groupByCurrency($earned), - 'transferred' => $this->groupByCurrency($transferred), - ]; + 'transactions' => 0, + 'title' => $title, + 'route' => route( + 'tags.show', + [$tag->id, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')] + ), + 'total_transactions' => count($spent) + count($earned) + count($transferred), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred' => $this->groupByCurrency($transferred), + ]; } return $entries; @@ -512,7 +537,7 @@ trait PeriodOverview { $return = []; foreach ($set as $entry) { - $found = false; + $found = false; /** @var array $localTag */ foreach ($entry['tags'] as $localTag) { @@ -534,12 +559,12 @@ trait PeriodOverview */ protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array { - $range = app('navigation')->getViewRange(true); - $types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType)); + $range = app('navigation')->getViewRange(true); + $types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType)); [$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; // properties for cache - $cache = new CacheProperties(); + $cache = new CacheProperties(); $cache->addProperty($start); $cache->addProperty($end); $cache->addProperty('transactions-period-entries'); @@ -549,13 +574,13 @@ trait PeriodOverview } /** @var array $dates */ - $dates = app('navigation')->blockPeriods($start, $end, $range); - $entries = []; + $dates = app('navigation')->blockPeriods($start, $end, $range); + $entries = []; // collect all journals in this period (regardless of type) - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setTypes($types)->setRange($start, $end); - $genericSet = $collector->getExtractedJournals(); + $genericSet = $collector->getExtractedJournals(); foreach ($dates as $currentDate) { $spent = []; @@ -574,14 +599,14 @@ trait PeriodOverview $transferred = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']); } $entries[] - = [ - 'title' => $title, - 'route' => route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), - 'total_transactions' => count($spent) + count($earned) + count($transferred), - 'spent' => $this->groupByCurrency($spent), - 'earned' => $this->groupByCurrency($earned), - 'transferred' => $this->groupByCurrency($transferred), - ]; + = [ + 'title' => $title, + 'route' => route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]), + 'total_transactions' => count($spent) + count($earned) + count($transferred), + 'spent' => $this->groupByCurrency($spent), + 'earned' => $this->groupByCurrency($earned), + 'transferred' => $this->groupByCurrency($transferred), + ]; } return $entries; From 453ccd32710bc4d3660211a119400759f694042f Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 9 Mar 2025 09:54:14 +0100 Subject: [PATCH 6/6] Clean up overview. --- resources/views/list/periods.twig | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/resources/views/list/periods.twig b/resources/views/list/periods.twig index 2fde0b1c41..489ba2abe1 100644 --- a/resources/views/list/periods.twig +++ b/resources/views/list/periods.twig @@ -32,7 +32,11 @@ {{ 'earned'|_ }} - {{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }} + {% if entry.amount < 0 %} + {{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }} + {% else %} + {{ formatAmountBySymbol(entry.amount, entry.currency_symbol, entry.currency_decimal_places) }} + {% endif %} @@ -58,7 +62,11 @@ {{ 'transferred_away'|_ }} - {{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }} + {% if entry.amount < 0 %} + {{ formatAmountBySymbol(entry.amount, entry.currency_symbol, entry.currency_decimal_places) }} + {% else %} + {{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }} + {% endif %} @@ -71,7 +79,11 @@ {{ 'transferred_in'|_ }} - {{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }} + {% if entry.amount < 0 %} + {{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }} + {% else %} + {{ formatAmountBySymbol(entry.amount, entry.currency_symbol, entry.currency_decimal_places) }} + {% endif %}