Repeated expenses.

This commit is contained in:
James Cole
2015-02-27 11:02:08 +01:00
parent defad3d820
commit fc5c339e27
15 changed files with 877 additions and 34 deletions

View File

@@ -39,8 +39,6 @@ class AccountController extends Controller
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $what);
$subTitle = 'Create a new ' . e($what) . ' account';
//\FireflyIII\Forms\Tags::ffAmount('12');
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
}

View File

@@ -0,0 +1,199 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use Config;
use ExpandedForm;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\PiggyBankFormRequest;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Redirect;
use Session;
use View;
/**
* Class RepeatedExpenseController
*
* @package FireflyIII\Http\Controllers
*/
class RepeatedExpenseController extends Controller
{
/**
*
*/
public function __construct()
{
View::share('title', 'Repeated expenses');
View::share('mainTitleIcon', 'fa-rotate-left');
}
/**
* @return $this
*/
public function create()
{
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']));
return View::make('repeatedExpense.create', compact('accounts', 'periods'))->with('subTitle', 'Create new repeated expense')->with(
'subTitleIcon', 'fa-plus'
);
}
/**
* @param PiggyBank $repeatedExpense
*
* @return $this
*/
public function delete(PiggyBank $repeatedExpense)
{
$subTitle = 'Delete "' . e($repeatedExpense->name) . '"';
return View::make('repeatedExpense.delete', compact('repeatedExpense', 'subTitle'));
}
/**
* @param PiggyBank $repeatedExpense
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(PiggyBank $repeatedExpense)
{
Session::flash('success', 'Repeated expense "' . e($repeatedExpense->name) . '" deleted.');
$repeatedExpense->delete();
return Redirect::route('repeated.index');
}
/**
* @param PiggyBank $repeatedExpense
*
* @return $this
*/
public function edit(PiggyBank $repeatedExpense)
{
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']));
$subTitle = 'Edit repeated expense "' . e($repeatedExpense->name) . '"';
$subTitleIcon = 'fa-pencil';
/*
* Flash some data to fill the form.
*/
$preFilled = ['name' => $repeatedExpense->name,
'account_id' => $repeatedExpense->account_id,
'targetamount' => $repeatedExpense->targetamount,
'reminder_skip' => $repeatedExpense->reminder_skip,
'rep_every' => $repeatedExpense->rep_every,
'rep_times' => $repeatedExpense->rep_times,
'targetdate' => $repeatedExpense->targetdate->format('Y-m-d'),
'reminder' => $repeatedExpense->reminder,
'remind_me' => intval($repeatedExpense->remind_me) == 1 || !is_null($repeatedExpense->reminder) ? true : false
];
Session::flash('preFilled', $preFilled);
return View::make('repeatedExpense.edit', compact('subTitle', 'subTitleIcon', 'repeatedExpense', 'accounts', 'periods', 'preFilled'));
}
/**
* @return \Illuminate\View\View
*/
public function index()
{
$subTitle = 'Overview';
$expenses = Auth::user()->piggyBanks()->where('repeats', 1)->get();
$expenses->each(
function (PiggyBank $piggyBank) {
$piggyBank->currentRelevantRep();
}
);
return View::make('repeatedExpense.index', compact('expenses', 'subTitle'));
}
/**
* @param PiggyBank $repeatedExpense
*
* @return \Illuminate\View\View
*/
public function show(PiggyBank $repeatedExpense, PiggyBankRepositoryInterface $repository)
{
$subTitle = $repeatedExpense->name;
$today = Carbon::now();
$repetitions = $repeatedExpense->piggyBankRepetitions()->get();
$repetitions->each(
function (PiggyBankRepetition $repetition) use ($repository) {
$repetition->bars = $repository->calculateParts($repetition);
}
);
return View::make('repeatedExpense.show', compact('repetitions', 'repeatedExpense', 'today', 'subTitle'));
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*/
public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository)
{
$piggyBankData = [
'repeats' => true,
'name' => $request->get('name'),
'startdate' => new Carbon,
'account_id' => intval($request->get('account_id')),
'targetamount' => floatval($request->get('targetamount')),
'targetdate' => new Carbon($request->get('targetdate')),
'reminder' => $request->get('reminder'),
'skip' => intval($request->get('skip')),
'rep_every' => intval($request->get('rep_every')),
'rep_times' => intval($request->get('rep_times')),
];
$piggyBank = $repository->store($piggyBankData);
Session::flash('success', 'Stored repeated expense "' . e($piggyBank->name) . '".');
return Redirect::route('repeated.index');
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param PiggyBank $repeatedExpense
*
* @return $this
*/
public function update(PiggyBank $repeatedExpense, PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository)
{
$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,
'rep_length' => $request->get('rep_length'),
'rep_every' => intval($request->get('rep_every')),
'rep_times' => intval($request->get('rep_times')),
'remind_me' => intval($request->get('remind_me')) == 1 ? true : false ,
'reminder' => $request->get('reminder'),
];
$piggyBank = $repository->update($repeatedExpense, $piggyBankData);
Session::flash('success', 'Updated repeated expense "' . e($piggyBank->name) . '".');
return Redirect::route('repeated.index');
}
}

View File

@@ -29,17 +29,23 @@ class PiggyBankFormRequest extends Request
{
$nameRule = 'required|between:1,255|uniqueForUser:piggy_banks,name';
$targetDateRule = 'date';
if (intval(Input::get('id'))) {
$nameRule = 'required|between:1,255';
}
if (intval(Input::get('repeats')) == 1) {
$targetDateRule = 'required|date|after:' . date('Y-m-d');
}
$rules = [
'account_id' => 'required|belongsToUser:accounts',
'name' => $nameRule,
'targetamount' => 'required|min:0.01',
'startdate' => 'date',
'targetdate' => 'date',
'repeats' => 'required|boolean',
'name' => $nameRule,
'account_id' => 'required|belongsToUser:accounts',
'targetamount' => 'required|min:0.01',
'amount_currency_id' => 'exists:transaction_currencies,id',
'startdate' => 'date',
'targetdate' => $targetDateRule,
'rep_length' => 'in:day,week,quarter,month,year',
'rep_every' => 'integer|min:0|max:31',
'rep_times' => 'integer|min:0|max:99',

View File

@@ -27,6 +27,20 @@ Route::bind(
}
);
Route::bind(
'repeatedExpense', 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', 1)->first(['piggy_banks.*']);
}
return null;
}
);
Route::bind(
'tjSecond', function ($value, $route) {
if (Auth::check()) {
@@ -263,11 +277,14 @@ Route::group(
/**
* Repeated Expenses Controller
*/
Route::get('/repeatedexpenses', ['uses' => 'RepeatedExpenseController@index', 'as' => 'repeated.index']);
//Route::get('/repeatedexpenses/create', ['uses' => 'RepeatedExpenseController@create', 'as' => 'repeated.create']);
//Route::get('/repeatedexpenses/edit/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@edit', 'as' => 'repeated.edit']);
//Route::get('/repeatedexpenses/delete/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@delete', 'as' => 'repeated.delete']);
//Route::get('/repeatedexpenses/show/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@show', 'as' => 'repeated.show']);
Route::get('/repeated-expenses', ['uses' => 'RepeatedExpenseController@index', 'as' => 'repeated.index']);
Route::get('/repeated-expenses/create', ['uses' => 'RepeatedExpenseController@create', 'as' => 'repeated.create']);
Route::get('/repeated-expenses/edit/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@edit', 'as' => 'repeated.edit']);
Route::get('/repeated-expenses/delete/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@delete', 'as' => 'repeated.delete']);
Route::get('/repeated-expenses/show/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@show', 'as' => 'repeated.show']);
Route::post('/repeated-expense/store', ['uses' => 'RepeatedExpenseController@store', 'as' => 'repeated.store']);
Route::post('/repeated-expense/update/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@update', 'as' => 'repeated.update']);
Route::post('/repeated-expense/destroy/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@destroy', 'as' => 'repeated.destroy']);
/**
* Report Controller

View File

@@ -14,7 +14,7 @@ class PiggyBank extends Model
{
use SoftDeletes;
protected $fillable = ['repeats', 'name', 'account_id', 'targetamount','startdate', 'targetdate', 'reminder',];
protected $fillable = ['repeats', 'name', 'account_id','rep_every', 'rep_times', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder',];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo

View File

@@ -3,6 +3,9 @@
namespace FireflyIII\Repositories\PiggyBank;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use Illuminate\Support\Collection;
use Navigation;
/**
* Class PiggyBankRepository
@@ -20,18 +23,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
public function store(array $data)
{
$piggyBank = PiggyBank::create(
[
'repeats' => $data['repeats'],
'name' => $data['name'],
'account_id' => $data['account_id'],
'targetamount' => $data['targetamount'],
'startdate' => $data['startdate'],
'targetdate' => $data['targetdate'],
'reminder' => $data['reminder'],
]
);
$piggyBank = PiggyBank::create($data);
return $piggyBank;
}
@@ -44,13 +36,94 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
*/
public function update(PiggyBank $piggyBank, array $data)
{
/**
'rep_length' => $request->get('rep_length'),
'rep_every' => intval($request->get('rep_every')),
'rep_times' => intval($request->get('rep_times')),
'remind_me' => intval($request->get('remind_me')) == 1 ? true : false ,
'reminder' => $request->get('reminder'),
*/
$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->rep_length = isset($data['rep_length']) ? $data['rep_length'] : null;
$piggyBank->rep_every =isset($data['rep_every']) ? $data['rep_every'] : null;
$piggyBank->rep_times = isset($data['rep_times']) ? $data['rep_times'] : null;
$piggyBank->remind_me = isset($data['remind_me']) ? $data['remind_me'] : null;
$piggyBank->save();
return $piggyBank;
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* Based on the piggy bank, the reminder-setting and
* other variables this method tries to divide the piggy bank into equal parts. Each is
* accommodated by a reminder (if everything goes to plan).
*
* @param PiggyBankRepetition $repetition
*
* @return Collection
*/
public function calculateParts(PiggyBankRepetition $repetition)
{
/** @var PiggyBank $piggyBank */
$piggyBank = $repetition->piggyBank()->first();
$bars = new Collection;
$currentStart = clone $repetition->startdate;
if (is_null($piggyBank->reminder)) {
$entry = ['repetition' => $repetition, 'amountPerBar' => floatval($piggyBank->targetamount),
'currentAmount' => floatval($repetition->currentamount), 'cumulativeAmount' => floatval($piggyBank->targetamount),
'startDate' => clone $repetition->startdate, 'targetDate' => clone $repetition->targetdate];
$bars->push($this->createPiggyBankPart($entry));
return $bars;
}
while ($currentStart < $repetition->targetdate) {
$currentTarget = Navigation::endOfX($currentStart, $piggyBank->reminder, $repetition->targetdate);
$entry = ['repetition' => $repetition, 'amountPerBar' => null, 'currentAmount' => floatval($repetition->currentamount),
'cumulativeAmount' => null, 'startDate' => $currentStart, 'targetDate' => $currentTarget];
$bars->push($this->createPiggyBankPart($entry));
$currentStart = clone $currentTarget;
$currentStart->addDay();
}
$amountPerBar = floatval($piggyBank->targetamount) / $bars->count();
$cumulative = $amountPerBar;
/** @var PiggyBankPart $bar */
foreach ($bars as $index => $bar) {
$bar->setAmountPerBar($amountPerBar);
$bar->setCumulativeAmount($cumulative);
if ($bars->count() - 1 == $index) {
$bar->setCumulativeAmount($piggyBank->targetamount);
}
$cumulative += $amountPerBar;
}
return $bars;
}
/**
* @param array $data
*
* @return PiggyBankPart
*/
public function createPiggyBankPart(array $data)
{
$part = new PiggyBankPart;
$part->setRepetition($data['repetition']);
$part->setAmountPerBar($data['amountPerBar']);
$part->setCurrentamount($data['currentAmount']);
$part->setCumulativeAmount($data['cumulativeAmount']);
$part->setStartdate($data['startDate']);
$part->setTargetdate($data['targetDate']);
return $part;
}
}

View File

@@ -3,6 +3,8 @@
namespace FireflyIII\Repositories\PiggyBank;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use Illuminate\Support\Collection;
/**
* Interface PiggyBankRepositoryInterface
@@ -26,4 +28,24 @@ interface PiggyBankRepositoryInterface {
* @return PiggyBank
*/
public function update(PiggyBank $piggyBank, array $data);
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* Based on the piggy bank, the reminder-setting and
* other variables this method tries to divide the piggy bank into equal parts. Each is
* accommodated by a reminder (if everything goes to plan).
*
* @param PiggyBankRepetition $repetition
*
* @return Collection
*/
public function calculateParts(PiggyBankRepetition $repetition);
/**
* @param array $data
*
* @return PiggyBankPart
*/
public function createPiggyBankPart(array $data);
}

View File

@@ -0,0 +1,181 @@
<?php
namespace FireflyIII\Repositories\PiggyBank;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\PiggyBankRepetition;
use Carbon\Carbon;
/**
* Class PiggyBankPart
*
* @package FireflyIII\Collection
*/
class PiggyBankPart
{
/** @var float */
public $amountPerBar;
/** @var float */
public $cumulativeAmount;
/** @var float */
public $currentamount;
/** @var Reminder */
public $reminder;
/** @var PiggyBankRepetition */
public $repetition;
/** @var Carbon */
public $startdate;
/** @var Carbon */
public $targetdate;
/**
* @return Reminder
*/
public function getReminder()
{
if (is_null($this->reminder)) {
$this->reminder = $this->repetition->piggyBank->reminders()->where('startdate', $this->getStartdate()->format('Y-m-d'))->where(
'enddate', $this->getTargetdate()->format('Y-m-d')
)->first();
}
return $this->reminder;
}
/**
* @param Reminder $reminder
*/
public function setReminder($reminder)
{
$this->reminder = $reminder;
}
/**
* @return Carbon
*/
public function getStartdate()
{
return $this->startdate;
}
/**
* @param Carbon $startdate
*/
public function setStartdate($startdate)
{
$this->startdate = $startdate;
}
/**
* @return Carbon
*/
public function getTargetdate()
{
return $this->targetdate;
}
/**
* @param Carbon $targetdate
*/
public function setTargetdate($targetdate)
{
$this->targetdate = $targetdate;
}
/**
* @return PiggyBankRepetition
*/
public function getRepetition()
{
return $this->repetition;
}
/**
* @param PiggyBankRepetition $repetition
*/
public function setRepetition($repetition)
{
$this->repetition = $repetition;
}
/**
* @return bool
*/
public function hasReminder()
{
return !is_null($this->reminder);
}
/**
* @return float|int
*/
public function percentage()
{
if ($this->getCurrentamount() < $this->getCumulativeAmount()) {
$pct = 0;
// calculate halfway point?
if ($this->getCumulativeAmount() - $this->getCurrentamount() < $this->getAmountPerBar()) {
$left = $this->getCurrentamount() % $this->getAmountPerBar();
$pct = round($left / $this->getAmountPerBar() * 100);
}
return $pct;
} else {
return 100;
}
}
/**
* @return float
*/
public function getCurrentamount()
{
return $this->currentamount;
}
/**
* @param float $currentamount
*/
public function setCurrentamount($currentamount)
{
$this->currentamount = $currentamount;
}
/**
* @return float
*/
public function getCumulativeAmount()
{
return $this->cumulativeAmount;
}
/**
* @param float $cumulativeAmount
*/
public function setCumulativeAmount($cumulativeAmount)
{
$this->cumulativeAmount = $cumulativeAmount;
}
/**
* @return float
*/
public function getAmountPerBar()
{
return $this->amountPerBar;
}
/**
* @param float $amountPerBar
*/
public function setAmountPerBar($amountPerBar)
{
$this->amountPerBar = $amountPerBar;
}
}

View File

@@ -103,6 +103,50 @@ class Navigation
return $currentEnd;
}
/**
*
* @param Carbon $theCurrentEnd
* @param $repeatFreq
* @param Carbon $maxDate
*
* @return Carbon
*/
public function endOfX(Carbon $theCurrentEnd, $repeatFreq, Carbon $maxDate)
{
$functionMap = [
'daily' => 'endOfDay',
'week' => 'endOfWeek',
'weekly' => 'endOfWeek',
'month' => 'endOfMonth',
'monthly' => 'endOfMonth',
'quarter' => 'lastOfQuarter',
'quarterly' => 'lastOfQuarter',
'year' => 'endOfYear',
'yearly' => 'endOfYear',
];
$specials = ['mont', 'monthly'];
$currentEnd = clone $theCurrentEnd;
if (isset($functionMap[$repeatFreq])) {
$function = $functionMap[$repeatFreq];
$currentEnd->$function();
}
if (isset($specials[$repeatFreq])) {
$month = intval($theCurrentEnd->format('m'));
$currentEnd->endOfYear();
if ($month <= 6) {
$currentEnd->subMonths(6);
}
}
if ($currentEnd > $maxDate) {
return clone $maxDate;
}
return $currentEnd;
}
/**
* @param $range
* @param Carbon $date

View File

@@ -4,6 +4,8 @@ namespace FireflyIII\Support;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use Illuminate\Support\Collection;
/**
@@ -161,4 +163,22 @@ class Steam
return $array;
}
/**
* @param PiggyBank $piggyBank
* @param PiggyBankRepetition $repetition
*
* @return int
*/
public function percentage(PiggyBank $piggyBank, PiggyBankRepetition $repetition)
{
$pct = $repetition->currentamount / $piggyBank->targetamount * 100;
if ($pct > 100) {
// @codeCoverageIgnoreStart
return 100;
// @codeCoverageIgnoreEnd
} else {
return floor($pct);
}
}
}

View File

@@ -0,0 +1,58 @@
@extends('layouts.default')
@section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
{!! Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('repeated.store')]) !!}
<input type="hidden" name="repeats" value="1" />
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-6">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-fw fa-exclamation"></i> Mandatory fields
</div>
<div class="panel-body">
{!! ExpandedForm::text('name') !!}
{!! ExpandedForm::select('account_id',$accounts,null,['label' => 'Save on account']) !!}
{!! ExpandedForm::amount('targetamount') !!}
{!! ExpandedForm::date('targetdate',null,['label' => 'First target date']) !!}
{!! ExpandedForm::select('rep_length',$periods,'month',['label' => 'Repeats every']) !!}
{!! ExpandedForm::integer('rep_every',0,['label' => 'Skip period']) !!}
{!! ExpandedForm::integer('rep_times',0,['label' => 'Repeat times']) !!}
</div>
</div>
<p>
<button type="submit" class="btn btn-lg btn-success">
<i class="fa fa-plus-circle"></i> Store new repeated expense
</button>
</p>
</div>
<div class="col-lg-6 col-md-12 col-sm-12">
<!-- panel for optional fields -->
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-smile-o"></i> Optional fields
</div>
<div class="panel-body">
{!! ExpandedForm::checkbox('remind_me','1',false,['label' => 'Remind me']) !!}
{!! ExpandedForm::select('reminder',$periods,'month',['label' => 'Remind every']) !!}
</div>
</div>
<!-- panel for options -->
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-bolt"></i> Options
</div>
<div class="panel-body">
{!! ExpandedForm::optionsList('create','repeated expense') !!}
</div>
</div>
</div>
</div>
{!! Form::close() !!}
@stop

View File

@@ -0,0 +1,37 @@
@extends('layouts.default')
@section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $repeatedExpense) !!}
{!! Form::open(['class' => 'form-horizontal','id' => 'destroy','url' => route('repeated.destroy',$repeatedExpense->id)]) !!}
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-12">
<div class="panel panel-red">
<div class="panel-heading">
Delete repeated expense "{{{$repeatedExpense->name}}}"
</div>
<div class="panel-body">
<p>
Are you sure?
</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">
</div>
</div>
</div>
</div>
{!! Form::close() !!}
@stop

View File

@@ -0,0 +1,58 @@
@extends('layouts.default')
@section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $repeatedExpense) !!}
{!! Form::model($repeatedExpense, ['class' => 'form-horizontal','id' => 'update','url' => route('repeated.update',$repeatedExpense->id)]) !!}
<input type="hidden" name="id" value="{{$repeatedExpense->id}}" />
<input type="hidden" name="repeats" value="0" />
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-6">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-fw fa-exclamation"></i> Mandatory fields
</div>
<div class="panel-body">
{!! ExpandedForm::text('name') !!}
{!! ExpandedForm::select('account_id',$accounts,null,['label' => 'Save on account']) !!}
{!! ExpandedForm::amount('targetamount') !!}
{!! ExpandedForm::date('targetdate',null,['label' => 'First target date']) !!}
{!! ExpandedForm::select('rep_length',$periods,null,['label' => 'Repeats every']) !!}
{!! ExpandedForm::integer('rep_every',null,['label' => 'Skip period']) !!}
{!! ExpandedForm::integer('rep_times',null,['label' => 'Repeat times']) !!}
</div>
</div>
<p>
<button type="submit" class="btn btn-lg btn-success">
<i class="fa fa-pencil"></i> Update repeated expense
</button>
</p>
</div>
<div class="col-lg-6 col-md-12 col-sm-12">
<!-- panel for optional fields -->
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-smile-o"></i> Optional fields
</div>
<div class="panel-body">
{!! ExpandedForm::checkbox('remind_me','1',$preFilled['remind_me'],['label' => 'Remind me']) !!}
{!! ExpandedForm::select('reminder',$periods,$preFilled['reminder'],['label' => 'Remind every']) !!}
</div>
</div>
<!-- panel for options -->
<div class="panel panel-default">
<div class="panel-heading">
<i class="fa fa-bolt"></i> Options
</div>
<div class="panel-body">
{!! ExpandedForm::optionsList('update','piggy bank') !!}
</div>
</div>
</div>
</div>
{!! Form::close() !!}
@stop

View File

@@ -0,0 +1,69 @@
@extends('layouts.default')
@section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<p>
<a class="btn btn-success" href="{{route('repeated.create')}}">Create new repeated expense</a>
</p>
</div>
</div>
@foreach($expenses as $entry)
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">
<a href="{{route('repeated.show',$entry->id)}}" title="{{{$entry->name}}}">{{{$entry->name}}}</a>
({!! Amount::format($entry->targetamount) !!})
<!-- 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('repeated.edit',$entry->id)}}"><i class="fa fa-pencil fa-fw"></i> Edit</a></li>
<li><a href="{{route('repeated.delete',$entry->id)}}"><i class="fa fa-trash fa-fw"></i> Delete</a></li>
</ul>
</div>
</div>
</div>
<div class="panel-body">
<div class="progress progress-striped">
<div class="progress-bar" role="progressbar" aria-valuenow="{{Steam::percentage($entry,$entry->currentRep)}}" aria-valuemin="0" aria-valuemax="100" style="width: {{Steam::percentage($entry,$entry->currentRep)}}%; min-width:15px;">
@if(Steam::percentage($entry,$entry->currentRep) > 30)
{{Amount::format($entry->currentRep->currentamount,false)}}
@endif
</div>
@if(Steam::percentage($entry,$entry->currentRep) <= 30)
&nbsp;<small>{{Amount::format($entry->currentRep->currentamount,false)}}</small>
@endif
</div>
</div>
<div class="panel-footer">
<small>{{$entry->currentRep->startdate->format('j F Y')}} to {{$entry->currentRep->targetdate->format('j F Y')}}</small>
</div>
</div>
</div>
</div>
@endforeach
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<p>
<a class="btn btn-success" href="{{route('repeated.create')}}">Create new repeated expense</a>
</p>
</div>
</div>
@stop
@section('scripts')
@stop

View File

@@ -0,0 +1,61 @@
@extends('layouts.default')
@section('content')
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $repeatedExpense) !!}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
@foreach($repetitions as $rep)
<?php
$barSize = floor(12 / $rep->bars->count()) == 0 ? 1 : floor(12 / $rep->bars->count());
?>
<div class="panel
@if($today > $rep->startdate && $today < $rep->targetdate)
panel-primary
@else
panel-default
@endif
">
<div class="panel-heading">
Repetition from {{$rep->startdate->format('j F Y')}} to {{$rep->targetdate->format('j F Y')}}
</div>
<div class="panel-body">
<p>
Target amount: {!! Amount::format($repeatedExpense->targetamount) !!}. Currently saved: {!! Amount::format($rep->currentamount) !!}.
</p>
<div class="row">
@foreach($rep->bars as $bar)
<div class="col-lg-{{$barSize}} col-md-{{$barSize}} col-sm-{{$barSize}}">
<div class="progress">
<!-- currentAmount:{{$bar->getCurrentAmount()}} getAmount:{{$bar->getCumulativeAmount()}} -->
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{$bar->percentage()}}" aria-valuemin="0" aria-valuemax="100" style="width: {{$bar->percentage()}}%;">
@if($bar->percentage() > 50 && $bar->percentage() == 100)
@if($bar->hasReminder() && $bar->getReminder()->active == 1)
<a href="{{route('reminders.show',$bar->getReminder()->id)}}" style="color:#fff;"><i class="fa fa-fw fa-clock-o"></i></a>
@endif
@if($bar->hasReminder() && $bar->getReminder()->active == 0 && $bar->getReminder()->notnow == 0)
<i class="fa fa-fw fa-thumbs-up"></i>
@endif
@if($bar->hasReminder() && $bar->getReminder()->active == 0 && $bar->getReminder()->notnow == 1)
<i class="fa fa-fw fa-thumbs-down"></i>
@endif
@endif
@if($bar->percentage() > 50 && $bar->percentage() < 100)
{{Amount::format($rep->currentamount,false)}}
@endif
</div>
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="{{100-$bar->percentage()}}" aria-valuemin="0" aria-valuemax="100" style="width: {{100-$bar->percentage()}}%;"></div>
</div>
<p class="small">
{{$bar->getStartDate()->format('j F Y')}} &mdash; {{$bar->getTargetDate()->format('j F Y')}}
</p>
</div>
@endforeach
</div>
</div>
</div>
@endforeach
</div>
</div>
@stop