🤖 Auto commit for release 'develop' on 2025-08-08

This commit is contained in:
JC5
2025-08-08 21:03:45 +02:00
parent 76e91be4dc
commit 92f534bcb3
14 changed files with 323 additions and 318 deletions

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Chart;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Chart\ChartRequest;
use FireflyIII\Enums\TransactionTypeEnum;
@@ -43,7 +42,7 @@ class BalanceController extends Controller
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
$this->collector->setUserGroup($userGroup);
$this->chartData = new ChartData();
$this->chartData = new ChartData();
// $this->default = app('amount')->getPrimaryCurrency();
return $next($request);
@@ -69,17 +68,18 @@ class BalanceController extends Controller
// prepare for currency conversion and data collection:
/** @var TransactionCurrency $primary */
$primary = Amount::getPrimaryCurrency();
$primary = Amount::getPrimaryCurrency();
// get journals for entire period:
$this->collector->setRange($queryParameters['start'], $queryParameters['end'])
->withAccountInformation()
->setXorAccounts($accounts)
->setTypes([TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::RECONCILIATION->value, TransactionTypeEnum::TRANSFER->value]);
$journals = $this->collector->getExtractedJournals();
->withAccountInformation()
->setXorAccounts($accounts)
->setTypes([TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::RECONCILIATION->value, TransactionTypeEnum::TRANSFER->value])
;
$journals = $this->collector->getExtractedJournals();
$object = new AccountBalanceGrouped();
$object = new AccountBalanceGrouped();
$object->setPreferredRange($queryParameters['period']);
$object->setPrimary($primary);
$object->setAccounts($accounts);
@@ -87,7 +87,7 @@ class BalanceController extends Controller
$object->setStart($queryParameters['start']);
$object->setEnd($queryParameters['end']);
$object->groupByCurrencyAndPeriod();
$data = $object->convertToChartData();
$data = $object->convertToChartData();
foreach ($data as $entry) {
$this->chartData->add($entry);
}

View File

@@ -43,6 +43,7 @@ use FireflyIII\Support\Http\Controllers\DateCalculation;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use function Safe\json_encode;
/**
@@ -87,14 +88,14 @@ class AccountController extends Controller
Log::debug('ExpenseAccounts');
/** @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());
$start->startOfDay();
$end->endOfDay();
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($this->convertToPrimary);
@@ -104,13 +105,13 @@ class AccountController extends Controller
}
// prep some vars:
$currencies = [];
$chartData = [];
$tempData = [];
$currencies = [];
$chartData = [];
$tempData = [];
// grab all accounts and names
$accounts = $this->accountRepository->getAccountsByType([AccountTypeEnum::EXPENSE->value]);
$accountNames = $this->extractNames($accounts);
$accounts = $this->accountRepository->getAccountsByType([AccountTypeEnum::EXPENSE->value]);
$accountNames = $this->extractNames($accounts);
// grab all balances
Log::debug(sprintf('expenseAccounts: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
@@ -144,14 +145,14 @@ class AccountController extends Controller
continue;
}
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToPrimary ? $this->primaryCurrency->code : $key;
$searchCode = 'balance' === $searchCode || 'pc_balance' === $searchCode ? $this->primaryCurrency->code : $searchCode;
$searchCode = $this->convertToPrimary ? $this->primaryCurrency->code : $key;
$searchCode = 'balance' === $searchCode || 'pc_balance' === $searchCode ? $this->primaryCurrency->code : $searchCode;
// Log::debug(sprintf('Search code is %s', $searchCode));
// see if there is an accompanying start amount.
// grab the difference and find the currency.
$startBalance = ($startBalances[$account->id][$key] ?? '0');
// Log::debug(sprintf('Start balance is %s', $startBalance));
$diff = bcsub($endBalance, $startBalance);
$diff = bcsub($endBalance, $startBalance);
$currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode);
if (0 !== bccomp($diff, '0')) {
// store the values in a temporary array.
@@ -169,26 +170,26 @@ class AccountController extends Controller
foreach ($currencies as $currency) {
$newCurrencies[$currency->id] = $currency;
}
$currencies = $newCurrencies;
$currencies = $newCurrencies;
// sort temp array by amount.
$amounts = array_column($tempData, 'diff_float');
$amounts = array_column($tempData, 'diff_float');
array_multisort($amounts, SORT_DESC, $tempData);
// loop all found currencies and build the data array for the chart.
/**
* @var int $currencyId
* @var int $currencyId
* @var TransactionCurrency $currency
*/
foreach ($currencies as $currencyId => $currency) {
$dataSet
= [
'label' => (string)trans('firefly.spent'),
'type' => 'bar',
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'entries' => $this->expandNames($tempData),
];
'label' => (string)trans('firefly.spent'),
'type' => 'bar',
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'entries' => $this->expandNames($tempData),
];
$chartData[$currencyId] = $dataSet;
}
@@ -199,7 +200,7 @@ class AccountController extends Controller
$chartData[$currencyId]['entries'][$name] = (float)$entry['difference'];
}
$data = $this->generator->multiSet($chartData);
$data = $this->generator->multiSet($chartData);
$cache->store($data);
return response()->json($data);
@@ -207,7 +208,6 @@ class AccountController extends Controller
/**
* Expenses per budget for all time, as shown on account overview.
*
*/
public function expenseBudgetAll(AccountRepositoryInterface $repository, Account $account): JsonResponse
{
@@ -222,7 +222,7 @@ class AccountController extends Controller
*/
public function expenseBudget(Account $account, Carbon $start, Carbon $end): JsonResponse
{
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty($start);
$cache->addProperty($this->convertToPrimary);
@@ -235,8 +235,9 @@ class AccountController extends Controller
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))
->setRange($start, $end)
->withBudgetInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
->setRange($start, $end)
->withBudgetInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
;
$journals = $collector->getExtractedJournals();
$chartData = [];
$result = [];
@@ -244,9 +245,9 @@ class AccountController extends Controller
/** @var array $journal */
foreach ($journals as $journal) {
$budgetId = (int)$journal['budget_id'];
$key = sprintf('%d-%d', $budgetId, $journal['currency_id']);
$budgetIds[] = $budgetId;
$budgetId = (int)$journal['budget_id'];
$key = sprintf('%d-%d', $budgetId, $journal['currency_id']);
$budgetIds[] = $budgetId;
// currency info:
$currencyId = (int)$journal['currency_id'];
@@ -277,7 +278,7 @@ class AccountController extends Controller
$result[$key]['total'] = bcadd((string)$journal[$field], $result[$key]['total']);
}
$names = $this->getBudgetNames($budgetIds);
$names = $this->getBudgetNames($budgetIds);
foreach ($result as $row) {
$budgetId = $row['budget_id'];
@@ -286,7 +287,7 @@ class AccountController extends Controller
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']];
}
$data = $this->generator->multiCurrencyPieChart($chartData);
$data = $this->generator->multiCurrencyPieChart($chartData);
$cache->store($data);
return response()->json($data);
@@ -308,14 +309,14 @@ class AccountController extends Controller
*/
public function expenseCategory(Account $account, Carbon $start, Carbon $end): JsonResponse
{
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($this->convertToPrimary);
$cache->addProperty('chart.account.expense-category');
if ($cache->has()) {
return response()->json($cache->get());
return response()->json($cache->get());
}
/** @var GroupCollectorInterface $collector */
@@ -327,7 +328,7 @@ class AccountController extends Controller
/** @var array $journal */
foreach ($journals as $journal) {
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
if (!array_key_exists($key, $result)) {
// currency info:
@@ -345,7 +346,7 @@ class AccountController extends Controller
$currencyDecimalPlaces = $this->primaryCurrency->decimal_places;
}
$result[$key] = [
$result[$key] = [
'total' => '0',
'category_id' => (int)$journal['category_id'],
'currency_name' => $currencyName,
@@ -356,7 +357,7 @@ class AccountController extends Controller
}
$result[$key]['total'] = bcadd((string)$journal[$field], $result[$key]['total']);
}
$names = $this->getCategoryNames(array_keys($result));
$names = $this->getCategoryNames(array_keys($result));
foreach ($result as $row) {
$categoryId = $row['category_id'];
@@ -365,7 +366,7 @@ class AccountController extends Controller
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']];
}
$data = $this->generator->multiCurrencyPieChart($chartData);
$data = $this->generator->multiCurrencyPieChart($chartData);
$cache->store($data);
return response()->json($data);
@@ -378,9 +379,9 @@ class AccountController extends Controller
* */
public function frontpage(AccountRepositoryInterface $repository): JsonResponse
{
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
$defaultSet = $repository->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
$defaultSet = $repository->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
// Log::debug('Default set is ', $defaultSet);
$frontpage = Preferences::get('frontpageAccounts', $defaultSet);
$frontpageArray = !is_array($frontpage->data) ? [] : $frontpage->data;
@@ -389,7 +390,7 @@ class AccountController extends Controller
Preferences::set('frontpageAccounts', $defaultSet);
Log::debug('frontpage set is empty!');
}
$accounts = $repository->getAccountsById($frontpageArray);
$accounts = $repository->getAccountsById($frontpageArray);
// move to end of day for $end.
$end->endOfDay();
@@ -413,14 +414,14 @@ class AccountController extends Controller
*/
public function incomeCategory(Account $account, Carbon $start, Carbon $end): JsonResponse
{
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty($start);
$cache->addProperty($this->convertToPrimary);
$cache->addProperty($end);
$cache->addProperty('chart.account.income-category');
if ($cache->has()) {
return response()->json($cache->get());
return response()->json($cache->get());
}
// grab all journals:
@@ -434,7 +435,7 @@ class AccountController extends Controller
/** @var array $journal */
foreach ($journals as $journal) {
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
if (!array_key_exists($key, $result)) {
// currency info:
@@ -452,26 +453,26 @@ class AccountController extends Controller
$currencyDecimalPlaces = $this->primaryCurrency->decimal_places;
}
$result[$key] = [
'total' => '0',
'category_id' => $journal['category_id'],
'currency_name' => $currencyName,
'currency_code' => $currencyCode,
'currency_symbol' => $currencySymbol,
$result[$key] = [
'total' => '0',
'category_id' => $journal['category_id'],
'currency_name' => $currencyName,
'currency_code' => $currencyCode,
'currency_symbol' => $currencySymbol,
'currency_decimal_places' => $currencyDecimalPlaces,
];
}
$result[$key]['total'] = bcadd((string)$journal[$field], $result[$key]['total']);
}
$names = $this->getCategoryNames(array_keys($result));
$names = $this->getCategoryNames(array_keys($result));
foreach ($result as $row) {
$categoryId = $row['category_id'];
$name = $names[$categoryId] ?? '(unknown)';
$label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]);
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']];
}
$data = $this->generator->multiCurrencyPieChart($chartData);
$data = $this->generator->multiCurrencyPieChart($chartData);
$cache->store($data);
return response()->json($data);
@@ -488,7 +489,7 @@ class AccountController extends Controller
$end->endOfDay();
// TODO not sure if these date ranges will work as expected.
Log::debug(sprintf('Now in period("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty('chart.account.period');
$cache->addProperty($start);
$cache->addProperty($end);
@@ -499,10 +500,10 @@ class AccountController extends Controller
}
// collect and filter balances for the entire period.
$step = $this->calculateStep($start, $end);
$step = $this->calculateStep($start, $end);
Log::debug(sprintf('Step is %s', $step));
$locale = Steam::getLocale();
$return = [];
$locale = Steam::getLocale();
$return = [];
// fix for issue https://github.com/firefly-iii/firefly-iii/issues/8041
// have to make sure this chart is always based on the balance at the END of the period.
@@ -512,8 +513,8 @@ class AccountController extends Controller
$format = (string)trans('config.month_and_day_js', [], $locale);
$accountCurrency = $this->accountRepository->getAccountCurrency($account);
$range = Steam::finalAccountBalanceInRange($account, $start, $end, $this->convertToPrimary);
$range = Steam::filterAccountBalances($range, $account, $this->convertToPrimary, $accountCurrency);
$range = Steam::finalAccountBalanceInRange($account, $start, $end, $this->convertToPrimary);
$range = Steam::filterAccountBalances($range, $account, $this->convertToPrimary, $accountCurrency);
// temp, get end balance.
Log::debug(sprintf('period: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
@@ -524,14 +525,14 @@ class AccountController extends Controller
$accountCurrency ??= $this->primaryCurrency; // do this AFTER getting the balances.
Log::debug('Start chart loop.');
$newRange = [];
$expectedIndex = 0;
$newRange = [];
$expectedIndex = 0;
Log::debug('Balances exist at:');
foreach ($range as $key => $value) {
$newRange[] = ['date' => $key, 'info' => $value];
Log::debug(sprintf('%d - %s (%s)', count($newRange) - 1, $key, json_encode($value)));
}
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[0]['date'])->endOfDay();
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[0]['date'])->endOfDay();
Log::debug(sprintf('Start of loop, $carbon is %s', $carbon->format('Y-m-d H:i:s')));
while ($end->gte($current)) {
$momentBalance = $previous;
@@ -552,21 +553,21 @@ class AccountController extends Controller
}
}
Log::debug(sprintf('momentBalance is now %s', json_encode($momentBalance)));
$return = $this->updateChartKeys($return, $momentBalance);
$previous = $momentBalance;
$return = $this->updateChartKeys($return, $momentBalance);
$previous = $momentBalance;
// process each balance thing.
foreach ($momentBalance as $key => $amount) {
$label = $current->isoFormat($format);
$return[$key]['entries'][$label] = $amount;
}
$current = app('navigation')->addPeriod($current, $step, 0);
$current = app('navigation')->addPeriod($current, $step, 0);
// here too, to fix #8041, the data is corrected to the end of the period.
$current = app('navigation')->endOfX($current, $step, null);
$current = app('navigation')->endOfX($current, $step, null);
}
Log::debug('End of chart loop.');
// second loop (yes) to create nice array with info! Yay!
$chartData = [];
$chartData = [];
foreach ($return as $key => $info) {
if ('balance' !== $key && 'pc_balance' !== $key) {
@@ -589,7 +590,7 @@ class AccountController extends Controller
$chartData[] = $info;
}
$data = $this->generator->multiSet($chartData);
$data = $this->generator->multiSet($chartData);
$cache->store($data);
return response()->json($data);
@@ -626,15 +627,15 @@ class AccountController extends Controller
public function revenueAccounts(): JsonResponse
{
/** @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());
$start->startOfDay();
$end->endOfDay();
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($this->convertToPrimary);
@@ -644,13 +645,13 @@ class AccountController extends Controller
}
// prep some vars:
$currencies = [];
$chartData = [];
$tempData = [];
$currencies = [];
$chartData = [];
$tempData = [];
// grab all accounts and names
$accounts = $this->accountRepository->getAccountsByType([AccountTypeEnum::REVENUE->value]);
$accountNames = $this->extractNames($accounts);
$accounts = $this->accountRepository->getAccountsByType([AccountTypeEnum::REVENUE->value]);
$accountNames = $this->extractNames($accounts);
// grab all balances
Log::debug(sprintf('revAccounts: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
@@ -685,14 +686,14 @@ class AccountController extends Controller
continue;
}
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToPrimary ? $this->primaryCurrency->code : $key;
$searchCode = 'balance' === $searchCode || 'pc_balance' === $searchCode ? $this->primaryCurrency->code : $searchCode;
$searchCode = $this->convertToPrimary ? $this->primaryCurrency->code : $key;
$searchCode = 'balance' === $searchCode || 'pc_balance' === $searchCode ? $this->primaryCurrency->code : $searchCode;
// Log::debug(sprintf('Search code is %s', $searchCode));
// see if there is an accompanying start amount.
// grab the difference and find the currency.
$startBalance = ($startBalances[$account->id][$key] ?? '0');
// Log::debug(sprintf('Start balance is %s', $startBalance));
$diff = bcsub($endBalance, $startBalance);
$diff = bcsub($endBalance, $startBalance);
$currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode);
if (0 !== bccomp($diff, '0')) {
// store the values in a temporary array.
@@ -712,26 +713,26 @@ class AccountController extends Controller
foreach ($currencies as $currency) {
$newCurrencies[$currency->id] = $currency;
}
$currencies = $newCurrencies;
$currencies = $newCurrencies;
// sort temp array by amount.
$amounts = array_column($tempData, 'diff_float');
$amounts = array_column($tempData, 'diff_float');
array_multisort($amounts, SORT_ASC, $tempData);
// loop all found currencies and build the data array for the chart.
/**
* @var int $currencyId
* @var int $currencyId
* @var TransactionCurrency $currency
*/
foreach ($currencies as $currencyId => $currency) {
$dataSet
= [
'label' => (string)trans('firefly.earned'),
'type' => 'bar',
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'entries' => $this->expandNames($tempData),
];
'label' => (string)trans('firefly.earned'),
'type' => 'bar',
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'entries' => $this->expandNames($tempData),
];
$chartData[$currencyId] = $dataSet;
}
@@ -742,7 +743,7 @@ class AccountController extends Controller
$chartData[$currencyId]['entries'][$name] = bcmul($entry['difference'], '-1');
}
$data = $this->generator->multiSet($chartData);
$data = $this->generator->multiSet($chartData);
$cache->store($data);
return response()->json($data);

View File

@@ -85,52 +85,52 @@ class ShowController extends Controller
public function show(TransactionGroup $transactionGroup)
{
/** @var User $admin */
$admin = auth()->user();
$admin = auth()->user();
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setUser($admin)->setTransactionGroup($transactionGroup)->withAPIInformation();
$selectedGroup = $collector->getGroups()->first();
$selectedGroup = $collector->getGroups()->first();
if (null === $selectedGroup) {
throw new NotFoundHttpException();
}
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
/** @var null|TransactionJournal $first */
$first = $transactionGroup->transactionJournals()->first(['transaction_journals.*']);
$splits = $transactionGroup->transactionJournals()->count();
$splits = count($selectedGroup['transactions']);
$keys = array_keys($selectedGroup['transactions']);
$first = $selectedGroup['transactions'][array_shift($keys)];
$first = $transactionGroup->transactionJournals()->first(['transaction_journals.*']);
$splits = $transactionGroup->transactionJournals()->count();
$splits = count($selectedGroup['transactions']);
$keys = array_keys($selectedGroup['transactions']);
$first = $selectedGroup['transactions'][array_shift($keys)];
unset($keys);
if (null === $first) {
throw new FireflyException('This transaction is broken :(.');
}
$type = (string)trans(sprintf('firefly.%s', $first['transaction_type_type']));
$title = 1 === $splits ? $first['description'] : $selectedGroup['title'];
$subTitle = sprintf('%s: "%s"', $type, $title);
$type = (string)trans(sprintf('firefly.%s', $first['transaction_type_type']));
$title = 1 === $splits ? $first['description'] : $selectedGroup['title'];
$subTitle = sprintf('%s: "%s"', $type, $title);
// enrich
$enrichment = new TransactionGroupEnrichment();
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
/** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class);
$transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters(new ParameterBag());
$groupArray = $transformer->transformObject($transactionGroup);
$groupArray = $transformer->transformObject($transactionGroup);
// do some calculations:
$amounts = $this->getAmounts($selectedGroup);
$accounts = $this->getAccounts($selectedGroup);
$amounts = $this->getAmounts($selectedGroup);
$accounts = $this->getAccounts($selectedGroup);
foreach (array_keys($selectedGroup['transactions']) as $index) {
$selectedGroup['transactions'][$index]['tags'] = $this->repository->getTagObjects((int)$selectedGroup['transactions'][$index]['transaction_journal_id']);
@@ -142,9 +142,9 @@ class ShowController extends Controller
$logEntries[$journal['transaction_journal_id']] = $this->aleRepository->getForId(TransactionJournal::class, $journal['transaction_journal_id']);
}
$events = $this->repository->getPiggyEvents($transactionGroup);
$attachments = $this->repository->getAttachments($transactionGroup);
$links = $this->repository->getLinks($transactionGroup);
$events = $this->repository->getPiggyEvents($transactionGroup);
$attachments = $this->repository->getAttachments($transactionGroup);
$links = $this->repository->getLinks($transactionGroup);
return view(
'transactions.show',
@@ -173,7 +173,7 @@ class ShowController extends Controller
foreach ($group['transactions'] as $transaction) {
// add normal amount:
$symbol = $transaction['currency_symbol'];
$amounts[$symbol] ??= [
$amounts[$symbol] ??= [
'amount' => '0',
'symbol' => $symbol,
'decimal_places' => $transaction['currency_decimal_places'],
@@ -184,7 +184,7 @@ class ShowController extends Controller
if (null !== $transaction['foreign_amount'] && '' !== $transaction['foreign_amount'] && 0 !== bccomp('0', (string)$transaction['foreign_amount'])) {
// same for foreign currency:
$foreignSymbol = $transaction['foreign_currency_symbol'];
$amounts[$foreignSymbol] ??= [
$amounts[$foreignSymbol] ??= [
'amount' => '0',
'symbol' => $foreignSymbol,
'decimal_places' => $transaction['foreign_currency_decimal_places'],
@@ -195,7 +195,7 @@ class ShowController extends Controller
if (null !== $transaction['pc_amount'] && $transaction['currency_id'] !== $this->primaryCurrency->id) {
// same for foreign currency:
$primarySymbol = $this->primaryCurrency->symbol;
$amounts[$primarySymbol] ??= [
$amounts[$primarySymbol] ??= [
'amount' => '0',
'symbol' => $this->primaryCurrency->symbol,
'decimal_places' => $this->primaryCurrency->decimal_places,
@@ -210,7 +210,7 @@ class ShowController extends Controller
private function getAccounts(array $group): array
{
$accounts = [
$accounts = [
'source' => [],
'destination' => [],
];

View File

@@ -567,8 +567,8 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
'transaction_journals.transaction_currency_id',
'transactions.amount',
'transactions.native_amount',
'transactions.foreign_amount'
])
'transactions.foreign_amount',
])
->toArray()
;

View File

@@ -45,8 +45,8 @@ use Illuminate\Support\Collection;
interface ALERepositoryInterface
{
public function getForObject(Model $model): Collection;
public function getForId(string $model, int $modelId): Collection;
public function getForId(string $model, int $modelId): Collection;
public function store(array $data): AuditLogEntry;
}

View File

@@ -58,15 +58,15 @@ class Amount
*/
public function formatFlat(string $symbol, int $decimalPlaces, string $amount, ?bool $coloured = null): string
{
$locale = app('steam')->getLocale();
$rounded = app('steam')->bcround($amount, $decimalPlaces);
$locale = app('steam')->getLocale();
$rounded = app('steam')->bcround($amount, $decimalPlaces);
$coloured ??= true;
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $symbol);
$fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces);
$fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces);
$result = (string)$fmt->format((float)$rounded); // intentional float
$result = (string)$fmt->format((float)$rounded); // intentional float
if (true === $coloured) {
if (1 === bccomp((string)$rounded, '0')) {
@@ -122,15 +122,18 @@ class Amount
if (null === $pref) {
$res = true === Preferences::get('convert_to_primary', false)->data && true === config('cer.enabled');
$instance->setPreference('convert_to_primary_no_user', $res);
return $res;
}
return $pref;
}
$key = sprintf('convert_to_primary_%d', $user->id);
$pref = $instance->getPreference($key);
if(null === $pref) {
$key = sprintf('convert_to_primary_%d', $user->id);
$pref = $instance->getPreference($key);
if (null === $pref) {
$res = true === Preferences::getForUser($user, 'convert_to_primary', false)->data && true === config('cer.enabled');
$instance->setPreference($key, $res);
return $res;
}
@@ -152,7 +155,7 @@ class Amount
public function getPrimaryCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency
{
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty('getPrimaryCurrencyByGroup');
$cache->addProperty($userGroup->id);
if ($cache->has()) {
@@ -182,16 +185,16 @@ class Amount
*/
public function getAmountFromJournalObject(TransactionJournal $journal): string
{
$convertToPrimary = $this->convertToPrimary();
$currency = $this->getPrimaryCurrency();
$field = $convertToPrimary && $currency->id !== $journal->transaction_currency_id ? 'pc_amount' : 'amount';
$convertToPrimary = $this->convertToPrimary();
$currency = $this->getPrimaryCurrency();
$field = $convertToPrimary && $currency->id !== $journal->transaction_currency_id ? 'pc_amount' : 'amount';
/** @var null|Transaction $sourceTransaction */
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
if (null === $sourceTransaction) {
return '0';
}
$amount = $sourceTransaction->{$field} ?? '0';
$amount = $sourceTransaction->{$field} ?? '0';
if ((int)$sourceTransaction->foreign_currency_id === $currency->id) {
// use foreign amount instead!
$amount = (string)$sourceTransaction->foreign_amount; // hard coded to be foreign amount.
@@ -239,20 +242,20 @@ class Amount
private function getLocaleInfo(): array
{
// get config from preference, not from translation:
$locale = app('steam')->getLocale();
$array = app('steam')->getLocaleArray($locale);
$locale = app('steam')->getLocale();
$array = app('steam')->getLocaleArray($locale);
setlocale(LC_MONETARY, $array);
$info = localeconv();
$info = localeconv();
// correct variables
$info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes');
$info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes');
$info['n_cs_precedes'] = $this->getLocaleField($info, 'n_cs_precedes');
$info['p_cs_precedes'] = $this->getLocaleField($info, 'p_cs_precedes');
$info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space');
$info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space');
$info['n_sep_by_space'] = $this->getLocaleField($info, 'n_sep_by_space');
$info['p_sep_by_space'] = $this->getLocaleField($info, 'p_sep_by_space');
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$fmt = new NumberFormatter($locale, NumberFormatter::CURRENCY);
$info['mon_decimal_point'] = $fmt->getSymbol(NumberFormatter::MONETARY_SEPARATOR_SYMBOL);
$info['mon_thousands_sep'] = $fmt->getSymbol(NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL);
@@ -284,11 +287,11 @@ class Amount
// there are five possible positions for the "+" or "-" sign (if it is even used)
// pos_a and pos_e could be the ( and ) symbol.
$posA = ''; // before everything
$posB = ''; // before currency symbol
$posC = ''; // after currency symbol
$posD = ''; // before amount
$posE = ''; // after everything
$posA = ''; // before everything
$posB = ''; // before currency symbol
$posC = ''; // after currency symbol
$posD = ''; // before amount
$posE = ''; // after everything
// format would be (currency before amount)
// AB%sC_D%vE
@@ -330,9 +333,9 @@ class Amount
}
if ($csPrecedes) {
return $posA . $posB . '%s' . $posC . $space . $posD . '%v' . $posE;
return $posA.$posB.'%s'.$posC.$space.$posD.'%v'.$posE;
}
return $posA . $posD . '%v' . $space . $posB . '%s' . $posC . $posE;
return $posA.$posD.'%v'.$space.$posB.'%s'.$posC.$posE;
}
}

View File

@@ -56,7 +56,7 @@ trait ChartGeneration
$cache->addProperty($accounts);
$cache->addProperty($convertToPrimary);
if ($cache->has()) {
return $cache->get();
return $cache->get();
}
Log::debug('Regenerate chart.account.account-balance-chart from scratch.');
$locale = app('steam')->getLocale();

View File

@@ -83,10 +83,10 @@ trait PeriodOverview
Timer::start('account-period-total');
$this->accountRepository = app(AccountRepositoryInterface::class);
$range = Navigation::getViewRange(true);
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
[$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');
@@ -96,35 +96,35 @@ trait PeriodOverview
}
/** @var array $dates */
$dates = Navigation::blockPeriods($start, $end, $range);
$entries = [];
$spent = [];
$earned = [];
$transferredAway = [];
$transferredIn = [];
$dates = Navigation::blockPeriods($start, $end, $range);
$entries = [];
$spent = [];
$earned = [];
$transferredAway = [];
$transferredIn = [];
// run a custom query because doing this with the collector is MEGA slow.
$transactions = $this->accountRepository->periodCollection($account, $start, $end);
$transactions = $this->accountRepository->periodCollection($account, $start, $end);
// loop dates
Log::debug(sprintf('Count of loops: %d', count($dates)));
$loops = 0;
$loops = 0;
// stop after 10 loops for memory reasons.
foreach ($dates as $currentDate) {
$title = Navigation::periodShow($currentDate['start'], $currentDate['period']);
[$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']);
[$transactions, $earned] = $this->filterTransactionsByType(TransactionTypeEnum::DEPOSIT, $transactions, $currentDate['start'], $currentDate['end']);
$title = Navigation::periodShow($currentDate['start'], $currentDate['period']);
[$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']);
[$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),
];
++$loops;
}
$cache->store($entries);
@@ -136,11 +136,11 @@ trait PeriodOverview
private function filterTransactionsByType(TransactionTypeEnum $type, array $transactions, Carbon $start, Carbon $end): array
{
$result = [];
$result = [];
$filtered = [];
/**
* @var int $index
* @var int $index
* @var array $item
*/
foreach ($transactions as $index => $item) {
@@ -150,7 +150,7 @@ trait PeriodOverview
$result[] = $item;
unset($transactions[$index]);
}
if(!$fits) {
if (!$fits) {
$filtered[] = $item;
}
}
@@ -160,11 +160,11 @@ trait PeriodOverview
private function filterTransfers(string $direction, array $transactions, Carbon $start, Carbon $end): array
{
$result = [];
$result = [];
$filtered = [];
/**
* @var int $index
* @var int $index
* @var array $item
*/
foreach ($transactions as $index => $item) {
@@ -172,10 +172,12 @@ trait PeriodOverview
if ($date >= $start && $date <= $end) {
if ('away' === $direction && -1 === bccomp((string)$item['amount'], '0')) {
$result[] = $item;
continue;
}
if ('in' === $direction && 1 === bccomp((string)$item['amount'], '0')) {
$result[] = $item;
continue;
}
$filtered[] = $item;
@@ -191,13 +193,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->convertToPrimary && $currencyId !== $this->primaryCurrency->id && $foreignCurrencyId !== $this->primaryCurrency->id) {
$amount = $journal['pc_amount'] ?? '0';
@@ -240,11 +242,11 @@ trait PeriodOverview
*/
protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array
{
$range = Navigation::getViewRange(true);
$range = 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);
@@ -256,32 +258,32 @@ trait PeriodOverview
}
/** @var array $dates */
$dates = Navigation::blockPeriods($start, $end, $range);
$entries = [];
$dates = 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']);
@@ -289,17 +291,17 @@ trait PeriodOverview
$title = 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);
@@ -332,11 +334,11 @@ trait PeriodOverview
*/
protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array
{
$range = Navigation::getViewRange(true);
$range = 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->convertToPrimary);
@@ -347,28 +349,28 @@ trait PeriodOverview
}
/** @var array $dates */
$dates = Navigation::blockPeriods($start, $end, $range);
$entries = [];
$dates = 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 = 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);
@@ -385,38 +387,38 @@ trait PeriodOverview
protected function getNoCategoryPeriodOverview(Carbon $theDate): array
{
app('log')->debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d')));
$range = Navigation::getViewRange(true);
$first = $this->journalRepos->firstNull();
$start = null === $first ? new Carbon() : $first->date;
$end = clone $theDate;
$end = Navigation::endOfPeriod($end, $range);
$range = Navigation::getViewRange(true);
$first = $this->journalRepos->firstNull();
$start = null === $first ? new Carbon() : $first->date;
$end = clone $theDate;
$end = 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 = Navigation::blockPeriods($start, $end, $range);
$entries = [];
$dates = 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]);
@@ -430,13 +432,13 @@ trait PeriodOverview
$title = 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');
@@ -450,11 +452,11 @@ trait PeriodOverview
*/
protected function getTagPeriodOverview(Tag $tag, Carbon $start, Carbon $end): array // period overview for tags.
{
$range = Navigation::getViewRange(true);
$range = 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');
@@ -464,37 +466,37 @@ trait PeriodOverview
}
/** @var array $dates */
$dates = Navigation::blockPeriods($start, $end, $range);
$entries = [];
$dates = 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']);
@@ -503,17 +505,17 @@ trait PeriodOverview
$title = 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;
@@ -523,7 +525,7 @@ trait PeriodOverview
{
$return = [];
foreach ($set as $entry) {
$found = false;
$found = false;
/** @var array $localTag */
foreach ($entry['tags'] as $localTag) {
@@ -545,12 +547,12 @@ trait PeriodOverview
*/
protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array
{
$range = Navigation::getViewRange(true);
$types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType));
$range = 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');
@@ -560,16 +562,16 @@ trait PeriodOverview
}
/** @var array $dates */
$dates = Navigation::blockPeriods($start, $end, $range);
$entries = [];
$spent = [];
$earned = [];
$transferred = [];
$dates = Navigation::blockPeriods($start, $end, $range);
$entries = [];
$spent = [];
$earned = [];
$transferred = [];
// 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();
$loops = 0;
$genericSet = $collector->getExtractedJournals();
$loops = 0;
foreach ($dates as $currentDate) {
$title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
@@ -587,14 +589,14 @@ trait PeriodOverview
}
}
$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),
];
++$loops;
}

View File

@@ -284,9 +284,9 @@ class Preferences
*/
public function lastActivity(): string
{
$instance = PreferencesSingleton::getInstance();
$pref = $instance->getPreference('last_activity');
if(null !== $pref) {
$instance = PreferencesSingleton::getInstance();
$pref = $instance->getPreference('last_activity');
if (null !== $pref) {
// Log::debug(sprintf('Found last activity in singleton: %s', $pref));
return $pref;
}
@@ -299,8 +299,9 @@ class Preferences
if (is_array($lastActivity)) {
$lastActivity = implode(',', $lastActivity);
}
$setting = hash('sha256', (string) $lastActivity);
$setting = hash('sha256', (string) $lastActivity);
$instance->setPreference('last_activity', $setting);
return $setting;
}

View File

@@ -1,28 +1,31 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Support\Singleton;
class PreferencesSingleton
{
private static ?PreferencesSingleton $instance = null;
private array $preferences = [];
private array $preferences = [];
private function __construct()
{
// Private constructor to prevent direct instantiation.
}
public static function getInstance(): PreferencesSingleton
public static function getInstance(): self
{
if (self::$instance === null) {
self::$instance = new PreferencesSingleton();
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function resetPreferences(): void {
public function resetPreferences(): void
{
$this->preferences = [];
}
@@ -35,5 +38,4 @@ class PreferencesSingleton
{
return $this->preferences[$key] ?? null;
}
}

22
composer.lock generated
View File

@@ -939,16 +939,16 @@
},
{
"name": "filp/whoops",
"version": "2.18.3",
"version": "2.18.4",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "59a123a3d459c5a23055802237cb317f609867e5"
"reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5",
"reference": "59a123a3d459c5a23055802237cb317f609867e5",
"url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d",
"reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d",
"shasum": ""
},
"require": {
@@ -998,7 +998,7 @@
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.18.3"
"source": "https://github.com/filp/whoops/tree/2.18.4"
},
"funding": [
{
@@ -1006,7 +1006,7 @@
"type": "github"
}
],
"time": "2025-06-16T00:02:10+00:00"
"time": "2025-08-08T12:00:00+00:00"
},
{
"name": "firebase/php-jwt",
@@ -1879,16 +1879,16 @@
},
{
"name": "laravel/framework",
"version": "v12.22.0",
"version": "v12.22.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "6ab00c913ef6ec6fad0bd506f7452c0bb9e792c3"
"reference": "d33ee45184126f32f593d4b809a846ed88a1dc43"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/6ab00c913ef6ec6fad0bd506f7452c0bb9e792c3",
"reference": "6ab00c913ef6ec6fad0bd506f7452c0bb9e792c3",
"url": "https://api.github.com/repos/laravel/framework/zipball/d33ee45184126f32f593d4b809a846ed88a1dc43",
"reference": "d33ee45184126f32f593d4b809a846ed88a1dc43",
"shasum": ""
},
"require": {
@@ -2090,7 +2090,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-08-07T13:49:53+00:00"
"time": "2025-08-08T13:58:03+00:00"
},
{
"name": "laravel/passport",

View File

@@ -79,7 +79,7 @@ return [
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2025-08-08',
'build_time' => 1754630161,
'build_time' => 1754679717,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 26,

12
package-lock.json generated
View File

@@ -3148,9 +3148,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.2.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.0.tgz",
"integrity": "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==",
"version": "24.2.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz",
"integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4486,9 +4486,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001731",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz",
"integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==",
"version": "1.0.30001733",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001733.tgz",
"integrity": "sha512-e4QKw/O2Kavj2VQTKZWrwzkt3IxOmIlU6ajRb6LP64LHpBo1J67k2Hi4Vu/TgJWsNtynurfS0uK3MaUTCPfu5Q==",
"dev": true,
"funding": [
{

View File

@@ -24,10 +24,6 @@ declare(strict_types=1);
use Illuminate\Support\Facades\Route;
/*
* ____ ____ __ .______ ______ __ __ .___________. _______ _______.
* \ \ / / /_ | | _ \ / __ \ | | | | | || ____| / |