From a785c450b1b42387156df066443d75b0a0cc6bc5 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 11 Dec 2015 17:53:17 +0100 Subject: [PATCH] First attempt at including a budget report. --- app/Helpers/Report/ReportHelper.php | 70 +++++++++++++++++++ app/Helpers/Report/ReportHelperInterface.php | 29 +++++--- app/Http/Controllers/ReportController.php | 2 +- app/Repositories/Budget/BudgetRepository.php | 13 ++++ .../Budget/BudgetRepositoryInterface.php | 13 ++++ .../Shared/ComponentRepository.php | 44 ++++++++++++ 6 files changed, 160 insertions(+), 11 deletions(-) diff --git a/app/Helpers/Report/ReportHelper.php b/app/Helpers/Report/ReportHelper.php index b9a15f100c..d47a39c8d3 100644 --- a/app/Helpers/Report/ReportHelper.php +++ b/app/Helpers/Report/ReportHelper.php @@ -227,6 +227,7 @@ class ReportHelper implements ReportHelperInterface } + /** * @param Carbon $start * @param Carbon $end @@ -494,4 +495,73 @@ class ReportHelper implements ReportHelperInterface return $object; } + + /** + * @param Carbon $start + * @param Carbon $end + * @param Collection $accounts + * + * @return BudgetCollection + */ + public function getBudgetReportForList(Carbon $start, Carbon $end, Collection $accounts) + { + $object = new BudgetCollection; + /** @var \FireflyIII\Repositories\Budget\BudgetRepositoryInterface $repository */ + $repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); + $set = $repository->getBudgets(); + + bcscale(2); + + foreach ($set as $budget) { + + $repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end); + + // no repetition(s) for this budget: + if ($repetitions->count() == 0) { + $spent = $repository->balanceInPeriodForList($budget, $start, $end, $accounts); + $budgetLine = new BudgetLine; + $budgetLine->setBudget($budget); + $budgetLine->setOverspent($spent); + $object->addOverspent($spent); + $object->addBudgetLine($budgetLine); + continue; + } + + // one or more repetitions for budget: + /** @var LimitRepetition $repetition */ + foreach ($repetitions as $repetition) { + $budgetLine = new BudgetLine; + $budgetLine->setBudget($budget); + $budgetLine->setRepetition($repetition); + $expenses = $repository->balanceInPeriodForList($budget, $repetition->startdate, $repetition->enddate, $accounts); + $expenses = $expenses * -1; + $left = $expenses < $repetition->amount ? bcsub($repetition->amount, $expenses) : 0; + $spent = $expenses > $repetition->amount ? 0 : $expenses; + $overspent = $expenses > $repetition->amount ? bcsub($expenses, $repetition->amount) : 0; + + $budgetLine->setLeft($left); + $budgetLine->setSpent($spent); + $budgetLine->setOverspent($overspent); + $budgetLine->setBudgeted($repetition->amount); + + $object->addBudgeted($repetition->amount); + $object->addSpent($spent); + $object->addLeft($left); + $object->addOverspent($overspent); + $object->addBudgetLine($budgetLine); + + } + + } + + // stuff outside of budgets: + $noBudget = $repository->getWithoutBudgetSum($start, $end); + $budgetLine = new BudgetLine; + $budgetLine->setOverspent($noBudget); + $budgetLine->setSpent($noBudget); + $object->addOverspent($noBudget); + $object->addBudgetLine($budgetLine); + + return $object; + } } diff --git a/app/Helpers/Report/ReportHelperInterface.php b/app/Helpers/Report/ReportHelperInterface.php index 6db8ce93e3..9d4c05a331 100644 --- a/app/Helpers/Report/ReportHelperInterface.php +++ b/app/Helpers/Report/ReportHelperInterface.php @@ -73,6 +73,15 @@ interface ReportHelperInterface */ public function getBudgetReport(Carbon $start, Carbon $end, $shared); + /** + * @param Carbon $start + * @param Carbon $end + * @param Collection $accounts + * + * @return BudgetCollection + */ + public function getBudgetReportForList(Carbon $start, Carbon $end, Collection $accounts); + /** * @param Carbon $start * @param Carbon $end @@ -83,21 +92,21 @@ interface ReportHelperInterface public function getCategoryReport(Carbon $start, Carbon $end, $shared); /** - * Get a full report on the users expenses during the period. - * - * @param Carbon $start - * @param Carbon $end - * @param boolean $shared - * - * @return Expense - */ + * Get a full report on the users expenses during the period. + * + * @param Carbon $start + * @param Carbon $end + * @param boolean $shared + * + * @return Expense + */ public function getExpenseReport($start, $end, $shared); /** * Get a full report on the users expenses during the period for a list of accounts. * - * @param Carbon $start - * @param Carbon $end + * @param Carbon $start + * @param Carbon $end * @param Collection $accounts * * @return Expense diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index cf6928cd12..7cb84f7145 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -244,7 +244,7 @@ class ReportController extends Controller $accounts = $this->helper->getAccountReportForList($start, $end, $list); $incomes = $this->helper->getIncomeReportForList($start, $end, $list); $expenses = $this->helper->getExpenseReportForList($start, $end, $list); - // $budgets = $this->helper->getBudgetReportForList($start, $end, $list); + $budgets = $this->helper->getBudgetReportForList($start, $end, $list); // $categories = $this->helper->getCategoryReportForList($start, $end, $list); // $balance = $this->helper->getBalanceReportForList($start, $end, $list); // $bills = $this->helper->getBillReportForList($start, $end); diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 019e407f1f..9940e2f933 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -315,6 +315,19 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn return bcmul($noBudgetSet, -1); } + /** + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * @param Collection $accounts + * + * @return string + */ + public function balanceInPeriodForList(Budget $budget, Carbon $start, Carbon $end, Collection $accounts) + { + return $this->commonBalanceInPeriodForList($budget, $start, $end, $accounts); + } + /** * @param Budget $budget * @param Carbon $start diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index e614db0f02..ac4e0af7aa 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -139,6 +139,19 @@ interface BudgetRepositoryInterface */ public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, $shared = true); + /** + * + * Same as ::spentInPeriod but corrects journals for a set of accounts + * + * @param Budget $budget + * @param Carbon $start + * @param Carbon $end + * @param Collection $accounts + * + * @return string + */ + public function balanceInPeriodForList(Budget $budget, Carbon $start, Carbon $end, Collection $accounts); + /** * @param array $data * diff --git a/app/Repositories/Shared/ComponentRepository.php b/app/Repositories/Shared/ComponentRepository.php index 4ddb7c9b7d..7f91fb8c13 100644 --- a/app/Repositories/Shared/ComponentRepository.php +++ b/app/Repositories/Shared/ComponentRepository.php @@ -3,9 +3,11 @@ namespace FireflyIII\Repositories\Shared; use Carbon\Carbon; +use FireflyIII\Models\Account; use FireflyIII\Models\TransactionType; use FireflyIII\Support\CacheProperties; use Illuminate\Database\Query\JoinClause; +use Illuminate\Support\Collection; /** * Class ComponentRepository @@ -63,4 +65,46 @@ class ComponentRepository return $sum; } + + /** + * @param $object + * @param Carbon $start + * @param Carbon $end + * @param Collection $accounts + * + * @return string + */ + protected function commonBalanceInPeriodForList($object, Carbon $start, Carbon $end, Collection $accounts) + { + $cache = new CacheProperties; // we must cache this. + $cache->addProperty($object->id); + $cache->addProperty(get_class($object)); + $cache->addProperty($start); + $cache->addProperty($end); + $cache->addProperty($accounts); + $cache->addProperty('balanceInPeriodList'); + + $ids = []; + /** @var Account $account */ + foreach ($accounts as $account) { + $ids[] = $account->id; + } + + if ($cache->has()) { + return $cache->get(); // @codeCoverageIgnore + } + + $sum = $object->transactionjournals() + ->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE]) + ->before($end) + ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') + ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') + ->whereIn('accounts.id', $ids) + ->after($start) + ->get(['transaction_journals.*'])->sum('amount'); + + $cache->store($sum); + + return $sum; + } }