🤖 Auto commit for release 'develop' on 2026-01-23

This commit is contained in:
JC5
2026-01-23 15:14:29 +01:00
parent 8f15a32bd6
commit eeeba86d38
888 changed files with 10732 additions and 10387 deletions

View File

@@ -68,11 +68,11 @@ class BudgetController extends Controller
parent::__construct();
$this->middleware(function ($request, $next) {
$this->generator = app(GeneratorInterface::class);
$this->repository = app(BudgetRepositoryInterface::class);
$this->generator = app(GeneratorInterface::class);
$this->repository = app(BudgetRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->nbRepository = app(NoBudgetRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->nbRepository = app(NoBudgetRepositoryInterface::class);
return $next($request);
});
@@ -84,11 +84,11 @@ class BudgetController extends Controller
public function budget(Budget $budget): JsonResponse
{
/** @var Carbon $start */
$start = $this->repository->firstUseDate($budget) ?? session('start', today(config('app.timezone')));
$start = $this->repository->firstUseDate($budget) ?? session('start', today(config('app.timezone')));
/** @var Carbon $end */
$end = session('end', today(config('app.timezone')));
$cache = new CacheProperties();
$end = session('end', today(config('app.timezone')));
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($this->convertToPrimary);
@@ -98,7 +98,7 @@ class BudgetController extends Controller
if ($cache->has()) {
return response()->json($cache->get());
}
$step = $this->calculateStep($start, $end); // depending on diff, do something with range of chart.
$step = $this->calculateStep($start, $end); // depending on diff, do something with range of chart.
$collection = new Collection()->push($budget);
$chartData = [];
$loopStart = clone $start;
@@ -107,19 +107,19 @@ class BudgetController extends Controller
$defaultEntries = [];
while ($end >= $loopStart) {
/** @var Carbon $loopEnd */
$loopEnd = Navigation::endOfPeriod($loopStart, $step);
$spent = $this->opsRepository->sumExpenses($loopStart, $loopEnd, null, $collection); // this method already converts to primary currency.
$label = trim(Navigation::periodShow($loopStart, $step));
$loopEnd = Navigation::endOfPeriod($loopStart, $step);
$spent = $this->opsRepository->sumExpenses($loopStart, $loopEnd, null, $collection); // this method already converts to primary currency.
$label = trim(Navigation::periodShow($loopStart, $step));
foreach ($spent as $row) {
$currencyId = $row['currency_id'];
$currencyId = $row['currency_id'];
$currencies[$currencyId] ??= $row; // don't mind the field 'sum'
// also store this day's sum:
$currencies[$currencyId]['spent'][$label] = $row['sum'];
}
$defaultEntries[$label] = 0;
// set loop start to the next period:
$loopStart = clone $loopEnd;
$loopStart = clone $loopEnd;
$loopStart->addSecond();
}
// loop all currencies:
@@ -129,13 +129,13 @@ class BudgetController extends Controller
'type' => 'bar',
'currency_symbol' => $currency['currency_symbol'],
'currency_code' => $currency['currency_code'],
'entries' => $defaultEntries
'entries' => $defaultEntries,
];
foreach ($currency['spent'] as $label => $spent) {
$chartData[$currencyId]['entries'][$label] = bcmul((string) $spent, '-1');
}
}
$data = $this->generator->multiSet(array_values($chartData));
$data = $this->generator->multiSet(array_values($chartData));
$cache->store($data);
return response()->json($data);
@@ -152,9 +152,9 @@ class BudgetController extends Controller
throw new FireflyException('This budget limit is not part of this budget.');
}
$start = clone $budgetLimit->start_date;
$end = clone $budgetLimit->end_date;
$cache = new CacheProperties();
$start = clone $budgetLimit->start_date;
$end = clone $budgetLimit->end_date;
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($this->convertToPrimary);
@@ -165,19 +165,19 @@ class BudgetController extends Controller
if ($cache->has()) {
return response()->json($cache->get());
}
$locale = Steam::getLocale();
$entries = [];
$amount = $budgetLimit->amount ?? '0';
$budgetCollection = new Collection()->push($budget);
$currency = $budgetLimit->transactionCurrency;
$locale = Steam::getLocale();
$entries = [];
$amount = $budgetLimit->amount ?? '0';
$budgetCollection = new Collection()->push($budget);
$currency = $budgetLimit->transactionCurrency;
if ($this->convertToPrimary) {
$amount = $budgetLimit->native_amount ?? $amount;
$currency = $this->primaryCurrency;
}
while ($start <= $end) {
$current = clone $start;
$expenses = $this->opsRepository->sumExpenses(
$current = clone $start;
$expenses = $this->opsRepository->sumExpenses(
$current,
$current,
null,
@@ -185,17 +185,17 @@ class BudgetController extends Controller
$budgetLimit->transactionCurrency,
$this->convertToPrimary
);
$spent = $expenses[$currency->id]['sum'] ?? '0';
$amount = bcadd((string) $amount, $spent);
$format = $start->isoFormat((string) trans('config.month_and_day_js', [], $locale));
$spent = $expenses[$currency->id]['sum'] ?? '0';
$amount = bcadd((string) $amount, $spent);
$format = $start->isoFormat((string) trans('config.month_and_day_js', [], $locale));
$entries[$format] = $amount;
$start->addDay();
}
$data = $this->generator->singleSet((string) trans('firefly.left'), $entries);
$data = $this->generator->singleSet((string) trans('firefly.left'), $entries);
// add currency symbol from budget limit:
$data['datasets'][0]['currency_symbol'] = $currency->symbol;
$data['datasets'][0]['currency_code'] = $currency->code;
$data['datasets'][0]['currency_code'] = $currency->code;
$cache->store($data);
// var_dump($data);exit;
@@ -205,7 +205,7 @@ class BudgetController extends Controller
/**
* Shows how much is spent per asset account.
*/
public function expenseAsset(Budget $budget, null|BudgetLimit $budgetLimit = null): JsonResponse
public function expenseAsset(Budget $budget, ?BudgetLimit $budgetLimit = null): JsonResponse
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
@@ -215,8 +215,8 @@ class BudgetController extends Controller
$cache->addProperty($this->convertToPrimary);
$cache->addProperty($budgetLimitId);
$cache->addProperty('chart.budget.expense-asset');
$start = session('first', today(config('app.timezone'))->startOfYear());
$end = today();
$start = session('first', today(config('app.timezone'))->startOfYear());
$end = today();
if ($budgetLimit instanceof BudgetLimit) {
$start = $budgetLimit->start_date;
@@ -231,18 +231,18 @@ class BudgetController extends Controller
}
$collector->setRange($start, $end);
$collector->setBudget($budget);
$journals = $collector->getExtractedJournals();
$result = [];
$chartData = [];
$journals = $collector->getExtractedJournals();
$result = [];
$chartData = [];
// group by asset account ID:
foreach ($journals as $journal) {
$key = sprintf('%d-%d', $journal['source_account_id'], $journal['currency_id']);
$amount = $journal['amount'];
$key = sprintf('%d-%d', $journal['source_account_id'], $journal['currency_id']);
$amount = $journal['amount'];
$symbol = $journal['currency_symbol'];
$code = $journal['currency_code'];
$name = $journal['currency_name'];
$symbol = $journal['currency_symbol'];
$code = $journal['currency_code'];
$name = $journal['currency_name'];
// if convert to primary, use the primary things, unless it's the foreign amount which is in the primary currency.
if ($this->convertToPrimary && $journal['currency_id'] !== $this->primaryCurrency->id) {
@@ -261,19 +261,19 @@ class BudgetController extends Controller
$result[$key]['amount'] = bcadd((string) $amount, $result[$key]['amount']);
}
$names = $this->getAccountNames(array_keys($result));
$names = $this->getAccountNames(array_keys($result));
foreach ($result as $combinedId => $info) {
$parts = explode('-', $combinedId);
$assetId = (int) $parts[0];
$title = sprintf('%s (%s)', $names[$assetId] ?? '(empty)', $info['currency_name']);
$parts = explode('-', $combinedId);
$assetId = (int) $parts[0];
$title = sprintf('%s (%s)', $names[$assetId] ?? '(empty)', $info['currency_name']);
$chartData[$title] = [
'amount' => $info['amount'],
'currency_symbol' => $info['currency_symbol'],
'currency_code' => $info['currency_code']
'currency_code' => $info['currency_code'],
];
}
$data = $this->generator->multiCurrencyPieChart($chartData);
$data = $this->generator->multiCurrencyPieChart($chartData);
$cache->store($data);
return response()->json($data);
@@ -282,7 +282,7 @@ class BudgetController extends Controller
/**
* Shows how much is spent per category.
*/
public function expenseCategory(Budget $budget, null|BudgetLimit $budgetLimit = null): JsonResponse
public function expenseCategory(Budget $budget, ?BudgetLimit $budgetLimit = null): JsonResponse
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
@@ -292,8 +292,8 @@ class BudgetController extends Controller
$cache->addProperty($this->convertToPrimary);
$cache->addProperty($budgetLimitId);
$cache->addProperty('chart.budget.expense-category');
$start = session('first', today(config('app.timezone'))->startOfYear());
$end = today();
$start = session('first', today(config('app.timezone'))->startOfYear());
$end = today();
if ($budgetLimit instanceof BudgetLimit) {
$start = $budgetLimit->start_date;
$end = $budgetLimit->end_date;
@@ -307,15 +307,15 @@ class BudgetController extends Controller
}
$collector->setRange($start, $end);
$collector->setBudget($budget)->withCategoryInformation();
$journals = $collector->getExtractedJournals();
$result = [];
$chartData = [];
$journals = $collector->getExtractedJournals();
$result = [];
$chartData = [];
foreach ($journals as $journal) {
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
$symbol = $journal['currency_symbol'];
$code = $journal['currency_code'];
$name = $journal['currency_name'];
$amount = $journal['amount'];
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
$symbol = $journal['currency_symbol'];
$code = $journal['currency_code'];
$name = $journal['currency_name'];
$amount = $journal['amount'];
// if convert to primary, use the primary things, unless it's the foreign amount which is in the primary currency.
if (
$this->convertToPrimary
@@ -345,18 +345,18 @@ class BudgetController extends Controller
$result[$key]['amount'] = bcadd((string) $amount, $result[$key]['amount']);
}
$names = $this->getCategoryNames(array_keys($result));
$names = $this->getCategoryNames(array_keys($result));
foreach ($result as $combinedId => $info) {
$parts = explode('-', $combinedId);
$categoryId = (int) $parts[0];
$title = sprintf('%s (%s)', $names[$categoryId] ?? '(empty)', $info['currency_name']);
$parts = explode('-', $combinedId);
$categoryId = (int) $parts[0];
$title = sprintf('%s (%s)', $names[$categoryId] ?? '(empty)', $info['currency_name']);
$chartData[$title] = [
'amount' => $info['amount'],
'currency_symbol' => $info['currency_symbol'],
'currency_code' => $info['currency_code']
'currency_code' => $info['currency_code'],
];
}
$data = $this->generator->multiCurrencyPieChart($chartData);
$data = $this->generator->multiCurrencyPieChart($chartData);
$cache->store($data);
return response()->json($data);
@@ -365,7 +365,7 @@ class BudgetController extends Controller
/**
* Shows how much is spent per expense account.
*/
public function expenseExpense(Budget $budget, null|BudgetLimit $budgetLimit = null): JsonResponse
public function expenseExpense(Budget $budget, ?BudgetLimit $budgetLimit = null): JsonResponse
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
@@ -375,8 +375,8 @@ class BudgetController extends Controller
$cache->addProperty($budgetLimitId);
$cache->addProperty($this->convertToPrimary);
$cache->addProperty('chart.budget.expense-expense');
$start = session('first', today(config('app.timezone'))->startOfYear());
$end = today();
$start = session('first', today(config('app.timezone'))->startOfYear());
$end = today();
if ($budgetLimit instanceof BudgetLimit) {
$start = $budgetLimit->start_date;
$end = $budgetLimit->end_date;
@@ -390,17 +390,17 @@ class BudgetController extends Controller
}
$collector->setRange($start, $end);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setBudget($budget)->withAccountInformation();
$journals = $collector->getExtractedJournals();
$result = [];
$chartData = [];
$journals = $collector->getExtractedJournals();
$result = [];
$chartData = [];
/** @var array $journal */
foreach ($journals as $journal) {
$key = sprintf('%d-%d', $journal['destination_account_id'], $journal['currency_id']);
$amount = $journal['amount'];
$symbol = $journal['currency_symbol'];
$code = $journal['currency_code'];
$name = $journal['currency_name'];
$key = sprintf('%d-%d', $journal['destination_account_id'], $journal['currency_id']);
$amount = $journal['amount'];
$symbol = $journal['currency_symbol'];
$code = $journal['currency_code'];
$name = $journal['currency_name'];
// if convert to primary, use the primary things, unless it's the foreign amount which is in the primary currency.
if (
@@ -431,20 +431,20 @@ class BudgetController extends Controller
$result[$key]['amount'] = bcadd((string) $amount, $result[$key]['amount']);
}
$names = $this->getAccountNames(array_keys($result));
$names = $this->getAccountNames(array_keys($result));
foreach ($result as $combinedId => $info) {
$parts = explode('-', $combinedId);
$opposingId = (int) $parts[0];
$name = $names[$opposingId] ?? 'no name';
$title = sprintf('%s (%s)', $name, $info['currency_name']);
$parts = explode('-', $combinedId);
$opposingId = (int) $parts[0];
$name = $names[$opposingId] ?? 'no name';
$title = sprintf('%s (%s)', $name, $info['currency_name']);
$chartData[$title] = [
'amount' => $info['amount'],
'currency_symbol' => $info['currency_symbol'],
'currency_code' => $info['currency_code']
'currency_code' => $info['currency_code'],
];
}
$data = $this->generator->multiCurrencyPieChart($chartData);
$data = $this->generator->multiCurrencyPieChart($chartData);
$cache->store($data);
return response()->json($data);
@@ -455,10 +455,10 @@ class BudgetController extends Controller
*/
public function frontpage(): JsonResponse
{
$start = session('start', today(config('app.timezone'))->startOfMonth());
$end = session('end', today(config('app.timezone'))->endOfMonth());
$start = session('start', today(config('app.timezone'))->startOfMonth());
$end = session('end', today(config('app.timezone'))->endOfMonth());
// chart properties for cache:
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($this->convertToPrimary);
@@ -467,15 +467,15 @@ class BudgetController extends Controller
return response()->json($cache->get());
}
Log::debug('Regenerate frontpage chart from scratch.');
$chartGenerator = app(FrontpageChartGenerator::class);
$chartGenerator = app(FrontpageChartGenerator::class);
$chartGenerator->setUser(auth()->user());
$chartGenerator->setStart($start);
$chartGenerator->setEnd($end);
$chartGenerator->convertToPrimary = $this->convertToPrimary;
$chartGenerator->default = $this->primaryCurrency;
$chartGenerator->default = $this->primaryCurrency;
$chartData = $chartGenerator->generate();
$data = $this->generator->multiSet($chartData);
$chartData = $chartGenerator->generate();
$data = $this->generator->multiSet($chartData);
$cache->store($data);
return response()->json($data);
@@ -491,7 +491,7 @@ class BudgetController extends Controller
public function period(Budget $budget, TransactionCurrency $currency, Collection $accounts, Carbon $start, Carbon $end): JsonResponse
{
// chart properties for cache:
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($accounts);
@@ -509,22 +509,22 @@ class BudgetController extends Controller
'type' => 'bar',
'entries' => [],
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code
'currency_code' => $currency->code,
],
[
'label' => (string) trans('firefly.box_budgeted_in_currency', ['currency' => $currency->name]),
'type' => 'bar',
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
'entries' => []
]
'entries' => [],
],
];
$currentStart = clone $start;
$currentStart = clone $start;
while ($currentStart <= $end) {
$currentStart = Navigation::startOfPeriod($currentStart, $preferredRange);
$title = $currentStart->isoFormat($titleFormat);
$currentEnd = Navigation::endOfPeriod($currentStart, $preferredRange);
$currentStart = Navigation::startOfPeriod($currentStart, $preferredRange);
$title = $currentStart->isoFormat($titleFormat);
$currentEnd = Navigation::endOfPeriod($currentStart, $preferredRange);
// default limit is no limit:
$chartData[0]['entries'][$title] = 0;
@@ -533,21 +533,21 @@ class BudgetController extends Controller
$chartData[1]['entries'][$title] = 0;
// get budget limit in this period for this currency.
$limit = $this->blRepository->find($budget, $currency, $currentStart, $currentEnd);
$limit = $this->blRepository->find($budget, $currency, $currentStart, $currentEnd);
if ($limit instanceof BudgetLimit) {
$chartData[1]['entries'][$title] = Steam::bcround($limit->amount, $currency->decimal_places);
}
// get spent amount in this period for this currency.
$sum = $this->opsRepository->sumExpenses($currentStart, $currentEnd, $accounts, new Collection()->push($budget), $currency);
$amount = Steam::positive($sum[$currency->id]['sum'] ?? '0');
$sum = $this->opsRepository->sumExpenses($currentStart, $currentEnd, $accounts, new Collection()->push($budget), $currency);
$amount = Steam::positive($sum[$currency->id]['sum'] ?? '0');
$chartData[0]['entries'][$title] = Steam::bcround($amount, $currency->decimal_places);
$currentStart = clone $currentEnd;
$currentStart = clone $currentEnd;
$currentStart->addDay()->startOfDay();
}
$data = $this->generator->multiSet($chartData);
$data = $this->generator->multiSet($chartData);
$cache->store($data);
return response()->json($data);
@@ -559,7 +559,7 @@ class BudgetController extends Controller
public function periodNoBudget(TransactionCurrency $currency, Collection $accounts, Carbon $start, Carbon $end): JsonResponse
{
// chart properties for cache:
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($accounts);
@@ -575,15 +575,15 @@ class BudgetController extends Controller
$currentStart = clone $start;
$preferredRange = Navigation::preferredRangeFormat($start, $end);
while ($currentStart <= $end) {
$currentEnd = Navigation::endOfPeriod($currentStart, $preferredRange);
$title = $currentStart->isoFormat($titleFormat);
$sum = $this->nbRepository->sumExpenses($currentStart, $currentEnd, $accounts, $currency);
$amount = Steam::positive($sum[$currency->id]['sum'] ?? '0');
$currentEnd = Navigation::endOfPeriod($currentStart, $preferredRange);
$title = $currentStart->isoFormat($titleFormat);
$sum = $this->nbRepository->sumExpenses($currentStart, $currentEnd, $accounts, $currency);
$amount = Steam::positive($sum[$currency->id]['sum'] ?? '0');
$chartData[$title] = Steam::bcround($amount, $currency->decimal_places);
$currentStart = Navigation::addPeriod($currentStart, $preferredRange, 0);
$currentStart = Navigation::addPeriod($currentStart, $preferredRange, 0);
}
$data = $this->generator->singleSet((string) trans('firefly.spent'), $chartData);
$data = $this->generator->singleSet((string) trans('firefly.spent'), $chartData);
$cache->store($data);
return response()->json($data);