mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Finally implemented repeated expenses properly. [skip ci]
This commit is contained in:
parent
c0c37eec7b
commit
b451e207e2
@ -32,6 +32,11 @@ class HelpController extends BaseController
|
||||
} catch (ErrorException $e) {
|
||||
$content = '<p>There is no help for this route.</p>';
|
||||
}
|
||||
if (strlen($content) == 0) {
|
||||
$content = '<p>There is no help for this route.</p>';
|
||||
}
|
||||
\Log::debug('Found help for ' . $route);
|
||||
\Log::debug('Help text length is ' . strlen($content));
|
||||
$helpText = \Michelf\Markdown::defaultTransform($content);
|
||||
$helpTitle = $route;
|
||||
|
||||
|
@ -35,11 +35,68 @@ class RepeatedExpenseController extends BaseController
|
||||
|
||||
$accounts = FFForm::makeSelectList($acct->getAssetAccounts());
|
||||
|
||||
return View::make('repeatedexpense.create', compact('accounts', 'periods'))->with('subTitle', 'Create new repeated expense')->with(
|
||||
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.');
|
||||
$this->_repository->destroy($repeatedExpense);
|
||||
|
||||
return Redirect::route('repeated.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $repeatedExpense
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function edit(PiggyBank $repeatedExpense)
|
||||
{
|
||||
|
||||
/** @var \FireflyIII\Database\Account\Account $acct */
|
||||
$acct = App::make('FireflyIII\Database\Account\Account');
|
||||
|
||||
$periods = Config::get('firefly.piggy_bank_periods');
|
||||
$accounts = FFForm::makeSelectList($acct->getAssetAccounts());
|
||||
$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,
|
||||
'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
|
||||
*/
|
||||
@ -48,50 +105,51 @@ class RepeatedExpenseController extends BaseController
|
||||
|
||||
$subTitle = 'Overview';
|
||||
|
||||
/** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repository */
|
||||
$repository = App::make('FireflyIII\Database\PiggyBank\RepeatedExpense');
|
||||
|
||||
$expenses = $repository->get();
|
||||
$expenses = $this->_repository->get();
|
||||
$expenses->each(
|
||||
function (PiggyBank $piggyBank) use ($repository) {
|
||||
function (PiggyBank $piggyBank) {
|
||||
$piggyBank->currentRelevantRep();
|
||||
}
|
||||
);
|
||||
|
||||
return View::make('repeatedexpense.index', compact('expenses', 'subTitle'));
|
||||
return View::make('repeatedExpense.index', compact('expenses', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param PiggyBank $repeatedExpense
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(PiggyBank $piggyBank)
|
||||
public function show(PiggyBank $repeatedExpense)
|
||||
{
|
||||
$subTitle = $piggyBank->name;
|
||||
$subTitle = $repeatedExpense->name;
|
||||
$today = Carbon::now();
|
||||
|
||||
/** @var \FireflyIII\Database\PiggyBank\RepeatedExpense $repository */
|
||||
$repository = App::make('FireflyIII\Database\PiggyBank\RepeatedExpense');
|
||||
|
||||
$repetitions = $piggyBank->piggyBankRepetitions()->get();
|
||||
$repetitions = $repeatedExpense->piggyBankRepetitions()->get();
|
||||
$repetitions->each(
|
||||
function (PiggyBankRepetition $repetition) use ($repository) {
|
||||
$repetition->bars = $repository->calculateParts($repetition);
|
||||
function (PiggyBankRepetition $repetition) {
|
||||
$repetition->bars = $this->_repository->calculateParts($repetition);
|
||||
}
|
||||
);
|
||||
|
||||
return View::make('repeatedexpense.show', compact('repetitions', 'piggyBank', 'today', 'subTitle'));
|
||||
return View::make('repeatedExpense.show', compact('repetitions', 'repeatedExpense', 'today', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @throws FireflyException
|
||||
*
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
$data = Input::except('_token');
|
||||
$data['repeats'] = 1;
|
||||
$data = Input::all();
|
||||
$data['repeats'] = 1;
|
||||
$data['user_id'] = Auth::user()->id;
|
||||
$targetDate = new Carbon($data['targetdate']);
|
||||
$startDate = \DateKit::subtractPeriod($targetDate, $data['rep_length']);
|
||||
$data['startdate'] = $startDate->format('Y-m-d');
|
||||
$data['targetdate'] = $targetDate->format('Y-m-d');
|
||||
$data['reminder_skip'] = 0;
|
||||
$data['remind_me'] = isset($data['remind_me']) ? 1 : 0;
|
||||
$data['order'] = 0;
|
||||
|
||||
// always validate:
|
||||
$messages = $this->_repository->validate($data);
|
||||
@ -101,25 +159,70 @@ class RepeatedExpenseController extends BaseController
|
||||
Session::flash('successes', $messages['successes']);
|
||||
Session::flash('errors', $messages['errors']);
|
||||
if ($messages['errors']->count() > 0) {
|
||||
Session::flash('error', 'Could not validate repeated expense: ' . $messages['errors']->first());
|
||||
Session::flash('error', 'Could not store repeated expense: ' . $messages['errors']->first());
|
||||
}
|
||||
|
||||
|
||||
// return to create screen:
|
||||
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
|
||||
return Redirect::route('repeated.create')->withInput();
|
||||
}
|
||||
|
||||
// store:
|
||||
$this->_repository->store($data);
|
||||
Session::flash('success', 'Budget "' . e($data['name']) . '" stored.');
|
||||
$piggyBank = $this->_repository->store($data);
|
||||
Event::fire('piggy_bank.store', [$piggyBank]); // new and used.
|
||||
Session::flash('success', 'Piggy bank "' . e($data['name']) . '" stored.');
|
||||
if ($data['post_submit_action'] == 'store') {
|
||||
return Redirect::route('repeated.index');
|
||||
}
|
||||
|
||||
// create another.
|
||||
if ($data['post_submit_action'] == 'create_another') {
|
||||
return Redirect::route('repeated.create')->withInput();
|
||||
return Redirect::route('repeated.create')->withInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $repeatedExpense
|
||||
*
|
||||
* @return $this
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function update(PiggyBank $repeatedExpense)
|
||||
{
|
||||
|
||||
$data = Input::except('_token');
|
||||
$data['rep_every'] = 0;
|
||||
$data['reminder_skip'] = 0;
|
||||
$data['order'] = 0;
|
||||
$data['repeats'] = 1;
|
||||
$data['remind_me'] = isset($data['remind_me']) ? 1 : 0;
|
||||
$data['user_id'] = Auth::user()->id;
|
||||
|
||||
// always validate:
|
||||
$messages = $this->_repository->validate($data);
|
||||
|
||||
// flash messages:
|
||||
Session::flash('warnings', $messages['warnings']);
|
||||
Session::flash('successes', $messages['successes']);
|
||||
Session::flash('errors', $messages['errors']);
|
||||
if ($messages['errors']->count() > 0) {
|
||||
Session::flash('error', 'Could not update repeated expense: ' . $messages['errors']->first());
|
||||
}
|
||||
|
||||
return Redirect::route('repeated.index');
|
||||
// return to update screen:
|
||||
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
|
||||
return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput();
|
||||
}
|
||||
|
||||
// update
|
||||
$this->_repository->update($repeatedExpense, $data);
|
||||
Session::flash('success', 'Repeated expense "' . e($data['name']) . '" updated.');
|
||||
|
||||
// go back to list
|
||||
if ($data['post_submit_action'] == 'update') {
|
||||
return Redirect::route('repeated.index');
|
||||
}
|
||||
|
||||
// go back to update screen.
|
||||
return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput(['post_submit_action' => 'return_to_edit']);
|
||||
|
||||
}
|
||||
}
|
@ -4,223 +4,18 @@ namespace FireflyIII\Database\PiggyBank;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Database\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\CUD;
|
||||
use FireflyIII\Database\SwitchUser;
|
||||
use FireflyIII\Exception\FireflyException;
|
||||
use FireflyIII\Exception\NotImplementedException;
|
||||
use Illuminate\Database\Eloquent\Model as Eloquent;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\MessageBag;
|
||||
|
||||
/**
|
||||
* Class PiggyBank
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class PiggyBank implements CUD, CommonDatabaseCalls, PiggyBankInterface
|
||||
class PiggyBank extends PiggyBankShared implements CUD, CommonDatabaseCalls, PiggyBankInterface
|
||||
{
|
||||
use SwitchUser;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setUser(\Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Eloquent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Eloquent $model)
|
||||
{
|
||||
$model->delete();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return \Eloquent
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
if (!isset($data['remind_me']) || (isset($data['remind_me']) && $data['remind_me'] == 0)) {
|
||||
$data['reminder'] = null;
|
||||
}
|
||||
$piggyBank = new \PiggyBank($data);
|
||||
$piggyBank->save();
|
||||
|
||||
return $piggyBank;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Eloquent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Eloquent $model, array $data)
|
||||
{
|
||||
/** @var \PiggyBank $model */
|
||||
$model->name = $data['name'];
|
||||
$model->account_id = intval($data['account_id']);
|
||||
$model->targetamount = floatval($data['targetamount']);
|
||||
$model->targetdate = isset($data['targetdate']) && $data['targetdate'] != '' ? $data['targetdate'] : null;
|
||||
$model->rep_every = intval($data['rep_every']);
|
||||
$model->reminder_skip = intval($data['reminder_skip']);
|
||||
$model->order = intval($data['order']);
|
||||
$model->remind_me = intval($data['remind_me']);
|
||||
$model->reminder = isset($data['reminder']) ? $data['reminder'] : 'month';
|
||||
|
||||
if ($model->remind_me == 0) {
|
||||
$model->reminder = null;
|
||||
}
|
||||
|
||||
$model->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* Ignore PHPMD rules because Laravel 5.0 will make this method superfluous anyway.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
$warnings = new MessageBag;
|
||||
$successes = new MessageBag;
|
||||
$errors = new MessageBag;
|
||||
|
||||
/*
|
||||
* Name validation:
|
||||
*/
|
||||
if (!isset($model['name'])) {
|
||||
$errors->add('name', 'Name is mandatory');
|
||||
}
|
||||
|
||||
if (isset($model['name']) && strlen($model['name']) == 0) {
|
||||
$errors->add('name', 'Name is too short');
|
||||
}
|
||||
if (isset($model['name']) && strlen($model['name']) > 100) {
|
||||
$errors->add('name', 'Name is too long');
|
||||
}
|
||||
|
||||
if (intval($model['account_id']) == 0) {
|
||||
$errors->add('account_id', 'Account is mandatory');
|
||||
}
|
||||
if ($model['targetdate'] == '' && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
|
||||
$errors->add('targetdate', 'Target date is mandatory when setting reminders.');
|
||||
}
|
||||
if ($model['targetdate'] != '') {
|
||||
try {
|
||||
new Carbon($model['targetdate']);
|
||||
} catch (\Exception $e) {
|
||||
$errors->add('targetdate', 'Invalid date.');
|
||||
}
|
||||
}
|
||||
if (floatval($model['targetamount']) < 0.01) {
|
||||
$errors->add('targetamount', 'Amount should be above 0.01.');
|
||||
}
|
||||
if (!in_array(ucfirst($model['reminder']), \Config::get('firefly.piggy_bank_periods'))) {
|
||||
$errors->add('reminder', 'Invalid reminder period (' . $model['reminder'] . ')');
|
||||
}
|
||||
// check period.
|
||||
if (!$errors->has('reminder') && !$errors->has('targetdate') && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
|
||||
$today = new Carbon;
|
||||
$target = new Carbon($model['targetdate']);
|
||||
switch ($model['reminder']) {
|
||||
case 'week':
|
||||
$today->addWeek();
|
||||
break;
|
||||
case 'month':
|
||||
$today->addMonth();
|
||||
break;
|
||||
case 'year':
|
||||
$today->addYear();
|
||||
break;
|
||||
}
|
||||
if ($today > $target) {
|
||||
$errors->add('reminder', 'Target date is too close to today to set reminders.');
|
||||
}
|
||||
}
|
||||
|
||||
$validator = \Validator::make($model, \PiggyBank::$rules);
|
||||
if ($validator->invalid()) {
|
||||
$errors->merge($errors);
|
||||
}
|
||||
|
||||
// add ok messages.
|
||||
$list = ['name', 'account_id', 'targetamount', 'targetdate', 'remind_me', 'reminder'];
|
||||
foreach ($list as $entry) {
|
||||
if (!$errors->has($entry) && !$warnings->has($entry)) {
|
||||
$successes->add($entry, 'OK');
|
||||
}
|
||||
}
|
||||
|
||||
return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $objectId
|
||||
*
|
||||
* @return \Eloquent
|
||||
*/
|
||||
public function find($objectId)
|
||||
{
|
||||
return \PiggyBank::
|
||||
leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')->where('piggy_banks.id', '=', $objectId)->where(
|
||||
'accounts.user_id', $this->getUser()->id
|
||||
)
|
||||
->first(['piggy_banks.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement findByWhat() method.
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->getUser()->piggyBanks()->where('repeats', 0)->orderBy('name')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PiggyBank $piggyBank
|
||||
* @param Carbon $date
|
||||
@ -257,21 +52,12 @@ class PiggyBank implements CUD, CommonDatabaseCalls, PiggyBankInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return float
|
||||
* @return Collection
|
||||
*/
|
||||
public function leftOnAccount(\Account $account)
|
||||
public function get()
|
||||
{
|
||||
\Log::debug('Now in leftOnAccount() for account #'.$account->id.' ('.$account->name.')');
|
||||
$balance = \Steam::balance($account);
|
||||
\Log::debug('Steam says: ' . $balance);
|
||||
/** @var \PiggyBank $p */
|
||||
foreach ($account->piggyBanks()->get() as $p) {
|
||||
$balance -= $p->currentRelevantRep()->currentamount;
|
||||
}
|
||||
|
||||
return $balance;
|
||||
|
||||
return $this->getUser()->piggyBanks()->where('repeats', 0)->orderBy('name')->get();
|
||||
}
|
||||
}
|
220
app/lib/FireflyIII/Database/PiggyBank/PiggyBankShared.php
Normal file
220
app/lib/FireflyIII/Database/PiggyBank/PiggyBankShared.php
Normal file
@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\PiggyBank;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Database\SwitchUser;
|
||||
use FireflyIII\Exception\NotImplementedException;
|
||||
use Illuminate\Database\Eloquent\Model as Eloquent;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\MessageBag;
|
||||
|
||||
/**
|
||||
* Class PiggyBankShared
|
||||
*
|
||||
* @package FireflyIII\Database\PiggyBank
|
||||
*/
|
||||
class PiggyBankShared
|
||||
{
|
||||
use SwitchUser;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setUser(\Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Eloquent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Eloquent $model)
|
||||
{
|
||||
$model->delete();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $objectId
|
||||
*
|
||||
* @return \Eloquent
|
||||
*/
|
||||
public function find($objectId)
|
||||
{
|
||||
return \PiggyBank::
|
||||
leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')->where('piggy_banks.id', '=', $objectId)->where(
|
||||
'accounts.user_id', $this->getUser()->id
|
||||
)
|
||||
->first(['piggy_banks.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement findByWhat() method.
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
return \PiggyBank::
|
||||
leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')->whereIn('piggy_banks.id', [$ids])->where(
|
||||
'accounts.user_id', $this->getUser()->id
|
||||
)
|
||||
->first(['piggy_banks.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function leftOnAccount(\Account $account)
|
||||
{
|
||||
\Log::debug('Now in leftOnAccount() for account #' . $account->id . ' (' . $account->name . ')');
|
||||
$balance = \Steam::balance($account);
|
||||
\Log::debug('Steam says: ' . $balance);
|
||||
/** @var \PiggyBank $p */
|
||||
foreach ($account->piggyBanks()->get() as $p) {
|
||||
$balance -= $p->currentRelevantRep()->currentamount;
|
||||
}
|
||||
|
||||
return $balance;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return \Eloquent
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
if (!isset($data['remind_me']) || (isset($data['remind_me']) && $data['remind_me'] == 0)) {
|
||||
$data['reminder'] = null;
|
||||
}
|
||||
$piggyBank = new \PiggyBank($data);
|
||||
$piggyBank->save();
|
||||
|
||||
return $piggyBank;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Eloquent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Eloquent $model, array $data)
|
||||
{
|
||||
/** @var \PiggyBank $model */
|
||||
$model->name = $data['name'];
|
||||
$model->account_id = intval($data['account_id']);
|
||||
$model->targetamount = floatval($data['targetamount']);
|
||||
$model->targetdate = isset($data['targetdate']) && $data['targetdate'] != '' ? $data['targetdate'] : null;
|
||||
$model->rep_every = intval($data['rep_every']);
|
||||
$model->reminder_skip = intval($data['reminder_skip']);
|
||||
$model->order = intval($data['order']);
|
||||
$model->remind_me = intval($data['remind_me']);
|
||||
$model->reminder = isset($data['reminder']) ? $data['reminder'] : 'month';
|
||||
|
||||
if ($model->remind_me == 0) {
|
||||
$model->reminder = null;
|
||||
}
|
||||
|
||||
$model->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* Ignore PHPMD rules because Laravel 5.0 will make this method superfluous anyway.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
$warnings = new MessageBag;
|
||||
$successes = new MessageBag;
|
||||
$model = new \PiggyBank($model);
|
||||
$model->isValid();
|
||||
$errors = $model->getErrors();
|
||||
|
||||
// add ok messages.
|
||||
$list = ['name', 'account_id', 'targetamount', 'targetdate', 'remind_me', 'reminder'];
|
||||
foreach ($list as $entry) {
|
||||
if (!$errors->has($entry) && !$warnings->has($entry)) {
|
||||
$successes->add($entry, 'OK');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes];
|
||||
|
||||
exit;
|
||||
|
||||
if (!in_array(ucfirst($model['reminder']), \Config::get('firefly.piggy_bank_periods'))) {
|
||||
$errors->add('reminder', 'Invalid reminder period (' . $model['reminder'] . ')');
|
||||
}
|
||||
// check period.
|
||||
if (!$errors->has('reminder') && !$errors->has('targetdate') && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
|
||||
$today = new Carbon;
|
||||
$target = new Carbon($model['targetdate']);
|
||||
switch ($model['reminder']) {
|
||||
case 'week':
|
||||
$today->addWeek();
|
||||
break;
|
||||
case 'month':
|
||||
$today->addMonth();
|
||||
break;
|
||||
case 'year':
|
||||
$today->addYear();
|
||||
break;
|
||||
}
|
||||
if ($today > $target) {
|
||||
$errors->add('reminder', 'Target date is too close to today to set reminders.');
|
||||
}
|
||||
}
|
||||
|
||||
$validator = \Validator::make($model, \PiggyBank::$rules);
|
||||
if ($validator->invalid()) {
|
||||
$errors->merge($errors);
|
||||
}
|
||||
|
||||
// add ok messages.
|
||||
$list = ['name', 'account_id', 'targetamount', 'targetdate', 'remind_me', 'reminder'];
|
||||
foreach ($list as $entry) {
|
||||
if (!$errors->has($entry) && !$warnings->has($entry)) {
|
||||
$successes->add($entry, 'OK');
|
||||
}
|
||||
}
|
||||
|
||||
return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes];
|
||||
}
|
||||
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
namespace FireflyIII\Database\PiggyBank;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Collection\PiggyBankPart;
|
||||
use FireflyIII\Database\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\CUD;
|
||||
@ -11,24 +10,14 @@ use FireflyIII\Database\SwitchUser;
|
||||
use FireflyIII\Exception\NotImplementedException;
|
||||
use Illuminate\Database\Eloquent\Model as Eloquent;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\MessageBag;
|
||||
|
||||
/**
|
||||
* Class RepeatedExpense
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggyBankInterface
|
||||
class RepeatedExpense extends PiggyBankShared implements CUD, CommonDatabaseCalls, PiggyBankInterface
|
||||
{
|
||||
use SwitchUser;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setUser(\Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the piggy bank, the reminder-setting and
|
||||
@ -97,17 +86,6 @@ class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggyBankInterface
|
||||
return $part;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Eloquent $model
|
||||
*
|
||||
* @return bool
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function destroy(Eloquent $model)
|
||||
{
|
||||
// TODO: Implement destroy() method.
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
@ -134,144 +112,6 @@ class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggyBankInterface
|
||||
return $repeated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Eloquent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function update(Eloquent $model, array $data)
|
||||
{
|
||||
// TODO: Implement update() method.
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
*
|
||||
* ignored because this method will be gone soon.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
$warnings = new MessageBag;
|
||||
$successes = new MessageBag;
|
||||
$errors = new MessageBag;
|
||||
|
||||
/*
|
||||
* Name validation:
|
||||
*/
|
||||
if (!isset($model['name'])) {
|
||||
$errors->add('name', 'Name is mandatory');
|
||||
}
|
||||
|
||||
if (isset($model['name']) && strlen($model['name']) == 0) {
|
||||
$errors->add('name', 'Name is too short');
|
||||
}
|
||||
if (isset($model['name']) && strlen($model['name']) > 100) {
|
||||
$errors->add('name', 'Name is too long');
|
||||
}
|
||||
|
||||
if (intval($model['account_id']) == 0) {
|
||||
$errors->add('account_id', 'Account is mandatory');
|
||||
}
|
||||
if ($model['targetdate'] == '' && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
|
||||
$errors->add('targetdate', 'Target date is mandatory when setting reminders.');
|
||||
}
|
||||
if ($model['targetdate'] != '') {
|
||||
try {
|
||||
new Carbon($model['targetdate']);
|
||||
} catch (\Exception $e) {
|
||||
$errors->add('targetdate', 'Invalid date.');
|
||||
}
|
||||
$diff = Carbon::now()->diff(new Carbon($model['targetdate']));
|
||||
if ($diff->days > 365) {
|
||||
$errors->add('targetdate', 'First target date should a a year or less from now.');
|
||||
}
|
||||
} else {
|
||||
$errors->add('targetdate', 'Invalid target date.');
|
||||
}
|
||||
if (floatval($model['targetamount']) < 0.01) {
|
||||
$errors->add('targetamount', 'Amount should be above 0.01.');
|
||||
}
|
||||
if (!in_array(ucfirst($model['reminder']), \Config::get('firefly.piggy_bank_periods'))) {
|
||||
$errors->add('reminder', 'Invalid reminder period (' . $model['reminder'] . ')');
|
||||
}
|
||||
|
||||
if (!in_array(ucfirst($model['rep_length']), \Config::get('firefly.piggy_bank_periods'))) {
|
||||
$errors->add('rep_length', 'Invalid repeat period (' . $model['rep_length'] . ')');
|
||||
}
|
||||
|
||||
// check period.
|
||||
if (!$errors->has('reminder') && !$errors->has('targetdate') && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
|
||||
$today = new Carbon;
|
||||
$target = new Carbon($model['targetdate']);
|
||||
switch ($model['reminder']) {
|
||||
case 'week':
|
||||
$today->addWeek();
|
||||
break;
|
||||
case 'month':
|
||||
$today->addMonth();
|
||||
break;
|
||||
case 'year':
|
||||
$today->addYear();
|
||||
break;
|
||||
}
|
||||
if ($today > $target) {
|
||||
$errors->add('reminder', 'Target date is too close to today to set reminders.');
|
||||
}
|
||||
}
|
||||
|
||||
$validator = \Validator::make($model, \PiggyBank::$rules);
|
||||
if ($validator->invalid()) {
|
||||
$errors->merge($errors);
|
||||
}
|
||||
|
||||
// add ok messages.
|
||||
$list = ['name', 'account_id', 'rep_every', 'rep_times', 'rep_length', 'targetamount', 'targetdate', 'remind_me', 'reminder'];
|
||||
foreach ($list as $entry) {
|
||||
if (!$errors->has($entry) && !$warnings->has($entry)) {
|
||||
$successes->add($entry, 'OK');
|
||||
}
|
||||
}
|
||||
|
||||
return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $objectId
|
||||
*
|
||||
* @return \Eloquent
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function find($objectId)
|
||||
{
|
||||
// TODO: Implement find() method.
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement findByWhat() method.
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
@ -282,27 +122,4 @@ class RepeatedExpense implements CUD, CommonDatabaseCalls, PiggyBankInterface
|
||||
return $this->getUser()->piggyBanks()->where('repeats', 1)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
*
|
||||
* @return float
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function leftOnAccount(\Account $account)
|
||||
{
|
||||
// TODO: Implement leftOnAccount() method.
|
||||
throw new NotImplementedException;
|
||||
}
|
||||
}
|
@ -241,12 +241,15 @@ class Date
|
||||
default:
|
||||
throw new FireflyException('Cannot do subtractPeriod for $repeat_freq ' . $repeatFreq);
|
||||
break;
|
||||
case 'day':
|
||||
case 'daily':
|
||||
$date->subDays($subtract);
|
||||
break;
|
||||
case 'week':
|
||||
case 'weekly':
|
||||
$date->subWeeks($subtract);
|
||||
break;
|
||||
case 'month':
|
||||
case 'monthly':
|
||||
$date->subMonths($subtract);
|
||||
break;
|
||||
|
@ -9,10 +9,10 @@ use Watson\Validating\ValidatingTrait;
|
||||
class PiggyBank extends Eloquent
|
||||
{
|
||||
use ValidatingTrait;
|
||||
public static $rules
|
||||
protected $rules
|
||||
= ['account_id' => 'required|exists:accounts,id', // link to Account
|
||||
'name' => 'required|between:1,255', // name
|
||||
'targetamount' => 'required|min:0', // amount you want to save
|
||||
'targetamount' => 'required|min:0.01|numeric', // amount you want to save
|
||||
'startdate' => 'date', // when you started
|
||||
'targetdate' => 'date', // when its due
|
||||
'repeats' => 'required|boolean', // does it repeat?
|
||||
|
@ -119,7 +119,7 @@ Route::bind(
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'piggy_bank', function ($value, $route) {
|
||||
'piggyBank', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return PiggyBank::
|
||||
where('piggy_banks.id', $value)
|
||||
@ -132,6 +132,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(
|
||||
'repeated', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
@ -198,7 +212,7 @@ Route::group(
|
||||
Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']);
|
||||
Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']);
|
||||
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']);
|
||||
Route::get('/chart/piggy_history/{piggy_bank}', ['uses' => 'GoogleChartController@piggyBankHistory']);
|
||||
Route::get('/chart/piggy_history/{piggyBank}', ['uses' => 'GoogleChartController@piggyBankHistory']);
|
||||
|
||||
// google chart for components (categories + budgets combined)
|
||||
Route::get('/chart/budget/{budget}/spending/{year}', ['uses' => 'GoogleChartController@budgetsAndSpending']);
|
||||
@ -219,13 +233,13 @@ Route::group(
|
||||
|
||||
// piggy bank controller
|
||||
Route::get('/piggy_banks', ['uses' => 'PiggyBankController@index', 'as' => 'piggy_banks.index']);
|
||||
Route::get('/piggy_banks/add/{piggy_bank}', ['uses' => 'PiggyBankController@add']); # add money
|
||||
Route::get('/piggy_banks/remove/{piggy_bank}', ['uses' => 'PiggyBankController@remove']); #remove money
|
||||
Route::get('/piggy_banks/add/{piggyBank}', ['uses' => 'PiggyBankController@add']); # add money
|
||||
Route::get('/piggy_banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove']); #remove money
|
||||
|
||||
Route::get('/piggy_banks/create', ['uses' => 'PiggyBankController@create', 'as' => 'piggy_banks.create']);
|
||||
Route::get('/piggy_banks/edit/{piggy_bank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy_banks.edit']);
|
||||
Route::get('/piggy_banks/delete/{piggy_bank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy_banks.delete']);
|
||||
Route::get('/piggy_banks/show/{piggy_bank}', ['uses' => 'PiggyBankController@show', 'as' => 'piggy_banks.show']);
|
||||
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']);
|
||||
|
||||
// preferences controller
|
||||
Route::get('/preferences', ['uses' => 'PreferencesController@index', 'as' => 'preferences']);
|
||||
@ -245,7 +259,9 @@ 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/show/{repeated}', ['uses' => 'RepeatedExpenseController@show', 'as' => 'repeated.show']);
|
||||
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']);
|
||||
|
||||
// report controller:
|
||||
Route::get('/reports', ['uses' => 'ReportController@index', 'as' => 'reports.index']);
|
||||
@ -314,13 +330,15 @@ Route::group(
|
||||
|
||||
// piggy bank controller
|
||||
Route::post('/piggy_banks/store', ['uses' => 'PiggyBankController@store', 'as' => 'piggy_banks.store']);
|
||||
Route::post('/piggy_banks/update/{piggy_bank}', ['uses' => 'PiggyBankController@update', 'as' => 'piggy_banks.update']);
|
||||
Route::post('/piggy_banks/destroy/{piggy_bank}', ['uses' => 'PiggyBankController@destroy', 'as' => 'piggy_banks.destroy']);
|
||||
Route::post('/piggy_banks/add/{piggy_bank}', ['uses' => 'PiggyBankController@postAdd', 'as' => 'piggy_banks.add']); # add money
|
||||
Route::post('/piggy_banks/remove/{piggy_bank}', ['uses' => 'PiggyBankController@postRemove', 'as' => 'piggy_banks.remove']); # remove money.
|
||||
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.
|
||||
|
||||
// repeated expense controller
|
||||
Route::post('/repeatedexpense/store', ['uses' => 'RepeatedExpenseController@store', 'as' => 'repeated.store']);
|
||||
Route::post('/repeatedexpense/update/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@update', 'as' => 'repeated.update']);
|
||||
Route::post('/repeatedexpense/destroy/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@destroy', 'as' => 'repeated.destroy']);
|
||||
|
||||
// preferences controller
|
||||
Route::post('/preferences', ['uses' => 'PreferencesController@postIndex']);
|
||||
|
@ -1,12 +1,34 @@
|
||||
@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 href="{{route('piggy_banks.create')}}" class="btn btn-success">Create new piggy bank</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@foreach($piggyBanks as $piggyBank)
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw fa-rocket"></i> <a href="{{route('piggy_banks.show',$piggyBank->id)}}" title="{{{$piggyBank->name}}}">{{{$piggyBank->name}}}</a>
|
||||
|
||||
<!-- ACTIONS MENU -->
|
||||
<div class="pull-right">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
|
||||
Actions
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li><a href="{{route('piggy_banks.edit',$piggyBank->id)}}"><i class="fa fa-pencil fa-fw"></i> Edit</a></li>
|
||||
<li><a href="{{route('piggy_banks.delete',$piggyBank->id)}}"><i class="fa fa-trash fa-fw"></i> Delete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
@ -61,19 +83,10 @@
|
||||
</div>
|
||||
@endforeach
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw fa-plus"></i> Create piggy bank
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-md-6 col-sm-4 col-lg-offset-2 col-md-offset-3 col-sm-offset-4">
|
||||
<a href="{{route('piggy_banks.create')}}" class="btn btn-success">Create new piggy bank</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p>
|
||||
<a href="{{route('piggy_banks.create')}}" class="btn btn-success">Create new piggy bank</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
37
app/views/repeatedexpense/delete.blade.php
Normal file
37
app/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
|
97
app/views/repeatedexpense/edit.blade.php
Normal file
97
app/views/repeatedexpense/edit.blade.php
Normal file
@ -0,0 +1,97 @@
|
||||
@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)])}}
|
||||
|
||||
<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">
|
||||
{{Form::ffText('name')}}
|
||||
{{Form::ffSelect('account_id',$accounts,null,['label' => 'Save on account'])}}
|
||||
{{Form::ffAmount('targetamount')}}
|
||||
{{Form::ffDate('targetdate',null,['label' => 'First target date'])}}
|
||||
{{Form::ffSelect('rep_length',$periods,null,['label' => 'Repeats every'])}}
|
||||
{{Form::ffInteger('rep_every',null,['label' => 'Skip period'])}}
|
||||
{{Form::ffInteger('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">
|
||||
{{Form::ffCheckbox('remind_me','1',$preFilled['remind_me'],['label' => 'Remind me'])}}
|
||||
{{Form::ffSelect('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">
|
||||
{{Form::ffOptionsList('update','piggy bank')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{--
|
||||
|
||||
<h4>Mandatory fields</h4>
|
||||
|
||||
<h4>Optional fields</h4>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}}
|
||||
<div class="col-sm-8">
|
||||
<input type="number" step="1" min="1" value="{{Input::old('reminder_skip') ?: 1}}" style="width:50px;display:inline;" max="100" name="reminder_skip" class="form-control" />
|
||||
|
||||
<select class="form-control" name="reminder" style="width:150px;display: inline">
|
||||
<option value="none" label="do not remind me">do not remind me</option>
|
||||
@foreach($periods as $period)
|
||||
<option value="{{$period}}" label="{{$period}}">{{$period}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@if($errors->has('reminder'))
|
||||
<p class="text-danger">{{$errors->first('reminder')}}</p>
|
||||
@else
|
||||
<span class="help-block">Enter a number and a period and Firefly will remind you to add money
|
||||
to this piggy bank every now and then.</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-4 col-sm-8">
|
||||
<button type="submit" class="btn btn-default btn-success">Create the piggy bank</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
--}}
|
||||
|
||||
{{Form::close()}}
|
||||
@stop
|
@ -4,24 +4,34 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p>
|
||||
<a class="btn btn-lg btn-success" href="{{route('repeated.create')}}">Create new repeated expense</a>
|
||||
<a class="btn btn-success" href="{{route('repeated.create')}}">Create new repeated expense</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO create update and destroy -->
|
||||
|
||||
@foreach($expenses as $entry)
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO create update and destroy -->
|
||||
<div class="row">
|
||||
@foreach($expenses as $entry)
|
||||
<div class="col-lg-3 col-md-4 col-sm-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="{{route('repeated.show',$entry->id)}}" title="{{{$entry->name}}}">{{{$entry->name}}}</a>
|
||||
({{mf($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">
|
||||
@ -40,7 +50,16 @@
|
||||
</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>
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $piggyBank) }}
|
||||
{{ Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $repeatedExpense) }}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
@foreach($repetitions as $rep)
|
||||
@ -21,7 +21,7 @@
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
Target amount: {{mf($piggyBank->targetamount)}}. Currently saved: {{mf($rep->currentamount)}}.
|
||||
Target amount: {{mf($repeatedExpense->targetamount)}}. Currently saved: {{mf($rep->currentamount)}}.
|
||||
</p>
|
||||
<div class="row">
|
||||
@foreach($rep->bars as $bar)
|
||||
|
@ -42,12 +42,22 @@
|
||||
</tr>
|
||||
@foreach($budgets as $id => $budget)
|
||||
<tr>
|
||||
<td>{{{$budget['name']}}}</td>
|
||||
<td>{{{$budget['name']}}}
|
||||
@if($id == 0)
|
||||
<i class="fa fa-fw fa-question-circle" data-toggle="tooltip" data-placement="top" title="The calculation used here is slightly different from the row below. The numbers should match."></i>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{mf($budget['amount'])}}</td>
|
||||
<?php $spent = 0;?>
|
||||
@foreach($accounts as $account)
|
||||
@if(isset($account->budgetInformation[$id]))
|
||||
<td>{{mf($account->budgetInformation[$id]['amount'])}}</td>
|
||||
<td>
|
||||
@if($id == 0)
|
||||
<a href="#">{{mf($account->budgetInformation[$id]['amount'])}}</a>
|
||||
@else
|
||||
{{mf($account->budgetInformation[$id]['amount'])}}
|
||||
@endif
|
||||
</td>
|
||||
<?php
|
||||
$spent += floatval($account->budgetInformation[$id]['amount']);
|
||||
$accountSums[$account->id] += floatval($account->budgetInformation[$id]['amount']);
|
||||
@ -61,10 +71,14 @@
|
||||
</tr>
|
||||
@endforeach
|
||||
<tr>
|
||||
<td colspan="2">Without budget</td>
|
||||
<td colspan="2">Without budget
|
||||
<i class="fa fa-fw fa-question-circle" data-toggle="tooltip" data-placement="top" title="The calculation used here is slightly different from the row above. The numbers should match."></i>
|
||||
</td>
|
||||
@foreach($accounts as $account)
|
||||
@if(isset($account->budgetInformation[0]))
|
||||
<td>{{mf($account->budgetInformation[0]['amount'])}}</td>
|
||||
<td>
|
||||
<a href="#">{{mf($account->budgetInformation[0]['amount'])}}</a>
|
||||
</td>
|
||||
@else
|
||||
<td>{{mf(0)}}</td>
|
||||
@endif
|
||||
@ -74,7 +88,9 @@
|
||||
<tr>
|
||||
<td colspan="2">Balanced by transfers</td>
|
||||
@foreach($accounts as $account)
|
||||
<td>{{mf($account->balancedAmount)}}</td>
|
||||
<td>
|
||||
<a href="#">{{mf($account->balancedAmount)}}</a>
|
||||
</td>
|
||||
@endforeach
|
||||
<td colspan="2"> </td>
|
||||
</tr>
|
||||
@ -101,7 +117,9 @@
|
||||
$accountSums[$account->id] += $account->balancedAmount;
|
||||
?>
|
||||
@if(isset($account->budgetInformation[0]))
|
||||
<td>{{mf($account->budgetInformation[0]['amount'] + $account->balancedAmount)}}</td>
|
||||
<td>
|
||||
<a href="#">{{mf($account->budgetInformation[0]['amount'] + $account->balancedAmount)}}</a>
|
||||
</td>
|
||||
@else
|
||||
<td>{{mf(0)}}</td>
|
||||
@endif
|
||||
@ -126,4 +144,13 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- modal to show various budget information -->
|
||||
<div class="modal fade" id="budgetModal">
|
||||
|
||||
</div>
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
{{HTML::script('assets/javascript/firefly/reports.js')}}
|
||||
@stop
|
@ -1,5 +1,8 @@
|
||||
$(function () {
|
||||
$('#help').click(showHelp);
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
})
|
||||
});
|
||||
|
||||
function showHelp(e) {
|
||||
|
@ -1,5 +1,8 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class PreferencesControllerCest
|
||||
*/
|
||||
class PreferencesControllerCest
|
||||
{
|
||||
/**
|
||||
|
23
tests/functional/RepeatedExpenseCest.php
Normal file
23
tests/functional/RepeatedExpenseCest.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class RepeatedExpenseCest
|
||||
*/
|
||||
class RepeatedExpenseCest {
|
||||
/**
|
||||
* @param FunctionalTester $I
|
||||
*/
|
||||
public function _after(FunctionalTester $I)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FunctionalTester $I
|
||||
*/
|
||||
public function _before(FunctionalTester $I)
|
||||
{
|
||||
$I->amLoggedAs(['email' => 'thegrumpydictator@gmail.com', 'password' => 'james']);
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user