Add and remove transactions.

This commit is contained in:
James Cole 2015-02-24 22:53:38 +01:00
parent 5b9c2cdc13
commit d83b508bbc
15 changed files with 398 additions and 33 deletions

View File

@ -5,9 +5,12 @@ use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\CategoryFormRequest; use FireflyIII\Http\Requests\CategoryFormRequest;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator;
use Redirect; use Redirect;
use Session; use Session;
use View; use View;
use Input;
/** /**
* Class CategoryController * Class CategoryController
@ -17,6 +20,9 @@ use View;
class CategoryController extends Controller class CategoryController extends Controller
{ {
/**
*
*/
public function __construct() public function __construct()
{ {
View::share('title', 'Categories'); View::share('title', 'Categories');
@ -31,6 +37,24 @@ class CategoryController extends Controller
return view('categories.create')->with('subTitle', 'Create a new category'); return view('categories.create')->with('subTitle', 'Create a new category');
} }
/**
* @param Category $category
*
* @return $this
*/
public function show(Category $category, CategoryRepositoryInterface $repository)
{
$hideCategory = true; // used in list.
$page = intval(Input::get('page'));
$offset = $page > 0 ? $page * 50 : 0;
$set = $category->transactionJournals()->withRelevantData()->take(50)->offset($offset)->orderBy('date', 'DESC')->get(['transaction_journals.*']);
$count = $category->transactionJournals()->count();
$journals = new LengthAwarePaginator($set, $count, 50, $page);
return view('categories.show', compact('category', 'journals', 'hideCategory'));
}
/** /**
* @param Category $category * @param Category $category
* *

View File

@ -12,6 +12,7 @@ use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Grumpydictator\Gchart\GChart; use Grumpydictator\Gchart\GChart;
use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\Builder as QueryBuilder;
@ -30,6 +31,49 @@ class GoogleChartController extends Controller
{ {
/**
*
* @param Category $category
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function categoriesAndSpending(Category $category, $year, GChart $chart)
{
try {
new Carbon('01-01-' . $year);
} catch (Exception $e) {
return view('error')->with('message', 'Invalid year.');
}
$chart->addColumn('Month', 'date');
$chart->addColumn('Budgeted', 'number');
$chart->addColumn('Spent', 'number');
$start = new Carbon('01-01-' . $year);
$end = clone $start;
$end->endOfYear();
while ($start <= $end) {
$currentEnd = clone $start;
$currentEnd->endOfMonth();
$spent = floatval($category->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
$budgeted = null;
$chart->addRow(clone $start, $budgeted, $spent);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/** /**
* @param Account $account * @param Account $account
* @param string $view * @param string $view

View File

@ -0,0 +1,68 @@
<?php namespace FireflyIII\Http\Controllers;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Response;
use Auth;
/**
* Class JsonController
*
* @package FireflyIII\Http\Controllers
*/
class JsonController extends Controller {
/**
* Returns a list of categories.
*
* @return \Illuminate\Http\JsonResponse
*/
public function categories()
{
$list = Auth::user()->categories()->orderBy('name','ASC')->get();
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
}
return Response::json($return);
}
/**
* Returns a JSON list of all beneficiaries.
*
* @return \Illuminate\Http\JsonResponse
*/
public function expenseAccounts()
{
$list = Auth::user()->accounts()->accountTypeIn(['Expense account', 'Beneficiary account'])->get();
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
}
return Response::json($return);
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function revenueAccounts()
{
$list = Auth::user()->accounts()->accountTypeIn(['Revenue account'])->get();
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
}
return Response::json($return);
}
}

View File

@ -64,7 +64,7 @@ class PiggyBankController extends Controller {
} }
} }
return View::make('piggy-banks.index', compact('piggyBanks', 'accounts')); return view('piggy-banks.index', compact('piggyBanks', 'accounts'));
} }
} }

View File

@ -102,7 +102,7 @@ class ReportController extends Controller
* End getBudgetsForMonth DONE * End getBudgetsForMonth DONE
*/ */
return View::make('reports.budget', compact('subTitle', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly')); return view('reports.budget', compact('subTitle', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly'));
} }
@ -239,7 +239,7 @@ class ReportController extends Controller
*/ */
return View::make( return view(
'reports.month', 'reports.month',
compact( compact(
'income', 'expenses', 'budgets', 'accounts', 'categories', 'income', 'expenses', 'budgets', 'accounts', 'categories',
@ -258,7 +258,7 @@ class ReportController extends Controller
try { try {
new Carbon('01-01-' . $year); new Carbon('01-01-' . $year);
} catch (Exception $e) { } catch (Exception $e) {
return View::make('error')->with('message', 'Invalid date.'); return view('error')->with('message', 'Invalid date.');
} }
$date = new Carbon('01-01-' . $year); $date = new Carbon('01-01-' . $year);
$end = clone $date; $end = clone $date;
@ -273,7 +273,7 @@ class ReportController extends Controller
//$groupedExpenses = $helper-> expensesGroupedByAccount($date, $end, 15); //$groupedExpenses = $helper-> expensesGroupedByAccount($date, $end, 15);
return View::make( return view(
'reports.year', compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon') 'reports.year', compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon')
); );
} }

View File

@ -1,14 +1,17 @@
<?php namespace FireflyIII\Http\Controllers; <?php namespace FireflyIII\Http\Controllers;
use Auth; use Auth;
use Carbon\Carbon;
use ExpandedForm; use ExpandedForm;
use FireflyIII\Http\Requests; use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\JournalFormRequest;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Input; use Input;
use Redirect;
use Session; use Session;
use View; use View;
/** /**
* Class TransactionController * Class TransactionController
* *
@ -34,7 +37,7 @@ class TransactionController extends Controller
public function create($what = 'deposit') public function create($what = 'deposit')
{ {
$accounts = ExpandedForm::makeSelectList( $accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->where('active', 1)->orderBy('name', 'DESC')->get() Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->where('active', 1)->orderBy('name', 'DESC')->get(['accounts.*'])
); );
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get()); $budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = '(no budget)'; $budgets[0] = '(no budget)';
@ -98,7 +101,34 @@ class TransactionController extends Controller
$journals = new LengthAwarePaginator($set, $count, 50, $page); $journals = new LengthAwarePaginator($set, $count, 50, $page);
$journals->setPath('transactions/' . $what); $journals->setPath('transactions/' . $what);
return View::make('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals')); return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals'));
}
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository)
{
$journalData = [
'what' => $request->get('what'),
'description' => $request->get('description'),
'account_id' => intval($request->get('account_id')),
'account_from_id' => intval($request->get('account_from_id')),
'account_to_id' => intval($request->get('account_to_id')),
'expense_account' => $request->get('expense_account'),
'revenue_account' => $request->get('revenue_account'),
'amount' => floatval($request->get('amount')),
'user' => Auth::user()->id,
'amount_currency_id' => intval($request->get('amount_currency_id')),
'date' => new Carbon($request->get('date')),
'budget_id' => intval($request->get('budget_id')),
'category' => $request->get('category'),
];
$journal = $repository->store($journalData);
Session::flash('success', 'New transaction "' . $journal->description . '" stored!');
return Redirect::route('transactions.index', $request->input('what'));
} }

View File

@ -0,0 +1,72 @@
<?php
namespace FireflyIII\Http\Requests;
use Auth;
use FireflyIII\Models\Account;
use Input;
/**
* Class JournalFormRequest
*
* @package FireflyIII\Http\Requests
*/
class JournalFormRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
// can we switch on the "what"?
$what = Input::get('what');
$rules = [
'description' => 'required|min:1,max:255',
'what' => 'required|in:withdrawal,deposit,transfer|exists:transaction_types,type',
'amount' => 'numeric|required|min:0.01',
'date' => 'required|date',
'amount_currency_id' => 'required|exists:transaction_currencies,id',
];
switch ($what) {
case 'withdrawal':
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
$rules['expense_account'] = 'between:1,255';
$rules['category'] = 'between:1,255';
if (intval(Input::get('budget_id')) != 0) {
$rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets';
}
break;
case 'deposit':
$rules['category'] = 'between:1,255';
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
$rules['revenue_account'] = 'between:1,255';
break;
case 'transfer':
$rules['account_from_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_to_id';
$rules['account_to_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_from_id';
$rules['category'] = 'between:1,255';
break;
default:
die('Cannot handle ' . $what);
break;
}
return $rules;
}
}

View File

@ -151,11 +151,17 @@ Route::group(
Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']); Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']);
Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending']); Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending']);
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']); Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']);
Route::get('/chart/category/{category}/spending/{year}', ['uses' => 'GoogleChartController@categoriesAndSpending']);
Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']); 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/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']);
//Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']); //Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']);
// JSON controller
Route::get('/json/expense-accounts', ['uses' => 'JsonController@expenseAccounts', 'as' => 'json.expense-accounts']);
Route::get('/json/revenue-accounts', ['uses' => 'JsonController@revenueAccounts', 'as' => 'json.revenue-accounts']);
Route::get('/json/categories', ['uses' => 'JsonController@categories', 'as' => 'json.categories']);
/** /**
* Piggy Bank Controller * Piggy Bank Controller

View File

@ -2,6 +2,14 @@
namespace FireflyIII\Repositories\Journal; namespace FireflyIII\Repositories\Journal;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
/** /**
* Class JournalRepository * Class JournalRepository
* *
@ -10,4 +18,97 @@ namespace FireflyIII\Repositories\Journal;
class JournalRepository implements JournalRepositoryInterface class JournalRepository implements JournalRepositoryInterface
{ {
/**
* @param array $data
*
* @return TransactionJournal
*/
public function store(array $data)
{
// find transaction type.
$transactionType = TransactionType::where('type', ucfirst($data['what']))->first();
// store actual journal.
$journal = new TransactionJournal(
[
'user_id' => $data['user'],
'transaction_type_id' => $transactionType->id,
'transaction_currency_id' => $data['amount_currency_id'],
'description' => $data['description'],
'completed' => 0,
'date' => $data['date'],
]
);
$journal->save();
// store or get category
if (strlen($data['category']) > 0) {
$category = Category::firstOrCreate(['name' => $data['category'], 'user_id' => $data['user']]);
$journal->categories()->save($category);
}
// store or get budget
if (intval($data['budget_id']) > 0) {
$budget = Budget::find($data['budget_id']);
$journal->budgets()->save($budget);
}
// store accounts (depends on type)
switch ($transactionType->type) {
case 'Withdrawal':
$from = Account::find($data['account_id']);
if (strlen($data['expense_account']) > 0) {
$toType = AccountType::where('type', 'Expense account')->first();
$to = Account::firstOrCreate(
['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => $data['expense_account'], 'active' => 1]
);
} else {
$toType = AccountType::where('type', 'Cash account')->first();
$to = Account::firstOrCreate(['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => 'Cash account', 'active' => 1]);
}
break;
case 'Deposit':
$to = Account::find($data['account_id']);
if (strlen($data['revenue_account']) > 0) {
$fromType = AccountType::where('type', 'Revenue account')->first();
$from = Account::firstOrCreate(
['user_id' => $data['user'], 'account_type_id' => $fromType->id, 'name' => $data['revenue_account'], 'active' => 1]
);
} else {
$toType = AccountType::where('type', 'Cash account')->first();
$from = Account::firstOrCreate(['user_id' => $data['user'], 'account_type_id' => $toType->id, 'name' => 'Cash account', 'active' => 1]);
}
break;
case 'Transfer':
$from = Account::find($data['account_from_id']);
$to = Account::find($data['account_to_id']);
break;
}
// store accompanying transactions.
Transaction::create( // first transaction.
[
'account_id' => $from->id,
'transaction_journal_id' => $journal->id,
'amount' => $data['amount'] * -1
]
);
Transaction::create( // second transaction.
[
'account_id' => $to->id,
'transaction_journal_id' => $journal->id,
'amount' => $data['amount']
]
);
return $journal;
}
} }

View File

@ -1,13 +1,8 @@
<?php <?php
/**
* Created by PhpStorm.
* User: sander
* Date: 08/02/15
* Time: 18:15
*/
namespace FireflyIII\Repositories\Journal; namespace FireflyIII\Repositories\Journal;
use FireflyIII\Models\TransactionJournal;
/** /**
* Interface JournalRepositoryInterface * Interface JournalRepositoryInterface
@ -16,5 +11,11 @@ namespace FireflyIII\Repositories\Journal;
*/ */
interface JournalRepositoryInterface interface JournalRepositoryInterface
{ {
/**
* @param array $data
*
* @return TransactionJournal
*/
public function store(array $data);
} }

View File

@ -218,7 +218,6 @@ class ExpandedForm
$selectList[$id] = $title; $selectList[$id] = $title;
} }
return $selectList; return $selectList;
} }

View File

@ -2,6 +2,7 @@
namespace FireflyIII\Validation; namespace FireflyIII\Validation;
use Auth;
use DB; use DB;
use Illuminate\Validation\Validator; use Illuminate\Validation\Validator;
@ -13,6 +14,24 @@ use Illuminate\Validation\Validator;
class FireflyValidator extends Validator class FireflyValidator extends Validator
{ {
/**
* @param $attribute
* @param $value
* @param $parameters
*
* @return bool
*/
public function validateBelongsToUser($attribute, $value, $parameters)
{
$count = DB::table($parameters[0])->where('user_id', Auth::user()->id)->where('id', $value)->count();
if ($count == 1) {
return true;
}
return false;
}
/** /**
* @param $attribute * @param $attribute
* @param $value * @param $value

View File

@ -1,6 +1,6 @@
@extends('layouts.default') @extends('layouts.default')
@section('content') @section('content')
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $category) }} {!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $category) !!}
<div class="row"> <div class="row">
<div class="col-lg-9 col-md-9 col-sm-7"> <div class="col-lg-9 col-md-9 col-sm-7">
<div class="panel panel-default"> <div class="panel panel-default">
@ -22,7 +22,7 @@
</div> </div>
</div> </div>
<div class="col-lg-3 col-md-3 col-sm-5"> <div class="col-lg-3 col-md-3 col-sm-5">
BLa bla something here. (TODO)
</div> </div>
</div> </div>
@ -35,8 +35,8 @@
</script> </script>
<!-- load the libraries and scripts necessary for Google Charts: --> <!-- load the libraries and scripts necessary for Google Charts: -->
<script type="text/javascript" src="https://www.google.com/jsapi"></script> <script type="text/javascript" src="https://www.google.com/jsapi"></script>
{{HTML::script('assets/javascript/firefly/gcharts.options.js')}} <script type="text/javascript" src="js/gcharts.options.js"></script>
{{HTML::script('assets/javascript/firefly/gcharts.js')}} <script type="text/javascript" src="js/gcharts.js"></script>
{{HTML::script('assets/javascript/firefly/categories.js')}} <script type="text/javascript" src="js/categories.js"></script>
@stop @stop

View File

@ -12,11 +12,11 @@
@endforeach @endforeach
</ul> </ul>
</div> </div>
{{Form::input('number', $name, $value, $options)}} {!! Form::input('number', $name, $value, $options) !!}
</div> </div>
@include('form.feedback') @include('form.feedback')
</div> </div>
{{Form::input('hidden','amount_currency_id',$defaultCurrency->id)}} {!! Form::input('hidden','amount_currency_id',$defaultCurrency->id) !!}
</div> </div>

View File

@ -3,6 +3,7 @@
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $what) !!} {!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $what) !!}
{!! Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('transactions.store',$what)]) !!} {!! Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('transactions.store',$what)]) !!}
{!! Form::hidden('reminder',Input::get('reminder_id')) !!} {!! Form::hidden('reminder',Input::get('reminder_id')) !!}
{!! Form::hidden('what',$what) !!}
<div class="row"> <div class="row">
<div class="col-lg-6 col-md-12 col-sm-12"> <div class="col-lg-6 col-md-12 col-sm-12">
@ -21,27 +22,27 @@
<!-- SHOW EXPENSE ACCOUNT ONLY FOR WITHDRAWALS --> <!-- SHOW EXPENSE ACCOUNT ONLY FOR WITHDRAWALS -->
@if($what == 'withdrawal') @if($what == 'withdrawal')
{{ExpandedForm::text('expense_account')}} {!! ExpandedForm::text('expense_account') !!}
@endif @endif
<!-- SHOW REVENUE ACCOUNT ONLY FOR DEPOSITS --> <!-- SHOW REVENUE ACCOUNT ONLY FOR DEPOSITS -->
@if($what == 'deposit') @if($what == 'deposit')
{{ExpandedForm::text('revenue_account')}} {!! ExpandedForm::text('revenue_account') !!}
@endif @endif
<!-- ONLY SHOW FROM/TO ACCOUNT WHEN CREATING TRANSFER --> <!-- ONLY SHOW FROM/TO ACCOUNT WHEN CREATING TRANSFER -->
@if($what == 'transfer') @if($what == 'transfer')
{{ExpandedForm::select('account_from_id',$accounts)}} {!! ExpandedForm::select('account_from_id',$accounts) !!}
{{ExpandedForm::select('account_to_id',$accounts)}} {!! ExpandedForm::select('account_to_id',$accounts) !!}
@endif @endif
<!-- ALWAYS SHOW AMOUNT --> <!-- ALWAYS SHOW AMOUNT -->
{{ExpandedForm::amount('amount')}} {!! ExpandedForm::amount('amount') !!}
<!-- ALWAYS SHOW DATE --> <!-- ALWAYS SHOW DATE -->
{{ExpandedForm::date('date', date('Y-m-d'))}} {!! ExpandedForm::date('date', date('Y-m-d')) !!}
</div> </div>
</div> </div>
<p> <p>
@ -60,17 +61,17 @@
<div class="panel-body"> <div class="panel-body">
<!-- BUDGET ONLY WHEN CREATING A WITHDRAWAL --> <!-- BUDGET ONLY WHEN CREATING A WITHDRAWAL -->
@if($what == 'withdrawal') @if($what == 'withdrawal')
{{ExpandedForm::select('budget_id',$budgets,0)}} {!! ExpandedForm::select('budget_id',$budgets,0) !!}
@endif @endif
<!-- CATEGORY ALWAYS --> <!-- CATEGORY ALWAYS -->
{{ExpandedForm::text('category')}} {!! ExpandedForm::text('category') !!}
<!-- TAGS --> <!-- TAGS -->
<!-- RELATE THIS TRANSFER TO A PIGGY BANK --> <!-- RELATE THIS TRANSFER TO A PIGGY BANK -->
@if($what == 'transfer' && count($piggies) > 0) @if($what == 'transfer' && count($piggies) > 0)
{{ExpandedForm::select('piggy_bank_id',$piggies)}} {!! ExpandedForm::select('piggy_bank_id',$piggies) !!}
@endif @endif
</div> </div>
</div> </div>
@ -80,14 +81,14 @@
<i class="fa fa-bolt"></i> Options <i class="fa fa-bolt"></i> Options
</div> </div>
<div class="panel-body"> <div class="panel-body">
{{ExpandedForm::optionsList('create','transaction')}} {!! ExpandedForm::optionsList('create','transaction') !!}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{{Form::close()}} {!! Form::close() !!}
@stop @stop
@section('scripts') @section('scripts')