mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-12 01:42:32 +00:00
New event to create budget limits, new handler to handle said event, new routes for budget control, new routes for limit control, extended migration, extended models, extended JS. [skip-ci]
This commit is contained in:
97
app/controllers/BudgetController.php
Normal file
97
app/controllers/BudgetController.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
use Firefly\Storage\Budget\BudgetRepositoryInterface as BRI;
|
||||
|
||||
class BudgetController extends BaseController
|
||||
{
|
||||
|
||||
protected $_budgets;
|
||||
|
||||
public function __construct(BRI $budgets)
|
||||
{
|
||||
$this->_budgets = $budgets;
|
||||
View::share('menu', 'budgets');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$budgets = $this->_budgets->get();
|
||||
$today = new \Carbon\Carbon;
|
||||
|
||||
|
||||
return View::make('budgets.index')->with('budgets', $budgets)->with('today', $today);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
|
||||
$periods = [
|
||||
'weekly' => 'A week',
|
||||
'monthly' => 'A month',
|
||||
'quarterly' => 'A quarter',
|
||||
'half-year' => 'Six months',
|
||||
'yearly' => 'A year',
|
||||
];
|
||||
|
||||
return View::make('budgets.create')->with('periods', $periods);
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
|
||||
$data = [
|
||||
'name' => Input::get('name'),
|
||||
'amount' => floatval(Input::get('amount')),
|
||||
'repeat_freq' => Input::get('period'),
|
||||
'repeats' => intval(Input::get('repeats'))
|
||||
];
|
||||
|
||||
$budget = $this->_budgets->create($data);
|
||||
Session::flash('success', 'Budget created!');
|
||||
return Redirect::route('budgets.index');
|
||||
}
|
||||
|
||||
public function show($budgetId)
|
||||
{
|
||||
$budget = $this->_budgets->find($budgetId);
|
||||
|
||||
$list = $budget->transactionjournals()->get();
|
||||
$return = [];
|
||||
/** @var \TransactionJournal $entry */
|
||||
foreach ($list as $entry) {
|
||||
$month = $entry->date->format('F Y');
|
||||
$return[$month] = isset($return[$month]) ? $return[$month] : [];
|
||||
|
||||
$return[$month][] = $entry;
|
||||
|
||||
}
|
||||
|
||||
foreach ($return as $month => $set) {
|
||||
echo '<h1>' . $month . '</h1>';
|
||||
/** @var \TransactionJournal $tj */
|
||||
$sum = 0;
|
||||
foreach ($set as $tj) {
|
||||
echo '#' . $tj->id . ' ' . $tj->description . ': ';
|
||||
|
||||
foreach ($tj->transactions as $index => $t) {
|
||||
echo $t->amount . ', ';
|
||||
if ($index == 0) {
|
||||
$sum += $t->amount;
|
||||
|
||||
}
|
||||
}
|
||||
echo '<br>';
|
||||
|
||||
}
|
||||
echo 'sum: ' . $sum . '<br><br>';
|
||||
}
|
||||
|
||||
|
||||
exit;
|
||||
|
||||
return View::make('budgets.show');
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,9 @@ class HomeController extends BaseController
|
||||
$this->_preferences = $preferences;
|
||||
$this->_journal = $journal;
|
||||
View::share('menu', 'home');
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,10 +33,28 @@ class HomeController extends BaseController
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// get the accounts to display on the home screen:
|
||||
// count, maybe we need some introductionary text to show:
|
||||
$count = $this->_accounts->count();
|
||||
|
||||
|
||||
// get the preference for the home accounts to show:
|
||||
$frontpage = $this->_preferences->get('frontpageAccounts', []);
|
||||
|
||||
$accounts = $this->_accounts->getByIds($frontpage->data);
|
||||
|
||||
$transactions = [];
|
||||
foreach($accounts as $account) {
|
||||
$transactions[] = [$this->_journal->getByAccount($account,15),$account];
|
||||
}
|
||||
|
||||
if(count($transactions) % 2 == 0) {
|
||||
$transactions = array_chunk($transactions, 2);
|
||||
} elseif(count($transactions) == 1) {
|
||||
$transactions = array_chunk($transactions, 3);
|
||||
} else {
|
||||
$transactions = array_chunk($transactions, 3);
|
||||
}
|
||||
// build the home screen:
|
||||
return View::make('index')->with('count', $count);
|
||||
return View::make('index')->with('count', $count)->with('transactions',$transactions);
|
||||
}
|
||||
}
|
||||
49
app/controllers/LimitController.php
Normal file
49
app/controllers/LimitController.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
use Firefly\Storage\Budget\BudgetRepositoryInterface as BRI;
|
||||
use Firefly\Storage\Limit\LimitRepositoryInterface as LRI;
|
||||
|
||||
class LimitController extends BaseController
|
||||
{
|
||||
|
||||
protected $_budgets;
|
||||
protected $_limits;
|
||||
|
||||
public function __construct(BRI $budgets, LRI $limits)
|
||||
{
|
||||
$this->_budgets = $budgets;
|
||||
$this->_limits = $limits;
|
||||
View::share('menu', 'budgets');
|
||||
|
||||
}
|
||||
|
||||
public function create($budgetId = null)
|
||||
{
|
||||
$periods = [
|
||||
'weekly' => 'A week',
|
||||
'monthly' => 'A month',
|
||||
'quarterly' => 'A quarter',
|
||||
'half-year' => 'Six months',
|
||||
'yearly' => 'A year',
|
||||
];
|
||||
|
||||
$budget = $this->_budgets->find($budgetId);
|
||||
$budget_id = is_null($budget) ? null : $budget->id;
|
||||
$budgets = $this->_budgets->getAsSelectList();
|
||||
return View::make('limits.create')->with('budgets', $budgets)->with('budget_id', $budget_id)->with(
|
||||
'periods', $periods
|
||||
);
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
// find a limit with these properties, as we might already have one:
|
||||
$limit = $this->_limits->store(Input::all());
|
||||
if($limit->id) {
|
||||
return Redirect::route('budgets.index');
|
||||
} else {
|
||||
return Redirect::route('budgets.limits.create')->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Carbon\Carbon as Carbon;
|
||||
use Firefly\Helper\Migration\MigrationHelperInterface as MHI;
|
||||
|
||||
/**
|
||||
@@ -40,10 +41,123 @@ class MigrationController extends BaseController
|
||||
exit();
|
||||
}
|
||||
}
|
||||
echo '<a href="'.route('index').'">home</a>';
|
||||
echo '<a href="' . route('index') . '">home</a>';
|
||||
exit();
|
||||
}
|
||||
|
||||
public function limit()
|
||||
{
|
||||
$user = User::find(1);
|
||||
$budgets = [];
|
||||
// new budget
|
||||
for ($i = 0; $i < 7; $i++) {
|
||||
$budget = new Budget();
|
||||
$budget->user()->associate($user);
|
||||
$budget->name = 'Some budget #' . rand(1, 2000);
|
||||
$budget->save();
|
||||
$budgets[] = $budget;
|
||||
}
|
||||
|
||||
// create a non-repeating limit for this week:
|
||||
$today = new Carbon('01-07-2014');
|
||||
|
||||
$limit = new Limit;
|
||||
$limit->budget()->associate($budgets[0]);
|
||||
$limit->amount = 100;
|
||||
$limit->startdate = $today;
|
||||
$limit->amount = 100;
|
||||
$limit->repeats = 0;
|
||||
$limit->repeat_freq = 'weekly';
|
||||
|
||||
var_dump($limit->save());
|
||||
var_dump($limit->errors()->all());
|
||||
|
||||
|
||||
// create a repeating daily limit:
|
||||
$day = new Limit;
|
||||
$day->budget()->associate($budgets[1]);
|
||||
$day->amount = 100;
|
||||
$day->startdate = $today;
|
||||
$day->amount = 100;
|
||||
$day->repeats = 1;
|
||||
$day->repeat_freq = 'daily';
|
||||
$day->save();
|
||||
|
||||
// repeating weekly limit.
|
||||
$week = new Limit;
|
||||
$week->budget()->associate($budgets[2]);
|
||||
$week->amount = 100;
|
||||
$week->startdate = $today;
|
||||
$week->amount = 100;
|
||||
$week->repeats = 1;
|
||||
$week->repeat_freq = 'weekly';
|
||||
$week->save();
|
||||
|
||||
// repeating monthly limit
|
||||
$month = new Limit;
|
||||
$month->budget()->associate($budgets[3]);
|
||||
$month->amount = 100;
|
||||
$month->startdate = $today;
|
||||
$month->amount = 100;
|
||||
$month->repeats = 1;
|
||||
$month->repeat_freq = 'monthly';
|
||||
$month->save();
|
||||
|
||||
// quarter
|
||||
$quarter = new Limit;
|
||||
$quarter->budget()->associate($budgets[4]);
|
||||
$quarter->amount = 100;
|
||||
$quarter->startdate = $today;
|
||||
$quarter->amount = 100;
|
||||
$quarter->repeats = 1;
|
||||
$quarter->repeat_freq = 'quarterly';
|
||||
$quarter->save();
|
||||
|
||||
// six months
|
||||
$six = new Limit;
|
||||
$six->budget()->associate($budgets[5]);
|
||||
$six->amount = 100;
|
||||
$six->startdate = $today;
|
||||
$six->amount = 100;
|
||||
$six->repeats = 1;
|
||||
$six->repeat_freq = 'half-year';
|
||||
$six->save();
|
||||
|
||||
// year
|
||||
$yearly = new Limit;
|
||||
$yearly->budget()->associate($budgets[6]);
|
||||
$yearly->amount = 100;
|
||||
$yearly->startdate = $today;
|
||||
$yearly->amount = 100;
|
||||
$yearly->repeats = 1;
|
||||
$yearly->repeat_freq = 'yearly';
|
||||
$yearly->save();
|
||||
|
||||
|
||||
// create a repeating weekly limit:
|
||||
// create a repeating monthly limit:
|
||||
|
||||
foreach ($budgets as $budget) {
|
||||
|
||||
echo '#' . $budget->id . ': ' . $budget->name . ':<br />';
|
||||
foreach ($budget->limits()->get() as $limit) {
|
||||
echo ' Limit #' . $limit->id . ', amount: ' . $limit->amount . ', start: '
|
||||
. $limit->startdate->format('D d-m-Y') . ', repeats: '
|
||||
. $limit->repeats . ', repeat_freq: ' . $limit->repeat_freq . '<br />';
|
||||
|
||||
foreach ($limit->limitrepetitions()->get() as $rep) {
|
||||
echo ' rep: #' . $rep->id . ', from ' . $rep->startdate->format('D d-m-Y')
|
||||
. ' to '
|
||||
. $rep->enddate->format('D d-m-Y') . '<br>';
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
|
||||
@@ -18,8 +18,9 @@ class CreateLimitsTable extends Migration {
|
||||
$table->timestamps();
|
||||
$table->integer('component_id')->unsigned();
|
||||
$table->date('startdate');
|
||||
$table->date('enddate');
|
||||
$table->decimal('amount',10,2);
|
||||
$table->boolean('repeats');
|
||||
$table->enum('repeat_freq', ['daily', 'weekly','monthly','quarterly','half-year','yearly']);
|
||||
|
||||
// connect component
|
||||
$table->foreign('component_id')
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateLimitRepeatTable extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('limit_repetitions', function(Blueprint $table)
|
||||
{
|
||||
$table->increments('id');
|
||||
$table->timestamps();
|
||||
$table->integer('limit_id')->unsigned();
|
||||
$table->date('startdate');
|
||||
$table->date('enddate');
|
||||
$table->decimal('amount',10,2);
|
||||
|
||||
$table->unique(['limit_id','startdate','enddate']);
|
||||
|
||||
// connect limit
|
||||
$table->foreign('limit_id')
|
||||
->references('id')->on('limits')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('limit_repetitions');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ App::before(
|
||||
if (Auth::check()) {
|
||||
\Firefly\Helper\Toolkit\Toolkit::getDateRange();
|
||||
}
|
||||
Event::fire('app.before');
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace Firefly\Helper\Migration;
|
||||
|
||||
|
||||
use Firefly\Helper\MigrationException;
|
||||
|
||||
class MigrationHelper implements MigrationHelperInterface
|
||||
{
|
||||
protected $path;
|
||||
@@ -56,6 +58,9 @@ class MigrationHelper implements MigrationHelperInterface
|
||||
// create transfers:
|
||||
$this->_importTransfers();
|
||||
|
||||
// create limits:
|
||||
$this->_importLimits();
|
||||
|
||||
|
||||
} catch (\Firefly\Exception\FireflyException $e) {
|
||||
\DB::rollBack();
|
||||
@@ -75,7 +80,7 @@ class MigrationHelper implements MigrationHelperInterface
|
||||
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accounts */
|
||||
$accounts = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
|
||||
$cash = $accounts->store(['name' => 'Cash account', 'account_type' => $cashAT, 'active' => 0]);
|
||||
\Log::info('Created cash account (#'.$cash->id.')');
|
||||
\Log::info('Created cash account (#' . $cash->id . ')');
|
||||
$this->map['cash'] = $cash;
|
||||
}
|
||||
|
||||
@@ -149,6 +154,39 @@ class MigrationHelper implements MigrationHelperInterface
|
||||
return $components->store(['name' => $component->name, 'class' => 'Budget']);
|
||||
}
|
||||
|
||||
protected function _importLimits()
|
||||
{
|
||||
\Log::info('Importing limits');
|
||||
foreach ($this->JSON->limits as $entry) {
|
||||
\Log::debug(
|
||||
'Now at #' . $entry->id . ': EUR ' . $entry->amount . ' for month ' . $entry->date
|
||||
. ' and componentID: ' . $entry->component_id
|
||||
);
|
||||
$budget = isset($this->map['budgets'][$entry->component_id]) ? $this->map['budgets'][$entry->component_id]
|
||||
: null;
|
||||
if (!is_null($budget)) {
|
||||
\Log::debug('Found budget for this limit: #' . $budget->id . ', ' . $budget->name);
|
||||
|
||||
$limit = new \Limit;
|
||||
$limit->budget()->associate($budget);
|
||||
$limit->startdate = new \Carbon\Carbon($entry->date);
|
||||
$limit->amount = floatval($entry->amount);
|
||||
$limit->repeats = 0;
|
||||
$limit->repeat_freq = 'monthly';
|
||||
if (!$limit->save()) {
|
||||
\Log::error('MigrationException!');
|
||||
throw new MigrationException('Importing limits failed: ' . $limit->errors()->first());
|
||||
}
|
||||
} else {
|
||||
\Log::warning('No budget for this limit!');
|
||||
}
|
||||
|
||||
|
||||
// create repeat thing should not be necessary.
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected function _importTransactions()
|
||||
{
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
|
||||
|
||||
public function get()
|
||||
{
|
||||
return \Auth::user()->accounts()->with('accounttype')->orderBy('name','ASC')->get();
|
||||
return \Auth::user()->accounts()->with('accounttype')->orderBy('name', 'ASC')->get();
|
||||
}
|
||||
|
||||
public function getBeneficiaries()
|
||||
@@ -23,7 +23,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
|
||||
)
|
||||
->where('account_types.description', 'Beneficiary account')->where('accounts.active', 1)
|
||||
|
||||
->orderBy('accounts.name','ASC')->get(['accounts.*']);
|
||||
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
|
||||
return $list;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,11 @@ class EloquentAccountRepository implements AccountRepositoryInterface
|
||||
|
||||
public function getByIds($ids)
|
||||
{
|
||||
return \Auth::user()->accounts()->with('accounttype')->whereIn('id', $ids)->orderBy('name','ASC')->get();
|
||||
if (count($ids) > 0) {
|
||||
return \Auth::user()->accounts()->with('accounttype')->whereIn('id', $ids)->orderBy('name', 'ASC')->get();
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public function getDefault()
|
||||
@@ -42,7 +46,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
|
||||
return \Auth::user()->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
||||
->where('account_types.description', 'Default account')
|
||||
|
||||
->orderBy('accounts.name','ASC')->get(['accounts.*']);
|
||||
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
|
||||
}
|
||||
|
||||
public function getActiveDefault()
|
||||
@@ -60,7 +64,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
|
||||
)
|
||||
->where('account_types.description', 'Default account')->where('accounts.active', 1)
|
||||
|
||||
->orderBy('accounts.name','ASC')->get(['accounts.*']);
|
||||
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[intval($entry->id)] = $entry->name;
|
||||
|
||||
@@ -6,6 +6,9 @@ namespace Firefly\Storage\Budget;
|
||||
interface BudgetRepositoryInterface
|
||||
{
|
||||
public function getAsSelectList();
|
||||
public function get();
|
||||
|
||||
public function create($data);
|
||||
|
||||
public function find($id);
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ class EloquentBudgetRepository implements BudgetRepositoryInterface
|
||||
|
||||
public function getAsSelectList()
|
||||
{
|
||||
$list = \Auth::user()->budgets()->get();
|
||||
$list = \Auth::user()->budgets()->with(
|
||||
['limits', 'limits.limitrepetitions']
|
||||
)->orderBy('name', 'ASC')->get();
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[intval($entry->id)] = $entry->name;
|
||||
@@ -16,6 +18,63 @@ class EloquentBudgetRepository implements BudgetRepositoryInterface
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function create($data)
|
||||
{
|
||||
$budget = new \Budget;
|
||||
$budget->name = $data['name'];
|
||||
$budget->user()->associate(\Auth::user());
|
||||
$budget->save();
|
||||
|
||||
// if limit, create limit (repetition itself will be picked up elsewhere).
|
||||
if ($data['amount'] > 0) {
|
||||
$limit = new \Limit;
|
||||
$limit->budget()->associate($budget);
|
||||
$startDate = new \Carbon\Carbon;
|
||||
switch ($data['repeat_freq']) {
|
||||
case 'daily':
|
||||
$startDate->startOfDay();
|
||||
break;
|
||||
case 'weekly':
|
||||
$startDate->startOfWeek();
|
||||
break;
|
||||
case 'monthly':
|
||||
$startDate->startOfMonth();
|
||||
break;
|
||||
case 'quarterly':
|
||||
$startDate->firstOfQuarter();
|
||||
break;
|
||||
case 'half-year':
|
||||
$startDate->startOfYear();
|
||||
if (intval($startDate->format('m')) >= 7) {
|
||||
$startDate->addMonths(6);
|
||||
}
|
||||
break;
|
||||
case 'yearly':
|
||||
$startDate->startOfYear();
|
||||
break;
|
||||
}
|
||||
$limit->startdate = $startDate;
|
||||
$limit->amount = $data['amount'];
|
||||
$limit->repeats = $data['repeats'];
|
||||
$limit->repeat_freq = $data['repeat_freq'];
|
||||
$limit->save();
|
||||
}
|
||||
|
||||
|
||||
return $budget;
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
return \Auth::user()->budgets()->with(
|
||||
['limits' => function ($q) {
|
||||
$q->orderBy('limits.startdate','ASC');
|
||||
}, 'limits.limitrepetitions' => function ($q) {
|
||||
$q->orderBy('limit_repetitions.startdate','ASC');
|
||||
}]
|
||||
)->orderBy('name', 'ASC')->get();
|
||||
}
|
||||
|
||||
public function find($id)
|
||||
{
|
||||
|
||||
|
||||
84
app/lib/Firefly/Storage/Limit/EloquentLimitRepository.php
Normal file
84
app/lib/Firefly/Storage/Limit/EloquentLimitRepository.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: sander
|
||||
* Date: 20/07/14
|
||||
* Time: 13:43
|
||||
*/
|
||||
|
||||
namespace Firefly\Storage\Limit;
|
||||
|
||||
|
||||
class EloquentLimitRepository implements LimitRepositoryInterface
|
||||
{
|
||||
public function store($data)
|
||||
{
|
||||
$budget = \Budget::find($data['budget_id']);
|
||||
if (is_null($budget)) {
|
||||
\Session::flash('error', 'No such budget.');
|
||||
return new \Limit;
|
||||
}
|
||||
// set the date to the correct start period:
|
||||
$date = new \Carbon\Carbon($data['startdate']);
|
||||
switch ($data['period']) {
|
||||
case 'daily':
|
||||
$date->startOfDay();
|
||||
break;
|
||||
case 'weekly':
|
||||
$date->startOfWeek();
|
||||
break;
|
||||
case 'monthly':
|
||||
$date->startOfMonth();
|
||||
break;
|
||||
case 'quarterly':
|
||||
$date->firstOfQuarter();
|
||||
break;
|
||||
case 'half-year':
|
||||
|
||||
if (intval($date->format('m')) >= 7) {
|
||||
$date->startOfYear();
|
||||
$date->addMonths(6);
|
||||
} else {
|
||||
$date->startOfYear();
|
||||
}
|
||||
break;
|
||||
case 'yearly':
|
||||
$date->startOfYear();
|
||||
break;
|
||||
}
|
||||
// find existing:
|
||||
$count = \Limit::
|
||||
leftJoin('components', 'components.id', '=', 'limits.component_id')->where(
|
||||
'components.user_id', \Auth::user()->id
|
||||
)->where('startdate', $date->format('Y-m-d'))->where('component_id', $data['budget_id'])->where(
|
||||
'repeat_freq', $data['period']
|
||||
)->count();
|
||||
if ($count > 0) {
|
||||
\Session::flash('error', 'There already is an entry for these parameters.');
|
||||
return new \Limit;
|
||||
}
|
||||
// create new limit:
|
||||
$limit = new \Limit;
|
||||
$limit->budget()->associate($budget);
|
||||
$limit->startdate = $date;
|
||||
$limit->amount = floatval($data['amount']);
|
||||
$limit->repeats = isset($data['repeats']) ? intval($data['repeats']) : 0;
|
||||
$limit->repeat_freq = $data['period'];
|
||||
if (!$limit->save()) {
|
||||
Session::flash('error', 'Could not save: ' . $limit->errors()->first());
|
||||
}
|
||||
return $limit;
|
||||
}
|
||||
|
||||
public function getTJByBudgetAndDateRange(\Budget $budget, \Carbon\Carbon $start, \Carbon\Carbon $end)
|
||||
{
|
||||
$type = \TransactionType::where('type', 'Withdrawal')->first();
|
||||
|
||||
$result = $budget->transactionjournals()->after($start)->
|
||||
before($end)->get();
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
12
app/lib/Firefly/Storage/Limit/LimitRepositoryInterface.php
Normal file
12
app/lib/Firefly/Storage/Limit/LimitRepositoryInterface.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Firefly\Storage\Limit;
|
||||
|
||||
|
||||
interface LimitRepositoryInterface
|
||||
{
|
||||
|
||||
public function store($data);
|
||||
|
||||
public function getTJByBudgetAndDateRange(\Budget $budget, \Carbon\Carbon $start, \Carbon\Carbon $end);
|
||||
}
|
||||
@@ -34,6 +34,11 @@ class StorageServiceProvider extends ServiceProvider
|
||||
'Firefly\Storage\Component\EloquentComponentRepository'
|
||||
);
|
||||
|
||||
$this->app->bind(
|
||||
'Firefly\Storage\Limit\LimitRepositoryInterface',
|
||||
'Firefly\Storage\Limit\EloquentLimitRepository'
|
||||
);
|
||||
|
||||
$this->app->bind(
|
||||
'Firefly\Storage\Budget\BudgetRepositoryInterface',
|
||||
'Firefly\Storage\Budget\EloquentBudgetRepository'
|
||||
|
||||
178
app/lib/Firefly/Trigger/Limits/EloquentLimitTrigger.php
Normal file
178
app/lib/Firefly/Trigger/Limits/EloquentLimitTrigger.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
namespace Firefly\Trigger\Limits;
|
||||
|
||||
/**
|
||||
* Class EloquentLimitTrigger
|
||||
*
|
||||
* @package Firefly\Trigger\Limits
|
||||
*/
|
||||
class EloquentLimitTrigger
|
||||
{
|
||||
|
||||
public function updateLimitRepetitions()
|
||||
{
|
||||
if (!\Auth::check()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get budgets with limits:
|
||||
$budgets = \Auth::user()->budgets()
|
||||
->with(['limits', 'limits.limitrepetitions'])
|
||||
->whereNotNull('limits.id')
|
||||
->leftJoin('limits', 'components.id', '=', 'limits.component_id')->get(['components.*']);
|
||||
|
||||
// get todays date.
|
||||
|
||||
foreach ($budgets as $budget) {
|
||||
\Log::debug(
|
||||
'Now checking the ' . count($budget->limits) . ' limits in ' . $budget->name . ' (#' . $budget->id
|
||||
. ').'
|
||||
);
|
||||
// loop limits:
|
||||
foreach ($budget->limits as $limit) {
|
||||
\Log::debug(
|
||||
'Now at limit #' . $limit->id . ', which has ' . count($limit->limitrepetitions) . ' reps already'
|
||||
);
|
||||
\Log::debug(
|
||||
'More: Amount: ' . $limit->amount . ', repeat: ' . $limit->repeats . ', freq: '
|
||||
. $limit->repeat_freq
|
||||
);
|
||||
// should have a repetition, at the very least
|
||||
// for the period it starts (startdate and onwards).
|
||||
if (count($limit->limitrepetitions) == 0) {
|
||||
\Log::debug('No reps, create one.');
|
||||
// create such a repetition:
|
||||
$repetition = new \LimitRepetition();
|
||||
$start = clone $limit->startdate;
|
||||
$end = clone $start;
|
||||
|
||||
// go to end:
|
||||
switch ($limit->repeat_freq) {
|
||||
case 'daily':
|
||||
$end->addDay();
|
||||
break;
|
||||
case 'weekly':
|
||||
$end->addWeek();
|
||||
break;
|
||||
case 'monthly':
|
||||
$end->addMonth();
|
||||
break;
|
||||
case 'quarterly':
|
||||
$end->addMonths(3);
|
||||
break;
|
||||
case 'half-year':
|
||||
$end->addMonths(6);
|
||||
break;
|
||||
case 'yearly':
|
||||
$end->addYear();
|
||||
break;
|
||||
}
|
||||
$end->subDay();
|
||||
$repetition->startdate = $start;
|
||||
$repetition->enddate = $end;
|
||||
$repetition->amount = $limit->amount;
|
||||
$repetition->limit()->associate($limit);
|
||||
\Log::debug('Created single rep for non-repeating limit, from ' . $start . ' until ' . $end);
|
||||
|
||||
try {
|
||||
$repetition->save();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
// do nothing
|
||||
\Log::error($e->getMessage());
|
||||
}
|
||||
} else {
|
||||
// there are limits already, do they
|
||||
// fall into the range surrounding today?
|
||||
$today = new \Carbon\Carbon;
|
||||
$today->addMonths(2);
|
||||
if ($limit->repeats == 1 && $today >= $limit->startdate) {
|
||||
|
||||
/** @var \Carbon\Carbon $flowStart */
|
||||
$flowStart = clone $today;
|
||||
/** @var \Carbon\Carbon $flowEnd */
|
||||
$flowEnd = clone $today;
|
||||
|
||||
switch ($limit->repeat_freq) {
|
||||
case 'daily':
|
||||
$flowStart->startOfDay();
|
||||
$flowEnd->endOfDay();
|
||||
break;
|
||||
case 'weekly':
|
||||
$flowStart->startOfWeek();
|
||||
$flowEnd->endOfWeek();
|
||||
break;
|
||||
case 'monthly':
|
||||
$flowStart->startOfMonth();
|
||||
$flowEnd->endOfMonth();
|
||||
break;
|
||||
case 'quarterly':
|
||||
$flowStart->firstOfQuarter();
|
||||
$flowEnd->startOfMonth()->lastOfQuarter()->endOfDay();
|
||||
break;
|
||||
case 'half-year':
|
||||
|
||||
if (intval($flowStart->format('m')) >= 7) {
|
||||
$flowStart->startOfYear();
|
||||
$flowStart->addMonths(6);
|
||||
} else {
|
||||
$flowStart->startOfYear();
|
||||
}
|
||||
|
||||
$flowEnd->endOfYear();
|
||||
if (intval($start->format('m')) <= 6) {
|
||||
$flowEnd->subMonths(6);
|
||||
$flowEnd->subDay();
|
||||
|
||||
}
|
||||
break;
|
||||
case 'yearly':
|
||||
$flowStart->startOfYear();
|
||||
$flowEnd->endOfYear();
|
||||
break;
|
||||
}
|
||||
|
||||
$inRange = false;
|
||||
foreach ($limit->limitrepetitions as $rep) {
|
||||
if ($rep->startdate->format('dmY') == $flowStart->format('dmY')
|
||||
&& $rep->enddate->format('dmY') == $flowEnd->format('dmY')
|
||||
) {
|
||||
// falls in current range, do nothing?
|
||||
$inRange = true;
|
||||
}
|
||||
}
|
||||
// if there is none that fall in range, create!
|
||||
if ($inRange === false) {
|
||||
// create (but check first)!
|
||||
$count = \LimitRepetition::where('limit_id', $limit->id)->where('startdate', $flowStart)
|
||||
->where('enddate', $flowEnd)->count();
|
||||
if ($count == 0) {
|
||||
$repetition = new \LimitRepetition;
|
||||
$repetition->startdate = $flowStart;
|
||||
$repetition->enddate = $flowEnd;
|
||||
$repetition->amount = $limit->amount;
|
||||
$repetition->limit()->associate($limit);
|
||||
try {
|
||||
$repetition->save();
|
||||
} catch (\Illuminate\Database\QueryException $e) {
|
||||
// do nothing
|
||||
\Log::error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
\Log::debug('Done checking the budget!');
|
||||
}
|
||||
}
|
||||
|
||||
public function subscribe(\Illuminate\Events\Dispatcher $events)
|
||||
{
|
||||
$events->listen('app.before', 'Firefly\Trigger\Limits\EloquentLimitTrigger@updateLimitRepetitions');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
\Limit::observe(new EloquentLimitTrigger);
|
||||
@@ -14,13 +14,13 @@ use LaravelBook\Ardent\Ardent as Ardent;
|
||||
* @property-read \AccountType $accountType
|
||||
* @property-read \User $user
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Transaction[] $transactions
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereAccountTypeId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereName($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereActive($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereAccountTypeId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereName($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Account whereActive($value)
|
||||
*/
|
||||
class Account extends Ardent
|
||||
{
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $description
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Account[] $accounts
|
||||
* @method static \Illuminate\Database\Query\Builder|\AccountType whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\AccountType whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\AccountType whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\AccountType whereDescription($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\AccountType whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\AccountType whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\AccountType whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\AccountType whereDescription($value)
|
||||
*/
|
||||
class AccountType extends Eloquent
|
||||
{
|
||||
|
||||
@@ -3,29 +3,40 @@
|
||||
/**
|
||||
* Budget
|
||||
*
|
||||
* @property integer $id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $name
|
||||
* @property integer $user_id
|
||||
* @property string $class
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Transaction[] $transactions
|
||||
* @property integer $id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $name
|
||||
* @property integer $user_id
|
||||
* @property string $class
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Transaction[] $transactions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\TransactionJournal[] $transactionjournals
|
||||
* @property-read \User $user
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereName($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereClass($value)
|
||||
* @property-read \User $user
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereName($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Budget whereClass($value)
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Limit[] $limits
|
||||
*/
|
||||
class Budget extends Component {
|
||||
class Budget extends Component
|
||||
{
|
||||
public static $factory
|
||||
= [
|
||||
'name' => 'string',
|
||||
'user_id' => 'factory|User',
|
||||
'class' => 'Budget'
|
||||
];
|
||||
protected $isSubclass = true;
|
||||
|
||||
public static $factory = [
|
||||
'name' => 'string',
|
||||
'user_id' => 'factory|User',
|
||||
'class' => 'Budget'
|
||||
];
|
||||
public function limits()
|
||||
{
|
||||
return $this->hasMany('Limit', 'component_id');
|
||||
}
|
||||
|
||||
public function transactionjournals() {
|
||||
return $this->belongsToMany('TransactionJournal','component_transaction_journal','component_id');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,28 +3,30 @@
|
||||
/**
|
||||
* Category
|
||||
*
|
||||
* @property integer $id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $name
|
||||
* @property integer $user_id
|
||||
* @property string $class
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Transaction[] $transactions
|
||||
* @property integer $id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $name
|
||||
* @property integer $user_id
|
||||
* @property string $class
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Transaction[] $transactions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\TransactionJournal[] $transactionjournals
|
||||
* @property-read \User $user
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereName($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereClass($value)
|
||||
* @property-read \User $user
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereName($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Category whereClass($value)
|
||||
* @property-read \Limit $limits
|
||||
*/
|
||||
class Category extends Component
|
||||
{
|
||||
public static $factory
|
||||
= [
|
||||
'name' => 'string',
|
||||
'user_id' => 'factory|User',
|
||||
'class' => 'Category'
|
||||
];
|
||||
protected $isSubclass = true;
|
||||
public static $factory = [
|
||||
'name' => 'string',
|
||||
'user_id' => 'factory|User',
|
||||
'class' => 'Category'
|
||||
];
|
||||
}
|
||||
@@ -4,45 +4,47 @@
|
||||
/**
|
||||
* Component
|
||||
*
|
||||
* @property integer $id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $name
|
||||
* @property integer $user_id
|
||||
* @property string $class
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Transaction[] $transactions
|
||||
* @property integer $id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $name
|
||||
* @property integer $user_id
|
||||
* @property string $class
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Transaction[] $transactions
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\TransactionJournal[] $transactionjournals
|
||||
* @property-read \User $user
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereName($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereClass($value)
|
||||
* @property-read \User $user
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereName($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Component whereClass($value)
|
||||
* @property-read \Limit $limits
|
||||
*/
|
||||
class Component extends Firefly\Database\SingleTableInheritanceEntity
|
||||
{
|
||||
|
||||
public static $rules
|
||||
= [
|
||||
'user_id' => 'exists:users,id|required',
|
||||
'name' => 'required|between:1,255',
|
||||
'class' => 'required',
|
||||
'user_id' => 'exists:users,id|required',
|
||||
'name' => 'required|between:1,255',
|
||||
'class' => 'required',
|
||||
];
|
||||
public static $factory
|
||||
= [
|
||||
'name' => 'string',
|
||||
'user_id' => 'factory|User',
|
||||
];
|
||||
protected $table = 'components';
|
||||
protected $subclassField = 'class';
|
||||
|
||||
public static $factory = [
|
||||
'name' => 'string',
|
||||
'user_id' => 'factory|User',
|
||||
];
|
||||
|
||||
public function transactions()
|
||||
{
|
||||
return $this->belongsToMany('Transaction');
|
||||
}
|
||||
|
||||
public function limits() {
|
||||
public function limits()
|
||||
{
|
||||
return $this->belongsTo('Limit');
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,29 @@
|
||||
|
||||
use LaravelBook\Ardent\Ardent as Ardent;
|
||||
|
||||
/**
|
||||
* Limit
|
||||
*
|
||||
* @property integer $id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property integer $component_id
|
||||
* @property \Carbon\Carbon $startdate
|
||||
* @property float $amount
|
||||
* @property boolean $repeats
|
||||
* @property string $repeat_freq
|
||||
* @property-read \Component $component
|
||||
* @property-read \Budget $budget
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\LimitRepetition[] $limitrepetitions
|
||||
* @method static \Illuminate\Database\Query\Builder|\Limit whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Limit whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Limit whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Limit whereComponentId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Limit whereStartdate($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Limit whereAmount($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Limit whereRepeats($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Limit whereRepeatFreq($value)
|
||||
*/
|
||||
class Limit extends Ardent
|
||||
{
|
||||
|
||||
@@ -9,8 +32,9 @@ class Limit extends Ardent
|
||||
= [
|
||||
'component_id' => 'required|exists:components,id',
|
||||
'startdate' => 'required|date',
|
||||
'enddate' => 'required|date',
|
||||
'amount' => 'numeric|required|min:0.01'
|
||||
'amount' => 'numeric|required|min:0.01',
|
||||
'repeats' => 'required|between:0,1',
|
||||
'repeat_freq' => 'required|in:daily,weekly,monthly,quarterly,half-year,yearly'
|
||||
|
||||
];
|
||||
|
||||
@@ -24,7 +48,7 @@ class Limit extends Ardent
|
||||
|
||||
public function component()
|
||||
{
|
||||
return $this->belongsTo('Component');
|
||||
return $this->belongsTo('Component','component_id');
|
||||
}
|
||||
|
||||
public function budget()
|
||||
@@ -32,6 +56,10 @@ class Limit extends Ardent
|
||||
return $this->belongsTo('Budget', 'component_id');
|
||||
}
|
||||
|
||||
public function limitrepetitions() {
|
||||
return $this->hasMany('LimitRepetition');
|
||||
}
|
||||
|
||||
public function getDates()
|
||||
{
|
||||
return ['created_at', 'updated_at', 'startdate', 'enddate'];
|
||||
|
||||
84
app/models/LimitRepetition.php
Normal file
84
app/models/LimitRepetition.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
use LaravelBook\Ardent\Ardent as Ardent;
|
||||
|
||||
/**
|
||||
* LimitRepetition
|
||||
*
|
||||
* @property integer $id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property integer $limit_id
|
||||
* @property \Carbon\Carbon $startdate
|
||||
* @property \Carbon\Carbon $enddate
|
||||
* @property float $amount
|
||||
* @property-read \Limit $limit
|
||||
* @method static \Illuminate\Database\Query\Builder|\LimitRepetition whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\LimitRepetition whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\LimitRepetition whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\LimitRepetition whereLimitId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\LimitRepetition whereStartdate($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\LimitRepetition whereEnddate($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\LimitRepetition whereAmount($value)
|
||||
*/
|
||||
class LimitRepetition extends Ardent
|
||||
{
|
||||
public static $rules
|
||||
= [
|
||||
'limit_id' => 'required|exists:limits,id',
|
||||
'startdate' => 'required|date',
|
||||
'enddate' => 'required|date',
|
||||
'amount' => 'numeric|required|min:0.01',
|
||||
];
|
||||
|
||||
public static $factory
|
||||
= [
|
||||
'limit_id' => 'factory|Limit',
|
||||
'startdate' => 'date',
|
||||
'enddate' => 'date',
|
||||
'amount' => 'integer'
|
||||
];
|
||||
|
||||
public function limit()
|
||||
{
|
||||
return $this->belongsTo('Limit');
|
||||
}
|
||||
|
||||
public function getDates()
|
||||
{
|
||||
return ['created_at', 'updated_at', 'startdate', 'enddate'];
|
||||
}
|
||||
|
||||
/**
|
||||
* How much money is left in this?
|
||||
*/
|
||||
public function left()
|
||||
{
|
||||
$key = 'limit-rep-left-' . $this->id;
|
||||
if (Cache::has($key)) {
|
||||
return Cache::get($key);
|
||||
}
|
||||
$left = floatval($this->amount);
|
||||
|
||||
// budget:
|
||||
$budget = $this->limit->budget;
|
||||
|
||||
/** @var \Firefly\Storage\Limit\EloquentLimitRepository $limits */
|
||||
$limits = App::make('Firefly\Storage\Limit\EloquentLimitRepository');
|
||||
$set = $limits->getTJByBudgetAndDateRange($budget, $this->startdate, $this->enddate);
|
||||
|
||||
foreach ($set as $journal) {
|
||||
foreach ($journal->transactions as $t) {
|
||||
if ($t->amount < 0) {
|
||||
$left += floatval($t->amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
Cache::forever($key, $left);
|
||||
|
||||
|
||||
return $left;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -13,12 +13,12 @@ use LaravelBook\Ardent\Ardent;
|
||||
* @property string $name
|
||||
* @property string $data
|
||||
* @property-read \User $user
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereName($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereData($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereName($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Preference whereData($value)
|
||||
*/
|
||||
class Preference extends Ardent
|
||||
{
|
||||
|
||||
@@ -18,13 +18,13 @@ use LaravelBook\Ardent\Ardent;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Component[] $components
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Category[] $categories
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereAccountId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereTransactionJournalId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereDescription($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereAmount($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereAccountId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereTransactionJournalId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereDescription($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\Transaction whereAmount($value)
|
||||
*/
|
||||
class Transaction extends Ardent
|
||||
{
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $code
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\TransactionJournal[] $transactionJournals
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionCurrency whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionCurrency whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionCurrency whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionCurrency whereCode($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionCurrency whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionCurrency whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionCurrency whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionCurrency whereCode($value)
|
||||
*/
|
||||
class TransactionCurrency extends Eloquent
|
||||
{
|
||||
|
||||
@@ -32,6 +32,13 @@ use LaravelBook\Ardent\Ardent;
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereDate($value)
|
||||
* @method static \TransactionJournal after($date)
|
||||
* @method static \TransactionJournal before($date)
|
||||
* @property integer $user_id
|
||||
* @property-read \User $user
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereUserId($value)
|
||||
*/
|
||||
class TransactionJournal extends Ardent
|
||||
{
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property string $type
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\TransactionJournal[] $transactionJournals
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionType whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionType whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionType whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionType whereType($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionType whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionType whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionType whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionType whereType($value)
|
||||
*/
|
||||
class TransactionType extends Eloquent {
|
||||
public function transactionJournals() {
|
||||
|
||||
@@ -23,14 +23,15 @@ use LaravelBook\Ardent\Ardent;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Component[] $components
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Category[] $categories
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereEmail($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User wherePassword($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereReset($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereRememberToken($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereMigrated($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereEmail($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User wherePassword($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereReset($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereRememberToken($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\User whereMigrated($value)
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\TransactionJournal[] $transactionjournals
|
||||
*/
|
||||
class User extends Ardent implements UserInterface, RemindableInterface
|
||||
{
|
||||
|
||||
@@ -26,8 +26,13 @@ Route::group(['before' => 'auth'], function () {
|
||||
Route::get('/accounts/create', ['uses' => 'AccountController@create', 'as' => 'accounts.create']);
|
||||
Route::get('/accounts/{account}', ['uses' => 'AccountController@show', 'as' => 'accounts.show']);
|
||||
|
||||
// budget controller
|
||||
Route::get('/bugets',['uses' => 'BudgetController@index','as' => 'budgets.index']);
|
||||
// budget controller:
|
||||
Route::get('/budgets',['uses' => 'BudgetController@index','as' => 'budgets.index']);
|
||||
Route::get('/budget/create',['uses' => 'BudgetController@create', 'as' => 'budgets.create']);
|
||||
Route::get('/budget/show/{id}',['uses' => 'BudgetController@show', 'as' => 'budgets.show']);
|
||||
|
||||
// limit controller:
|
||||
Route::get('/budgets/limits/create/{id?}',['uses' => 'LimitController@create','as' => 'budgets.limits.create']);
|
||||
|
||||
// JSON controller:
|
||||
Route::get('/json/beneficiaries', ['uses' => 'JsonController@beneficiaries', 'as' => 'json.beneficiaries']);
|
||||
@@ -53,6 +58,9 @@ Route::group(['before' => 'csrf|auth'], function () {
|
||||
// profile controller
|
||||
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword']);
|
||||
|
||||
// budget controller:
|
||||
Route::post('/budget/store',['uses' => 'BudgetController@store', 'as' => 'budgets.store']);
|
||||
|
||||
// migration controller
|
||||
Route::post('/migrate', ['uses' => 'MigrationController@postIndex']);
|
||||
|
||||
@@ -62,6 +70,9 @@ Route::group(['before' => 'csrf|auth'], function () {
|
||||
// account controller:
|
||||
Route::get('/accounts/store', ['uses' => 'AccountController@store', 'as' => 'accounts.store']);
|
||||
|
||||
// limit controller:
|
||||
Route::post('/limits/store', ['uses' => 'LimitController@store', 'as' => 'limits.store']);
|
||||
|
||||
// transaction controller:
|
||||
Route::post('/transactions/store/{what}', ['uses' => 'TransactionController@store', 'as' => 'transactions.store'])
|
||||
->where(['what' => 'withdrawal|deposit|transfer']);
|
||||
@@ -81,6 +92,7 @@ Route::group(['before' => 'guest'], function () {
|
||||
|
||||
// dev import route:
|
||||
Route::get('/dev',['uses' => 'MigrationController@dev']);
|
||||
Route::get('/limit',['uses' => 'MigrationController@limit']);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
87
app/views/budgets/create.blade.php
Normal file
87
app/views/budgets/create.blade.php
Normal file
@@ -0,0 +1,87 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<h1>Firefly
|
||||
<small>Create a budget</small>
|
||||
</h1>
|
||||
<p class="text-info">
|
||||
Firefly uses the <a href="http://en.wikipedia.org/wiki/Envelope_System" class="text-success">envelope system</a>. Every budget
|
||||
is an envelope in which you put money every [period]. Expenses allocated to each budget are paid from this
|
||||
(virtual) envelope.
|
||||
</p>
|
||||
<p class="text-info">
|
||||
When the envelope is empty, you must stop spending on the budget. If the envelope still has some money left at the
|
||||
end of the [period], congratulations! You have saved money!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('budgets.store')])}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<h4>Mandatory fields</h4>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name" class="col-sm-3 control-label">Name</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="name" class="form-control" id="name" value="{{Input::old('name')}}" placeholder="Name">
|
||||
<span class="help-block">For example: groceries, bills</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<h4>Optional fields</h4>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="amount" class="col-sm-3 control-label">Max. amount</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="number" min="0.01" step="any" name="amount" class="form-control" id="amount" value="{{Input::old('amount')}}">
|
||||
<span class="help-block">What's the most you're willing to spend in this budget? This amount is "put" in the virtual
|
||||
envelope.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="period" class="col-sm-3 control-label">Spending period</label>
|
||||
<div class="col-sm-9">
|
||||
{{Form::select('period',$periods,Input::old('period') ?: 'monthly',['class' => 'form-control'])}}
|
||||
<span class="help-block">How long will the envelope last? A week, a month, or even longer?</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="period" class="col-sm-3 control-label">Repeat</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" value="1" name="repeats">
|
||||
Repeat
|
||||
</label>
|
||||
</div>
|
||||
<span class="help-block">If you want, Firefly can automatically recreate the "envelope" and fill it again
|
||||
when the timespan above has expired. Be careful with this option though. It makes it easier
|
||||
to <a href="http://en.wikipedia.org/wiki/Personal_budget#Concepts">fall back to old habits</a>.
|
||||
Instead, you should recreate the envelope yourself each [period].</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<input type="submit" name="submit" class="btn btn-info" value="Create new budget" />
|
||||
<br /><br /><br /><br />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{Form::close()}}
|
||||
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
<script type="text/javascript" src="assets/javascript/moment.min.js"></script>
|
||||
<script type="text/javascript" src="assets/javascript/limits.js"></script>
|
||||
@stop
|
||||
102
app/views/budgets/index.blade.php
Normal file
102
app/views/budgets/index.blade.php
Normal file
@@ -0,0 +1,102 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<h1>Firefly
|
||||
<small>Budgets and limits</small>
|
||||
</h1>
|
||||
<p class="text-info">
|
||||
These are your budgets and if set, their "limits". Firefly uses an "<a
|
||||
href="http://en.wikipedia.org/wiki/Envelope_System" class="text-success">envelope system</a>" for your
|
||||
budgets,
|
||||
which means that for each period of time (for example a month) a virtual "envelope" can be created
|
||||
containing a certain amount of money. Money spent within a budget is removed from the envelope.
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<table class="table table-bordered table-striped">
|
||||
<tr>
|
||||
<th>Budget</th>
|
||||
<th>Current envelope(s)</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
@foreach($budgets as $budget)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{route('budgets.show',$budget->id)}}">{{{$budget->name}}}</a>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<small>Envelope</small>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<small>Left</small>
|
||||
</div>
|
||||
</div>
|
||||
@foreach($budget->limits as $limit)
|
||||
@foreach($limit->limitrepetitions as $index => $rep)
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<span class="label label-primary">
|
||||
<span class="glyphicon glyphicon-envelope"></span>
|
||||
{{mf($rep->amount,false)}}</span>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
@if($rep->left() < 0)
|
||||
<span class="label label-danger">
|
||||
<span class="glyphicon glyphicon-envelope"></span>
|
||||
{{mf($rep->left(),false)}}</span>
|
||||
@else
|
||||
<span class="label label-success">
|
||||
<span class="glyphicon glyphicon-envelope"></span>
|
||||
{{mf($rep->left(),false)}}</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<small>
|
||||
@if($limit->repeat_freq == 'monthly')
|
||||
{{$rep->startdate->format('F Y')}}
|
||||
@else
|
||||
NO FORMAT
|
||||
@endif
|
||||
</small>
|
||||
</div>
|
||||
@if($limit->repeats == 1)
|
||||
<div class="col-sm-2">
|
||||
<span class="label label-warning">auto repeats</span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="col-sm-2 @if($limit->repeats == 0) col-sm-offset-2 @endif">
|
||||
<a href="#" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
@if($limit->repeats == 0 || ($limit->repeats == 1 && $index == 0))
|
||||
<a href="#" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endforeach
|
||||
<p style="margin-top:5px;">
|
||||
<a href="{{route('budgets.limits.create',$budget->id)}}" class="btn btn-default btn-xs"><span
|
||||
class="glyphicon-plus-sign glyphicon"></span> Add another limit</a>
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a href="#" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="#" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
4
app/views/budgets/show.blade.php
Normal file
4
app/views/budgets/show.blade.php
Normal file
@@ -0,0 +1,4 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
|
||||
@stop
|
||||
@@ -7,6 +7,7 @@
|
||||
<small>What's playing?</small>
|
||||
@endif
|
||||
</h1>
|
||||
@if($count > 0)
|
||||
<form role="form" class="form-horizontal">
|
||||
<div class="input-group">
|
||||
|
||||
@@ -23,6 +24,7 @@
|
||||
<button class="btn btn-default btn-sm @if($r=='custom') btn-info @endif" type="submit" name="range" value="custom">Custom</button>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,12 +62,35 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TRANSACTIONS -->
|
||||
@if(count($transactions) > 0)
|
||||
@foreach($transactions as $set)
|
||||
<div class="row">
|
||||
<?php $split = 12 / count($set); ?>
|
||||
@foreach($set as $data)
|
||||
<div class="col-lg-{{$split}} col-md-{{$split}}">
|
||||
<h4>{{{$data[1]->name}}}</h4>
|
||||
@include('transactions.journals',['transactions' => $data[0],'account' => $data[1]])
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div id="categories"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@endif
|
||||
|
||||
@stop
|
||||
|
||||
103
app/views/limits/create.blade.php
Normal file
103
app/views/limits/create.blade.php
Normal file
@@ -0,0 +1,103 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<h1>Firefly
|
||||
<small>Set a limit to a budget</small>
|
||||
</h1>
|
||||
<p class="text-info">
|
||||
Firefly uses an "<a href="http://en.wikipedia.org/wiki/Envelope_System" class="text-success">envelope
|
||||
system</a>" for your budgets, which means that for each period of time (for example a month) a virtual
|
||||
"envelope" can be created containing a certain amount of money. Money spent within a budget is removed from
|
||||
the envelope.
|
||||
</p>
|
||||
|
||||
<p class="text-info">
|
||||
Firefly gives you the opportunity to create such an envelope when you create a budget. However, you can
|
||||
always add more of them.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('limits.store')])}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<h4>Mandatory fields</h4>
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('budget_id', 'Budget', ['class' => 'col-sm-3 control-label'])}}
|
||||
<div class="col-sm-9">
|
||||
{{Form::select('budget_id',$budgets,Input::old('budget_id') ?: $budget_id, ['class' =>
|
||||
'form-control'])}}
|
||||
@if($errors->has('budget_id'))
|
||||
<p class="text-danger">{{$errors->first('name')}}</p>
|
||||
@else
|
||||
<span class="help-block">Select one of your existing budgets.</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('startdate', 'Start date', ['class' => 'col-sm-3 control-label'])}}
|
||||
<div class="col-sm-9">
|
||||
<input type="date" name="startdate" value="{{Input::old('startdate') ?: date('Y-m-d')}}"
|
||||
class="form-control"/>
|
||||
<span class="help-block">This date indicates when the envelope "starts". The date you select
|
||||
here will correct itself to the nearest [period] you select below.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="period" class="col-sm-3 control-label">Spending period</label>
|
||||
|
||||
<div class="col-sm-9">
|
||||
{{Form::select('period',$periods,Input::old('period') ?: 'monthly',['class' => 'form-control'])}}
|
||||
<span class="help-block">How long will the envelope last? A week, a month, or even longer?</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="period" class="col-sm-3 control-label">Repeat</label>
|
||||
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" value="1" name="repeats" @if(intval(Input::old('repeats')) == 1) checked @endif>
|
||||
Repeat
|
||||
</label>
|
||||
</div>
|
||||
<span class="help-block">If you want, Firefly can automatically recreate the "envelope" and fill it again
|
||||
when the timespan above has expired. Be careful with this option though. It makes it easier
|
||||
to <a href="http://en.wikipedia.org/wiki/Personal_budget#Concepts">fall back to old habits</a>.
|
||||
Instead, you should recreate the envelope yourself each [period].</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('amount', 'Amount', ['class' => 'col-sm-3 control-label'])}}
|
||||
<div class="col-sm-9">
|
||||
<input type="number" value="{{Input::old('amount')}}" name="amount" min="0.01" step="any" class="form-control"/>
|
||||
<span class="help-block">Of course, there needs to be money in the envelope.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('submit', ' ', ['class' => 'col-sm-3 control-label'])}}
|
||||
<div class="col-sm-9">
|
||||
<input type="submit" name="submit" value="Save new limit" class="btn btn-default"/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{Form::open()}}
|
||||
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
<script type="text/javascript" src="assets/javascript/moment.min.js"></script>
|
||||
<script type="text/javascript" src="assets/javascript/limits.js"></script>
|
||||
@stop
|
||||
28
app/views/partials/menu/budgets.blade.php
Normal file
28
app/views/partials/menu/budgets.blade.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
$r = Route::current()->getName();
|
||||
?>
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="{{route('index')}}">Firefly III</a>
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li @if($r=='index')class="active"@endif><a href="{{route('index')}}">Home</a></li>
|
||||
<li @if($r=='budgets.index')class="active"@endif><a href="{{route('budgets.index')}}">Budgets</a></li>
|
||||
<li @if($r=='budgets.create')class="active"@endif><a href="{{route('budgets.create')}}"><span class="glyphicon glyphicon-plus"></span> Create budget</a></li>
|
||||
<li @if($r=='budgets.limits.create')class="active"@endif><a href="{{route('budgets.limits.create')}}"><span class="glyphicon glyphicon-plus"></span> Set limit</a></li>
|
||||
</ul>
|
||||
@include('partials.menu.shared')
|
||||
</div><!-- /.navbar-collapse -->
|
||||
</div><!-- /.container-fluid -->
|
||||
</nav>
|
||||
@@ -5,7 +5,6 @@
|
||||
<h1>Firefly
|
||||
<small>Preferences</small>
|
||||
</h1>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<th>Date</th>
|
||||
<th>Amount</th>
|
||||
</tr>
|
||||
@foreach($account->transactionList as $journal)
|
||||
@foreach($transactions as $journal)
|
||||
<tr>
|
||||
|
||||
<td>
|
||||
|
||||
Reference in New Issue
Block a user