Cleanup budget view.

This commit is contained in:
James Cole 2015-05-24 22:54:59 +02:00
parent 8e1f493daf
commit 4a93bb35f8
3 changed files with 302 additions and 231 deletions

View File

@ -1,5 +1,6 @@
<?php namespace FireflyIII\Http\Controllers;
use Amount;
use Auth;
use Carbon\Carbon;
use FireflyIII\Http\Requests;
@ -45,6 +46,9 @@ class BudgetController extends Controller
$amount = intval(Input::get('amount'));
$date = Session::get('start', Carbon::now()->startOfMonth());
$limitRepetition = $repository->updateLimitAmount($budget, $date, $amount);
if ($amount == 0) {
$limitRepetition = null;
}
return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0]);
@ -126,7 +130,9 @@ class BudgetController extends Controller
{
$budgets = $repository->getActiveBudgets();
$inactive = $repository->getInactiveBudgets();
$spent = '0';
$budgeted = '0';
bcscale(2);
/**
* Do some cleanup:
*/
@ -134,24 +140,28 @@ class BudgetController extends Controller
// loop the budgets:
$budgets->each(
function (Budget $budget) use ($repository) {
/** @var Budget $budget */
foreach ($budgets as $budget) {
$date = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$budget->spent = $repository->spentInPeriodCorrected($budget, $date, $end);
$budget->currentRep = $repository->getCurrentRepetition($budget, $date);
if ($budget->currentRep) {
$budgeted = bcadd($budgeted, $budget->currentRep->amount);
}
$spent = bcadd($spent, $budget->spent);
}
);
$dateAsString = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
$spent = $budgets->sum('spent');
$amount = Preferences::get('budgetIncomeTotal' . $dateAsString, 1000)->data;
$overspent = $spent > $amount;
$spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100);
$budgetMax = Preferences::get('budgetMaximum', 1000);
$budgetMaximum = $budgetMax->data;
$budgetIncomeTotal = Preferences::get('budgetIncomeTotal' . $dateAsString, 1000)->data;
$spentPercentage = ($spent > $budgeted) ? ceil($budgeted / $spent * 100) : ceil($spent / $budgeted * 100);
$budgetMaximum = Preferences::get('budgetMaximum', 1000)->data;
$defaultCurrency = Amount::getDefaultCurrency();
return view('budgets.index', compact('budgetMaximum', 'inactive', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount'));
return view(
'budgets.index', compact('budgetMaximum', 'budgetIncomeTotal', 'defaultCurrency', 'inactive', 'budgets', 'spent', 'spentPercentage', 'budgeted')
);
}
/**

View File

@ -1,15 +1,101 @@
/* globals $, token, budgetID, repetitionID */
/* globals $, budgeted, currencySymbol, overspent, budgetIncomeTotal ,budgetedMuch, budgetedPercentage, token, budgetID, repetitionID, spent, budgeted, overspent, spentPercentage */
function drawSpentBar() {
"use strict";
if (overspent) {
// draw overspent bar
$('.spentBar .progress-bar-warning').css('width', spentPercentage + '%');
$('.spentBar .progress-bar-danger').css('width', (100 - spentPercentage) + '%');
} else {
// draw normal bar:
$('.spentBar .progress-bar-info').css('width', spentPercentage + '%');
}
}
function drawBudgetedBar() {
"use strict";
var budgetedMuch = budgeted > budgetIncomeTotal;
// recalculate percentage:
var pct;
if (budgetedMuch) {
// budgeted too much.
pct = (budgetIncomeTotal / budgeted) * 100;
console.log('Budgeted TOO much. Pct is ' + pct)
$('.budgetedBar .progress-bar-warning').css('width', pct + '%');
$('.budgetedBar .progress-bar-danger').css('width', (100 - pct) + '%');
$('.budgetedBar .progress-bar-info').css('width', 0);
} else {
pct = (budgeted / budgetIncomeTotal) * 100;
console.log('Not budgeted too much. Pct is ' + pct)
$('.budgetedBar .progress-bar-warning').css('width', 0);
$('.budgetedBar .progress-bar-danger').css('width', 0);
$('.budgetedBar .progress-bar-info').css('width', pct + '%');
}
$('#budgetedAmount').html(currencySymbol + ' ' + budgeted.toFixed(2));
}
function updateBudgetedAmounts(e) {
"use strict";
var target = $(e.target);
var id = target.data('id');
var value = target.val();
var original = target.data('original');
var difference = value - original;
if (difference !== 0) {
// add difference to 'budgeted' var
budgeted = budgeted + difference;
// update original:
target.data('original', value);
// run drawBudgetedBar() again:
drawBudgetedBar();
// send a post to Firefly to update the amount:
$.post('budgets/amount/' + id, {amount: value, _token: token}).success(function (data) {
// update the link if relevant:
if (data.repetition > 0) {
$('.budget-link[data-id="' + id + '"]').attr('href', 'budgets/show/' + id + '/' + data.repetition);
} else {
$('.budget-link[data-id="' + id + '"]').attr('href', 'budgets/show/' + id);
}
});
}
console.log('Budget id is ' + id);
console.log('Difference = ' + (value - original ));
}
$(function () {
"use strict";
updateRanges();
//$('input[type="range"]').change(updateSingleRange);
$('input[type="range"]').on('input', updateSingleRange);
//$('input[type="number"]').on('change', updateSingleRange);
$('input[type="number"]').on('input', updateSingleRange);
$('.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);
//updateRanges();
//$('input[type="range"]').on('input', updateSingleRange);
//$('input[type="number"]').on('input', updateSingleRange);
/*
Draw the charts, if necessary:
*/
if (typeof budgetID !== 'undefined' && typeof repetitionID === 'undefined') {
googleColumnChart('chart/budget/' + budgetID, 'budgetOverview');
}
@ -20,85 +106,85 @@ $(function () {
});
function updateSingleRange(e) {
"use strict";
// get some values:
var input = $(e.target);
var id = input.data('id');
var value = parseInt(input.val());
var spent = parseFloat($('#spent-' + id).data('value'));
// update small display:
if (value > 0) {
// show the input:
$('#budget-info-' + id + ' span').show();
$('#budget-info-' + id + ' input').show();
// update the text:
$('#budget-description-' + id).text('Budgeted: ');
} else {
// hide the input:
$('#budget-info-' + id + ' span').hide();
$('#budget-info-' + id + ' input').hide();
// update the text:
$('#budget-description-' + id).html('<em>No budget</em>');
}
// update the range display text:
$('#budget-range-display-' + id).text('\u20AC ' + value.toFixed(2));
// send a post to Firefly to update the amount:
$.post('budgets/amount/' + id, {amount: value, _token: token}).success(function (data) {
// update the link if relevant:
$('#budget-link-' + id).attr('href', 'budgets/show/' + id + '/' + data.repetition);
});
if (input.attr('type') === 'number') {
// update the range-input:
$('#budget-range-' + id).val(value);
} else {
// update the number-input:
$('#budget-info-' + id + ' input').val(value);
}
// update or hide the bar, whichever is necessary.
updateTotal();
return value;
}
function updateTotal() {
"use strict";
var sum = 0;
$('input[type="range"]').each(function (i, v) {
// get some values:
sum += parseInt($(v).val());
});
/**
* Update total sum:
*/
var totalAmount = parseInt($('#totalAmount').data('value'));
var pct;
if (sum <= totalAmount) {
pct = sum / totalAmount * 100;
$('#progress-bar-default').css('width', pct + '%');
$('#progress-bar-warning').css('width', '0');
$('#progress-bar-danger').css('width', '0');
$('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-success').removeClass('text-danger');
} else {
// we gaan er X overheen,
pct = totalAmount / sum * 100;
var danger = 100 - pct;
var err = 100 - danger;
$('#progress-bar-default').css('width', 0);
$('#progress-bar-warning').css('width', err + '%');
$('#progress-bar-danger').css('width', danger + '%');
$('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-danger').removeClass('text-success');
}
}
//function updateSingleRange(e) {
// "use strict";
// // get some values:
// var input = $(e.target);
// var id = input.data('id');
// var value = parseInt(input.val());
// var spent = parseFloat($('#spent-' + id).data('value'));
//
// // update small display:
// if (value > 0) {
// // show the input:
// $('#budget-info-' + id + ' span').show();
// $('#budget-info-' + id + ' input').show();
//
// // update the text:
// $('#budget-description-' + id).text('Budgeted: ');
// } else {
// // hide the input:
// $('#budget-info-' + id + ' span').hide();
// $('#budget-info-' + id + ' input').hide();
//
// // update the text:
// $('#budget-description-' + id).html('<em>No budget</em>');
// }
//
// // update the range display text:
// $('#budget-range-display-' + id).text('\u20AC ' + value.toFixed(2));
//
// // send a post to Firefly to update the amount:
// $.post('budgets/amount/' + id, {amount: value, _token: token}).success(function (data) {
// // update the link if relevant:
// $('#budget-link-' + id).attr('href', 'budgets/show/' + id + '/' + data.repetition);
// });
// if (input.attr('type') === 'number') {
// // update the range-input:
// $('#budget-range-' + id).val(value);
// } else {
// // update the number-input:
// $('#budget-info-' + id + ' input').val(value);
// }
//
// // update or hide the bar, whichever is necessary.
// updateTotal();
// return value;
//}
//
//function updateTotal() {
// "use strict";
// var sum = 0;
// $('input[type="range"]').each(function (i, v) {
// // get some values:
// sum += parseInt($(v).val());
// });
//
// /**
// * Update total sum:
// */
// var totalAmount = parseInt($('#totalAmount').data('value'));
// var pct;
// if (sum <= totalAmount) {
// pct = sum / totalAmount * 100;
// $('#progress-bar-default').css('width', pct + '%');
// $('#progress-bar-warning').css('width', '0');
// $('#progress-bar-danger').css('width', '0');
// $('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-success').removeClass('text-danger');
// } else {
// // we gaan er X overheen,
//
// pct = totalAmount / sum * 100;
// var danger = 100 - pct;
// var err = 100 - danger;
// $('#progress-bar-default').css('width', 0);
// $('#progress-bar-warning').css('width', err + '%');
// $('#progress-bar-danger').css('width', danger + '%');
// $('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-danger').removeClass('text-success');
// }
//
//}
//
function updateIncome() {
"use strict";
$('#monthlyBudgetModal').empty().load('budgets/income', function () {
@ -107,51 +193,51 @@ function updateIncome() {
return false;
}
function updateRanges() {
"use strict";
var sum = 0;
$('input[type="range"]').each(function (i, v) {
// get some values:
var input = $(v);
var id = input.data('id');
var value = parseInt(input.val());
// calculate sum:
sum += value;
// update small display:
$('#budget-range-display-' + id).text('\u20AC ' + value.toFixed(2));
// send a post to Firefly to update the amount:
$.post('budgets/amount/' + id, {amount: value, _token: token});
});
/**
* Update total sum:
*/
var totalAmount = parseInt($('#totalAmount').data('value'));
var pct;
if (sum <= totalAmount) {
pct = sum / totalAmount * 100;
$('#progress-bar-default').css('width', pct + '%');
$('#progress-bar-warning').css('width', '0');
$('#progress-bar-danger').css('width', '0');
$('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-success').removeClass('text-danger');
} else {
// we gaan er X overheen,
pct = totalAmount / sum * 100;
var danger = 100 - pct;
var err = 100 - danger;
$('#progress-bar-default').css('width', 0);
$('#progress-bar-warning').css('width', err + '%');
$('#progress-bar-danger').css('width', danger + '%');
$('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-danger').removeClass('text-success');
}
}
//
//function updateRanges() {
// "use strict";
//
//
// var sum = 0;
// $('input[type="range"]').each(function (i, v) {
// // get some values:
// var input = $(v);
// var id = input.data('id');
// var value = parseInt(input.val());
//
// // calculate sum:
// sum += value;
//
// // update small display:
// $('#budget-range-display-' + id).text('\u20AC ' + value.toFixed(2));
//
// // send a post to Firefly to update the amount:
// $.post('budgets/amount/' + id, {amount: value, _token: token});
//
// });
//
// /**
// * Update total sum:
// */
// var totalAmount = parseInt($('#totalAmount').data('value'));
// var pct;
// if (sum <= totalAmount) {
// pct = sum / totalAmount * 100;
// $('#progress-bar-default').css('width', pct + '%');
// $('#progress-bar-warning').css('width', '0');
// $('#progress-bar-danger').css('width', '0');
// $('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-success').removeClass('text-danger');
// } else {
// // we gaan er X overheen,
//
// pct = totalAmount / sum * 100;
// var danger = 100 - pct;
// var err = 100 - danger;
// $('#progress-bar-default').css('width', 0);
// $('#progress-bar-warning').css('width', err + '%');
// $('#progress-bar-danger').css('width', danger + '%');
// $('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-danger').removeClass('text-success');
// }
//
//
//}

View File

@ -11,23 +11,20 @@
<div class="panel-body">
<div class="row">
<div class="col-lg-6 col-md-4 col-sm-3">
<small>{{ 'budgeted'|_ }}: <span id="budgetedAmount" data-value="300"></span></small>
<small>{{ 'budgeted'|_ }}: <span id="budgetedAmount" class="text-success">{{ budgeted|formatAmountPlain }}</span></small>
</div>
<div class="col-lg-6 col-md-4 col-sm-3" style="text-align:right;">
<small>{{ trans('firefly.availableIn',{date : Session.get('start').formatLocalized(monthFormat) }) }}:
<a href="#" class="updateIncome"><span id="totalAmount" data-value="{{ amount }}">{{ amount|formatAmount }}</span></a></small>
<a href="#" class="updateIncome"><span id="budgetIncomeTotal" data-value="{{ budgetIncomeTotal }}">{{ budgetIncomeTotal|formatAmount }}</span></a></small>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="progress progress-striped">
<div class="progress-bar progress-bar-info" id="progress-bar-default" role="progressbar" aria-valuenow="0" aria-valuemin="0"
aria-valuemax="100" style="width: 0;"></div>
<div class="progress-bar progress-bar-danger" id="progress-bar-danger" role="progressbar" aria-valuenow="0" aria-valuemin="0"
aria-valuemax="100" style="width: 0;"></div>
<div class="progress-bar progress-bar-warning" id="progress-bar-warning" role="progressbar" aria-valuenow="10" aria-valuemin="0"
aria-valuemax="100" style="width: 0;"></div>
<div class="progress progress-striped budgetedBar">
<div class="progress-bar progress-bar-danger" id="progress-bar-danger" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0;"></div>
<div class="progress-bar progress-bar-warning" id="progress-bar-warning" role="progressbar" aria-valuenow="10" aria-valuemin="0" aria-valuemax="100" style="width: 0;"></div>
<div class="progress-bar progress-bar-info" id="progress-bar-default" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0;"></div>
</div>
</div>
</div>
@ -38,16 +35,10 @@
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="progress progress-striped">
{% if overspent %}
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="{{ spentPCT }}" aria-valuemin="0"
aria-valuemax="100" style="width: {{ spentPCT }}%;"></div>
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="{{ 100-spentPCT }}" aria-valuemin="0"
aria-valuemax="100" style="width: {{ 100-spentPCT }}%;"></div>
{% else %}
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="{{ spentPCT }}" aria-valuemin="0"
aria-valuemax="100" style="width: {{ spentPCT }}%;"></div>
{% endif %}
<div class="progress progress-striped spentBar">
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0;"></div>
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0;"></div>
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0;"></div>
</div>
</div>
</div>
@ -80,10 +71,11 @@
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-fw fa-tasks"></i>
<!-- link in header -->
{% if budget.currentRep %}
<a href="{{ route('budgets.show', [budget.id, budget.currentRep.id]) }}" id="budget-link-{{ budget.id }}">{{ budget.name }}</a>
<a href="{{ route('budgets.show', [budget.id, budget.currentRep.id]) }}" class="budget-link" data-id="{{ budget.id }}">{{ budget.name }}</a>
{% else %}
<a href="{{ route('budgets.show',budget.id) }}" id="budget-link-{{ budget.id }}">{{ budget.name }}</a>
<a href="{{ route('budgets.show',budget.id) }}" class="budget-link" data-id="{{ budget.id }}">{{ budget.name }}</a>
{% endif %}
@ -100,55 +92,26 @@
</ul>
</div>
</div>
</div>
<div class="panel-body">
<!-- the range in which the budget can be set -->
<p>
{% if budget.currentRep %}
<input type="range" data-id="{{ budget.id }}" data-spent="{{ budget.spent }}" id="budget-range-{{ budget.id }}"
max="{{ budgetMaximum }}" min="0" value="{{ budget.currentRep.amount }}"/>
{% else %}
<input type="range" data-id="{{ budget.id }}" data-spent="{{ budget.spent }}" id="budget-range-{{ budget.id }}"
max="{{ budgetMaximum }}" min="0" value="0"/>
{% endif %}
</p>
<!-- some textual info about the budget. Updates dynamically. -->
<p>
<!-- budget-holder-X holds all the elements -->
<span id="budget-holder-{{ budget.id }}">
{% if budget.currentRep %}
<!-- budget-description-X holds the description. -->
<span id="budget-description-{{ budget.id }}">Budgeted: </span>
<!-- budget-info-X holds the input and the euro-sign: -->
<span id="budget-info-{{ budget.id }}">
{% if budget.currentRep.amount > budget.spent %}
<span class="text-success">{{ getCurrencySymbol()|raw }}</span> <input type="number" min="0" max="{{ budgetMaximum }}" data-id="{{ budget.id }}"
step="1" value="{{ budget.currentRep.amount }}"
style="width:90px;color:#3c763d;"/>
{% else %}
<span class="text-danger">{{ getCurrencySymbol()|raw }}</span> <input type="number" min="0" max="{{ budgetMaximum }}" data-id="{{ budget.id }}"
step="1" value="{{ budget.currentRep.amount }}"
style="width:90px;color:#a94442;"/>
{% endif %}
</span>
{% else %}
<span id="budget-description-{{ budget.id }}"><em>No budget</em></span>
<span id="budget-info-{{ budget.id }}">
<span class="text-success" style="display:none;">{{ getCurrencySymbol()|raw }}</span> <input data-id="{{ budget.id }}" type="number"
min="0" max="{{ budgetMaximum }}" step="1"
value="0"
style="width:50px;color:#3c763d;display:none;"/>
</span>
{% endif %}
</span>
</p>
<p>
<span id="spent-{{ budget.id }}" data-value="{{ budget.spent }}">{{ 'spent'|_ }}: {{ budget.spent|formatAmount }}</span>
</p>
<table class="table">
<tr>
<td style="width:40%;">{{ 'budgeted'|_ }}</td>
<td>
<div class="form-group" style="margin-bottom:0;">
<div class="input-group">
<div class="input-group-addon">{{ defaultCurrency.symbol|raw }}</div>
<input type="hidden" name="balance_currency_id" value="1" />
<input class="form-control budgetAmount" data-original="{{ budget.currentRep.amount|number_format(0,'','') }}" data-id="{{ budget.id }}" value="{{ budget.currentRep.amount|number_format(0,'','') }}" autocomplete="off" step="1" min="0" max="{{ budgetMaximum }}" name="amount" type="number">
</div>
</div>
</td>
</tr>
<tr>
<td style="width:50%;">{{ 'spent'|_ }}</td>
<td>{{ budget.spent|formatAmount }}</td>
</tr>
</table>
</div>
</div>
{% endfor %}
<div class="col-lg-3 col-sm-4 col-md-6">
@ -191,5 +154,17 @@
{% endblock %}
{% block scripts %}
<script type="text/javascript">
// actually spent bar data:
var spent = {{ spent }};
var overspent = {{ spent }} > {{ budgeted }};
var spentPercentage = {{ spentPercentage }};
var currencySymbol = "{{ getCurrencySymbol()|raw }}";
// budgeted data:
var budgeted = {{ budgeted }};
var budgetIncomeTotal = {{ budgetIncomeTotal }};
</script>
<script type="text/javascript" src="js/budgets.js"></script>
{% endblock %}