mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-30 02:26:58 +00:00
Repeated expenses.
This commit is contained in:
@@ -39,8 +39,6 @@ class AccountController extends Controller
|
|||||||
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $what);
|
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $what);
|
||||||
$subTitle = 'Create a new ' . e($what) . ' account';
|
$subTitle = 'Create a new ' . e($what) . ' account';
|
||||||
|
|
||||||
//\FireflyIII\Forms\Tags::ffAmount('12');
|
|
||||||
|
|
||||||
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
|
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
199
app/Http/Controllers/RepeatedExpenseController.php
Normal file
199
app/Http/Controllers/RepeatedExpenseController.php
Normal 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');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -28,25 +28,31 @@ class PiggyBankFormRequest extends Request
|
|||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
|
|
||||||
$nameRule = 'required|between:1,255|uniqueForUser:piggy_banks,name';
|
$nameRule = 'required|between:1,255|uniqueForUser:piggy_banks,name';
|
||||||
|
$targetDateRule = 'date';
|
||||||
if (intval(Input::get('id'))) {
|
if (intval(Input::get('id'))) {
|
||||||
$nameRule = 'required|between:1,255';
|
$nameRule = 'required|between:1,255';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (intval(Input::get('repeats')) == 1) {
|
||||||
|
$targetDateRule = 'required|date|after:' . date('Y-m-d');
|
||||||
|
}
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
'account_id' => 'required|belongsToUser:accounts',
|
'repeats' => 'required|boolean',
|
||||||
'name' => $nameRule,
|
'name' => $nameRule,
|
||||||
'targetamount' => 'required|min:0.01',
|
'account_id' => 'required|belongsToUser:accounts',
|
||||||
'startdate' => 'date',
|
'targetamount' => 'required|min:0.01',
|
||||||
'targetdate' => 'date',
|
'amount_currency_id' => 'exists:transaction_currencies,id',
|
||||||
'repeats' => 'required|boolean',
|
'startdate' => 'date',
|
||||||
'rep_length' => 'in:day,week,quarter,month,year',
|
'targetdate' => $targetDateRule,
|
||||||
'rep_every' => 'integer|min:0|max:31',
|
'rep_length' => 'in:day,week,quarter,month,year',
|
||||||
'rep_times' => 'integer|min:0|max:99',
|
'rep_every' => 'integer|min:0|max:31',
|
||||||
'reminder' => 'in:day,week,quarter,month,year',
|
'rep_times' => 'integer|min:0|max:99',
|
||||||
'reminder_skip' => 'integer|min:0|max:99',
|
'reminder' => 'in:day,week,quarter,month,year',
|
||||||
'remind_me' => 'boolean',
|
'reminder_skip' => 'integer|min:0|max:99',
|
||||||
'order' => 'integer|min:1',
|
'remind_me' => 'boolean',
|
||||||
|
'order' => 'integer|min:1',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -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(
|
Route::bind(
|
||||||
'tjSecond', function ($value, $route) {
|
'tjSecond', function ($value, $route) {
|
||||||
if (Auth::check()) {
|
if (Auth::check()) {
|
||||||
@@ -263,11 +277,14 @@ Route::group(
|
|||||||
/**
|
/**
|
||||||
* Repeated Expenses Controller
|
* Repeated Expenses Controller
|
||||||
*/
|
*/
|
||||||
Route::get('/repeatedexpenses', ['uses' => 'RepeatedExpenseController@index', 'as' => 'repeated.index']);
|
Route::get('/repeated-expenses', ['uses' => 'RepeatedExpenseController@index', 'as' => 'repeated.index']);
|
||||||
//Route::get('/repeatedexpenses/create', ['uses' => 'RepeatedExpenseController@create', 'as' => 'repeated.create']);
|
Route::get('/repeated-expenses/create', ['uses' => 'RepeatedExpenseController@create', 'as' => 'repeated.create']);
|
||||||
//Route::get('/repeatedexpenses/edit/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@edit', 'as' => 'repeated.edit']);
|
Route::get('/repeated-expenses/edit/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@edit', 'as' => 'repeated.edit']);
|
||||||
//Route::get('/repeatedexpenses/delete/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@delete', 'as' => 'repeated.delete']);
|
Route::get('/repeated-expenses/delete/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@delete', 'as' => 'repeated.delete']);
|
||||||
//Route::get('/repeatedexpenses/show/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@show', 'as' => 'repeated.show']);
|
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
|
* Report Controller
|
||||||
|
@@ -14,7 +14,7 @@ class PiggyBank extends Model
|
|||||||
{
|
{
|
||||||
use SoftDeletes;
|
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
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
@@ -3,6 +3,9 @@
|
|||||||
namespace FireflyIII\Repositories\PiggyBank;
|
namespace FireflyIII\Repositories\PiggyBank;
|
||||||
|
|
||||||
use FireflyIII\Models\PiggyBank;
|
use FireflyIII\Models\PiggyBank;
|
||||||
|
use FireflyIII\Models\PiggyBankRepetition;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Navigation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class PiggyBankRepository
|
* Class PiggyBankRepository
|
||||||
@@ -20,18 +23,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
|||||||
public function store(array $data)
|
public function store(array $data)
|
||||||
{
|
{
|
||||||
|
|
||||||
$piggyBank = PiggyBank::create(
|
$piggyBank = PiggyBank::create($data);
|
||||||
[
|
|
||||||
|
|
||||||
'repeats' => $data['repeats'],
|
|
||||||
'name' => $data['name'],
|
|
||||||
'account_id' => $data['account_id'],
|
|
||||||
'targetamount' => $data['targetamount'],
|
|
||||||
'startdate' => $data['startdate'],
|
|
||||||
'targetdate' => $data['targetdate'],
|
|
||||||
'reminder' => $data['reminder'],
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
return $piggyBank;
|
return $piggyBank;
|
||||||
}
|
}
|
||||||
@@ -44,13 +36,94 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
|||||||
*/
|
*/
|
||||||
public function update(PiggyBank $piggyBank, array $data)
|
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->name = $data['name'];
|
||||||
$piggyBank->account_id = intval($data['account_id']);
|
$piggyBank->account_id = intval($data['account_id']);
|
||||||
$piggyBank->targetamount = floatval($data['targetamount']);
|
$piggyBank->targetamount = floatval($data['targetamount']);
|
||||||
$piggyBank->targetdate = $data['targetdate'];
|
$piggyBank->targetdate = $data['targetdate'];
|
||||||
$piggyBank->reminder = $data['reminder'];
|
$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();
|
$piggyBank->save();
|
||||||
return $piggyBank;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -3,6 +3,8 @@
|
|||||||
namespace FireflyIII\Repositories\PiggyBank;
|
namespace FireflyIII\Repositories\PiggyBank;
|
||||||
|
|
||||||
use FireflyIII\Models\PiggyBank;
|
use FireflyIII\Models\PiggyBank;
|
||||||
|
use FireflyIII\Models\PiggyBankRepetition;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface PiggyBankRepositoryInterface
|
* Interface PiggyBankRepositoryInterface
|
||||||
@@ -26,4 +28,24 @@ interface PiggyBankRepositoryInterface {
|
|||||||
* @return PiggyBank
|
* @return PiggyBank
|
||||||
*/
|
*/
|
||||||
public function update(PiggyBank $piggyBank, array $data);
|
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);
|
||||||
}
|
}
|
181
app/Repositories/PiggyBank/PiggybankPart.php
Normal file
181
app/Repositories/PiggyBank/PiggybankPart.php
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -103,6 +103,50 @@ class Navigation
|
|||||||
return $currentEnd;
|
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 $range
|
||||||
* @param Carbon $date
|
* @param Carbon $date
|
||||||
|
@@ -4,6 +4,8 @@ namespace FireflyIII\Support;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\PiggyBank;
|
||||||
|
use FireflyIII\Models\PiggyBankRepetition;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -161,4 +163,22 @@ class Steam
|
|||||||
return $array;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
58
resources/views/repeatedExpense/create.blade.php
Normal file
58
resources/views/repeatedExpense/create.blade.php
Normal 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
|
37
resources/views/repeatedExpense/delete.blade.php
Normal file
37
resources/views/repeatedExpense/delete.blade.php
Normal 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
|
58
resources/views/repeatedExpense/edit.blade.php
Normal file
58
resources/views/repeatedExpense/edit.blade.php
Normal 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
|
69
resources/views/repeatedExpense/index.blade.php
Normal file
69
resources/views/repeatedExpense/index.blade.php
Normal 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)
|
||||||
|
<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
|
61
resources/views/repeatedExpense/show.blade.php
Normal file
61
resources/views/repeatedExpense/show.blade.php
Normal 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')}} — {{$bar->getTargetDate()->format('j F Y')}}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@stop
|
Reference in New Issue
Block a user