First attempt at unifying code for categories and budgets, which are basically the same thing.

This commit is contained in:
Sander Dorigo 2014-11-10 21:55:22 +01:00
parent af9473c126
commit 9fa326f630
11 changed files with 417 additions and 393 deletions

View File

@ -116,7 +116,7 @@ class BudgetController extends BaseController
$budgetAmount = $preferences->get('budgetIncomeTotal' . $date->format('FY'), 1000);
$amount = floatval($budgetAmount->data);
$overspent = $spent > $amount;
if($overspent) {
if ($overspent) {
// overspent on total amount
$spentPCT = ceil($amount / $spent * 100);
} else {
@ -124,7 +124,7 @@ class BudgetController extends BaseController
$spentPCT = ceil($spent / $amount * 100);
}
return View::make('budgets.index', compact('budgets','spent','spentPCT','overspent'))->with('budgetAmount', $budgetAmount);
return View::make('budgets.index', compact('budgets', 'spent', 'spentPCT', 'overspent'))->with('budgetAmount', $budgetAmount);
}
/**

View File

@ -75,15 +75,7 @@ class CategoryController extends BaseController
*/
public function show(Category $category)
{
$start = \Session::get('start');
$end = \Session::get('end');
$journals = $this->_category->journalsInRange($category, $start, $end);
return View::make('categories.show')->with('category', $category)->with('journals', $journals)->with(
'highlight', Input::get('highlight')
)->with('subTitle', 'Overview for category "' . $category->name . '"');
return View::make('categories.show', compact('category'));
}
/**

View File

@ -200,15 +200,26 @@ class GoogleChartController extends BaseController
return Response::json($chart->getData());
}
public function budgetsAndSpending(Budget $budget, $year) {
/**
* @param Component $component
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function componentsAndSpending(Component $component, $year) {
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
App::abort(500);
}
/** @var \FireflyIII\Database\Budget $bdt */
$bdt = App::make('FireflyIII\Database\Budget');
if($component->class == 'Budget') {
/** @var \FireflyIII\Database\Budget $repos */
$repos = App::make('FireflyIII\Database\Budget');
} else {
/** @var \FireflyIII\Database\Category $repos */
$repos = App::make('FireflyIII\Database\Category');
}
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
@ -220,12 +231,12 @@ class GoogleChartController extends BaseController
$end->endOfYear();
while($start <= $end) {
$spent = $bdt->spentInMonth($budget, $start);
$repetition = $bdt->repetitionOnStartingOnDate($budget, $start);
$spent = $repos->spentInMonth($component, $start);
$repetition = $repos->repetitionOnStartingOnDate($component, $start);
if($repetition) {
$budgeted = floatval($repetition->amount);
} else {
$budgeted = 0;
$budgeted = null;
}
$chart->addRow(clone $start, $budgeted, $spent);

View File

@ -90,10 +90,10 @@ class GoogleTableController extends BaseController
}
/**
* @param Budget $budget
* @param Component $component
* @param LimitRepetition $repetition
*/
public function transactionsByBudget(Budget $budget, LimitRepetition $repetition = null)
public function transactionsByComponent(Component $component, LimitRepetition $repetition = null)
{
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
@ -114,9 +114,12 @@ class GoogleTableController extends BaseController
$chart->addColumn('Category', 'string');
if (is_null($repetition)) {
$journals = $budget->transactionjournals()->with(['budgets', 'categories', 'transactions', 'transactions.account'])->orderBy('date', 'DESC')->get();
$journals = $component->transactionjournals()->with(['budgets', 'categories', 'transactions', 'transactions.account'])->orderBy('date', 'DESC')
->get();
} else {
$journals = $budget->transactionjournals()->with(['budgets', 'categories', 'transactions', 'transactions.account'])->after($repetition->startdate)
$journals = $component->transactionjournals()->with(['budgets', 'categories', 'transactions', 'transactions.account'])->after(
$repetition->startdate
)
->before($repetition->enddate)->orderBy('date', 'DESC')->get();
}
/** @var TransactionJournal $transaction */
@ -138,10 +141,10 @@ class GoogleTableController extends BaseController
}
if (isset($journal->budgets[0])) {
$budgetURL = route('budgets.show', $journal->budgets[0]->id);
$budget = $journal->budgets[0]->name;
$component = $journal->budgets[0]->name;
} else {
$budgetURL = '';
$budget = '';
$component = '';
}
if (isset($journal->categories[0])) {
@ -157,7 +160,7 @@ class GoogleTableController extends BaseController
$edit = route('transactions.edit', $journal->id);
$delete = route('transactions.delete', $journal->id);
$chart->addRow(
$id, $edit, $delete, $date, $descriptionURL, $description, $amount, $fromURL, $from, $toURL, $to, $budgetURL, $budget, $categoryURL,
$id, $edit, $delete, $date, $descriptionURL, $description, $amount, $fromURL, $from, $toURL, $to, $budgetURL, $component, $categoryURL,
$category
);
}

View File

@ -148,6 +148,32 @@ class Category implements CUD, CommonDatabaseCalls, CategoryInterface
// TODO: Implement findByWhat() method.
}
/**
* @param \Category $budget
* @param Carbon $date
*
* @return null
*/
public function repetitionOnStartingOnDate(\Category $category, Carbon $date)
{
return null;
}
/**
* @param \Category $category
* @param Carbon $date
*
* @return float
*/
public function spentInMonth(\Category $category, Carbon $date)
{
$end = clone $date;
$date->startOfMonth();
$end->endOfMonth();
$sum = floatval($category->transactionjournals()->before($end)->after($date)->lessThan(0)->sum('amount')) * -1;
return $sum;
}
/**
* @param Ardent $model
* @param array $data

View File

@ -50,6 +50,16 @@ Route::bind(
}
);
Route::bind(
'component', function ($value, $route) {
if (Auth::check()) {
return Component::
where('id', $value)->where('user_id', Auth::user()->id)->first();
}
return null;
}
);
Route::bind(
'reminder', function ($value, $route) {
if (Auth::check()) {
@ -169,13 +179,18 @@ Route::group(
Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']);
Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']);
Route::get('/chart/reports/budgets/{year}', ['uses' => 'GoogleChartController@budgetsReportChart']);
Route::get('/chart/budgets/{budget}/spending/{year}', ['uses' => 'GoogleChartController@budgetsAndSpending']);
// google chart (categories + budgets)
Route::get('/chart/component/{component}/spending/{year}', ['uses' => 'GoogleChartController@componentsAndSpending']);
// google table controller
Route::get('/table/account/{account}/transactions', ['uses' => 'GoogleTableController@transactionsByAccount']);
Route::get('/table/accounts/{what}', ['uses' => 'GoogleTableController@accountList']);
Route::get('/table/categories', ['uses' => 'GoogleTableController@categoryList']);
Route::get('/table/budget/{budget}/{limitrepetition?}/transactions', ['uses' => 'GoogleTableController@transactionsByBudget']);
// google table (categories + budgets)
Route::get('/table/component/{component}/{limitrepetition}/transactions', ['uses' => 'GoogleTableController@transactionsByComponent']);
Route::get('/chart/home/info/{accountnameA}/{day}/{month}/{year}', ['uses' => 'ChartController@homeAccountInfo', 'as' => 'chart.info']);

View File

@ -5,10 +5,10 @@
<div class="col-lg-9 col-md-9 col-sm-7">
<div class="panel panel-default">
<div class="panel-heading">
Some stuff?
Overview
</div>
<div class="panel-body">
<div id="budgetOverview"></div>
<div id="componentOverview"></div>
</div>
</div>
@ -73,7 +73,7 @@
@stop
@section('scripts')
<script type="text/javascript">
var budgetID = {{$budget->id}};
var componentID = {{$budget->id}};
@if(!is_null($repetition))
var repetitionID = {{$repetition->id}};
var year = {{$repetition->startdate->format('Y')}};

View File

@ -1,44 +1,43 @@
@extends('layouts.default')
@section('content')
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<p class="lead">Use categories to group your expenses</p>
<p class="text-info">
Use categories to group expenses by hobby, for certain types of groceries or what bills are for.
Expenses grouped in categories do not have to reoccur every month or every week, like budgets.
</p>
<p class="text-info">
This overview will show you the expenses you've made in each [period] and show you the actual
transactions for the currently selected period.
</p>
<div class="col-lg-9 col-md-9 col-sm-7">
<div class="panel panel-default">
<div class="panel-heading">
Overview
</div>
</div><!-- TODO cleanup to match new theme & form -->
@include('partials.date_nav')
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div id="chart"><img src="http://placehold.it/650x300" title="Placeholder" alt="" /></div>
<div class="panel-body">
<div id="componentOverview"></div>
</div>
</div>
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<h4>Transactions<small> in current range</small></h4>
@include('lists.transactions',['journals' => $journals,'sum' => true])
<div class="panel panel-default">
<div class="panel-heading">
Transactions
</div>
<div class="panel-body">
<div id="transactions"></div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-3 col-sm-5">
BLa bla something here.
</div>
</div>
@stop
@section('scripts')
<script type="text/javascript">
var categoryID = {{$category->id}};
var componentID = {{$category->id}};
var year = {{Session::get('start')->format('Y')}};
</script>
<!-- load the libraries and scripts necessary for Google Charts: -->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
{{HTML::script('assets/javascript/firefly/gcharts.options.js')}}
{{HTML::script('assets/javascript/firefly/gcharts.js')}}
{{HTML::script('assets/javascript/firefly/categories.js')}}
@stop

View File

@ -8,12 +8,15 @@ $(function () {
if (typeof(googleTable) == 'function') {
if (typeof budgetID != 'undefined' && typeof repetitionID == 'undefined') {
googleTable('table/budget/' + budgetID + '/0/transactions', 'transactions');
googleColumnChart('chart/budgets/'+budgetID+'/spending/2014','budgetOverview');
console.log('A');
if (typeof componentID != 'undefined' && typeof repetitionID == 'undefined') {
console.log('B');
googleTable('table/component/' + componentID + '/0/transactions', 'transactions');
googleColumnChart('chart/component/' + componentID + '/spending/' + year, 'componentOverview');
} else if (typeof budgetID != 'undefined' && typeof repetitionID != 'undefined') {
googleTable('table/budget/' + budgetID + '/' + repetitionID + '/transactions', 'transactions');
} else if (typeof componentID != 'undefined' && typeof repetitionID != 'undefined') {
console.log('C');
googleTable('table/component/' + componentID + '/' + repetitionID + '/transactions', 'transactions');
}
}
@ -162,7 +165,6 @@ function updateRanges() {
// we gaan er X overheen,
var pct = totalAmount / sum * 100;
console.log(pct)
var danger = 100 - pct;
var err = 100 - danger;
$('#progress-bar-default').css('width', 0);

View File

@ -2,93 +2,17 @@ $(function () {
if (typeof googleTable == 'function') {
googleTable('table/categories', 'category-list');
if (typeof(componentID) != 'undefined') {
googleTable('table/component/' + componentID + '/0/transactions','transactions');
if (typeof googleColumnChart == 'function') {
googleColumnChart('chart/component/' + componentID + '/spending/' + year, 'componentOverview');
}
if ($('#chart').length == 1) {
/**
* get data from controller for home charts:
*/
$.getJSON('chart/categories/show/' + categoryID).success(function (data) {
var options = {
chart: {
renderTo: 'chart',
type: 'column'
},
series: [data.series],
title: {
text: data.chart_title
},
yAxis: {
formatter: function () {
return '$' + Highcharts.numberFormat(this.y, 0);
}
},
subtitle: {
text: data.subtitle,
useHTML: true
},
}
xAxis: {
floor: 0,
type: 'category',
title: {
text: 'Period'
}
},
tooltip: {
shared: true,
crosshairs: false,
formatter: function () {
var str = '<span style="font-size:80%;">' + Highcharts.dateFormat("%A, %e %B", this.x) + '</span><br />';
for (x in this.points) {
var point = this.points[x];
var colour = point.point.pointAttr[''].fill;
str += '<span style="color:' + colour + '">' + point.series.name + '</span>: \u20AC ' + Highcharts.numberFormat(point.y, 2) + '<br />';
}
//console.log();
return str;
return '<span style="font-size:80%;">' + this.series.name + ' on ' + Highcharts.dateFormat("%e %B", this.x) + ':</span><br /> \u20AC ' + Highcharts.numberFormat(this.y, 2);
}
},
plotOptions: {
line: {
shadow: true
},
series: {
cursor: 'pointer',
negativeColor: '#FF0000',
threshold: 0,
lineWidth: 1,
marker: {
radius: 2
},
point: {
events: {
click: function (e) {
hs.htmlExpand(null, {
src: 'chart/home/info/' + this.series.name + '/' + Highcharts.dateFormat("%d/%m/%Y", this.x),
pageOrigin: {
x: e.pageX,
y: e.pageY
},
objectType: 'ajax',
headingText: '<a href="#">' + this.series.name + '</a>',
width: 250
}
)
;
}
}
}
}
},
credits: {
enabled: false
}
};
$('#chart').highcharts(options);
});
}
});

View File

@ -1,6 +1,7 @@
google.load('visualization', '1.1', {'packages': ['corechart', 'bar', 'sankey', 'table']});
function googleLineChart(URL, container) {
if ($('#' + container).length == 1) {
$.getJSON(URL).success(function (data) {
/*
Get the data from the JSON
@ -10,7 +11,11 @@ function googleLineChart(URL, container) {
/*
Format as money
*/
var money = new google.visualization.NumberFormat({decimalSymbol: ',', groupingSymbol: '.', prefix: '\u20AC '});
var money = new google.visualization.NumberFormat({
decimalSymbol: ',',
groupingSymbol: '.',
prefix: '\u20AC '
});
for (i = 1; i < gdata.getNumberOfColumns(); i++) {
money.format(gdata, i);
}
@ -28,9 +33,13 @@ function googleLineChart(URL, container) {
}).fail(function () {
$('#' + container).addClass('google-chart-error');
});
} else {
console.log('No container found called "' + container + '"');
}
}
function googleBarChart(URL, container) {
if ($('#' + container).length == 1) {
$.getJSON(URL).success(function (data) {
/*
Get the data from the JSON
@ -40,7 +49,11 @@ function googleBarChart(URL, container) {
/*
Format as money
*/
var money = new google.visualization.NumberFormat({decimalSymbol: ',', groupingSymbol: '.', prefix: '\u20AC '});
var money = new google.visualization.NumberFormat({
decimalSymbol: ',',
groupingSymbol: '.',
prefix: '\u20AC '
});
for (i = 1; i < gdata.getNumberOfColumns(); i++) {
money.format(gdata, i);
}
@ -58,9 +71,13 @@ function googleBarChart(URL, container) {
}).fail(function () {
$('#' + container).addClass('google-chart-error');
});
} else {
console.log('No container found called "' + container + '"');
}
}
function googleColumnChart(URL, container) {
if ($('#' + container).length == 1) {
$.getJSON(URL).success(function (data) {
/*
Get the data from the JSON
@ -70,7 +87,11 @@ function googleColumnChart(URL, container) {
/*
Format as money
*/
var money = new google.visualization.NumberFormat({decimalSymbol: ',', groupingSymbol: '.', prefix: '\u20AC '});
var money = new google.visualization.NumberFormat({
decimalSymbol: ',',
groupingSymbol: '.',
prefix: '\u20AC '
});
for (i = 1; i < gdata.getNumberOfColumns(); i++) {
money.format(gdata, i);
}
@ -87,9 +108,13 @@ function googleColumnChart(URL, container) {
}).fail(function () {
$('#' + container).addClass('google-chart-error');
});
} else {
console.log('No container found called "' + container + '"');
}
}
function googleStackedColumnChart(URL, container) {
if ($('#' + container).length == 1) {
$.getJSON(URL).success(function (data) {
/*
Get the data from the JSON
@ -99,7 +124,11 @@ function googleStackedColumnChart(URL, container) {
/*
Format as money
*/
var money = new google.visualization.NumberFormat({decimalSymbol: ',', groupingSymbol: '.', prefix: '\u20AC '});
var money = new google.visualization.NumberFormat({
decimalSymbol: ',',
groupingSymbol: '.',
prefix: '\u20AC '
});
for (i = 1; i < gdata.getNumberOfColumns(); i++) {
money.format(gdata, i);
}
@ -116,9 +145,13 @@ function googleStackedColumnChart(URL, container) {
}).fail(function () {
$('#' + container).addClass('google-chart-error');
});
} else {
console.log('No container found called "' + container + '"');
}
}
function googlePieChart(URL, container) {
if ($('#' + container).length == 1) {
$.getJSON(URL).success(function (data) {
/*
Get the data from the JSON
@ -128,7 +161,11 @@ function googlePieChart(URL, container) {
/*
Format as money
*/
var money = new google.visualization.NumberFormat({decimalSymbol: ',', groupingSymbol: '.', prefix: '\u20AC '});
var money = new google.visualization.NumberFormat({
decimalSymbol: ',',
groupingSymbol: '.',
prefix: '\u20AC '
});
for (i = 1; i < gdata.getNumberOfColumns(); i++) {
money.format(gdata, i);
}
@ -146,9 +183,13 @@ function googlePieChart(URL, container) {
}).fail(function () {
$('#' + container).addClass('google-chart-error');
});
} else {
console.log('No container found called "' + container + '"');
}
}
function googleSankeyChart(URL, container) {
if ($('#' + container).length == 1) {
$.getJSON(URL).success(function (data) {
/*
Get the data from the JSON
@ -184,9 +225,13 @@ function googleSankeyChart(URL, container) {
}).fail(function () {
$('#' + container).addClass('google-chart-error');
});
} else {
console.log('No container found called "' + container + '"');
}
}
function googleTable(URL, container) {
if ($('#' + container).length == 1) {
$.getJSON(URL).success(function (data) {
/*
Get the data from the JSON
@ -207,7 +252,11 @@ function googleTable(URL, container) {
var EditButtonFormatter = new google.visualization.PatternFormat('<div class="btn-group btn-group-xs"><a href="{0}" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-pencil"></span></a><a class="btn btn-xs btn-danger" href="{1}"><span class="glyphicon glyphicon-trash"></span></a></div>');
var money = new google.visualization.NumberFormat({decimalSymbol: ',', groupingSymbol: '.', prefix: '\u20AC '});
var money = new google.visualization.NumberFormat({
decimalSymbol: ',',
groupingSymbol: '.',
prefix: '\u20AC '
});
for (var i = 0; i < x; i++) {
@ -260,4 +309,7 @@ function googleTable(URL, container) {
}).fail(function () {
$('#' + container).addClass('google-chart-error');
});
} else {
console.log('No container found called "' + container + '"');
}
}