From e15932fe4aa85d71a561c9cb78bdda2fc0db00ac Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 23 Dec 2016 17:50:26 +0100 Subject: [PATCH] Make budget report actually more useful. --- .../Chart/BudgetReportController.php | 79 +++++++++++++++++-- .../Models/TransactionJournalSupport.php | 9 ++- resources/lang/en_US/firefly.php | 5 +- 3 files changed, 84 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Chart/BudgetReportController.php b/app/Http/Controllers/Chart/BudgetReportController.php index 530e5b00bb..2a7be91751 100644 --- a/app/Http/Controllers/Chart/BudgetReportController.php +++ b/app/Http/Controllers/Chart/BudgetReportController.php @@ -20,16 +20,17 @@ use FireflyIII\Generator\Report\Category\MonthReportGenerator; use FireflyIII\Helpers\Collector\JournalCollector; use FireflyIII\Http\Controllers\Controller; use FireflyIII\Models\Budget; +use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Support\CacheProperties; use Illuminate\Support\Collection; +use Log; use Navigation; use Response; - /** * Separate controller because many helper functions are shared. * @@ -195,21 +196,36 @@ class BudgetReportController extends Controller if ($cache->has()) { return Response::json($cache->get()); } - + /** @var BudgetRepositoryInterface $repository */ + $repository = app(BudgetRepositoryInterface::class); $format = Navigation::preferredCarbonLocalizedFormat($start, $end); $function = Navigation::preferredEndOfPeriod($start, $end); $chartData = []; $currentStart = clone $start; + $limits = $repository->getAllBudgetLimitRepetitions($start, $end); // also for ALL budgets. // prep chart data: foreach ($budgets as $budget) { - $chartData[$budget->id] = [ - 'label' => $budget->name, + $chartData[$budget->id] = [ + 'label' => strval(trans('firefly.spent_in_specific_budget', ['budget' => $budget->name])), 'type' => 'bar', 'entries' => [], ]; + $chartData[$budget->id . '-sum'] = [ + 'label' => strval(trans('firefly.sum_of_expenses_in_budget', ['budget' => $budget->name])), + 'type' => 'line', + 'fill' => false, + 'entries' => [], + ]; + $chartData[$budget->id . '-left'] = [ + 'label' => strval(trans('firefly.left_in_budget_limit', ['budget' => $budget->name])), + 'type' => 'line', + 'fill' => false, + 'entries' => [], + ]; } - + $sumOfExpenses = []; + $leftOfLimits = []; while ($currentStart < $end) { $currentEnd = clone $currentStart; $currentEnd = $currentEnd->$function(); @@ -218,7 +234,20 @@ class BudgetReportController extends Controller /** @var Budget $budget */ foreach ($budgets as $budget) { - $chartData[$budget->id]['entries'][$label] = round(($expenses[$budget->id] ?? '0'), 2); + $currentExpenses = $expenses[$budget->id] ?? '0'; + $sumOfExpenses[$budget->id] = $sumOfExpenses[$budget->id] ?? '0'; + $sumOfExpenses[$budget->id] = bcadd($currentExpenses, $sumOfExpenses[$budget->id]); + $chartData[$budget->id]['entries'][$label] = round(bcmul($currentExpenses, '-1'), 2); + $chartData[$budget->id . '-sum']['entries'][$label] = round(bcmul($sumOfExpenses[$budget->id], '-1'), 2); + + $limit = $this->filterLimits($limits, $budget, $currentStart); + if (!is_null($limit->id)) { + $leftOfLimits[$limit->id] = $leftOfLimits[$limit->id] ?? strval($limit->amount); + $leftOfLimits[$limit->id] = bcadd($leftOfLimits[$limit->id], $currentExpenses); + $chartData[$budget->id . '-left']['entries'][$label] = round($leftOfLimits[$limit->id], 2); + } + + } $currentStart = clone $currentEnd; $currentStart->addDay(); @@ -230,6 +259,44 @@ class BudgetReportController extends Controller return Response::json($data); } + /** + * @param $limits + * @param $budget + * @param $currentStart + * + * @return LimitRepetition + */ + private function filterLimits(Collection $limits, Budget $budget, Carbon $date): LimitRepetition + { + Log::debug(sprintf('Start of filterLimits with %d limits.', $limits->count())); + $filtered = $limits->filter( + function (LimitRepetition $limit) use ($budget, $date) { + if ($limit->budget_id !== $budget->id) { + Log::debug(sprintf('LimitRepetition has budget #%d but expecting #%d', $limit->budget_id, $budget->id)); + + return false; + } + if ($date < $limit->startdate || $date > $limit->enddate) { + Log::debug( + sprintf( + 'Date %s is not between %s and %s', + $date->format('Y-m-d'), $limit->startdate->format('Y-m-d'), $limit->enddate->format('Y-m-d') + ) + ); + + return false; + } + + return $limit; + } + ); + if ($filtered->count() === 1) { + return $filtered->first(); + } + + return new LimitRepetition; + } + /** * @param Collection $accounts diff --git a/app/Support/Models/TransactionJournalSupport.php b/app/Support/Models/TransactionJournalSupport.php index 513fec2623..e1d928bef4 100644 --- a/app/Support/Models/TransactionJournalSupport.php +++ b/app/Support/Models/TransactionJournalSupport.php @@ -163,7 +163,9 @@ class TransactionJournalSupport extends Model if ($cache->has()) { return $cache->get(); } - $transactions = $journal->transactions()->where('amount', '>', 0)->orderBy('transactions.account_id')->with('account')->get(); + $transactions = $journal->transactions() + ->whereNull('transactions.deleted_at') + ->where('transactions.amount', '>', 0)->orderBy('transactions.account_id')->with('account')->get(); $list = new Collection; /** @var Transaction $t */ foreach ($transactions as $t) { @@ -255,7 +257,10 @@ class TransactionJournalSupport extends Model if ($cache->has()) { return $cache->get(); } - $transactions = $journal->transactions()->where('amount', '<', 0)->orderBy('transactions.account_id')->with('account')->get(); + $transactions = $journal->transactions() + ->whereNull('transactions.deleted_at') + ->where('transactions.amount', '<', 0) + ->orderBy('transactions.account_id')->with('account')->get(); $list = new Collection; /** @var Transaction $t */ foreach ($transactions as $t) { diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 18c6a81aea..af44a37ef1 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -93,7 +93,10 @@ return [ 'cannot_redirect_to_account' => 'Firefly III cannot redirect you to the correct page. Apologies.', 'sum_of_expenses' => 'Sum of expenses', 'sum_of_income' => 'Sum of income', - + 'spent_in_specific_budget' => 'Spent in budget ":budget"', + 'sum_of_expenses_in_budget' => 'Spent total in budget ":budget"', + 'left_in_budget_limit' => 'Left to spend according to budgeting', + // repeat frequencies: 'repeat_freq_yearly' => 'yearly', 'repeat_freq_monthly' => 'monthly',