diff --git a/app/Http/Controllers/BudgetController.php b/app/Http/Controllers/BudgetController.php index fdbe4bfe7d..b2ed2af41f 100644 --- a/app/Http/Controllers/BudgetController.php +++ b/app/Http/Controllers/BudgetController.php @@ -26,6 +26,7 @@ use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; use Input; +use Log; use Navigation; use Preferences; use Response; @@ -199,10 +200,12 @@ class BudgetController extends Controller $accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH]); $startAsString = $start->format('Y-m-d'); $endAsString = $end->format('Y-m-d'); + Log::debug('Now at /budgets'); // loop the budgets: /** @var Budget $budget */ foreach ($budgets as $budget) { + Log::debug(sprintf('Now at budget #%d ("%s")', $budget->id, $budget->name)); $budget->spent = $repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end); $allRepetitions = $repository->getAllBudgetLimitRepetitions($start, $end); $otherRepetitions = new Collection; @@ -290,13 +293,13 @@ class BudgetController extends Controller } /** - * @param BudgetRepositoryInterface $repository - * @param Budget $budget + * @param BudgetRepositoryInterface $repository + * @param AccountRepositoryInterface $accountRepository + * @param Budget $budget * * @return View - * @throws FireflyException */ - public function show(BudgetRepositoryInterface $repository, Budget $budget) + public function show(BudgetRepositoryInterface $repository, AccountRepositoryInterface $accountRepository, Budget $budget) { /** @var Carbon $start */ $start = session('first', Carbon::create()->startOfYear()); @@ -308,6 +311,7 @@ class BudgetController extends Controller $count = $journals->count(); $journals = $journals->slice($offset, $pageSize); $journals = new LengthAwarePaginator($journals, $count, $pageSize); + $accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH]); $journals->setPath('/budgets/show/' . $budget->id); @@ -318,7 +322,7 @@ class BudgetController extends Controller /** @var LimitRepetition $entry */ foreach ($set as $entry) { - $entry->spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $entry->startdate, $entry->enddate); + $entry->spent = $repository->spentInPeriod(new Collection([$budget]), $accounts, $entry->startdate, $entry->enddate); $limits->push($entry); } @@ -326,15 +330,17 @@ class BudgetController extends Controller } /** - * @param BudgetRepositoryInterface $repository - * @param Budget $budget - * @param LimitRepetition $repetition + * @param BudgetRepositoryInterface $repository + * @param AccountRepositoryInterface $accountRepository + * @param Budget $budget + * @param LimitRepetition $repetition * * @return View * @throws FireflyException */ - public function showWithRepetition(BudgetRepositoryInterface $repository, Budget $budget, LimitRepetition $repetition) - { + public function showWithRepetition( + BudgetRepositoryInterface $repository, AccountRepositoryInterface $accountRepository, Budget $budget, LimitRepetition $repetition + ) { if ($repetition->budgetLimit->budget->id != $budget->id) { throw new FireflyException('This budget limit is not part of this budget.'); } @@ -348,11 +354,13 @@ class BudgetController extends Controller $journals = $journals->slice($offset, $pageSize); $journals = new LengthAwarePaginator($journals, $count, $pageSize); $subTitle = trans('firefly.budget_in_month', ['name' => $budget->name, 'month' => $repetition->startdate->formatLocalized($this->monthFormat)]); + $accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH]); + $journals->setPath('/budgets/show/' . $budget->id . '/' . $repetition->id); - $repetition->spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $repetition->startdate, $repetition->enddate); + $repetition->spent = $repository->spentInPeriod(new Collection([$budget]), $accounts, $repetition->startdate, $repetition->enddate); $limits = new Collection([$repetition]); return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle')); diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index b674435881..3679b922c7 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -19,6 +19,7 @@ use FireflyIII\Events\UpdatedBudgetLimit; use FireflyIII\Models\Budget; use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\LimitRepetition; +use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; use FireflyIII\User; @@ -347,79 +348,66 @@ class BudgetRepository implements BudgetRepositoryInterface */ public function spentInPeriod(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end) : string { - // first collect actual transaction journals (fairly easy) - $query = $this->user - ->transactionJournals() + // collect amount of transaction journals, which is easy: + $budgetIds = $budgets->pluck('id')->toArray(); + $accountIds = $accounts->pluck('id')->toArray(); + $fromJournalsQuery = 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 as source', function (JoinClause $join) { - $join->on('source.transaction_journal_id', '=', 'transaction_journals.id')->where('source.amount', '<', 0); + 'transactions', function (JoinClause $join) { + $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', '0'); } ) - ->leftJoin( - 'transactions as destination', function (JoinClause $join) { - $join->on('destination.transaction_journal_id', '=', 'transaction_journals.id')->where('destination.amount', '>', 0); - } - ); - $query->whereNull('source.deleted_at'); - $query->whereNull('destination.deleted_at'); - $query->where('transaction_journals.completed', 1); + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->whereNull('transaction_journals.deleted_at') + ->whereNull('transactions.deleted_at') + ->where('transaction_journals.user_id', $this->user->id) + ->where('transaction_types.type', 'Withdrawal'); - if ($end >= $start) { - $query->before($end)->after($start); - } - if ($accounts->count() > 0) { - $accountIds = $accounts->pluck('id')->toArray(); - $query->where( - // source.account_id in accountIds XOR destination.account_id in accountIds - function (Builder $query) use ($accountIds) { - $query->where( - function (Builder $q1) use ($accountIds) { - $q1->whereIn('source.account_id', $accountIds) - ->whereNotIn('destination.account_id', $accountIds); - } - )->orWhere( - function (Builder $q2) use ($accountIds) { - $q2->whereIn('destination.account_id', $accountIds) - ->whereNotIn('source.account_id', $accountIds); - } - ); - } - ); - } + // add budgets: if ($budgets->count() > 0) { - $budgetIds = $budgets->pluck('id')->toArray(); - $query->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'); - $query->whereIn('budget_transaction_journal.budget_id', $budgetIds); - + $fromJournalsQuery->whereIn('budget_transaction_journal.budget_id', $budgetIds); } - // that should do it: - $ids = $query->distinct()->get(['transaction_journals.id'])->pluck('id')->toArray(); - $first = '0'; - if (count($ids) > 0) { - $first = strval( - $this->user->transactions() - ->whereIn('transaction_journal_id', $ids) - ->where('amount', '<', '0') - ->whereNull('transactions.deleted_at') - ->sum('amount') - ); - } - // then collection transactions (harder) - $query = $this->user->transactions() - ->where('transactions.amount', '<', 0) - ->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00')) - ->where('transaction_journals.date', '<=', $end->format('Y-m-d 23:59:59')); + // add accounts: if ($accounts->count() > 0) { - $accountIds = $accounts->pluck('id')->toArray(); - $query->whereIn('transactions.account_id', $accountIds); + $fromJournalsQuery->whereIn('transactions.account_id', $accountIds); } + $first = strval($fromJournalsQuery->sum('transactions.amount')); + unset($fromJournalsQuery); + + // collect amount from transactions: + /** + * select transactions.id, budget_transaction.budget_id , transactions.amount + * + * + * and budget_transaction.budget_id in (1,61) + * and transactions.account_id in (2) + */ + $fromTransactionsQuery = Transaction + ::leftJoin('budget_transaction', 'budget_transaction.transaction_id', '=', 'transactions.id') + ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') + ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') + ->whereNull('transactions.deleted_at') + ->whereNull('transaction_journals.deleted_at') + ->where('transactions.amount', '<', 0) + ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) + ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) + ->where('transaction_journals.user_id', $this->user->id) + ->where('transaction_types.type', 'Withdrawal'); + + // add budgets: if ($budgets->count() > 0) { - $budgetIds = $budgets->pluck('id')->toArray(); - $query->leftJoin('budget_transaction', 'budget_transaction.transaction_id', '=', 'transactions.id'); - $query->whereIn('budget_transaction.budget_id', $budgetIds); + $fromTransactionsQuery->whereIn('budget_transaction.budget_id', $budgetIds); } - $second = strval($query->sum('transactions.amount')); + + // add accounts: + if ($accounts->count() > 0) { + $fromTransactionsQuery->whereIn('transactions.account_id', $accountIds); + } + $second = strval($fromTransactionsQuery->sum('transactions.amount')); return bcadd($first, $second); }