diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index b276cdf313..767a87280b 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -37,6 +37,8 @@ class BudgetController extends Controller } /** + * TODO expand with no budget chart. + * * @param BudgetRepositoryInterface $repository * @param $report_type * @param Carbon $start @@ -61,41 +63,43 @@ class BudgetController extends Controller return Response::json($cache->get()); // @codeCoverageIgnore } - /** - * budget - * year: - * spent: x - * budgeted: x - * year - * spent: x - * budgeted: x + /* + * Get the budgeted amounts for each budgets in each year. */ + $budgetedSet = $repository->getBudgetedPerYear($budgets, $start, $end); + $budgetedArray = []; + /** @var Budget $entry */ + foreach ($budgetedSet as $entry) { + $budgetedArray[$entry->id][$entry->dateFormatted] = $entry->budgeted; + } + + $set = $repository->getBudgetsAndExpensesPerYear($budgets, $accounts, $start, $end); $entries = new Collection; // go by budget, not by year. + /** @var Budget $budget */ foreach ($budgets as $budget) { - $entry = ['name' => '', 'spent' => [], 'budgeted' => []]; - + $entry = ['name' => '', 'spent' => [], 'budgeted' => []]; + $id = $budget->id; $currentStart = clone $start; while ($currentStart < $end) { // fix the date: $currentEnd = clone $currentStart; $currentEnd->endOfYear(); - // get data: - if (is_null($budget->id)) { - $name = trans('firefly.noBudget'); - $sum = $repository->getWithoutBudgetSum($currentStart, $currentEnd); - $budgeted = 0; - } else { - $name = $budget->name; - $sum = $repository->balanceInPeriod($budget, $currentStart, $currentEnd, $accounts); - $budgeted = $repository->getBudgetLimitRepetitions($budget, $currentStart, $currentEnd)->sum('amount'); + // save to array: + $year = $currentStart->year; + $entry['name'] = $budget->name; + $spent = 0; + $budgeted = 0; + if (isset($set[$id]['entries'][$year])) { + $spent = $set[$id]['entries'][$year] * -1; } - // save to array: - $year = $currentStart->year; - $entry['name'] = $name; - $entry['spent'][$year] = ($sum * -1); + if (isset($budgetedArray[$id][$year])) { + $budgeted = round($budgetedArray[$id][$year], 2); + } + + $entry['spent'][$year] = $spent; $entry['budgeted'][$year] = $budgeted; // jump to next year. @@ -106,6 +110,7 @@ class BudgetController extends Controller } // generate chart with data: $data = $this->generator->multiYear($entries); + $cache->store($data); return Response::json($data); @@ -273,6 +278,8 @@ class BudgetController extends Controller } /** + * TODO expand with no budget chart. + * * @param BudgetRepositoryInterface $repository * @param $report_type * @param Carbon $start @@ -295,7 +302,7 @@ class BudgetController extends Controller return Response::json($cache->get()); // @codeCoverageIgnore } - $budgetInformation = $repository->getBudgetsAndExpenses($start, $end); + $budgetInformation = $repository->getBudgetsAndExpensesPerMonth($accounts, $start, $end); $budgets = new Collection; $entries = new Collection; diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 56113c1d76..9b90c88d69 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -5,6 +5,7 @@ namespace FireflyIII\Repositories\Budget; use Auth; use Carbon\Carbon; use DB; +use FireflyIII\Models\Account; use FireflyIII\Models\Budget; use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\LimitRepetition; @@ -214,33 +215,41 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn * Returns an array with every budget in it and the expenses for each budget * per month. * - * @param Carbon $start - * @param Carbon $end + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end * * @return array */ - public function getBudgetsAndExpenses(Carbon $start, Carbon $end) + public function getBudgetsAndExpensesPerMonth(Collection $accounts, Carbon $start, Carbon $end) { + $ids = []; + /** @var Account $account */ + foreach ($accounts as $account) { + $ids[] = $account->id; + } + /** @var Collection $set */ - $set = Auth::user()->budgets() - ->leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id') - ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id') - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); - } - ) - ->groupBy('budgets.id') - ->groupBy('dateFormatted') - ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) - ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) - ->get( - [ - 'budgets.*', - DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y-%m") AS `dateFormatted`'), - DB::Raw('SUM(`transactions`.`amount`) AS `sumAmount`') - ] - ); + $set = Auth::user()->budgets() + ->leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id') + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id') + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); + } + ) + ->groupBy('budgets.id') + ->groupBy('dateFormatted') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->whereIn('transactions.account_id', $ids) + ->get( + [ + 'budgets.*', + DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y-%m") AS `dateFormatted`'), + DB::Raw('SUM(`transactions`.`amount`) AS `sumAmount`') + ] + ); $set = $set->sortBy( function (Budget $budget) { @@ -260,6 +269,7 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn // store each entry: $return[$id]['entries'][$budget->dateFormatted] = $budget->sumAmount; } + return $return; } @@ -503,7 +513,110 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn } return $limit; + } + /** + * Get the budgeted amounts for each budgets in each year. + * + * @param Collection $budgets + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getBudgetedPerYear(Collection $budgets, Carbon $start, Carbon $end) + { + $budgetIds = []; + /** @var Budget $budget */ + foreach ($budgets as $budget) { + $budgetIds[] = $budget->id; + } + + $set = Auth::user()->budgets() + ->leftJoin('budget_limits', 'budgets.id', '=', 'budget_limits.budget_id') + ->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') + ->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d')) + ->where('limit_repetitions.enddate', '<=', $end->format('Y-m-d')) + ->groupBy('budgets.id') + ->groupBy('dateFormatted') + ->whereIn('budgets.id', $budgetIds) + ->get( + [ + 'budgets.*', + DB::Raw('DATE_FORMAT(`limit_repetitions`.`startdate`,"%Y") as `dateFormatted`'), + DB::Raw('SUM(`limit_repetitions`.`amount`) as `budgeted`') + ] + ); + return $set; + } + + /** + * Returns an array with every budget in it and the expenses for each budget + * per year for. + * + * @param Collection $budgets + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function getBudgetsAndExpensesPerYear(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end) + { + $ids = []; + /** @var Account $account */ + foreach ($accounts as $account) { + $ids[] = $account->id; + } + $budgetIds = []; + /** @var Budget $budget */ + foreach ($budgets as $budget) { + $budgetIds[] = $budget->id; + } + + /** @var Collection $set */ + $set = Auth::user()->budgets() + ->leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id') + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id') + ->leftJoin( + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); + } + ) + ->groupBy('budgets.id') + ->groupBy('dateFormatted') + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->whereIn('transactions.account_id', $ids) + ->whereIn('budgets.id', $budgetIds) + ->get( + [ + 'budgets.*', + DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y") AS `dateFormatted`'), + DB::Raw('SUM(`transactions`.`amount`) AS `sumAmount`') + ] + ); + + $set = $set->sortBy( + function (Budget $budget) { + return strtolower($budget->name); + } + ); + + $return = []; + foreach ($set as $budget) { + $id = $budget->id; + if (!isset($return[$id])) { + $return[$id] = [ + 'budget' => $budget, + 'entries' => [], + ]; + } + // store each entry: + $return[$id]['entries'][$budget->dateFormatted] = $budget->sumAmount; + } + + return $return; } } diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index 4e75e37bc6..0c14906983 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -31,12 +31,26 @@ interface BudgetRepositoryInterface * Returns an array with every budget in it and the expenses for each budget * per month. * - * @param Carbon $start - * @param Carbon $end + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end * * @return array */ - public function getBudgetsAndExpenses(Carbon $start, Carbon $end); + public function getBudgetsAndExpensesPerMonth(Collection $accounts, Carbon $start, Carbon $end); + + /** + * Returns an array with every budget in it and the expenses for each budget + * per year for. + * + * @param Collection $budgets + * @param Collection $accounts + * @param Carbon $start + * @param Carbon $end + * + * @return array + */ + public function getBudgetsAndExpensesPerYear(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end); /** * Takes tags into account. @@ -53,6 +67,17 @@ interface BudgetRepositoryInterface */ public function getActiveBudgets(); + /** + * Get the budgeted amounts for each budgets in each year. + * + * @param Collection $budgets + * @param Carbon $start + * @param Carbon $end + * + * @return Collection + */ + public function getBudgetedPerYear(Collection $budgets, Carbon $start, Carbon $end); + /** * @param Budget $budget * @param Carbon $start