mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Merge branch 'release/3.1.5'
This commit is contained in:
commit
83594e6f1f
@ -28,7 +28,6 @@ Everything is organised:
|
||||
- Clear views that should show you how you're doing;
|
||||
- Easy navigation through your records;
|
||||
- Browse back and forth to see previous months or even years;
|
||||
- Lots of help text in case you don't get it;
|
||||
- Lots of charts because we all love them.
|
||||
|
||||
## Changes
|
||||
@ -36,6 +35,7 @@ Everything is organised:
|
||||
Firefly III will feature, but does not feature yet:
|
||||
|
||||
- Financial reporting showing you how well you are doing;
|
||||
- Lots of help text in case you don't get it;
|
||||
- More control over other resources outside of personal finance
|
||||
- Accounts shared with a partner (household accounts)
|
||||
- Debts
|
||||
@ -51,6 +51,10 @@ Some stuff has been removed:
|
||||
- The nesting of budgets, categories and beneficiaries is removed because it was pretty pointless.
|
||||
- Firefly will not encrypt the content of the (MySQL) tables. Old versions of Firefly had this capability but it sucks when searching, sorting and organizing entries.
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
|
||||
## Current state
|
||||
I have the basics up and running. Test coverage is currently non-existent.
|
||||
|
||||
|
@ -43,7 +43,7 @@ return [
|
||||
'Firefly\Helper\HelperServiceProvider',
|
||||
'Firefly\Validation\ValidationServiceProvider',
|
||||
'DaveJamesMiller\Breadcrumbs\ServiceProvider',
|
||||
'TwigBridge\ServiceProvider'
|
||||
'Grumpydictator\Gchart\GchartServiceProvider',
|
||||
],
|
||||
'manifest' => storage_path() . '/meta',
|
||||
'aliases' => [
|
||||
|
@ -2,10 +2,14 @@
|
||||
use Carbon\Carbon;
|
||||
|
||||
return [
|
||||
'index_periods' => ['1D', '1W', '1M', '3M', '6M','1Y', 'custom'],
|
||||
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
|
||||
'piggybank_periods' => ['day', 'week', 'month', 'year'],
|
||||
'periods_to_text' => [
|
||||
'index_periods' => ['1D', '1W', '1M', '3M', '6M', '1Y', 'custom'],
|
||||
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
|
||||
'piggybank_periods' => [
|
||||
'week' => 'Week',
|
||||
'month' => 'Month',
|
||||
'year' => 'Year'
|
||||
],
|
||||
'periods_to_text' => [
|
||||
'weekly' => 'A week',
|
||||
'monthly' => 'A month',
|
||||
'quarterly' => 'A quarter',
|
||||
@ -13,7 +17,7 @@ return [
|
||||
'yearly' => 'A year',
|
||||
],
|
||||
|
||||
'range_to_text' => [
|
||||
'range_to_text' => [
|
||||
'1D' => 'day',
|
||||
'1W' => 'week',
|
||||
'1M' => 'month',
|
||||
@ -21,15 +25,15 @@ return [
|
||||
'6M' => 'half year',
|
||||
'custom' => '(custom)'
|
||||
],
|
||||
'range_to_name' => [
|
||||
'1D' => 'one day',
|
||||
'1W' => 'one week',
|
||||
'1M' => 'one month',
|
||||
'3M' => 'three months',
|
||||
'6M' => 'six months',
|
||||
'1Y' => 'one year',
|
||||
'range_to_name' => [
|
||||
'1D' => 'one day',
|
||||
'1W' => 'one week',
|
||||
'1M' => 'one month',
|
||||
'3M' => 'three months',
|
||||
'6M' => 'six months',
|
||||
'1Y' => 'one year',
|
||||
],
|
||||
'range_to_repeat_freq' => [
|
||||
'range_to_repeat_freq' => [
|
||||
'1D' => 'weekly',
|
||||
'1W' => 'weekly',
|
||||
'1M' => 'monthly',
|
||||
|
@ -1,31 +1,116 @@
|
||||
<?php
|
||||
|
||||
use Firefly\Helper\Controllers\AccountInterface as AI;
|
||||
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
|
||||
use Firefly\Exception\FireflyException;
|
||||
use Illuminate\Support\MessageBag;
|
||||
|
||||
/**
|
||||
* Class AccountController
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
|
||||
*/
|
||||
class AccountController extends \BaseController
|
||||
class AccountController extends BaseController
|
||||
{
|
||||
|
||||
protected $_repository;
|
||||
protected $_accounts;
|
||||
|
||||
/**
|
||||
* @param ARI $repository
|
||||
* @param AI $accounts
|
||||
*
|
||||
*/
|
||||
public function __construct(ARI $repository, AI $accounts)
|
||||
public function __construct()
|
||||
{
|
||||
$this->_accounts = $accounts;
|
||||
$this->_repository = $repository;
|
||||
View::share('mainTitleIcon', 'fa-credit-card');
|
||||
View::share('title', 'Accounts');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $what
|
||||
*
|
||||
* @return View
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function index($what = 'default')
|
||||
{
|
||||
switch ($what) {
|
||||
default:
|
||||
throw new FireflyException('Cannot handle account type "' . e($what) . '".');
|
||||
break;
|
||||
case 'asset':
|
||||
View::share('subTitleIcon', 'fa-money');
|
||||
View::share('subTitle', 'Asset accounts');
|
||||
break;
|
||||
case 'expense':
|
||||
View::share('subTitleIcon', 'fa-shopping-cart');
|
||||
View::share('subTitle', 'Expense accounts');
|
||||
break;
|
||||
case 'revenue':
|
||||
View::share('subTitleIcon', 'fa-download');
|
||||
View::share('subTitle', 'Revenue accounts');
|
||||
break;
|
||||
}
|
||||
return View::make('accounts.index')->with('what', $what);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $what
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function json($what = 'default')
|
||||
{
|
||||
/** @var \FireflyIII\Database\Account $acct */
|
||||
$acct = App::make('FireflyIII\Database\Account');
|
||||
|
||||
/** @var \FireflyIII\Shared\Json\Json $json */
|
||||
$json = App::make('FireflyIII\Shared\Json\Json');
|
||||
|
||||
$parameters = $json->dataTableParameters();
|
||||
|
||||
switch ($what) {
|
||||
default:
|
||||
throw new FireflyException('Cannot handle account type "' . e($what) . '".');
|
||||
break;
|
||||
case 'asset':
|
||||
$accounts = $acct->getAssetAccounts($parameters);
|
||||
$count = $acct->countAssetAccounts();
|
||||
break;
|
||||
case 'expense':
|
||||
$accounts = $acct->getExpenseAccounts($parameters);
|
||||
$count = $acct->countExpenseAccounts();
|
||||
break;
|
||||
case 'revenue':
|
||||
$accounts = $acct->getRevenueAccounts($parameters);
|
||||
$count = $acct->countRevenueAccounts();
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output the set compatible with data tables:
|
||||
*/
|
||||
$return = [
|
||||
'draw' => intval(Input::get('draw')),
|
||||
'recordsTotal' => $count,
|
||||
'recordsFiltered' => $accounts->count(),
|
||||
'data' => [],
|
||||
];
|
||||
|
||||
/*
|
||||
* Loop the accounts:
|
||||
*/
|
||||
/** @var \Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$entry = [
|
||||
'name' => ['name' => $account->name, 'url' => route('accounts.show', $account->id)],
|
||||
'balance' => $account->balance(),
|
||||
'id' => [
|
||||
'edit' => route('accounts.edit', $account->id),
|
||||
'delete' => route('accounts.delete', $account->id),
|
||||
]
|
||||
];
|
||||
$return['data'][] = $entry;
|
||||
}
|
||||
|
||||
|
||||
return Response::jsoN($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
@ -43,52 +128,7 @@ class AccountController extends \BaseController
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return View::make('accounts.create')->with('subTitle', 'Create a new ' . $what . ' account')->with(
|
||||
'what', $what
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function asset()
|
||||
{
|
||||
View::share('subTitleIcon', 'fa-money');
|
||||
|
||||
$accounts = $this->_repository->getOfTypes(['Asset account', 'Default account']);
|
||||
|
||||
return View::make('accounts.asset')->with('subTitle', 'Asset accounts')->with(
|
||||
'accounts', $accounts
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function expense()
|
||||
{
|
||||
View::share('subTitleIcon', 'fa-shopping-cart');
|
||||
|
||||
$accounts = $this->_repository->getOfTypes(['Expense account', 'Beneficiary account']);
|
||||
|
||||
return View::make('accounts.expense')->with('subTitle', 'Expense accounts')->with(
|
||||
'accounts', $accounts
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function revenue()
|
||||
{
|
||||
View::share('subTitleIcon', 'fa-download');
|
||||
|
||||
$accounts = $this->_repository->getOfTypes(['Revenue account']);
|
||||
|
||||
return View::make('accounts.revenue')->with('subTitle', 'Revenue accounts')->with(
|
||||
'accounts', $accounts
|
||||
);
|
||||
return View::make('accounts.create')->with('subTitle', 'Create a new ' . $what . ' account')->with('what', $what);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,9 +139,9 @@ class AccountController extends \BaseController
|
||||
public function delete(Account $account)
|
||||
{
|
||||
return View::make('accounts.delete')->with('account', $account)
|
||||
->with(
|
||||
'subTitle', 'Delete ' . strtolower($account->accountType->type) . ' "' . $account->name . '"'
|
||||
);
|
||||
->with(
|
||||
'subTitle', 'Delete ' . strtolower($account->accountType->type) . ' "' . $account->name . '"'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,20 +151,67 @@ class AccountController extends \BaseController
|
||||
*/
|
||||
public function destroy(Account $account)
|
||||
{
|
||||
|
||||
$type = $account->accountType->type;
|
||||
$this->_repository->destroy($account);
|
||||
|
||||
/** @var \FireflyIII\Database\Account $acct */
|
||||
$acct = App::make('FireflyIII\Database\Account');
|
||||
|
||||
/** @var \FireflyIII\Database\TransactionJournal $jrnls */
|
||||
$jrnls = App::make('FireflyIII\Database\TransactionJournal');
|
||||
|
||||
/*
|
||||
* Find the "initial balance account", should it exist:
|
||||
*/
|
||||
$initialBalance = $acct->findInitialBalanceAccount($account);
|
||||
|
||||
/*
|
||||
* Get all the transaction journals that are part of this/these account(s):
|
||||
*/
|
||||
$journals = [];
|
||||
if ($initialBalance) {
|
||||
$transactions = $initialBalance->transactions()->get();
|
||||
/** @var \Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$journals[] = $transaction->transaction_journal_id;
|
||||
}
|
||||
}
|
||||
/** @var \Transaction $transaction */
|
||||
foreach ($account->transactions() as $transaction) {
|
||||
$journals[] = $transaction->transaction_journal_id;
|
||||
}
|
||||
|
||||
$journals = array_unique($journals);
|
||||
|
||||
/*
|
||||
* Delete the journals. Should get rid of the transactions as well.
|
||||
*/
|
||||
foreach ($journals as $id) {
|
||||
$journal = $jrnls->find($id);
|
||||
$journal->delete();
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete it
|
||||
*/
|
||||
if ($initialBalance) {
|
||||
$acct->destroy($initialBalance);
|
||||
}
|
||||
|
||||
$acct->destroy($account);
|
||||
|
||||
Session::flash('success', 'The account was deleted.');
|
||||
switch ($type) {
|
||||
case 'Asset account':
|
||||
case 'Default account':
|
||||
return Redirect::route('accounts.asset');
|
||||
return Redirect::route('accounts.index', 'asset');
|
||||
break;
|
||||
case 'Expense account':
|
||||
case 'Beneficiary account':
|
||||
return Redirect::route('accounts.expense');
|
||||
return Redirect::route('accounts.index', 'expense');
|
||||
break;
|
||||
case 'Revenue account':
|
||||
return Redirect::route('accounts.revenue');
|
||||
return Redirect::route('accounts.index', 'revenue');
|
||||
break;
|
||||
}
|
||||
|
||||
@ -153,18 +240,23 @@ class AccountController extends \BaseController
|
||||
break;
|
||||
}
|
||||
|
||||
$openingBalance = $this->_accounts->openingBalanceTransaction($account);
|
||||
return View::make('accounts.edit')->with('account', $account)->with('openingBalance', $openingBalance)
|
||||
/** @var \FireflyIII\Database\Account $acct */
|
||||
$acct = App::make('FireflyIII\Database\Account');
|
||||
|
||||
->with('subTitle', 'Edit ' . strtolower($account->accountType->type) . ' "' . $account->name . '"');
|
||||
}
|
||||
$openingBalance = $acct->openingBalanceTransaction($account);
|
||||
Session::forget('prefilled');
|
||||
if (!is_null($openingBalance)) {
|
||||
$prefilled['openingbalancedate'] = $openingBalance->date->format('Y-m-d');
|
||||
$prefilled['openingbalance'] = floatval($openingBalance->transactions()->where('account_id', $account->id)->first()->amount);
|
||||
Session::flash('prefilled', $prefilled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return View::make('error')->with('message', 'This view has been disabled');
|
||||
|
||||
return View::make('accounts.edit')->with('account', $account)->with('openingBalance', $openingBalance)->with(
|
||||
'subTitle', 'Edit ' . strtolower(
|
||||
$account->accountType->type
|
||||
) . ' "' . $account->name . '"'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,86 +281,116 @@ class AccountController extends \BaseController
|
||||
}
|
||||
|
||||
|
||||
$data = $this->_accounts->show($account, 40);
|
||||
|
||||
return View::make('accounts.show')->with('account', $account)->with('show', $data)->with(
|
||||
'subTitle',
|
||||
'Details for ' . strtolower($account->accountType->type) . ' "' . $account->name . '"'
|
||||
);
|
||||
//$data = $this->_accounts->show($account, 40);
|
||||
return View::make('accounts.show')
|
||||
->with('account', $account)
|
||||
->with('subTitle', 'Details for ' . strtolower($account->accountType->type) . ' "' . $account->name . '"');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this|\Illuminate\Http\RedirectResponse
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
|
||||
$data = Input::all();
|
||||
$data['what'] = isset($data['what']) && $data['what'] != '' ? $data['what'] : 'asset';
|
||||
/** @var \FireflyIII\Database\Account $acct */
|
||||
$acct = App::make('FireflyIII\Database\Account');
|
||||
|
||||
|
||||
switch ($data['what']) {
|
||||
switch ($data['post_submit_action']) {
|
||||
default:
|
||||
case 'asset':
|
||||
$data['account_type'] = 'Asset account';
|
||||
break;
|
||||
case 'expense':
|
||||
$data['account_type'] = 'Expense account';
|
||||
break;
|
||||
case 'revenue':
|
||||
$data['account_type'] = 'Revenue account';
|
||||
throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"');
|
||||
break;
|
||||
case 'create_another':
|
||||
case 'store':
|
||||
$messages = $acct->validate($data);
|
||||
/** @var MessageBag $messages ['errors'] */
|
||||
if ($messages['errors']->count() > 0) {
|
||||
Session::flash('warnings', $messages['warnings']);
|
||||
Session::flash('successes', $messages['successes']);
|
||||
Session::flash('error', 'Could not save account: ' . $messages['errors']->first());
|
||||
return Redirect::route('accounts.create', $data['what'])->withInput()->withErrors($messages['errors']);
|
||||
}
|
||||
// store!
|
||||
$acct->store($data);
|
||||
Session::flash('success', 'New account stored!');
|
||||
|
||||
}
|
||||
$account = $this->_repository->store($data);
|
||||
|
||||
if ($account->validate()) {
|
||||
// saved! return to wherever.
|
||||
Session::flash('success', 'Account "' . $account->name . '" created!');
|
||||
if (intval(Input::get('create')) === 1) {
|
||||
if ($data['post_submit_action'] == 'create_another') {
|
||||
return Redirect::route('accounts.create', $data['what']);
|
||||
} else {
|
||||
return Redirect::route('accounts.index', $data['what']);
|
||||
}
|
||||
break;
|
||||
case 'validate_only':
|
||||
$messageBags = $acct->validate($data);
|
||||
Session::flash('warnings', $messageBags['warnings']);
|
||||
Session::flash('successes', $messageBags['successes']);
|
||||
Session::flash('errors', $messageBags['errors']);
|
||||
return Redirect::route('accounts.create', $data['what'])->withInput();
|
||||
} else {
|
||||
|
||||
return Redirect::route('accounts.' . e($data['what']));
|
||||
}
|
||||
} else {
|
||||
// did not save, return with error:
|
||||
Session::flash('error', 'Could not save the new account: ' . $account->errors()->first());
|
||||
|
||||
return Redirect::route('accounts.create', $data['what'])->withErrors($account->errors())->withInput();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse
|
||||
* @return $this
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function update(Account $account)
|
||||
{
|
||||
/** @var \Account $account */
|
||||
$account = $this->_repository->update($account, Input::all());
|
||||
if ($account->validate()) {
|
||||
Session::flash('success', 'Account "' . $account->name . '" updated.');
|
||||
switch ($account->accountType->type) {
|
||||
case 'Asset account':
|
||||
case 'Default account':
|
||||
return Redirect::route('accounts.asset');
|
||||
break;
|
||||
case 'Expense account':
|
||||
case 'Beneficiary account':
|
||||
return Redirect::route('accounts.expense');
|
||||
break;
|
||||
case 'Revenue account':
|
||||
return Redirect::route('accounts.revenue');
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
Session::flash('error', 'Could not update account: ' . $account->errors()->first());
|
||||
/** @var \FireflyIII\Database\Account $acct */
|
||||
$acct = App::make('FireflyIII\Database\Account');
|
||||
$data = Input::except('_token');
|
||||
|
||||
return Redirect::route('accounts.edit', $account->id)->withInput()->withErrors($account->errors());
|
||||
switch ($account->accountType->type) {
|
||||
default:
|
||||
throw new FireflyException('Cannot handle account type "' . e($account->accountType->type) . '"');
|
||||
break;
|
||||
case 'Default account':
|
||||
$data['what'] = 'asset';
|
||||
break;
|
||||
case 'Beneficiary account':
|
||||
$data['what'] = 'expense';
|
||||
break;
|
||||
case 'Revenue account':
|
||||
$data['what'] = 'revenue';
|
||||
break;
|
||||
}
|
||||
|
||||
switch (Input::get('post_submit_action')) {
|
||||
default:
|
||||
throw new FireflyException('Cannot handle post_submit_action "' . e(Input::get('post_submit_action')) . '"');
|
||||
break;
|
||||
case 'create_another':
|
||||
case 'update':
|
||||
$messages = $acct->validate($data);
|
||||
/** @var MessageBag $messages ['errors'] */
|
||||
if ($messages['errors']->count() > 0) {
|
||||
Session::flash('warnings', $messages['warnings']);
|
||||
Session::flash('successes', $messages['successes']);
|
||||
Session::flash('error', 'Could not save account: ' . $messages['errors']->first());
|
||||
return Redirect::route('accounts.edit', $account->id)->withInput()->withErrors($messages['errors']);
|
||||
}
|
||||
// store!
|
||||
$acct->update($account, $data);
|
||||
Session::flash('success', 'Account updated!');
|
||||
|
||||
if ($data['post_submit_action'] == 'create_another') {
|
||||
return Redirect::route('accounts.edit', $account->id);
|
||||
} else {
|
||||
return Redirect::route('accounts.index',$data['what']);
|
||||
}
|
||||
case 'validate_only':
|
||||
$messageBags = $acct->validate($data);
|
||||
Session::flash('warnings', $messageBags['warnings']);
|
||||
Session::flash('successes', $messageBags['successes']);
|
||||
Session::flash('errors', $messageBags['errors']);
|
||||
return Redirect::route('accounts.edit', $account->id)->withInput();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,72 +4,175 @@ use Carbon\Carbon;
|
||||
use Firefly\Exception\FireflyException;
|
||||
use Firefly\Helper\Controllers\BudgetInterface as BI;
|
||||
use Firefly\Storage\Budget\BudgetRepositoryInterface as BRI;
|
||||
use FireflyIII\Exception\NotImplementedException;
|
||||
use Illuminate\Support\MessageBag;
|
||||
|
||||
|
||||
/**
|
||||
* Class BudgetController
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
*
|
||||
*/
|
||||
class BudgetController extends BaseController
|
||||
{
|
||||
|
||||
protected $_budgets;
|
||||
protected $_repository;
|
||||
|
||||
/**
|
||||
* @param BI $budgets
|
||||
* @param BRI $repository
|
||||
*/
|
||||
public function __construct(BI $budgets, BRI $repository)
|
||||
public function __construct()
|
||||
{
|
||||
$this->_budgets = $budgets;
|
||||
$this->_repository = $repository;
|
||||
View::share('title', 'Budgets');
|
||||
View::share('mainTitleIcon', 'fa-tasks');
|
||||
}
|
||||
|
||||
public function nobudget($view = 'session') {
|
||||
switch($view) {
|
||||
default:
|
||||
throw new FireflyException('Cannot show transactions without a budget for view "'.$view.'".');
|
||||
break;
|
||||
case 'session':
|
||||
$start = Session::get('start');
|
||||
$end = Session::get('end');
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function postUpdateIncome()
|
||||
{
|
||||
/** @var \Firefly\Helper\Preferences\PreferencesHelperInterface $preferences */
|
||||
$preferences = App::make('Firefly\Helper\Preferences\PreferencesHelperInterface');
|
||||
$date = Session::get('start');
|
||||
|
||||
// Add expenses that have no budget:
|
||||
$set = \Auth::user()->transactionjournals()->whereNotIn(
|
||||
'transaction_journals.id', function ($query) use ($start, $end) {
|
||||
$query->select('transaction_journals.id')->from('transaction_journals')
|
||||
->leftJoin(
|
||||
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
|
||||
'transaction_journals.id'
|
||||
)
|
||||
->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id')
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->where('components.class', 'Budget');
|
||||
}
|
||||
)->before($end)->after($start)->get();
|
||||
|
||||
return View::make('budgets.nobudget')
|
||||
->with('view', $view)
|
||||
->with('transactions',$set)
|
||||
->with('subTitle', 'Transactions without a budget');
|
||||
$value = intval(Input::get('amount'));
|
||||
$preferences->set('budgetIncomeTotal' . $date->format('FY'), $value);
|
||||
return Redirect::route('budgets.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this|\Illuminate\View\View
|
||||
* Update the amount for a budget's limitrepetition and/or create it.
|
||||
*
|
||||
* @param Budget $budget
|
||||
*/
|
||||
public function amount(Budget $budget)
|
||||
{
|
||||
$amount = intval(Input::get('amount'));
|
||||
$date = Session::get('start');
|
||||
/** @var \Limit $limit */
|
||||
$limit = $budget->limits()->where('startdate', $date->format('Y-m-d'))->first();
|
||||
if (!$limit) {
|
||||
// create one!
|
||||
$limit = new Limit;
|
||||
$limit->budget()->associate($budget);
|
||||
$limit->startdate = $date;
|
||||
$limit->amount = $amount;
|
||||
$limit->repeat_freq = 'monthly';
|
||||
$limit->repeats = 0;
|
||||
$limit->save();
|
||||
Event::fire('limits.store', [$limit]);
|
||||
|
||||
} else {
|
||||
if ($amount > 0) {
|
||||
$limit->amount = $amount;
|
||||
$limit->save();
|
||||
Event::fire('limits.update', [$limit]);
|
||||
} else {
|
||||
$limit->delete();
|
||||
}
|
||||
}
|
||||
// try to find the limit repetition for this limit:
|
||||
$repetition = $limit->limitrepetitions()->first();
|
||||
if ($repetition) {
|
||||
return Response::json(['name' => $budget->name, 'repetition' => $repetition->id]);
|
||||
} else {
|
||||
return Response::json(['name' => $budget->name, 'repetition' => null]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
|
||||
/** @var \Firefly\Helper\Preferences\PreferencesHelperInterface $preferences */
|
||||
$preferences = App::make('Firefly\Helper\Preferences\PreferencesHelperInterface');
|
||||
$date = Session::get('start');
|
||||
|
||||
/** @var \FireflyIII\Database\Budget $repos */
|
||||
$repos = App::make('FireflyIII\Database\Budget');
|
||||
$budgets = $repos->get();
|
||||
|
||||
// get the limits for the current month.
|
||||
$date = \Session::get('start');
|
||||
$spent = 0;
|
||||
/** @var \Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
|
||||
$budget->spent = $repos->spentInMonth($budget, $date);
|
||||
$spent += $budget->spent;
|
||||
$budget->pct = 0;
|
||||
$budget->limit = 0;
|
||||
|
||||
/** @var \Limit $limit */
|
||||
foreach ($budget->limits as $limit) {
|
||||
/** @var \LimitRepetition $repetition */
|
||||
foreach ($limit->limitrepetitions as $repetition) {
|
||||
if ($repetition->startdate == $date) {
|
||||
$budget->currentRep = $repetition;
|
||||
$budget->limit = floatval($repetition->amount);
|
||||
if ($budget->limit > $budget->spent) {
|
||||
// not overspent:
|
||||
$budget->pct = 30;
|
||||
} else {
|
||||
$budget->pct = 50;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$budgetAmount = $preferences->get('budgetIncomeTotal' . $date->format('FY'), 1000);
|
||||
$amount = floatval($budgetAmount->data);
|
||||
$overspent = $spent > $amount;
|
||||
if($overspent) {
|
||||
// overspent on total amount
|
||||
$spentPCT = ceil($amount / $spent * 100);
|
||||
} else {
|
||||
// not overspent on total amount.
|
||||
$spentPCT = ceil($spent / $amount * 100);
|
||||
}
|
||||
|
||||
return View::make('budgets.index', compact('budgets','spent','spentPCT','overspent'))->with('budgetAmount', $budgetAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function updateIncome()
|
||||
{
|
||||
$date = Session::get('start');
|
||||
/** @var \Firefly\Helper\Preferences\PreferencesHelperInterface $preferences */
|
||||
$preferences = App::make('Firefly\Helper\Preferences\PreferencesHelperInterface');
|
||||
$budgetAmount = $preferences->get('budgetIncomeTotal' . $date->format('FY'), 1000);
|
||||
return View::make('budgets.income')->with('amount', $budgetAmount)->with('date', $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param LimitRepetition $repetition
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(Budget $budget, LimitRepetition $repetition = null)
|
||||
{
|
||||
if (!is_null($repetition) && $repetition->limit->budget->id != $budget->id) {
|
||||
App::abort(500);
|
||||
}
|
||||
|
||||
if (is_null($repetition)) {
|
||||
// get all other repetitions:
|
||||
$limits = $budget->limits()->orderBy('startdate', 'DESC')->get();
|
||||
|
||||
} else {
|
||||
// get nothing? i dunno
|
||||
$limits = [$repetition->limit];
|
||||
}
|
||||
|
||||
return View::make('budgets.show', compact('limits', 'budget', 'repetition'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$periods = \Config::get('firefly.periods_to_text');
|
||||
|
||||
return View::make('budgets.create')->with('periods', $periods)->with('subTitle', 'Create a new budget');
|
||||
return View::make('budgets.create')->with('subTitle', 'Create a new budget');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,27 +182,17 @@ class BudgetController extends BaseController
|
||||
*/
|
||||
public function delete(Budget $budget)
|
||||
{
|
||||
return View::make('budgets.delete')->with('budget', $budget)
|
||||
->with('subTitle', 'Delete budget "' . $budget->name . '"');
|
||||
return View::make('budgets.delete')->with('budget', $budget)->with('subTitle', 'Delete budget "' . $budget->name . '"');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Budget $budget)
|
||||
{
|
||||
/** @var \FireflyIII\Database\Budget $repos */
|
||||
$repos = App::make('FireflyIII\Database\Budget');
|
||||
// remove budget
|
||||
Event::fire('budgets.destroy', [$budget]); // just before deletion.
|
||||
$this->_repository->destroy($budget);
|
||||
$repos->destroy($budget);
|
||||
Session::flash('success', 'The budget was deleted.');
|
||||
|
||||
// redirect:
|
||||
if (Input::get('from') == 'date') {
|
||||
return Redirect::route('budgets.index');
|
||||
}
|
||||
return Redirect::route('budgets.index.budget');
|
||||
return Redirect::route('budgets.index');
|
||||
|
||||
}
|
||||
|
||||
@ -110,142 +203,96 @@ class BudgetController extends BaseController
|
||||
*/
|
||||
public function edit(Budget $budget)
|
||||
{
|
||||
return View::make('budgets.edit')->with('budget', $budget)
|
||||
->with('subTitle', 'Edit budget "' . $budget->name . '"');
|
||||
Session::flash('prefilled', ['name' => $budget->name]);
|
||||
return View::make('budgets.edit')->with('budget', $budget)->with('subTitle', 'Edit budget "' . $budget->name . '"');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this|\Illuminate\View\View
|
||||
*/
|
||||
public function indexByBudget()
|
||||
{
|
||||
View::share('subTitleIcon', 'fa-folder-open');
|
||||
|
||||
$budgets = $this->_repository->get();
|
||||
|
||||
return View::make('budgets.indexByBudget')->with('budgets', $budgets)->with('today', new Carbon)
|
||||
->with('subTitle', 'Grouped by budget');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function indexByDate()
|
||||
{
|
||||
View::share('subTitleIcon', 'fa-calendar');
|
||||
|
||||
// get a list of dates by getting all repetitions:
|
||||
$set = $this->_repository->get();
|
||||
$budgets = $this->_budgets->organizeByDate($set);
|
||||
|
||||
return View::make('budgets.indexByDate')->with('budgets', $budgets)
|
||||
->with('subTitle', 'Grouped by date');
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Three use cases for this view:
|
||||
*
|
||||
* - Show everything.
|
||||
* - Show a specific repetition.
|
||||
* - Show everything shows NO repetition.
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param LimitRepetition $repetition
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function show(Budget $budget, \LimitRepetition $repetition = null)
|
||||
{
|
||||
$useSessionDates = Input::get('useSession') == 'true' ? true : false;
|
||||
$view = null;
|
||||
$title = null;
|
||||
\Log::debug('Is envelope true? ' . (Input::get('noenvelope') == 'true'));
|
||||
switch (true) {
|
||||
case (!is_null($repetition)):
|
||||
$data = $this->_budgets->organizeRepetition($repetition);
|
||||
$view = 1;
|
||||
$title = $budget->name . ', ' . $repetition->periodShow() . ', ' . mf(
|
||||
$repetition->limit->amount,
|
||||
false
|
||||
);
|
||||
break;
|
||||
case (Input::get('noenvelope') == 'true'):
|
||||
$data = $this->_budgets->outsideRepetitions($budget);
|
||||
$view = 2;
|
||||
$title = $budget->name . ', transactions outside an envelope';
|
||||
break;
|
||||
default:
|
||||
$data = $this->_budgets->organizeRepetitions($budget, $useSessionDates);
|
||||
$view = $useSessionDates ? 3 : 4;
|
||||
$title = $useSessionDates ? $budget->name . ' in session period' : $budget->name;
|
||||
break;
|
||||
}
|
||||
|
||||
return View::make('budgets.show')
|
||||
->with('budget', $budget)
|
||||
->with('repetitions', $data)
|
||||
->with('view', $view)
|
||||
->with('highlight', Input::get('highlight'))
|
||||
->with('useSessionDates', $useSessionDates)
|
||||
->with('subTitle', 'Overview for ' . $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
/** @var \FireflyIII\Database\Budget $repos */
|
||||
$repos = App::make('FireflyIII\Database\Budget');
|
||||
$data = Input::except('_token');
|
||||
|
||||
$budget = $this->_repository->store(Input::all());
|
||||
if ($budget->validate()) {
|
||||
Event::fire('budgets.store', [$budget]);
|
||||
Session::flash('success', 'Budget created!');
|
||||
switch ($data['post_submit_action']) {
|
||||
default:
|
||||
throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"');
|
||||
break;
|
||||
case 'create_another':
|
||||
case 'store':
|
||||
$messages = $repos->validate($data);
|
||||
/** @var MessageBag $messages ['errors'] */
|
||||
if ($messages['errors']->count() > 0) {
|
||||
Session::flash('warnings', $messages['warnings']);
|
||||
Session::flash('successes', $messages['successes']);
|
||||
Session::flash('error', 'Could not save budget: ' . $messages['errors']->first());
|
||||
return Redirect::route('budgets.create')->withInput()->withErrors($messages['errors']);
|
||||
}
|
||||
// store!
|
||||
$repos->store($data);
|
||||
Session::flash('success', 'New budget stored!');
|
||||
|
||||
if (Input::get('create') == '1') {
|
||||
return Redirect::route('budgets.create', ['from' => Input::get('from')]);
|
||||
}
|
||||
|
||||
if (Input::get('from') == 'date') {
|
||||
return Redirect::route('budgets.index');
|
||||
} else {
|
||||
return Redirect::route('budgets.index.budget');
|
||||
}
|
||||
} else {
|
||||
Session::flash('error', 'Could not save the new budget');
|
||||
|
||||
return Redirect::route('budgets.create')->withInput()->withErrors($budget->errors());
|
||||
if ($data['post_submit_action'] == 'create_another') {
|
||||
return Redirect::route('budgets.create');
|
||||
} else {
|
||||
return Redirect::route('budgets.index');
|
||||
}
|
||||
break;
|
||||
case 'validate_only':
|
||||
$messageBags = $repos->validate($data);
|
||||
Session::flash('warnings', $messageBags['warnings']);
|
||||
Session::flash('successes', $messageBags['successes']);
|
||||
Session::flash('errors', $messageBags['errors']);
|
||||
return Redirect::route('budgets.create')->withInput();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function update(Budget $budget)
|
||||
{
|
||||
$budget = $this->_repository->update($budget, Input::all());
|
||||
if ($budget->validate()) {
|
||||
Event::fire('budgets.update', [$budget]);
|
||||
Session::flash('success', 'Budget "' . $budget->name . '" updated.');
|
||||
|
||||
if (Input::get('from') == 'date') {
|
||||
return Redirect::route('budgets.index');
|
||||
} else {
|
||||
return Redirect::route('budgets.index.budget');
|
||||
}
|
||||
} else {
|
||||
Session::flash('error', 'Could not update budget: ' . $budget->errors()->first());
|
||||
/** @var \FireflyIII\Database\Budget $repos */
|
||||
$repos = App::make('FireflyIII\Database\Budget');
|
||||
$data = Input::except('_token');
|
||||
|
||||
return Redirect::route('budgets.edit', $budget->id)->withInput()->withErrors($budget->errors());
|
||||
switch (Input::get('post_submit_action')) {
|
||||
default:
|
||||
throw new FireflyException('Cannot handle post_submit_action "' . e(Input::get('post_submit_action')) . '"');
|
||||
break;
|
||||
case 'create_another':
|
||||
case 'update':
|
||||
$messages = $repos->validate($data);
|
||||
/** @var MessageBag $messages ['errors'] */
|
||||
if ($messages['errors']->count() > 0) {
|
||||
Session::flash('warnings', $messages['warnings']);
|
||||
Session::flash('successes', $messages['successes']);
|
||||
Session::flash('error', 'Could not save budget: ' . $messages['errors']->first());
|
||||
return Redirect::route('budgets.edit', $budget->id)->withInput()->withErrors($messages['errors']);
|
||||
}
|
||||
// store!
|
||||
$repos->update($budget, $data);
|
||||
Session::flash('success', 'Budget updated!');
|
||||
|
||||
if ($data['post_submit_action'] == 'create_another') {
|
||||
return Redirect::route('budgets.edit', $budget->id);
|
||||
} else {
|
||||
return Redirect::route('budgets.index');
|
||||
}
|
||||
case 'validate_only':
|
||||
$messageBags = $repos->validate($data);
|
||||
Session::flash('warnings', $messageBags['warnings']);
|
||||
Session::flash('successes', $messageBags['successes']);
|
||||
Session::flash('errors', $messageBags['errors']);
|
||||
return Redirect::route('budgets.edit', $budget->id)->withInput();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
600
app/controllers/GoogleChartController.php
Normal file
600
app/controllers/GoogleChartController.php
Normal file
@ -0,0 +1,600 @@
|
||||
<?php
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Class GoogleChartController
|
||||
*/
|
||||
class GoogleChartController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* This method renders the b
|
||||
*/
|
||||
public function allAccountsBalanceChart()
|
||||
{
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('Day of the month', 'date');
|
||||
|
||||
/** @var \FireflyIII\Shared\Preferences\Preferences $preferences */
|
||||
$preferences = App::make('FireflyIII\Shared\Preferences\Preferences');
|
||||
$pref = $preferences->get('frontpageAccounts');
|
||||
|
||||
/** @var \FireflyIII\Database\Account $acct */
|
||||
$acct = App::make('FireflyIII\Database\Account');
|
||||
$accounts = $acct->getByIds($pref->data);
|
||||
|
||||
|
||||
/*
|
||||
* Add a column for each account.
|
||||
*/
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$chart->addColumn('Balance for ' . $account->name, 'number');
|
||||
}
|
||||
/*
|
||||
* Loop the date, then loop the accounts, then add balance.
|
||||
*/
|
||||
$start = Session::get('start');
|
||||
$end = Session::get('end');
|
||||
$current = clone $start;
|
||||
|
||||
while ($end >= $current) {
|
||||
$row = [clone $current];
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
//if ($current > Carbon::now()) {
|
||||
// $row[] = 0;
|
||||
//} else {
|
||||
$row[] = $account->balance($current);
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
$chart->addRowArray($row);
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $year
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function yearInExp($year)
|
||||
{
|
||||
try {
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
App::abort(500);
|
||||
}
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('Month', 'date');
|
||||
$chart->addColumn('Income', 'number');
|
||||
$chart->addColumn('Expenses', 'number');
|
||||
|
||||
/** @var \FireflyIII\Database\TransactionJournal $tj */
|
||||
$tj = App::make('FireflyIII\Database\TransactionJournal');
|
||||
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
while ($start < $end) {
|
||||
|
||||
// total income:
|
||||
$income = $tj->getSumOfIncomesByMonth($start);
|
||||
$expense = $tj->getSumOfExpensesByMonth($start);
|
||||
|
||||
$chart->addRow(clone $start, $income, $expense);
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $year
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function yearInExpSum($year)
|
||||
{
|
||||
try {
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
App::abort(500);
|
||||
}
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('Summary', 'string');
|
||||
$chart->addColumn('Income', 'number');
|
||||
$chart->addColumn('Expenses', 'number');
|
||||
|
||||
/** @var \FireflyIII\Database\TransactionJournal $tj */
|
||||
$tj = App::make('FireflyIII\Database\TransactionJournal');
|
||||
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
$income = 0;
|
||||
$expense = 0;
|
||||
$count = 0;
|
||||
while ($start < $end) {
|
||||
|
||||
// total income:
|
||||
$income += $tj->getSumOfIncomesByMonth($start);
|
||||
$expense += $tj->getSumOfExpensesByMonth($start);
|
||||
$count++;
|
||||
|
||||
$start->addMonth();
|
||||
}
|
||||
$chart->addRow('Sum', $income, $expense);
|
||||
$count = $count > 0 ? $count : 1;
|
||||
$chart->addRow('Average', ($income / $count), ($expense / $count));
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function budgetsReportChart($year)
|
||||
{
|
||||
|
||||
try {
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
App::abort(500);
|
||||
}
|
||||
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
|
||||
/** @var \FireflyIII\Database\Budget $bdt */
|
||||
$bdt = App::make('FireflyIII\Database\Budget');
|
||||
$budgets = $bdt->get();
|
||||
|
||||
$chart->addColumn('Month', 'date');
|
||||
/** @var \Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
$chart->addColumn($budget->name, 'number');
|
||||
}
|
||||
$chart->addColumn('No budget','number');
|
||||
|
||||
/*
|
||||
* Loop budgets this year.
|
||||
*/
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
while ($start <= $end) {
|
||||
$row = [clone $start];
|
||||
|
||||
foreach($budgets as $budget) {
|
||||
$row[] = $bdt->spentInMonth($budget, $start);
|
||||
}
|
||||
|
||||
/*
|
||||
* Without a budget:
|
||||
*/
|
||||
$endOfMonth = clone $start;
|
||||
$endOfMonth->endOfMonth();
|
||||
$set = $bdt->transactionsWithoutBudgetInDateRange($start, $endOfMonth);
|
||||
$row[] = floatval($set->sum('amount')) * -1;
|
||||
|
||||
$chart->addRowArray($row);
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
}
|
||||
|
||||
public function budgetsAndSpending(Budget $budget, $year) {
|
||||
try {
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
App::abort(500);
|
||||
}
|
||||
|
||||
/** @var \FireflyIII\Database\Budget $bdt */
|
||||
$bdt = App::make('FireflyIII\Database\Budget');
|
||||
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('Month', 'date');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
while($start <= $end) {
|
||||
|
||||
$spent = $bdt->spentInMonth($budget, $start);
|
||||
$repetition = $bdt->repetitionOnStartingOnDate($budget, $start);
|
||||
if($repetition) {
|
||||
$budgeted = floatval($repetition->amount);
|
||||
} else {
|
||||
$budgeted = 0;
|
||||
}
|
||||
|
||||
$chart->addRow(clone $start, $budgeted, $spent);
|
||||
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function allBudgetsHomeChart()
|
||||
{
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('Budget', 'string');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
/** @var \FireflyIII\Database\Budget $bdt */
|
||||
$bdt = App::make('FireflyIII\Database\Budget');
|
||||
$budgets = $bdt->get();
|
||||
|
||||
/*
|
||||
* Loop budgets:
|
||||
*/
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
|
||||
/*
|
||||
* Is there a repetition starting on this particular date? We can use that.
|
||||
*/
|
||||
/** @var \LimitRepetition $repetition */
|
||||
$repetition = $bdt->repetitionOnStartingOnDate($budget, Session::get('start'));
|
||||
|
||||
/*
|
||||
* If there is, use it. Otherwise, forget it.
|
||||
*/
|
||||
if (is_null($repetition)) {
|
||||
// use the session start and end for our search query
|
||||
$searchStart = Session::get('start');
|
||||
$searchEnd = Session::get('end');
|
||||
// the limit is zero:
|
||||
$limit = 0;
|
||||
|
||||
} else {
|
||||
// use the limit's start and end for our search query
|
||||
$searchStart = $repetition->startdate;
|
||||
$searchEnd = $repetition->enddate;
|
||||
// the limit is the repetitions limit:
|
||||
$limit = floatval($repetition->amount);
|
||||
}
|
||||
|
||||
/*
|
||||
* No matter the result of the search for the repetition, get all the transactions associated
|
||||
* with the budget, and sum up the expenses made.
|
||||
*/
|
||||
$expenses = floatval($budget->transactionjournals()->before($searchEnd)->after($searchStart)->lessThan(0)->sum('amount')) * -1;
|
||||
if ($expenses > 0) {
|
||||
$chart->addRow($budget->name, $limit, $expenses);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, get all transactions WITHOUT a budget and add those as well.
|
||||
* (yes this method is oddly specific).
|
||||
*/
|
||||
$noBudgetSet = $bdt->transactionsWithoutBudgetInDateRange(Session::get('start'), Session::get('end'));
|
||||
$sum = $noBudgetSet->sum('amount') * -1;
|
||||
$chart->addRow('No budget', 0, $sum);
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function allCategoriesHomeChart()
|
||||
{
|
||||
$data = [];
|
||||
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('Category', 'string');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
/** @var \FireflyIII\Database\TransactionJournal $tj */
|
||||
$tj = App::make('FireflyIII\Database\TransactionJournal');
|
||||
|
||||
/*
|
||||
* Get the journals:
|
||||
*/
|
||||
$journals = $tj->getInDateRange(Session::get('start'), Session::get('end'));
|
||||
|
||||
/** @var \TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
if ($journal->transactionType->type == 'Withdrawal') {
|
||||
$amount = $journal->getAmount();
|
||||
$category = $journal->categories()->first();
|
||||
if (!is_null($category)) {
|
||||
if (isset($data[$category->name])) {
|
||||
$data[$category->name] += $amount;
|
||||
} else {
|
||||
$data[$category->name] = $amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
arsort($data);
|
||||
foreach ($data as $key => $entry) {
|
||||
$chart->addRow($key, $entry);
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws \Firefly\Exception\FireflyException
|
||||
*/
|
||||
public function recurringTransactionsOverview()
|
||||
{
|
||||
|
||||
/*
|
||||
* Set of paid transaction journals.
|
||||
* Set of unpaid recurring transactions.
|
||||
*/
|
||||
$paid = [
|
||||
'items' => [],
|
||||
'amount' => 0
|
||||
];
|
||||
$unpaid = [
|
||||
'items' => [],
|
||||
'amount' => 0
|
||||
];
|
||||
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('Name', 'string');
|
||||
$chart->addColumn('Amount', 'number');
|
||||
|
||||
/** @var \FireflyIII\Database\Recurring $rcr */
|
||||
$rcr = App::make('FireflyIII\Database\Recurring');
|
||||
|
||||
/** @var \FireflyIII\Shared\Toolkit\Date $dateKit */
|
||||
$dateKit = App::make('FireflyIII\Shared\Toolkit\Date');
|
||||
|
||||
$recurring = $rcr->get();
|
||||
|
||||
/** @var \RecurringTransaction $entry */
|
||||
foreach ($recurring as $entry) {
|
||||
/*
|
||||
* Start another loop starting at the $date.
|
||||
*/
|
||||
$start = clone $entry->date;
|
||||
$end = Carbon::now();
|
||||
|
||||
/*
|
||||
* The jump we make depends on the $repeat_freq
|
||||
*/
|
||||
$current = clone $start;
|
||||
|
||||
while ($current <= $end) {
|
||||
/*
|
||||
* Get end of period for $current:
|
||||
*/
|
||||
$currentEnd = clone $current;
|
||||
$dateKit->endOfPeriod($currentEnd, $entry->repeat_freq);
|
||||
|
||||
/*
|
||||
* In the current session range?
|
||||
*/
|
||||
if (\Session::get('end') >= $current and $currentEnd >= \Session::get('start')) {
|
||||
/*
|
||||
* Lets see if we've already spent money on this recurring transaction (it hath recurred).
|
||||
*/
|
||||
/** @var TransactionJournal $set */
|
||||
$journal = $rcr->getJournalForRecurringInRange($entry, $current, $currentEnd);
|
||||
|
||||
if (is_null($journal)) {
|
||||
$unpaid['items'][] = $entry->name;
|
||||
$unpaid['amount'] += (($entry->amount_max + $entry->amount_min) / 2);
|
||||
} else {
|
||||
$amount = $journal->getAmount();
|
||||
$paid['items'][] = $journal->description;
|
||||
$paid['amount'] += $amount;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add some time for the next loop!
|
||||
*/
|
||||
$dateKit->addPeriod($current, $entry->repeat_freq, intval($entry->skip));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/** @var \RecurringTransaction $entry */
|
||||
$chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
|
||||
$chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*/
|
||||
public function accountBalanceChart(Account $account)
|
||||
{
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('Day of month', 'date');
|
||||
$chart->addColumn('Balance for ' . $account->name, 'number');
|
||||
|
||||
/*
|
||||
* Loop the date, then loop the accounts, then add balance.
|
||||
*/
|
||||
$start = Session::get('start');
|
||||
$end = Session::get('end');
|
||||
$current = clone $start;
|
||||
|
||||
while ($end >= $current) {
|
||||
$row = [clone $current];
|
||||
if ($current > Carbon::now()) {
|
||||
$row[] = null;
|
||||
} else {
|
||||
$row[] = $account->balance($current);
|
||||
}
|
||||
|
||||
$chart->addRowArray($row);
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function accountSankeyOutChart(Account $account)
|
||||
{
|
||||
// collect all relevant entries.
|
||||
$set = [];
|
||||
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('From', 'string');
|
||||
$chart->addColumn('To', 'string', 'domain');
|
||||
$chart->addColumn('Weight', 'number');
|
||||
|
||||
$transactions = $account->transactions()->with(
|
||||
['transactionjournal', 'transactionjournal.transactions', 'transactionjournal.budgets', 'transactionjournal.transactiontype',
|
||||
'transactionjournal.categories']
|
||||
)->before(Session::get('end'))->after(
|
||||
Session::get('start')
|
||||
)->get();
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$amount = floatval($transaction->amount);
|
||||
$type = $transaction->transactionJournal->transactionType->type;
|
||||
|
||||
if ($amount < 0 && $type != 'Transfer') {
|
||||
|
||||
// from account to a budget (if present).
|
||||
$budgetName = isset($transaction->transactionJournal->budgets[0]) ? $transaction->transactionJournal->budgets[0]->name : '(no budget)';
|
||||
$set[] = [$account->name, $budgetName, $amount * -1];
|
||||
|
||||
// from budget to category.
|
||||
$categoryName = isset($transaction->transactionJournal->categories[0]) ? ' ' . $transaction->transactionJournal->categories[0]->name
|
||||
: '(no cat)';
|
||||
$set[] = [$budgetName, $categoryName, $amount * -1];
|
||||
}
|
||||
}
|
||||
// loop the set, group everything together:
|
||||
$grouped = [];
|
||||
foreach ($set as $entry) {
|
||||
$key = $entry[0] . $entry[1];
|
||||
if (isset($grouped[$key])) {
|
||||
$grouped[$key][2] += $entry[2];
|
||||
} else {
|
||||
$grouped[$key] = $entry;
|
||||
}
|
||||
}
|
||||
|
||||
// add rows to the chart:
|
||||
foreach ($grouped as $entry) {
|
||||
$chart->addRow($entry[0], $entry[1], $entry[2]);
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function accountSankeyInChart(Account $account)
|
||||
{
|
||||
// collect all relevant entries.
|
||||
$set = [];
|
||||
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('From', 'string');
|
||||
$chart->addColumn('To', 'string', 'domain');
|
||||
$chart->addColumn('Weight', 'number');
|
||||
|
||||
$transactions = $account->transactions()->with(
|
||||
['transactionjournal', 'transactionjournal.transactions' => function ($q) {
|
||||
$q->where('amount', '<', 0);
|
||||
}, 'transactionjournal.budgets', 'transactionjournal.transactiontype', 'transactionjournal.categories']
|
||||
)->before(Session::get('end'))->after(
|
||||
Session::get('start')
|
||||
)->get();
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$amount = floatval($transaction->amount);
|
||||
$type = $transaction->transactionJournal->transactionType->type;
|
||||
|
||||
if ($amount > 0 && $type != 'Transfer') {
|
||||
|
||||
$otherAccount = $transaction->transactionJournal->transactions[0]->account->name;
|
||||
$categoryName = isset($transaction->transactionJournal->categories[0]) ? $transaction->transactionJournal->categories[0]->name
|
||||
: '(no cat)';
|
||||
$set[] = [$otherAccount, $categoryName, $amount];
|
||||
$set[] = [$categoryName, $account->name, $amount];
|
||||
}
|
||||
}
|
||||
// loop the set, group everything together:
|
||||
$grouped = [];
|
||||
foreach ($set as $entry) {
|
||||
$key = $entry[0] . $entry[1];
|
||||
if (isset($grouped[$key])) {
|
||||
$grouped[$key][2] += $entry[2];
|
||||
} else {
|
||||
$grouped[$key] = $entry;
|
||||
}
|
||||
}
|
||||
|
||||
// add rows to the chart:
|
||||
foreach ($grouped as $entry) {
|
||||
$chart->addRow($entry[0], $entry[1], $entry[2]);
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
}
|
240
app/controllers/GoogleTableController.php
Normal file
240
app/controllers/GoogleTableController.php
Normal file
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
use Carbon\Carbon;
|
||||
use Firefly\Exception\FireflyException;
|
||||
|
||||
/**
|
||||
* Class GoogleTableController
|
||||
*/
|
||||
class GoogleTableController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $what
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function accountList($what)
|
||||
{
|
||||
|
||||
/** @var \FireflyIII\Database\Account $acct */
|
||||
$acct = App::make('FireflyIII\Database\Account');
|
||||
|
||||
switch ($what) {
|
||||
default:
|
||||
throw new FireflyException('Cannot handle "' . e($what) . '" in accountList.');
|
||||
break;
|
||||
case 'asset':
|
||||
$list = $acct->getAssetAccounts();
|
||||
break;
|
||||
case 'expense':
|
||||
$list = $acct->getExpenseAccounts();
|
||||
break;
|
||||
case 'revenue':
|
||||
$list = $acct->getRevenueAccounts();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('ID', 'number');
|
||||
$chart->addColumn('ID_Edit', 'string');
|
||||
$chart->addColumn('ID_Delete', 'string');
|
||||
$chart->addColumn('Name_URL', 'string');
|
||||
$chart->addColumn('Name', 'string');
|
||||
$chart->addColumn('Balance', 'number');
|
||||
|
||||
/** @var \Account $entry */
|
||||
foreach ($list as $entry) {
|
||||
$edit = route('accounts.edit', $entry->id);
|
||||
$delete = route('accounts.delete', $entry->id);
|
||||
$show = route('accounts.show', $entry->id);
|
||||
$chart->addRow($entry->id, $edit, $delete, $show, $entry->name, $entry->balance());
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param LimitRepetition $repetition
|
||||
*/
|
||||
public function transactionsByBudget(Budget $budget, LimitRepetition $repetition = null)
|
||||
{
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('ID', 'number');
|
||||
$chart->addColumn('ID_Edit', 'string');
|
||||
$chart->addColumn('ID_Delete', 'string');
|
||||
$chart->addColumn('Date', 'date');
|
||||
$chart->addColumn('Description_URL', 'string');
|
||||
$chart->addColumn('Description', 'string');
|
||||
$chart->addColumn('Amount', 'number');
|
||||
$chart->addColumn('From_URL', 'string');
|
||||
$chart->addColumn('From', 'string');
|
||||
$chart->addColumn('To_URL', 'string');
|
||||
$chart->addColumn('To', 'string');
|
||||
$chart->addColumn('Budget_URL', 'string');
|
||||
$chart->addColumn('Budget', 'string');
|
||||
$chart->addColumn('Category_URL', 'string');
|
||||
$chart->addColumn('Category', 'string');
|
||||
|
||||
if (is_null($repetition)) {
|
||||
$journals = $budget->transactionjournals()->with(['budgets', 'categories', 'transactions', 'transactions.account'])->orderBy('date', 'DESC')->get();
|
||||
} else {
|
||||
$journals = $budget->transactionjournals()->with(['budgets', 'categories', 'transactions', 'transactions.account'])->
|
||||
after($repetition->startdate)->before($repetition->enddate)->orderBy('date', 'DESC')->get();
|
||||
}
|
||||
/** @var TransactionJournal $transaction */
|
||||
foreach ($journals as $journal) {
|
||||
$date = $journal->date;
|
||||
$descriptionURL = route('transactions.show', $journal->id);
|
||||
$description = $journal->description;
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($journal->transactions as $transaction) {
|
||||
if (floatval($transaction->amount) > 0) {
|
||||
$amount = floatval($transaction->amount);
|
||||
$to = $transaction->account->name;
|
||||
$toURL = route('accounts.show', $transaction->account->id);
|
||||
} else {
|
||||
$from = $transaction->account->name;
|
||||
$fromURL = route('accounts.show', $transaction->account->id);
|
||||
}
|
||||
|
||||
}
|
||||
if (isset($journal->budgets[0])) {
|
||||
$budgetURL = route('budgets.show', $journal->budgets[0]->id);
|
||||
$budget = $journal->budgets[0]->name;
|
||||
} else {
|
||||
$budgetURL = '';
|
||||
$budget = '';
|
||||
}
|
||||
|
||||
if (isset($journal->categories[0])) {
|
||||
$categoryURL = route('categories.show', $journal->categories[0]->id);
|
||||
$category = $journal->categories[0]->name;
|
||||
} else {
|
||||
$categoryURL = '';
|
||||
$category = '';
|
||||
}
|
||||
|
||||
|
||||
$id = $journal->id;
|
||||
$edit = route('transactions.edit', $journal->id);
|
||||
$delete = route('transactions.delete', $journal->id);
|
||||
$chart->addRow(
|
||||
$id, $edit, $delete, $date, $descriptionURL, $description, $amount, $fromURL, $from, $toURL, $to, $budgetURL, $budget, $categoryURL,
|
||||
$category
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*/
|
||||
public function transactionsByAccount(Account $account)
|
||||
{
|
||||
/** @var \Grumpydictator\Gchart\GChart $chart */
|
||||
$chart = App::make('gchart');
|
||||
$chart->addColumn('ID', 'number');
|
||||
$chart->addColumn('ID_Edit', 'string');
|
||||
$chart->addColumn('ID_Delete', 'string');
|
||||
$chart->addColumn('Date', 'date');
|
||||
$chart->addColumn('Description_URL', 'string');
|
||||
$chart->addColumn('Description', 'string');
|
||||
$chart->addColumn('Amount', 'number');
|
||||
$chart->addColumn('From_URL', 'string');
|
||||
$chart->addColumn('From', 'string');
|
||||
$chart->addColumn('To_URL', 'string');
|
||||
$chart->addColumn('To', 'string');
|
||||
$chart->addColumn('Budget_URL', 'string');
|
||||
$chart->addColumn('Budget', 'string');
|
||||
$chart->addColumn('Category_URL', 'string');
|
||||
$chart->addColumn('Category', 'string');
|
||||
|
||||
/*
|
||||
* Find transactions:
|
||||
*/
|
||||
$accountID = $account->id;
|
||||
$transactions = $account->transactions()->with(
|
||||
['transactionjournal', 'transactionjournal.transactions' => function ($q) use ($accountID) {
|
||||
$q->where('account_id', '!=', $accountID);
|
||||
}, 'transactionjournal.budgets', 'transactionjournal.transactiontype',
|
||||
'transactionjournal.categories']
|
||||
)->before(Session::get('end'))->after(
|
||||
Session::get('start')
|
||||
)->orderBy('date', 'DESC')->get();
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$date = $transaction->transactionJournal->date;
|
||||
$descriptionURL = route('transactions.show', $transaction->transaction_journal_id);
|
||||
$description = $transaction->transactionJournal->description;
|
||||
$amount = floatval($transaction->amount);
|
||||
|
||||
if ($transaction->transactionJournal->transactions[0]->account->id == $account->id) {
|
||||
$opposingAccountURI = route('accounts.show', $transaction->transactionJournal->transactions[1]->account->id);
|
||||
$opposingAccountName = $transaction->transactionJournal->transactions[1]->account->name;
|
||||
} else {
|
||||
$opposingAccountURI = route('accounts.show', $transaction->transactionJournal->transactions[0]->account->id);
|
||||
$opposingAccountName = $transaction->transactionJournal->transactions[0]->account->name;
|
||||
}
|
||||
if (isset($transaction->transactionJournal->budgets[0])) {
|
||||
$budgetURL = route('budgets.show', $transaction->transactionJournal->budgets[0]->id);
|
||||
$budget = $transaction->transactionJournal->budgets[0]->name;
|
||||
} else {
|
||||
$budgetURL = '';
|
||||
$budget = '';
|
||||
}
|
||||
|
||||
if (isset($transaction->transactionJournal->categories[0])) {
|
||||
$categoryURL = route('categories.show', $transaction->transactionJournal->categories[0]->id);
|
||||
$category = $transaction->transactionJournal->categories[0]->name;
|
||||
} else {
|
||||
$categoryURL = '';
|
||||
$category = '';
|
||||
}
|
||||
|
||||
|
||||
if ($amount < 0) {
|
||||
$from = $account->name;
|
||||
$fromURL = route('accounts.show', $account->id);
|
||||
|
||||
$to = $opposingAccountName;
|
||||
$toURL = $opposingAccountURI;
|
||||
} else {
|
||||
$to = $account->name;
|
||||
$toURL = route('accounts.show', $account->id);
|
||||
|
||||
$from = $opposingAccountName;
|
||||
$fromURL = $opposingAccountURI;
|
||||
}
|
||||
|
||||
$id = $transaction->transactionJournal->id;
|
||||
$edit = route('transactions.edit', $transaction->transactionJournal->id);
|
||||
$delete = route('transactions.delete', $transaction->transactionJournal->id);
|
||||
$chart->addRow(
|
||||
$id, $edit, $delete, $date, $descriptionURL, $description, $amount, $fromURL, $from, $toURL, $to, $budgetURL, $budget, $categoryURL, $category
|
||||
);
|
||||
}
|
||||
|
||||
// <th>Date</th>
|
||||
// <th>Description</th>
|
||||
// <th>Amount (€)</th>
|
||||
// <th>From</th>
|
||||
// <th>To</th>
|
||||
// <th>Budget / category</th>
|
||||
// <th>ID</th>
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
}
|
||||
}
|
@ -15,8 +15,8 @@ class HomeController extends BaseController
|
||||
protected $_journal;
|
||||
|
||||
/**
|
||||
* @param ARI $accounts
|
||||
* @param PHI $preferences
|
||||
* @param ARI $accounts
|
||||
* @param PHI $preferences
|
||||
* @param TJRI $journal
|
||||
*/
|
||||
public function __construct(ARI $accounts, PHI $preferences, TJRI $journal)
|
||||
@ -115,4 +115,59 @@ class HomeController extends BaseController
|
||||
return View::make('index')->with('count', $count)->with('transactions', $transactions)->with('title', 'Firefly')
|
||||
->with('subTitle', 'What\'s playing?')->with('mainTitleIcon', 'fa-fire');
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
/** @var \FireflyIII\Database\TransactionJournal $jrnls */
|
||||
$jrnls = App::make('FireflyIII\Database\TransactionJournal');
|
||||
|
||||
/** @var \FireflyIII\Database\Account $acct */
|
||||
$acct = \App::make('FireflyIII\Database\Account');
|
||||
|
||||
/** @var \FireflyIII\Database\AccountType $acctType */
|
||||
$acctType = \App::make('FireflyIII\Database\AccountType');
|
||||
$rightAcctType = $acctType->findByWhat('revenue');
|
||||
|
||||
$all = $jrnls->get();
|
||||
|
||||
/** @var \TransactionJournal $entry */
|
||||
foreach ($all as $entry) {
|
||||
$wrongFromType = false;
|
||||
$wrongToType = false;
|
||||
$transactions = $entry->transactions;
|
||||
if (count($transactions) == 2) {
|
||||
switch ($entry->transactionType->type) {
|
||||
case 'Deposit':
|
||||
/** @var \Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
if (floatval($transaction->amount) < 0) {
|
||||
$accountType = $transaction->account->accountType;
|
||||
if ($accountType->type == 'Beneficiary account') {
|
||||
// should be a Revenue account!
|
||||
$name = $transaction->account->name;
|
||||
/** @var \Account $account */
|
||||
$account = \Auth::user()->accounts()->where('name', $name)->where('account_type_id', $rightAcctType->id)->first();
|
||||
if (!$account) {
|
||||
$new = [
|
||||
'name' => $name,
|
||||
'what' => 'revenue'
|
||||
];
|
||||
$account = $acct->store($new);
|
||||
}
|
||||
$transaction->account()->associate($account);
|
||||
$transaction->save();
|
||||
}
|
||||
|
||||
echo 'Paid by: ' . $transaction->account->name . ' (' . $transaction->account->accountType->type . ')<br />';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,31 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Firefly\Exception\FireflyException;
|
||||
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
|
||||
use Firefly\Storage\Piggybank\PiggybankRepositoryInterface as PRI;
|
||||
use FireflyIII\Exception\NotImplementedException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\MessageBag;
|
||||
|
||||
/**
|
||||
* Class PiggybankController
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
* @SuppressWarnings(PHPMD.TooManyMethods)
|
||||
*
|
||||
*/
|
||||
class PiggybankController extends BaseController
|
||||
{
|
||||
|
||||
protected $_accounts;
|
||||
protected $_repository;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PRI $repository
|
||||
* @param ARI $accounts
|
||||
* @throws NotImplementedException
|
||||
*/
|
||||
public function __construct(PRI $repository, ARI $accounts)
|
||||
public function create()
|
||||
{
|
||||
$this->_repository = $repository;
|
||||
$this->_accounts = $accounts;
|
||||
|
||||
/** @var \FireflyIII\Database\Account $acct */
|
||||
$acct = App::make('FireflyIII\Database\Account');
|
||||
|
||||
/** @var \FireflyIII\Shared\Toolkit\Form $toolkit */
|
||||
$toolkit = App::make('FireflyIII\Shared\Toolkit\Form');
|
||||
|
||||
$periods = Config::get('firefly.piggybank_periods');
|
||||
|
||||
|
||||
$accounts = $toolkit->makeSelectList($acct->getAssetAccounts());
|
||||
return View::make('piggybanks.create', compact('accounts', 'periods'))->with('title', 'Piggy banks')->with('mainTitleIcon', 'fa-sort-amount-asc')
|
||||
->with('subTitle', 'Create new piggy bank')->with('subTitleIcon', 'fa-plus');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,74 +44,13 @@ class PiggybankController extends BaseController
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addMoney(Piggybank $piggyBank)
|
||||
public function delete(Piggybank $piggybank)
|
||||
{
|
||||
$what = 'add';
|
||||
$maxAdd = $this->_repository->leftOnAccount($piggyBank->account);
|
||||
$maxRemove = null;
|
||||
|
||||
return View::make('piggybanks.modifyAmount')->with('what', $what)->with('maxAdd', $maxAdd)->with(
|
||||
'maxRemove', $maxRemove
|
||||
)->with('piggybank', $piggyBank);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function createPiggybank()
|
||||
{
|
||||
/** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */
|
||||
$toolkit = App::make('Firefly\Helper\Toolkit\Toolkit');
|
||||
|
||||
|
||||
$periods = Config::get('firefly.piggybank_periods');
|
||||
$list = $this->_accounts->getActiveDefault();
|
||||
$accounts = $toolkit->makeSelectList($list);
|
||||
|
||||
View::share('subTitle', 'Delete "' . $piggybank->name . '"');
|
||||
View::share('title', 'Piggy banks');
|
||||
View::share('subTitle', 'Create new');
|
||||
View::share('mainTitleIcon', 'fa-sort-amount-asc');
|
||||
|
||||
return View::make('piggybanks.create-piggybank')->with('accounts', $accounts)
|
||||
->with('periods', $periods);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function createRepeated()
|
||||
{
|
||||
/** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */
|
||||
$toolkit = App::make('Firefly\Helper\Toolkit\Toolkit');
|
||||
|
||||
$periods = Config::get('firefly.piggybank_periods');
|
||||
$list = $this->_accounts->getActiveDefault();
|
||||
$accounts = $toolkit->makeSelectList($list);
|
||||
|
||||
View::share('title', 'Repeated expenses');
|
||||
View::share('subTitle', 'Create new');
|
||||
View::share('mainTitleIcon', 'fa-rotate-right');
|
||||
|
||||
return View::make('piggybanks.create-repeated')->with('accounts', $accounts)->with('periods', $periods);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Piggybank $piggyBank
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function delete(Piggybank $piggyBank)
|
||||
{
|
||||
View::share('subTitle', 'Delete "' . $piggyBank->name . '"');
|
||||
if ($piggyBank->repeats == 1) {
|
||||
View::share('title', 'Repeated expenses');
|
||||
View::share('mainTitleIcon', 'fa-rotate-right');
|
||||
} else {
|
||||
View::share('title', 'Piggy banks');
|
||||
View::share('mainTitleIcon', 'fa-sort-amount-asc');
|
||||
}
|
||||
|
||||
return View::make('piggybanks.delete')->with('piggybank', $piggyBank);
|
||||
return View::make('piggybanks.delete')->with('piggybank', $piggybank);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,18 +61,13 @@ class PiggybankController extends BaseController
|
||||
public function destroy(Piggybank $piggyBank)
|
||||
{
|
||||
Event::fire('piggybanks.destroy', [$piggyBank]);
|
||||
if ($piggyBank->repeats == 1) {
|
||||
$route = 'piggybanks.index.repeated';
|
||||
$message = 'Repeated expense';
|
||||
} else {
|
||||
$route = 'piggybanks.index.piggybanks';
|
||||
$message = 'Piggybank';
|
||||
}
|
||||
$this->_repository->destroy($piggyBank);
|
||||
|
||||
Session::flash('success', $message . ' deleted.');
|
||||
/** @var \FireflyIII\Database\Piggybank $acct */
|
||||
$repos = App::make('FireflyIII\Database\Piggybank');
|
||||
$repos->destroy($piggyBank);
|
||||
Session::flash('success', 'Piggy bank deleted.');
|
||||
|
||||
return Redirect::route($route);
|
||||
return Redirect::route('piggybanks.index');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,245 +75,203 @@ class PiggybankController extends BaseController
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function edit(Piggybank $piggyBank)
|
||||
public function edit(Piggybank $piggybank)
|
||||
{
|
||||
/** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */
|
||||
$toolkit = App::make('Firefly\Helper\Toolkit\Toolkit');
|
||||
|
||||
$list = $this->_accounts->getActiveDefault();
|
||||
$accounts = $toolkit->makeSelectList($list);
|
||||
$periods = Config::get('firefly.piggybank_periods');
|
||||
/** @var \FireflyIII\Database\Account $acct */
|
||||
$acct = App::make('FireflyIII\Database\Account');
|
||||
|
||||
/** @var \FireflyIII\Shared\Toolkit\Form $toolkit */
|
||||
$toolkit = App::make('FireflyIII\Shared\Toolkit\Form');
|
||||
|
||||
View::share('subTitle', 'Edit "' . $piggyBank->name . '"');
|
||||
$periods = Config::get('firefly.piggybank_periods');
|
||||
|
||||
$accounts = $toolkit->makeSelectList($acct->getAssetAccounts());
|
||||
|
||||
if ($piggyBank->repeats == 1) {
|
||||
View::share('title', 'Repeated expenses');
|
||||
View::share('mainTitleIcon', 'fa-rotate-left');
|
||||
|
||||
return View::make('piggybanks.edit-repeated')->with('piggybank', $piggyBank)->with('accounts', $accounts)
|
||||
->with('periods', $periods);
|
||||
} else {
|
||||
// piggy bank.
|
||||
View::share('title', 'Piggy banks');
|
||||
View::share('mainTitleIcon', 'fa-sort-amount-asc');
|
||||
|
||||
return View::make('piggybanks.edit-piggybank')->with('piggybank', $piggyBank)->with('accounts', $accounts)
|
||||
->with('periods', $periods);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flash some data to fill the form.
|
||||
*/
|
||||
$prefilled = [
|
||||
'name' => $piggybank->name,
|
||||
'account_id' => $piggybank->account_id,
|
||||
'targetamount' => $piggybank->targetamount,
|
||||
'targetdate' => $piggybank->targetdate,
|
||||
'remind_me' => intval($piggybank->remind_me) == 1 ? true : false
|
||||
];
|
||||
Session::flash('prefilled', $prefilled);
|
||||
|
||||
return View::make('piggybanks.edit', compact('piggybank', 'accounts', 'periods', 'prefilled'))->with('title', 'Piggybanks')->with(
|
||||
'mainTitleIcon', 'fa-sort-amount-asc'
|
||||
)
|
||||
->with('subTitle', 'Edit piggy bank "' . e($piggybank->name) . '"')->with('subTitleIcon', 'fa-pencil');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Piggybank $piggyBank
|
||||
* @param Piggybank $piggybank
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function add(Piggybank $piggybank)
|
||||
{
|
||||
/** @var \FireflyIII\Database\Piggybank $acct */
|
||||
$repos = App::make('FireflyIII\Database\Piggybank');
|
||||
|
||||
$leftOnAccount = $repos->leftOnAccount($piggybank->account);
|
||||
$savedSoFar = $piggybank->currentRelevantRep()->currentamount;
|
||||
$leftToSave = $piggybank->targetamount - $savedSoFar;
|
||||
$amount = min($leftOnAccount, $leftToSave);
|
||||
|
||||
|
||||
return View::make('piggybanks.add', compact('piggybank'))->with('maxAmount', $amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Piggybank $piggybank
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws Firefly\Exception\FireflyException
|
||||
*/
|
||||
public function modMoney(Piggybank $piggyBank)
|
||||
public function postAdd(Piggybank $piggybank)
|
||||
{
|
||||
$amount = round(floatval(Input::get('amount')), 2);
|
||||
|
||||
/** @var \FireflyIII\Database\Piggybank $acct */
|
||||
$repos = App::make('FireflyIII\Database\Piggybank');
|
||||
|
||||
$leftOnAccount = $repos->leftOnAccount($piggybank->account);
|
||||
$savedSoFar = $piggybank->currentRelevantRep()->currentamount;
|
||||
$leftToSave = $piggybank->targetamount - $savedSoFar;
|
||||
$maxAmount = round(min($leftOnAccount, $leftToSave), 2);
|
||||
|
||||
if ($amount <= $maxAmount) {
|
||||
$repetition = $piggybank->currentRelevantRep();
|
||||
$repetition->currentamount += $amount;
|
||||
$repetition->save();
|
||||
Session::flash('success', 'Added ' . mf($amount, false) . ' to "' . e($piggybank->name) . '".');
|
||||
} else {
|
||||
Session::flash('error', 'Could not add ' . mf($amount, false) . ' to "' . e($piggybank->name) . '".');
|
||||
}
|
||||
return Redirect::route('piggybanks.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Piggybank $piggybank
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function remove(Piggybank $piggybank)
|
||||
{
|
||||
return View::make('piggybanks.remove', compact('piggybank'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Piggybank $piggybank
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function postRemove(Piggybank $piggybank)
|
||||
{
|
||||
$amount = floatval(Input::get('amount'));
|
||||
switch (Input::get('what')) {
|
||||
default:
|
||||
throw new FireflyException('No such action');
|
||||
break;
|
||||
case 'add':
|
||||
$maxAdd = $this->_repository->leftOnAccount($piggyBank->account);
|
||||
if (round($amount, 2) <= round(min($maxAdd, $piggyBank->targetamount), 2)) {
|
||||
Session::flash('success', 'Amount updated!');
|
||||
$this->_repository->modifyAmount($piggyBank, $amount);
|
||||
Event::fire('piggybanks.modifyAmountAdd', [$piggyBank, $amount]);
|
||||
} else {
|
||||
Session::flash('warning', 'Could not!');
|
||||
}
|
||||
break;
|
||||
case 'remove':
|
||||
$rep = $piggyBank->currentRelevantRep();
|
||||
$maxRemove = $rep->currentamount;
|
||||
if (round($amount, 2) <= round($maxRemove, 2)) {
|
||||
Session::flash('success', 'Amount updated!');
|
||||
$this->_repository->modifyAmount($piggyBank, ($amount * -1));
|
||||
Event::fire('piggybanks.modifyAmountRemove', [$piggyBank, ($amount * -1)]);
|
||||
} else {
|
||||
Session::flash('warning', 'Could not!');
|
||||
}
|
||||
break;
|
||||
}
|
||||
if($piggyBank->repeats == 1) {
|
||||
$route = 'piggybanks.index.repeated';
|
||||
|
||||
$savedSoFar = $piggybank->currentRelevantRep()->currentamount;
|
||||
|
||||
if ($amount <= $savedSoFar) {
|
||||
$repetition = $piggybank->currentRelevantRep();
|
||||
$repetition->currentamount -= $amount;
|
||||
$repetition->save();
|
||||
Session::flash('success', 'Removed ' . mf($amount, false) . ' from "' . e($piggybank->name) . '".');
|
||||
} else {
|
||||
$route = 'piggybanks.index.piggybanks';
|
||||
Session::flash('error', 'Could not remove ' . mf($amount, false) . ' from "' . e($piggybank->name) . '".');
|
||||
}
|
||||
return Redirect::route($route);
|
||||
return Redirect::route('piggybanks.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function piggybanks()
|
||||
public function index()
|
||||
{
|
||||
$countRepeating = $this->_repository->countRepeating();
|
||||
$countNonRepeating = $this->_repository->countNonrepeating();
|
||||
/** @var \FireflyIII\Database\Piggybank $repos */
|
||||
$repos = App::make('FireflyIII\Database\Piggybank');
|
||||
|
||||
$piggybanks = $this->_repository->get();
|
||||
|
||||
// get the accounts with each piggy bank and check their balance; Fireflyy might needs to
|
||||
// show the user a correction.
|
||||
/** @var Collection $piggybanks */
|
||||
$piggybanks = $repos->get();
|
||||
|
||||
$accounts = [];
|
||||
/** @var \Piggybank $piggybank */
|
||||
/** @var Piggybank $piggybank */
|
||||
foreach ($piggybanks as $piggybank) {
|
||||
$piggybank->savedSoFar = floatval($piggybank->currentRelevantRep()->currentamount);
|
||||
$piggybank->percentage = intval($piggybank->savedSoFar / $piggybank->targetamount * 100);
|
||||
$piggybank->leftToSave = $piggybank->targetamount - $piggybank->savedSoFar;
|
||||
|
||||
/*
|
||||
* Fill account information:
|
||||
*/
|
||||
$account = $piggybank->account;
|
||||
$id = $account->id;
|
||||
if (!isset($accounts[$id])) {
|
||||
$account->leftOnAccount = $this->_repository->leftOnAccount($account);
|
||||
$accounts[$id] = ['account' => $account, 'left' => $this->_repository->leftOnAccount($account)];
|
||||
if (!isset($accounts[$account->id])) {
|
||||
$accounts[$account->id] = [
|
||||
'name' => $account->name,
|
||||
'balance' => $account->balance(),
|
||||
'leftForPiggybanks' => $repos->leftOnAccount($account),
|
||||
'sumOfSaved' => $piggybank->savedSoFar,
|
||||
'sumOfTargets' => floatval($piggybank->targetamount),
|
||||
'leftToSave' => $piggybank->leftToSave
|
||||
];
|
||||
} else {
|
||||
$accounts[$account->id]['sumOfSaved'] += $piggybank->savedSoFar;
|
||||
$accounts[$account->id]['sumOfTargets'] += floatval($piggybank->targetamount);
|
||||
$accounts[$account->id]['leftToSave'] += $piggybank->leftToSave;
|
||||
}
|
||||
}
|
||||
|
||||
View::share('title', 'Piggy banks');
|
||||
View::share('subTitle', 'Save for big expenses');
|
||||
View::share('mainTitleIcon', 'fa-sort-amount-asc');
|
||||
|
||||
return View::make('piggybanks.index')->with('piggybanks', $piggybanks)
|
||||
->with('countRepeating', $countRepeating)
|
||||
->with('countNonRepeating', $countNonRepeating)
|
||||
->with('accounts', $accounts);
|
||||
return View::make('piggybanks.index', compact('piggybanks', 'accounts'))->with('title', 'Piggy banks')->with('mainTitleIcon', 'fa-sort-amount-asc');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Piggybank $piggyBank
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeMoney(Piggybank $piggyBank)
|
||||
{
|
||||
$what = 'remove';
|
||||
$maxAdd = $this->_repository->leftOnAccount($piggyBank->account);
|
||||
$maxRemove = $piggyBank->currentRelevantRep()->currentamount;
|
||||
|
||||
return View::make('piggybanks.modifyAmount')->with('what', $what)->with('maxAdd', $maxAdd)->with(
|
||||
'maxRemove', $maxRemove
|
||||
)->with('piggybank', $piggyBank);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function repeated()
|
||||
{
|
||||
$countRepeating = $this->_repository->countRepeating();
|
||||
$countNonRepeating = $this->_repository->countNonrepeating();
|
||||
|
||||
$piggybanks = $this->_repository->get();
|
||||
|
||||
// get the accounts with each piggy bank and check their balance; Fireflyy might needs to
|
||||
// show the user a correction.
|
||||
|
||||
$accounts = [];
|
||||
/** @var \Piggybank $piggybank */
|
||||
foreach ($piggybanks as $piggybank) {
|
||||
$account = $piggybank->account;
|
||||
$id = $account->id;
|
||||
if (!isset($accounts[$id])) {
|
||||
$account->leftOnAccount = $this->_repository->leftOnAccount($account);
|
||||
$accounts[$id] = ['account' => $account, 'left' => $this->_repository->leftOnAccount($account)];
|
||||
}
|
||||
}
|
||||
|
||||
View::share('title', 'Repeated expenses');
|
||||
View::share('subTitle', 'Save for returning bills');
|
||||
View::share('mainTitleIcon', 'fa-rotate-left');
|
||||
|
||||
|
||||
return View::make('piggybanks.index')->with('piggybanks', $piggybanks)
|
||||
->with('countRepeating', $countRepeating)
|
||||
->with('countNonRepeating', $countNonRepeating)
|
||||
->with('accounts', $accounts);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function show(Piggybank $piggyBank)
|
||||
{
|
||||
$leftOnAccount = $this->_repository->leftOnAccount($piggyBank->account);
|
||||
$balance = $piggyBank->account->balance();
|
||||
|
||||
View::share('subTitle', $piggyBank->name);
|
||||
|
||||
if ($piggyBank->repeats == 1) {
|
||||
// repeated expense.
|
||||
View::share('title', 'Repeated expenses');
|
||||
View::share('mainTitleIcon', 'fa-rotate-left');
|
||||
} else {
|
||||
// piggy bank.
|
||||
View::share('title', 'Piggy banks');
|
||||
View::share('mainTitleIcon', 'fa-sort-amount-asc');
|
||||
}
|
||||
|
||||
return View::make('piggybanks.show')->with('piggyBank', $piggyBank)->with('leftOnAccount', $leftOnAccount)
|
||||
->with('balance', $balance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function storePiggybank()
|
||||
{
|
||||
$data = Input::all();
|
||||
unset($data['_token']);
|
||||
|
||||
// extend the data array with the settings needed to create a piggy bank:
|
||||
$data['repeats'] = 0;
|
||||
$data['rep_times'] = 1;
|
||||
$data['rep_every'] = 1;
|
||||
$data['order'] = 0;
|
||||
|
||||
$piggyBank = $this->_repository->store($data);
|
||||
if (!is_null($piggyBank->id)) {
|
||||
Session::flash('success', 'New piggy bank "' . $piggyBank->name . '" created!');
|
||||
Event::fire('piggybanks.store', [$piggyBank]);
|
||||
|
||||
return Redirect::route('piggybanks.index.piggybanks');
|
||||
|
||||
|
||||
} else {
|
||||
Session::flash('error', 'Could not save piggy bank: ' . $piggyBank->errors()->first());
|
||||
|
||||
return Redirect::route('piggybanks.create.piggybank')->withInput()->withErrors($piggyBank->errors());
|
||||
}
|
||||
throw new NotImplementedException;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this|\Illuminate\Http\RedirectResponse
|
||||
*
|
||||
*/
|
||||
public function storeRepeated()
|
||||
public function store()
|
||||
{
|
||||
$data = Input::all();
|
||||
$data['repeats'] = 0;
|
||||
/** @var \FireflyIII\Database\Piggybank $repos */
|
||||
$repos = App::make('FireflyIII\Database\Piggybank');
|
||||
|
||||
$data = Input::all();
|
||||
unset($data['_token']);
|
||||
switch ($data['post_submit_action']) {
|
||||
default:
|
||||
throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"');
|
||||
break;
|
||||
case 'create_another':
|
||||
case 'store':
|
||||
$messages = $repos->validate($data);
|
||||
/** @var MessageBag $messages ['errors'] */
|
||||
if ($messages['errors']->count() > 0) {
|
||||
Session::flash('warnings', $messages['warnings']);
|
||||
Session::flash('successes', $messages['successes']);
|
||||
Session::flash('error', 'Could not save piggy bank: ' . $messages['errors']->first());
|
||||
return Redirect::route('piggybanks.create')->withInput()->withErrors($messages['errors']);
|
||||
}
|
||||
// store!
|
||||
$repos->store($data);
|
||||
Session::flash('success', 'New piggy bank stored!');
|
||||
|
||||
// extend the data array with the settings needed to create a repeated:
|
||||
$data['repeats'] = 1;
|
||||
$data['order'] = 0;
|
||||
if ($data['post_submit_action'] == 'create_another') {
|
||||
return Redirect::route('piggybanks.create');
|
||||
} else {
|
||||
return Redirect::route('piggybanks.index');
|
||||
}
|
||||
break;
|
||||
case 'validate_only':
|
||||
$messageBags = $repos->validate($data);
|
||||
Session::flash('warnings', $messageBags['warnings']);
|
||||
Session::flash('successes', $messageBags['successes']);
|
||||
Session::flash('errors', $messageBags['errors']);
|
||||
|
||||
$piggyBank = $this->_repository->store($data);
|
||||
if ($piggyBank->id) {
|
||||
Session::flash('success', 'New piggy bank "' . $piggyBank->name . '" created!');
|
||||
Event::fire('piggybanks.store', [$piggyBank]);
|
||||
return Redirect::route('piggybanks.index.repeated');
|
||||
|
||||
} else {
|
||||
Session::flash('error', 'Could not save piggy bank: ' . $piggyBank->errors()->first());
|
||||
|
||||
return Redirect::route('piggybanks.create.repeated')->withInput()->withErrors($piggyBank->errors());
|
||||
return Redirect::route('piggybanks.create')->withInput();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -378,25 +281,41 @@ class PiggybankController extends BaseController
|
||||
*/
|
||||
public function update(Piggybank $piggyBank)
|
||||
{
|
||||
$piggyBank = $this->_repository->update($piggyBank, Input::all());
|
||||
if ($piggyBank->validate()) {
|
||||
if ($piggyBank->repeats == 1) {
|
||||
$route = 'piggybanks.index.repeated';
|
||||
$message = 'Repeated expense';
|
||||
} else {
|
||||
$route = 'piggybanks.index.piggybanks';
|
||||
$message = 'Piggy bank';
|
||||
}
|
||||
|
||||
/** @var \FireflyIII\Database\Piggybank $repos */
|
||||
$repos = App::make('FireflyIII\Database\Piggybank');
|
||||
$data = Input::except('_token');
|
||||
|
||||
Session::flash('success', $message . ' "' . $piggyBank->name . '" updated.');
|
||||
Event::fire('piggybanks.update', [$piggyBank]);
|
||||
switch (Input::get('post_submit_action')) {
|
||||
default:
|
||||
throw new FireflyException('Cannot handle post_submit_action "' . e(Input::get('post_submit_action')) . '"');
|
||||
break;
|
||||
case 'create_another':
|
||||
case 'update':
|
||||
$messages = $repos->validate($data);
|
||||
/** @var MessageBag $messages ['errors'] */
|
||||
if ($messages['errors']->count() > 0) {
|
||||
Session::flash('warnings', $messages['warnings']);
|
||||
Session::flash('successes', $messages['successes']);
|
||||
Session::flash('error', 'Could not save piggy bank: ' . $messages['errors']->first());
|
||||
return Redirect::route('piggybanks.edit', $piggyBank->id)->withInput()->withErrors($messages['errors']);
|
||||
}
|
||||
// store!
|
||||
$repos->update($piggyBank, $data);
|
||||
Session::flash('success', 'Piggy bank updated!');
|
||||
|
||||
return Redirect::route($route);
|
||||
} else {
|
||||
Session::flash('error', 'Could not update piggy bank: ' . $piggyBank->errors()->first());
|
||||
|
||||
return Redirect::route('piggybanks.edit', $piggyBank->id)->withErrors($piggyBank->errors())->withInput();
|
||||
if ($data['post_submit_action'] == 'create_another') {
|
||||
return Redirect::route('piggybanks.edit', $piggyBank->id);
|
||||
} else {
|
||||
return Redirect::route('piggybanks.index');
|
||||
}
|
||||
case 'validate_only':
|
||||
$messageBags = $repos->validate($data);
|
||||
Session::flash('warnings', $messageBags['warnings']);
|
||||
Session::flash('successes', $messageBags['successes']);
|
||||
Session::flash('errors', $messageBags['errors']);
|
||||
return Redirect::route('piggybanks.edit', $piggyBank->id)->withInput();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Class ReportController
|
||||
@ -12,7 +13,55 @@ class ReportController extends BaseController
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return View::make('reports.index')->with('title','Reports')->with('mainTitleIcon','fa-line-chart');
|
||||
/** @var \FireflyIII\Database\TransactionJournal $journals */
|
||||
$journals = App::make('FireflyIII\Database\TransactionJournal');
|
||||
$journal = $journals->first();
|
||||
|
||||
$date = $journal->date;
|
||||
$years = [];
|
||||
while ($date <= Carbon::now()) {
|
||||
$years[] = $date->format('Y');
|
||||
$date->addYear();
|
||||
}
|
||||
|
||||
|
||||
return View::make('reports.index', compact('years'))->with('title', 'Reports')->with('mainTitleIcon', 'fa-line-chart');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $year
|
||||
*/
|
||||
public function year($year)
|
||||
{
|
||||
try {
|
||||
$date = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
App::abort(500);
|
||||
}
|
||||
|
||||
/** @var \FireflyIII\Database\TransactionJournal $tj */
|
||||
$tj = App::make('FireflyIII\Database\TransactionJournal');
|
||||
|
||||
// get some sums going
|
||||
$summary = [];
|
||||
|
||||
|
||||
$end = clone $date;
|
||||
$end->endOfYear();
|
||||
while ($date < $end) {
|
||||
$summary[] = [
|
||||
'month' => $date->format('F'),
|
||||
'income' => $tj->getSumOfIncomesByMonth($date),
|
||||
'expense' => $tj->getSumOfExpensesByMonth($date),
|
||||
];
|
||||
$date->addMonth();
|
||||
}
|
||||
|
||||
|
||||
// draw some charts etc.
|
||||
return View::make('reports.year', compact('summary'))->with('title', 'Reports')->with('mainTitleIcon', 'fa-line-chart')->with('subTitle', $year)->with(
|
||||
'subTitleIcon', 'fa-bar-chart'
|
||||
)->with('year', $year);
|
||||
}
|
||||
|
||||
}
|
@ -33,6 +33,7 @@ class CreatePiggybanksTable extends Migration
|
||||
$table->smallInteger('rep_times')->unsigned()->nullable();
|
||||
$table->enum('reminder', ['day', 'week', 'month', 'year'])->nullable();
|
||||
$table->smallInteger('reminder_skip')->unsigned();
|
||||
$table->boolean('remind_me');
|
||||
$table->integer('order')->unsigned();
|
||||
|
||||
// connect account to piggybank.
|
||||
|
@ -10,9 +10,10 @@ class Form
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*/
|
||||
@ -29,18 +30,42 @@ class Form
|
||||
return self::ffInput('checkbox', $name, $value, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public static function ffAmount($name, $value = null, array $options = [])
|
||||
{
|
||||
$options['step'] = 'any';
|
||||
$options['min'] = '0.01';
|
||||
$options['min'] = '0.01';
|
||||
return self::ffInput('amount', $name, $value, $options);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public static function ffBalance($name, $value = null, array $options = [])
|
||||
{
|
||||
$options['step'] = 'any';
|
||||
return self::ffInput('amount', $name, $value, $options);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*/
|
||||
@ -50,9 +75,10 @@ class Form
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*/
|
||||
@ -63,10 +89,11 @@ class Form
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $name
|
||||
* @param array $list
|
||||
* @param null $selected
|
||||
* @param null $selected
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*/
|
||||
@ -76,9 +103,10 @@ class Form
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*/
|
||||
@ -88,16 +116,25 @@ class Form
|
||||
|
||||
}
|
||||
|
||||
public static function label($name)
|
||||
/**
|
||||
* @param $name
|
||||
* @param $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function label($name, $options)
|
||||
{
|
||||
if (isset($options['label'])) {
|
||||
return $options['label'];
|
||||
}
|
||||
$labels = [
|
||||
'amount_min' => 'Amount (min)',
|
||||
'amount_max' => 'Amount (max)',
|
||||
'match' => 'Matches on',
|
||||
'repeat_freq' => 'Repetition',
|
||||
'amount_min' => 'Amount (min)',
|
||||
'amount_max' => 'Amount (max)',
|
||||
'match' => 'Matches on',
|
||||
'repeat_freq' => 'Repetition',
|
||||
'account_from_id' => 'Account from',
|
||||
'account_to_id' => 'Account to',
|
||||
'account_id' => 'Asset account'
|
||||
'account_to_id' => 'Account to',
|
||||
'account_id' => 'Asset account'
|
||||
];
|
||||
|
||||
return isset($labels[$name]) ? $labels[$name] : str_replace('_', ' ', ucfirst($name));
|
||||
@ -151,28 +188,29 @@ class Form
|
||||
case 'create':
|
||||
$return = '<div class="form-group"><label for="return_to_form" class="col-sm-4 control-label">';
|
||||
$return .= 'Return here</label><div class="col-sm-8"><div class="radio"><label>';
|
||||
$return .= \Form::radio('post_submit_action','create_another', $previousValue == 'create_another');
|
||||
$return .= \Form::radio('post_submit_action', 'create_another', $previousValue == 'create_another');
|
||||
$return .= 'After storing, return here to create another one.</label></div></div></div>';
|
||||
break;
|
||||
case 'update':
|
||||
$return = '<div class="form-group"><label for="return_to_edit" class="col-sm-4 control-label">';
|
||||
$return .= 'Return here</label><div class="col-sm-8"><div class="radio"><label>';
|
||||
$return .= \Form::radio('post_submit_action','return_to_edit', $previousValue == 'return_to_edit');
|
||||
$return .= \Form::radio('post_submit_action', 'return_to_edit', $previousValue == 'return_to_edit');
|
||||
$return .= 'After updating, return here.</label></div></div></div>';
|
||||
break;
|
||||
default:
|
||||
throw new FireflyException('Cannot create ffOptionsList for option (store+return) ' . $type);
|
||||
break;
|
||||
}
|
||||
return $store.$validate.$return;
|
||||
return $store . $validate . $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param $type
|
||||
* @param $name
|
||||
* @param null $value
|
||||
* @param array $options
|
||||
* @param array $list
|
||||
*
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*/
|
||||
@ -181,10 +219,10 @@ class Form
|
||||
/*
|
||||
* add some defaults to this method:
|
||||
*/
|
||||
$options['class'] = 'form-control';
|
||||
$options['id'] = 'ffInput_' . $name;
|
||||
$options['class'] = 'form-control';
|
||||
$options['id'] = 'ffInput_' . $name;
|
||||
$options['autocomplete'] = 'off';
|
||||
$label = self::label($name);
|
||||
$label = self::label($name, $options);
|
||||
/*
|
||||
* Make label and placeholder look nice.
|
||||
*/
|
||||
@ -193,9 +231,9 @@ class Form
|
||||
/*
|
||||
* Get prefilled value:
|
||||
*/
|
||||
if(\Session::has('prefilled')) {
|
||||
if (\Session::has('prefilled')) {
|
||||
$prefilled = \Session::get('prefilled');
|
||||
$value = isset($prefilled[$name]) && is_null($value) ? $prefilled[$name] : $value;
|
||||
$value = isset($prefilled[$name]) && is_null($value) ? $prefilled[$name] : $value;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -12,14 +12,17 @@ class Account implements AccountInterface
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
*
|
||||
* @return \TransactionJournal|null
|
||||
*/
|
||||
public function openingBalanceTransaction(\Account $account)
|
||||
{
|
||||
return \TransactionJournal::withRelevantData()
|
||||
->accountIs($account)
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=',
|
||||
'transaction_journals.transaction_type_id')
|
||||
->leftJoin(
|
||||
'transaction_types', 'transaction_types.id', '=',
|
||||
'transaction_journals.transaction_type_id'
|
||||
)
|
||||
->where('transaction_types.type', 'Opening balance')
|
||||
->first(['transaction_journals.*']);
|
||||
}
|
||||
@ -36,7 +39,7 @@ class Account implements AccountInterface
|
||||
* For now, Firefly simply warns the user of this.
|
||||
*
|
||||
* @param \Account $account
|
||||
* @param $perPage
|
||||
* @param $perPage
|
||||
*
|
||||
* @return array|mixed
|
||||
* @throws \Firefly\Exception\FireflyException
|
||||
@ -110,17 +113,25 @@ class Account implements AccountInterface
|
||||
|
||||
|
||||
// statistics (transactions)
|
||||
$trIn = floatval(\Transaction::before($end)->after($start)->accountIs($account)->moreThan(0)
|
||||
->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount'));
|
||||
$trOut = floatval(\Transaction::before($end)->after($start)->accountIs($account)->lessThan(0)
|
||||
->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount'));
|
||||
$trIn = floatval(
|
||||
\Transaction::before($end)->after($start)->accountIs($account)->moreThan(0)
|
||||
->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount')
|
||||
);
|
||||
$trOut = floatval(
|
||||
\Transaction::before($end)->after($start)->accountIs($account)->lessThan(0)
|
||||
->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount')
|
||||
);
|
||||
$trDiff = $trIn + $trOut;
|
||||
|
||||
// statistics (transfers)
|
||||
$trfIn = floatval(\Transaction::before($end)->after($start)->accountIs($account)->moreThan(0)
|
||||
->transactionTypes(['Transfer'])->sum('transactions.amount'));
|
||||
$trfOut = floatval(\Transaction::before($end)->after($start)->accountIs($account)->lessThan(0)
|
||||
->transactionTypes(['Transfer'])->sum('transactions.amount'));
|
||||
$trfIn = floatval(
|
||||
\Transaction::before($end)->after($start)->accountIs($account)->moreThan(0)
|
||||
->transactionTypes(['Transfer'])->sum('transactions.amount')
|
||||
);
|
||||
$trfOut = floatval(
|
||||
\Transaction::before($end)->after($start)->accountIs($account)->lessThan(0)
|
||||
->transactionTypes(['Transfer'])->sum('transactions.amount')
|
||||
);
|
||||
$trfDiff = $trfIn + $trfOut;
|
||||
|
||||
$stats['period'] = [
|
||||
|
@ -1,11 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: sander
|
||||
* Date: 27/09/14
|
||||
* Time: 07:39
|
||||
*/
|
||||
|
||||
namespace Firefly\Helper\Controllers;
|
||||
|
||||
use LaravelBook\Ardent\Builder;
|
||||
|
@ -126,9 +126,6 @@ class EloquentLimitTrigger
|
||||
// remove and recreate limit repetitions.
|
||||
// if limit is not repeating, simply update the repetition to match the limit,
|
||||
// even though deleting everything is easier.
|
||||
foreach ($limit->limitrepetitions()->get() as $l) {
|
||||
$l->delete();
|
||||
}
|
||||
$limit->createRepetition($limit->startdate);
|
||||
|
||||
return true;
|
||||
|
@ -193,7 +193,7 @@ class EloquentPiggybankTrigger
|
||||
'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@updateRelatedTransfer'
|
||||
);
|
||||
$events->listen(
|
||||
'piggybanks.check', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@checkRepeatingPiggies'
|
||||
'piggybanks.storepiggybanks.check', 'Firefly\Trigger\Piggybanks\EloquentPiggybankTrigger@checkRepeatingPiggies'
|
||||
);
|
||||
|
||||
}
|
||||
|
469
app/lib/FireflyIII/Database/Account.php
Normal file
469
app/lib/FireflyIII/Database/Account.php
Normal file
@ -0,0 +1,469 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Database\Ifaces\AccountInterface;
|
||||
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\Ifaces\CUD;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class Account
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class Account implements CUD, CommonDatabaseCalls, AccountInterface
|
||||
{
|
||||
use SwitchUser;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setUser(\Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data)
|
||||
{
|
||||
$model->name = $data['name'];
|
||||
$model->active = isset($data['active']) ? intval($data['active']) : 0;
|
||||
$model->save();
|
||||
|
||||
if (isset($data['openingbalance']) && isset($data['openingbalancedate'])) {
|
||||
$openingBalance = $this->openingBalanceTransaction($model);
|
||||
|
||||
$openingBalance->date = new Carbon($data['openingbalancedate']);
|
||||
$openingBalance->save();
|
||||
$amount = floatval($data['openingbalance']);
|
||||
/** @var \Transaction $transaction */
|
||||
foreach ($openingBalance->transactions as $transaction) {
|
||||
if ($transaction->account_id == $model->id) {
|
||||
$transaction->amount = $amount;
|
||||
} else {
|
||||
$transaction->amount = $amount * -1;
|
||||
}
|
||||
$transaction->save();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all asset accounts. Optional JSON based parameters.
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAssetAccounts(array $parameters = [])
|
||||
{
|
||||
return $this->getAccountsByType(['Default account', 'Asset account'], $parameters);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
*
|
||||
* @return \Account|null
|
||||
*/
|
||||
public function findInitialBalanceAccount(\Account $account)
|
||||
{
|
||||
/** @var \FireflyIII\Database\AccountType $acctType */
|
||||
$acctType = \App::make('FireflyIII\Database\AccountType');
|
||||
|
||||
$accountType = $acctType->findByWhat('initial');
|
||||
|
||||
return $this->getUser()->accounts()->where('account_type_id', $accountType->id)->where('name', 'LIKE', $account->name . '%')->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAccountsByType(array $types, array $parameters = [])
|
||||
{
|
||||
/*
|
||||
* Basic query:
|
||||
*/
|
||||
$query = $this->getUser()->accounts()->accountTypeIn($types);
|
||||
|
||||
|
||||
/*
|
||||
* Without an opening balance, the rest of these queries will fail.
|
||||
*/
|
||||
|
||||
$query->leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id');
|
||||
$query->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id');
|
||||
|
||||
/*
|
||||
* Not used, but useful for the balance within a certain month / year.
|
||||
*/
|
||||
$balanceOnDate = isset($parameters['date']) ? $parameters['date'] : Carbon::now();
|
||||
$query->where(
|
||||
function ($q) use ($balanceOnDate) {
|
||||
$q->where('transaction_journals.date', '<=', $balanceOnDate->format('Y-m-d'));
|
||||
$q->orWhereNull('transaction_journals.date');
|
||||
}
|
||||
);
|
||||
|
||||
$query->groupBy('accounts.id');
|
||||
|
||||
/*
|
||||
* If present, process parameters for sorting:
|
||||
*/
|
||||
$query->orderBy('name', 'ASC');
|
||||
|
||||
/*
|
||||
* If present, process parameters for searching.
|
||||
*/
|
||||
if (isset($parameters['search'])) {
|
||||
$query->where('name', 'LIKE', '%' . e($parameters['search']['value'] . '%'));
|
||||
}
|
||||
|
||||
/*
|
||||
* If present, start at $start:
|
||||
*/
|
||||
if (isset($parameters['start'])) {
|
||||
$query->skip(intval($parameters['start']));
|
||||
}
|
||||
if (isset($parameters['length'])) {
|
||||
$query->take(intval($parameters['length']));
|
||||
}
|
||||
|
||||
return $query->get(['accounts.*', \DB::Raw('SUM(`transactions`.`amount`) as `balance`')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function countAssetAccounts()
|
||||
{
|
||||
return $this->countAccountsByType(['Default account', 'Asset account']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function countExpenseAccounts()
|
||||
{
|
||||
return $this->countAccountsByType(['Expense account', 'Beneficiary account']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countAccountsByType(array $types)
|
||||
{
|
||||
return $this->getUser()->accounts()->accountTypeIn($types)->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getExpenseAccounts(array $parameters = [])
|
||||
{
|
||||
return $this->getAccountsByType(['Expense account', 'Beneficiary account'], $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all default accounts.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getDefaultAccounts()
|
||||
{
|
||||
// TODO: Implement getDefaultAccounts() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
// TODO: Implement find() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
// TODO: Implement get() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of total revenue accounts. Useful for DataTables.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countRevenueAccounts()
|
||||
{
|
||||
return $this->countAccountsByType(['Revenue account']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all revenue accounts.
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getRevenueAccounts(array $parameters = [])
|
||||
{
|
||||
return $this->getAccountsByType(['Revenue account'], $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model)
|
||||
{
|
||||
$model->delete();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
*
|
||||
* @return \TransactionJournal|null
|
||||
*/
|
||||
public function openingBalanceTransaction(\Account $account)
|
||||
{
|
||||
return \TransactionJournal::withRelevantData()
|
||||
->accountIs($account)
|
||||
->leftJoin(
|
||||
'transaction_types', 'transaction_types.id', '=',
|
||||
'transaction_journals.transaction_type_id'
|
||||
)
|
||||
->where('transaction_types.type', 'Opening balance')
|
||||
->first(['transaction_journals.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model)
|
||||
{
|
||||
die('No impl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
$warnings = new MessageBag;
|
||||
$successes = new MessageBag;
|
||||
$errors = new MessageBag;
|
||||
|
||||
/*
|
||||
* Name validation:
|
||||
*/
|
||||
if (!isset($model['name'])) {
|
||||
$errors->add('name', 'Name is mandatory');
|
||||
}
|
||||
|
||||
if (isset($model['name']) && strlen($model['name']) == 0) {
|
||||
$errors->add('name', 'Name is too short');
|
||||
}
|
||||
if (isset($model['name']) && strlen($model['name']) > 100) {
|
||||
$errors->add('name', 'Name is too long');
|
||||
}
|
||||
$validator = \Validator::make([$model], \Account::$rules);
|
||||
if ($validator->invalid()) {
|
||||
$errors->merge($errors);
|
||||
}
|
||||
|
||||
/*
|
||||
* type validation.
|
||||
*/
|
||||
if (!isset($model['what'])) {
|
||||
$errors->add('name', 'Internal error: need to know type of account!');
|
||||
}
|
||||
|
||||
/*
|
||||
* Opening balance and opening balance date.
|
||||
*/
|
||||
if (isset($model['what']) && $model['what'] == 'asset') {
|
||||
if (isset($model['openingbalance']) && strlen($model['openingbalance']) > 0 && !is_numeric($model['openingbalance'])) {
|
||||
$errors->add('openingbalance', 'This is not a number.');
|
||||
}
|
||||
if (isset($model['openingbalancedate']) && strlen($model['openingbalancedate']) > 0) {
|
||||
try {
|
||||
new Carbon($model['openingbalancedate']);
|
||||
} catch (\Exception $e) {
|
||||
$errors->add('openingbalancedate', 'This date is invalid.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!$errors->has('name')) {
|
||||
$successes->add('name', 'OK');
|
||||
}
|
||||
if (!$errors->has('openingbalance')) {
|
||||
$successes->add('openingbalance', 'OK');
|
||||
}
|
||||
if (!$errors->has('openingbalancedate')) {
|
||||
$successes->add('openingbalancedate', 'OK');
|
||||
}
|
||||
return [
|
||||
'errors' => $errors,
|
||||
'warnings' => $warnings,
|
||||
'successes' => $successes
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
|
||||
/*
|
||||
* Find account type.
|
||||
*/
|
||||
/** @var \FireflyIII\Database\AccountType $acctType */
|
||||
$acctType = \App::make('FireflyIII\Database\AccountType');
|
||||
|
||||
$accountType = $acctType->findByWhat($data['what']);
|
||||
|
||||
$data['user_id'] = $this->getUser()->id;
|
||||
$data['account_type_id'] = $accountType->id;
|
||||
$data['active'] = isset($data['active']) && $data['active'] === '1' ? 1 : 0;
|
||||
|
||||
|
||||
$data = array_except($data, array('_token', 'what'));
|
||||
$account = new \Account($data);
|
||||
if (!$account->validate()) {
|
||||
var_dump($account->errors()->all());
|
||||
exit;
|
||||
}
|
||||
$account->save();
|
||||
if (isset($data['openingbalance']) && floatval($data['openingbalance']) != 0) {
|
||||
$this->storeInitialBalance($account, $data);
|
||||
}
|
||||
|
||||
|
||||
/* Tell transaction journal to store a new one.*/
|
||||
|
||||
|
||||
return $account;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function storeInitialBalance(\Account $account, array $data)
|
||||
{
|
||||
$opposingData = [
|
||||
'name' => $account->name . ' Initial Balance',
|
||||
'active' => 0,
|
||||
'what' => 'initial'
|
||||
];
|
||||
$opposingAccount = $this->store($opposingData);
|
||||
|
||||
/*
|
||||
* Create a journal from opposing to account or vice versa.
|
||||
*/
|
||||
$balance = floatval($data['openingbalance']);
|
||||
$date = new Carbon($data['openingbalancedate']);
|
||||
/** @var \FireflyIII\Database\TransactionJournal $tj */
|
||||
$tj = \App::make('FireflyIII\Database\TransactionJournal');
|
||||
if ($balance < 0) {
|
||||
// first transaction draws money from the new account to the opposing
|
||||
$from = $account;
|
||||
$to = $opposingAccount;
|
||||
} else {
|
||||
// first transaction puts money into account
|
||||
$from = $opposingAccount;
|
||||
$to = $account;
|
||||
}
|
||||
|
||||
// data for transaction journal:
|
||||
$balance = $balance < 0 ? $balance * -1 : $balance;
|
||||
$opening = [
|
||||
'what' => 'opening',
|
||||
'currency' => 'EUR',
|
||||
'amount' => $balance,
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
'date' => $date,
|
||||
'description' => 'Opening balance for new account ' . $account->name,
|
||||
];
|
||||
|
||||
|
||||
$validation = $tj->validate($opening);
|
||||
if ($validation['errors']->count() == 0) {
|
||||
$tj->store($opening);
|
||||
return true;
|
||||
} else {
|
||||
var_dump($validation['errors']);
|
||||
exit;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement findByWhat() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
return $this->getUser()->accounts()->whereIn('id', $ids)->get();
|
||||
}
|
||||
}
|
139
app/lib/FireflyIII/Database/AccountType.php
Normal file
139
app/lib/FireflyIII/Database/AccountType.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
use Firefly\Exception\FireflyException;
|
||||
use Illuminate\Support\Collection;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use FireflyIII\Database\Ifaces\AccountTypeInterface;
|
||||
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\Ifaces\CUD;
|
||||
|
||||
/**
|
||||
* Class AccountType
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class AccountType implements AccountTypeInterface, CUD, CommonDatabaseCalls
|
||||
{
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
switch ($what) {
|
||||
case 'expense':
|
||||
return \AccountType::whereType('Expense account')->first();
|
||||
break;
|
||||
case 'asset':
|
||||
return \AccountType::whereType('Asset account')->first();
|
||||
break;
|
||||
case 'revenue':
|
||||
return \AccountType::whereType('Revenue account')->first();
|
||||
break;
|
||||
case 'initial':
|
||||
return \AccountType::whereType('Initial balance account')->first();
|
||||
break;
|
||||
default:
|
||||
throw new FireflyException('Cannot find account type described as "' . e($what) . '".');
|
||||
break;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model)
|
||||
{
|
||||
// TODO: Implement destroy() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model)
|
||||
{
|
||||
// TODO: Implement validateObject() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
// TODO: Implement validate() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
// TODO: Implement store() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
// TODO: Implement find() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
// TODO: Implement get() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data)
|
||||
{
|
||||
// TODO: Implement update() method.
|
||||
}
|
||||
}
|
234
app/lib/FireflyIII/Database/Budget.php
Normal file
234
app/lib/FireflyIII/Database/Budget.php
Normal file
@ -0,0 +1,234 @@
|
||||
<?php
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exception\NotImplementedException;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use Illuminate\Support\Collection;
|
||||
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\Ifaces\CUD;
|
||||
use FireflyIII\Database\Ifaces\BudgetInterface;
|
||||
/**
|
||||
* Class Budget
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class Budget implements CUD, CommonDatabaseCalls, BudgetInterface
|
||||
{
|
||||
use SwitchUser;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setUser(\Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return \LimitRepetition|null
|
||||
*/
|
||||
public function repetitionOnStartingOnDate(\Budget $budget, Carbon $date)
|
||||
{
|
||||
return \LimitRepetition::
|
||||
leftJoin('limits', 'limit_repetitions.limit_id', '=', 'limits.id')->leftJoin(
|
||||
'components', 'limits.component_id', '=', 'components.id'
|
||||
)->where('limit_repetitions.startdate', $date->format('Y-m-d'))->where(
|
||||
'components.id', $budget->id
|
||||
)->first(['limit_repetitions.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model)
|
||||
{
|
||||
$model->delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model)
|
||||
{
|
||||
// TODO: Implement validateObject() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
$warnings = new MessageBag;
|
||||
$successes = new MessageBag;
|
||||
$errors = new MessageBag;
|
||||
|
||||
if(isset($model['name'])) {
|
||||
if(strlen($model['name']) < 1) {
|
||||
$errors->add('name', 'Name is too short');
|
||||
}
|
||||
if(strlen($model['name']) > 200) {
|
||||
$errors->add('name', 'Name is too long');
|
||||
|
||||
}
|
||||
} else {
|
||||
$errors->add('name', 'Name is mandatory');
|
||||
}
|
||||
$validator = \Validator::make($model, \Component::$rules);
|
||||
|
||||
if ($validator->invalid()) {
|
||||
$errors->merge($validator->errors());
|
||||
}
|
||||
|
||||
|
||||
if(!$errors->has('name')) {
|
||||
$successes->add('name','OK');
|
||||
}
|
||||
|
||||
return [
|
||||
'errors' => $errors,
|
||||
'warnings' => $warnings,
|
||||
'successes' => $successes
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
$data['user_id'] = $this->getUser()->id;
|
||||
|
||||
$budget = new \Budget($data);
|
||||
$budget->class = 'Budget';
|
||||
|
||||
if (!$budget->validate()) {
|
||||
var_dump($budget->errors()->all());
|
||||
exit;
|
||||
}
|
||||
$budget->save();
|
||||
return $budget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
// TODO: Implement find() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$budgets = $this->getUser()->budgets()->get();
|
||||
|
||||
return $budgets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement findByWhat() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function transactionsWithoutBudgetInDateRange(Carbon $start, Carbon $end)
|
||||
{
|
||||
// Add expenses that have no budget:
|
||||
return \Auth::user()->transactionjournals()->whereNotIn(
|
||||
'transaction_journals.id', function ($query) use ($start, $end) {
|
||||
$query->select('transaction_journals.id')->from('transaction_journals')
|
||||
->leftJoin(
|
||||
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
|
||||
'transaction_journals.id'
|
||||
)
|
||||
->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id')
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->where('components.class', 'Budget');
|
||||
}
|
||||
)->before($end)->after($start)->lessThan(0)->transactionTypes(['Withdrawal'])->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data)
|
||||
{
|
||||
$model->name = $data['name'];
|
||||
if (!$model->validate()) {
|
||||
var_dump($model->errors()->all());
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
$model->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
129
app/lib/FireflyIII/Database/Category.php
Normal file
129
app/lib/FireflyIII/Database/Category.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use Illuminate\Support\Collection;
|
||||
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\Ifaces\CUD;
|
||||
use FireflyIII\Database\Ifaces\CategoryInterface;
|
||||
|
||||
/**
|
||||
* Class Category
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class Category implements CUD, CommonDatabaseCalls, CategoryInterface
|
||||
{
|
||||
use SwitchUser;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setUser(\Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model)
|
||||
{
|
||||
// TODO: Implement destroy() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model)
|
||||
{
|
||||
// TODO: Implement validateObject() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
// TODO: Implement validate() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
// TODO: Implement store() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
// TODO: Implement find() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
// TODO: Implement get() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement findByWhat() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data)
|
||||
{
|
||||
// TODO: Implement update() method.
|
||||
}
|
||||
}
|
109
app/lib/FireflyIII/Database/Ifaces/AccountInterface.php
Normal file
109
app/lib/FireflyIII/Database/Ifaces/AccountInterface.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface AccountInterface
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface AccountInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Get all asset accounts. The parameters are optional and are provided by the DataTables plugin.
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAssetAccounts(array $parameters = []);
|
||||
|
||||
/**
|
||||
* Counts the number of total asset accounts. Useful for DataTables.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countAssetAccounts();
|
||||
|
||||
/**
|
||||
* Counts the number of total expense accounts. Useful for DataTables.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countExpenseAccounts();
|
||||
|
||||
/**
|
||||
* Counts the number of total revenue accounts. Useful for DataTables.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countRevenueAccounts();
|
||||
|
||||
/**
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
*
|
||||
* @return \Account|null
|
||||
*/
|
||||
public function findInitialBalanceAccount(\Account $account);
|
||||
|
||||
public function getExpenseAccounts(array $parameters = []);
|
||||
|
||||
/**
|
||||
* Get all revenue accounts.
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getRevenueAccounts(array $parameters = []);
|
||||
|
||||
/**
|
||||
* Get all accounts of the selected types. Is also capable of handling DataTables' parameters.
|
||||
*
|
||||
* @param array $types
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAccountsByType(array $types, array $parameters = []);
|
||||
|
||||
/**
|
||||
* Counts the number of accounts found with the included types.
|
||||
*
|
||||
* @param array $types
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countAccountsByType(array $types);
|
||||
|
||||
/**
|
||||
* Get all default accounts.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getDefaultAccounts();
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
*
|
||||
* @return \TransactionJournal|null
|
||||
*/
|
||||
public function openingBalanceTransaction(\Account $account);
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function storeInitialBalance(\Account $account, array $data);
|
||||
}
|
13
app/lib/FireflyIII/Database/Ifaces/AccountTypeInterface.php
Normal file
13
app/lib/FireflyIII/Database/Ifaces/AccountTypeInterface.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
|
||||
/**
|
||||
* Interface AccountTypeInterface
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface AccountTypeInterface
|
||||
{
|
||||
|
||||
|
||||
}
|
31
app/lib/FireflyIII/Database/Ifaces/BudgetInterface.php
Normal file
31
app/lib/FireflyIII/Database/Ifaces/BudgetInterface.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface BudgetInterface
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface BudgetInterface
|
||||
{
|
||||
/**
|
||||
* @param \Budget $budget
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return \LimitRepetition|null
|
||||
*/
|
||||
public function repetitionOnStartingOnDate(\Budget $budget, Carbon $date);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function transactionsWithoutBudgetInDateRange(Carbon $start, Carbon $end);
|
||||
|
||||
}
|
57
app/lib/FireflyIII/Database/Ifaces/CUD.php
Normal file
57
app/lib/FireflyIII/Database/Ifaces/CUD.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
|
||||
/**
|
||||
* Interface CUD
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface CUD
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model);
|
||||
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model);
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model);
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data);
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data);
|
||||
|
||||
}
|
16
app/lib/FireflyIII/Database/Ifaces/CategoryInterface.php
Normal file
16
app/lib/FireflyIII/Database/Ifaces/CategoryInterface.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface CategoryInterface
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface CategoryInterface
|
||||
{
|
||||
|
||||
}
|
49
app/lib/FireflyIII/Database/Ifaces/CommonDatabaseCalls.php
Normal file
49
app/lib/FireflyIII/Database/Ifaces/CommonDatabaseCalls.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
|
||||
|
||||
/**
|
||||
* Interface CommonDatabaseCalls
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface CommonDatabaseCalls
|
||||
{
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id);
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get();
|
||||
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids);
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
*/
|
||||
public function findByWhat($what);
|
||||
|
||||
}
|
19
app/lib/FireflyIII/Database/Ifaces/PiggybankInterface.php
Normal file
19
app/lib/FireflyIII/Database/Ifaces/PiggybankInterface.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
|
||||
/**
|
||||
* Interface PiggybankInterface
|
||||
*
|
||||
* @package FireflyIII\Database\Ifaces
|
||||
*/
|
||||
interface PiggybankInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function leftOnAccount(\Account $account);
|
||||
}
|
22
app/lib/FireflyIII/Database/Ifaces/RecurringInterface.php
Normal file
22
app/lib/FireflyIII/Database/Ifaces/RecurringInterface.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* Interface RecurringInterface
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface RecurringInterface
|
||||
{
|
||||
/**
|
||||
* @param \RecurringTransaction $recurring
|
||||
* @param Carbon $current
|
||||
* @param Carbon $currentEnd
|
||||
*
|
||||
* @return \TransactionJournal|null
|
||||
*/
|
||||
public function getJournalForRecurringInRange(\RecurringTransaction $recurring, Carbon $start, Carbon $end);
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
|
||||
|
||||
/**
|
||||
* Interface TransactionTypeInterface
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface TransactionCurrencyInterface
|
||||
{
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @return \TransactionCurrency|null
|
||||
*/
|
||||
public function findByCode($code);
|
||||
|
||||
}
|
14
app/lib/FireflyIII/Database/Ifaces/TransactionInterface.php
Normal file
14
app/lib/FireflyIII/Database/Ifaces/TransactionInterface.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
|
||||
|
||||
/**
|
||||
* Interface TransactionInterface
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface TransactionInterface
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface TransactionJournalInterface
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface TransactionJournalInterface
|
||||
{
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getInDateRange(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* Get the very first transaction journal.
|
||||
* @return mixed
|
||||
*/
|
||||
public function first();
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getSumOfIncomesByMonth(Carbon $date);
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getSumOfExpensesByMonth(Carbon $date);
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database\Ifaces;
|
||||
|
||||
|
||||
/**
|
||||
* Interface TransactionTypeInterface
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
interface TransactionTypeInterface
|
||||
{
|
||||
|
||||
}
|
250
app/lib/FireflyIII/Database/Piggybank.php
Normal file
250
app/lib/FireflyIII/Database/Piggybank.php
Normal file
@ -0,0 +1,250 @@
|
||||
<?php
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exception\NotImplementedException;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use Illuminate\Support\Collection;
|
||||
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\Ifaces\CUD;
|
||||
use FireflyIII\Database\Ifaces\PiggybankInterface;
|
||||
|
||||
/**
|
||||
* Class Piggybank
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class Piggybank implements CUD, CommonDatabaseCalls, PiggybankInterface
|
||||
{
|
||||
use SwitchUser;
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function leftOnAccount(\Account $account)
|
||||
{
|
||||
$balance = $account->balance();
|
||||
/** @var \Piggybank $p */
|
||||
foreach ($account->piggybanks()->get() as $p) {
|
||||
$balance -= $p->currentRelevantRep()->currentamount;
|
||||
}
|
||||
|
||||
return $balance;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setUser(\Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model)
|
||||
{
|
||||
$model->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model)
|
||||
{
|
||||
// TODO: Implement validateObject() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
$warnings = new MessageBag;
|
||||
$successes = new MessageBag;
|
||||
$errors = new MessageBag;
|
||||
|
||||
/*
|
||||
* Name validation:
|
||||
*/
|
||||
if (!isset($model['name'])) {
|
||||
$errors->add('name', 'Name is mandatory');
|
||||
}
|
||||
|
||||
if (isset($model['name']) && strlen($model['name']) == 0) {
|
||||
$errors->add('name', 'Name is too short');
|
||||
}
|
||||
if (isset($model['name']) && strlen($model['name']) > 100) {
|
||||
$errors->add('name', 'Name is too long');
|
||||
}
|
||||
|
||||
if (intval($model['account_id']) == 0) {
|
||||
$errors->add('account_id', 'Account is mandatory');
|
||||
}
|
||||
if ($model['targetdate'] == '' && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
|
||||
$errors->add('targetdate', 'Target date is mandatory when setting reminders.');
|
||||
}
|
||||
if ($model['targetdate'] != '') {
|
||||
try {
|
||||
new Carbon($model['targetdate']);
|
||||
} catch (\Exception $e) {
|
||||
$errors->add('date', 'Invalid date.');
|
||||
}
|
||||
}
|
||||
if (floatval($model['targetamount']) < 0.01) {
|
||||
$errors->add('targetamount', 'Amount should be above 0.01.');
|
||||
}
|
||||
if (!in_array(ucfirst($model['reminder']), \Config::get('firefly.piggybank_periods'))) {
|
||||
$errors->add('reminder', 'Invalid reminder period (' . $model['reminder'] . ')');
|
||||
}
|
||||
// check period.
|
||||
if (!$errors->has('reminder') && !$errors->has('targetdate') && isset($model['remind_me']) && intval($model['remind_me']) == 1) {
|
||||
$today = new Carbon;
|
||||
$target = new Carbon($model['targetdate']);
|
||||
switch ($model['reminder']) {
|
||||
case 'week':
|
||||
$today->addWeek();
|
||||
break;
|
||||
case 'month':
|
||||
$today->addMonth();
|
||||
break;
|
||||
case 'year':
|
||||
$today->addYear();
|
||||
break;
|
||||
}
|
||||
if ($today > $target) {
|
||||
$errors->add('reminder', 'Target date is too close to today to set reminders.');
|
||||
}
|
||||
}
|
||||
|
||||
$validator = \Validator::make($model, \Piggybank::$rules);
|
||||
if ($validator->invalid()) {
|
||||
$errors->merge($errors);
|
||||
}
|
||||
|
||||
// add ok messages.
|
||||
$list = ['name', 'account_id', 'targetamount', 'targetdate', 'remind_me', 'reminder'];
|
||||
foreach ($list as $entry) {
|
||||
if (!$errors->has($entry) && !$warnings->has($entry)) {
|
||||
$successes->add($entry, 'OK');
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'errors' => $errors,
|
||||
'warnings' => $warnings,
|
||||
'successes' => $successes
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
$data['rep_every'] = isset($data['rep_every']) ? $data['rep_every'] : 0;
|
||||
$data['reminder_skip'] = isset($data['reminder_skip']) ? $data['reminder_skip'] : 0;
|
||||
$data['order'] = isset($data['order']) ? $data['order'] : 0;
|
||||
$data['remind_me'] = isset($data['remind_me']) ? intval($data['remind_me']) : 0;
|
||||
$data['startdate'] = isset($data['startdate']) ? $data['startdate'] : Carbon::now()->format('Y-m-d');
|
||||
$data['targetdate'] = isset($data['targetdate']) && $data['targetdate'] != '' ? $data['targetdate'] : null;
|
||||
|
||||
|
||||
$piggybank = new \Piggybank($data);
|
||||
if (!$piggybank->validate()) {
|
||||
var_dump($piggybank->errors()->all());
|
||||
exit;
|
||||
}
|
||||
$piggybank->save();
|
||||
\Event::fire('piggybanks.store', [$piggybank]);
|
||||
$piggybank->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
// TODO: Implement find() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->getUser()->piggybanks()->where('repeats', 0)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement findByWhat() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data)
|
||||
{
|
||||
/** @var \Piggybank $model */
|
||||
$model->name = $data['name'];
|
||||
$model->account_id = intval($data['account_id']);
|
||||
$model->targetamount = floatval($data['targetamount']);
|
||||
$model->targetdate = isset($data['targetdate']) && $data['targetdate'] != '' ? $data['targetdate'] : null;
|
||||
$model->rep_every = isset($data['rep_every']) ? $data['rep_every'] : 0;
|
||||
$model->reminder_skip = isset($data['reminder_skip']) ? $data['reminder_skip'] : 0;
|
||||
$model->order = isset($data['order']) ? $data['order'] : 0;
|
||||
$model->remind_me = isset($data['remind_me']) ? intval($data['remind_me']) : 0;
|
||||
if(!$model->validate()) {
|
||||
var_dump($model->errors());
|
||||
exit();
|
||||
}
|
||||
$model->save();
|
||||
return true;
|
||||
}
|
||||
}
|
143
app/lib/FireflyIII/Database/Recurring.php
Normal file
143
app/lib/FireflyIII/Database/Recurring.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\Ifaces\CUD;
|
||||
use FireflyIII\Database\Ifaces\RecurringInterface;
|
||||
|
||||
/**
|
||||
* Class Recurring
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class Recurring implements CUD, CommonDatabaseCalls, RecurringInterface
|
||||
{
|
||||
use SwitchUser;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setUser(\Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RecurringTransaction $recurring
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return \TransactionJournal|null
|
||||
*/
|
||||
public function getJournalForRecurringInRange(\RecurringTransaction $recurring, Carbon $start, Carbon $end)
|
||||
{
|
||||
return $this->getUser()->transactionjournals()->where('recurring_transaction_id', $recurring->id)->after($start)->before($end)->first();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model)
|
||||
{
|
||||
// TODO: Implement destroy() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model)
|
||||
{
|
||||
// TODO: Implement validateObject() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
// TODO: Implement validate() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
// TODO: Implement store() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
// TODO: Implement find() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->getUser()->recurringtransactions()->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement findByWhat() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data)
|
||||
{
|
||||
// TODO: Implement update() method.
|
||||
}
|
||||
}
|
27
app/lib/FireflyIII/Database/SwitchUser.php
Normal file
27
app/lib/FireflyIII/Database/SwitchUser.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
|
||||
/**
|
||||
* Class SwitchUser
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
trait SwitchUser
|
||||
{
|
||||
protected $_user;
|
||||
|
||||
public function getUser()
|
||||
{
|
||||
return $this->_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $user
|
||||
*/
|
||||
public function setUser($user)
|
||||
{
|
||||
$this->_user = $user;
|
||||
}
|
||||
}
|
195
app/lib/FireflyIII/Database/Transaction.php
Normal file
195
app/lib/FireflyIII/Database/Transaction.php
Normal file
@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
use Firefly\Exception\FireflyException;
|
||||
use FireflyIII\Exception\NotImplementedException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\Ifaces\CUD;
|
||||
use FireflyIII\Database\Ifaces\TransactionInterface;
|
||||
/**
|
||||
* Class Transaction
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class Transaction implements TransactionInterface, CUD, CommonDatabaseCalls
|
||||
{
|
||||
use SwitchUser;
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model)
|
||||
{
|
||||
// TODO: Implement destroy() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model)
|
||||
{
|
||||
// TODO: Implement validateObject() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
$warnings = new MessageBag;
|
||||
$successes = new MessageBag;
|
||||
$errors = new MessageBag;
|
||||
|
||||
|
||||
if (!isset($model['account_id']) && !isset($model['account'])) {
|
||||
$errors->add('account', 'No account present');
|
||||
}
|
||||
if (isset($model['account']) && !($model['account'] instanceof \Account)) {
|
||||
$errors->add('account', 'No valid account present');
|
||||
}
|
||||
if (isset($model['account_id']) && intval($model['account_id']) < 0) {
|
||||
$errors->add('account', 'No valid account_id present');
|
||||
}
|
||||
|
||||
if (isset($model['piggybank_id']) && intval($model['piggybank_id']) < 0) {
|
||||
$errors->add('piggybank', 'No valid piggybank_id present');
|
||||
}
|
||||
|
||||
if (!isset($model['transaction_journal_id']) && !isset($model['transaction_journal'])) {
|
||||
$errors->add('transaction_journal', 'No TJ present');
|
||||
}
|
||||
if (isset($model['transaction_journal']) && !($model['transaction_journal'] instanceof \TransactionJournal)) {
|
||||
$errors->add('transaction_journal', 'No valid transaction_journal present');
|
||||
}
|
||||
if (isset($model['transaction_journal_id']) && intval($model['transaction_journal_id']) < 0) {
|
||||
$errors->add('account', 'No valid transaction_journal_id present');
|
||||
}
|
||||
|
||||
if (isset($model['description']) && strlen($model['description']) > 255) {
|
||||
$errors->add('account', 'Description too long');
|
||||
}
|
||||
|
||||
if (!isset($model['amount'])) {
|
||||
$errors->add('amount', 'No amount present.');
|
||||
}
|
||||
if (isset($model['amount']) && floatval($model['amount']) == 0) {
|
||||
$errors->add('amount', 'Invalid amount.');
|
||||
}
|
||||
|
||||
if (!$errors->has('account')) {
|
||||
$successes->add('account', 'OK');
|
||||
}
|
||||
if (!$errors->has('')) {
|
||||
$successes->add('piggybank', 'OK');
|
||||
}
|
||||
if (!$errors->has('transaction_journal')) {
|
||||
$successes->add('transaction_journal', 'OK');
|
||||
}
|
||||
if (!$errors->has('amount')) {
|
||||
$successes->add('amount', 'OK');
|
||||
}
|
||||
|
||||
return [
|
||||
'errors' => $errors,
|
||||
'warnings' => $warnings,
|
||||
'successes' => $successes
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
// TODO: Implement store() method.
|
||||
$transaction = new \Transaction;
|
||||
$transaction->account()->associate($data['account']);
|
||||
$transaction->transactionJournal()->associate($data['transaction_journal']);
|
||||
$transaction->amount = floatval($data['amount']);
|
||||
if (isset($data['piggybank'])) {
|
||||
$transaction->piggybank()->associate($data['piggybank']);
|
||||
}
|
||||
if (isset($data['description'])) {
|
||||
$transaction->description = $data['description'];
|
||||
}
|
||||
if ($transaction->validate()) {
|
||||
$transaction->save();
|
||||
} else {
|
||||
throw new FireflyException($transaction->errors()->first());
|
||||
}
|
||||
return $transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
// TODO: Implement find() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
// TODO: Implement get() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement findByWhat() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data)
|
||||
{
|
||||
// TODO: Implement update() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
}
|
||||
}
|
130
app/lib/FireflyIII/Database/TransactionCurrency.php
Normal file
130
app/lib/FireflyIII/Database/TransactionCurrency.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\Ifaces\CUD;
|
||||
use FireflyIII\Database\Ifaces\TransactionCurrencyInterface;
|
||||
|
||||
/**
|
||||
* Class TransactionType
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class TransactionCurrency implements TransactionCurrencyInterface, CUD, CommonDatabaseCalls
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model)
|
||||
{
|
||||
// TODO: Implement destroy() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model)
|
||||
{
|
||||
// TODO: Implement validateObject() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
// TODO: Implement validate() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
// TODO: Implement store() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
// TODO: Implement find() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
// TODO: Implement get() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement get() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @return \TransactionCurrency|null
|
||||
*/
|
||||
public function findByCode($code)
|
||||
{
|
||||
return \TransactionCurrency::whereCode($code)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data)
|
||||
{
|
||||
// TODO: Implement update() method.
|
||||
}
|
||||
}
|
334
app/lib/FireflyIII/Database/TransactionJournal.php
Normal file
334
app/lib/FireflyIII/Database/TransactionJournal.php
Normal file
@ -0,0 +1,334 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Firefly\Exception\FireflyException;
|
||||
use FireflyIII\Exception\NotImplementedException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\Ifaces\CUD;
|
||||
use FireflyIII\Database\Ifaces\TransactionJournalInterface;
|
||||
|
||||
/**
|
||||
* Class TransactionJournal
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class TransactionJournal implements TransactionJournalInterface, CUD, CommonDatabaseCalls
|
||||
{
|
||||
use SwitchUser;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setUser(\Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getSumOfIncomesByMonth(Carbon $date)
|
||||
{
|
||||
$end = clone $date;
|
||||
$date->startOfMonth();
|
||||
$end->endOfMonth();
|
||||
|
||||
$sum = \DB::table('transactions')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
|
||||
->where('amount', '>', 0)
|
||||
->where('transaction_types.type', '=', 'Deposit')
|
||||
->where('transaction_journals.date', '>=', $date->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))->sum('transactions.amount');
|
||||
$sum = floatval($sum);
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getSumOfExpensesByMonth(Carbon $date)
|
||||
{
|
||||
$end = clone $date;
|
||||
$date->startOfMonth();
|
||||
$end->endOfMonth();
|
||||
|
||||
$sum = \DB::table('transactions')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
|
||||
->where('amount', '>', 0)
|
||||
->where('transaction_types.type', '=', 'Withdrawal')
|
||||
->where('transaction_journals.date', '>=', $date->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))->sum('transactions.amount');
|
||||
$sum = floatval($sum);
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getInDateRange(Carbon $start, Carbon $end)
|
||||
{
|
||||
return $this->getuser()->transactionjournals()->withRelevantData()->before($end)->after($start)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TransactionJournal
|
||||
*/
|
||||
public function first()
|
||||
{
|
||||
return $this->getUser()->transactionjournals()->orderBy('date', 'ASC')->first();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model)
|
||||
{
|
||||
// TODO: Implement destroy() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model)
|
||||
{
|
||||
// TODO: Implement validateObject() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
|
||||
$warnings = new MessageBag;
|
||||
$successes = new MessageBag;
|
||||
$errors = new MessageBag;
|
||||
|
||||
|
||||
if (!isset($model['what'])) {
|
||||
$errors->add('description', 'Internal error: need to know type of transaction!');
|
||||
}
|
||||
if (isset($model['recurring_transaction_id']) && intval($model['recurring_transaction_id']) < 0) {
|
||||
$errors->add('recurring_transaction_id', 'Recurring transaction is invalid.');
|
||||
}
|
||||
if (!isset($model['description'])) {
|
||||
$errors->add('description', 'This field is mandatory.');
|
||||
}
|
||||
if (isset($model['description']) && strlen($model['description']) == 0) {
|
||||
$errors->add('description', 'This field is mandatory.');
|
||||
}
|
||||
if (isset($model['description']) && strlen($model['description']) > 255) {
|
||||
$errors->add('description', 'Description is too long.');
|
||||
}
|
||||
|
||||
if (!isset($model['currency'])) {
|
||||
$errors->add('description', 'Internal error: currency is mandatory!');
|
||||
}
|
||||
if (isset($model['date']) && !($model['date'] instanceof Carbon) && strlen($model['date']) > 0) {
|
||||
try {
|
||||
new Carbon($model['date']);
|
||||
} catch (\Exception $e) {
|
||||
$errors->add('date', 'This date is invalid.');
|
||||
}
|
||||
}
|
||||
if (!isset($model['date'])) {
|
||||
$errors->add('date', 'This date is invalid.');
|
||||
}
|
||||
|
||||
if (isset($model['to_id']) && intval($model['to_id']) < 0) {
|
||||
$errors->add('account_to', 'Invalid to-account');
|
||||
}
|
||||
if (isset($model['from_id']) && intval($model['from_id']) < 0) {
|
||||
$errors->add('account_from', 'Invalid from-account');
|
||||
}
|
||||
if (isset($model['to']) && !($model['to'] instanceof \Account)) {
|
||||
$errors->add('account_to', 'Invalid to-account');
|
||||
}
|
||||
if (isset($model['from']) && !($model['from'] instanceof \Account)) {
|
||||
$errors->add('account_from', 'Invalid from-account');
|
||||
}
|
||||
if (!isset($model['amount']) || (isset($model['amount']) && floatval($model['amount']) < 0)) {
|
||||
$errors->add('amount', 'Invalid amount');
|
||||
}
|
||||
if (!isset($model['from']) && !isset($model['to'])) {
|
||||
$errors->add('account_to', 'No accounts found!');
|
||||
}
|
||||
|
||||
$validator = \Validator::make([$model], \Transaction::$rules);
|
||||
if ($validator->invalid()) {
|
||||
$errors->merge($errors);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add "OK"
|
||||
*/
|
||||
if (!$errors->has('description')) {
|
||||
$successes->add('description', 'OK');
|
||||
}
|
||||
if (!$errors->has('date')) {
|
||||
$successes->add('date', 'OK');
|
||||
}
|
||||
return [
|
||||
'errors' => $errors,
|
||||
'warnings' => $warnings,
|
||||
'successes' => $successes
|
||||
];
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
|
||||
/** @var \FireflyIII\Database\TransactionType $typeRepository */
|
||||
$typeRepository = \App::make('FireflyIII\Database\TransactionType');
|
||||
|
||||
/** @var \FireflyIII\Database\TransactionCurrency $currencyRepository */
|
||||
$currencyRepository = \App::make('FireflyIII\Database\TransactionCurrency');
|
||||
|
||||
/** @var \FireflyIII\Database\Transaction $transactionRepository */
|
||||
$transactionRepository = \App::make('FireflyIII\Database\Transaction');
|
||||
|
||||
$journalType = $typeRepository->findByWhat($data['what']);
|
||||
$currency = $currencyRepository->findByCode($data['currency']);
|
||||
|
||||
$journal = new \TransactionJournal;
|
||||
$journal->transactionType()->associate($journalType);
|
||||
$journal->transactionCurrency()->associate($currency);
|
||||
$journal->user()->associate($this->getUser());
|
||||
$journal->description = $data['description'];
|
||||
$journal->date = $data['date'];
|
||||
$journal->completed = 0;
|
||||
//$journal->user_id = $this->getUser()->id;
|
||||
|
||||
/*
|
||||
* This must be enough to store the journal:
|
||||
*/
|
||||
if (!$journal->validate()) {
|
||||
\Log::error($journal->errors()->all());
|
||||
throw new FireflyException('store() transactionjournal failed, but it should not!');
|
||||
}
|
||||
$journal->save();
|
||||
|
||||
/*
|
||||
* Then store both transactions.
|
||||
*/
|
||||
$first = [
|
||||
'account' => $data['from'],
|
||||
'transaction_journal' => $journal,
|
||||
'amount' => ($data['amount'] * -1),
|
||||
];
|
||||
$validate = $transactionRepository->validate($first);
|
||||
if ($validate['errors']->count() == 0) {
|
||||
$transactionRepository->store($first);
|
||||
} else {
|
||||
throw new FireflyException($validate['errors']->first());
|
||||
}
|
||||
|
||||
$second = [
|
||||
'account' => $data['to'],
|
||||
'transaction_journal' => $journal,
|
||||
'amount' => floatval($data['amount']),
|
||||
];
|
||||
|
||||
$validate = $transactionRepository->validate($second);
|
||||
if ($validate['errors']->count() == 0) {
|
||||
$transactionRepository->store($second);
|
||||
} else {
|
||||
throw new FireflyException($validate['errors']->first());
|
||||
}
|
||||
|
||||
$journal->completed = 1;
|
||||
$journal->save();
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
return $this->getUser()->transactionjournals()->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->getUser()->transactionjournals()->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
// TODO: Implement findByWhat() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data)
|
||||
{
|
||||
// TODO: Implement update() method.
|
||||
}
|
||||
}
|
129
app/lib/FireflyIII/Database/TransactionType.php
Normal file
129
app/lib/FireflyIII/Database/TransactionType.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Database;
|
||||
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use FireflyIII\Database\Ifaces\CommonDatabaseCalls;
|
||||
use FireflyIII\Database\Ifaces\CUD;
|
||||
use FireflyIII\Database\Ifaces\TransactionTypeInterface;
|
||||
|
||||
/**
|
||||
* Class TransactionType
|
||||
*
|
||||
* @package FireflyIII\Database
|
||||
*/
|
||||
class TransactionType implements TransactionTypeInterface, CUD, CommonDatabaseCalls
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy(Ardent $model)
|
||||
{
|
||||
// TODO: Implement destroy() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a model. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param Ardent $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateObject(Ardent $model)
|
||||
{
|
||||
// TODO: Implement validateObject() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array. Returns an array containing MessageBags
|
||||
* errors/warnings/successes.
|
||||
*
|
||||
* @param array $model
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate(array $model)
|
||||
{
|
||||
// TODO: Implement validate() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function store(array $data)
|
||||
{
|
||||
// TODO: Implement store() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with id $id.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ardent
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
// TODO: Implement find() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all objects.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
// TODO: Implement get() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an account type using one of the "$what"'s: expense, asset, revenue, opening, etc.
|
||||
*
|
||||
* @param $what
|
||||
*
|
||||
* @return \AccountType|null
|
||||
*/
|
||||
public function findByWhat($what)
|
||||
{
|
||||
switch ($what) {
|
||||
case 'opening':
|
||||
return \TransactionType::whereType('Opening balance')->first();
|
||||
break;
|
||||
default:
|
||||
throw new FireflyException('Cannot find transaction type described as "' . e($what) . '".');
|
||||
break;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $ids
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getByIds(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIds() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ardent $model
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update(Ardent $model, array $data)
|
||||
{
|
||||
// TODO: Implement update() method.
|
||||
}
|
||||
}
|
13
app/lib/FireflyIII/Exception/NotImplementedException.php
Normal file
13
app/lib/FireflyIII/Exception/NotImplementedException.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace FireflyIII\Exception;
|
||||
|
||||
|
||||
/**
|
||||
* Class NotImplementedException
|
||||
*
|
||||
* @package FireflyIII\Exception
|
||||
*/
|
||||
class NotImplementedException extends \Exception
|
||||
{
|
||||
|
||||
}
|
12
app/lib/FireflyIII/Shared/Json/Account.php
Normal file
12
app/lib/FireflyIII/Shared/Json/Account.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Shared\Json;
|
||||
|
||||
/**
|
||||
* Class Account
|
||||
*
|
||||
* @package FireflyIII\Shared\Json
|
||||
*/
|
||||
class Account {
|
||||
|
||||
}
|
86
app/lib/FireflyIII/Shared/Json/Json.php
Normal file
86
app/lib/FireflyIII/Shared/Json/Json.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Shared\Json;
|
||||
|
||||
/**
|
||||
* Class Json
|
||||
* @package FireflyIII\Shared\Json
|
||||
*/
|
||||
class Json
|
||||
{
|
||||
/**
|
||||
* Grabs all the parameters entered by the DataTables JQuery plugin and creates
|
||||
* a nice array to be used by the other methods. It's also cleaning up and what-not.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataTableParameters()
|
||||
{
|
||||
/*
|
||||
* Process all parameters!
|
||||
*/
|
||||
if (intval(\Input::get('length')) < 0) {
|
||||
$length = 10000; // we get them all if no length is defined.
|
||||
} else {
|
||||
$length = intval(\Input::get('length'));
|
||||
}
|
||||
$parameters = [
|
||||
'start' => intval(\Input::get('start')),
|
||||
'length' => $length,
|
||||
'draw' => intval(\Input::get('draw')),
|
||||
];
|
||||
|
||||
|
||||
/*
|
||||
* Columns:
|
||||
*/
|
||||
if (!is_null(\Input::get('columns')) && is_array(\Input::get('columns'))) {
|
||||
foreach (\Input::get('columns') as $column) {
|
||||
$parameters['columns'][] = [
|
||||
'data' => $column['data'],
|
||||
'name' => $column['name'],
|
||||
'searchable' => $column['searchable'] == 'true' ? true : false,
|
||||
'orderable' => $column['orderable'] == 'true' ? true : false,
|
||||
'search' => [
|
||||
'value' => $column['search']['value'],
|
||||
'regex' => $column['search']['regex'] == 'true' ? true : false,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sorting.
|
||||
*/
|
||||
$parameters['orderOnAccount'] = false;
|
||||
if (!is_null(\Input::get('order')) && is_array(\Input::get('order'))) {
|
||||
foreach (\Input::get('order') as $order) {
|
||||
$columnIndex = intval($order['column']);
|
||||
$columnName = $parameters['columns'][$columnIndex]['name'];
|
||||
$parameters['order'][] = [
|
||||
'name' => $columnName,
|
||||
'dir' => strtoupper($order['dir'])
|
||||
];
|
||||
if ($columnName == 'to' || $columnName == 'from') {
|
||||
$parameters['orderOnAccount'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Search parameters:
|
||||
*/
|
||||
$parameters['search'] = [
|
||||
'value' => '',
|
||||
'regex' => false
|
||||
];
|
||||
if (!is_null(\Input::get('search')) && is_array(\Input::get('search'))) {
|
||||
$search = \Input::get('search');
|
||||
$parameters['search'] = [
|
||||
'value' => $search['value'],
|
||||
'regex' => $search['regex'] == 'true' ? true : false
|
||||
];
|
||||
}
|
||||
return $parameters;
|
||||
}
|
||||
}
|
58
app/lib/FireflyIII/Shared/Preferences/Preferences.php
Normal file
58
app/lib/FireflyIII/Shared/Preferences/Preferences.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace FireflyIII\Shared\Preferences;
|
||||
/**
|
||||
* Class PreferencesHelper
|
||||
*
|
||||
* @package Firefly\Helper\Preferences
|
||||
*/
|
||||
class Preferences implements PreferencesInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $default
|
||||
*
|
||||
* @return null|\Preference
|
||||
*/
|
||||
public function get($name, $default = null)
|
||||
{
|
||||
$pref = \Preference::where('user_id', \Auth::user()->id)->where('name', $name)->first();
|
||||
if (is_null($default) && is_null($pref)) {
|
||||
// return NULL
|
||||
return null;
|
||||
}
|
||||
if (!is_null($pref)) {
|
||||
return $pref;
|
||||
}
|
||||
if (!is_null($default) && is_null($pref)) {
|
||||
// create preference, return that:
|
||||
return $this->set($name, $default);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
*
|
||||
* @return \Preference
|
||||
*/
|
||||
public function set($name, $value)
|
||||
{
|
||||
$pref = \Preference::where('user_id', \Auth::user()->id)->where('name', $name)->first();
|
||||
if (is_null($pref)) {
|
||||
$pref = new \Preference;
|
||||
$pref->name = $name;
|
||||
$pref->user()->associate(\Auth::user());
|
||||
|
||||
}
|
||||
$pref->data = $value;
|
||||
$pref->save();
|
||||
|
||||
|
||||
return $pref;
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace FireflyIII\Shared\Preferences;
|
||||
|
||||
/**
|
||||
* Interface PreferencesHelperInterface
|
||||
*
|
||||
* @package Firefly\Helper\Preferences
|
||||
*/
|
||||
interface PreferencesInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
*
|
||||
* @return null|\Preference
|
||||
*/
|
||||
public function set($name, $value);
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $default
|
||||
*
|
||||
* @return \Preference
|
||||
*/
|
||||
public function get($name, $default = null);
|
||||
|
||||
}
|
86
app/lib/FireflyIII/Shared/Toolkit/Date.php
Normal file
86
app/lib/FireflyIII/Shared/Toolkit/Date.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Shared\Toolkit;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Firefly\Exception\FireflyException;
|
||||
|
||||
/**
|
||||
* Class Date
|
||||
*
|
||||
* @package FireflyIII\Shared\Toolkit
|
||||
*/
|
||||
class Date
|
||||
{
|
||||
/**
|
||||
* @param Carbon $currentEnd
|
||||
* @param $repeatFreq
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function endOfPeriod(Carbon $currentEnd, $repeatFreq)
|
||||
{
|
||||
switch ($repeatFreq) {
|
||||
default:
|
||||
throw new FireflyException('Cannot do endOfPeriod for $repeat_freq ' . $repeatFreq);
|
||||
break;
|
||||
case 'daily':
|
||||
$currentEnd->addDay();
|
||||
break;
|
||||
case 'weekly':
|
||||
$currentEnd->addWeek()->subDay();
|
||||
break;
|
||||
case 'monthly':
|
||||
$currentEnd->addMonth()->subDay();
|
||||
break;
|
||||
case 'quarterly':
|
||||
$currentEnd->addMonths(3)->subDay();
|
||||
break;
|
||||
case 'half-year':
|
||||
$currentEnd->addMonths(6)->subDay();
|
||||
break;
|
||||
case 'yearly':
|
||||
$currentEnd->addYear()->subDay();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
* @param $repeatFreq
|
||||
* @param $skip
|
||||
*
|
||||
* @return Carbon
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function addPeriod(Carbon $date, $repeatFreq, $skip)
|
||||
{
|
||||
$add = ($skip + 1);
|
||||
switch ($repeatFreq) {
|
||||
default:
|
||||
throw new FireflyException('Cannot do addPeriod for $repeat_freq ' . $repeatFreq);
|
||||
break;
|
||||
case 'daily':
|
||||
$date->addDays($add);
|
||||
break;
|
||||
case 'weekly':
|
||||
$date->addWeeks($add);
|
||||
break;
|
||||
case 'monthly':
|
||||
$date->addMonths($add);
|
||||
break;
|
||||
case 'quarterly':
|
||||
$months = $add * 3;
|
||||
$date->addMonths($months);
|
||||
break;
|
||||
case 'half-year':
|
||||
$months = $add * 6;
|
||||
$date->addMonths($months);
|
||||
break;
|
||||
case 'yearly':
|
||||
$date->addYears($add);
|
||||
break;
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
}
|
50
app/lib/FireflyIII/Shared/Toolkit/Form.php
Normal file
50
app/lib/FireflyIII/Shared/Toolkit/Form.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Shared\Toolkit;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class Form
|
||||
*
|
||||
* @package FireflyIII\Shared\Toolkit
|
||||
*/
|
||||
class Form {
|
||||
/**
|
||||
* Takes any collection and tries to make a sensible select list compatible array of it.
|
||||
*
|
||||
* @param Collection $set
|
||||
* @param null $titleField
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function makeSelectList(Collection $set, $titleField = null)
|
||||
{
|
||||
$selectList = [];
|
||||
/** @var Model $entry */
|
||||
foreach ($set as $entry) {
|
||||
$id = intval($entry->id);
|
||||
$title = null;
|
||||
if (is_null($titleField)) {
|
||||
// try 'title' field.
|
||||
if (isset($entry->title)) {
|
||||
$title = $entry->title;
|
||||
}
|
||||
// try 'name' field
|
||||
if (is_null($title)) {
|
||||
$title = $entry->name;
|
||||
}
|
||||
|
||||
// try 'description' field
|
||||
if (is_null($title)) {
|
||||
$title = $entry->description;
|
||||
}
|
||||
} else {
|
||||
$title = $entry->$titleField;
|
||||
}
|
||||
$selectList[$id] = $title;
|
||||
}
|
||||
return $selectList;
|
||||
}
|
||||
|
||||
}
|
@ -89,9 +89,9 @@ class Limit extends Ardent
|
||||
break;
|
||||
}
|
||||
$end->subDay();
|
||||
$count = $this->limitrepetitions()->where('startdate', $start->format('Y-m-d'))->where(
|
||||
'enddate', $start->format('Y-m-d')
|
||||
)->count();
|
||||
$count = $this->limitrepetitions()->where('startdate', $start->format('Y-m-d'))->where('enddate', $end->format('Y-m-d'))->count();
|
||||
\Log::debug('All: '.$this->limitrepetitions()->count().' (#'.$this->id.')');
|
||||
\Log::debug('Found ' . $count.' limit-reps for limit #' . $this->id.' with start '.$start->format('Y-m-d') .' and end ' . $end->format('Y-m-d'));
|
||||
|
||||
if ($count == 0) {
|
||||
|
||||
@ -115,6 +115,12 @@ class Limit extends Ardent
|
||||
if (isset($repetition->id)) {
|
||||
\Event::fire('limits.repetition', [$repetition]);
|
||||
}
|
||||
} else if($count == 1) {
|
||||
// update this one:
|
||||
$repetition = $this->limitrepetitions()->where('startdate', $start->format('Y-m-d'))->where('enddate', $end->format('Y-m-d'))->first();
|
||||
$repetition->amount = $this->amount;
|
||||
$repetition->save();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,14 +5,14 @@ use LaravelBook\Ardent\Ardent as Ardent;
|
||||
/**
|
||||
* LimitRepetition
|
||||
*
|
||||
* @property integer $id
|
||||
* @property integer $id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property integer $limit_id
|
||||
* @property integer $limit_id
|
||||
* @property \Carbon\Carbon $startdate
|
||||
* @property \Carbon\Carbon $enddate
|
||||
* @property float $amount
|
||||
* @property-read \Limit $limit
|
||||
* @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)
|
||||
@ -39,29 +39,27 @@ class LimitRepetition extends Ardent
|
||||
return ['created_at', 'updated_at', 'startdate', 'enddate'];
|
||||
}
|
||||
|
||||
public function spentInRepetition() {
|
||||
$sum = \DB::table('transactions')
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id')
|
||||
->leftJoin('limits', 'limits.component_id', '=', 'components.id')
|
||||
->leftJoin('limit_repetitions', 'limit_repetitions.limit_id', '=', 'limits.id')
|
||||
->where('transaction_journals.date', '>=', $this->startdate->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $this->enddate->format('Y-m-d'))
|
||||
->where('transactions.amount', '>', 0)
|
||||
->where('limit_repetitions.id', '=', $this->id)->sum('transactions.amount');
|
||||
return floatval($sum);
|
||||
}
|
||||
|
||||
/**
|
||||
* How much money is left in this?
|
||||
*/
|
||||
public function leftInRepetition()
|
||||
{
|
||||
$left = floatval($this->amount);
|
||||
return floatval($this->amount - $this->spentInRepetition());
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $left;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,8 +83,10 @@ class LimitRepetition extends Ardent
|
||||
}
|
||||
switch ($this->repeat_freq) {
|
||||
default:
|
||||
throw new \Firefly\Exception\FireflyException('No date formats for frequency "' . $this->repeat_freq
|
||||
. '"!');
|
||||
throw new \Firefly\Exception\FireflyException(
|
||||
'No date formats for frequency "' . $this->repeat_freq
|
||||
. '"!'
|
||||
);
|
||||
break;
|
||||
case 'daily':
|
||||
return $this->startdate->format('Ymd') . '-5';
|
||||
@ -119,8 +119,10 @@ class LimitRepetition extends Ardent
|
||||
}
|
||||
switch ($this->repeat_freq) {
|
||||
default:
|
||||
throw new \Firefly\Exception\FireflyException('No date formats for frequency "' . $this->repeat_freq
|
||||
. '"!');
|
||||
throw new \Firefly\Exception\FireflyException(
|
||||
'No date formats for frequency "' . $this->repeat_freq
|
||||
. '"!'
|
||||
);
|
||||
break;
|
||||
case 'daily':
|
||||
return $this->startdate->format('j F Y');
|
||||
|
@ -56,6 +56,7 @@ class Piggybank extends Ardent
|
||||
'rep_times' => 'min:1|max:100', // how many times do you want to save this amount? eg. 3 times
|
||||
'reminder' => 'in:day,week,month,year', // want a reminder to put money in this?
|
||||
'reminder_skip' => 'required|min:0|max:100', // every week? every 2 months?
|
||||
'remind_me' => 'required|boolean',
|
||||
'order' => 'required:min:1', // not yet used.
|
||||
];
|
||||
public $fillable
|
||||
@ -71,6 +72,7 @@ class Piggybank extends Ardent
|
||||
'rep_times',
|
||||
'reminder',
|
||||
'reminder_skip',
|
||||
'remind_me',
|
||||
'order'
|
||||
];
|
||||
|
||||
@ -90,7 +92,6 @@ class Piggybank extends Ardent
|
||||
$rep->targetdate = $target;
|
||||
$rep->currentamount = 0;
|
||||
$rep->save();
|
||||
|
||||
\Event::fire('piggybanks.repetition', [$rep]);
|
||||
|
||||
return $rep;
|
||||
|
@ -4,242 +4,6 @@ use Carbon\Carbon;
|
||||
use LaravelBook\Ardent\Ardent;
|
||||
use LaravelBook\Ardent\Builder;
|
||||
|
||||
/**
|
||||
* TransactionJournal
|
||||
*
|
||||
* @property integer $id
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
* @property integer $user_id
|
||||
* @property integer $transaction_type_id
|
||||
* @property integer $transaction_currency_id
|
||||
* @property string $description
|
||||
* @property boolean $completed
|
||||
* @property \Carbon\Carbon $date
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Component[] $components
|
||||
* @property-read \TransactionCurrency $transactionCurrency
|
||||
* @property-read \TransactionType $transactionType
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\Transaction[] $transactions
|
||||
* @property-read \User $user
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereUserId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereTransactionTypeId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereTransactionCurrencyId($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereDescription($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereCompleted($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereDate($value)
|
||||
* @method static \TransactionJournal account($account)
|
||||
* @method static \TransactionJournal after($date)
|
||||
* @method static \TransactionJournal before($date)
|
||||
* @method static \TransactionJournal defaultSorting()
|
||||
* @method static \TransactionJournal moreThan($amount)
|
||||
* @method static \TransactionJournal lessThan($amount)
|
||||
* @method static \TransactionJournal onDate($date)
|
||||
* @method static \TransactionJournal transactionTypes($types)
|
||||
* @method static \TransactionJournal withRelevantData()
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property integer $recurring_transaction_id
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \RecurringTransaction $recurringTransaction
|
||||
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereRecurringTransactionId($value)
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @method static \TransactionJournal accountIs($account)
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Budget[] $budgets
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\
|
||||
* 'Category[] $categories
|
||||
*/
|
||||
class TransactionJournal extends Ardent
|
||||
{
|
||||
|
||||
@ -259,7 +23,7 @@ class TransactionJournal extends Ardent
|
||||
public function budgets()
|
||||
{
|
||||
return $this->belongsToMany(
|
||||
'Budget', 'component_transaction_journal', 'transaction_journal_id', 'component_id'
|
||||
'Budget', 'component_transaction_journal', 'transaction_journal_id', 'component_id'
|
||||
);
|
||||
}
|
||||
|
||||
@ -269,7 +33,7 @@ class TransactionJournal extends Ardent
|
||||
public function categories()
|
||||
{
|
||||
return $this->belongsToMany(
|
||||
'Category', 'component_transaction_journal', 'transaction_journal_id', 'component_id'
|
||||
'Category', 'component_transaction_journal', 'transaction_journal_id', 'component_id'
|
||||
);
|
||||
}
|
||||
|
||||
@ -281,6 +45,20 @@ class TransactionJournal extends Ardent
|
||||
return $this->belongsToMany('Component');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getAmount()
|
||||
{
|
||||
|
||||
foreach ($this->transactions as $t) {
|
||||
if (floatval($t->amount) > 0) {
|
||||
return floatval($t->amount);
|
||||
}
|
||||
}
|
||||
return -0.01;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
@ -312,7 +90,7 @@ class TransactionJournal extends Ardent
|
||||
|
||||
/**
|
||||
* @param $query
|
||||
* @param Carbon $date
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@ -323,7 +101,7 @@ class TransactionJournal extends Ardent
|
||||
|
||||
/**
|
||||
* @param $query
|
||||
* @param Carbon $date
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@ -340,8 +118,10 @@ class TransactionJournal extends Ardent
|
||||
public function scopeMoreThan(Builder $query, $amount)
|
||||
{
|
||||
if (is_null($this->joinedTransactions)) {
|
||||
$query->leftJoin('transactions', 'transactions.transaction_journal_id', '=',
|
||||
'transaction_journals.id');
|
||||
$query->leftJoin(
|
||||
'transactions', 'transactions.transaction_journal_id', '=',
|
||||
'transaction_journals.id'
|
||||
);
|
||||
$this->joinedTransactions = true;
|
||||
}
|
||||
|
||||
@ -351,8 +131,10 @@ class TransactionJournal extends Ardent
|
||||
public function scopeLessThan(Builder $query, $amount)
|
||||
{
|
||||
if (is_null($this->joinedTransactions)) {
|
||||
$query->leftJoin('transactions', 'transactions.transaction_journal_id', '=',
|
||||
'transaction_journals.id');
|
||||
$query->leftJoin(
|
||||
'transactions', 'transactions.transaction_journal_id', '=',
|
||||
'transaction_journals.id'
|
||||
);
|
||||
$this->joinedTransactions = true;
|
||||
}
|
||||
|
||||
@ -373,8 +155,10 @@ class TransactionJournal extends Ardent
|
||||
public function scopeTransactionTypes(Builder $query, array $types)
|
||||
{
|
||||
if (is_null($this->joinedTransactionTypes)) {
|
||||
$query->leftJoin('transaction_types', 'transaction_types.id', '=',
|
||||
'transaction_journals.transaction_type_id');
|
||||
$query->leftJoin(
|
||||
'transaction_types', 'transaction_types.id', '=',
|
||||
'transaction_journals.transaction_type_id'
|
||||
);
|
||||
$this->joinedTransactionTypes = true;
|
||||
}
|
||||
$query->whereIn('transaction_types.type', $types);
|
||||
@ -389,11 +173,11 @@ class TransactionJournal extends Ardent
|
||||
public function scopeWithRelevantData(Builder $query)
|
||||
{
|
||||
$query->with(
|
||||
['transactions' => function ($q) {
|
||||
$q->orderBy('amount', 'ASC');
|
||||
}, 'transactiontype', 'components' => function ($q) {
|
||||
$q->orderBy('class');
|
||||
}, 'transactions.account.accounttype','recurringTransaction']
|
||||
['transactions' => function ($q) {
|
||||
$q->orderBy('amount', 'ASC');
|
||||
}, 'transactiontype', 'components' => function ($q) {
|
||||
$q->orderBy('class');
|
||||
}, 'transactions.account.accounttype', 'recurringTransaction']
|
||||
);
|
||||
}
|
||||
|
||||
|
386
app/routes.php
386
app/routes.php
@ -3,174 +3,183 @@
|
||||
//use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
|
||||
|
||||
// models:
|
||||
Route::bind('account', function($value, $route)
|
||||
{
|
||||
if(Auth::check()) {
|
||||
Route::bind(
|
||||
'account', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
$account = Account::
|
||||
leftJoin('account_types','account_types.id','=','accounts.account_type_id')->
|
||||
where('account_types.editable',1)->
|
||||
where('accounts.id', $value)->
|
||||
where('user_id',Auth::user()->id)->
|
||||
first(['accounts.*']);
|
||||
if($account) {
|
||||
leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')->where('account_types.editable', 1)->where('accounts.id', $value)
|
||||
->where('user_id', Auth::user()->id)->first(['accounts.*']);
|
||||
if ($account) {
|
||||
return $account;
|
||||
}
|
||||
}
|
||||
App::abort(404);
|
||||
});
|
||||
|
||||
Route::bind('accountname', function($value, $route)
|
||||
{
|
||||
if(Auth::check()) {
|
||||
return Account::
|
||||
leftJoin('account_types','account_types.id','=','accounts.account_type_id')->
|
||||
where('account_types.editable',1)->
|
||||
where('name', $value)->
|
||||
where('user_id',Auth::user()->id)->first();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
|
||||
Route::bind('recurring', function($value, $route)
|
||||
{
|
||||
if(Auth::check()) {
|
||||
return RecurringTransaction::
|
||||
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;
|
||||
});
|
||||
|
||||
Route::bind('reminder', function($value, $route)
|
||||
{
|
||||
if(Auth::check()) {
|
||||
return Reminder::
|
||||
where('id', $value)->
|
||||
where('user_id',Auth::user()->id)->first();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
Route::bind('category', function($value, $route)
|
||||
{
|
||||
if(Auth::check()) {
|
||||
return Category::
|
||||
where('id', $value)->
|
||||
where('user_id',Auth::user()->id)->first();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
);
|
||||
|
||||
Route::bind('tj', function($value, $route)
|
||||
{
|
||||
if(Auth::check()) {
|
||||
Route::bind(
|
||||
'accountname', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Account::
|
||||
leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')->where('account_types.editable', 1)->where('name', $value)->where(
|
||||
'user_id', Auth::user()->id
|
||||
)->first();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Route::bind(
|
||||
'recurring', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return RecurringTransaction::
|
||||
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;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'reminder', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Reminder::
|
||||
where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'category', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Category::
|
||||
where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind(
|
||||
'tj', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return TransactionJournal::
|
||||
where('id', $value)->
|
||||
where('user_id',Auth::user()->id)->first();
|
||||
where('id', $value)->where('user_id', Auth::user()->id)->first();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind('limit', function($value, $route)
|
||||
{
|
||||
if(Auth::check()) {
|
||||
Route::bind(
|
||||
'limit', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Limit::
|
||||
where('limits.id', $value)->
|
||||
leftJoin('components','components.id','=','limits.component_id')->
|
||||
where('components.class','Budget')->
|
||||
where('components.user_id',Auth::user()->id)->first(['limits.*']);
|
||||
where('limits.id', $value)->leftJoin('components', 'components.id', '=', 'limits.component_id')->where('components.class', 'Budget')->where(
|
||||
'components.user_id', Auth::user()->id
|
||||
)->first(['limits.*']);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind('limitrepetition', function($value, $route)
|
||||
{
|
||||
if(Auth::check()) {
|
||||
Route::bind(
|
||||
'limitrepetition', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return LimitRepetition::
|
||||
where('limit_repetitions.id', $value)->
|
||||
leftjoin('limits','limits.id','=','limit_repetitions.limit_id')->
|
||||
leftJoin('components','components.id','=','limits.component_id')->
|
||||
where('components.class','Budget')->
|
||||
where('components.user_id',Auth::user()->id)->first(['limit_repetitions.*']);
|
||||
where('limit_repetitions.id', $value)->leftjoin('limits', 'limits.id', '=', 'limit_repetitions.limit_id')->leftJoin(
|
||||
'components', 'components.id', '=', 'limits.component_id'
|
||||
)->where('components.class', 'Budget')->where('components.user_id', Auth::user()->id)->first(['limit_repetitions.*']);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
Route::bind('piggybank', function($value, $route)
|
||||
{
|
||||
if(Auth::check()) {
|
||||
Route::bind(
|
||||
'piggybank', function ($value, $route) {
|
||||
if (Auth::check()) {
|
||||
return Piggybank::
|
||||
where('piggybanks.id', $value)->
|
||||
leftJoin('accounts','accounts.id','=','piggybanks.account_id')->
|
||||
where('accounts.user_id',Auth::user()->id)->first(['piggybanks.*']);
|
||||
where('piggybanks.id', $value)->leftJoin('accounts', 'accounts.id', '=', 'piggybanks.account_id')->where('accounts.user_id', Auth::user()->id)
|
||||
->first(['piggybanks.*']);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// a development route:
|
||||
Route::get('/dev', ['uses' => 'HomeController@jobDev']);
|
||||
|
||||
// protected routes:
|
||||
Route::group(['before' => 'auth'], function () {
|
||||
|
||||
|
||||
Route::group(
|
||||
['before' => 'auth'], function () {
|
||||
|
||||
|
||||
// some date routes:
|
||||
Route::get('/prev',['uses' => 'HomeController@sessionPrev', 'as' => 'sessionPrev']);
|
||||
Route::get('/next',['uses' => 'HomeController@sessionNext', 'as' => 'sessionNext']);
|
||||
Route::get('/jump/{range}',['uses' => 'HomeController@rangeJump','as' => 'rangeJump']);
|
||||
Route::get('/prev', ['uses' => 'HomeController@sessionPrev', 'as' => 'sessionPrev']);
|
||||
Route::get('/next', ['uses' => 'HomeController@sessionNext', 'as' => 'sessionNext']);
|
||||
Route::get('/jump/{range}', ['uses' => 'HomeController@rangeJump', 'as' => 'rangeJump']);
|
||||
Route::get('/cleanup', ['uses' => 'HomeController@cleanup', 'as' => 'cleanup']);
|
||||
|
||||
// account controller:
|
||||
Route::get('/accounts', ['uses' => 'AccountController@index', 'as' => 'accounts.index']);
|
||||
Route::get('/accounts/asset', ['uses' => 'AccountController@asset', 'as' => 'accounts.asset']);
|
||||
Route::get('/accounts/expense', ['uses' => 'AccountController@expense', 'as' => 'accounts.expense']);
|
||||
Route::get('/accounts/revenue', ['uses' => 'AccountController@revenue', 'as' => 'accounts.revenue']);
|
||||
|
||||
Route::get('/accounts/create/{what}', ['uses' => 'AccountController@create', 'as' => 'accounts.create'])->where('what','revenue|asset|expense');
|
||||
Route::get('/accounts/{account}', ['uses' => 'AccountController@show', 'as' => 'accounts.show']);
|
||||
Route::get('/accounts/{account}/edit', ['uses' => 'AccountController@edit', 'as' => 'accounts.edit']);
|
||||
Route::get('/accounts/{account}/delete', ['uses' => 'AccountController@delete', 'as' => 'accounts.delete']);
|
||||
Route::get('/accounts/json/{what}', ['uses' => 'AccountController@json', 'as' => 'accounts.json'])->where('what', 'revenue|asset|expense');
|
||||
Route::get('/accounts/{what}', ['uses' => 'AccountController@index', 'as' => 'accounts.index'])->where('what', 'revenue|asset|expense');
|
||||
Route::get('/accounts/create/{what}', ['uses' => 'AccountController@create', 'as' => 'accounts.create'])->where('what', 'revenue|asset|expense');
|
||||
Route::get('/accounts/edit/{account}', ['uses' => 'AccountController@edit', 'as' => 'accounts.edit']);
|
||||
Route::get('/accounts/delete/{account}', ['uses' => 'AccountController@delete', 'as' => 'accounts.delete']);
|
||||
Route::get('/accounts/show/{account}', ['uses' => 'AccountController@show', 'as' => 'accounts.show']);
|
||||
|
||||
// budget controller:
|
||||
Route::get('/budgets/date',['uses' => 'BudgetController@indexByDate','as' => 'budgets.index.date']);
|
||||
Route::get('/budgets/budget',['uses' => 'BudgetController@indexByBudget','as' => 'budgets.index.budget']);
|
||||
Route::get('/budgets/create',['uses' => 'BudgetController@create', 'as' => 'budgets.create']);
|
||||
Route::get('/budgets', ['uses' => 'BudgetController@index', 'as' => 'budgets.index']);
|
||||
Route::get('/budgets/income', ['uses' => 'BudgetController@updateIncome', 'as' => 'budgets.income']);
|
||||
Route::get('/budgets/show/{budget}/{limitrepetition?}', ['uses' => 'BudgetController@show', 'as' => 'budgets.show']);
|
||||
|
||||
Route::get('/budgets/nobudget/{period}',['uses' => 'BudgetController@nobudget', 'as' => 'budgets.nobudget']);
|
||||
#Route::get('/budgets/date', ['uses' => 'BudgetController@indexByDate', 'as' => 'budgets.index.date']);
|
||||
#Route::get('/budgets/budget', ['uses' => 'BudgetController@indexByBudget', 'as' => 'budgets.index.budget']);
|
||||
Route::get('/budgets/create', ['uses' => 'BudgetController@create', 'as' => 'budgets.create']);
|
||||
#Route::get('/budgets/nobudget/{period}', ['uses' => 'BudgetController@nobudget', 'as' => 'budgets.nobudget']);
|
||||
|
||||
Route::get('/budgets/show/{budget}/{limitrepetition?}',['uses' => 'BudgetController@show', 'as' => 'budgets.show']);
|
||||
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/edit/{budget}', ['uses' => 'BudgetController@edit', 'as' => 'budgets.edit']);
|
||||
Route::get('/budgets/delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'budgets.delete']);
|
||||
|
||||
// category controller:
|
||||
Route::get('/categories',['uses' => 'CategoryController@index','as' => 'categories.index']);
|
||||
Route::get('/categories/create',['uses' => 'CategoryController@create','as' => 'categories.create']);
|
||||
Route::get('/categories/show/{category}',['uses' => 'CategoryController@show','as' => 'categories.show']);
|
||||
Route::get('/categories/edit/{category}',['uses' => 'CategoryController@edit','as' => 'categories.edit']);
|
||||
Route::get('/categories/delete/{category}',['uses' => 'CategoryController@delete','as' => 'categories.delete']);
|
||||
Route::get('/categories', ['uses' => 'CategoryController@index', 'as' => 'categories.index']);
|
||||
Route::get('/categories/create', ['uses' => 'CategoryController@create', 'as' => 'categories.create']);
|
||||
Route::get('/categories/show/{category}', ['uses' => 'CategoryController@show', 'as' => 'categories.show']);
|
||||
Route::get('/categories/edit/{category}', ['uses' => 'CategoryController@edit', 'as' => 'categories.edit']);
|
||||
Route::get('/categories/delete/{category}', ['uses' => 'CategoryController@delete', 'as' => 'categories.delete']);
|
||||
|
||||
// google chart controller
|
||||
Route::get('/chart/home/account', ['uses' => 'GoogleChartController@allAccountsBalanceChart']);
|
||||
Route::get('/chart/home/budgets', ['uses' => 'GoogleChartController@allBudgetsHomeChart']);
|
||||
Route::get('/chart/home/categories', ['uses' => 'GoogleChartController@allCategoriesHomeChart']);
|
||||
Route::get('/chart/home/recurring', ['uses' => 'GoogleChartController@recurringTransactionsOverview']);
|
||||
Route::get('/chart/account/{account}', ['uses' => 'GoogleChartController@accountBalanceChart']);
|
||||
Route::get('/chart/sankey/{account}/out', ['uses' => 'GoogleChartController@accountSankeyOutChart']);
|
||||
Route::get('/chart/sankey/{account}/in', ['uses' => 'GoogleChartController@accountSankeyInChart']);
|
||||
Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']);
|
||||
Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']);
|
||||
Route::get('/chart/reports/budgets/{year}', ['uses' => 'GoogleChartController@budgetsReportChart']);
|
||||
Route::get('/chart/budgets/{budget}/spending/{year}', ['uses' => 'GoogleChartController@budgetsAndSpending']);
|
||||
|
||||
// google table controller
|
||||
Route::get('/table/account/{account}/transactions', ['uses' => 'GoogleTableController@transactionsByAccount']);
|
||||
Route::get('/table/accounts/{what}', ['uses' => 'GoogleTableController@accountList']);
|
||||
Route::get('/table/budget/{budget}/{limitrepetition?}/transactions', ['uses' => 'GoogleTableController@transactionsByBudget']);
|
||||
|
||||
|
||||
// chart controller
|
||||
Route::get('/chart/home/account/{account?}', ['uses' => 'ChartController@homeAccount', 'as' => 'chart.home']);
|
||||
Route::get('/chart/home/categories', ['uses' => 'ChartController@homeCategories', 'as' => 'chart.categories']);
|
||||
Route::get('/chart/home/budgets', ['uses' => 'ChartController@homeBudgets', 'as' => 'chart.budgets']);
|
||||
Route::get('/chart/home/info/{accountnameA}/{day}/{month}/{year}', ['uses' => 'ChartController@homeAccountInfo', 'as' => 'chart.info']);
|
||||
Route::get('/chart/categories/show/{category}', ['uses' => 'ChartController@categoryShowChart','as' => 'chart.showcategory']);
|
||||
Route::get('/chart/home/recurring', ['uses' => 'ChartController@homeRecurring', 'as' => 'chart.recurring']);
|
||||
Route::get('/chart/categories/show/{category}', ['uses' => 'ChartController@categoryShowChart', 'as' => 'chart.showcategory']);
|
||||
|
||||
// (new charts for budgets)
|
||||
Route::get('/chart/budget/{budget}/default', ['uses' => 'ChartController@budgetDefault', 'as' => 'chart.budget.default']);
|
||||
Route::get('chart/budget/{budget}/no_envelope', ['uses' => 'ChartController@budgetNoLimits', 'as' => 'chart.budget.nolimit']);
|
||||
@ -192,96 +201,111 @@ Route::group(['before' => 'auth'], function () {
|
||||
Route::get('/json/recurringjournals/{recurring}', ['uses' => 'JsonController@recurringjournals', 'as' => 'json.recurringjournals']);
|
||||
|
||||
// limit controller:
|
||||
Route::get('/budgets/limits/create/{budget?}',['uses' => 'LimitController@create','as' => 'budgets.limits.create']);
|
||||
Route::get('/budgets/limits/delete/{limit}',['uses' => 'LimitController@delete','as' => 'budgets.limits.delete']);
|
||||
Route::get('/budgets/limits/edit/{limit}',['uses' => 'LimitController@edit','as' => 'budgets.limits.edit']);
|
||||
Route::get('/budgets/limits/create/{budget?}', ['uses' => 'LimitController@create', 'as' => 'budgets.limits.create']);
|
||||
Route::get('/budgets/limits/delete/{limit}', ['uses' => 'LimitController@delete', 'as' => 'budgets.limits.delete']);
|
||||
Route::get('/budgets/limits/edit/{limit}', ['uses' => 'LimitController@edit', 'as' => 'budgets.limits.edit']);
|
||||
|
||||
Route::get('/migrate',['uses' => 'MigrateController@index', 'as' => 'migrate.index']);
|
||||
Route::get('/migrate', ['uses' => 'MigrateController@index', 'as' => 'migrate.index']);
|
||||
|
||||
// piggy bank controller
|
||||
Route::get('/piggybanks',['uses' => 'PiggybankController@piggybanks','as' => 'piggybanks.index.piggybanks']);
|
||||
Route::get('/repeated',['uses' => 'PiggybankController@repeated','as' => 'piggybanks.index.repeated']);
|
||||
Route::get('/piggybanks/create/piggybank', ['uses' => 'PiggybankController@createPiggybank','as' => 'piggybanks.create.piggybank']);
|
||||
Route::get('/piggybanks/create/repeated', ['uses' => 'PiggybankController@createRepeated','as' => 'piggybanks.create.repeated']);
|
||||
Route::get('/piggybanks/addMoney/{piggybank}', ['uses' => 'PiggybankController@addMoney','as' => 'piggybanks.amount.add']);
|
||||
Route::get('/piggybanks/removeMoney/{piggybank}', ['uses' => 'PiggybankController@removeMoney','as' => 'piggybanks.amount.remove']);
|
||||
Route::get('/piggybanks/show/{piggybank}', ['uses' => 'PiggybankController@show','as' => 'piggybanks.show']);
|
||||
Route::get('/piggybanks/edit/{piggybank}', ['uses' => 'PiggybankController@edit','as' => 'piggybanks.edit']);
|
||||
Route::get('/piggybanks/delete/{piggybank}', ['uses' => 'PiggybankController@delete','as' => 'piggybanks.delete']);
|
||||
Route::post('/piggybanks/updateAmount/{piggybank}',['uses' => 'PiggybankController@updateAmount','as' => 'piggybanks.updateAmount']);
|
||||
Route::get('/piggybanks', ['uses' => 'PiggybankController@index', 'as' => 'piggybanks.index']);
|
||||
Route::get('/piggybanks/add/{piggybank}', ['uses' => 'PiggybankController@add']);
|
||||
Route::get('/piggybanks/remove/{piggybank}', ['uses' => 'PiggybankController@remove']);
|
||||
Route::get('/piggybanks/edit/{piggybank}', ['uses' => 'PiggybankController@edit', 'as' => 'piggybanks.edit']);
|
||||
Route::get('/piggybanks/create', ['uses' => 'PiggybankController@create', 'as' => 'piggybanks.create']);
|
||||
Route::get('/piggybanks/delete/{piggybank}', ['uses' => 'PiggybankController@delete', 'as' => 'piggybanks.delete']);
|
||||
|
||||
|
||||
// Route::get('/repeated',['uses' => 'PiggybankController@repeated','as' => 'piggybanks.index.repeated']);
|
||||
// Route::get('/piggybanks/create/repeated', ['uses' => 'PiggybankController@createRepeated','as' => 'piggybanks.create.repeated']);
|
||||
// Route::get('/piggybanks/addMoney/{piggybank}', ['uses' => 'PiggybankController@addMoney','as' => 'piggybanks.amount.add']);
|
||||
// Route::get('/piggybanks/removeMoney/{piggybank}', ['uses' => 'PiggybankController@removeMoney','as' => 'piggybanks.amount.remove']);
|
||||
// Route::get('/piggybanks/show/{piggybank}', ['uses' => 'PiggybankController@show','as' => 'piggybanks.show']);
|
||||
// Route::get('/piggybanks/delete/{piggybank}', ['uses' => 'PiggybankController@delete','as' => 'piggybanks.delete']);
|
||||
// Route::post('/piggybanks/updateAmount/{piggybank}',['uses' => 'PiggybankController@updateAmount','as' => 'piggybanks.updateAmount']);
|
||||
|
||||
// preferences controller
|
||||
Route::get('/preferences', ['uses' => 'PreferencesController@index', 'as' => 'preferences']);
|
||||
|
||||
//profile controller
|
||||
Route::get('/profile', ['uses' => 'ProfileController@index', 'as' => 'profile']);
|
||||
Route::get('/profile/change-password',['uses' => 'ProfileController@changePassword', 'as' => 'change-password']);
|
||||
Route::get('/profile/change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']);
|
||||
|
||||
// recurring transactions controller
|
||||
Route::get('/recurring',['uses' => 'RecurringController@index', 'as' => 'recurring.index']);
|
||||
Route::get('/recurring/show/{recurring}',['uses' => 'RecurringController@show', 'as' => 'recurring.show']);
|
||||
Route::get('/recurring/rescan/{recurring}',['uses' => 'RecurringController@rescan', 'as' => 'recurring.rescan']);
|
||||
Route::get('/recurring/create',['uses' => 'RecurringController@create', 'as' => 'recurring.create']);
|
||||
Route::get('/recurring/edit/{recurring}',['uses' => 'RecurringController@edit','as' => 'recurring.edit']);
|
||||
Route::get('/recurring/delete/{recurring}',['uses' => 'RecurringController@delete','as' => 'recurring.delete']);
|
||||
Route::get('/recurring', ['uses' => 'RecurringController@index', 'as' => 'recurring.index']);
|
||||
Route::get('/recurring/show/{recurring}', ['uses' => 'RecurringController@show', 'as' => 'recurring.show']);
|
||||
Route::get('/recurring/rescan/{recurring}', ['uses' => 'RecurringController@rescan', 'as' => 'recurring.rescan']);
|
||||
Route::get('/recurring/create', ['uses' => 'RecurringController@create', 'as' => 'recurring.create']);
|
||||
Route::get('/recurring/edit/{recurring}', ['uses' => 'RecurringController@edit', 'as' => 'recurring.edit']);
|
||||
Route::get('/recurring/delete/{recurring}', ['uses' => 'RecurringController@delete', 'as' => 'recurring.delete']);
|
||||
|
||||
// report controller:
|
||||
Route::get('/reports',['uses' => 'ReportController@index','as' => 'reports.index']);
|
||||
Route::get('/reports', ['uses' => 'ReportController@index', 'as' => 'reports.index']);
|
||||
Route::get('/reports/{year}', ['uses' => 'ReportController@year', 'as' => 'reports.year']);
|
||||
|
||||
// search controller:
|
||||
Route::get('/search',['uses' => 'SearchController@index','as' => 'search']);
|
||||
Route::get('/search', ['uses' => 'SearchController@index', 'as' => 'search']);
|
||||
|
||||
// transaction controller:
|
||||
Route::get('/transactions/create/{what}', ['uses' => 'TransactionController@create', 'as' => 'transactions.create'])->where(['what' => 'withdrawal|deposit|transfer']);
|
||||
Route::get('/transaction/show/{tj}',['uses' => 'TransactionController@show','as' => 'transactions.show']);
|
||||
Route::get('/transaction/edit/{tj}',['uses' => 'TransactionController@edit','as' => 'transactions.edit']);
|
||||
Route::get('/transaction/delete/{tj}',['uses' => 'TransactionController@delete','as' => 'transactions.delete']);
|
||||
Route::get('/transactions/index',['uses' => 'TransactionController@index','as' => 'transactions.index']);
|
||||
Route::get('/transactions/expenses',['uses' => 'TransactionController@expenses','as' => 'transactions.expenses']);
|
||||
Route::get('/transactions/revenue',['uses' => 'TransactionController@revenue','as' => 'transactions.revenue']);
|
||||
Route::get('/transactions/transfers',['uses' => 'TransactionController@transfers','as' => 'transactions.transfers']);
|
||||
Route::get('/transactions/create/{what}', ['uses' => 'TransactionController@create', 'as' => 'transactions.create'])->where(
|
||||
['what' => 'withdrawal|deposit|transfer']
|
||||
);
|
||||
Route::get('/transaction/show/{tj}', ['uses' => 'TransactionController@show', 'as' => 'transactions.show']);
|
||||
Route::get('/transaction/edit/{tj}', ['uses' => 'TransactionController@edit', 'as' => 'transactions.edit']);
|
||||
Route::get('/transaction/delete/{tj}', ['uses' => 'TransactionController@delete', 'as' => 'transactions.delete']);
|
||||
Route::get('/transactions/index', ['uses' => 'TransactionController@index', 'as' => 'transactions.index']);
|
||||
Route::get('/transactions/expenses', ['uses' => 'TransactionController@expenses', 'as' => 'transactions.expenses']);
|
||||
Route::get('/transactions/revenue', ['uses' => 'TransactionController@revenue', 'as' => 'transactions.revenue']);
|
||||
Route::get('/transactions/transfers', ['uses' => 'TransactionController@transfers', 'as' => 'transactions.transfers']);
|
||||
|
||||
Route::get('/transactions/expenses',['uses' => 'TransactionController@expenses','as' => 'transactions.index.withdrawal']);
|
||||
Route::get('/transactions/revenue',['uses' => 'TransactionController@revenue','as' => 'transactions.index.deposit']);
|
||||
Route::get('/transactions/transfers',['uses' => 'TransactionController@transfers','as' => 'transactions.index.transfer']);
|
||||
Route::get('/transactions/expenses', ['uses' => 'TransactionController@expenses', 'as' => 'transactions.index.withdrawal']);
|
||||
Route::get('/transactions/revenue', ['uses' => 'TransactionController@revenue', 'as' => 'transactions.index.deposit']);
|
||||
Route::get('/transactions/transfers', ['uses' => 'TransactionController@transfers', 'as' => 'transactions.index.transfer']);
|
||||
|
||||
// user controller
|
||||
Route::get('/logout', ['uses' => 'UserController@logout', 'as' => 'logout']);
|
||||
|
||||
Route::post('budgets/amount/{budget}', ['uses' => 'BudgetController@amount']);
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// protected + csrf routes (POST)
|
||||
Route::group(['before' => 'csrf|auth'], function () {
|
||||
Route::group(
|
||||
['before' => 'csrf|auth'], function () {
|
||||
// account controller:
|
||||
Route::post('/accounts/store', ['uses' => 'AccountController@store', 'as' => 'accounts.store']);
|
||||
Route::post('/accounts/update/{account}', ['uses' => 'AccountController@update', 'as' => 'accounts.update']);
|
||||
Route::post('/accounts/destroy/{account}', ['uses' => 'AccountController@destroy', 'as' => 'accounts.destroy']);
|
||||
|
||||
// budget controller:
|
||||
Route::post('/budgets/store',['uses' => 'BudgetController@store', 'as' => 'budgets.store']);
|
||||
Route::post('/budgets/income', ['uses' => 'BudgetController@postUpdateIncome', 'as' => 'budgets.postIncome']);
|
||||
Route::post('/budgets/update/{budget}', ['uses' => 'BudgetController@update', 'as' => 'budgets.update']);
|
||||
Route::post('/budgets/store', ['uses' => 'BudgetController@store', 'as' => 'budgets.store']);
|
||||
Route::post('/budgets/destroy/{budget}', ['uses' => 'BudgetController@destroy', 'as' => 'budgets.destroy']);
|
||||
|
||||
// category controller
|
||||
Route::post('/categories/store',['uses' => 'CategoryController@store', 'as' => 'categories.store']);
|
||||
Route::post('/categories/store', ['uses' => 'CategoryController@store', 'as' => 'categories.store']);
|
||||
Route::post('/categories/update/{category}', ['uses' => 'CategoryController@update', 'as' => 'categories.update']);
|
||||
Route::post('/categories/destroy/{category}', ['uses' => 'CategoryController@destroy', 'as' => 'categories.destroy']);
|
||||
|
||||
// limit controller:
|
||||
Route::post('/budgets/limits/store/{budget?}', ['uses' => 'LimitController@store', 'as' => 'budgets.limits.store']);
|
||||
Route::post('/budgets/limits/destroy/{limit}',['uses' => 'LimitController@destroy','as' => 'budgets.limits.destroy']);
|
||||
Route::post('/budgets/limits/update/{limit}',['uses' => 'LimitController@update','as' => 'budgets.limits.update']);
|
||||
Route::post('/budgets/limits/destroy/{limit}', ['uses' => 'LimitController@destroy', 'as' => 'budgets.limits.destroy']);
|
||||
Route::post('/budgets/limits/update/{limit}', ['uses' => 'LimitController@update', 'as' => 'budgets.limits.update']);
|
||||
|
||||
Route::post('/migrate/upload',['uses' => 'MigrateController@upload', 'as' => 'migrate.upload']);
|
||||
Route::post('/migrate/upload', ['uses' => 'MigrateController@upload', 'as' => 'migrate.upload']);
|
||||
|
||||
|
||||
// piggy bank controller
|
||||
Route::post('/piggybanks/store/piggybank',['uses' => 'PiggybankController@storePiggybank','as' => 'piggybanks.store.piggybank']);
|
||||
Route::post('/piggybanks/store/repeated',['uses' => 'PiggybankController@storeRepeated','as' => 'piggybanks.store.repeated']);
|
||||
Route::post('/piggybanks/update/{piggybank}', ['uses' => 'PiggybankController@update','as' => 'piggybanks.update']);
|
||||
Route::post('/piggybanks/destroy/{piggybank}', ['uses' => 'PiggybankController@destroy','as' => 'piggybanks.destroy']);
|
||||
Route::post('/piggybanks/mod/{piggybank}', ['uses' => 'PiggybankController@modMoney','as' => 'piggybanks.modMoney']);
|
||||
Route::post('/piggybanks/store', ['uses' => 'PiggybankController@store', 'as' => 'piggybanks.store']);
|
||||
#Route::post('/piggybanks/store/repeated', ['uses' => 'PiggybankController@storeRepeated', 'as' => 'piggybanks.store.repeated']);
|
||||
Route::post('/piggybanks/update/{piggybank}', ['uses' => 'PiggybankController@update', 'as' => 'piggybanks.update']);
|
||||
Route::post('/piggybanks/destroy/{piggybank}', ['uses' => 'PiggybankController@destroy', 'as' => 'piggybanks.destroy']);
|
||||
#Route::post('/piggybanks/mod/{piggybank}', ['uses' => 'PiggybankController@modMoney', 'as' => 'piggybanks.modMoney']);
|
||||
Route::post('/piggybanks/add/{piggybank}', ['uses' => 'PiggybankController@postAdd', 'as' => 'piggybanks.add']);
|
||||
Route::post('/piggybanks/remove/{piggybank}', ['uses' => 'PiggybankController@postRemove', 'as' => 'piggybanks.remove']);
|
||||
|
||||
|
||||
// preferences controller
|
||||
@ -291,20 +315,23 @@ Route::group(['before' => 'csrf|auth'], function () {
|
||||
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword']);
|
||||
|
||||
// recurring controller
|
||||
Route::post('/recurring/store',['uses' => 'RecurringController@store', 'as' => 'recurring.store']);
|
||||
Route::post('/recurring/update/{recurring}',['uses' => 'RecurringController@update','as' => 'recurring.update']);
|
||||
Route::post('/recurring/destroy/{recurring}',['uses' => 'RecurringController@destroy','as' => 'recurring.destroy']);
|
||||
Route::post('/recurring/store', ['uses' => 'RecurringController@store', 'as' => 'recurring.store']);
|
||||
Route::post('/recurring/update/{recurring}', ['uses' => 'RecurringController@update', 'as' => 'recurring.update']);
|
||||
Route::post('/recurring/destroy/{recurring}', ['uses' => 'RecurringController@destroy', 'as' => 'recurring.destroy']);
|
||||
|
||||
// transaction controller:
|
||||
Route::post('/transactions/store/{what}', ['uses' => 'TransactionController@store', 'as' => 'transactions.store'])->where(['what' => 'withdrawal|deposit|transfer']);
|
||||
Route::post('/transaction/update/{tj}',['uses' => 'TransactionController@update','as' => 'transactions.update']);
|
||||
Route::post('/transaction/destroy/{tj}',['uses' => 'TransactionController@destroy','as' => 'transactions.destroy']);
|
||||
Route::post('/transactions/store/{what}', ['uses' => 'TransactionController@store', 'as' => 'transactions.store'])->where(
|
||||
['what' => 'withdrawal|deposit|transfer']
|
||||
);
|
||||
Route::post('/transaction/update/{tj}', ['uses' => 'TransactionController@update', 'as' => 'transactions.update']);
|
||||
Route::post('/transaction/destroy/{tj}', ['uses' => 'TransactionController@destroy', 'as' => 'transactions.destroy']);
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// guest routes:
|
||||
Route::group(['before' => 'guest'], function () {
|
||||
Route::group(
|
||||
['before' => 'guest'], function () {
|
||||
// user controller
|
||||
Route::get('/login', ['uses' => 'UserController@login', 'as' => 'login']);
|
||||
Route::get('/register', ['uses' => 'UserController@register', 'as' => 'register']);
|
||||
@ -317,7 +344,8 @@ Route::group(['before' => 'guest'], function () {
|
||||
);
|
||||
|
||||
// guest + csrf routes:
|
||||
Route::group(['before' => 'csrf|guest'], function () {
|
||||
Route::group(
|
||||
['before' => 'csrf|guest'], function () {
|
||||
|
||||
// user controller
|
||||
Route::post('/login', ['uses' => 'UserController@postLogin']);
|
||||
|
@ -72,30 +72,51 @@ App::down(
|
||||
);
|
||||
|
||||
// forms:
|
||||
\Form::macro('ffText', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffText($name, $value, $options);
|
||||
});
|
||||
\Form::macro('ffSelect', function ($name, array $list = [], $selected = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffSelect($name, $list, $selected, $options);
|
||||
});
|
||||
\Form::macro('ffInteger', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffInteger($name, $value, $options);
|
||||
});
|
||||
\Form::macro('ffAmount', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffAmount($name, $value, $options);
|
||||
});
|
||||
\Form::macro('ffDate', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffDate($name, $value, $options);
|
||||
});
|
||||
\Form::macro('ffTags', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffTags($name, $value, $options);
|
||||
});
|
||||
\Form::macro('ffCheckbox',function ($name, $value = 1, $checked = null, $options = []) {
|
||||
return \Firefly\Form\Form::ffCheckbox($name, $value, $checked, $options);
|
||||
});
|
||||
\Form::macro('ffOptionsList',function ($type, $name) {
|
||||
return \Firefly\Form\Form::ffOptionsList($type, $name);
|
||||
});
|
||||
\Form::macro(
|
||||
'ffText', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffText($name, $value, $options);
|
||||
}
|
||||
);
|
||||
\Form::macro(
|
||||
'ffSelect', function ($name, array $list = [], $selected = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffSelect($name, $list, $selected, $options);
|
||||
}
|
||||
);
|
||||
\Form::macro(
|
||||
'ffInteger', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffInteger($name, $value, $options);
|
||||
}
|
||||
);
|
||||
\Form::macro(
|
||||
'ffAmount', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffAmount($name, $value, $options);
|
||||
}
|
||||
);
|
||||
\Form::macro(
|
||||
'ffBalance', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffBalance($name, $value, $options);
|
||||
}
|
||||
);
|
||||
\Form::macro(
|
||||
'ffDate', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffDate($name, $value, $options);
|
||||
}
|
||||
);
|
||||
\Form::macro(
|
||||
'ffTags', function ($name, $value = null, array $options = []) {
|
||||
return \Firefly\Form\Form::ffTags($name, $value, $options);
|
||||
}
|
||||
);
|
||||
\Form::macro(
|
||||
'ffCheckbox', function ($name, $value = 1, $checked = null, $options = []) {
|
||||
return \Firefly\Form\Form::ffCheckbox($name, $value, $checked, $options);
|
||||
}
|
||||
);
|
||||
\Form::macro(
|
||||
'ffOptionsList', function ($type, $name) {
|
||||
return \Firefly\Form\Form::ffOptionsList($type, $name);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -1,18 +0,0 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p>
|
||||
<a href="{{route('accounts.create','asset')}}" class="btn btn-success btn-large">Create a new asset account</a>
|
||||
</p>
|
||||
@if(count($accounts) > 0)
|
||||
@include('accounts.list')
|
||||
<p>
|
||||
<a href="{{route('accounts.create','asset')}}" class="btn btn-success btn-large">Create a new asset account</a>
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@stop
|
@ -4,98 +4,50 @@
|
||||
{{Form::hidden('what',$what)}}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<h4>Mandatory fields</h4>
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('name', 'Account name', ['class' => 'col-sm-4 control-label'])}}
|
||||
<div class="col-sm-8">
|
||||
{{ Form::text('name', Input::old('name'), ['class' => 'form-control']) }}
|
||||
@if($errors->has('name'))
|
||||
<p class="text-danger">{{$errors->first('name')}}</p>
|
||||
@else
|
||||
@if($what == 'asset')
|
||||
<span class="help-block">
|
||||
Use something descriptive such as "checking account" or "My Bank Main Account".
|
||||
</span>
|
||||
@endif
|
||||
@if($what == 'expense')
|
||||
<span class="help-block">
|
||||
Use something descriptive such as "Albert Heijn" or "Amazon".
|
||||
</span>
|
||||
@endif
|
||||
@if($what == 'revenue')
|
||||
<span class="help-block">
|
||||
Use something descriptive such as "my mom" or "my job".
|
||||
</span>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{{$subTitleIcon}}}"></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 {{{$what}}} account
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
@if($what == 'asset')
|
||||
<h4>Optional fields</h4>
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('openingbalance', 'Opening balance', ['class' => 'col-sm-4 control-label'])}}
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">€</span>
|
||||
{{Form::input('number','openingbalance', Input::old('openingbalance'), ['step' => 'any', 'class' => 'form-control'])}}
|
||||
</div>
|
||||
|
||||
@if($errors->has('openingbalance'))
|
||||
<p class="text-danger">{{$errors->first('openingbalance')}}</p>
|
||||
@else
|
||||
<span class="help-block">What's the current balance of this new account?</span>
|
||||
@endif
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-smile-o"></i> Optional fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@if($what == 'asset')
|
||||
{{Form::ffBalance('openingbalance')}}
|
||||
{{Form::ffDate('openingbalancedate', date('Y-m-d'))}}
|
||||
@endif
|
||||
{{Form::ffCheckbox('active','1',true)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ Form::label('openingbalancedate', 'Opening balance date', ['class' => 'col-sm-4 control-label'])}}
|
||||
<div class="col-sm-8">
|
||||
{{ Form::input('date','openingbalancedate', Input::old('openingbalancedate') ?: date('Y-m-d'), ['class'
|
||||
=> 'form-control']) }}
|
||||
@if($errors->has('openingbalancedate'))
|
||||
<p class="text-danger">{{$errors->first('openingbalancedate')}}</p>
|
||||
@else
|
||||
<span class="help-block">When was this the balance of the new account? Since your bank statements may lag behind, update this date to match the date of the last known balance of the account.</span>
|
||||
@endif
|
||||
|
||||
|
||||
<!-- 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','account')}}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
|
||||
<!-- add another after this one? -->
|
||||
<div class="form-group">
|
||||
<label for="create" class="col-sm-4 control-label"> </label>
|
||||
<div class="col-sm-8">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
{{Form::checkbox('create',1,Input::old('create') == '1')}}
|
||||
Create another (return to this form)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-4 col-sm-8">
|
||||
<button type="submit" class="btn btn-default btn-success">Create the {{{$what}}} account</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{Form::close()}}
|
||||
@stop
|
@ -1,44 +1,38 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">
|
||||
Remember that deleting something is permanent.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('accounts.destroy',$account->id)])}}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
@if($account->transactions()->count() > 0)
|
||||
<p class="text-info">
|
||||
Account "{{{$account->name}}}" still has {{$account->transactions()->count()}} transaction(s) associated to it.
|
||||
These will be deleted as well.
|
||||
</p>
|
||||
@endif
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<div class="panel panel-red">
|
||||
<div class="panel-heading">
|
||||
Delete account "{{{$account->name}}}"
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
Are you sure?
|
||||
</p>
|
||||
|
||||
<p class="text-danger">
|
||||
Press "Delete permanently" If you are sure you want to delete "{{{$account->name}}}".
|
||||
</p>
|
||||
@if($account->transactions()->count() > 0)
|
||||
<p class="text-info">
|
||||
Account "{{{$account->name}}}" still has {{$account->transactions()->count()}} transaction(s) associated to it.
|
||||
These will be deleted as well.
|
||||
</p>
|
||||
@endif
|
||||
|
||||
<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">
|
||||
<button type="submit" class="btn btn-default btn-danger">Delete permanently</button>
|
||||
@if($account->accountType->type == 'Asset account' || $account->accountType->type == 'Default account')
|
||||
<a href="{{route('accounts.asset')}}" class="btn-default btn">Cancel</a >
|
||||
@endif
|
||||
@if($account->accountType->type == 'Expense account' || $account->accountType->type == 'Beneficiary account')
|
||||
<a href="{{route('accounts.expense')}}" class="btn-default btn">Cancel</a >
|
||||
@endif
|
||||
@if($account->accountType->type == 'Revenue account')
|
||||
<a href="{{route('accounts.revenue')}}" class="btn-default btn">Cancel</a >
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,79 +11,46 @@
|
||||
{{Form::model($account, ['class' => 'form-horizontal','url' => route('accounts.update',$account->id)])}}
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<h4>Mandatory fields</h4>
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('name', 'Account name', ['class' => 'col-sm-4 control-label'])}}
|
||||
<div class="col-sm-8">
|
||||
{{ Form::text('name', Input::old('name'), ['class' => 'form-control']) }}
|
||||
@if($errors->has('name'))
|
||||
<p class="text-danger">{{$errors->first('name')}}</p>
|
||||
@else
|
||||
<span
|
||||
class="help-block">Use something descriptive such as "checking account" or "Albert Heijn".</span>
|
||||
@endif
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{{$subTitleIcon}}}"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{Form::ffText('name')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
Update account
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
@if($account->accounttype->type == 'Default account' || $account->accounttype->type == 'Asset account')
|
||||
<h4>Optional fields</h4>
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('openingbalance', 'Opening balance', ['class' => 'col-sm-4 control-label'])}}
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">€</span>
|
||||
@if(!is_null($openingBalance))
|
||||
{{Form::input('number','openingbalance', Input::old('openingbalance') ?: $openingBalance->transactions[1]->amount, ['step' => 'any', 'class' => 'form-control'])}}
|
||||
@else
|
||||
{{Form::input('number','openingbalance', Input::old('openingbalance'), ['step' => 'any', 'class' => 'form-control'])}}
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
@if($errors->has('openingbalance'))
|
||||
<p class="text-danger">{{$errors->first('openingbalance')}}</p>
|
||||
@else
|
||||
<span class="help-block">What's the current balance of this new account?</span>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-smile-o"></i> Optional fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{Form::ffCheckbox('active','1')}}
|
||||
@if($account->accounttype->type == 'Default account' || $account->accounttype->type == 'Asset account')
|
||||
{{Form::ffBalance('openingbalance')}}
|
||||
{{Form::ffDate('openingbalancedate')}}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ Form::label('openingbalancedate', 'Opening balance date', ['class' => 'col-sm-4 control-label'])}}
|
||||
<div class="col-sm-8">
|
||||
@if(!is_null($openingBalance))
|
||||
{{ Form::input('date','openingbalancedate', Input::old('openingbalancedate') ?: $openingBalance->date->format('Y-m-d'), ['class' => 'form-control']) }}
|
||||
@else
|
||||
{{ Form::input('date','openingbalancedate', Input::old('openingbalancedate') ?: '', ['class' => 'form-control']) }}
|
||||
@endif
|
||||
@if($errors->has('openingbalancedate'))
|
||||
<p class="text-danger">{{$errors->first('openingbalancedate')}}</p>
|
||||
@else
|
||||
<span class="help-block">When was this the balance of the new account? Since your bank statements may lag behind, update this date to match the date of the last known balance of the account.</span>
|
||||
@endif
|
||||
|
||||
<!-- 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','account')}}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-4 col-sm-8">
|
||||
<button type="submit" class="btn btn-default btn-success">Update {{{$account->name}}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{Form::close()}}
|
||||
@stop
|
@ -1,28 +0,0 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">
|
||||
Bla bla expense
|
||||
</p>
|
||||
<p class="text-info">
|
||||
Bla bla bla expense
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p>
|
||||
<a href="{{route('accounts.create','expense')}}" class="btn btn-success">Create a new expense account</a>
|
||||
</p>
|
||||
@if(count($accounts) > 0)
|
||||
@include('accounts.list')
|
||||
<p>
|
||||
<a href="{{route('accounts.create','expense')}}" class="btn btn-success">Create a new expense account</a>
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@stop
|
@ -2,42 +2,45 @@
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<h1>Firefly
|
||||
<small>Accounts</small>
|
||||
</h1>
|
||||
<p class="lead">
|
||||
Accounts are the record holders for transactions and transfers. Money moves from one account to another.
|
||||
</p>
|
||||
<p class="text-info">
|
||||
In a double-entry bookkeeping system almost <em>everything</em> is an account. Your own personal
|
||||
bank accounts are representated as accounts (naturally), but the stores you buy stuff at are also
|
||||
represented as accounts. Likewise, if you have a job, your salary is drawn from their account.
|
||||
</p>
|
||||
<p>
|
||||
<a href="{{route('accounts.create')}}" class="btn btn-success">Create a new account</a>
|
||||
</p>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{{$subTitleIcon}}}"></i> {{{$subTitle}}}
|
||||
|
||||
<!-- 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('accounts.create',$what)}}"><i class="fa fa-plus fa-fw"></i> New {{$what}} account</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="account-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
@if(count($accounts['personal']) > 0)
|
||||
<h3>Your accounts</h3>
|
||||
<p style="width:50%;" class="text-info">
|
||||
These are your personal accounts.
|
||||
</p>
|
||||
@stop
|
||||
@section('scripts')
|
||||
<script type="text/javascript">
|
||||
var what = '{{{$what}}}';
|
||||
</script>
|
||||
|
||||
@include('accounts.list',['accounts' => $accounts['personal']])
|
||||
@endif
|
||||
<!-- 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')}}
|
||||
|
||||
@if(count($accounts['beneficiaries']) > 0)
|
||||
<h3>Beneficiaries</h3>
|
||||
<p style="width:50%;" class="text-info">
|
||||
These are beneficiaries; places where you spend money or people who pay you.
|
||||
</p>
|
||||
@include('accounts.list',['accounts' => $accounts['beneficiaries']])
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="assets/javascript/firefly/accounts.js"></script>
|
||||
@stop
|
||||
|
||||
@stop
|
||||
@section('styles')
|
||||
@endsection
|
@ -1,26 +0,0 @@
|
||||
<table class="table table-bordered table-striped">
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th style="width:30%;">Name</th>
|
||||
<th>Current balance</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
@foreach($accounts as $account)
|
||||
<tr>
|
||||
<td>
|
||||
@if($account->active == 0)
|
||||
<span title="This account is inactive." class="glyphicon glyphicon-ban-circle"></span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{route('accounts.show',$account->id)}}" title="Overview for account {{{$account->name}}}">{{{$account->name}}}</a></td>
|
||||
<td>{{mf($account->balance())}}</td>
|
||||
<td>
|
||||
<span class="btn-group-xs btn-group">
|
||||
<a href="{{route('accounts.edit',$account->id)}}" title="Edit {{{$account->name}}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="{{route('accounts.delete',$account->id)}}" title="Edit {{{$account->name}}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
@ -1,28 +0,0 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">
|
||||
Bla bla revenue
|
||||
</p>
|
||||
<p class="text-info">
|
||||
Bla bla bla revenue
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p>
|
||||
<a href="{{route('accounts.create','revenue')}}" class="btn btn-success">Create a new revenue account</a>
|
||||
</p>
|
||||
@if(count($accounts) > 0)
|
||||
@include('accounts.list')
|
||||
<p>
|
||||
<a href="{{route('accounts.create','revenue')}}" class="btn btn-success">Create a new revenue account</a>
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@stop
|
@ -4,10 +4,10 @@
|
||||
<div class="col-lg-8 col-md-6 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa {{$subTitleIcon}} fa-fw"></i> {{{$account->name}}}
|
||||
<i class="fa fa-fw {{$subTitleIcon}} fa-fw"></i> {{{$account->name}}}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="chart"></div>
|
||||
<div id="overview-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -16,88 +16,26 @@
|
||||
@include('partials.date_nav')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Summary
|
||||
Out
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-striped table-condensed">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Expense / income</th>
|
||||
<th>Transfers</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Out</td>
|
||||
<td>
|
||||
{{mf($show['statistics']['period']['out'])}}
|
||||
<a href="{{route('accounts.show',$account->id)}}?type=transactions&show=expenses"><span class="glyphicon glyphicon-circle-arrow-right"></span></a>
|
||||
</td>
|
||||
<td>
|
||||
{{mf($show['statistics']['period']['t_out'])}}
|
||||
<a href="{{route('accounts.show',$account->id)}}?type=transfers&show=out"><span class="glyphicon glyphicon-circle-arrow-right"></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>In</td>
|
||||
<td>
|
||||
{{mf($show['statistics']['period']['in'])}}
|
||||
<a href="{{route('accounts.show',$account->id)}}?type=transactions&show=income"><span class="glyphicon glyphicon-circle-arrow-right"></span></a>
|
||||
</td>
|
||||
<td>
|
||||
{{mf($show['statistics']['period']['t_in'])}}
|
||||
<a href="{{route('accounts.show',$account->id)}}?type=transfers&show=in"><span class="glyphicon glyphicon-circle-arrow-right"></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Difference</td>
|
||||
<td>{{mf($show['statistics']['period']['diff'])}}</td>
|
||||
<td>{{mf($show['statistics']['period']['t_diff'])}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="account-out-sankey"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Related
|
||||
In
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-striped table-condensed">
|
||||
@if(count($show['statistics']['accounts']) > 0)
|
||||
<tr>
|
||||
<td style="width:30%;">Related accounts</td>
|
||||
<td>
|
||||
@foreach($show['statistics']['accounts'] as $acct)
|
||||
<a href="{{route('accounts.show',$acct->id)}}" class="btn btn-default btn-xs">{{{$acct->name}}}</a>
|
||||
@endforeach
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
@if(isset($show['statistics']['Category']) && count($show['statistics']['Category']) > 0)
|
||||
<tr>
|
||||
<td>Related categories</td>
|
||||
<td>
|
||||
@foreach($show['statistics']['Category'] as $cat)
|
||||
<a href="{{route('categories.show',$cat->id)}}" class="btn btn-default btn-xs">{{{$cat->name}}}</a>
|
||||
@endforeach
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
@if(isset($show['statistics']['Budget']) && count($show['statistics']['Budget']) > 0)
|
||||
<tr>
|
||||
<td>Related budgets</td>
|
||||
<td>
|
||||
@foreach($show['statistics']['Budget'] as $bud)
|
||||
<a href="{{route('budgets.show',$bud->id)}}?useSession=true" class="btn btn-default btn-xs">{{{$bud->name}}}</a>
|
||||
@endforeach
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
</table>
|
||||
<div id="account-in-sankey"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -105,23 +43,26 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
|
||||
|
||||
<h4>Transactions <small> For selected account and period</small></h4>
|
||||
@include('paginated.transactions',['journals' => $show['journals'],'sum' => true])
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-repeat fa-fw"></i> Transactions
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="account-transactions"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('styles')
|
||||
{{HTML::style('assets/stylesheets/highslide/highslide.css')}}
|
||||
@stop
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
<script type="text/javascript">
|
||||
var accountID = {{$account->id}};
|
||||
var accountID = {{{$account->id}}};
|
||||
</script>
|
||||
{{HTML::script('assets/javascript/highcharts/highcharts.js')}}
|
||||
<!-- 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/accounts.js')}}
|
||||
@stop
|
@ -1,118 +1,39 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<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>
|
||||
<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')])}}
|
||||
|
||||
{{Form::hidden('from',e(Input::get('from')))}}
|
||||
|
||||
<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-4 control-label">Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="name" class="form-control" id="name" value="{{Input::old('name')}}" placeholder="Name">
|
||||
@if($errors->has('name'))
|
||||
<p class="text-danger">{{$errors->first('name')}}</p>
|
||||
@else
|
||||
<span class="help-block">For example: groceries, bills</span>
|
||||
@endif
|
||||
<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-12 col-sm-6">
|
||||
<h4>Optional fields</h4>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="amount" class="col-sm-4 control-label">Max. amount</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">€</span>
|
||||
<input type="number" min="0.01" step="any" name="amount" class="form-control" id="amount" value="{{Input::old('amount')}}">
|
||||
<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>
|
||||
|
||||
@if($errors->has('amount'))
|
||||
<p class="text-danger">{{$errors->first('amount')}}</p>
|
||||
@else
|
||||
<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>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="period" class="col-sm-4 control-label">Spending period</label>
|
||||
<div class="col-sm-8">
|
||||
{{Form::select('repeat_freq',$periods,Input::old('repeat_freq') ?: 'monthly',['class' => 'form-control'])}}
|
||||
@if($errors->has('repeat_freq'))
|
||||
<p class="text-danger">{{$errors->first('repeat_freq')}}</p>
|
||||
@else
|
||||
<span class="help-block">How long will the envelope last? A week, a month, or even longer?</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="period" class="col-sm-4 control-label">Repeat</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" value="1" name="repeats">
|
||||
Repeat
|
||||
</label>
|
||||
<div class="panel-body">
|
||||
{{Form::ffOptionsList('create','budget')}}
|
||||
</div>
|
||||
@if($errors->has('repeats'))
|
||||
<p class="text-danger">{{$errors->first('repeats')}}</p>
|
||||
@else
|
||||
<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>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
|
||||
<!-- add another after this one? -->
|
||||
<div class="form-group">
|
||||
<label for="create" class="col-sm-4 control-label"> </label>
|
||||
<div class="col-sm-8">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
{{Form::checkbox('create',1,Input::old('create') == '1')}}
|
||||
Create another (return to this form)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-4 col-sm-8">
|
||||
<button type="submit" class="btn btn-default btn-success">Create the budget</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{Form::close()}}
|
||||
|
||||
|
@ -1,42 +1,31 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">
|
||||
Remember that deleting something is permanent.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('budgets.destroy',$budget->id)])}}
|
||||
{{Form::hidden('from',e(Input::get('from')))}}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
@if($budget->transactionjournals()->count() > 0)
|
||||
<p class="text-info">
|
||||
<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>
|
||||
|
||||
Account "{{{$budget->name}}}" still has {{$budget->transactionjournals()->count()}} transaction(s) associated to it.
|
||||
These will NOT be deleted but will lose their connection to the budget.
|
||||
</p>
|
||||
@endif
|
||||
|
||||
<p class="text-danger">
|
||||
Press "Delete permanently" If you are sure you want to delete "{{{$budget->name}}}".
|
||||
</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">
|
||||
<button type="submit" class="btn btn-default btn-danger">Delete permanently</button>
|
||||
@if(Input::get('from') == 'date')
|
||||
<a href="{{route('budgets.index')}}" class="btn-default btn">Cancel</a>
|
||||
@else
|
||||
<a href="{{route('budgets.index.budget')}}" class="btn-default btn">Cancel</a>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,40 +7,34 @@
|
||||
</div>
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('budgets.update',$budget->id)])}}
|
||||
|
||||
{{Form::hidden('from',e(Input::get('from')))}}
|
||||
|
||||
<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-4 control-label">Name</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" name="name" class="form-control" id="name" value="{{Input::old('name') ?: $budget->name}}" placeholder="Name">
|
||||
@if($errors->has('name'))
|
||||
<p class="text-danger">{{$errors->first('name')}}</p>
|
||||
@else
|
||||
<span class="help-block">For example: groceries, bills</span>
|
||||
@endif
|
||||
<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>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-4 col-sm-8">
|
||||
<button type="submit" class="btn btn-default btn-success">Update the budget</button>
|
||||
<!-- 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()}}
|
||||
|
||||
|
||||
|
21
app/views/budgets/income.blade.php
Normal file
21
app/views/budgets/income.blade.php
Normal file
@ -0,0 +1,21 @@
|
||||
<form style="display: inline;" 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 {{$date->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>
|
190
app/views/budgets/index.blade.php
Normal file
190
app/views/budgets/index.blade.php
Normal file
@ -0,0 +1,190 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<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')->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">{{mf(300)}}</span></small>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-4 col-sm-3" style="text-align:right;">
|
||||
<small>Income {{\Session::get('start')->format('F Y')}}:
|
||||
<a href="#" class="updateIncome"><span id="totalAmount" data-value="{{$budgetAmount->data}}">{{mf($budgetAmount->data)}}</span></a></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="progress">
|
||||
<div class="progress-bar" 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: {{mf($spent)}}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="progress">
|
||||
@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" 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>
|
||||
</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($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="900" min="0" value="{{$budget->currentRep->amount}}" />
|
||||
@else
|
||||
<input type="range" data-id="{{$budget->id}}" data-spent="{{$budget->spent}}" id="budget-range-{{$budget->id}}" max="900" 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->limit > $budget->spent)
|
||||
<span class="text-success">€</span> <input type="number" min="0" max="900" data-id="{{$budget->id}}" step="1" value="{{$budget->limit}}" style="width:50px;color:#3c763d;" />
|
||||
@else
|
||||
<span class="text-danger">€</span> <input type="number" min="0" max="900" data-id="{{$budget->id}}" step="1" value="{{$budget->limit}}" style="width:50px;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;">€</span> <input data-id="{{$budget->id}}" type="number" min="0" max="900" 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: {{mf($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>
|
||||
|
||||
|
||||
|
||||
@foreach($budgets as $budget)
|
||||
{{--
|
||||
<div class="row">
|
||||
<div class="col-lg-9 col-sm-8 col-md-8">
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-4 col-sm-4">
|
||||
{{$budget->name}}
|
||||
</div>
|
||||
<div class="col-lg-7 col-md-4 col-sm-4">
|
||||
|
||||
</div>
|
||||
<div class="col-lg-2 col-md-4 col-sm-3">
|
||||
<span id="budget-range-display-{{$budget->id}}" data-id="{{$budget->id}}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-7 col-lg-offset-3 col-md-4 col-md-offset-4 col-sm-4 col-sm-offset-4">
|
||||
@if($budget->pct > 0)
|
||||
<!-- display a progress bar. -->
|
||||
<div class="progress" id="budget-progress-{{$budget->id}}" data-spent="{{$budget->spent}}" data-amount="{{$budget->limit}}">
|
||||
|
||||
</div>
|
||||
@else
|
||||
<!-- do NOT display a progress bar. -->
|
||||
<div style="display:none;" class="progress" id="budget-progress-{{$budget->id}}" data-spent="{{$budget->spent}}" data-amount="{{$budget->limit}}">
|
||||
|
||||
</div>
|
||||
@endif
|
||||
<!--
|
||||
@if($budget->currentRep)
|
||||
@if($budget->currentRep->amount <= $budget->spent)
|
||||
Overspent on budget (budgeted: {{$budget->currentRep->amount}}, spent: {{$budget->spent}}).
|
||||
@else
|
||||
NOT overspent on budget (budgeted: {{$budget->currentRep->amount}}, spent: {{$budget->spent}}).
|
||||
|
||||
@endif
|
||||
@else
|
||||
No limit.
|
||||
@endif
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
--}}
|
||||
@endforeach
|
||||
|
||||
<!-- DIALOG -->
|
||||
<div class="modal fade" id="monthlyBudgetModal">
|
||||
</div><!-- /.modal -->
|
||||
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
{{HTML::script('assets/javascript/firefly/budgets.js')}}
|
||||
@stop
|
@ -1,113 +0,0 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<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>
|
||||
|
||||
<p class="text-info">
|
||||
Budgets are groups of expenses that reappear every [period]*. Examples could be "groceries", "bills" or
|
||||
"drinks with friends". The table below lists all of the budgets you have, if any.
|
||||
<a href="http://dictionary.reference.com/browse/budget">By definition</a>, budgets are an estimated amount
|
||||
of money, ie. € 400,-. Such an estimation can change over time but <em>should</em> always be set. Budgets
|
||||
without an actual budget are fairly pointless.
|
||||
</p>
|
||||
<p class="text-info">
|
||||
Use this page to create or change budgets and the estimated amount of money you think is wise. Pages further ahead
|
||||
will explain what an "envelope" is in the context of budgeting.
|
||||
</p>
|
||||
<p class="text-info">
|
||||
* <small>Every month, week, year, etc.</small>
|
||||
</p>
|
||||
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-default" href ="{{route('budgets.create')}}?from=budget"><span class="glyphicon glyphicon-plus-sign"></span> Create a new budget</a>
|
||||
<a class="btn btn-default" href ="{{route('budgets.limits.create')}}?from=budget"><span class="glyphicon glyphicon-plus-sign"></span> Create a new envelope</a>
|
||||
</div>
|
||||
</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>Update budget</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->leftInRepetition() < 0)
|
||||
<span class="label label-danger">
|
||||
<span class="glyphicon glyphicon-envelope"></span>
|
||||
{{mf($rep->leftInRepetition(),false)}}</span>
|
||||
@else
|
||||
<span class="label label-success">
|
||||
<span class="glyphicon glyphicon-envelope"></span>
|
||||
{{mf($rep->leftInRepetition(),false)}}</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<small>
|
||||
<a href="{{route('budgets.show',$budget->id,$rep->id)}}">
|
||||
{{$rep->periodShow()}}
|
||||
</a>
|
||||
</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">
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{route('budgets.limits.edit',$limit->id)}}?from=budget" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
@if($limit->repeats == 0 || ($limit->repeats == 1 && $index == 0))
|
||||
<a href="{{route('budgets.limits.delete',$limit->id)}}?from=budget" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endforeach
|
||||
<p style="margin-top:5px;">
|
||||
<a href="{{route('budgets.limits.create',$budget->id)}}?from=budget" class="btn btn-default btn-xs"><span
|
||||
class="glyphicon-plus-sign glyphicon"></span> Add another envelope</a>
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a href="{{route('budgets.edit',$budget->id)}}?from=budget" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="{{route('budgets.delete',$budget->id)}}?from=budget" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
@ -1,87 +0,0 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<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>
|
||||
|
||||
<p class="text-info">
|
||||
Budgets are groups of expenses that reappear every [period]*. Examples could be "groceries", "bills" or
|
||||
"drinks with friends". The table below lists all of the budgets you have, if any.
|
||||
<a href="http://dictionary.reference.com/browse/budget">By definition</a>, budgets are an estimated amount
|
||||
of money, ie. € 400,-. Such an estimation can change over time but <em>should</em> always be set. Budgets
|
||||
without an actual budget are fairly pointless.
|
||||
</p>
|
||||
<p class="text-info">
|
||||
Use this page to create or change budgets and the estimated amount of money you think is wise. Pages further ahead
|
||||
will explain what an "envelope" is in the context of budgeting.
|
||||
</p>
|
||||
<p class="text-info">
|
||||
* <small>Every month, week, year, etc.</small>
|
||||
</p>
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-default" href ="{{route('budgets.create')}}?from=date"><span class="glyphicon glyphicon-plus-sign"></span> Create a new budget</a>
|
||||
<a class="btn btn-default" href ="{{route('budgets.limits.create')}}?from=date"><span class="glyphicon glyphicon-plus-sign"></span> Create a new envelope</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- count = zero! -->
|
||||
|
||||
@foreach($budgets as $date => $entry)
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<h3><a href="{{route('transactions.index')}}?startdate={{$entry['start']->format('Y-m-d')}}&enddate={{$entry['end']->format('Y-m-d')}}">{{$entry['date']}}</a>
|
||||
<a class="btn btn-default btn-xs" href ="{{route('budgets.limits.create')}}?startdate={{$entry['start']->format('Y-m-d')}}"><span class="glyphicon glyphicon-plus-sign"></span> Create a new envelope for {{$entry['date']}}</a>
|
||||
</h3>
|
||||
<table class="table table-bordered table-striped">
|
||||
<tr>
|
||||
<th colspan="2" style="width:45%;">Budget</th>
|
||||
<th style="width:15%;">Envelope</th>
|
||||
<th style="width:15%;">Left</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
@foreach($entry['limitrepetitions'] as $index => $repetition)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<a title="Edit budget {{{$repetition->limit->budget->name}}}" href="{{route('budgets.edit',$repetition->limit->budget->id)}}?from=date" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a title="Delete budget {{{$repetition->limit->budget->name}}}" href="{{route('budgets.delete',$repetition->limit->budget->id)}}?from=date" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{route('budgets.show',[$repetition->limit->budget->id,$repetition->id])}}">
|
||||
{{{$repetition->limit->budget->name}}}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label label-primary">
|
||||
<span class="glyphicon glyphicon-envelope"></span> {{mf($repetition->amount,false)}}</span>
|
||||
</td>
|
||||
<td>
|
||||
@if($repetition->left < 0)
|
||||
<span class="label label-danger">
|
||||
<span class="glyphicon glyphicon-envelope"></span>
|
||||
{{mf($repetition->left,false)}}</span>
|
||||
@else
|
||||
<span class="label label-success">
|
||||
<span class="glyphicon glyphicon-envelope"></span>
|
||||
{{mf($repetition->left,false)}}</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<a title="Edit envelope for {{{$repetition->limit->budget->name}}} in {{$entry['date']}}" href="{{route('budgets.limits.edit',$repetition->limit->id)}}?from=date" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a title="Delete envelope for {{{$repetition->limit->budget->name}}} in {{$entry['date']}}" href="{{route('budgets.limits.delete',$repetition->limit->id)}}?from=date" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</div>
|
||||
@if($repetition->limit->repeats == 1)
|
||||
<span class="label label-warning">auto repeats</span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
@stop
|
@ -1,30 +0,0 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
@if($view == 'session')
|
||||
<!-- warning for session date -->
|
||||
<p class="bg-primary" style="padding:15px;">
|
||||
This view is filtered to only show transactions between {{Session::get('start')->format('d M Y')}}
|
||||
and {{Session::get('end')->format('d M Y')}}.
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@if($transactions->count() > 0)
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
@include('lists.transactions',['journals' => $transactions,'sum' => true])
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h4>{{$repetition['date']}}
|
||||
</h4>
|
||||
<p><em>No transactions</em></p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@stop
|
@ -1,120 +1,92 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">Budgets can help you cut back on spending.</p>
|
||||
<div class="col-lg-9 col-md-9 col-sm-7">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Some stuff?
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="budgetOverview"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($view == 1)
|
||||
<!-- warning for selected limit -->
|
||||
<p class="bg-primary" style="padding:15px;">
|
||||
This view is filtered to show only the envelope from
|
||||
{{{$repetitions[0]['limitrepetition']->periodShow()}}},
|
||||
which contains {{mf($repetitions[0]['limit']->amount,false)}}.
|
||||
</p>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Transactions
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="transactions"></div>
|
||||
</div>
|
||||
</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: {{mf($rep->amount)}}
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-6">
|
||||
Spent: {{mf($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
|
||||
|
||||
@endif
|
||||
|
||||
|
||||
@if($view == 2)
|
||||
<!-- warning for non-caught only -->
|
||||
<p class="bg-primary" style="padding:15px;">
|
||||
This view is filtered to show transactions not in an envelope only.
|
||||
</p>
|
||||
@endif
|
||||
|
||||
@if($view == 3)
|
||||
<!-- warning for session date -->
|
||||
<p class="bg-primary" style="padding:15px;">
|
||||
This view is filtered to only show transactions between {{Session::get('start')->format('d M Y')}}
|
||||
and {{Session::get('end')->format('d M Y')}}.
|
||||
</p>
|
||||
@endif
|
||||
@if($view != 4)
|
||||
<p class="bg-info" style="padding:15px;">
|
||||
<a class="btn btn-default btn-sm" href="{{route('budgets.show',$budget->id)}}">Reset the filter</a>
|
||||
</p>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div id="chart"></div>
|
||||
@if($view == 1)
|
||||
<div id="instr" data-type="envelope" data-envelope="{{$repetitions[0]['limitrepetition']->id}}"></div>
|
||||
@endif
|
||||
|
||||
|
||||
@if($view == 2)
|
||||
<div id="instr" data-type="no_envelope" data-budget="{{$budget->id}}"></div>
|
||||
@endif
|
||||
|
||||
@if($view == 3)
|
||||
<div id="instr" data-type="session" data-budget="{{$budget->id}}"></div>
|
||||
@endif
|
||||
|
||||
@if($view == 4)
|
||||
<div id="instr" data-type="default" data-budget="{{$budget->id}}"></div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@foreach($repetitions as $repetition)
|
||||
@if(isset($repetition['journals']) && count($repetition['journals']) > 0)
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
|
||||
|
||||
@if($repetition['paginated'] == true)
|
||||
<h4>
|
||||
<a href="{{route('budgets.show',$budget->id)}}?noenvelope=true">
|
||||
{{$repetition['date']}}</a> <small>paginated</small></h4>
|
||||
@else
|
||||
<h4>
|
||||
<a href="{{route('budgets.show',$budget->id,$repetition['limitrepetition']->id)}}">
|
||||
{{$repetition['date']}}
|
||||
</a>
|
||||
</h4>
|
||||
<small>{{mf($repetition['limit']->amount,false)}}
|
||||
(left: {{mf($repetition['limitrepetition']->leftInRepetition(),false)}})</small>
|
||||
@endif
|
||||
</h4>
|
||||
@if($repetition['paginated'] == true)
|
||||
@include('paginated.transactions',['journals' => $repetition['journals'],'highlight' => $highlight])
|
||||
@else
|
||||
@include('lists.transactions',['journals' => $repetition['journals'],'sum' => true,'highlight' => $highlight])
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h4>{{$repetition['date']}}
|
||||
</h4>
|
||||
<p><em>No transactions</em></p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
{{HTML::script('assets/javascript/highcharts/highcharts.js')}}
|
||||
@if($view == 1)
|
||||
{{HTML::script('assets/javascript/firefly/budgets/limit.js')}}
|
||||
@endif
|
||||
<script type="text/javascript">
|
||||
var budgetID = {{$budget->id}};
|
||||
@if(!is_null($repetition))
|
||||
var repetitionID = {{$repetition->id}};
|
||||
var year = {{$repetition->startdate->format('Y')}};
|
||||
@else
|
||||
var year = {{Session::get('start')->format('Y')}};
|
||||
@endif
|
||||
|
||||
@if($view == 2)
|
||||
{{HTML::script('assets/javascript/firefly/budgets/nolimit.js')}}
|
||||
@endif
|
||||
</script>
|
||||
|
||||
@if($view == 3)
|
||||
{{HTML::script('assets/javascript/firefly/budgets/session.js')}}
|
||||
@endif
|
||||
@if($view == 4)
|
||||
{{HTML::script('assets/javascript/firefly/budgets/default.js')}}
|
||||
@endif
|
||||
<!-- 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
|
@ -8,7 +8,7 @@
|
||||
Expenses grouped in categories do not have to reoccur every month or every week, like budgets.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- TODO cleanup to match new theme & form -->
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('categories.store')])}}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
Remember that deleting something is permanent.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- TODO cleanup to match new theme & form -->
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('categories.destroy',$category->id)])}}
|
||||
<div class="row">
|
||||
|
@ -4,7 +4,7 @@
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">Use categories to group your expenses</p>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- TODO cleanup to match new theme & form -->
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('categories.update',$category->id)])}}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
<a href="{{route('categories.create')}}" class="btn btn-success"><span class="glyphicon glyphicon-plus"></span> Create a new category</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- TODO cleanup to match new theme & form -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
|
@ -15,13 +15,13 @@
|
||||
transactions for the currently selected period.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- TODO cleanup to match new theme & form -->
|
||||
|
||||
|
||||
@include('partials.date_nav')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div id="chart"><p class="small text-center">(Some chart here)</p></div>
|
||||
<div id="chart"><img src="http://placehold.it/650x300" title="Placeholder" alt="" /></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -40,6 +40,5 @@
|
||||
<script type="text/javascript">
|
||||
var categoryID = {{$category->id}};
|
||||
</script>
|
||||
{{HTML::script('assets/javascript/highcharts/highcharts.js')}}
|
||||
{{HTML::script('assets/javascript/firefly/categories.js')}}
|
||||
@stop
|
@ -9,4 +9,4 @@
|
||||
<td>{{mf($entry['amount']*-1)}}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
</table><!-- TODO remove me -->
|
@ -12,3 +12,4 @@
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<!-- TODO remove me -->
|
@ -30,102 +30,107 @@
|
||||
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-md-12 col-sm-12">
|
||||
<!-- ACCOUNTS -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-credit-card fa-fw"></i> <a href="#">Your accounts</a>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="accounts-chart" style="height:300px;"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-md-12 col-sm-12">
|
||||
<!-- ACCOUNTS -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-credit-card fa-fw"></i> <a href="#">Your accounts</a>
|
||||
</div>
|
||||
<!-- BUDGETS -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-tasks fa-fw"></i> <a href="{{route('budgets.index.date')}}">Budgets and spending</a>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="budgets"></div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="accounts-chart"></div>
|
||||
</div>
|
||||
<!-- CATEGORIES -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-bar-chart fa-fw"></i> <a href="{{route('categories.index')}}">Categories</a>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="categories"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-line-chart"></i> Savings
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
Bla bla
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6 col-sm-12">
|
||||
<!-- time based navigation -->
|
||||
@include('partials.date_nav')
|
||||
|
||||
<!-- REMINDERS -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-line-chart"></i> Recurring transactions
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="recurring"></div>
|
||||
</div>
|
||||
<!-- BUDGETS -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-tasks fa-fw"></i> <a href="{{route('budgets.index')}}">Budgets and spending</a>
|
||||
</div>
|
||||
|
||||
<!-- TRANSACTIONS -->
|
||||
@foreach($transactions as $data)
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-money fa-fw"></i>
|
||||
<a href="{{route('accounts.show',$data[1]->id)}}">{{{$data[1]->name}}}</a>
|
||||
|
||||
|
||||
<!-- ACTIONS MENU -->
|
||||
<div class="pull-right">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
|
||||
Actions
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li><a href="{{route('transactions.create','withdrawal')}}?account_id={{{$data[1]->id}}}"><i class="fa fa-long-arrow-left fa-fw"></i> New withdrawal</a></li>
|
||||
<li><a href="{{route('transactions.create','deposit')}}?account_id={{{$data[1]->id}}}"><i class="fa fa-long-arrow-right fa-fw"></i> New deposit</a></li>
|
||||
<li><a href="{{route('transactions.create','transfer')}}?account_from_id={{{$data[1]->id}}}"><i class="fa fa-arrows-h fa-fw"></i> New transfer</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@include('transactions.journals-small-index',['transactions' => $data[0],'account' => $data[1]])
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="budgets-chart"></div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<!-- CATEGORIES -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-bar-chart fa-fw"></i> <a href="{{route('categories.index')}}">Categories</a>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="categories-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-line-chart"></i> Savings
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
(todo)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6 col-sm-12">
|
||||
<!-- time based navigation -->
|
||||
@include('partials.date_nav')
|
||||
|
||||
@endif
|
||||
<!-- REMINDERS -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-line-chart"></i> Recurring transactions
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="recurring-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
{{HTML::script('assets/javascript/highcharts/highcharts.js')}}
|
||||
{{HTML::script('assets/javascript/firefly/index.js')}}
|
||||
@stop
|
||||
@section('styles')
|
||||
{{HTML::style('assets/stylesheets/highslide/highslide.css')}}
|
||||
@stop
|
||||
<!-- TRANSACTIONS -->
|
||||
@foreach($transactions as $data)
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-money fa-fw"></i>
|
||||
<a href="{{route('accounts.show',$data[1]->id)}}">{{{$data[1]->name}}}</a>
|
||||
|
||||
|
||||
<!-- ACTIONS MENU -->
|
||||
<div class="pull-right">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
|
||||
Actions
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu pull-right" role="menu">
|
||||
<li><a href="{{route('transactions.create','withdrawal')}}?account_id={{{$data[1]->id}}}"><i class="fa fa-long-arrow-left fa-fw"></i> New withdrawal</a></li>
|
||||
<li><a href="{{route('transactions.create','deposit')}}?account_id={{{$data[1]->id}}}"><i class="fa fa-long-arrow-right fa-fw"></i> New deposit</a></li>
|
||||
<li><a href="{{route('transactions.create','transfer')}}?account_from_id={{{$data[1]->id}}}"><i class="fa fa-arrows-h fa-fw"></i> New transfer</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@include('transactions.journals-small-index',['transactions' => $data[0],'account' => $data[1]])
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endif
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
<!-- 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/index.js')}}
|
||||
@stop
|
||||
@section('styles')
|
||||
@stop
|
@ -17,6 +17,7 @@
|
||||
{{HTML::style('assets/stylesheets/metisMenu/metisMenu.min.css')}}
|
||||
{{HTML::style('assets/stylesheets/sbadmin/sb.css')}}
|
||||
{{HTML::style('assets/stylesheets/fa/css/font-awesome.min.css')}}
|
||||
{{HTML::style('http://fonts.googleapis.com/css?family=Roboto2')}}
|
||||
@yield('styles')
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
|
@ -25,4 +25,4 @@
|
||||
@yield('content')
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html><!-- TODO main update title and title-tag -->
|
@ -14,7 +14,7 @@
|
||||
always add more of them.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- TODO cleanup and use new forms -->
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('budgets.limits.store',$prefilled['budget_id'])])}}
|
||||
{{Form::hidden('from',e(Input::get('from')))}}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div><!-- TODO cleanup and use new forms -->
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('budgets.limits.destroy',$limit->id)])}}
|
||||
|
||||
@ -31,9 +31,9 @@
|
||||
<div class="col-sm-8">
|
||||
<input type="submit" name="submit" value="Remove envelope" class="btn btn-danger" />
|
||||
@if(Input::get('from') == 'date')
|
||||
<a href="{{route('budgets.index.date')}}" class="btn-default btn">Cancel</a>
|
||||
<a href="{{route('budgets.index')}}" class="btn-default btn">Cancel</a>
|
||||
@else
|
||||
<a href="{{route('budgets.index.budget')}}" class="btn-default btn">Cancel</a>
|
||||
<a href="{{route('budgets.index')}}" class="btn-default btn">Cancel</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
@ -17,7 +17,7 @@
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- TODO cleanup and use new forms -->
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('budgets.limits.update',$limit->id)])}}
|
||||
{{Form::hidden('from',e(Input::get('from')))}}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2" id="empty1">A</th>
|
||||
<th>Date</th>
|
||||
<th>Date</th><!-- TODO remove me-->
|
||||
<th>Description</th>
|
||||
<th>Amount (€)</th>
|
||||
<th>From</th>
|
||||
|
@ -1,3 +1,3 @@
|
||||
{{$journals->links()}}
|
||||
@include('lists.transactions')
|
||||
{{$journals->links()}}
|
||||
{{$journals->links()}} <!-- TODO is this even used? -->
|
@ -48,7 +48,7 @@
|
||||
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-user fa-fw"></i> <i class="fa fa-caret-down"></i>
|
||||
<i class="fa fa-user fa-fw"></i> <i class="fa fa-caret-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-user">
|
||||
<li><a href="{{route('profile')}}"><i class="fa fa-user fa-fw"></i> {{Auth::user()->email}}</a>
|
||||
@ -98,34 +98,19 @@
|
||||
<a href="#"><i class="fa fa-credit-card fa-fw"></i> Accounts <span class="fa arrow"></span></a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li>
|
||||
<a @if($r == 'accounts.asset') class="active" @endif href="{{route('accounts.asset')}}"><i class="fa fa-money fa-fw"></i> Asset accounts</a>
|
||||
<a @if(isset($what) && $what == 'asset')class="active"@endif href="{{route('accounts.index','asset')}}"><i class="fa fa-money fa-fw"></i> Asset accounts</a>
|
||||
</li>
|
||||
<li>
|
||||
<a @if($r == 'accounts.expense') class="active" @endif href="{{route('accounts.expense')}}"><i class="fa fa-shopping-cart fa-fw"></i> Expense accounts</a>
|
||||
<a @if(isset($what) && $what == 'expense')class="active"@endif href="{{route('accounts.index','expense')}}"><i class="fa fa-shopping-cart fa-fw"></i> Expense accounts</a>
|
||||
</li>
|
||||
<li>
|
||||
<a @if($r == 'accounts.revenue') class="active" @endif href="{{route('accounts.revenue')}}"><i class="fa fa-download fa-fw"></i> Revenue accounts</a>
|
||||
<a @if(isset($what) && $what == 'revenue')class="active"@endif href="{{route('accounts.index','revenue')}}"><i class="fa fa-download fa-fw"></i> Revenue accounts</a>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- /.nav-second-level -->
|
||||
</li>
|
||||
<li
|
||||
@if(!(strpos($r,'budgets') === false))
|
||||
class="active"
|
||||
@endif
|
||||
>
|
||||
<a href="#"><i class="fa fa-tasks fa-fw"></i> Budgets <span class="fa arrow"></span></a>
|
||||
|
||||
<ul class="nav nav-second-level">
|
||||
<li>
|
||||
<a @if($r == 'budgets.index.date') class="active" @endif href="{{route('budgets.index.date')}}"><i class="fa fa-calendar fa-fw"></i> Grouped by date</a>
|
||||
</li>
|
||||
<li>
|
||||
<a @if($r == 'budgets.index.budget') class="active" @endif href="{{route('budgets.index.budget')}}"><i class="fa fa-folder-open fa-fw"></i> Grouped by budget</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<li>
|
||||
<a href="{{route('budgets.index')}}"><i class="fa fa-tasks fa-fw"></i> Budgets</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
@ -179,14 +164,16 @@
|
||||
<a href="#"><i class="fa fa-euro fa-fw"></i> Money management<span class="fa arrow"></span></a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li>
|
||||
<a @if($r == 'piggybanks.index.piggybanks') class="active" @endif href="{{route('piggybanks.index.piggybanks')}}"><i class="fa fa-sort-amount-asc fa-fw"></i> Piggy banks</a>
|
||||
<a @if($r == 'piggybanks.index') class="active" @endif href="{{route('piggybanks.index')}}"><i class="fa fa-sort-amount-asc fa-fw"></i> Piggy banks</a>
|
||||
</li>
|
||||
<li>
|
||||
<a @if($r == 'recurring.index') class="active" @endif href="{{route('recurring.index')}}"><i class="fa fa-rotate-right fa-fw"></i> Recurring transactions</a>
|
||||
</li>
|
||||
{{--
|
||||
<li>
|
||||
<a @if($r == 'piggybanks.index.repeated') class="active" @endif href="{{route('piggybanks.index.repeated')}}"><i class="fa fa-rotate-left fa-fw"></i> Repeated expenses</a>
|
||||
</li>
|
||||
--}}
|
||||
</ul>
|
||||
<!-- /.nav-second-level -->
|
||||
</li>
|
||||
@ -208,24 +195,28 @@
|
||||
</li>
|
||||
<!--
|
||||
<li>
|
||||
<a href="{{route('accounts.create')}}"><i class="fa fa-money fa-fw"></i> Account</a>
|
||||
<a href="#"><i class="fa fa-money fa-fw"></i> Account</a>
|
||||
</li>
|
||||
-->
|
||||
<li>
|
||||
<a href="{{route('budgets.create')}}"><i class="fa fa-tasks fa-fw"></i> Budget</a>
|
||||
<a href="#"><i class="fa fa-tasks fa-fw"></i> Budget</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#"><i class="fa fa-bar-chart fa-fw"></i> Category</a>
|
||||
</li>
|
||||
{{--
|
||||
<li>
|
||||
<a href="{{route('piggybanks.create.piggybank')}}"><i class="fa fa-envelope-o fa-fw"></i> Piggy bank</a>
|
||||
</li>
|
||||
--}}
|
||||
<li>
|
||||
<a href="{{route('recurring.create')}}"><i class="fa fa-rotate-right fa-fw"></i> Recurring transaction</a>
|
||||
</li>
|
||||
{{--
|
||||
<li>
|
||||
<a href="{{route('piggybanks.create.repeated')}}"><i class="fa fa-rotate-left fa-fw"></i> Repeated expense</a>
|
||||
</li>
|
||||
--}}
|
||||
</ul>
|
||||
<!-- /.nav-second-level -->
|
||||
</li>
|
||||
|
24
app/views/piggybanks/add.blade.php
Normal file
24
app/views/piggybanks/add.blade.php
Normal file
@ -0,0 +1,24 @@
|
||||
<form style="display: inline;" action="{{route('piggybanks.add',$piggybank->id)}}" 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">Add money to {{{$piggybank->name}}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
The maximum amount you can add is {{mf($maxAmount)}}
|
||||
</p>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">€</div>
|
||||
<input step="any" class="form-control" id="amount" autocomplete="off" name="amount" max="{{round($maxAmount,2)}}" 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">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -4,7 +4,7 @@
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">Use piggy banks to save for a one-time goal.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO cleanup for new forms and layout. -->
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('piggybanks.store.piggybank')])}}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">Create repeated expenses to keep track of long-term planned expenses</p>
|
||||
</div>
|
||||
</div><!-- TODO cleanup for new forms and layout. -->
|
||||
</div>
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('piggybanks.store.repeated')])}}
|
93
app/views/piggybanks/create.blade.php
Normal file
93
app/views/piggybanks/create.blade.php
Normal file
@ -0,0 +1,93 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('piggybanks.store')])}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw fa-exclamation"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{Form::ffText('name')}}
|
||||
{{Form::ffSelect('account_id',$accounts,null,['label' => 'Save on account'])}}
|
||||
{{Form::ffAmount('targetamount')}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-plus-circle"></i> Store new piggy bank
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<!-- panel for optional fields -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-smile-o"></i> Optional fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{Form::ffDate('targetdate')}}
|
||||
{{Form::ffCheckbox('remind_me','1',false,['label' => 'Remind me'])}}
|
||||
{{Form::ffSelect('reminder',$periods,'month',['label' => 'Remind every'])}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- panel for options -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{Form::ffOptionsList('create','piggy bank')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{--
|
||||
|
||||
<h4>Mandatory fields</h4>
|
||||
|
||||
<h4>Optional fields</h4>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}}
|
||||
<div class="col-sm-8">
|
||||
<input type="number" step="1" min="1" value="{{Input::old('reminder_skip') ?: 1}}" style="width:50px;display:inline;" max="100" name="reminder_skip" class="form-control" />
|
||||
|
||||
<select class="form-control" name="reminder" style="width:150px;display: inline">
|
||||
<option value="none" label="do not remind me">do not remind me</option>
|
||||
@foreach($periods as $period)
|
||||
<option value="{{$period}}" label="{{$period}}">{{$period}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@if($errors->has('reminder'))
|
||||
<p class="text-danger">{{$errors->first('reminder')}}</p>
|
||||
@else
|
||||
<span class="help-block">Enter a number and a period and Firefly will remind you to add money
|
||||
to this piggy bank every now and then.</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-4 col-sm-8">
|
||||
<button type="submit" class="btn btn-default btn-success">Create the piggy bank</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
--}}
|
||||
|
||||
{{Form::close()}}
|
||||
@stop
|
42
app/views/piggybanks/delete.blade.old.php
Normal file
42
app/views/piggybanks/delete.blade.old.php
Normal file
@ -0,0 +1,42 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">Remember that deleting something is permanent.</p>
|
||||
|
||||
</div>
|
||||
<!-- TODO cleanup for new forms and layout. -->
|
||||
</div>
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('piggybanks.destroy',$piggybank->id)])}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<h4> </h4>
|
||||
<p class="text-info">
|
||||
This form allows you to delete the piggy bank "{{{$piggybank->name}}}".
|
||||
</p>
|
||||
<p class="text-info">
|
||||
Destroying an envelope does not remove any transactions or accounts.
|
||||
</p>
|
||||
<p class="text-danger">
|
||||
Are you sure?
|
||||
</p>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-8">
|
||||
<input type="submit" name="submit" value="Remove piggy bank" class="btn btn-danger" />
|
||||
@if($piggybank->repeats == 1)
|
||||
<a href="{{route('piggybanks.index.repeated')}}" class="btn-default btn">Cancel</a>
|
||||
@else
|
||||
<a href="{{route('piggybanks.index.piggybanks')}}" class="btn-default btn">Cancel</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{Form::close()}}
|
||||
|
||||
@stop
|
@ -1,36 +1,31 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">Remember that deleting something is permanent.</p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('piggybanks.destroy',$piggybank->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 piggy bank "{{{$piggybank->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">
|
||||
<h4> </h4>
|
||||
<p class="text-info">
|
||||
This form allows you to delete the piggy bank "{{{$piggybank->name}}}".
|
||||
</p>
|
||||
<p class="text-info">
|
||||
Destroying an envelope does not remove any transactions or accounts.
|
||||
</p>
|
||||
<p class="text-danger">
|
||||
Are you sure?
|
||||
</p>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-8">
|
||||
<input type="submit" name="submit" value="Remove piggy bank" class="btn btn-danger" />
|
||||
@if($piggybank->repeats == 1)
|
||||
<a href="{{route('piggybanks.index.repeated')}}" class="btn-default btn">Cancel</a>
|
||||
@else
|
||||
<a href="{{route('piggybanks.index.piggybanks')}}" class="btn-default btn">Cancel</a>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -38,5 +33,4 @@
|
||||
|
||||
|
||||
{{Form::close()}}
|
||||
|
||||
@stop
|
||||
@stop
|
@ -4,7 +4,7 @@
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<p class="lead">Use piggy banks to save for a one-time goal.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- TODO cleanup for new forms and layout. -->
|
||||
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('piggybanks.update',$piggybank->id)])}}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<p class="lead">Create repeated expenses to keep track of long-term planned expenses</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TODO cleanup for new forms and layout. -->
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('piggybanks.update',$piggybank->id)])}}
|
||||
|
||||
<div class="row">
|
93
app/views/piggybanks/edit.blade.php
Normal file
93
app/views/piggybanks/edit.blade.php
Normal file
@ -0,0 +1,93 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
{{Form::open(['class' => 'form-horizontal','url' => route('piggybanks.update',$piggybank->id)])}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw fa-exclamation"></i> Mandatory fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{Form::ffText('name')}}
|
||||
{{Form::ffSelect('account_id',$accounts,null,['label' => 'Save on account'])}}
|
||||
{{Form::ffAmount('targetamount')}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<button type="submit" class="btn btn-lg btn-success">
|
||||
<i class="fa fa-pencil"></i> Update piggy bank
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<!-- panel for optional fields -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-smile-o"></i> Optional fields
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{Form::ffDate('targetdate')}}
|
||||
{{Form::ffCheckbox('remind_me','1',$prefilled['remind_me'],['label' => 'Remind me'])}}
|
||||
{{Form::ffSelect('reminder',$periods,'month',['label' => 'Remind every'])}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- panel for options -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-bolt"></i> Options
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{Form::ffOptionsList('update','piggy bank')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{--
|
||||
|
||||
<h4>Mandatory fields</h4>
|
||||
|
||||
<h4>Optional fields</h4>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
{{ Form::label('reminder', 'Remind you every', ['class' => 'col-sm-4 control-label'])}}
|
||||
<div class="col-sm-8">
|
||||
<input type="number" step="1" min="1" value="{{Input::old('reminder_skip') ?: 1}}" style="width:50px;display:inline;" max="100" name="reminder_skip" class="form-control" />
|
||||
|
||||
<select class="form-control" name="reminder" style="width:150px;display: inline">
|
||||
<option value="none" label="do not remind me">do not remind me</option>
|
||||
@foreach($periods as $period)
|
||||
<option value="{{$period}}" label="{{$period}}">{{$period}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@if($errors->has('reminder'))
|
||||
<p class="text-danger">{{$errors->first('reminder')}}</p>
|
||||
@else
|
||||
<span class="help-block">Enter a number and a period and Firefly will remind you to add money
|
||||
to this piggy bank every now and then.</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-4 col-sm-8">
|
||||
<button type="submit" class="btn btn-default btn-success">Create the piggy bank</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
--}}
|
||||
|
||||
{{Form::close()}}
|
||||
@stop
|
223
app/views/piggybanks/index.blade.old.php
Normal file
223
app/views/piggybanks/index.blade.old.php
Normal file
@ -0,0 +1,223 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
|
||||
@if($countNonRepeating > 0)
|
||||
<div class="row">
|
||||
@foreach($piggybanks as $piggyBank)
|
||||
@if($piggyBank->repeats == 0)
|
||||
<div class="col-lg-2 col-md-4 col-sm-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="{{route('piggybanks.show',$piggyBank->id)}}">{{{$piggyBank->name}}}</a>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="progress" style="height:3px;">
|
||||
<div class="progress-bar @if($piggyBank->currentRelevantRep()->pct() == 100)progress-bar-success @endif " role="progressbar" aria-valuenow="{{$piggyBank->currentRelevantRep()->pct()}}" aria-valuemin="0" aria-valuemax="100" style="width: {{$piggyBank->currentRelevantRep()->pct()}}%">
|
||||
</div>
|
||||
</div>
|
||||
<p class="small">
|
||||
{{mf($piggyBank->currentRelevantRep()->currentamount)}} of {{mf($piggyBank->targetamount)}}<br />
|
||||
@if($piggyBank->targetamount-$piggyBank->currentRelevantRep()->currentamount > 0)
|
||||
{{mf($piggyBank->targetamount-$piggyBank->currentRelevantRep()->currentamount)}} to go.
|
||||
@endif
|
||||
</p>
|
||||
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{route('piggybanks.edit',$piggyBank->id)}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="{{route('piggybanks.delete',$piggyBank->id)}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
@if($accounts[$piggyBank->account_id]['account']->leftOnAccount > 0)
|
||||
<a data-toggle="modal" href="{{route('piggybanks.amount.add',$piggyBank->id)}}" data-target="#modal" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span></a>
|
||||
@endif
|
||||
@if($piggyBank->currentRelevantRep()->currentamount > 0)
|
||||
<a data-toggle="modal" href="{{route('piggybanks.amount.remove',$piggyBank->id)}}" data-target="#modal" class="btn btn-default"><span class="glyphicon glyphicon-minus-sign"></span></a>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
<div class="col-lg-2 col-md-4 col-sm-6">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<a href="{{route('piggybanks.create.piggybank')}}" class="btn btn-success btn-block">Add new piggybank</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
{{--
|
||||
|
||||
|
||||
<h3>Current piggy banks</h3>
|
||||
@if($countNonRepeating == 0)
|
||||
<p class="text-warning">No piggy banks found.</p>
|
||||
@else
|
||||
@foreach($piggybanks as $piggyBank)
|
||||
@if($piggyBank->repeats == 0)
|
||||
<h4></h4>
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<td style="width:10%;">{{mf($piggyBank->currentRelevantRep()->currentamount)}}</td>
|
||||
<td colspan="2">
|
||||
<div class="progress">
|
||||
<div class="progress-bar
|
||||
@if($piggyBank->currentRelevantRep()->pct() == 100)
|
||||
progress-bar-success
|
||||
@endif
|
||||
" role="progressbar" aria-valuenow="{{$piggyBank->currentRelevantRep()->pct()}}" aria-valuemin="0" aria-valuemax="100" style="width: {{$piggyBank->currentRelevantRep()->pct()}}%;min-width: 30px;">
|
||||
{{$piggyBank->currentRelevantRep()->pct()}}%
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width:10%;">{{mf($piggyBank->targetamount)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<td style="width:40%;">
|
||||
<div class="btn-group-xs btn-group">
|
||||
@if($accounts[$piggyBank->account_id]['account']->leftOnAccount > 0)
|
||||
<a data-toggle="modal" href="{{route('piggybanks.amount.add',$piggyBank->id)}}" data-target="#modal" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> Add money</a>
|
||||
@endif
|
||||
@if($piggyBank->currentRelevantRep()->currentamount > 0)
|
||||
<a data-toggle="modal" href="{{route('piggybanks.amount.remove',$piggyBank->id)}}" data-target="#modal" class="btn btn-default"><span class="glyphicon glyphicon-minus-sign"></span> Remove money</a>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
<td style="width:40%;">
|
||||
<p class="small">
|
||||
@if(!is_null($piggyBank->targetdate))
|
||||
Target date: {{$piggyBank->targetdate->format('M jS, Y')}}<br />
|
||||
@endif
|
||||
@if(!is_null($piggyBank->reminder))
|
||||
Next reminder: TODO
|
||||
@endif
|
||||
</p>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{route('piggybanks.edit',$piggyBank->id)}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="{{route('piggybanks.delete',$piggyBank->id)}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<h3>Current repeated expenses</h3>
|
||||
@if($countRepeating == 0)
|
||||
<p class="text-warning">No repeated expenses found.</p>
|
||||
@else
|
||||
@foreach($piggybanks as $repeated)
|
||||
@if($repeated->repeats == 1)
|
||||
<h4><a href="{{route('piggybanks.show',$repeated->id)}}">{{{$repeated->name}}}</a></h4>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<td style="width:10%;">{{mf($repeated->currentRelevantRep()->currentamount)}}</td>
|
||||
<td colspan="2">
|
||||
<div class="progress">
|
||||
<div class="progress-bar
|
||||
@if($repeated->currentRelevantRep()->pct() == 100)
|
||||
progress-bar-success
|
||||
@endif
|
||||
" role="progressbar" aria-valuenow="{{$repeated->currentRelevantRep()->pct()}}" aria-valuemin="0" aria-valuemax="100" style="width: {{$repeated->currentRelevantRep()->pct()}}%;min-width: 30px;">
|
||||
{{$repeated->currentRelevantRep()->pct()}}%
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width:10%;">{{mf($repeated->targetamount)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<td style="width:40%;">
|
||||
<div class="btn-group-xs btn-group">
|
||||
@if($accounts[$repeated->account_id]['account']->leftOnAccount > 0)
|
||||
<a data-toggle="modal" href="{{route('piggybanks.amount.add',$repeated->id)}}" data-target="#modal" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> Add money</a>
|
||||
@endif
|
||||
@if($repeated->currentRelevantRep()->currentamount > 0)
|
||||
<a data-toggle="modal" href="{{route('piggybanks.amount.remove',$repeated->id)}}" data-target="#modal" class="btn btn-default"><span class="glyphicon glyphicon-minus-sign"></span> Remove money</a>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</td>
|
||||
<td style="width:40%;">
|
||||
|
||||
@if(!is_null($repeated->reminder))
|
||||
<small>
|
||||
Next reminder: TODO
|
||||
</small>
|
||||
@endif
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{route('piggybanks.edit',$repeated->id)}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="{{route('piggybanks.delete',$repeated->id)}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--}}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h4>Account information</h4>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Account</th>
|
||||
<th>Left for piggy banks</th>
|
||||
<th>Total planned savings</th>
|
||||
<th>Saved so far</th>
|
||||
<th>Left to save</th>
|
||||
</tr>
|
||||
@foreach($accounts as $account)
|
||||
<tr>
|
||||
<td>{{{$account['account']->name}}}</td>
|
||||
<td>{{mf($account['left'])}}</td>
|
||||
<td>{{mf($account['tosave'])}}</td>
|
||||
<td>{{mf($account['saved'])}}</td>
|
||||
<td>{{mf($account['tosave']-$account['saved'])}}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
@ -1,173 +1,112 @@
|
||||
@extends('layouts.default')
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<p>
|
||||
<a href="{{route('piggybanks.create.piggybank')}}" class="btn btn-success">Create new piggy bank</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<p>
|
||||
<a href="{{route('piggybanks.create.repeated')}}" class="btn btn-success">Create new repeated expense</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<h3>Current piggy banks</h3>
|
||||
@if($countNonRepeating == 0)
|
||||
<p class="text-warning">No piggy banks found.</p>
|
||||
@else
|
||||
@foreach($piggybanks as $piggyBank)
|
||||
@if($piggyBank->repeats == 0)
|
||||
<h4><a href="{{route('piggybanks.show',$piggyBank->id)}}">{{{$piggyBank->name}}}</a></h4>
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<td style="width:10%;">{{mf($piggyBank->currentRelevantRep()->currentamount)}}</td>
|
||||
<td colspan="2">
|
||||
<div class="progress">
|
||||
<div class="progress-bar
|
||||
@if($piggyBank->currentRelevantRep()->pct() == 100)
|
||||
progress-bar-success
|
||||
@endif
|
||||
" role="progressbar" aria-valuenow="{{$piggyBank->currentRelevantRep()->pct()}}" aria-valuemin="0" aria-valuemax="100" style="width: {{$piggyBank->currentRelevantRep()->pct()}}%;min-width: 30px;">
|
||||
{{$piggyBank->currentRelevantRep()->pct()}}%
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width:10%;">{{mf($piggyBank->targetamount)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<td style="width:40%;">
|
||||
<div class="btn-group-xs btn-group">
|
||||
@if($accounts[$piggyBank->account_id]['account']->leftOnAccount > 0)
|
||||
<a data-toggle="modal" href="{{route('piggybanks.amount.add',$piggyBank->id)}}" data-target="#modal" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> Add money</a>
|
||||
@endif
|
||||
@if($piggyBank->currentRelevantRep()->currentamount > 0)
|
||||
<a data-toggle="modal" href="{{route('piggybanks.amount.remove',$piggyBank->id)}}" data-target="#modal" class="btn btn-default"><span class="glyphicon glyphicon-minus-sign"></span> Remove money</a>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
<td style="width:40%;">
|
||||
<p class="small">
|
||||
@if(!is_null($piggyBank->targetdate))
|
||||
Target date: {{$piggyBank->targetdate->format('M jS, Y')}}<br />
|
||||
@foreach($piggybanks as $piggybank)
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw fa-rocket"></i> <a href="#" title="{{{$piggybank->name}}}">{{{$piggybank->name}}}</a>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-2 col-md-3 col-sm-4">
|
||||
{{mf($piggybank->savedSoFar,true)}}
|
||||
</div>
|
||||
<div class="col-lg-8 col-md-6 col-sm-4">
|
||||
<div class="progress progress-striped">
|
||||
<div
|
||||
@if($piggybank->percentage == 100)
|
||||
class="progress-bar progress-bar-success"
|
||||
@else
|
||||
class="progress-bar progress-bar-info"
|
||||
@endif
|
||||
@if(!is_null($piggyBank->reminder))
|
||||
Next reminder: TODO
|
||||
@endif
|
||||
</p>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{route('piggybanks.edit',$piggyBank->id)}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="{{route('piggybanks.delete',$piggyBank->id)}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<h3>Current repeated expenses</h3>
|
||||
@if($countRepeating == 0)
|
||||
<p class="text-warning">No repeated expenses found.</p>
|
||||
@else
|
||||
@foreach($piggybanks as $repeated)
|
||||
@if($repeated->repeats == 1)
|
||||
<h4><a href="{{route('piggybanks.show',$repeated->id)}}">{{{$repeated->name}}}</a></h4>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<td style="width:10%;">{{mf($repeated->currentRelevantRep()->currentamount)}}</td>
|
||||
<td colspan="2">
|
||||
<div class="progress">
|
||||
<div class="progress-bar
|
||||
@if($repeated->currentRelevantRep()->pct() == 100)
|
||||
progress-bar-success
|
||||
@endif
|
||||
" role="progressbar" aria-valuenow="{{$repeated->currentRelevantRep()->pct()}}" aria-valuemin="0" aria-valuemax="100" style="width: {{$repeated->currentRelevantRep()->pct()}}%;min-width: 30px;">
|
||||
{{$repeated->currentRelevantRep()->pct()}}%
|
||||
role="progressbar" aria-valuenow="{{$piggybank->percentage}}" aria-valuemin="0" aria-valuemax="100" style="width: {{$piggybank->percentage}}%;">
|
||||
{{$piggybank->percentage}}%
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width:10%;">{{mf($repeated->targetamount)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<td style="width:40%;">
|
||||
<div class="btn-group-xs btn-group">
|
||||
@if($accounts[$repeated->account_id]['account']->leftOnAccount > 0)
|
||||
<a data-toggle="modal" href="{{route('piggybanks.amount.add',$repeated->id)}}" data-target="#modal" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> Add money</a>
|
||||
@endif
|
||||
@if($repeated->currentRelevantRep()->currentamount > 0)
|
||||
<a data-toggle="modal" href="{{route('piggybanks.amount.remove',$repeated->id)}}" data-target="#modal" class="btn btn-default"><span class="glyphicon glyphicon-minus-sign"></span> Remove money</a>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</td>
|
||||
<td style="width:40%;">
|
||||
|
||||
@if(!is_null($repeated->reminder))
|
||||
<small>
|
||||
Next reminder: TODO
|
||||
</small>
|
||||
@endif
|
||||
|
||||
</td>
|
||||
<td>
|
||||
</div>
|
||||
<div class="col-lg-2 col-md-3 col-sm-4">
|
||||
{{mf($piggybank->targetamount,true)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-2 col-md-3 col-sm-4">
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{route('piggybanks.edit',$repeated->id)}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="{{route('piggybanks.delete',$repeated->id)}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
@if($piggybank->leftToSave > 0)
|
||||
<a href="#" class="btn btn-default addMoney" data-id="{{{$piggybank->id}}}"><span data-id="{{{$piggybank->id}}}" class="glyphicon glyphicon-plus"></span></a>
|
||||
@endif
|
||||
<a href="#" class="btn btn-default removeMoney" data-id="{{{$piggybank->id}}}"><span data-id="{{{$piggybank->id}}}" class="glyphicon glyphicon-minus"></span></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col-lg-8 col-md-6 col-sm-4">
|
||||
<div class="btn-group btn-group-xs">
|
||||
<a href="{{route('piggybanks.edit',$piggybank->id)}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
<a href="{{route('piggybanks.delete',$piggybank->id)}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2 col-md-3 col-sm-4">
|
||||
@if($piggybank->leftToSave > 0)
|
||||
{{mf($piggybank->leftToSave)}}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<h4>Account information</h4>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Account</th>
|
||||
<th>Left for piggy banks</th>
|
||||
</tr>
|
||||
@foreach($accounts as $account)
|
||||
<tr>
|
||||
<td>{{{$account['account']->name}}}</td>
|
||||
<td>{{mf($account['left'])}}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- MODAL -->
|
||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="col-lg-6 col-md-6 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-fw fa-plus"></i> Create piggy bank
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-md-6 col-sm-4 col-lg-offset-2 col-md-offset-3 col-sm-offset-4">
|
||||
<a href="{{route('piggybanks.create')}}" class="btn btn-success">Create new piggy bank</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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">
|
||||
<i class="fa fa-fw fa-money"></i> Account status
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Account</th>
|
||||
<th>Balance</th>
|
||||
<th>Left for piggy banks</th>
|
||||
<th>Sum of piggy banks</th>
|
||||
<th>Saved so far</th>
|
||||
<th>Left to save</th>
|
||||
</tr>
|
||||
@foreach($accounts as $id => $info)
|
||||
<tr>
|
||||
<td><a href="{{route('accounts.show',$id)}}">{{{$info['name']}}}</a></td>
|
||||
<td>{{mf($info['balance'])}}</td>
|
||||
<td>{{mf($info['leftForPiggybanks'])}}</td>
|
||||
<td>{{mf($info['sumOfTargets'])}}</td>
|
||||
<td>{{mf($info['sumOfSaved'])}}</td>
|
||||
<td>{{mf($info['leftToSave'])}}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- this is the modal for the add/remove money routine: -->
|
||||
<div class="modal fade" id="moneyManagementModal">
|
||||
</div><!-- /.modal -->
|
||||
|
||||
@stop
|
||||
@section('scripts')
|
||||
{{HTML::script('assets/javascript/firefly/piggybanks.js')}}
|
||||
@stop
|
@ -7,7 +7,7 @@
|
||||
Remove money from "{{{$piggybank->name}}}"
|
||||
@endif
|
||||
</h4>
|
||||
</div>
|
||||
</div><!-- TODO cleanup for new forms and layout. -->
|
||||
<form style="display: inline;" action="{{route('piggybanks.modMoney',$piggybank->id)}}" method="POST">
|
||||
<input type="hidden" name="what" value="{{$what}}" />
|
||||
{{Form::token()}}
|
24
app/views/piggybanks/remove.blade.php
Normal file
24
app/views/piggybanks/remove.blade.php
Normal file
@ -0,0 +1,24 @@
|
||||
<form style="display: inline;" action="{{route('piggybanks.remove',$piggybank->id)}}" 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">Remove money from {{{$piggybank->name}}}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
The maximum amount you can remove is {{mf($piggybank->currentRelevantRep()->currentamount)}}
|
||||
</p>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">€</div>
|
||||
<input step="any" class="form-control" id="amount" autocomplete="off" name="amount" max="{{round($piggybank->currentRelevantRep()->currentamount,2)}}" 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">Remove</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user