. */ /** @noinspection MoreThanThreeArgumentsInspection */ declare(strict_types=1); namespace FireflyIII\Http\Controllers\Chart; use Carbon\Carbon; use FireflyIII\Generator\Chart\Basic\GeneratorInterface; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Budget; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; use FireflyIII\Support\Http\Controllers\AugumentData; use FireflyIII\Support\Http\Controllers\TransactionCalculation; use Illuminate\Http\JsonResponse; use Illuminate\Support\Collection; /** * Separate controller because many helper functions are shared. * * Class BudgetReportController * */ class BudgetReportController extends Controller { use AugumentData, TransactionCalculation; /** @var GeneratorInterface Chart generation methods. */ private $generator; /** @var OperationsRepositoryInterface */ private $opsRepository; /** * BudgetReportController constructor. * * @codeCoverageIgnore */ public function __construct() { parent::__construct(); $this->middleware( function ($request, $next) { $this->generator = app(GeneratorInterface::class); $this->opsRepository = app(OperationsRepositoryInterface::class); return $next($request); } ); } /** * Chart that groups the expenses by budget. * * @param Collection $accounts * @param Collection $budgets * @param Carbon $start * @param Carbon $end * * @return JsonResponse */ public function budgetExpense(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end): JsonResponse { $result = []; $spent = $this->opsRepository->listExpenses($start, $end, $accounts, $budgets); // loop expenses. foreach ($spent as $currency) { foreach ($currency['budgets'] as $budget) { $title = sprintf('%s (%s)', $budget['name'], $currency['currency_name']); $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], ]; foreach ($budget['transaction_journals'] as $journal) { $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); } } } $data = $this->generator->multiCurrencyPieChart($result); return response()->json($data); } /** * Chart that groups the expenses by budget. * * @param Collection $accounts * @param Collection $budgets * @param Carbon $start * @param Carbon $end * * @return JsonResponse */ public function categoryExpense(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end): JsonResponse { $result = []; $spent = $this->opsRepository->listExpenses($start, $end, $accounts, $budgets); // loop expenses. foreach ($spent as $currency) { foreach ($currency['budgets'] as $budget) { foreach ($budget['transaction_journals'] as $journal) { $categoryName = $journal['category_name'] ?? trans('firefly.no_category'); $title = sprintf('%s (%s)', $categoryName, $currency['currency_name']); $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); } } } $data = $this->generator->multiCurrencyPieChart($result); return response()->json($data); } /** * Chart that groups expenses by the account. * * @param Collection $accounts * @param Collection $budgets * @param Carbon $start * @param Carbon $end * * @return JsonResponse */ public function destinationAccountExpense(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end): JsonResponse { $result = []; $spent = $this->opsRepository->listExpenses($start, $end, $accounts, $budgets); // loop expenses. foreach ($spent as $currency) { foreach ($currency['budgets'] as $budget) { foreach ($budget['transaction_journals'] as $journal) { $title = sprintf('%s (%s)', $journal['destination_account_name'], $currency['currency_name']); $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); } } } $data = $this->generator->multiCurrencyPieChart($result); return response()->json($data); } /** * Main overview of a budget in the budget report. * * @param Collection $accounts * @param Budget $budget * @param Carbon $start * @param Carbon $end * * @return JsonResponse */ public function mainChart(Collection $accounts, Budget $budget, Carbon $start, Carbon $end): JsonResponse { $chartData = []; $spent = $this->opsRepository->listExpenses($start, $end, $accounts, new Collection([$budget])); $format = app('navigation')->preferredCarbonLocalizedFormat($start, $end); // loop expenses. foreach ($spent as $currency) { // add things to chart Data for each currency: $spentKey = sprintf('%d-spent', $currency['currency_id']); $chartData[$spentKey] = $chartData[$spentKey] ?? [ 'label' => sprintf( '%s (%s)', (string)trans('firefly.spent_in_specific_budget', ['budget' => $budget->name]), $currency['currency_name'] ), 'type' => 'bar', 'currency_symbol' => $currency['currency_symbol'], 'currency_id' => $currency['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; foreach ($currency['budgets'] as $currentBudget) { foreach ($currentBudget['transaction_journals'] as $journal) { $key = $journal['date']->formatLocalized($format); $amount = app('steam')->positive($journal['amount']); $chartData[$spentKey]['entries'][$key] = $chartData[$spentKey]['entries'][$key] ?? '0'; $chartData[$spentKey]['entries'][$key] = bcadd($chartData[$spentKey]['entries'][$key], $amount); } } } $data = $this->generator->multiSet($chartData); return response()->json($data); } /** * Chart that groups expenses by the account. * * @param Collection $accounts * @param Collection $budgets * @param Carbon $start * @param Carbon $end * * @return JsonResponse */ public function sourceAccountExpense(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end): JsonResponse { $result = []; $spent = $this->opsRepository->listExpenses($start, $end, $accounts, $budgets); // loop expenses. foreach ($spent as $currency) { foreach ($currency['budgets'] as $budget) { foreach ($budget['transaction_journals'] as $journal) { $title = sprintf('%s (%s)', $journal['source_account_name'], $currency['currency_name']); $result[$title] = $result[$title] ?? [ 'amount' => '0', 'currency_symbol' => $currency['currency_symbol'], ]; $amount = app('steam')->positive($journal['amount']); $result[$title]['amount'] = bcadd($result[$title]['amount'], $amount); } } } $data = $this->generator->multiCurrencyPieChart($result); return response()->json($data); } /** * @param Carbon $start * @param Carbon $end * * @return array */ private function makeEntries(Carbon $start, Carbon $end): array { $return = []; $format = app('navigation')->preferredCarbonLocalizedFormat($start, $end); $preferredRange = app('navigation')->preferredRangeFormat($start, $end); $currentStart = clone $start; while ($currentStart <= $end) { $currentEnd = app('navigation')->endOfPeriod($currentStart, $preferredRange); $key = $currentStart->formatLocalized($format); $return[$key] = '0'; $currentStart = clone $currentEnd; $currentStart->addDay()->startOfDay(); } return $return; } }