Initial code for #595, transactions with no budget

This commit is contained in:
James Cole 2017-03-09 20:54:18 +01:00
parent 0e59f7433c
commit 61007a95a6
No known key found for this signature in database
GPG Key ID: C16961E655E74B5E
3 changed files with 158 additions and 20 deletions

View File

@ -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());
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
// 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();
}
// collector
// 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);
$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/noBudget');
$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;
}
}

View File

@ -5,18 +5,72 @@
{% endblock %}
{% block content %}
{# upper show-all instruction #}
{% if periods.count > 0 %}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="col-lg-offset-10 col-lg-2 col-md-offset-10 col-md-2 col-sm-12 col-xs-12">
<p class="small text-center"><a href="{{ route('budgets.no-budget',['all']) }}">{{ 'showEverything'|_ }}</a></p>
</div>
</div>
{% endif %}
<div class="row">
<div class="{% if periods.count > 0 %}col-lg-10 col-md-10 col-sm-12{% else %}col-lg-12 col-md-12 col-sm-12{% endif %}">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ subTitle }}</h3>
</div>
<div class="box-body ">
{% include 'list.journals-tasker' with {'journals': journals} %}
{% if periods.count > 0 %}
<p>
<i class="fa fa-calendar" aria-hidden="true"></i>
<a href="{{ route('budgets.no-budget', ['all']) }}">{{ 'show_all_no_filter'|_ }}</a>
</p>
{% else %}
<p>
<i class="fa fa-calendar" aria-hidden="true"></i>
<a href="{{ route('budgets.no-budget') }}">{{ 'show_the_current_period_and_overview'|_ }}</a>
</p>
{% endif %}
</div>
</div>
</div>
{% if periods.count > 0 %}
<div class="col-lg-2 col-md-2 col-sm-12 col-xs-12">
{% for entry in periods %}
{% if entry[2] > 0 %}
<div class="box {% if entry[3] == start %}box-solid box-primary{% endif %}">
<div class="box-header with-border">
<h3 class="box-title"><a href="{{ route('budgets.no-budget',[entry[0]]) }}">{{ entry[1] }}</a>
</h3>
</div>
<div class="box-body no-padding">
<table class="table table-hover">
<tr>
<td style="width:33%;">{{ 'transactions'|_ }}</td>
<td style="text-align: right;">{{ entry[2] }}</td>
</tr>
</table>
</div>
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
</div>
{# lower show-all instruction #}
{% if periods.count > 0 %}
<div class="row">
<div class="col-lg-offset-10 col-lg-2 col-md-offset-10 col-md-2 col-sm-12 col-xs-12">
<p class="small text-center"><a href="{{ route('budgets.no-budget',['all']) }}">{{ 'showEverything'|_ }}</a></p>
</div>
</div>
{% endif %}
{% endblock %}
{% block scripts %}

View File

@ -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']);