diff --git a/app/Helpers/Report/BudgetReportHelper.php b/app/Helpers/Report/BudgetReportHelper.php index 010f28f89d..d4af9fc8a4 100644 --- a/app/Helpers/Report/BudgetReportHelper.php +++ b/app/Helpers/Report/BudgetReportHelper.php @@ -17,10 +17,8 @@ namespace FireflyIII\Helpers\Report; use Carbon\Carbon; use FireflyIII\Helpers\Collection\Budget as BudgetCollection; use FireflyIII\Helpers\Collection\BudgetLine; -use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Models\Budget; use FireflyIII\Models\LimitRepetition; -use FireflyIII\Models\TransactionType; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use Illuminate\Support\Collection; @@ -54,66 +52,8 @@ class BudgetReportHelper implements BudgetReportHelperInterface public function getBudgetPeriodReport(Carbon $start, Carbon $end, Collection $accounts): array { $budgets = $this->repository->getBudgets(); - /** @var JournalCollectorInterface $collector */ - $collector = app(JournalCollectorInterface::class); - $collector->setAllAssetAccounts()->setRange($start, $end); - $collector->setBudgets($budgets); - $transactions = $collector->getJournals(); - - // this is the date format we need: - // define period to group on: - $carbonFormat = 'Y-m-d'; - // monthly report (for year) - if ($start->diffInMonths($end) > 1) { - $carbonFormat = 'Y-m'; - } - - // yearly report (for multi year) - if ($start->diffInMonths($end) > 12) { - $carbonFormat = 'Y'; - } - - // this is the set of transactions for this period - // in these budgets. Now they must be grouped (manually) - // id, period => amount - $data = []; - foreach ($transactions as $transaction) { - $budgetId = max(intval($transaction->transaction_journal_budget_id), intval($transaction->transaction_budget_id)); - $date = $transaction->date->format($carbonFormat); - - if (!isset($data[$budgetId])) { - $data[$budgetId]['name'] = $this->getBudgetName($budgetId, $budgets); - $data[$budgetId]['sum'] = '0'; - $data[$budgetId]['entries'] = []; - } - - if (!isset($data[$budgetId]['entries'][$date])) { - $data[$budgetId]['entries'][$date] = '0'; - } - $data[$budgetId]['entries'][$date] = bcadd($data[$budgetId]['entries'][$date], $transaction->transaction_amount); - } - // and now the same for stuff without a budget: - /** @var JournalCollectorInterface $collector */ - $collector = app(JournalCollectorInterface::class); - $collector->setAllAssetAccounts()->setRange($start, $end); - $collector->setTypes([TransactionType::WITHDRAWAL]); - $collector->withoutBudget(); - $transactions = $collector->getJournals(); - - $data[0]['entries'] = []; - $data[0]['name'] = strval(trans('firefly.no_budget')); - $data[0]['sum'] = '0'; - - foreach ($transactions as $transaction) { - $date = $transaction->date->format($carbonFormat); - - if (!isset($data[0]['entries'][$date])) { - $data[0]['entries'][$date] = '0'; - } - $data[0]['entries'][$date] = bcadd($data[0]['entries'][$date], $transaction->transaction_amount); - } - - $data = $this->filterBudgetPeriodReport($data); + $report = $this->repository->getBudgetPeriodReport($budgets, $accounts, $start, $end); + $data = $this->filterBudgetPeriodReport($report); return $data; } @@ -249,26 +189,4 @@ class BudgetReportHelper implements BudgetReportHelperInterface return $data; } - - /** - * @param int $budgetId - * @param Collection $budgets - * - * @return string - */ - private function getBudgetName(int $budgetId, Collection $budgets): string - { - - $first = $budgets->filter( - function (Budget $budget) use ($budgetId) { - return $budgetId === $budget->id; - } - ); - if (!is_null($first->first())) { - return $first->first()->name; - } - - return '(unknown)'; - } - } diff --git a/app/Http/Controllers/Chart/BudgetController.php b/app/Http/Controllers/Chart/BudgetController.php index 4ceb55d805..62ccd43752 100644 --- a/app/Http/Controllers/Chart/BudgetController.php +++ b/app/Http/Controllers/Chart/BudgetController.php @@ -207,13 +207,12 @@ class BudgetController extends Controller $cache->addProperty('budget'); $cache->addProperty('period'); if ($cache->has()) { - return Response::json($cache->get()); + // return Response::json($cache->get()); } // the expenses: $periods = Navigation::listOfPeriods($start, $end); - $result = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end); - $entries = $repository->filterAmounts($result, $budget->id, $periods); + $entries = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end); $budgeted = []; // the budget limits: @@ -229,6 +228,7 @@ class BudgetController extends Controller $key = 'Y'; } + // get budgeted: $repetitions = $repository->getAllBudgetLimitRepetitions($start, $end); $current = clone $start; while ($current < $end) { @@ -254,7 +254,7 @@ class BudgetController extends Controller foreach (array_keys($periods) as $period) { $nice = $periods[$period]; $result[$nice] = [ - 'spent' => isset($entries[$period]) ? $entries[$period] : '0', + 'spent' => isset($entries[$budget->id]['entries'][$period]) ? $entries[$budget->id]['entries'][$period] : '0', 'budgeted' => isset($entries[$period]) ? $budgeted[$period] : 0, ]; } @@ -348,7 +348,7 @@ class BudgetController extends Controller * * @return array */ - private function spentInPeriodWithout(Carbon $start, Carbon $end):array + private function spentInPeriodWithout(Carbon $start, Carbon $end): array { // collector $collector = new JournalCollector(auth()->user()); diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 62a9add9c1..2ee801dfc3 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -14,9 +14,9 @@ declare(strict_types = 1); namespace FireflyIII\Repositories\Budget; use Carbon\Carbon; -use DB; use FireflyIII\Events\StoredBudgetLimit; use FireflyIII\Events\UpdatedBudgetLimit; +use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Models\Budget; use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\LimitRepetition; @@ -221,59 +221,70 @@ class BudgetRepository implements BudgetRepositoryInterface * @param Carbon $start * @param Carbon $end * - * @return Collection + * @return array */ - public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): Collection + public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array { - // get account ID's. - $accountIds = $accounts->pluck('id')->toArray(); - - // get budget ID's. - $budgetIds = $budgets->pluck('id')->toArray(); + /** @var JournalCollectorInterface $collector */ + $collector = app(JournalCollectorInterface::class); + $collector->setAllAssetAccounts()->setRange($start, $end); + $collector->setBudgets($budgets); + $transactions = $collector->getJournals(); + // this is the date format we need: // define period to group on: - $sqlDateFormat = '%Y-%m-%d'; + $carbonFormat = 'Y-m-d'; // monthly report (for year) if ($start->diffInMonths($end) > 1) { - $sqlDateFormat = '%Y-%m'; + $carbonFormat = 'Y-m'; } // yearly report (for multi year) if ($start->diffInMonths($end) > 12) { - $sqlDateFormat = '%Y'; + $carbonFormat = 'Y'; } - // build query. - $query = TransactionJournal - ::leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') - ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') - ->leftJoin( - 'transactions', function (JoinClause $join) { - $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0); + // this is the set of transactions for this period + // in these budgets. Now they must be grouped (manually) + // id, period => amount + $data = []; + foreach ($transactions as $transaction) { + $budgetId = max(intval($transaction->transaction_journal_budget_id), intval($transaction->transaction_budget_id)); + $date = $transaction->date->format($carbonFormat); + + if (!isset($data[$budgetId])) { + $data[$budgetId]['name'] = $this->getBudgetName($budgetId, $budgets); + $data[$budgetId]['sum'] = '0'; + $data[$budgetId]['entries'] = []; } - ) - ->whereNull('transaction_journals.deleted_at') - ->whereNull('transactions.deleted_at') - ->where('transaction_types.type', 'Withdrawal') - ->where('transaction_journals.user_id', auth()->user()->id); - if (count($accountIds) > 0) { - $query->whereIn('transactions.account_id', $accountIds); + if (!isset($data[$budgetId]['entries'][$date])) { + $data[$budgetId]['entries'][$date] = '0'; + } + $data[$budgetId]['entries'][$date] = bcadd($data[$budgetId]['entries'][$date], $transaction->transaction_amount); + } + // and now the same for stuff without a budget: + /** @var JournalCollectorInterface $collector */ + $collector = app(JournalCollectorInterface::class); + $collector->setAllAssetAccounts()->setRange($start, $end); + $collector->setTypes([TransactionType::WITHDRAWAL]); + $collector->withoutBudget(); + $transactions = $collector->getJournals(); + + $data[0]['entries'] = []; + $data[0]['name'] = strval(trans('firefly.no_budget')); + $data[0]['sum'] = '0'; + + foreach ($transactions as $transaction) { + $date = $transaction->date->format($carbonFormat); + + if (!isset($data[0]['entries'][$date])) { + $data[0]['entries'][$date] = '0'; + } + $data[0]['entries'][$date] = bcadd($data[0]['entries'][$date], $transaction->transaction_amount); } - if (count($budgetIds) > 0) { - $query->whereIn('budget_transaction_journal.budget_id', $budgetIds); - } - - $query->groupBy(['budget_transaction_journal.budget_id', 'period_marker']); - - return $query->get( - [ - 'budget_transaction_journal.budget_id', - DB::raw(sprintf('DATE_FORMAT(transaction_journals.date,"%s") AS period_marker', $sqlDateFormat)), - DB::raw('SUM(transactions.amount) as sum_of_period'), - ] - ); + return $data; } @@ -319,7 +330,7 @@ class BudgetRepository implements BudgetRepositoryInterface * * @return string */ - public function spentInPeriod(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end) : string + public function spentInPeriod(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): string { // collect amount of transaction journals, which is easy: $budgetIds = $budgets->pluck('id')->toArray(); @@ -504,7 +515,7 @@ class BudgetRepository implements BudgetRepositoryInterface * * @return BudgetLimit */ - public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $range, int $amount) : BudgetLimit + public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $range, int $amount): BudgetLimit { // there might be a budget limit for this startdate: $repeatFreq = config('firefly.range_to_repeat_freq.' . $range); @@ -547,4 +558,25 @@ class BudgetRepository implements BudgetRepositoryInterface return $limit; } + + /** + * @param int $budgetId + * @param Collection $budgets + * + * @return string + */ + private function getBudgetName(int $budgetId, Collection $budgets): string + { + + $first = $budgets->filter( + function (Budget $budget) use ($budgetId) { + return $budgetId === $budget->id; + } + ); + if (!is_null($first->first())) { + return $first->first()->name; + } + + return '(unknown)'; + } } diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index fcc74eac31..c346debdac 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -91,19 +91,16 @@ interface BudgetRepositoryInterface public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end): Collection; /** - * This method is being used to generate the budget overview in the year/multi-year report. More specifically, this - * method runs the query and returns the result that is used for this report. - * - * The query is used in both the year/multi-year budget overview AND in the accompanying chart. * + * todo always collects without budget info * @param Collection $budgets * @param Collection $accounts * @param Carbon $start * @param Carbon $end * - * @return Collection + * @return array */ - public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): Collection; + public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array; /** * @return Collection