A basic box for #786

This commit is contained in:
James Cole
2017-09-29 08:52:15 +02:00
parent aaac47ebfc
commit 76ed261441
8 changed files with 163 additions and 32 deletions

View File

@@ -245,6 +245,59 @@ class BudgetController extends Controller
); );
} }
/**
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function infoIncome(Carbon $start, Carbon $end)
{
// properties for cache
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('info-income');
if ($cache->has()) {
$result = $cache->get(); // @codeCoverageIgnore
}
if (!$cache->has()) {
$result = [
'available' => '0',
'earned' => '0',
'suggested' => '0',
];
$currency = Amount::getDefaultCurrency();
$range = Preferences::get('viewRange', '1M')->data;
$begin = Navigation::subtractPeriod($start, $range, 3);
// get average amount available.
$total = '0';
$count = 0;
$currentStart = clone $begin;
while ($currentStart < $start) {
$currentEnd = Navigation::endOfPeriod($currentStart, $range);
$total = bcadd($total, $this->repository->getAvailableBudget($currency, $currentStart, $currentEnd));
$currentStart = Navigation::addPeriod($currentStart, $range, 0);
$count++;
}
$result['available'] = bcdiv($total, strval($count));
// amount earned in this period:
$subDay = clone $end;
$subDay->subDay();
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($begin, $subDay)->setTypes([TransactionType::DEPOSIT])->withOpposingAccount();
$result['earned'] = bcdiv(strval($collector->getJournals()->sum('transaction_amount')),strval($count));
$cache->store($result);
}
return view('budgets.info', compact('result', 'begin', 'currentEnd'));
}
/** /**
* @param Request $request * @param Request $request
* @param JournalRepositoryInterface $repository * @param JournalRepositoryInterface $repository

View File

@@ -42,6 +42,7 @@ return [
'navigate_periods' => ['element' => '#periodNavigator'], 'navigate_periods' => ['element' => '#periodNavigator'],
'new_budget' => ['element' => '#createBudgetBox'], 'new_budget' => ['element' => '#createBudgetBox'],
'list_of_budgets' => ['element' => '#budgetList'], 'list_of_budgets' => ['element' => '#budgetList'],
'outro' => [],
], ],
// reports: index, default report, audit, budget, cat, tag // reports: index, default report, audit, budget, cat, tag

View File

@@ -10,6 +10,37 @@
/** global: spent, budgeted, available, currencySymbol, budgetIndexUri, updateIncomeUri, periodStart, periodEnd, budgetAmountUri, accounting */ /** global: spent, budgeted, available, currencySymbol, budgetIndexUri, updateIncomeUri, periodStart, periodEnd, budgetAmountUri, accounting */
/**
*
*/
$(function () {
"use strict";
$('.updateIncome').on('click', updateIncome);
$('.infoIncome').on('click', infoIncome);
/*
On start, fill the "spent"-bar using the content from the page.
*/
drawSpentBar();
drawBudgetedBar();
/*
When the input changes, update the percentages for the budgeted bar:
*/
$('input[type="number"]').on('input', updateBudgetedAmounts);
//
$('.selectPeriod').change(function (e) {
var sel = $(e.target).val();
if (sel !== "x") {
var newUri = budgetIndexUri.replace("REPLACE", sel);
window.location.assign(newUri);
}
});
});
function drawSpentBar() { function drawSpentBar() {
"use strict"; "use strict";
if ($('.spentBar').length > 0) { if ($('.spentBar').length > 0) {
@@ -55,6 +86,10 @@ function drawBudgetedBar() {
} }
} }
/**
*
* @param e
*/
function updateBudgetedAmounts(e) { function updateBudgetedAmounts(e) {
"use strict"; "use strict";
var target = $(e.target); var target = $(e.target);
@@ -90,7 +125,7 @@ function updateBudgetedAmounts(e) {
// send a post to Firefly to update the amount: // send a post to Firefly to update the amount:
var newUri = budgetAmountUri.replace("REPLACE", id); var newUri = budgetAmountUri.replace("REPLACE", id);
$.post(newUri, {amount: value,start: periodStart, end: periodEnd}).done(function (data) { $.post(newUri, {amount: value, start: periodStart, end: periodEnd}).done(function (data) {
// update the link if relevant: // update the link if relevant:
if (data.repetition > 0) { if (data.repetition > 0) {
$('.budget-link[data-id="' + id + '"]').attr('href', 'budgets/show/' + id + '/' + data.repetition); $('.budget-link[data-id="' + id + '"]').attr('href', 'budgets/show/' + id + '/' + data.repetition);
@@ -101,33 +136,10 @@ function updateBudgetedAmounts(e) {
} }
} }
$(function () { /**
"use strict"; *
* @returns {boolean}
$('.updateIncome').on('click', updateIncome); */
/*
On start, fill the "spent"-bar using the content from the page.
*/
drawSpentBar();
drawBudgetedBar();
/*
When the input changes, update the percentages for the budgeted bar:
*/
$('input[type="number"]').on('input', updateBudgetedAmounts);
//
$('.selectPeriod').change(function (e) {
var sel = $(e.target).val();
if (sel !== "x") {
var newUri = budgetIndexUri.replace("REPLACE", sel);
window.location.assign(newUri);
}
});
});
function updateIncome() { function updateIncome() {
"use strict"; "use strict";
$('#defaultModal').empty().load(updateIncomeUri, function () { $('#defaultModal').empty().load(updateIncomeUri, function () {
@@ -136,3 +148,11 @@ function updateIncome() {
return false; return false;
} }
function infoIncome() {
$('#defaultModal').empty().load(infoIncomeUri, function () {
$('#defaultModal').modal('show');
});
return false;
}

View File

@@ -532,6 +532,13 @@ return [
'update_budget' => 'Update budget', 'update_budget' => 'Update budget',
'update_budget_amount_range' => 'Update (expected) available amount between :start and :end', 'update_budget_amount_range' => 'Update (expected) available amount between :start and :end',
'budget_period_navigator' => 'Period navigator', 'budget_period_navigator' => 'Period navigator',
'info_on_available_amount' => 'What do I have available?',
'available_amount_indication' => 'Use these amounts to get an indication of what your total budget could be.',
'amount_budgeted' => 'Amount budgeted',
'amount_earned' => 'Amount earned',
'suggested' => 'Suggested',
'average_between' => 'Average between :start and :end',
// bills: // bills:
'matching_on' => 'Matching on', 'matching_on' => 'Matching on',

View File

@@ -31,6 +31,7 @@ return [
'budgets_index_navigate_periods' => 'Navigate through periods to easily set budgets ahead of time.', 'budgets_index_navigate_periods' => 'Navigate through periods to easily set budgets ahead of time.',
'budgets_index_new_budget' => 'Create new budgets as you see fit.', 'budgets_index_new_budget' => 'Create new budgets as you see fit.',
'budgets_index_list_of_budgets' => 'Use this table to set the amounts for each budget and see how you are doing.', 'budgets_index_list_of_budgets' => 'Use this table to set the amounts for each budget and see how you are doing.',
'budgets_index_outro' => 'To learn more about budgeting, checkout the help icon in the top right corner.',
// reports (index) // reports (index)
'reports_index_intro' => 'Use these reports to get detailed insights in your finances.', 'reports_index_intro' => 'Use these reports to get detailed insights in your finances.',

View File

@@ -16,10 +16,11 @@
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6"> <div class="col-lg-6 col-md-6 col-sm-6 col-xs-6">
<small>{{ 'budgeted'|_ }}: <span id="budgetedAmount" class="text-success">{{ budgeted|formatAmountPlain }}</span></small> <small>{{ 'budgeted'|_ }}: <span id="budgetedAmount" class="text-success">{{ budgeted|formatAmountPlain }}</span></small>
</div> </div>
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6" style="text-align:right;"> <div class="col-lg-6 col-md-6 col-sm-6 col-xs-6" style="text-align:right;margin-bottom:3px;">
<small id="availableBar">{{ trans('firefly.available_between',{start : periodStart, end: periodEnd }) }}: <small id="availableBar">{{ trans('firefly.available_between',{start : periodStart, end: periodEnd }) }}:
<a href="#" class="updateIncome"><span id="available" <span id="available" data-value="{{ available }}">{{ available|formatAmountPlain }}</span>
data-value="{{ available }}">{{ available|formatAmountPlain }}</span></a> <a href="#" class="updateIncome btn btn-default btn-xs"><i class="fa fa-pencil"></i></a>
<a href="#" class="infoIncome btn btn-info btn-xs"><i class="fa fa-info-circle"></i></a>
</small> </small>
</div> </div>
</div> </div>
@@ -232,6 +233,7 @@
var budgetIndexUri = "{{ route('budgets.index','REPLACE') }}"; var budgetIndexUri = "{{ route('budgets.index','REPLACE') }}";
var budgetAmountUri = "{{ route('budgets.amount','REPLACE') }}"; var budgetAmountUri = "{{ route('budgets.amount','REPLACE') }}";
var updateIncomeUri = "{{ route('budgets.income',[start.format('Y-m-d'),end.format('Y-m-d')]) }}"; var updateIncomeUri = "{{ route('budgets.income',[start.format('Y-m-d'),end.format('Y-m-d')]) }}";
var infoIncomeUri = "{{ route('budgets.income.info',[start.format('Y-m-d'),end.format('Y-m-d')]) }}";
var periodStart = "{{ start.format('Y-m-d') }}"; var periodStart = "{{ start.format('Y-m-d') }}";
var periodEnd = "{{ end.format('Y-m-d') }}"; var periodEnd = "{{ end.format('Y-m-d') }}";
</script> </script>

View File

@@ -0,0 +1,46 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>&times;</span><span class="sr-only">{{ 'close'|_ }}</span>
</button>
<h4 class="modal-title">
{{ trans('firefly.info_on_available_amount',
{start: start.formatLocalized(monthAndDayFormat), end: end.formatLocalized(monthAndDayFormat)}) }}
</h4>
</div>
<div class="modal-body">
<p>
{{ 'available_amount_indication'|_ }}
</p>
<table class="table table-bordered table-striped">
<tr>
<td>
{{ 'amount_budgeted'|_ }}
<small><br />
{{ trans('firefly.average_between', {start:begin.formatLocalized(monthAndDayFormat), end:currentEnd.formatLocalized(monthAndDayFormat)}) }}
</td>
<td>
<span class="pull-right">{{ result.available|formatAmount }}</span>
</td>
</tr>
<tr>
<td>{{ 'amount_earned'|_ }}
<small><br />
{{ trans('firefly.average_between', {start:begin.formatLocalized(monthAndDayFormat), end:currentEnd.formatLocalized(monthAndDayFormat)}) }}
</small>
</td>
<td><span class="pull-right">{{ result.earned|formatAmount }}</span></td>
</tr>
<tr>
<td><strong>{{ 'suggested'|_ }}</strong></td>
<td><span class="pull-right">{{ ((result.available + result.earned) / 2)|formatAmount }}</span></td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'close'|_ }}</button>
</div>
</div>
</div>

View File

@@ -140,7 +140,8 @@ Route::group(
Route::group( Route::group(
['middleware' => 'user-full-auth', 'prefix' => 'budgets', 'as' => 'budgets.'], function () { ['middleware' => 'user-full-auth', 'prefix' => 'budgets', 'as' => 'budgets.'], function () {
Route::get('income/{start_date}/{end_date}', ['uses' => 'BudgetController@updateIncome', 'as' => 'income']); Route::get('income/{start_date}/{end_date}', ['uses' => 'BudgetController@updateIncome', 'as' => 'income']);
Route::get('info/{start_date}/{end_date}', ['uses' => 'BudgetController@infoIncome', 'as' => 'income.info']);
Route::get('create', ['uses' => 'BudgetController@create', 'as' => 'create']); Route::get('create', ['uses' => 'BudgetController@create', 'as' => 'create']);
Route::get('edit/{budget}', ['uses' => 'BudgetController@edit', 'as' => 'edit']); Route::get('edit/{budget}', ['uses' => 'BudgetController@edit', 'as' => 'edit']);
Route::get('delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'delete']); Route::get('delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'delete']);