mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-18 18:44:16 +00:00
Up to budgets now!
This commit is contained in:
76
app/Http/Controllers/BudgetController.php
Normal file
76
app/Http/Controllers/BudgetController.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Session;
|
||||
use View;
|
||||
use Response;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class BudgetController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class BudgetController extends Controller
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
View::share('title', 'Budgets');
|
||||
View::share('mainTitleIcon', 'fa-tasks');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function amount(Budget $budget, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$amount = intval(Input::get('amount'));
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth());
|
||||
Log::debug('Budget: '. $budget->id);
|
||||
Log::debug('Budget (full) ' . print_r($budget->toArray(),true));
|
||||
Log::debug('Amount:' . $amount);
|
||||
Log::debug('Date: ' . $date);
|
||||
$limitRepetition = $repository->updateLimitAmount($budget, $date, $amount);
|
||||
|
||||
return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function index(BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$budgets = Auth::user()->budgets()->get();
|
||||
|
||||
// loop the budgets:
|
||||
$budgets->each(
|
||||
function (Budget $budget) use ($repository) {
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$budget->spent = $repository->spentInMonth($budget, $date);
|
||||
$budget->currentRep = $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']);
|
||||
}
|
||||
);
|
||||
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
|
||||
$spent = $budgets->sum('spent');
|
||||
$amount = Preferences::get('budgetIncomeTotal' . $date, 1000)->data;
|
||||
$overspent = $spent > $amount;
|
||||
$spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100);
|
||||
$budgetMax = Preferences::get('budgetMaximum', 1000);
|
||||
$budgetMaximum = $budgetMax->data;
|
||||
|
||||
return View::make('budgets.index', compact('budgetMaximum', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount'));
|
||||
}
|
||||
|
||||
}
|
369
app/Http/breadcrumbs.php
Normal file
369
app/Http/breadcrumbs.php
Normal file
@@ -0,0 +1,369 @@
|
||||
<?php
|
||||
use Carbon\Carbon;
|
||||
use DaveJamesMiller\Breadcrumbs\Generator;
|
||||
use FireflyIII\Exception\FireflyException;
|
||||
|
||||
/*
|
||||
* Back home.
|
||||
*/
|
||||
Breadcrumbs::register(
|
||||
'home',
|
||||
function (Generator $breadcrumbs) {
|
||||
|
||||
$breadcrumbs->push('Home', route('index'));
|
||||
}
|
||||
);
|
||||
|
||||
// accounts
|
||||
Breadcrumbs::register(
|
||||
'accounts.index', function (Generator $breadcrumbs, $what) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push(ucfirst(e($what)) . ' accounts', route('accounts.index', $what));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'accounts.show', function (Generator $breadcrumbs, \Account $account) {
|
||||
switch ($account->accountType->type) {
|
||||
default:
|
||||
throw new FireflyException('Cannot handle account type "' . e($account->accountType->type) . '"');
|
||||
break;
|
||||
case 'Default account':
|
||||
case 'Asset account':
|
||||
$what = 'asset';
|
||||
break;
|
||||
case 'Cash account':
|
||||
$what = 'cash';
|
||||
break;
|
||||
case 'Expense account':
|
||||
case 'Beneficiary account':
|
||||
$what = 'expense';
|
||||
break;
|
||||
case 'Revenue account':
|
||||
$what = 'revenue';
|
||||
break;
|
||||
}
|
||||
$breadcrumbs->parent('accounts.index', $what);
|
||||
$breadcrumbs->push(e($account->name), route('accounts.show', $account->id));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'accounts.delete', function (Generator $breadcrumbs, \Account $account) {
|
||||
$breadcrumbs->parent('accounts.show', $account);
|
||||
$breadcrumbs->push('Delete ' . e($account->name), route('accounts.delete', $account->id));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'accounts.edit', function (Generator $breadcrumbs, \Account $account) {
|
||||
$breadcrumbs->parent('accounts.show', $account);
|
||||
$breadcrumbs->push('Edit ' . e($account->name), route('accounts.edit', $account->id));
|
||||
}
|
||||
);
|
||||
|
||||
// budgets.
|
||||
Breadcrumbs::register(
|
||||
'budgets.index', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Budgets', route('budgets.index'));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'budgets.create', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('budgets.index');
|
||||
$breadcrumbs->push('Create new budget', route('budgets.create'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'budgets.edit', function (Generator $breadcrumbs, Budget $budget) {
|
||||
$breadcrumbs->parent('budgets.show', $budget);
|
||||
$breadcrumbs->push('Edit ' . e($budget->name), route('budgets.edit', $budget->id));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'budgets.delete', function (Generator $breadcrumbs, Budget $budget) {
|
||||
$breadcrumbs->parent('budgets.show', $budget);
|
||||
$breadcrumbs->push('Delete ' . e($budget->name), route('budgets.delete', $budget->id));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'budgets.show', function (Generator $breadcrumbs, Budget $budget, LimitRepetition $repetition = null) {
|
||||
$breadcrumbs->parent('budgets.index');
|
||||
$breadcrumbs->push(e($budget->name), route('budgets.show', $budget->id));
|
||||
if (!is_null($repetition)) {
|
||||
$breadcrumbs->push(
|
||||
DateKit::periodShow($repetition->startdate, $repetition->budgetlimit->repeat_freq), route('budgets.show', $budget->id, $repetition->id)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// categories
|
||||
Breadcrumbs::register(
|
||||
'categories.index', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Categories', route('categories.index'));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'categories.create', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('categories.index');
|
||||
$breadcrumbs->push('Create new category', route('categories.create'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'categories.edit', function (Generator $breadcrumbs, Category $category) {
|
||||
$breadcrumbs->parent('categories.show', $category);
|
||||
$breadcrumbs->push('Edit ' . e($category->name), route('categories.edit', $category->id));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'categories.delete', function (Generator $breadcrumbs, Category $category) {
|
||||
$breadcrumbs->parent('categories.show', $category);
|
||||
$breadcrumbs->push('Delete ' . e($category->name), route('categories.delete', $category->id));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'categories.show', function (Generator $breadcrumbs, Category $category) {
|
||||
$breadcrumbs->parent('categories.index');
|
||||
$breadcrumbs->push(e($category->name), route('categories.show', $category->id));
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// piggy banks
|
||||
Breadcrumbs::register(
|
||||
'piggyBanks.index', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Piggy banks', route('piggyBanks.index'));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'piggyBanks.create', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('piggyBanks.index');
|
||||
$breadcrumbs->push('Create new piggy bank', route('piggyBanks.create'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'piggyBanks.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
|
||||
$breadcrumbs->parent('piggyBanks.show', $piggyBank);
|
||||
$breadcrumbs->push('Edit ' . e($piggyBank->name), route('piggyBanks.edit', $piggyBank->id));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'piggyBanks.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
|
||||
$breadcrumbs->parent('piggyBanks.show', $piggyBank);
|
||||
$breadcrumbs->push('Delete ' . e($piggyBank->name), route('piggyBanks.delete', $piggyBank->id));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'piggyBanks.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
|
||||
$breadcrumbs->parent('piggyBanks.index');
|
||||
$breadcrumbs->push(e($piggyBank->name), route('piggyBanks.show', $piggyBank->id));
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// preferences
|
||||
Breadcrumbs::register(
|
||||
'preferences', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Preferences', route('preferences'));
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// profile
|
||||
Breadcrumbs::register(
|
||||
'profile', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Profile', route('profile'));
|
||||
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'change-password', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('profile');
|
||||
$breadcrumbs->push('Change your password', route('change-password'));
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// bills
|
||||
Breadcrumbs::register(
|
||||
'bills.index', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Bills', route('bills.index'));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'bills.create', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('bills.index');
|
||||
$breadcrumbs->push('Create new bill', route('bills.create'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'bills.edit', function (Generator $breadcrumbs, Bill $bill) {
|
||||
$breadcrumbs->parent('bills.show', $bill);
|
||||
$breadcrumbs->push('Edit ' . e($bill->name), route('bills.edit', $bill->id));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'bills.delete', function (Generator $breadcrumbs, Bill $bill) {
|
||||
$breadcrumbs->parent('bills.show', $bill);
|
||||
$breadcrumbs->push('Delete ' . e($bill->name), route('bills.delete', $bill->id));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'bills.show', function (Generator $breadcrumbs, Bill $bill) {
|
||||
$breadcrumbs->parent('bills.index');
|
||||
$breadcrumbs->push(e($bill->name), route('bills.show', $bill->id));
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// reminders
|
||||
Breadcrumbs::register(
|
||||
'reminders.show', function (Generator $breadcrumbs, Reminder $reminder) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Reminder #' . $reminder->id, route('reminders.show', $reminder->id));
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// repeated expenses
|
||||
Breadcrumbs::register(
|
||||
'repeated.index', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Repeated expenses', route('repeated.index'));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'repeated.create', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('repeated.index');
|
||||
$breadcrumbs->push('Create new repeated expense', route('repeated.create'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'repeated.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
|
||||
$breadcrumbs->parent('repeated.show', $piggyBank);
|
||||
$breadcrumbs->push('Edit ' . e($piggyBank->name), route('repeated.edit', $piggyBank->id));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'repeated.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
|
||||
$breadcrumbs->parent('repeated.show', $piggyBank);
|
||||
$breadcrumbs->push('Delete ' . e($piggyBank->name), route('repeated.delete', $piggyBank->id));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'repeated.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
|
||||
$breadcrumbs->parent('repeated.index');
|
||||
$breadcrumbs->push(e($piggyBank->name), route('repeated.show', $piggyBank->id));
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// reports
|
||||
Breadcrumbs::register(
|
||||
'reports.index', function (Generator $breadcrumbs) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Reports', route('reports.index'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'reports.year', function (Generator $breadcrumbs, Carbon $date) {
|
||||
$breadcrumbs->parent('reports.index');
|
||||
$breadcrumbs->push($date->format('Y'), route('reports.year', $date->format('Y')));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'reports.month', function (Generator $breadcrumbs, Carbon $date) {
|
||||
$breadcrumbs->parent('reports.index');
|
||||
$breadcrumbs->push('Monthly report for ' . $date->format('F Y'), route('reports.month', $date));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'reports.budget', function (Generator $breadcrumbs, Carbon $date) {
|
||||
$breadcrumbs->parent('reports.index');
|
||||
$breadcrumbs->push('Budget report for ' . $date->format('F Y'), route('reports.budget', $date));
|
||||
}
|
||||
);
|
||||
|
||||
// search
|
||||
Breadcrumbs::register(
|
||||
'search', function (Generator $breadcrumbs, $query) {
|
||||
$breadcrumbs->parent('home');
|
||||
$breadcrumbs->push('Search for "' . e($query) . '"', route('search'));
|
||||
}
|
||||
);
|
||||
|
||||
// transactions
|
||||
Breadcrumbs::register(
|
||||
'transactions.index', function (Generator $breadcrumbs, $what) {
|
||||
$breadcrumbs->parent('home');
|
||||
|
||||
switch ($what) {
|
||||
case 'expenses':
|
||||
case 'withdrawal':
|
||||
$subTitle = 'Expenses';
|
||||
break;
|
||||
case 'revenue':
|
||||
case 'deposit':
|
||||
$subTitle = 'Revenue, income and deposits';
|
||||
break;
|
||||
case 'transfer':
|
||||
case 'transfers':
|
||||
$subTitle = 'Transfers';
|
||||
break;
|
||||
case 'opening balance':
|
||||
$subTitle = 'Opening balances';
|
||||
break;
|
||||
default:
|
||||
throw new FireflyException('Cannot handle $what "' . e($what) . '" in bread crumbs');
|
||||
}
|
||||
|
||||
$breadcrumbs->push($subTitle, route('transactions.index', $what));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'transactions.create', function (Generator $breadcrumbs, $what) {
|
||||
$breadcrumbs->parent('transactions.index', $what);
|
||||
$breadcrumbs->push('Create new ' .e($what), route('transactions.create', $what));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'transactions.edit', function (Generator $breadcrumbs, TransactionJournal $journal) {
|
||||
$breadcrumbs->parent('transactions.show', $journal);
|
||||
$breadcrumbs->push('Edit ' . e($journal->description), route('transactions.edit', $journal->id));
|
||||
}
|
||||
);
|
||||
Breadcrumbs::register(
|
||||
'transactions.delete', function (Generator $breadcrumbs, TransactionJournal $journal) {
|
||||
$breadcrumbs->parent('transactions.show', $journal);
|
||||
$breadcrumbs->push('Delete ' . e($journal->description), route('transactions.delete', $journal->id));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'transactions.show', function (Generator $breadcrumbs, TransactionJournal $journal) {
|
||||
|
||||
$breadcrumbs->parent('transactions.index', strtolower($journal->transactionType->type));
|
||||
$breadcrumbs->push(e($journal->description), route('transactions.show', $journal->id));
|
||||
|
||||
}
|
||||
);
|
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Bill;
|
||||
// models
|
||||
Route::bind(
|
||||
'account',
|
||||
@@ -19,6 +21,28 @@ Route::bind(
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'bill', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Bill::
|
||||
where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'budget', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Budget::
|
||||
where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Home Controller
|
||||
@@ -57,12 +81,17 @@ Route::group(
|
||||
* Budget Controller
|
||||
*/
|
||||
Route::get('/budgets', ['uses' => 'BudgetController@index', 'as' => 'budgets.index']);
|
||||
//Route::get('/budgets/income', ['uses' => 'BudgetController@updateIncome', 'as' => 'budgets.income']); # extra.
|
||||
//Route::get('/budgets/create', ['uses' => 'BudgetController@create', 'as' => 'budgets.create']);
|
||||
//Route::get('/budgets/edit/{budget}', ['uses' => 'BudgetController@edit', 'as' => 'budgets.edit']);
|
||||
//Route::get('/budgets/delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'budgets.delete']);
|
||||
Route::get('/budgets/income', ['uses' => 'BudgetController@updateIncome', 'as' => 'budgets.income']); # extra.
|
||||
Route::get('/budgets/create', ['uses' => 'BudgetController@create', 'as' => 'budgets.create']);
|
||||
Route::get('/budgets/edit/{budget}', ['uses' => 'BudgetController@edit', 'as' => 'budgets.edit']);
|
||||
Route::get('/budgets/delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'budgets.delete']);
|
||||
Route::get('/budgets/show/{budget}/{limitrepetition?}', ['uses' => 'BudgetController@show', 'as' => 'budgets.show']);
|
||||
//Route::get('/budgets/list/noBudget', ['uses' => 'BudgetController@noBudget', 'as' => 'budgets.noBudget']);
|
||||
Route::get('/budgets/list/noBudget', ['uses' => 'BudgetController@noBudget', 'as' => 'budgets.noBudget']);
|
||||
Route::post('/budgets/income', ['uses' => 'BudgetController@postUpdateIncome', 'as' => 'budgets.postIncome']);
|
||||
Route::post('/budgets/store', ['uses' => 'BudgetController@store', 'as' => 'budgets.store']);
|
||||
Route::post('/budgets/update/{budget}', ['uses' => 'BudgetController@update', 'as' => 'budgets.update']);
|
||||
Route::post('/budgets/destroy/{budget}', ['uses' => 'BudgetController@destroy', 'as' => 'budgets.destroy']);
|
||||
Route::post('budgets/amount/{budget}', ['uses' => 'BudgetController@amount']);
|
||||
|
||||
/**
|
||||
* Category Controller
|
||||
|
@@ -34,7 +34,7 @@ class Budget extends Model
|
||||
*/
|
||||
public function limitrepetitions()
|
||||
{
|
||||
return $this->hasManyThrough('FireflyIII\Models\LimitRepetition', 'BudgetLimit', 'budget_id');
|
||||
return $this->hasManyThrough('FireflyIII\Models\LimitRepetition', 'FireflyIII\Models\BudgetLimit', 'budget_id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -2,10 +2,16 @@
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Support\Facades\Navigation;
|
||||
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class EventServiceProvider
|
||||
*
|
||||
@@ -61,6 +67,46 @@ class EventServiceProvider extends ServiceProvider
|
||||
}
|
||||
);
|
||||
|
||||
BudgetLimit::saved(function(BudgetLimit $budgetLimit) {
|
||||
|
||||
$end = Navigation::addPeriod(clone $budgetLimit->startdate, $budgetLimit->repeat_freq, 0);
|
||||
$end->subDay();
|
||||
|
||||
$set = $budgetLimit->limitrepetitions()->where('startdate', $budgetLimit->startdate->format('Y-m-d'))->where('enddate', $end->format('Y-m-d'))->get();
|
||||
/*
|
||||
* Create new LimitRepetition:
|
||||
*/
|
||||
if ($set->count() == 0) {
|
||||
|
||||
$repetition = new LimitRepetition;
|
||||
$repetition->startdate = $budgetLimit->startdate;
|
||||
$repetition->enddate = $end;
|
||||
$repetition->amount = $budgetLimit->amount;
|
||||
$repetition->budgetLimit()->associate($budgetLimit);
|
||||
|
||||
try {
|
||||
$repetition->save();
|
||||
} catch (QueryException $e) {
|
||||
\Log::error('Trying to save new LimitRepetition failed!');
|
||||
\Log::error($e->getMessage());
|
||||
}
|
||||
} else {
|
||||
if ($set->count() == 1) {
|
||||
/*
|
||||
* Update existing one.
|
||||
*/
|
||||
$repetition = $set->first();
|
||||
$repetition->amount = $budgetLimit->amount;
|
||||
$repetition->save();
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -58,6 +58,7 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
|
||||
// preferences
|
||||
$this->app->bind('FireflyIII\Repositories\Account\AccountRepositoryInterface', 'FireflyIII\Repositories\Account\AccountRepository');
|
||||
$this->app->bind('FireflyIII\Repositories\Budget\BudgetRepositoryInterface', 'FireflyIII\Repositories\Budget\BudgetRepository');
|
||||
$this->app->bind('FireflyIII\Repositories\Journal\JournalRepositoryInterface', 'FireflyIII\Repositories\Journal\JournalRepository');
|
||||
}
|
||||
|
||||
|
66
app/Repositories/Budget/BudgetRepository.php
Normal file
66
app/Repositories/Budget/BudgetRepository.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Repositories\Budget;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
|
||||
/**
|
||||
* Class BudgetRepository
|
||||
*
|
||||
* @package FireflyIII\Repositories\Budget
|
||||
*/
|
||||
class BudgetRepository implements BudgetRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInMonth(Budget $budget, Carbon $date)
|
||||
{
|
||||
$end = clone $date;
|
||||
$date->startOfMonth();
|
||||
$end->endOfMonth();
|
||||
$sum = floatval($budget->transactionjournals()->before($end)->after($date)->lessThan(0)->sum('amount')) * -1;
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
* @param $amount
|
||||
*
|
||||
* @return LimitRepetition|null
|
||||
*/
|
||||
public function updateLimitAmount(Budget $budget, Carbon $date, $amount)
|
||||
{
|
||||
/** @var BudgetLimit $limit */
|
||||
$limit = $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']);
|
||||
if (!$limit) {
|
||||
// create one!
|
||||
$limit = new BudgetLimit;
|
||||
$limit->budget()->associate($budget);
|
||||
$limit->startdate = $date;
|
||||
$limit->amount = $amount;
|
||||
$limit->repeat_freq = 'monthly';
|
||||
$limit->repeats = 0;
|
||||
$limit->save();
|
||||
} else {
|
||||
if ($amount > 0) {
|
||||
$limit->amount = $amount;
|
||||
$limit->save();
|
||||
} else {
|
||||
$limit->delete();
|
||||
}
|
||||
}
|
||||
return $limit;
|
||||
|
||||
|
||||
}
|
||||
}
|
31
app/Repositories/Budget/BudgetRepositoryInterface.php
Normal file
31
app/Repositories/Budget/BudgetRepositoryInterface.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Repositories\Budget;
|
||||
use FireflyIII\Models\Budget;
|
||||
use Carbon\Carbon;
|
||||
/**
|
||||
* Interface BudgetRepositoryInterface
|
||||
*
|
||||
* @package FireflyIII\Repositories\Budget
|
||||
*/
|
||||
interface BudgetRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInMonth(Budget $budget, Carbon $date);
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $date
|
||||
* @param $amount
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateLimitAmount(Budget $budget, Carbon $date, $amount);
|
||||
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
namespace FireflyIII\Support;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exception\FireflyException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
|
||||
/**
|
||||
* Class Navigation
|
||||
@@ -197,5 +197,47 @@ class Navigation
|
||||
throw new FireflyException('updateStartDate cannot handle $range ' . $range);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $theDate
|
||||
* @param $repeatFreq
|
||||
* @param $skip
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function addPeriod(Carbon $theDate, $repeatFreq, $skip)
|
||||
{
|
||||
$date = clone $theDate;
|
||||
$add = ($skip + 1);
|
||||
|
||||
$functionMap = [
|
||||
'daily' => 'addDays',
|
||||
'weekly' => 'addWeeks',
|
||||
'week' => 'addWeeks',
|
||||
'month' => 'addMonths',
|
||||
'monthly' => 'addMonths',
|
||||
'quarter' => 'addMonths',
|
||||
'quarterly' => 'addMonths',
|
||||
'half-year' => 'addMonths',
|
||||
'year' => 'addYears',
|
||||
'yearly' => 'addYears',
|
||||
];
|
||||
$modifierMap = [
|
||||
'quarter' => 3,
|
||||
'quarterly' => 3,
|
||||
'half-year' => 6,
|
||||
];
|
||||
if (!isset($functionMap[$repeatFreq])) {
|
||||
throw new FireflyException('Cannot do addPeriod for $repeat_freq "' . $repeatFreq . '"');
|
||||
}
|
||||
if (isset($modifierMap[$repeatFreq])) {
|
||||
$add = $add * $modifierMap[$repeatFreq];
|
||||
}
|
||||
$function = $functionMap[$repeatFreq];
|
||||
$date->$function($add);
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"require": {
|
||||
"laravel/framework": "5.0.*",
|
||||
"davejamesmiller/laravel-breadcrumbs": "@stable",
|
||||
"davejamesmiller/laravel-breadcrumbs": "~3.0",
|
||||
"grumpydictator/gchart": "dev-master",
|
||||
"michelf/php-markdown": "@stable",
|
||||
"watson/validating": "dev-master",
|
||||
|
30
composer.lock
generated
30
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "13cdbee2532896d10d1b3d8833f72d74",
|
||||
"hash": "6399deca7bccfb38eaa5df996618bc4d",
|
||||
"packages": [
|
||||
{
|
||||
"name": "barryvdh/laravel-ide-helper",
|
||||
@@ -187,32 +187,33 @@
|
||||
},
|
||||
{
|
||||
"name": "davejamesmiller/laravel-breadcrumbs",
|
||||
"version": "2.3.0",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/davejamesmiller/laravel-breadcrumbs.git",
|
||||
"reference": "cfcdc58ceaa8bbafa403828b8d1279d65f62799f"
|
||||
"reference": "5a5d5d1b1f5780359604f7fde11bbf810ff3e9e4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/davejamesmiller/laravel-breadcrumbs/zipball/cfcdc58ceaa8bbafa403828b8d1279d65f62799f",
|
||||
"reference": "cfcdc58ceaa8bbafa403828b8d1279d65f62799f",
|
||||
"url": "https://api.github.com/repos/davejamesmiller/laravel-breadcrumbs/zipball/5a5d5d1b1f5780359604f7fde11bbf810ff3e9e4",
|
||||
"reference": "5a5d5d1b1f5780359604f7fde11bbf810ff3e9e4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "4.*|5.*",
|
||||
"illuminate/view": "4.*|5.*",
|
||||
"php": ">=5.3.0"
|
||||
"illuminate/support": "5.*",
|
||||
"illuminate/view": "5.*",
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~0.9.0",
|
||||
"phpunit/phpunit": "4.0.*",
|
||||
"satooshi/php-coveralls": "~0.6.0"
|
||||
"mockery/mockery": "0.9.*",
|
||||
"orchestra/testbench": "3.0.*",
|
||||
"phpunit/phpunit": "4.*",
|
||||
"satooshi/php-coveralls": "0.6.*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"DaveJamesMiller\\Breadcrumbs": "src/"
|
||||
"psr-4": {
|
||||
"DaveJamesMiller\\Breadcrumbs\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -231,7 +232,7 @@
|
||||
"keywords": [
|
||||
"laravel"
|
||||
],
|
||||
"time": "2014-10-26 22:36:05"
|
||||
"time": "2015-02-08 21:44:39"
|
||||
},
|
||||
{
|
||||
"name": "dnoegel/php-xdg-base-dir",
|
||||
@@ -4802,7 +4803,6 @@
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"davejamesmiller/laravel-breadcrumbs": 0,
|
||||
"grumpydictator/gchart": 20,
|
||||
"michelf/php-markdown": 0,
|
||||
"watson/validating": 20,
|
||||
|
@@ -138,6 +138,7 @@ return [
|
||||
'Illuminate\Html\HtmlServiceProvider',
|
||||
'Barryvdh\Debugbar\ServiceProvider',
|
||||
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
|
||||
'DaveJamesMiller\Breadcrumbs\ServiceProvider',
|
||||
|
||||
/*
|
||||
* Application Service Providers...
|
||||
@@ -198,6 +199,8 @@ return [
|
||||
'View' => 'Illuminate\Support\Facades\View',
|
||||
'Form' => 'Illuminate\Html\FormFacade',
|
||||
'Html' => 'Illuminate\Html\HtmlFacade',
|
||||
'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade',
|
||||
|
||||
'Preferences' => 'FireflyIII\Support\Facades\Preferences',
|
||||
'Navigation' => 'FireflyIII\Support\Facades\Navigation',
|
||||
'Amount' => 'FireflyIII\Support\Facades\Amount',
|
||||
|
153
public/js/budgets.js
Normal file
153
public/js/budgets.js
Normal file
@@ -0,0 +1,153 @@
|
||||
$(function () {
|
||||
updateRanges();
|
||||
//$('input[type="range"]').change(updateSingleRange);
|
||||
$('input[type="range"]').on('input', updateSingleRange);
|
||||
//$('input[type="number"]').on('change', updateSingleRange);
|
||||
$('input[type="number"]').on('input', updateSingleRange);
|
||||
$('.updateIncome').on('click', updateIncome);
|
||||
|
||||
|
||||
if (typeof budgetID !== 'undefined' && typeof repetitionID === 'undefined') {
|
||||
googleColumnChart('chart/budget/' + budgetID + '/spending', 'budgetOverview');
|
||||
}
|
||||
if (typeof budgetID !== 'undefined' && typeof repetitionID !== 'undefined') {
|
||||
googleLineChart('chart/budget/' + budgetID + '/' + repetitionID, 'budgetOverview');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
function updateSingleRange(e) {
|
||||
// get some values:
|
||||
var input = $(e.target);
|
||||
var id = input.data('id');
|
||||
var value = parseInt(input.val());
|
||||
var spent = parseFloat($('#spent-' + id).data('value'));
|
||||
|
||||
// update small display:
|
||||
if (value > 0) {
|
||||
// show the input:
|
||||
$('#budget-info-' + id + ' span').show();
|
||||
$('#budget-info-' + id + ' input').show();
|
||||
|
||||
// update the text:
|
||||
$('#budget-description-' + id).text('Budgeted: ');
|
||||
} else {
|
||||
// hide the input:
|
||||
$('#budget-info-' + id + ' span').hide();
|
||||
$('#budget-info-' + id + ' input').hide();
|
||||
|
||||
// update the text:
|
||||
$('#budget-description-' + id).html('<em>No budget</em>');
|
||||
}
|
||||
|
||||
// update the range display text:
|
||||
$('#budget-range-display-' + id).text('\u20AC ' + value.toFixed(2));
|
||||
|
||||
// send a post to Firefly to update the amount:
|
||||
$.post('budgets/amount/' + id, {amount: value, _token: token}).success(function (data) {
|
||||
// update the link if relevant:
|
||||
$('#budget-link-' + id).attr('href', 'budgets/show/' + id + '/' + data.repetition);
|
||||
});
|
||||
if (input.attr('type') == 'number') {
|
||||
// update the range-input:
|
||||
$('#budget-range-' + id).val(value);
|
||||
} else {
|
||||
// update the number-input:
|
||||
$('#budget-info-' + id + ' input').val(value);
|
||||
}
|
||||
|
||||
// update or hide the bar, whichever is necessary.
|
||||
updateTotal();
|
||||
return value;
|
||||
}
|
||||
|
||||
function updateTotal() {
|
||||
var sum = 0;
|
||||
$('input[type="range"]').each(function (i, v) {
|
||||
// get some values:
|
||||
sum += parseInt($(v).val());
|
||||
});
|
||||
|
||||
/**
|
||||
* Update total sum:
|
||||
*/
|
||||
var totalAmount = parseInt($('#totalAmount').data('value'));
|
||||
var pct;
|
||||
if (sum <= totalAmount) {
|
||||
pct = sum / totalAmount * 100;
|
||||
$('#progress-bar-default').css('width', pct + '%');
|
||||
$('#progress-bar-warning').css('width', '0');
|
||||
$('#progress-bar-danger').css('width', '0');
|
||||
$('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-success').removeClass('text-danger');
|
||||
} else {
|
||||
// we gaan er X overheen,
|
||||
|
||||
pct = totalAmount / sum * 100;
|
||||
var danger = 100 - pct;
|
||||
var err = 100 - danger;
|
||||
$('#progress-bar-default').css('width', 0);
|
||||
$('#progress-bar-warning').css('width', err + '%');
|
||||
$('#progress-bar-danger').css('width', danger + '%');
|
||||
$('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-danger').removeClass('text-success');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function updateIncome(e) {
|
||||
$('#monthlyBudgetModal').empty().load('budgets/income').modal('show');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateRanges() {
|
||||
/**
|
||||
* Update all ranges.
|
||||
*/
|
||||
var sum = 0;
|
||||
$('input[type="range"]').each(function (i, v) {
|
||||
// get some values:
|
||||
var input = $(v);
|
||||
var id = input.data('id');
|
||||
var value = parseInt(input.val());
|
||||
|
||||
// calculate sum:
|
||||
sum += value
|
||||
|
||||
// update small display:
|
||||
$('#budget-range-display-' + id).text('\u20AC ' + value.toFixed(2));
|
||||
|
||||
// update progress bar (if relevant)
|
||||
var barHolder = $('#budget-progress-' + id);
|
||||
var spent = parseFloat(barHolder.data('spent'));
|
||||
|
||||
// send a post to Firefly to update the amount:
|
||||
$.post('budgets/amount/' + id, {amount: value, _token: token}).success(function (data) {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* Update total sum:
|
||||
*/
|
||||
var totalAmount = parseInt($('#totalAmount').data('value'));
|
||||
if (sum <= totalAmount) {
|
||||
var pct = sum / totalAmount * 100;
|
||||
$('#progress-bar-default').css('width', pct + '%');
|
||||
$('#progress-bar-warning').css('width', '0');
|
||||
$('#progress-bar-danger').css('width', '0');
|
||||
$('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-success').removeClass('text-danger');
|
||||
} else {
|
||||
// we gaan er X overheen,
|
||||
|
||||
var pct = totalAmount / sum * 100;
|
||||
var danger = 100 - pct;
|
||||
var err = 100 - danger;
|
||||
$('#progress-bar-default').css('width', 0);
|
||||
$('#progress-bar-warning').css('width', err + '%');
|
||||
$('#progress-bar-danger').css('width', danger + '%');
|
||||
$('#budgetedAmount').text('\u20AC ' + sum.toFixed(2)).addClass('text-danger').removeClass('text-success');
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{{-- Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $what) --}}
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $what) !!}
|
||||
{!! Form::open(['class' => 'form-horizontal','id' => 'store','route' => 'accounts.store']) !!}
|
||||
{!! Form::hidden('what',$what) !!}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{{-- Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $account) --}}
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $account) !!}
|
||||
{!! Form::open(['class' => 'form-horizontal','id' => 'destroy','url' => route('accounts.destroy',$account->id)]) !!}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
|
@@ -1,6 +1,6 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{{-- Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $account) --}}
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $account) !!}
|
||||
{!! Form::model($account, ['class' => 'form-horizontal','id' => 'update','url' => route('accounts.update',$account->id)]) !!}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
|
@@ -1,6 +1,6 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{{-- Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $what) --}}
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $what) !!}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
|
@@ -1,6 +1,6 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{{-- Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $account) --}}
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $account) !!}
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-md-6 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
|
42
resources/views/budgets/create.blade.php
Normal file
42
resources/views/budgets/create.blade.php
Normal file
@@ -0,0 +1,42 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
|
||||
{{Form::open(['class' => 'form-horizontal','id' => 'store','url' => route('budgets.store')])}}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-exclamation"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{Form::ffText('name')}}
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new budget
|
||||
</button>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<!-- 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('create','budget')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{{Form::close()}}
|
||||
|
||||
|
||||
@stop
|
37
resources/views/budgets/delete.blade.php
Normal file
37
resources/views/budgets/delete.blade.php
Normal file
@@ -0,0 +1,37 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $budget) !!}
|
||||
{{Form::open(['class' => 'form-horizontal','id' => 'destroy','url' => route('budgets.destroy',$budget->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 budget "{{{$budget->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
|
42
resources/views/budgets/edit.blade.php
Normal file
42
resources/views/budgets/edit.blade.php
Normal file
@@ -0,0 +1,42 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $budget) !!}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">Use budgets to organize and limit your expenses.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{Form::model($budget, ['class' => 'form-horizontal','id' => 'update','url' => route('budgets.update',$budget->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')}}
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-pencil"></i> Update budget
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<!-- 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','budget')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{Form::close()}}
|
||||
|
||||
|
||||
@stop
|
21
resources/views/budgets/income.blade.php
Normal file
21
resources/views/budgets/income.blade.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<form style="display: inline;" id="income" action="{{route('budgets.postIncome')}}" method="POST">
|
||||
{{Form::token()}}
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
||||
<h4 class="modal-title" id="myModalLabel">Update (expected) income for {{Session::get('start', \Carbon\Carbon::now()->startOfMonth())->format('F Y')}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">€</div>
|
||||
<input step="any" class="form-control" id="amount" value="{{$amount->data}}" autocomplete="off" name="amount" type="number">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
158
resources/views/budgets/index.blade.php
Normal file
158
resources/views/budgets/index.blade.php
Normal file
@@ -0,0 +1,158 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
|
||||
<div class="row">
|
||||
<div class="col-lg-9 col-sm-8 col-md-8">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
{{Session::get('start', \Carbon\Carbon::now()->startOfMonth())->format('F Y')}}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-4 col-sm-3">
|
||||
<small>Budgeted: <span id="budgetedAmount" data-value="300">{{Amount::format(300)}}</span></small>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-4 col-sm-3" style="text-align:right;">
|
||||
<small>Income {{Session::get('start', \Carbon\Carbon::now()->startOfMonth())->format('F Y')}}:
|
||||
<a href="#" class="updateIncome"><span id="totalAmount" data-value="{{$amount}}">{!! Amount::format($amount) !!}</span></a></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="progress progress-striped">
|
||||
<div class="progress-bar progress-bar-info" id="progress-bar-default" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0;"></div>
|
||||
<div class="progress-bar progress-bar-danger" id="progress-bar-danger" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0;"></div>
|
||||
<div class="progress-bar progress-bar-warning" id="progress-bar-warning" role="progressbar" aria-valuenow="10" aria-valuemin="0" aria-valuemax="100" style="width: 0;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-4 col-sm-3">
|
||||
<small>Spent: {!! Amount::format($spent) !!}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="progress progress-striped">
|
||||
@if($overspent)
|
||||
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="{{$spentPCT}}" aria-valuemin="0" aria-valuemax="100" style="width: {{$spentPCT}}%;"></div>
|
||||
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="{{100-$spentPCT}}" aria-valuemin="0" aria-valuemax="100" style="width: {{100-$spentPCT}}%;"></div>
|
||||
@else
|
||||
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="{{$spentPCT}}" aria-valuemin="0" aria-valuemax="100" style="width: {{$spentPCT}}%;"></div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-4 col-md-4">
|
||||
<!-- time based navigation -->
|
||||
@include('partials.date_nav')
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Transactions without a budget
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
<a href="{{route('budgets.noBudget')}}">Transactions without a budget in
|
||||
{{Session::get('start', \Carbon\Carbon::now()->startOfMonth())->format('F Y')}}.</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
@foreach($budgets as $budget)
|
||||
<div class="col-lg-3 col-sm-4 col-md-6" style="height:180px;">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@if(isset($budget->currentRep))
|
||||
<a href="{{route('budgets.show',[$budget->id,$budget->currentRep->id])}}" id="budget-link-{{$budget->id}}">{{{$budget->name}}}</a>
|
||||
@else
|
||||
<a href="{{route('budgets.show',$budget->id)}}" id="budget-link-{{$budget->id}}">{{{$budget->name}}}</a>
|
||||
@endif
|
||||
|
||||
|
||||
<!-- 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('budgets.edit',$budget->id)}}"><i class="fa fa-pencil fa-fw"></i> Edit</a></li>
|
||||
<li><a href="{{route('budgets.delete',$budget->id)}}"><i class="fa fa-trash fa-fw"></i> Delete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<!-- the range in which the budget can be set -->
|
||||
<p>
|
||||
@if($budget->currentRep)
|
||||
<input type="range" data-id="{{$budget->id}}" data-spent="{{$budget->spent}}" id="budget-range-{{$budget->id}}" max="{{$budgetMaximum}}" min="0" value="{{$budget->currentRep->amount}}" />
|
||||
@else
|
||||
<input type="range" data-id="{{$budget->id}}" data-spent="{{$budget->spent}}" id="budget-range-{{$budget->id}}" max="{{$budgetMaximum}}" min="0" value="0" />
|
||||
@endif
|
||||
</p>
|
||||
<!-- some textual info about the budget. Updates dynamically. -->
|
||||
<p>
|
||||
<!-- budget-holder-X holds all the elements -->
|
||||
<span id="budget-holder-{{$budget->id}}">
|
||||
@if($budget->currentRep)
|
||||
<!-- budget-description-X holds the description. -->
|
||||
<span id="budget-description-{{$budget->id}}">Budgeted: </span>
|
||||
<!-- budget-info-X holds the input and the euro-sign: -->
|
||||
<span id="budget-info-{{$budget->id}}">
|
||||
@if($budget->currentRep->amount > $budget->spent)
|
||||
<span class="text-success">{{Amount::getCurrencySymbol()}}</span> <input type="number" min="0" max="{{$budgetMaximum}}" data-id="{{$budget->id}}" step="1" value="{{$budget->currentRep->amount}}" style="width:90px;color:#3c763d;" />
|
||||
@else
|
||||
<span class="text-danger">{{Amount::getCurrencySymbol()}}</span> <input type="number" min="0" max="{{$budgetMaximum}}" data-id="{{$budget->id}}" step="1" value="{{$budget->currentRep->amount}}" style="width:90px;color:#a94442;" />
|
||||
@endif
|
||||
</span>
|
||||
@else
|
||||
<span id="budget-description-{{$budget->id}}"><em>No budget</em></span>
|
||||
<span id="budget-info-{{$budget->id}}">
|
||||
<span class="text-success" style="display:none;">{{Amount::getCurrencySymbol()}}</span> <input data-id="{{$budget->id}}" type="number" min="0" max="{{$budgetMaximum}}" step="1" value="0" style="width:50px;color:#3c763d;display:none;" />
|
||||
</span>
|
||||
@endif
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span id="spent-{{$budget->id}}" data-value="{{$budget->spent}}">Spent: {!! Amount::format($budget->spent) !!}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
<div class="col-lg-3 col-sm-4 col-md-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Create budget
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<a href="{{route('budgets.create')}}" class="btn btn-success">Create new budget</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DIALOG -->
|
||||
<div class="modal fade" id="monthlyBudgetModal">
|
||||
</div><!-- /.modal -->
|
||||
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
<script type="text/javascript">
|
||||
var token = "{{csrf_token()}}";
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" src="js/budgets.js"></script>
|
||||
@stop
|
24
resources/views/budgets/noBudget.blade.php
Normal file
24
resources/views/budgets/noBudget.blade.php
Normal file
@@ -0,0 +1,24 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName()) !!}
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-md-4 col-sm-12 ">
|
||||
<!-- time based navigation -->
|
||||
@include('partials.date_nav')
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
{{{$subTitle}}}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@include('list.journals-full',['journals' => $list])
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@stop
|
91
resources/views/budgets/show.blade.php
Normal file
91
resources/views/budgets/show.blade.php
Normal file
@@ -0,0 +1,91 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{!! Breadcrumbs::renderIfExists(Route::getCurrentRoute()->getName(), $budget, $repetition) !!}
|
||||
<div class="row">
|
||||
<div class="col-lg-9 col-md-9 col-sm-7">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Overview
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="budgetOverview"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Transactions
|
||||
</div>
|
||||
@include('list.journals-full')
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-3 col-sm-5">
|
||||
@foreach($limits as $limit)
|
||||
@foreach($limit->limitrepetitions as $rep)
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="{{route('budgets.show',[$budget->id,$rep->id])}}">{{$rep->startdate->format('F Y')}}</a>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-6">
|
||||
Amount: {{Amount::format($rep->amount)}}
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-6">
|
||||
Spent: {{Amount::format($rep->spentInRepetition())}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<?php
|
||||
$overspent = $rep->spentInRepetition() > $rep->amount;
|
||||
?>
|
||||
@if($overspent)
|
||||
<?php
|
||||
$pct = $rep->amount / $rep->spentInRepetition()*100;
|
||||
?>
|
||||
<div class="progress progress-striped">
|
||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{ceil($pct)}}" aria-valuemin="0" aria-valuemax="100" style="width: {{ceil($pct)}}%;"></div>
|
||||
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="{{100-ceil($pct)}}" aria-valuemin="0" aria-valuemax="100" style="width: {{100-ceil($pct)}}%;"></div>
|
||||
</div>
|
||||
@else
|
||||
<?php
|
||||
$pct = $rep->spentInRepetition() / $rep->amount*100;
|
||||
?>
|
||||
<div class="progress progress-striped">
|
||||
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="{{ceil($pct)}}" aria-valuemin="0" aria-valuemax="100" style="width: {{ceil($pct)}}%;">
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endforeach
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
<script type="text/javascript">
|
||||
var budgetID = {{$budget->id}};
|
||||
var currencyCode = '{{Amount::getCurrencyCode()}}';
|
||||
@if(!is_null($repetition))
|
||||
var repetitionID = {{$repetition->id}};
|
||||
var year = {{$repetition->startdate->format('Y')}};
|
||||
@else
|
||||
var year = {{Session::get('start',\Carbon\Carbon::now()->startOfMonth())->format('Y')}};
|
||||
@endif
|
||||
|
||||
</script>
|
||||
|
||||
<!-- load the libraries and scripts necessary for Google Charts: -->
|
||||
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
|
||||
{{HTML::script('assets/javascript/firefly/gcharts.options.js')}}
|
||||
{{HTML::script('assets/javascript/firefly/gcharts.js')}}
|
||||
{{HTML::script('assets/javascript/firefly/budgets.js')}}
|
||||
|
||||
@stop
|
@@ -1,6 +1,6 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{{-- Breadcrumbs::renderIfExists() --}}
|
||||
{!! Breadcrumbs::renderIfExists() !!}
|
||||
@if($count == 0)
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-clock-o fa-fw"></i>
|
||||
{{{\Session::get('period')}}}
|
||||
{{{Session::get('period')}}}
|
||||
|
||||
<!-- ACTIONS MENU -->
|
||||
<div class="pull-right">
|
||||
@@ -21,8 +21,8 @@
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="btn-group btn-group-sm btn-group-justified">
|
||||
<a class="btn btn-default" href="{{route('sessionPrev')}}"><i class="fa fa-arrow-left"></i> {{{\Session::get('prev')}}}</a>
|
||||
<a class="btn btn-default" href="{{route('sessionNext')}}">{{{\Session::get('next')}}} <i class="fa fa-arrow-right"></i></a>
|
||||
<a class="btn btn-default" href="{{route('sessionPrev')}}"><i class="fa fa-arrow-left"></i> {{{Session::get('prev')}}}</a>
|
||||
<a class="btn btn-default" href="{{route('sessionNext')}}">{{{Session::get('next')}}} <i class="fa fa-arrow-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user