2015-05-16 02:41:14 -05:00
|
|
|
<?php
|
2016-05-20 05:41:23 -05:00
|
|
|
/**
|
|
|
|
* BudgetController.php
|
2020-01-31 00:32:04 -06:00
|
|
|
* Copyright (c) 2019 james@firefly-iii.org
|
2016-05-20 05:41:23 -05:00
|
|
|
*
|
2019-10-01 23:37:26 -05:00
|
|
|
* This file is part of Firefly III (https://github.com/firefly-iii).
|
2016-10-04 23:52:15 -05:00
|
|
|
*
|
2019-10-01 23:37:26 -05:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
2017-10-21 01:40:00 -05:00
|
|
|
*
|
2019-10-01 23:37:26 -05:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
2017-10-21 01:40:00 -05:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2019-10-01 23:37:26 -05:00
|
|
|
* GNU Affero General Public License for more details.
|
2017-10-21 01:40:00 -05:00
|
|
|
*
|
2019-10-01 23:37:26 -05:00
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2016-05-20 05:41:23 -05:00
|
|
|
*/
|
2017-04-09 00:44:22 -05:00
|
|
|
declare(strict_types=1);
|
2015-05-16 02:41:14 -05:00
|
|
|
|
|
|
|
namespace FireflyIII\Http\Controllers\Chart;
|
|
|
|
|
|
|
|
use Carbon\Carbon;
|
2016-12-30 01:41:48 -06:00
|
|
|
use FireflyIII\Exceptions\FireflyException;
|
2016-12-15 02:49:35 -06:00
|
|
|
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
2019-05-30 05:31:19 -05:00
|
|
|
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
2015-05-16 02:41:14 -05:00
|
|
|
use FireflyIII\Http\Controllers\Controller;
|
|
|
|
use FireflyIII\Models\Budget;
|
2016-12-30 01:41:48 -06:00
|
|
|
use FireflyIII\Models\BudgetLimit;
|
2020-03-17 09:01:00 -05:00
|
|
|
use FireflyIII\Models\TransactionCurrency;
|
2016-11-05 12:08:44 -05:00
|
|
|
use FireflyIII\Models\TransactionType;
|
2019-08-30 01:09:39 -05:00
|
|
|
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
2015-05-16 02:41:14 -05:00
|
|
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
2019-08-30 01:15:09 -05:00
|
|
|
use FireflyIII\Repositories\Budget\NoBudgetRepositoryInterface;
|
2019-08-29 14:42:55 -05:00
|
|
|
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
2016-05-06 03:32:26 -05:00
|
|
|
use FireflyIII\Support\CacheProperties;
|
2020-10-18 05:41:49 -05:00
|
|
|
use FireflyIII\Support\Chart\Budget\FrontpageChartGenerator;
|
2018-08-10 23:39:29 -05:00
|
|
|
use FireflyIII\Support\Http\Controllers\AugumentData;
|
2018-07-14 16:22:08 -05:00
|
|
|
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
2018-07-08 05:28:42 -05:00
|
|
|
use Illuminate\Http\JsonResponse;
|
2015-05-16 02:41:14 -05:00
|
|
|
use Illuminate\Support\Collection;
|
|
|
|
|
|
|
|
/**
|
2017-11-15 05:25:49 -06:00
|
|
|
* Class BudgetController.
|
2015-05-16 02:41:14 -05:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
class BudgetController extends Controller
|
|
|
|
{
|
2018-08-10 23:39:29 -05:00
|
|
|
use DateCalculation, AugumentData;
|
2020-09-11 00:12:11 -05:00
|
|
|
|
2020-10-26 13:15:57 -05:00
|
|
|
protected GeneratorInterface $generator;
|
|
|
|
protected OperationsRepositoryInterface $opsRepository;
|
|
|
|
protected BudgetRepositoryInterface $repository;
|
|
|
|
private BudgetLimitRepositoryInterface $blRepository;
|
|
|
|
private NoBudgetRepositoryInterface $nbRepository;
|
2019-08-30 01:15:09 -05:00
|
|
|
|
2015-06-27 04:44:18 -05:00
|
|
|
/**
|
2016-09-16 02:09:54 -05:00
|
|
|
* BudgetController constructor.
|
2019-08-29 14:42:55 -05:00
|
|
|
*
|
2019-06-29 01:14:28 -05:00
|
|
|
* @codeCoverageIgnore
|
2015-06-27 04:44:18 -05:00
|
|
|
*/
|
|
|
|
public function __construct()
|
|
|
|
{
|
|
|
|
parent::__construct();
|
2017-01-02 13:42:29 -06:00
|
|
|
|
|
|
|
$this->middleware(
|
|
|
|
function ($request, $next) {
|
2019-08-29 14:42:55 -05:00
|
|
|
$this->generator = app(GeneratorInterface::class);
|
|
|
|
$this->repository = app(BudgetRepositoryInterface::class);
|
|
|
|
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
2019-08-30 01:09:39 -05:00
|
|
|
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
|
2019-08-30 01:15:09 -05:00
|
|
|
$this->nbRepository = app(NoBudgetRepositoryInterface::class);
|
2017-01-02 13:42:29 -06:00
|
|
|
|
|
|
|
return $next($request);
|
|
|
|
}
|
|
|
|
);
|
2015-06-27 04:44:18 -05:00
|
|
|
}
|
2021-03-28 04:46:23 -05:00
|
|
|
|
2016-04-25 02:57:39 -05:00
|
|
|
/**
|
2018-07-21 01:06:24 -05:00
|
|
|
* Shows overview of a single budget.
|
|
|
|
*
|
2017-01-02 13:42:29 -06:00
|
|
|
* @param Budget $budget
|
2016-04-25 02:57:39 -05:00
|
|
|
*
|
2018-07-08 05:28:42 -05:00
|
|
|
* @return JsonResponse
|
2016-04-25 02:57:39 -05:00
|
|
|
*/
|
2018-07-08 05:28:42 -05:00
|
|
|
public function budget(Budget $budget): JsonResponse
|
2016-04-25 02:57:39 -05:00
|
|
|
{
|
2018-07-23 14:49:15 -05:00
|
|
|
/** @var Carbon $start */
|
2020-09-11 00:12:11 -05:00
|
|
|
$start = $this->repository->firstUseDate($budget) ?? session('start', today(config('app.timezone')));
|
2018-07-14 16:32:03 -05:00
|
|
|
/** @var Carbon $end */
|
2020-09-11 00:12:11 -05:00
|
|
|
$end = session('end', today(config('app.timezone')));
|
2018-01-14 09:32:26 -06:00
|
|
|
$cache = new CacheProperties();
|
|
|
|
$cache->addProperty($start);
|
|
|
|
$cache->addProperty($end);
|
2016-12-15 02:49:35 -06:00
|
|
|
$cache->addProperty('chart.budget.budget');
|
2018-02-25 08:09:57 -06:00
|
|
|
$cache->addProperty($budget->id);
|
2016-05-06 03:32:26 -05:00
|
|
|
|
|
|
|
if ($cache->has()) {
|
2021-04-07 00:28:43 -05:00
|
|
|
//return response()->json($cache->get());
|
2016-05-06 03:32:26 -05:00
|
|
|
}
|
2020-03-17 09:01:00 -05:00
|
|
|
$step = $this->calculateStep($start, $end); // depending on diff, do something with range of chart.
|
|
|
|
$collection = new Collection([$budget]);
|
|
|
|
$chartData = [];
|
|
|
|
$loopStart = clone $start;
|
|
|
|
$loopStart = app('navigation')->startOfPeriod($loopStart, $step);
|
2019-11-22 23:14:50 -06:00
|
|
|
$currencies = [];
|
|
|
|
$defaultEntries = [];
|
|
|
|
while ($end >= $loopStart) {
|
2021-04-26 23:23:16 -05:00
|
|
|
/** @var Carbon $loopEnd */
|
2019-11-22 23:14:50 -06:00
|
|
|
$loopEnd = app('navigation')->endOfPeriod($loopStart, $step);
|
2020-10-01 05:48:27 -05:00
|
|
|
$spent = $this->opsRepository->sumExpenses($loopStart, $loopEnd, null, $collection);
|
|
|
|
$label = trim(app('navigation')->periodShow($loopStart, $step));
|
2019-11-22 23:14:50 -06:00
|
|
|
|
|
|
|
foreach ($spent as $row) {
|
|
|
|
$currencyId = $row['currency_id'];
|
|
|
|
$currencies[$currencyId] = $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->addSecond();
|
2016-05-06 03:32:26 -05:00
|
|
|
}
|
2019-11-22 23:14:50 -06:00
|
|
|
// loop all currencies:
|
|
|
|
foreach ($currencies as $currencyId => $currency) {
|
|
|
|
$chartData[$currencyId] = [
|
2020-03-17 09:01:00 -05:00
|
|
|
'label' => count($currencies) > 1 ? sprintf('%s (%s)', $budget->name, $currency['currency_name']) : $budget->name,
|
|
|
|
'type' => 'bar',
|
2019-11-22 23:14:50 -06:00
|
|
|
'currency_symbol' => $currency['currency_symbol'],
|
2020-07-27 23:25:14 -05:00
|
|
|
'currency_code' => $currency['currency_code'],
|
2020-03-17 09:01:00 -05:00
|
|
|
'entries' => $defaultEntries,
|
2019-11-22 23:14:50 -06:00
|
|
|
];
|
|
|
|
foreach ($currency['spent'] as $label => $spent) {
|
2020-09-11 00:12:11 -05:00
|
|
|
$chartData[$currencyId]['entries'][$label] = bcmul($spent, '-1');
|
2019-11-22 23:14:50 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
$data = $this->generator->multiSet(array_values($chartData));
|
2016-05-06 03:32:26 -05:00
|
|
|
$cache->store($data);
|
|
|
|
|
2018-03-10 13:30:09 -06:00
|
|
|
return response()->json($data);
|
2016-04-25 02:57:39 -05:00
|
|
|
}
|
2021-03-28 04:46:23 -05:00
|
|
|
|
2015-05-16 06:06:38 -05:00
|
|
|
/**
|
|
|
|
* Shows the amount left in a specific budget limit.
|
|
|
|
*
|
2019-08-29 14:42:55 -05:00
|
|
|
* @param Budget $budget
|
2017-01-02 13:42:29 -06:00
|
|
|
* @param BudgetLimit $budgetLimit
|
2015-05-16 06:06:38 -05:00
|
|
|
*
|
2018-07-08 05:28:42 -05:00
|
|
|
* @return JsonResponse
|
2017-11-15 05:25:49 -06:00
|
|
|
*
|
2020-03-23 05:01:00 -05:00
|
|
|
* @throws FireflyException
|
2015-05-16 06:06:38 -05:00
|
|
|
*/
|
2018-07-08 05:28:42 -05:00
|
|
|
public function budgetLimit(Budget $budget, BudgetLimit $budgetLimit): JsonResponse
|
2015-05-16 06:06:38 -05:00
|
|
|
{
|
2017-07-15 09:41:07 -05:00
|
|
|
if ($budgetLimit->budget->id !== $budget->id) {
|
2016-12-30 01:41:48 -06:00
|
|
|
throw new FireflyException('This budget limit is not part of this budget.');
|
|
|
|
}
|
|
|
|
|
|
|
|
$start = clone $budgetLimit->start_date;
|
|
|
|
$end = clone $budgetLimit->end_date;
|
2016-05-06 03:32:26 -05:00
|
|
|
$cache = new CacheProperties();
|
|
|
|
$cache->addProperty($start);
|
|
|
|
$cache->addProperty($end);
|
2016-12-15 02:49:35 -06:00
|
|
|
$cache->addProperty('chart.budget.budget.limit');
|
2016-12-30 01:41:48 -06:00
|
|
|
$cache->addProperty($budgetLimit->id);
|
2018-02-25 08:09:57 -06:00
|
|
|
$cache->addProperty($budget->id);
|
2016-05-06 03:32:26 -05:00
|
|
|
|
|
|
|
if ($cache->has()) {
|
2021-04-07 00:28:43 -05:00
|
|
|
return response()->json($cache->get());
|
2016-05-06 03:32:26 -05:00
|
|
|
}
|
2020-09-11 00:12:11 -05:00
|
|
|
$locale = app('steam')->getLocale();
|
2016-12-15 02:49:35 -06:00
|
|
|
$entries = [];
|
2016-12-30 01:41:48 -06:00
|
|
|
$amount = $budgetLimit->amount;
|
2016-05-06 03:32:26 -05:00
|
|
|
$budgetCollection = new Collection([$budget]);
|
2020-11-08 07:06:49 -06:00
|
|
|
$currency = $budgetLimit->transactionCurrency;
|
2016-05-06 03:32:26 -05:00
|
|
|
while ($start <= $end) {
|
2020-11-08 07:06:49 -06:00
|
|
|
$current = clone $start;
|
|
|
|
$expenses = $this->opsRepository->sumExpenses($current, $current, null, $budgetCollection, $currency);
|
|
|
|
$spent = $expenses[(int)$currency->id]['sum'] ?? '0';
|
2016-12-15 02:49:35 -06:00
|
|
|
$amount = bcadd($amount, $spent);
|
2020-10-26 13:15:57 -05:00
|
|
|
$format = $start->formatLocalized((string)trans('config.month_and_day', [], $locale));
|
2016-12-15 02:49:35 -06:00
|
|
|
$entries[$format] = $amount;
|
2016-05-06 03:32:26 -05:00
|
|
|
|
|
|
|
$start->addDay();
|
|
|
|
}
|
2020-10-26 13:15:57 -05:00
|
|
|
$data = $this->generator->singleSet((string)trans('firefly.left'), $entries);
|
2019-09-14 23:56:20 -05:00
|
|
|
// add currency symbol from budget limit:
|
|
|
|
$data['datasets'][0]['currency_symbol'] = $budgetLimit->transactionCurrency->symbol;
|
2020-07-27 23:25:14 -05:00
|
|
|
$data['datasets'][0]['currency_code'] = $budgetLimit->transactionCurrency->code;
|
2016-05-06 03:32:26 -05:00
|
|
|
$cache->store($data);
|
2015-05-16 06:06:38 -05:00
|
|
|
|
2018-03-10 13:30:09 -06:00
|
|
|
return response()->json($data);
|
2015-05-16 06:06:38 -05:00
|
|
|
}
|
2021-03-28 04:46:23 -05:00
|
|
|
|
2017-04-22 00:04:39 -05:00
|
|
|
/**
|
2018-07-21 01:06:24 -05:00
|
|
|
* Shows how much is spent per asset account.
|
|
|
|
*
|
2019-08-29 14:42:55 -05:00
|
|
|
* @param Budget $budget
|
2017-04-22 00:04:39 -05:00
|
|
|
* @param BudgetLimit|null $budgetLimit
|
|
|
|
*
|
2018-07-08 05:28:42 -05:00
|
|
|
* @return JsonResponse
|
2017-04-22 00:04:39 -05:00
|
|
|
*/
|
2019-09-14 23:56:20 -05:00
|
|
|
public function expenseAsset(Budget $budget, ?BudgetLimit $budgetLimit = null): JsonResponse
|
2017-04-22 00:04:39 -05:00
|
|
|
{
|
2020-01-01 07:13:35 -06:00
|
|
|
/** @var GroupCollectorInterface $collector */
|
2020-03-17 09:01:00 -05:00
|
|
|
$collector = app(GroupCollectorInterface::class);
|
2018-07-09 12:24:08 -05:00
|
|
|
$budgetLimitId = null === $budgetLimit ? 0 : $budgetLimit->id;
|
|
|
|
$cache = new CacheProperties;
|
2017-04-22 00:04:39 -05:00
|
|
|
$cache->addProperty($budget->id);
|
2018-07-09 12:24:08 -05:00
|
|
|
$cache->addProperty($budgetLimitId);
|
2017-04-22 00:04:39 -05:00
|
|
|
$cache->addProperty('chart.budget.expense-asset');
|
2020-09-11 00:12:11 -05:00
|
|
|
$start = session('first', Carbon::now()->startOfYear());
|
|
|
|
$end = today();
|
|
|
|
|
2020-01-01 07:13:35 -06:00
|
|
|
if (null !== $budgetLimit) {
|
|
|
|
$start = $budgetLimit->start_date;
|
|
|
|
$end = $budgetLimit->end_date;
|
|
|
|
$collector->setRange($budgetLimit->start_date, $budgetLimit->end_date)->setCurrency($budgetLimit->transactionCurrency);
|
|
|
|
}
|
|
|
|
$cache->addProperty($start);
|
|
|
|
$cache->addProperty($end);
|
|
|
|
|
2017-04-22 00:04:39 -05:00
|
|
|
if ($cache->has()) {
|
2021-04-07 00:28:43 -05:00
|
|
|
return response()->json($cache->get());
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
2020-07-01 12:47:32 -05:00
|
|
|
$collector->setRange($start, $end);
|
2019-05-30 05:31:19 -05:00
|
|
|
$collector->setBudget($budget);
|
|
|
|
$journals = $collector->getExtractedJournals();
|
|
|
|
$result = [];
|
|
|
|
$chartData = [];
|
2019-09-14 23:56:20 -05:00
|
|
|
|
|
|
|
// group by asset account ID:
|
2019-05-30 05:31:19 -05:00
|
|
|
foreach ($journals as $journal) {
|
2020-10-26 13:15:57 -05:00
|
|
|
$key = sprintf('%d-%d', (int)$journal['source_account_id'], $journal['currency_id']);
|
2020-01-01 07:26:49 -06:00
|
|
|
$result[$key] = $result[$key] ?? [
|
2019-09-14 23:56:20 -05:00
|
|
|
'amount' => '0',
|
|
|
|
'currency_symbol' => $journal['currency_symbol'],
|
2020-07-27 23:25:14 -05:00
|
|
|
'currency_code' => $journal['currency_code'],
|
2020-01-01 07:26:49 -06:00
|
|
|
'currency_name' => $journal['currency_name'],
|
2019-09-14 23:56:20 -05:00
|
|
|
];
|
2020-01-01 07:26:49 -06:00
|
|
|
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
$names = $this->getAccountNames(array_keys($result));
|
2020-01-01 07:26:49 -06:00
|
|
|
foreach ($result as $combinedId => $info) {
|
|
|
|
$parts = explode('-', $combinedId);
|
2020-10-26 13:15:57 -05:00
|
|
|
$assetId = (int)$parts[0];
|
2020-01-05 12:29:28 -06:00
|
|
|
$title = sprintf('%s (%s)', $names[$assetId] ?? '(empty)', $info['currency_name']);
|
2020-01-01 07:26:49 -06:00
|
|
|
$chartData[$title]
|
|
|
|
= [
|
2019-09-14 23:56:20 -05:00
|
|
|
'amount' => $info['amount'],
|
|
|
|
'currency_symbol' => $info['currency_symbol'],
|
2020-09-11 00:12:11 -05:00
|
|
|
'currency_code' => $info['currency_code'],
|
2019-09-14 23:56:20 -05:00
|
|
|
];
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
|
|
|
|
2019-09-14 23:56:20 -05:00
|
|
|
$data = $this->generator->multiCurrencyPieChart($chartData);
|
2017-04-22 00:04:39 -05:00
|
|
|
$cache->store($data);
|
|
|
|
|
2018-03-10 13:30:09 -06:00
|
|
|
return response()->json($data);
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
2021-03-28 04:46:23 -05:00
|
|
|
|
2017-04-22 00:04:39 -05:00
|
|
|
/**
|
2018-07-21 01:06:24 -05:00
|
|
|
* Shows how much is spent per category.
|
|
|
|
*
|
2019-08-29 14:42:55 -05:00
|
|
|
* @param Budget $budget
|
2017-04-22 00:04:39 -05:00
|
|
|
* @param BudgetLimit|null $budgetLimit
|
|
|
|
*
|
2018-07-08 05:28:42 -05:00
|
|
|
* @return JsonResponse
|
2017-04-22 00:04:39 -05:00
|
|
|
*/
|
2019-09-14 23:56:20 -05:00
|
|
|
public function expenseCategory(Budget $budget, ?BudgetLimit $budgetLimit = null): JsonResponse
|
2017-04-22 00:04:39 -05:00
|
|
|
{
|
2020-01-01 07:13:35 -06:00
|
|
|
/** @var GroupCollectorInterface $collector */
|
2020-03-17 09:01:00 -05:00
|
|
|
$collector = app(GroupCollectorInterface::class);
|
2018-07-09 12:24:08 -05:00
|
|
|
$budgetLimitId = null === $budgetLimit ? 0 : $budgetLimit->id;
|
2018-07-13 08:50:42 -05:00
|
|
|
$cache = new CacheProperties;
|
2017-04-22 00:04:39 -05:00
|
|
|
$cache->addProperty($budget->id);
|
2018-07-09 12:24:08 -05:00
|
|
|
$cache->addProperty($budgetLimitId);
|
2017-04-22 00:04:39 -05:00
|
|
|
$cache->addProperty('chart.budget.expense-category');
|
2020-09-11 00:12:11 -05:00
|
|
|
$start = session('first', Carbon::now()->startOfYear());
|
|
|
|
$end = today();
|
2020-01-01 07:13:35 -06:00
|
|
|
if (null !== $budgetLimit) {
|
|
|
|
$start = $budgetLimit->start_date;
|
|
|
|
$end = $budgetLimit->end_date;
|
2020-07-01 12:47:32 -05:00
|
|
|
$collector->setCurrency($budgetLimit->transactionCurrency);
|
2020-01-01 07:13:35 -06:00
|
|
|
}
|
|
|
|
$cache->addProperty($start);
|
|
|
|
$cache->addProperty($end);
|
|
|
|
|
2017-04-22 00:04:39 -05:00
|
|
|
if ($cache->has()) {
|
2021-04-07 00:28:43 -05:00
|
|
|
return response()->json($cache->get());
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
2020-07-01 12:47:32 -05:00
|
|
|
$collector->setRange($start, $end);
|
2019-05-30 05:31:19 -05:00
|
|
|
$collector->setBudget($budget)->withCategoryInformation();
|
|
|
|
$journals = $collector->getExtractedJournals();
|
|
|
|
$result = [];
|
|
|
|
$chartData = [];
|
|
|
|
foreach ($journals as $journal) {
|
2020-01-01 07:26:49 -06:00
|
|
|
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
|
|
|
|
$result[$key] = $result[$key] ?? [
|
2019-09-14 23:56:20 -05:00
|
|
|
'amount' => '0',
|
|
|
|
'currency_symbol' => $journal['currency_symbol'],
|
2020-07-27 23:25:14 -05:00
|
|
|
'currency_code' => $journal['currency_code'],
|
2020-01-01 07:26:49 -06:00
|
|
|
'currency_name' => $journal['currency_name'],
|
2019-09-14 23:56:20 -05:00
|
|
|
];
|
2020-01-01 07:26:49 -06:00
|
|
|
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
$names = $this->getCategoryNames(array_keys($result));
|
2020-01-01 07:26:49 -06:00
|
|
|
foreach ($result as $combinedId => $info) {
|
|
|
|
$parts = explode('-', $combinedId);
|
2020-10-26 13:15:57 -05:00
|
|
|
$categoryId = (int)$parts[0];
|
2020-01-05 12:29:28 -06:00
|
|
|
$title = sprintf('%s (%s)', $names[$categoryId] ?? '(empty)', $info['currency_name']);
|
2020-01-01 07:26:49 -06:00
|
|
|
$chartData[$title] = [
|
2019-09-14 23:56:20 -05:00
|
|
|
'amount' => $info['amount'],
|
|
|
|
'currency_symbol' => $info['currency_symbol'],
|
2020-09-11 00:12:11 -05:00
|
|
|
'currency_code' => $info['currency_code'],
|
2019-09-14 23:56:20 -05:00
|
|
|
];
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
2019-09-14 23:56:20 -05:00
|
|
|
$data = $this->generator->multiCurrencyPieChart($chartData);
|
2017-04-22 00:04:39 -05:00
|
|
|
$cache->store($data);
|
2017-10-15 07:05:31 -05:00
|
|
|
|
2018-03-10 13:30:09 -06:00
|
|
|
return response()->json($data);
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
2021-03-28 04:46:23 -05:00
|
|
|
|
2017-04-22 00:04:39 -05:00
|
|
|
/**
|
2018-07-21 01:06:24 -05:00
|
|
|
* Shows how much is spent per expense account.
|
|
|
|
*
|
2018-08-27 11:59:30 -05:00
|
|
|
*
|
2019-08-29 14:42:55 -05:00
|
|
|
* @param Budget $budget
|
2017-04-22 00:04:39 -05:00
|
|
|
* @param BudgetLimit|null $budgetLimit
|
|
|
|
*
|
2018-07-08 05:28:42 -05:00
|
|
|
* @return JsonResponse
|
2017-04-22 00:04:39 -05:00
|
|
|
*/
|
2019-09-14 23:56:20 -05:00
|
|
|
public function expenseExpense(Budget $budget, ?BudgetLimit $budgetLimit = null): JsonResponse
|
2017-04-22 00:04:39 -05:00
|
|
|
{
|
2020-01-01 07:13:35 -06:00
|
|
|
/** @var GroupCollectorInterface $collector */
|
2020-03-17 09:01:00 -05:00
|
|
|
$collector = app(GroupCollectorInterface::class);
|
2018-07-09 12:24:08 -05:00
|
|
|
$budgetLimitId = null === $budgetLimit ? 0 : $budgetLimit->id;
|
2018-07-13 08:50:42 -05:00
|
|
|
$cache = new CacheProperties;
|
2017-04-22 00:04:39 -05:00
|
|
|
$cache->addProperty($budget->id);
|
2018-07-09 12:24:08 -05:00
|
|
|
$cache->addProperty($budgetLimitId);
|
2017-04-22 00:04:39 -05:00
|
|
|
$cache->addProperty('chart.budget.expense-expense');
|
2020-09-11 00:12:11 -05:00
|
|
|
$start = session('first', Carbon::now()->startOfYear());
|
|
|
|
$end = today();
|
2018-07-09 12:24:08 -05:00
|
|
|
if (null !== $budgetLimit) {
|
2020-01-01 07:13:35 -06:00
|
|
|
$start = $budgetLimit->start_date;
|
|
|
|
$end = $budgetLimit->end_date;
|
|
|
|
$collector->setRange($budgetLimit->start_date, $budgetLimit->end_date)->setCurrency($budgetLimit->transactionCurrency);
|
2019-09-14 23:56:20 -05:00
|
|
|
}
|
2020-01-01 07:13:35 -06:00
|
|
|
$cache->addProperty($start);
|
|
|
|
$cache->addProperty($end);
|
2019-09-14 23:56:20 -05:00
|
|
|
|
2020-01-01 07:13:35 -06:00
|
|
|
if ($cache->has()) {
|
2021-04-07 00:28:43 -05:00
|
|
|
return response()->json($cache->get());
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
2020-07-01 12:47:32 -05:00
|
|
|
$collector->setRange($start, $end);
|
2020-01-01 07:13:35 -06:00
|
|
|
$collector->setTypes([TransactionType::WITHDRAWAL])->setBudget($budget)->withAccountInformation();
|
2019-05-30 05:31:19 -05:00
|
|
|
$journals = $collector->getExtractedJournals();
|
|
|
|
$result = [];
|
|
|
|
$chartData = [];
|
|
|
|
/** @var array $journal */
|
|
|
|
foreach ($journals as $journal) {
|
2020-01-01 07:26:49 -06:00
|
|
|
$key = sprintf('%d-%d', $journal['destination_account_id'], $journal['currency_id']);
|
|
|
|
$result[$key] = $result[$key] ?? [
|
2019-09-14 23:56:20 -05:00
|
|
|
'amount' => '0',
|
|
|
|
'currency_symbol' => $journal['currency_symbol'],
|
2020-07-27 23:25:14 -05:00
|
|
|
'currency_code' => $journal['currency_code'],
|
2020-01-01 07:26:49 -06:00
|
|
|
'currency_name' => $journal['currency_name'],
|
2019-09-14 23:56:20 -05:00
|
|
|
];
|
2020-01-01 07:26:49 -06:00
|
|
|
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
$names = $this->getAccountNames(array_keys($result));
|
2020-01-01 07:26:49 -06:00
|
|
|
foreach ($result as $combinedId => $info) {
|
|
|
|
$parts = explode('-', $combinedId);
|
2020-10-26 13:15:57 -05:00
|
|
|
$opposingId = (int)$parts[0];
|
2020-01-01 07:26:49 -06:00
|
|
|
$name = $names[$opposingId] ?? 'no name';
|
|
|
|
$title = sprintf('%s (%s)', $name, $info['currency_name']);
|
|
|
|
$chartData[$title] = [
|
2019-09-14 23:56:20 -05:00
|
|
|
'amount' => $info['amount'],
|
|
|
|
'currency_symbol' => $info['currency_symbol'],
|
2020-09-11 00:12:11 -05:00
|
|
|
'currency_code' => $info['currency_code'],
|
2019-09-14 23:56:20 -05:00
|
|
|
];
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
|
|
|
|
2019-09-14 23:56:20 -05:00
|
|
|
$data = $this->generator->multiCurrencyPieChart($chartData);
|
2017-04-22 00:04:39 -05:00
|
|
|
$cache->store($data);
|
|
|
|
|
2018-03-10 13:30:09 -06:00
|
|
|
return response()->json($data);
|
2017-04-22 00:04:39 -05:00
|
|
|
}
|
2021-03-28 04:46:23 -05:00
|
|
|
|
2015-05-16 02:41:14 -05:00
|
|
|
/**
|
|
|
|
* Shows a budget list with spent/left/overspent.
|
2017-11-15 05:25:49 -06:00
|
|
|
*
|
2018-08-06 12:14:30 -05:00
|
|
|
* @return JsonResponse
|
2018-07-15 12:17:26 -05:00
|
|
|
*
|
2015-05-16 02:41:14 -05:00
|
|
|
*/
|
2018-08-06 12:14:30 -05:00
|
|
|
public function frontpage(): JsonResponse
|
2015-05-16 02:41:14 -05:00
|
|
|
{
|
2016-05-06 03:32:26 -05:00
|
|
|
$start = session('start', Carbon::now()->startOfMonth());
|
|
|
|
$end = session('end', Carbon::now()->endOfMonth());
|
2020-10-18 05:41:49 -05:00
|
|
|
|
2016-05-06 03:32:26 -05:00
|
|
|
// chart properties for cache:
|
|
|
|
$cache = new CacheProperties();
|
|
|
|
$cache->addProperty($start);
|
|
|
|
$cache->addProperty($end);
|
2016-12-15 02:49:35 -06:00
|
|
|
$cache->addProperty('chart.budget.frontpage');
|
2016-05-06 03:32:26 -05:00
|
|
|
if ($cache->has()) {
|
2021-04-07 00:28:43 -05:00
|
|
|
return response()->json($cache->get());
|
2016-05-06 03:32:26 -05:00
|
|
|
}
|
2020-10-18 05:41:49 -05:00
|
|
|
|
2020-10-26 13:15:57 -05:00
|
|
|
$chartGenerator = app(FrontpageChartGenerator::class);
|
|
|
|
$chartGenerator->setUser(auth()->user());
|
|
|
|
$chartGenerator->setStart($start);
|
|
|
|
$chartGenerator->setEnd($end);
|
2020-10-18 05:41:49 -05:00
|
|
|
|
2020-10-26 13:15:57 -05:00
|
|
|
$chartData = $chartGenerator->generate();
|
2020-10-18 05:41:49 -05:00
|
|
|
$data = $this->generator->multiSet($chartData);
|
2016-05-06 03:32:26 -05:00
|
|
|
$cache->store($data);
|
|
|
|
|
2018-03-10 13:30:09 -06:00
|
|
|
return response()->json($data);
|
2015-05-16 02:41:14 -05:00
|
|
|
}
|
2021-03-28 04:46:23 -05:00
|
|
|
|
2016-04-24 13:23:17 -05:00
|
|
|
/**
|
2018-07-21 01:06:24 -05:00
|
|
|
* Shows a budget overview chart (spent and budgeted).
|
2017-01-02 13:42:29 -06:00
|
|
|
*
|
2019-09-01 09:52:49 -05:00
|
|
|
* @param Budget $budget
|
|
|
|
* @param TransactionCurrency $currency
|
|
|
|
* @param Collection $accounts
|
|
|
|
* @param Carbon $start
|
|
|
|
* @param Carbon $end
|
2016-04-26 02:21:57 -05:00
|
|
|
*
|
2018-07-08 05:28:42 -05:00
|
|
|
* @return JsonResponse
|
2016-04-24 13:23:17 -05:00
|
|
|
*/
|
2019-09-01 09:52:49 -05:00
|
|
|
public function period(Budget $budget, TransactionCurrency $currency, Collection $accounts, Carbon $start, Carbon $end): JsonResponse
|
2016-04-24 13:23:17 -05:00
|
|
|
{
|
2016-05-06 15:53:08 -05:00
|
|
|
// chart properties for cache:
|
|
|
|
$cache = new CacheProperties();
|
|
|
|
$cache->addProperty($start);
|
|
|
|
$cache->addProperty($end);
|
|
|
|
$cache->addProperty($accounts);
|
|
|
|
$cache->addProperty($budget->id);
|
2019-09-01 09:52:49 -05:00
|
|
|
$cache->addProperty($currency->id);
|
2016-12-15 03:41:10 -06:00
|
|
|
$cache->addProperty('chart.budget.period');
|
2016-05-06 15:53:08 -05:00
|
|
|
if ($cache->has()) {
|
2021-04-07 00:28:43 -05:00
|
|
|
return response()->json($cache->get());
|
2016-05-06 15:53:08 -05:00
|
|
|
}
|
2019-09-01 11:41:57 -05:00
|
|
|
$titleFormat = app('navigation')->preferredCarbonLocalizedFormat($start, $end);
|
|
|
|
$preferredRange = app('navigation')->preferredRangeFormat($start, $end);
|
|
|
|
$chartData = [
|
2019-09-01 09:52:49 -05:00
|
|
|
[
|
2020-10-26 13:15:57 -05:00
|
|
|
'label' => (string)trans('firefly.box_spent_in_currency', ['currency' => $currency->name]),
|
2019-09-01 09:52:49 -05:00
|
|
|
'type' => 'bar',
|
|
|
|
'entries' => [],
|
|
|
|
'currency_symbol' => $currency->symbol,
|
2020-07-27 23:25:14 -05:00
|
|
|
'currency_code' => $currency->code,
|
2019-09-01 09:52:49 -05:00
|
|
|
],
|
|
|
|
[
|
2020-10-26 13:15:57 -05:00
|
|
|
'label' => (string)trans('firefly.box_budgeted_in_currency', ['currency' => $currency->name]),
|
2019-09-01 09:52:49 -05:00
|
|
|
'type' => 'bar',
|
|
|
|
'currency_symbol' => $currency->symbol,
|
2020-07-27 23:25:14 -05:00
|
|
|
'currency_code' => $currency->code,
|
2019-09-01 09:52:49 -05:00
|
|
|
'entries' => [],
|
|
|
|
],
|
2016-12-15 03:41:10 -06:00
|
|
|
];
|
2016-11-19 06:37:44 -06:00
|
|
|
|
2019-09-01 09:52:49 -05:00
|
|
|
$currentStart = clone $start;
|
|
|
|
while ($currentStart <= $end) {
|
2020-03-17 09:01:00 -05:00
|
|
|
$currentStart = app('navigation')->startOfPeriod($currentStart, $preferredRange);
|
|
|
|
$title = $currentStart->formatLocalized($titleFormat);
|
|
|
|
$currentEnd = app('navigation')->endOfPeriod($currentStart, $preferredRange);
|
2019-09-01 09:52:49 -05:00
|
|
|
|
|
|
|
// default limit is no limit:
|
|
|
|
$chartData[0]['entries'][$title] = 0;
|
|
|
|
|
2019-09-01 12:08:10 -05:00
|
|
|
// default spent is not spent at all.
|
|
|
|
$chartData[1]['entries'][$title] = 0;
|
2019-09-01 09:52:49 -05:00
|
|
|
|
|
|
|
// get budget limit in this period for this currency.
|
|
|
|
$limit = $this->blRepository->find($budget, $currency, $currentStart, $currentEnd);
|
|
|
|
if (null !== $limit) {
|
2021-03-28 04:46:23 -05:00
|
|
|
$chartData[1]['entries'][$title] = round((float)$limit->amount, $currency->decimal_places);
|
2019-09-01 09:52:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// get spent amount in this period for this currency.
|
|
|
|
$sum = $this->opsRepository->sumExpenses($currentStart, $currentEnd, $accounts, new Collection([$budget]), $currency);
|
|
|
|
$amount = app('steam')->positive($sum[$currency->id]['sum'] ?? '0');
|
2021-03-28 04:46:23 -05:00
|
|
|
$chartData[0]['entries'][$title] = round((float)$amount, $currency->decimal_places);
|
2019-09-01 09:52:49 -05:00
|
|
|
|
2019-09-01 12:08:10 -05:00
|
|
|
$currentStart = clone $currentEnd;
|
|
|
|
$currentStart->addDay()->startOfDay();
|
2016-12-15 03:41:10 -06:00
|
|
|
}
|
2019-09-01 09:52:49 -05:00
|
|
|
|
2016-12-15 03:44:06 -06:00
|
|
|
$data = $this->generator->multiSet($chartData);
|
2016-05-06 15:53:08 -05:00
|
|
|
$cache->store($data);
|
|
|
|
|
2018-03-10 13:30:09 -06:00
|
|
|
return response()->json($data);
|
2015-05-16 02:41:14 -05:00
|
|
|
}
|
2021-03-28 04:46:23 -05:00
|
|
|
|
2016-12-04 11:02:19 -06:00
|
|
|
/**
|
2018-07-21 01:06:24 -05:00
|
|
|
* Shows a chart for transactions without a budget.
|
|
|
|
*
|
2019-09-01 09:52:49 -05:00
|
|
|
* @param TransactionCurrency $currency
|
|
|
|
* @param Collection $accounts
|
|
|
|
* @param Carbon $start
|
|
|
|
* @param Carbon $end
|
2016-12-04 11:02:19 -06:00
|
|
|
*
|
2018-07-08 05:28:42 -05:00
|
|
|
* @return JsonResponse
|
2016-12-04 11:02:19 -06:00
|
|
|
*/
|
2019-09-01 09:52:49 -05:00
|
|
|
public function periodNoBudget(TransactionCurrency $currency, Collection $accounts, Carbon $start, Carbon $end): JsonResponse
|
2016-12-04 11:02:19 -06:00
|
|
|
{
|
|
|
|
// chart properties for cache:
|
|
|
|
$cache = new CacheProperties();
|
|
|
|
$cache->addProperty($start);
|
|
|
|
$cache->addProperty($end);
|
|
|
|
$cache->addProperty($accounts);
|
2019-09-01 09:52:49 -05:00
|
|
|
$cache->addProperty($currency->id);
|
2016-12-15 03:41:10 -06:00
|
|
|
$cache->addProperty('chart.budget.no-budget');
|
2016-12-04 11:02:19 -06:00
|
|
|
if ($cache->has()) {
|
2021-04-07 00:28:43 -05:00
|
|
|
return response()->json($cache->get());
|
2016-12-04 11:02:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// the expenses:
|
2019-09-01 11:41:57 -05:00
|
|
|
$titleFormat = app('navigation')->preferredCarbonLocalizedFormat($start, $end);
|
|
|
|
$chartData = [];
|
|
|
|
$currentStart = clone $start;
|
|
|
|
$preferredRange = app('navigation')->preferredRangeFormat($start, $end);
|
2019-09-01 09:52:49 -05:00
|
|
|
while ($currentStart <= $end) {
|
2019-09-01 11:41:57 -05:00
|
|
|
$currentEnd = app('navigation')->endOfPeriod($currentStart, $preferredRange);
|
2019-09-01 09:52:49 -05:00
|
|
|
$title = $currentStart->formatLocalized($titleFormat);
|
|
|
|
$sum = $this->nbRepository->sumExpenses($currentStart, $currentEnd, $accounts, $currency);
|
|
|
|
$amount = app('steam')->positive($sum[$currency->id]['sum'] ?? '0');
|
2021-03-28 04:46:23 -05:00
|
|
|
$chartData[$title] = round((float)$amount, $currency->decimal_places);
|
2019-09-01 11:41:57 -05:00
|
|
|
$currentStart = app('navigation')->addPeriod($currentStart, $preferredRange, 0);
|
2016-12-04 11:02:19 -06:00
|
|
|
}
|
2019-09-01 09:52:49 -05:00
|
|
|
|
2020-10-26 13:15:57 -05:00
|
|
|
$data = $this->generator->singleSet((string)trans('firefly.spent'), $chartData);
|
2016-12-04 11:02:19 -06:00
|
|
|
$cache->store($data);
|
|
|
|
|
2018-03-10 13:30:09 -06:00
|
|
|
return response()->json($data);
|
2016-12-04 11:02:19 -06:00
|
|
|
}
|
2015-05-20 12:56:14 -05:00
|
|
|
}
|