From 61007a95a601d4599c069afad26816d1225bc805 Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 9 Mar 2017 20:54:18 +0100 Subject: [PATCH] Initial code for #595, transactions with no budget --- app/Http/Controllers/BudgetController.php | 118 ++++++++++++++++++---- resources/views/budgets/no-budget.twig | 58 ++++++++++- routes/web.php | 2 +- 3 files changed, 158 insertions(+), 20 deletions(-) diff --git a/app/Http/Controllers/BudgetController.php b/app/Http/Controllers/BudgetController.php index a9ac2a2749..6802b9b235 100644 --- a/app/Http/Controllers/BudgetController.php +++ b/app/Http/Controllers/BudgetController.php @@ -24,9 +24,12 @@ use FireflyIII\Models\Budget; use FireflyIII\Models\BudgetLimit; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Support\CacheProperties; use Illuminate\Http\Request; use Illuminate\Support\Collection; +use Log; +use Navigation; use Preferences; use Response; use View; @@ -191,27 +194,66 @@ class BudgetController extends Controller * * @return View */ - public function noBudget(Request $request) + public function noBudget(Request $request, string $moment = '') { - /** @var Carbon $start */ - $start = session('start', Carbon::now()->startOfMonth()); - /** @var Carbon $end */ - $end = session('end', Carbon::now()->endOfMonth()); + // default values: + $range = Preferences::get('viewRange', '1M')->data; + $start = null; + $end = null; + $periods = new Collection; + + // prep for "all" view. + if ($moment === 'all') { + $subTitle = trans('firefly.all_journals_without_budget'); + } + + // prep for "specific date" view. + if (strlen($moment) > 0 && $moment !== 'all') { + $start = new Carbon($moment); + $end = Navigation::endOfPeriod($start, $range); + $subTitle = trans( + 'firefly.without_budget_between', + ['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)] + ); + $periods = $this->noBudgetPeriodEntries(); + } + + // prep for current period + if (strlen($moment) === 0) { + $start = clone session('start', Navigation::startOfPeriod(new Carbon, $range)); + $end = clone session('end', Navigation::endOfPeriod(new Carbon, $range)); + $periods = $this->noBudgetPeriodEntries(); + $subTitle = trans( + 'firefly.without_budget_between', + ['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)] + ); + } + $page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page')); $pageSize = intval(Preferences::get('transactionPageSize', 50)->data); - $subTitle = trans( - 'firefly.without_budget_between', - ['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)] - ); - // collector - /** @var JournalCollectorInterface $collector */ - $collector = app(JournalCollectorInterface::class); - $collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withoutBudget(); - $journals = $collector->getPaginatedJournals(); - $journals->setPath('/budgets/list/noBudget'); + $count = 0; + $loop = 0; + // grab journals, but be prepared to jump a period back to get the right ones: + Log::info('Now at no-budget loop start.'); + while ($count === 0 && $loop < 3) { + $loop++; + Log::info('Count is zero, search for journals.'); + /** @var JournalCollectorInterface $collector */ + $collector = app(JournalCollectorInterface::class); + $collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withoutBudget(); + $journals = $collector->getPaginatedJournals(); + $journals->setPath('/budgets/list/no-budget'); + $count = $journals->getCollection()->count(); + if ($count === 0) { + $start->subDay(); + $start = Navigation::startOfPeriod($start, $range); + $end = Navigation::endOfPeriod($start, $range); + Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d'))); + } + } - return view('budgets.no-budget', compact('journals', 'subTitle')); + return view('budgets.no-budget', compact('journals', 'subTitle', 'periods', 'start', 'end')); } /** @@ -405,7 +447,6 @@ class BudgetController extends Controller return $return; } - /** * @param Budget $budget * @param Carbon $start @@ -442,4 +483,47 @@ class BudgetController extends Controller return $set; } + /** + * @return Collection + */ + private function noBudgetPeriodEntries(): Collection + { + $repository = app(JournalRepositoryInterface::class); + $first = $repository->first(); + $start = $first->date ?? new Carbon; + $range = Preferences::get('viewRange', '1M')->data; + $start = Navigation::startOfPeriod($start, $range); + $end = Navigation::endOfX(new Carbon, $range); + $entries = new Collection; + + // properties for cache + $cache = new CacheProperties; + $cache->addProperty($start); + $cache->addProperty($end); + $cache->addProperty('no-budget-period-entries'); + + if ($cache->has()) { + return $cache->get(); // @codeCoverageIgnore + } + + Log::debug('Going to get period expenses and incomes.'); + while ($end >= $start) { + $end = Navigation::startOfPeriod($end, $range); + $currentEnd = Navigation::endOfPeriod($end, $range); + + // count journals without budget in this period: + /** @var JournalCollectorInterface $collector */ + $collector = app(JournalCollectorInterface::class); + $collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutBudget(); + $journals = $collector->getJournals()->count(); + $dateStr = $end->format('Y-m-d'); + $dateName = Navigation::periodShow($end, $range); + $entries->push([$dateStr, $dateName, $journals, clone $end]); + $end = Navigation::subtractPeriod($end, $range, 1); + } + $cache->store($entries); + + return $entries; + } + } diff --git a/resources/views/budgets/no-budget.twig b/resources/views/budgets/no-budget.twig index e8e1f0809b..83ef89391e 100644 --- a/resources/views/budgets/no-budget.twig +++ b/resources/views/budgets/no-budget.twig @@ -5,19 +5,73 @@ {% endblock %} {% block content %} + + {# upper show-all instruction #} + {% if periods.count > 0 %} +
+ +
+ {% endif %} +
-
+

{{ subTitle }}

-
+
{% include 'list.journals-tasker' with {'journals': journals} %} + {% if periods.count > 0 %} +

+ + {{ 'show_all_no_filter'|_ }} +

+ {% else %} +

+ + {{ 'show_the_current_period_and_overview'|_ }} +

+ {% endif %}
+ + {% if periods.count > 0 %} +
+ {% for entry in periods %} + {% if entry[2] > 0 %} +
+ +
+ + + + + +
{{ 'transactions'|_ }}{{ entry[2] }}
+
+
+ {% endif %} + {% endfor %} +
+ {% endif %} +
+ {# lower show-all instruction #} + {% if periods.count > 0 %} + + {% endif %} + {% endblock %} {% block scripts %} diff --git a/routes/web.php b/routes/web.php index 201351db87..36571253d9 100755 --- a/routes/web.php +++ b/routes/web.php @@ -144,7 +144,7 @@ Route::group( Route::get('delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'delete']); Route::get('show/{budget}', ['uses' => 'BudgetController@show', 'as' => 'show']); Route::get('show/{budget}/{budgetlimit}', ['uses' => 'BudgetController@showByBudgetLimit', 'as' => 'show.limit']); - Route::get('list/no-budget', ['uses' => 'BudgetController@noBudget', 'as' => 'no-budget']); + Route::get('list/no-budget/{moment?}', ['uses' => 'BudgetController@noBudget', 'as' => 'no-budget']); Route::post('income', ['uses' => 'BudgetController@postUpdateIncome', 'as' => 'income.post']); Route::post('store', ['uses' => 'BudgetController@store', 'as' => 'store']);