diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php index 0ecb765ec5..589dc52c8e 100644 --- a/app/Http/Controllers/PiggyBankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -1,23 +1,30 @@ leftOnAccount($piggyBank->account); + $savedSoFar = $piggyBank->currentRelevantRep()->currentamount; + $leftToSave = $piggyBank->targetamount - $savedSoFar; + $maxAmount = min($leftOnAccount, $leftToSave); + + + \Log::debug('Now going to view for piggy bank #' . $piggyBank->id . ' (' . $piggyBank->name . ')'); + + return View::make('piggy-banks.add', compact('piggyBank', 'maxAmount')); + } + + /** + * @return mixed + */ + public function create() + { + + $periods = Config::get('firefly.piggy_bank_periods'); + $accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])); + $subTitle = 'Create new piggy bank'; + $subTitleIcon = 'fa-plus'; + + return View::make('piggy-banks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon')); + } + + /** + * @param PiggyBank $piggyBank + * + * @return $this + */ + public function delete(PiggyBank $piggyBank) + { + $subTitle = 'Delete "' . e($piggyBank->name) . '"'; + + return View::make('piggy_banks.delete', compact('piggyBank', 'subTitle')); + } + + /** + * @param PiggyBank $piggyBank + * + * @return \Illuminate\Http\RedirectResponse + */ + public function destroy(PiggyBank $piggyBank) + { + + Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.'); + $this->_repository->destroy($piggyBank); + + return Redirect::route('piggy_banks.index'); + } + + /** + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * + * @param PiggyBank $piggyBank + * + * @return $this + */ + public function edit(PiggyBank $piggyBank) + { + + $periods = Config::get('firefly.piggy_bank_periods'); + $accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])); + $subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"'; + $subTitleIcon = 'fa-pencil'; + + /* + * Flash some data to fill the form. + */ + if (is_null($piggyBank->targetdate) || $piggyBank->targetdate == '') { + $targetDate = null; + } else { + $targetDate = new Carbon($piggyBank->targetdate); + $targetDate = $targetDate->format('Y-m-d'); + } + $preFilled = ['name' => $piggyBank->name, + 'account_id' => $piggyBank->account_id, + 'targetamount' => $piggyBank->targetamount, + 'targetdate' => $targetDate, + 'reminder' => $piggyBank->reminder, + 'remind_me' => intval($piggyBank->remind_me) == 1 || !is_null($piggyBank->reminder) ? true : false + ]; + Session::flash('preFilled', $preFilled); + + return View::make('piggy-banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'accounts', 'periods', 'preFilled')); + } + /** * @return $this @@ -35,7 +138,7 @@ class PiggyBankController extends Controller { public function index(AccountRepositoryInterface $repository) { /** @var Collection $piggyBanks */ - $piggyBanks = Auth::user()->piggyBanks()->where('repeats',0)->get(); + $piggyBanks = Auth::user()->piggyBanks()->where('repeats', 0)->get(); $accounts = []; /** @var PiggyBank $piggyBank */ @@ -68,5 +171,149 @@ class PiggyBankController extends Controller { } + /** + * POST add money to piggy bank + * + * @param PiggyBank $piggyBank + * + * @return \Illuminate\Http\RedirectResponse + */ + public function postAdd(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository, AccountRepositoryInterface $accounts) + { + $amount = round(floatval(Input::get('amount')), 2); + $leftOnAccount = $accounts->leftOnAccount($piggyBank->account); + $savedSoFar = $piggyBank->currentRelevantRep()->currentamount; + $leftToSave = $piggyBank->targetamount - $savedSoFar; + $maxAmount = round(min($leftOnAccount, $leftToSave), 2); + + if ($amount <= $maxAmount) { + $repetition = $piggyBank->currentRelevantRep(); + $repetition->currentamount += $amount; + $repetition->save(); + + /* + * Create event! + */ + //Event::fire('piggy_bank.addMoney', [$piggyBank, $amount]); // new and used. + + Session::flash('success', 'Added ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".'); + } else { + Session::flash('error', 'Could not add ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".'); + } + + return Redirect::route('piggy-banks.index'); + } + + /** + * @param PiggyBank $piggyBank + * + * @return \Illuminate\Http\RedirectResponse + */ + public function postRemove(PiggyBank $piggyBank) + { + $amount = floatval(Input::get('amount')); + + $savedSoFar = $piggyBank->currentRelevantRep()->currentamount; + + if ($amount <= $savedSoFar) { + $repetition = $piggyBank->currentRelevantRep(); + $repetition->currentamount -= $amount; + $repetition->save(); + + /* + * Create event! + */ + //Event::fire('piggy_bank.removeMoney', [$piggyBank, $amount]); // new and used. + + Session::flash('success', 'Removed ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".'); + } else { + Session::flash('error', 'Could not remove ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".'); + } + + return Redirect::route('piggy-banks.index'); + } + + /** + * @param PiggyBank $piggyBank + * + * @SuppressWarnings("Unused") + * + * @return \Illuminate\View\View + */ + public function remove(PiggyBank $piggyBank) + { + return View::make('piggy-banks.remove', compact('piggyBank')); + } + + /** + * @param PiggyBank $piggyBank + * + * @return $this + */ + public function show(PiggyBank $piggyBank) + { + + $events = $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get(); + + /* + * Number of reminders: + */ + + $subTitle = e($piggyBank->name); + + return View::make('piggy-banks.show', compact('piggyBank', 'events', 'subTitle')); + + } + + /** + * + */ + public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository) + { + $piggyBankData = [ + 'repeats' => false, + 'name' => $request->get('name'), + 'startdate' => new Carbon, + 'account_id' => intval($request->get('account_id')), + 'targetamount' => floatval($request->get('targetamount')), + 'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null, + 'reminder' => $request->get('reminder'), + ]; + + $piggyBank = $repository->store($piggyBankData); + + Session::flash('success', 'Stored piggy bank "' . e($piggyBank->name) . '".'); + + return Redirect::route('piggy-banks.index'); + } + + /** + * @param PiggyBank $piggyBank + * + * @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind. + * + * @return $this + */ + public function update(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository, PiggyBankFormRequest $request) + { + $piggyBankData = [ + 'repeats' => false, + 'name' => $request->get('name'), + 'account_id' => intval($request->get('account_id')), + 'targetamount' => floatval($request->get('targetamount')), + 'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null, + 'reminder' => $request->get('reminder'), + ]; + + $piggyBank = $repository->update($piggyBank, $piggyBankData); + + Session::flash('success', 'Updated piggy bank "' . e($piggyBank->name) . '".'); + + return Redirect::route('piggy-banks.index'); + + + } + + } diff --git a/app/Http/Requests/PiggyBankFormRequest.php b/app/Http/Requests/PiggyBankFormRequest.php new file mode 100644 index 0000000000..f50a0ef00b --- /dev/null +++ b/app/Http/Requests/PiggyBankFormRequest.php @@ -0,0 +1,55 @@ + 'required|belongsToUser:accounts', + 'name' => $nameRule, + 'targetamount' => 'required|min:0.01', + 'startdate' => 'date', + 'targetdate' => 'date', + 'repeats' => 'required|boolean', + 'rep_length' => 'in:day,week,quarter,month,year', + 'rep_every' => 'integer|min:0|max:31', + 'rep_times' => 'integer|min:0|max:99', + 'reminder' => 'in:day,week,quarter,month,year', + 'reminder_skip' => 'integer|min:0|max:99', + 'remind_me' => 'boolean', + 'order' => 'integer|min:1', + + ]; + + return $rules; + } +} \ No newline at end of file diff --git a/app/Http/routes.php b/app/Http/routes.php index 194cf1c7e3..125445694d 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -5,6 +5,7 @@ use FireflyIII\Models\Budget; use FireflyIII\Models\Category; use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\TransactionCurrency; +use FireflyIII\Models\PiggyBank; // models @@ -65,6 +66,20 @@ Route::bind( } ); +Route::bind( + 'piggyBank', function ($value, $route) { + if (Auth::check()) { + return PiggyBank:: + where('piggy_banks.id', $value) + ->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') + ->where('accounts.user_id', Auth::user()->id) + ->where('repeats', 0)->first(['piggy_banks.*']); + } + + return null; +} +); + Route::bind( 'category', function ($value, $route) { if (Auth::check()) { @@ -169,6 +184,7 @@ 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/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']); + Route::get('/chart/piggy-history/{piggyBank}', ['uses' => 'GoogleChartController@piggyBankHistory']); /** * Help Controller @@ -193,6 +209,11 @@ Route::group( Route::get('/piggy-banks/edit/{piggyBank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy-banks.edit']); Route::get('/piggy-banks/delete/{piggyBank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy-banks.delete']); Route::get('/piggy-banks/show/{piggyBank}', ['uses' => 'PiggyBankController@show', 'as' => 'piggy-banks.show']); + Route::post('/piggy-banks/store', ['uses' => 'PiggyBankController@store', 'as' => 'piggy-banks.store']); + Route::post('/piggy-banks/update/{piggyBank}', ['uses' => 'PiggyBankController@update', 'as' => 'piggy-banks.update']); + Route::post('/piggy-banks/destroy/{piggyBank}', ['uses' => 'PiggyBankController@destroy', 'as' => 'piggy-banks.destroy']); + Route::post('/piggy-banks/add/{piggyBank}', ['uses' => 'PiggyBankController@postAdd', 'as' => 'piggy-banks.add']); # add money + Route::post('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@postRemove', 'as' => 'piggy-banks.remove']); # remove money. /** * Preferences Controller diff --git a/app/Models/PiggyBank.php b/app/Models/PiggyBank.php index 187e4dd722..d3fe2e1316 100644 --- a/app/Models/PiggyBank.php +++ b/app/Models/PiggyBank.php @@ -14,6 +14,8 @@ class PiggyBank extends Model { use SoftDeletes; + protected $fillable = ['repeats', 'name', 'account_id', 'targetamount','startdate', 'targetdate', 'reminder',]; + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ @@ -22,38 +24,6 @@ class PiggyBank extends Model return $this->belongsTo('FireflyIII\Models\Account'); } - /** - * @return array - */ - public function getDates() - { - return ['created_at', 'updated_at', 'deleted_at', 'startdate', 'targetdate']; - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function piggyBankEvents() - { - return $this->hasMany('FireflyIII\Models\PiggyBankEvent'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function piggyBankRepetitions() - { - return $this->hasMany('FireflyIII\Models\PiggyBankRepetition'); - } - - /** - * @return \Illuminate\Database\Eloquent\Relations\MorphMany - */ - public function reminders() - { - return $this->morphMany('FireflyIII\Models\Reminder', 'remindersable'); - } - /** * Grabs the PiggyBankRepetition that's currently relevant / active * @@ -70,7 +40,7 @@ class PiggyBank extends Model return $rep; } else { - $query = $this->piggyBankRepetitions()->where( + $query = $this->piggyBankRepetitions()->where( function (EloquentBuilder $q) { $q->where( @@ -100,7 +70,7 @@ class PiggyBank extends Model } )->orderBy('startdate', 'ASC'); - $result = $query->first(['piggy_bank_repetitions.*']); + $result = $query->first(['piggy_bank_repetitions.*']); $this->currentRep = $result; return $result; @@ -108,4 +78,36 @@ class PiggyBank extends Model } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function piggyBankRepetitions() + { + return $this->hasMany('FireflyIII\Models\PiggyBankRepetition'); + } + + /** + * @return array + */ + public function getDates() + { + return ['created_at', 'updated_at', 'deleted_at', 'startdate', 'targetdate']; + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function piggyBankEvents() + { + return $this->hasMany('FireflyIII\Models\PiggyBankEvent'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\MorphMany + */ + public function reminders() + { + return $this->morphMany('FireflyIII\Models\Reminder', 'remindersable'); + } } diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index b98aa01128..2a98c7656e 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -5,6 +5,8 @@ use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; +use FireflyIII\Models\PiggyBank; +use FireflyIII\Models\PiggyBankRepetition; use FireflyIII\Support\Facades\Navigation; use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; use Illuminate\Database\QueryException; @@ -66,6 +68,15 @@ class EventServiceProvider extends ServiceProvider } ); + PiggyBank::created(function(PiggyBank $piggyBank) { + $repetition = new PiggyBankRepetition; + $repetition->piggyBank()->associate($piggyBank); + $repetition->startdate = $piggyBank->startdate; + $repetition->targetdate = $piggyBank->targetdate; + $repetition->currentamount = 0; + $repetition->save(); + }); + BudgetLimit::saved( function (BudgetLimit $budgetLimit) { diff --git a/app/Providers/FireflyServiceProvider.php b/app/Providers/FireflyServiceProvider.php index 6d9a785905..e3d111dac7 100644 --- a/app/Providers/FireflyServiceProvider.php +++ b/app/Providers/FireflyServiceProvider.php @@ -61,6 +61,7 @@ class FireflyServiceProvider extends ServiceProvider $this->app->bind('FireflyIII\Repositories\Category\CategoryRepositoryInterface', 'FireflyIII\Repositories\Category\CategoryRepository'); $this->app->bind('FireflyIII\Repositories\Journal\JournalRepositoryInterface', 'FireflyIII\Repositories\Journal\JournalRepository'); $this->app->bind('FireflyIII\Repositories\Bill\BillRepositoryInterface', 'FireflyIII\Repositories\Bill\BillRepository'); + $this->app->bind('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface', 'FireflyIII\Repositories\PiggyBank\PiggyBankRepository'); $this->app->bind('FireflyIII\Helpers\Report\ReportHelperInterface', 'FireflyIII\Helpers\Report\ReportHelper'); $this->app->bind('FireflyIII\Helpers\Report\ReportQueryInterface', 'FireflyIII\Helpers\Report\ReportQuery'); diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php new file mode 100644 index 0000000000..f304e178e9 --- /dev/null +++ b/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -0,0 +1,56 @@ + $data['repeats'], + 'name' => $data['name'], + 'account_id' => $data['account_id'], + 'targetamount' => $data['targetamount'], + 'startdate' => $data['startdate'], + 'targetdate' => $data['targetdate'], + 'reminder' => $data['reminder'], + ] + ); + + return $piggyBank; + } + + /** + * @param PiggyBank $account + * @param array $data + * + * @return PiggyBank + */ + public function update(PiggyBank $piggyBank, array $data) + { + + $piggyBank->name = $data['name']; + $piggyBank->account_id = intval($data['account_id']); + $piggyBank->targetamount = floatval($data['targetamount']); + $piggyBank->targetdate = $data['targetdate']; + $piggyBank->reminder = $data['reminder']; + $piggyBank->save(); + return $piggyBank; + } +} \ No newline at end of file diff --git a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php new file mode 100644 index 0000000000..333a2e993f --- /dev/null +++ b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php @@ -0,0 +1,29 @@ + + + @if(isset($showPiggyBank) && $showPiggyBank === true) + Piggy bank + @endif + Date + Amount + + @foreach($events as $event) + + @if(isset($showPiggyBank) && $showPiggyBank === true) + + {{{$event->piggyBank->name}}} + + @endif + + @if(!is_null($event->transaction_journal_id)) + {{$event->date->format('j F Y')}} + @else + {{$event->date->format('j F Y')}} + @endif + + + + @if($event->amount < 0) + Removed {{Amount::format($event->amount*-1,false)}} + @else + Added {{Amount::format($event->amount,false)}} + @endif + + + @endforeach + diff --git a/resources/views/piggy-banks/add.blade.php b/resources/views/piggy-banks/add.blade.php index bb6ac6866c..94c46696b3 100644 --- a/resources/views/piggy-banks/add.blade.php +++ b/resources/views/piggy-banks/add.blade.php @@ -1,5 +1,5 @@
-{{Form::token()}} +{!! Form::token() !!} -{{-- -

Mandatory fields

- -

Optional fields

- - -
- {{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}} -
- - - - @if($errors->has('reminder')) -

{{$errors->first('reminder')}}

- @else - Enter a number and a period and Firefly will remind you to add money - to this piggy bank every now and then. - @endif -
-
- - - - - -
-
- -
-
- -
-
-
-
---}} - -{{Form::close()}} +{!! Form::close() !!} @stop diff --git a/resources/views/piggy-banks/edit.blade.php b/resources/views/piggy-banks/edit.blade.php index 444ef599c1..351679bb49 100644 --- a/resources/views/piggy-banks/edit.blade.php +++ b/resources/views/piggy-banks/edit.blade.php @@ -1,7 +1,10 @@ @extends('layouts.default') @section('content') -{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $piggyBank) }} -{{Form::model($piggyBank, ['class' => 'form-horizontal','id' => 'update','url' => route('piggy-banks.update',$piggyBank->id)])}} +{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $piggyBank) !!} +{!! Form::model($piggyBank, ['class' => 'form-horizontal','id' => 'update','url' => route('piggy-banks.update',$piggyBank->id)]) !!} + + +
@@ -10,9 +13,13 @@ Mandatory fields
- {{Form::ffText('name')}} - {{Form::ffSelect('account_id',$accounts,null,['label' => 'Save on account'])}} - {{Form::ffAmount('targetamount')}} + @foreach($errors->all() as $err) + {{$err}} + @endforeach + + {!! ExpandedForm::text('name') !!} + {!! ExpandedForm::select('account_id',$accounts,null,['label' => 'Save on account']) !!} + {!! ExpandedForm::amount('targetamount') !!}
@@ -29,9 +36,9 @@ Optional fields
- {{Form::ffDate('targetdate')}} - {{Form::ffCheckbox('remind_me','1',$preFilled['remind_me'],['label' => 'Remind me'])}} - {{Form::ffSelect('reminder',$periods,$preFilled['reminder'],['label' => 'Remind every'])}} + {!! ExpandedForm::date('targetdate') !!} + {!! ExpandedForm::checkbox('remind_me','1',$preFilled['remind_me'],['label' => 'Remind me']) !!} + {!! ExpandedForm::select('reminder',$periods,$preFilled['reminder'],['label' => 'Remind every']) !!}
@@ -41,54 +48,12 @@ Options
- {{Form::ffOptionsList('update','piggy bank')}} + {!! ExpandedForm::optionsList('update','piggy bank') !!}
-{{-- -

Mandatory fields

- -

Optional fields

- - -
- {{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}} -
- - - - @if($errors->has('reminder')) -

{{$errors->first('reminder')}}

- @else - Enter a number and a period and Firefly will remind you to add money - to this piggy bank every now and then. - @endif -
-
- - - - - -
-
- -
-
- -
-
-
-
---}} - -{{Form::close()}} +{!! Form::close() !!} @stop diff --git a/resources/views/piggy-banks/remove.blade.php b/resources/views/piggy-banks/remove.blade.php index 48d9ab4f65..3a06e99184 100644 --- a/resources/views/piggy-banks/remove.blade.php +++ b/resources/views/piggy-banks/remove.blade.php @@ -1,5 +1,5 @@ -{{Form::token()}} +{!! Form::token() !!}