Fixed some bugs in various controllers and started rebuilding the category controller.

This commit is contained in:
Sander Dorigo 2014-11-10 19:03:03 +01:00
parent cb08df0770
commit af9473c126
13 changed files with 291 additions and 220 deletions

View File

@ -312,7 +312,7 @@ class AccountController extends BaseController
default:
throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"');
break;
case 'create_another':
case 'return_to_edit':
case 'store':
$messages = $acct->validate($data);
/** @var MessageBag $messages ['errors'] */

View File

@ -263,7 +263,7 @@ class BudgetController extends BaseController
default:
throw new FireflyException('Cannot handle post_submit_action "' . e(Input::get('post_submit_action')) . '"');
break;
case 'create_another':
case 'return_to_edit':
case 'update':
$messages = $repos->validate($data);
/** @var MessageBag $messages ['errors'] */
@ -277,7 +277,7 @@ class BudgetController extends BaseController
$repos->update($budget, $data);
Session::flash('success', 'Budget updated!');
if ($data['post_submit_action'] == 'create_another') {
if ($data['post_submit_action'] == 'return_to_edit') {
return Redirect::route('budgets.edit', $budget->id);
} else {
return Redirect::route('budgets.index');

View File

@ -1,26 +1,17 @@
<?php
use Firefly\Helper\Controllers\CategoryInterface as CI;
use Firefly\Storage\Category\CategoryRepositoryInterface as CRI;
use Firefly\Exception\FireflyException;
use Illuminate\Support\MessageBag;
/**
* Class CategoryController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class CategoryController extends BaseController
{
protected $_repository;
protected $_category;
/**
* @param CRI $repository
* @param CI $category
*
*/
public function __construct(CRI $repository, CI $category)
public function __construct()
{
$this->_repository = $repository;
$this->_category = $category;
View::share('title', 'Categories');
View::share('mainTitleIcon', 'fa-bar-chart');
}
@ -40,8 +31,7 @@ class CategoryController extends BaseController
*/
public function delete(Category $category)
{
return View::make('categories.delete')->with('category', $category)
->with('subTitle', 'Delete category "' . $category->name . '"');
return View::make('categories.delete')->with('category', $category)->with('subTitle', 'Delete category "' . $category->name . '"');
}
/**
@ -51,7 +41,10 @@ class CategoryController extends BaseController
*/
public function destroy(Category $category)
{
$this->_repository->destroy($category);
/** @var \FireflyIII\Database\Category $repos */
$repos = App::make('FireflyIII\Database\Category');
$repos->destroy($category);
Session::flash('success', 'The category was deleted.');
return Redirect::route('categories.index');
}
@ -72,10 +65,7 @@ class CategoryController extends BaseController
*/
public function index()
{
$categories = $this->_repository->get();
return View::make('categories.index')->with('categories', $categories)
->with('subTitle', 'All your categories');
return View::make('categories.index');
}
/**
@ -124,15 +114,40 @@ class CategoryController extends BaseController
*/
public function update(Category $category)
{
$category = $this->_repository->update($category, Input::all());
if ($category->validate()) {
Session::flash('success', 'Category "' . $category->name . '" updated.');
/** @var \FireflyIII\Database\Category $repos */
$repos = App::make('FireflyIII\Database\Category');
$data = Input::except('_token');
return Redirect::route('categories.index');
} else {
Session::flash('success', 'Could not update category "' . $category->name . '".');
switch (Input::get('post_submit_action')) {
default:
throw new FireflyException('Cannot handle post_submit_action "' . e(Input::get('post_submit_action')) . '"');
break;
case 'return_to_edit':
case 'update':
$messages = $repos->validate($data);
/** @var MessageBag $messages ['errors'] */
if ($messages['errors']->count() > 0) {
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('error', 'Could not save category: ' . $messages['errors']->first());
return Redirect::route('categories.edit', $category->id)->withInput()->withErrors($messages['errors']);
}
// store!
$repos->update($category, $data);
Session::flash('success', 'Category updated!');
return Redirect::route('categories.edit')->withErrors($category->errors())->withInput();
if ($data['post_submit_action'] == 'return_to_edit') {
return Redirect::route('categories.edit', $category->id);
} else {
return Redirect::route('categories.index');
}
case 'validate_only':
$messageBags = $repos->validate($data);
Session::flash('warnings', $messageBags['warnings']);
Session::flash('successes', $messageBags['successes']);
Session::flash('errors', $messageBags['errors']);
return Redirect::route('categories.edit', $category->id)->withInput();
break;
}

View File

@ -8,6 +8,38 @@ use Firefly\Exception\FireflyException;
class GoogleTableController extends BaseController
{
/**
* @return \Illuminate\Http\JsonResponse
*/
public function categoryList()
{
/** @var \FireflyIII\Database\Category $repos */
$repos = App::make('FireflyIII\Database\Category');
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('ID', 'number');
$chart->addColumn('ID_Edit', 'string');
$chart->addColumn('ID_Delete', 'string');
$chart->addColumn('Name_URL', 'string');
$chart->addColumn('Name', 'string');
$list = $repos->get();
/** @var Category $entry */
foreach ($list as $entry) {
$chart->addRow(
$entry->id, route('categories.edit', $entry->id), route('categories.delete', $entry->id), route('categories.show', $entry->id), $entry->name
);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param $what
*
@ -84,8 +116,8 @@ class GoogleTableController extends BaseController
if (is_null($repetition)) {
$journals = $budget->transactionjournals()->with(['budgets', 'categories', 'transactions', 'transactions.account'])->orderBy('date', 'DESC')->get();
} else {
$journals = $budget->transactionjournals()->with(['budgets', 'categories', 'transactions', 'transactions.account'])->
after($repetition->startdate)->before($repetition->enddate)->orderBy('date', 'DESC')->get();
$journals = $budget->transactionjournals()->with(['budgets', 'categories', 'transactions', 'transactions.account'])->after($repetition->startdate)
->before($repetition->enddate)->orderBy('date', 'DESC')->get();
}
/** @var TransactionJournal $transaction */
foreach ($journals as $journal) {

View File

@ -9,6 +9,7 @@ use Illuminate\Support\Collection;
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
use FireflyIII\Database\Ifaces\CUD;
use FireflyIII\Database\Ifaces\BudgetInterface;
/**
* Class Budget
*
@ -80,11 +81,11 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
$successes = new MessageBag;
$errors = new MessageBag;
if(isset($model['name'])) {
if(strlen($model['name']) < 1) {
if (isset($model['name'])) {
if (strlen($model['name']) < 1) {
$errors->add('name', 'Name is too short');
}
if(strlen($model['name']) > 200) {
if (strlen($model['name']) > 200) {
$errors->add('name', 'Name is too long');
}
@ -98,8 +99,8 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
}
if(!$errors->has('name')) {
$successes->add('name','OK');
if (!$errors->has('name')) {
$successes->add('name', 'OK');
}
return [
@ -118,7 +119,7 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
{
$data['user_id'] = $this->getUser()->id;
$budget = new \Budget($data);
$budget = new \Budget($data);
$budget->class = 'Budget';
if (!$budget->validate()) {
@ -155,10 +156,12 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
/**
* @param \Budget $budget
* @param Carbon $date
* @param Carbon $date
*
* @return float
*/
public function spentInMonth(\Budget $budget, Carbon $date) {
public function spentInMonth(\Budget $budget, Carbon $date)
{
$end = clone $date;
$date->startOfMonth();
$end->endOfMonth();
@ -220,7 +223,7 @@ class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
*/
public function update(Ardent $model, array $data)
{
$model->name = $data['name'];
$model->name = $data['name'];
if (!$model->validate()) {
var_dump($model->errors()->all());
exit;

View File

@ -2,6 +2,7 @@
namespace FireflyIII\Database;
use Carbon\Carbon;
use FireflyIII\Exception\NotImplementedException;
use Illuminate\Support\MessageBag;
use LaravelBook\Ardent\Ardent;
use Illuminate\Support\Collection;
@ -33,7 +34,8 @@ class Category implements CUD, CommonDatabaseCalls, CategoryInterface
*/
public function destroy(Ardent $model)
{
// TODO: Implement destroy() method.
$model->delete();
return true;
}
/**
@ -59,7 +61,37 @@ class Category implements CUD, CommonDatabaseCalls, CategoryInterface
*/
public function validate(array $model)
{
// TODO: Implement validate() method.
$warnings = new MessageBag;
$successes = new MessageBag;
$errors = new MessageBag;
if (isset($model['name'])) {
if (strlen($model['name']) < 1) {
$errors->add('name', 'Name is too short');
}
if (strlen($model['name']) > 200) {
$errors->add('name', 'Name is too long');
}
} else {
$errors->add('name', 'Name is mandatory');
}
$validator = \Validator::make($model, \Component::$rules);
if ($validator->invalid()) {
$errors->merge($validator->errors());
}
if (!$errors->has('name')) {
$successes->add('name', 'OK');
}
return [
'errors' => $errors,
'warnings' => $warnings,
'successes' => $successes
];
}
/**
@ -91,7 +123,7 @@ class Category implements CUD, CommonDatabaseCalls, CategoryInterface
*/
public function get()
{
// TODO: Implement get() method.
return $this->getUser()->categories()->orderBy('name', 'ASC')->get();
}
/**
@ -124,6 +156,15 @@ class Category implements CUD, CommonDatabaseCalls, CategoryInterface
*/
public function update(Ardent $model, array $data)
{
// TODO: Implement update() method.
$model->name = $data['name'];
if (!$model->validate()) {
var_dump($model->errors()->all());
exit;
}
$model->save();
return true;
}
}

View File

@ -174,6 +174,7 @@ Route::group(
// 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']);

View File

@ -1,13 +1,5 @@
@extends('layouts.default')
@section('content')
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<p class="lead">
Bla text here.
</p>
</div>
</div>
{{Form::model($account, ['class' => 'form-horizontal','url' => route('accounts.update',$account->id)])}}
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12">

View File

@ -40,7 +40,4 @@
<script src="assets/javascript/firefly/accounts.js"></script>
@stop
@section('styles')
@endsection
@stop

View File

@ -1,37 +1,31 @@
@extends('layouts.default')
@section('content')
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<p class="lead">
Remember that deleting something is permanent.
</p>
</div>
</div><!-- TODO cleanup to match new theme & form -->
{{Form::open(['class' => 'form-horizontal','url' => route('categories.destroy',$category->id)])}}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
@if($category->transactionjournals()->count() > 0)
<p class="text-info">
<div class="col-lg-6 col-md-12 col-sm-12">
<div class="panel panel-red">
<div class="panel-heading">
Delete category "{{{$category->name}}}"
</div>
<div class="panel-body">
<p>
Are you sure?
</p>
Account "{{{$category->name}}}" still has {{$category->transactionjournals()->count()}} transaction(s) associated to it.
These will NOT be deleted but will lose their connection to the category.
</p>
@endif
<p class="text-danger">
Press "Delete permanently" If you are sure you want to delete "{{{$category->name}}}".
</p>
<p>
<button type="submit" class="btn btn-default btn-danger">Delete permanently</button>
<a href="{{URL::previous()}}" class="btn-default btn">Cancel</a >
</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6">
<div class="form-group">
<div class="col-sm-8">
<button type="submit" class="btn btn-default btn-danger">Delete permanently</button>
<a href="{{route('categories.index')}}" class="btn-default btn">Cancel</a>
</div>
</div>
</div>

View File

@ -1,46 +1,37 @@
@extends('layouts.default')
@section('content')
{{Form::model($category, ['class' => 'form-horizontal','url' => route('categories.update',$category->id)])}}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<p class="lead">Use categories to group your expenses</p>
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-exclamation"></i> Mandatory fields
</div>
<div class="panel-body">
{{Form::ffText('name')}}
</div>
</div>
<p>
<button type="submit" class="btn btn-lg btn-success">
Update category
</button>
</p>
</div>
</div><!-- TODO cleanup to match new theme & form -->
{{Form::open(['class' => 'form-horizontal','url' => route('categories.update',$category->id)])}}
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-6">
<h4>Mandatory fields</h4>
<div class="form-group">
<label for="name" class="col-sm-4 control-label">Name</label>
<div class="col-sm-8">
<input type="text" name="name" class="form-control" id="name" value="{{Input::old('name') ?: $category->name}}" placeholder="Name">
@if($errors->has('name'))
<p class="text-danger">{{$errors->first('name')}}</p>
@else
<span class="help-block">For example: bike, utilities, daily groceries</span>
@endif
<!-- panel for options -->
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-bolt"></i> Options
</div>
<div class="panel-body">
{{Form::ffOptionsList('update','category')}}
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-6">
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<button type="submit" class="btn btn-default btn-success">Update the category</button>
</div>
</div>
</div>
</div>
{{Form::close()}}
@stop
@stop

View File

@ -2,37 +2,38 @@
@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>
<a href="{{route('categories.create')}}" class="btn btn-success"><span class="glyphicon glyphicon-plus"></span> Create a new category</a>
</p>
</div>
</div><!-- TODO cleanup to match new theme & form -->
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa {{{$mainTitleIcon}}}"></i> Categories
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<table class="table table-striped">
<tr>
</tr>
@foreach($categories as $category)
<tr>
<td>
<a href="{{route('categories.show',$category->id)}}">{{{$category->name}}}</a>
</td>
<td>
<div class="btn-group btn-group-xs">
<a href="{{route('categories.edit',$category->id)}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
<a href="{{route('categories.delete',$category->id)}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
<!-- ACTIONS MENU -->
<div class="pull-right">
<div class="btn-group">
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
Actions
<span class="caret"></span>
</button>
<ul class="dropdown-menu pull-right" role="menu">
<li><a href="{{route('categories.create')}}"><i class="fa fa-plus fa-fw"></i> New category</a></li>
</ul>
</div>
</td>
</tr>
@endforeach
</table>
</div>
</div>
<div class="panel-body">
<div id="category-list"></div>
</div>
</div>
</div>
</div>
@stop
@section('scripts')
<!-- 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')}}
<script src="assets/javascript/firefly/categories.js"></script>
@stop

View File

@ -1,90 +1,94 @@
$(function () {
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
if (typeof googleTable == 'function') {
googleTable('table/categories', 'category-list');
}
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: {
cursor: 'pointer',
negativeColor: '#FF0000',
threshold: 0,
lineWidth: 1,
marker: {
radius: 2
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
},
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
}
)
;
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
}
},
credits: {
enabled: false
}
};
$('#chart').highcharts(options);
});
}
};
$('#chart').highcharts(options);
});
}
});