Files
firefly-iii/app/Helpers/Report/BudgetReportHelper.php

224 lines
9.6 KiB
PHP
Raw Normal View History

2016-01-27 20:54:14 +01:00
<?php
/**
* BudgetReportHelper.php
2017-10-21 08:40:00 +02:00
* Copyright (c) 2017 thegrumpydictator@gmail.com
2016-01-27 20:54:14 +01:00
*
2017-10-21 08:40:00 +02:00
* This file is part of Firefly III.
*
2017-10-21 08:40:00 +02:00
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
2017-12-17 14:41:58 +01:00
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
2016-01-27 20:54:14 +01:00
*/
declare(strict_types=1);
2016-01-27 20:54:14 +01:00
namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
2016-04-24 20:00:20 +02:00
use FireflyIII\Models\Budget;
2016-12-30 08:41:48 +01:00
use FireflyIII\Models\BudgetLimit;
2019-08-30 08:09:39 +02:00
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
2016-05-02 20:49:19 +02:00
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
2019-08-30 09:13:10 +02:00
use FireflyIII\Repositories\Budget\NoBudgetRepositoryInterface;
2019-08-30 08:19:55 +02:00
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
2016-01-27 20:54:14 +01:00
use Illuminate\Support\Collection;
use Log;
2016-01-27 20:54:14 +01:00
/**
2017-11-15 12:25:49 +01:00
* Class BudgetReportHelper.
*
* @codeCoverageIgnore
2016-01-27 20:54:14 +01:00
*/
class BudgetReportHelper implements BudgetReportHelperInterface
{
2019-08-30 08:09:39 +02:00
/** @var BudgetLimitRepositoryInterface */
private $blRepository;
2019-08-30 09:13:10 +02:00
/** @var NoBudgetRepositoryInterface */
private $noBudgetRepository;
2019-08-30 08:19:55 +02:00
/** @var OperationsRepositoryInterface */
private $opsRepository;
/** @var BudgetRepositoryInterface The budget repository interface. */
2016-05-18 07:01:27 +02:00
private $repository;
/**
* BudgetReportHelper constructor.
*/
2019-08-30 08:09:39 +02:00
public function __construct()
2016-05-18 07:01:27 +02:00
{
2019-08-30 09:13:10 +02:00
$this->repository = app(BudgetRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->noBudgetRepository = app(NoBudgetRepositoryInterface::class);
if ('testing' === config('app.env')) {
2019-06-07 18:20:15 +02:00
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
2016-05-18 07:01:27 +02:00
}
2016-01-27 20:54:14 +01:00
2016-06-16 20:52:30 +02:00
/**
* Get the full budget report.
*
2019-08-16 08:27:08 +02:00
* TODO one big method is very complex.
*
2016-01-27 20:54:14 +01:00
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
2017-02-11 10:05:58 +01:00
* @return array
2016-01-27 20:54:14 +01:00
*/
2017-02-11 10:05:58 +01:00
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts): array
2016-01-27 20:54:14 +01:00
{
2017-02-11 10:05:58 +01:00
$set = $this->repository->getBudgets();
2019-08-16 08:27:08 +02:00
$array = [
'budgets' => [],
'sums' => [],
];
2016-01-27 20:54:14 +01:00
2016-05-06 06:15:46 +02:00
/** @var Budget $budget */
2016-01-27 20:54:14 +01:00
foreach ($set as $budget) {
2019-08-16 08:27:08 +02:00
$entry = [
'budget_id' => $budget->id,
'budget_name' => $budget->name,
'no_budget' => false,
'rows' => [],
];
// get multi currency expenses first:
2019-08-30 08:09:39 +02:00
$budgetLimits = $this->blRepository->getBudgetLimits($budget, $start, $end);
2019-08-30 08:19:55 +02:00
$expenses = $this->opsRepository->spentInPeriodMc(new Collection([$budget]), $accounts, $start, $end);
2019-08-21 18:07:15 +02:00
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($budget->user);
Log::debug(sprintf('Default currency for getBudgetReport is %s', $defaultCurrency->code));
2019-08-16 08:27:08 +02:00
if (0 === count($expenses)) {
// list the budget limits, basic amounts.
/** @var BudgetLimit $limit */
foreach ($budgetLimits as $limit) {
2019-08-21 18:07:15 +02:00
$currency = $limit->transactionCurrency ?? $defaultCurrency;
Log::debug(sprintf('Default currency for limit #%d is %s', $limit->id, $currency->code));
$row = [
2019-08-16 08:27:08 +02:00
'limit_id' => $limit->id,
'start_date' => $limit->start_date,
'end_date' => $limit->end_date,
'budgeted' => $limit->amount,
'spent' => '0',
'left' => $limit->amount,
2019-09-03 16:56:46 +02:00
'overspent' => '0',
2019-08-21 18:07:15 +02:00
'currency_id' => $currency->id,
'currency_code' => $currency->code,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
2017-02-11 10:05:58 +01:00
];
2019-08-16 08:27:08 +02:00
$entry['rows'][] = $row;
}
2016-01-27 20:54:14 +01:00
}
2019-08-16 08:27:08 +02:00
foreach ($expenses as $expense) {
$limit = $this->budgetLimitInCurrency($expense['currency_id'], $budgetLimits);
$row = [
'limit_id' => null,
'start_date' => null,
'end_date' => null,
'budgeted' => null,
'spent' => $expense['amount'],
'left' => null,
2019-09-03 16:56:46 +02:00
'overspent' => '0',
2019-08-16 08:27:08 +02:00
'currency_id' => $expense['currency_id'],
'currency_code' => $expense['currency_name'],
'currency_name' => $expense['currency_name'],
'currency_symbol' => $expense['currency_symbol'],
'currency_decimal_places' => $expense['currency_decimal_places'],
2017-02-11 10:05:58 +01:00
];
2019-08-16 08:27:08 +02:00
if (null !== $limit) {
// yes
$row['start_date'] = $limit->start_date;
$row['end_date'] = $limit->end_date;
$row['budgeted'] = $limit->amount;
$row['limit_id'] = $limit->id;
// less than zero? Set to 0.0
$row['left'] = -1 === bccomp(bcadd($limit->amount, $row['spent']), '0') ? '0' : bcadd($limit->amount, $row['spent']);
// spent > budgeted? then sum, otherwise other sum
2019-09-03 16:56:46 +02:00
$row['overspent'] = 1 === bccomp(bcmul($row['spent'],'-1'), $row['budgeted']) ? bcadd($row['spent'], $row['budgeted']) : '0';
2019-08-16 08:27:08 +02:00
}
$entry['rows'][] = $row;
2016-01-27 20:54:14 +01:00
}
2019-08-16 08:27:08 +02:00
$array['budgets'][] = $entry;
2016-01-27 20:54:14 +01:00
}
2019-08-30 09:13:10 +02:00
$noBudget = $this->noBudgetRepository->spentInPeriodWoBudgetMc($accounts, $start, $end);
2019-08-16 08:27:08 +02:00
$noBudgetEntry = [
'budget_id' => null,
'budget_name' => null,
'no_budget' => true,
'rows' => [],
2017-02-11 10:05:58 +01:00
];
2019-08-16 08:27:08 +02:00
foreach ($noBudget as $row) {
$noBudgetEntry['rows'][] = [
'limit_id' => null,
'start_date' => null,
'end_date' => null,
'budgeted' => null,
'spent' => $row['amount'],
'left' => null,
'overspent' => null,
'currency_id' => $row['currency_id'],
'currency_code' => $row['currency_code'],
'currency_name' => $row['currency_name'],
'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'],
];
}
$array['budgets'][] = $noBudgetEntry;
2016-04-24 20:00:20 +02:00
2019-08-16 08:27:08 +02:00
// fill sums:
/** @var array $budget */
foreach ($array['budgets'] as $budget) {
/** @var array $row */
foreach ($budget['rows'] as $row) {
2019-08-21 18:07:15 +02:00
$currencyId = $row['currency_id'];
$array['sums'][$currencyId] = $array['sums'][$currencyId] ?? [
2019-08-16 08:27:08 +02:00
'currency_id' => $row['currency_id'],
'currency_code' => $row['currency_code'],
'currency_name' => $row['currency_name'],
'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'],
'budgeted' => '0',
'spent' => '0',
'left' => '0',
'overspent' => '0',
];
2019-08-21 18:07:15 +02:00
$array['sums'][$currencyId]['budgeted'] = bcadd($array['sums'][$currencyId]['budgeted'], $row['budgeted'] ?? '0');
$array['sums'][$currencyId]['spent'] = bcadd($array['sums'][$currencyId]['spent'], $row['spent'] ?? '0');
$array['sums'][$currencyId]['left'] = bcadd($array['sums'][$currencyId]['left'], $row['left'] ?? '0');
2019-08-16 08:27:08 +02:00
$array['sums'][$currencyId]['overspent'] = bcadd($array['sums'][$currencyId]['overspent'], $row['overspent'] ?? '0');
2016-04-24 20:00:20 +02:00
}
}
2019-08-21 18:07:15 +02:00
2019-08-16 08:27:08 +02:00
return $array;
2016-04-24 20:00:20 +02:00
}
2016-05-18 07:01:27 +02:00
/**
2019-08-16 08:27:08 +02:00
* Returns from the collection the budget limit with the indicated currency ID
2018-07-08 07:59:58 +02:00
*
2019-08-16 08:27:08 +02:00
* @param int $currencyId
* @param Collection $budgetLimits
2016-05-18 07:01:27 +02:00
*
2019-08-16 08:27:08 +02:00
* @return BudgetLimit|null
2016-05-18 07:01:27 +02:00
*/
2019-08-16 08:27:08 +02:00
private function budgetLimitInCurrency(int $currencyId, Collection $budgetLimits): ?BudgetLimit
2016-05-18 07:01:27 +02:00
{
2019-08-16 08:27:08 +02:00
return $budgetLimits->first(
static function (BudgetLimit $limit) use ($currencyId) {
return $limit->transaction_currency_id === $currencyId;
}
);
2016-05-18 07:01:27 +02:00
}
}