New stuff!

This commit is contained in:
James Cole
2014-12-07 15:37:53 +01:00
parent 742479bb01
commit 6aecd77b77
31 changed files with 678 additions and 477 deletions

1
.gitignore vendored
View File

@@ -18,3 +18,4 @@ firefly-iii-import-*.json
tests/_output/* tests/_output/*
testing.sqlite testing.sqlite
c3.php c3.php
_ide_helper_models.php

View File

@@ -18,7 +18,7 @@ return [
], ],
'accountRoles' => [ 'accountRoles' => [
'default' => 'Default expense account', 'defaultExpense' => 'Default expense account',
'sharedExpense' => 'Shared expense account' 'sharedExpense' => 'Shared expense account'
], ],

View File

@@ -1,7 +1,7 @@
<?php <?php
use FireflyIII\Database\Account as AccountRepository;
use FireflyIII\Exception\FireflyException; use FireflyIII\Exception\FireflyException;
use Illuminate\Support\MessageBag;
/** /**
* Class AccountController * Class AccountController
@@ -9,11 +9,53 @@ use Illuminate\Support\MessageBag;
class AccountController extends BaseController class AccountController extends BaseController
{ {
/** @var array */
protected $_accountTypesByIdentifier
= [
'asset' => ['Default account', 'Asset account'],
'expense' => ['Expense account', 'Beneficiary account'],
'revenue' => ['Revenue account'],
];
/** @var AccountRepository */
protected $_repository;
/** @var array */
protected $_shortNamesByFullName
= [
'Default account' => 'asset',
'Asset account' => 'asset',
'Expense account' => 'expense',
'Beneficiary account' => 'expense',
'Revenue account' => 'revenue',
];
/** @var array */
protected $_subIconsByIdentifier
= [
'asset' => 'fa-money',
'Asset account' => 'fa-money',
'Default account' => 'fa-money',
'expense' => 'fa-shopping-cart',
'Expense account' => 'fa-shopping-cart',
'Beneficiary account' => 'fa-shopping-cart',
'revenue' => 'fa-download',
'Revenue account' => 'fa-download',
];
/** @var array */
protected $_subTitlesByIdentifier
= [
'asset' => 'Asset accounts',
'expense' => 'Expense accounts',
'revenue' => 'Revenue accounts',
];
/** /**
* * @param AccountRepository $repository
*/ */
public function __construct() public function __construct(AccountRepository $repository)
{ {
$this->_repository = $repository;
View::share('mainTitleIcon', 'fa-credit-card'); View::share('mainTitleIcon', 'fa-credit-card');
View::share('title', 'Accounts'); View::share('title', 'Accounts');
} }
@@ -25,17 +67,7 @@ class AccountController extends BaseController
*/ */
public function create($what) public function create($what)
{ {
switch ($what) { $subTitleIcon = $this->_subIconsByIdentifier[$what];
case 'asset':
$subTitleIcon = 'fa-money';
break;
case 'expense':
$subTitleIcon = 'fa-shopping-cart';
break;
case 'revenue':
$subTitleIcon = 'fa-download';
break;
}
$subTitle = 'Create a new ' . $what . ' account'; $subTitle = 'Create a new ' . $what . ' account';
return View::make('accounts.create', compact('subTitleIcon', 'what', 'subTitle')); return View::make('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
@@ -62,27 +94,14 @@ class AccountController extends BaseController
{ {
$type = $account->accountType->type; $type = $account->accountType->type;
$typeName = $this->_shortNamesByFullName[$type];
$name = $account->name; $name = $account->name;
/** @var \FireflyIII\Database\Account $acct */ $this->_repository->destroy($account);
$acct = App::make('FireflyIII\Database\Account');
$acct->destroy($account); Session::flash('success', 'The ' . $typeName . ' account "' . e($name) . '" was deleted.');
$return = 'asset'; return Redirect::route('accounts.index', $type);
switch ($type) {
case 'Expense account':
case 'Beneficiary account':
$return = 'expense';
break;
case 'Revenue account':
$return = 'revenue';
break;
}
Session::flash('success', 'The ' . $return . ' account "' . e($name) . '" was deleted.');
return Redirect::route('accounts.index', $return);
} }
/** /**
@@ -92,42 +111,24 @@ class AccountController extends BaseController
*/ */
public function edit(Account $account) public function edit(Account $account)
{ {
$prefilled = [];
switch ($account->accountType->type) { $openingBalance = $this->_repository->openingBalanceTransaction($account);
case 'Asset account': $subTitleIcon = $this->_subIconsByIdentifier[$account->accountType->type];
case 'Default account': $subTitle = 'Edit ' . strtolower($account->accountType->type) . ' "' . $account->name . '"';
$subTitleIcon = 'fa-money';
$prefilled['account_role'] = $account->getMeta('accountRole');
break;
case 'Expense account':
case 'Beneficiary account':
$subTitleIcon = 'fa-shopping-cart';
break;
case 'Revenue account':
$subTitleIcon = 'fa-download';
break;
}
/** @var \FireflyIII\Database\Account $acct */ // pre fill some useful values.
$acct = App::make('FireflyIII\Database\Account'); $preFilled = [
'account_role' => $account->getMeta('accountRole'),
'openingBalanceDate' => $openingBalance ? $openingBalance->date->format('Y-m-d') : null,
'openingBalance' => $openingBalance ? $openingBalance->getAmount($account) : null
];
Session::flash('preFilled', $preFilled);
$openingBalance = $acct->openingBalanceTransaction($account); return View::make('accounts.edit', compact('account', 'subTitle', 'openingBalance', 'subTitleIcon'));
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 View::make('accounts.edit', compact('account', 'openingBalance', 'subTitleIcon'))->with(
'subTitle', 'Edit ' . strtolower(
$account->accountType->type
) . ' "' . $account->name . '"'
);
} }
/** /**
*
* @param string $what * @param string $what
* *
* @return View * @return View
@@ -135,94 +136,28 @@ class AccountController extends BaseController
*/ */
public function index($what = 'default') public function index($what = 'default')
{ {
/** @var \FireflyIII\Database\Account $acct */ $subTitle = $this->_subTitlesByIdentifier[$what];
$acct = App::make('FireflyIII\Database\Account'); $subTitleIcon = $this->_subIconsByIdentifier[$what];
switch ($what) { $accounts = $this->_repository->getAccountsByType($this->_accountTypesByIdentifier[$what]);
default:
throw new FireflyException('Cannot handle account type "' . e($what) . '".');
break;
case 'asset':
$subTitleIcon = 'fa-money';
$subTitle = 'Asset accounts';
$accounts = $acct->getAssetAccounts();
break;
case 'expense':
$subTitleIcon = 'fa-shopping-cart';
$subTitle = 'Expense accounts';
$accounts = $acct->getExpenseAccounts();
break;
case 'revenue':
$subTitleIcon = 'fa-download';
$subTitle = 'Revenue accounts';
$accounts = $acct->getRevenueAccounts();
break;
}
$accounts->each(
function (Account $account) {
if (Cache::has('account.' . $account->id . '.lastActivityDate')) {
$account->lastActionDate = Cache::get('account.' . $account->id . '.lastActivityDate');
} else {
$transaction = $account->transactions()->orderBy('updated_at', 'DESC')->first();
if (is_null($transaction)) {
$account->lastActionDate = null;
Cache::forever('account.' . $account->id . '.lastActivityDate', 0);
} else {
$account->lastActionDate = $transaction->updated_at;
Cache::forever('account.' . $account->id . '.lastActivityDate', $transaction->updated_at);
}
}
}
);
return View::make('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts')); return View::make('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
} }
/** /**
* @param Account $account * @param Account $account
* @param string $view * @param string $range
* *
* @return $this * @return $this
*/ */
public function show(Account $account, $view = 'session') public function show(Account $account, $range = 'session')
{ {
switch ($account->accountType->type) { $subTitleIcon = $this->_subIconsByIdentifier[$account->accountType->type];
case 'Asset account': $what = $this->_shortNamesByFullName[$account->accountType->type];
case 'Default account': $journals = $this->_repository->getTransactionJournals($account, 50, $range);
$subTitleIcon = 'fa-money'; $subTitle = 'Details for ' . strtolower($account->accountType->type) . ' "' . $account->name . '"';
$what = 'asset';
break;
case 'Expense account':
case 'Beneficiary account':
$subTitleIcon = 'fa-shopping-cart';
$what = 'expense';
break;
case 'Revenue account':
$subTitleIcon = 'fa-download';
$what = 'revenue';
break;
}
// get a paginated view of all transactions for this account: return View::make('accounts.show', compact('account', 'what', 'range', 'subTitleIcon', 'journals', 'subTitle'));
/** @var \FireflyIII\Database\Account $acct */
$acct = App::make('FireflyIII\Database\Account');
switch ($view) {
default:
case 'session':
$journals = $acct->getTransactionJournals($account, 50);
break;
case 'all':
$journals = $acct->getAllTransactionJournals($account, 50);
break;
}
return View::make('accounts.show', compact('account', 'what', 'view', 'subTitleIcon', 'journals'))->with('account', $account)->with(
'subTitle', 'Details for ' . strtolower($account->accountType->type) . ' "' . $account->name . '"'
);
} }
/** /**
@@ -232,45 +167,36 @@ class AccountController extends BaseController
public function store() public function store()
{ {
$data = Input::all(); $data = Input::except('_token');
$data['what'] = isset($data['what']) && $data['what'] != '' ? $data['what'] : 'asset';
/** @var \FireflyIII\Database\Account $acct */
$acct = App::make('FireflyIII\Database\Account');
switch ($data['post_submit_action']) { // always validate:
default: $messages = $this->_repository->validate($data);
throw new FireflyException('Cannot handle post_submit_action "' . e($data['post_submit_action']) . '"');
break; // flash messages:
case 'return_to_edit':
case 'store':
$messages = $acct->validate($data);
/** @var MessageBag $messages ['errors'] */
if ($messages['errors']->count() > 0) {
Session::flash('warnings', $messages['warnings']); Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']); Session::flash('successes', $messages['successes']);
Session::flash('error', 'Could not save account: ' . $messages['errors']->first()); Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
return Redirect::route('accounts.create', $data['what'])->withInput()->withErrors($messages['errors']); Session::flash('error', 'Could not store account: ' . $messages['errors']->first());
} }
// store!
$acct->store($data);
Session::flash('success', 'New account stored!');
if ($data['post_submit_action'] == 'create_another') { // return to create screen:
return Redirect::route('accounts.create', $data['what']); if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
} else { return Redirect::route('accounts.create', $data['what'])->withInput();
}
// store:
$this->_repository->store($data);
Session::flash('success', 'Account "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('accounts.index', $data['what']); return Redirect::route('accounts.index', $data['what']);
} }
break; // create another.
case 'validate_only': if ($data['post_submit_action'] == 'create_another') {
$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(); return Redirect::route('accounts.create', $data['what'])->withInput();
break;
} }
return Redirect::route('accounts.index', $data['what']);
} }
/** /**
@@ -281,62 +207,38 @@ class AccountController extends BaseController
*/ */
public function update(Account $account) public function update(Account $account)
{ {
/** @var \FireflyIII\Database\Account $acct */
$acct = App::make('FireflyIII\Database\Account');
$data = Input::except('_token'); $data = Input::except('_token');
$data['what'] = $this->_shortNamesByFullName[$account->accountType->type];
switch ($account->accountType->type) { // always validate:
default: $messages = $this->_repository->validate($data);
throw new FireflyException('Cannot handle account type "' . e($account->accountType->type) . '"');
break;
case 'Default account':
case 'Asset account':
$data['what'] = 'asset';
break;
case 'Expense account':
case 'Beneficiary account':
$data['what'] = 'expense';
break;
case 'Revenue account':
$data['what'] = 'revenue';
break;
}
switch (Input::get('post_submit_action')) { // flash messages:
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('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']); Session::flash('successes', $messages['successes']);
Session::flash('error', 'Could not save account: ' . $messages['errors']->first()); Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
return Redirect::route('accounts.edit', $account->id)->withInput()->withErrors($messages['errors']); Session::flash('error', 'Could not update account: ' . $messages['errors']->first());
} }
// store!
$acct->update($account, $data);
Session::flash('success', 'Account updated!');
if ($data['post_submit_action'] == 'create_another') { // return to update screen:
return Redirect::route('accounts.edit', $account->id); if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
} else { return Redirect::route('accounts.edit', $account->id)->withInput();
}
// update
$this->_repository->update($account, $data);
Session::flash('success', 'Account "' . e($data['name']) . '" updated.');
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('accounts.index', $data['what']); return Redirect::route('accounts.index', $data['what']);
} }
case 'validate_only': // go back to update screen.
$messageBags = $acct->validate($data); if ($data['post_submit_action'] == 'return_to_edit') {
Session::flash('warnings', $messageBags['warnings']); return Redirect::route('accounts.edit', $account->id);
Session::flash('successes', $messageBags['successes']);
Session::flash('errors', $messageBags['errors']);
return Redirect::route('accounts.edit', $account->id)->withInput();
break;
}
} }
return Redirect::route('accounts.index', $data['what']);
}
} }

View File

@@ -110,7 +110,7 @@ class BudgetController extends BaseController
*/ */
public function edit(Budget $budget) public function edit(Budget $budget)
{ {
Session::flash('prefilled', ['name' => $budget->name]); Session::flash('preFilled', ['name' => $budget->name]);
return View::make('budgets.edit')->with('budget', $budget)->with('subTitle', 'Edit budget "' . $budget->name . '"'); return View::make('budgets.edit')->with('budget', $budget)->with('subTitle', 'Edit budget "' . $budget->name . '"');

View File

@@ -103,16 +103,16 @@ class PiggybankController extends BaseController
/* /*
* Flash some data to fill the form. * Flash some data to fill the form.
*/ */
$prefilled = ['name' => $piggybank->name, $preFilled = ['name' => $piggybank->name,
'account_id' => $piggybank->account_id, 'account_id' => $piggybank->account_id,
'targetamount' => $piggybank->targetamount, 'targetamount' => $piggybank->targetamount,
'targetdate' => !is_null($piggybank->targetdate) ? $piggybank->targetdate->format('Y-m-d') : null, 'targetdate' => !is_null($piggybank->targetdate) ? $piggybank->targetdate->format('Y-m-d') : null,
'reminder' => $piggybank->reminder, 'reminder' => $piggybank->reminder,
'remind_me' => intval($piggybank->remind_me) == 1 || !is_null($piggybank->reminder) ? true : false 'remind_me' => intval($piggybank->remind_me) == 1 || !is_null($piggybank->reminder) ? true : false
]; ];
Session::flash('prefilled', $prefilled); Session::flash('preFilled', $preFilled);
return View::make('piggybanks.edit', compact('piggybank', 'accounts', 'periods', 'prefilled'))->with('title', 'Piggybanks')->with( return View::make('piggybanks.edit', compact('piggybank', 'accounts', 'periods', 'preFilled'))->with('title', 'Piggybanks')->with(
'mainTitleIcon', 'fa-sort-amount-asc' 'mainTitleIcon', 'fa-sort-amount-asc'
)->with('subTitle', 'Edit piggy bank "' . e($piggybank->name) . '"')->with('subTitleIcon', 'fa-pencil'); )->with('subTitle', 'Edit piggy bank "' . e($piggybank->name) . '"')->with('subTitleIcon', 'fa-pencil');
} }

View File

@@ -33,13 +33,13 @@ class ReminderController extends BaseController
break; break;
case 'Piggybank': case 'Piggybank':
$amount = Reminders::amountForReminder($reminder); $amount = Reminders::amountForReminder($reminder);
$prefilled = [ $preFilled = [
'amount' => round($amount, 2), 'amount' => round($amount, 2),
'description' => 'Money for ' . $reminder->remindersable->name, 'description' => 'Money for ' . $reminder->remindersable->name,
'piggybank_id' => $reminder->remindersable_id, 'piggybank_id' => $reminder->remindersable_id,
'account_to_id' => $reminder->remindersable->account_id 'account_to_id' => $reminder->remindersable->account_id
]; ];
Session::flash('prefilled', $prefilled); Session::flash('preFilled', $preFilled);
return Redirect::route('transactions.create', 'transfer'); return Redirect::route('transactions.create', 'transfer');
break; break;

View File

@@ -1,11 +1,41 @@
<?php <?php
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Database\Account as AccountRepository;
use FireflyIII\Database\Report as ReportRepository;
use FireflyIII\Database\TransactionJournal as TransactionJournalRepository;
use FireflyIII\Report\ReportInterface as ReportHelper;
/** /**
* Class ReportController * Class ReportController
*/ */
class ReportController extends BaseController class ReportController extends BaseController
{ {
/** @var AccountRepository */
protected $_accounts;
/** @var TransactionJournalRepository */
protected $_journals;
/** @var ReportHelper */
protected $_reports;
/** @var ReportRepository */
protected $_repository;
/**
* @param AccountRepository $accounts
* @param TransactionJournalRepository $journals
* @param ReportHelper $reports
* @param ReportRepository $repository
*/
public function __construct(AccountRepository $accounts, TransactionJournalRepository $journals, ReportHelper $reports, ReportRepository $repository)
{
$this->_accounts = $accounts;
$this->_journals = $journals;
$this->_reports = $reports;
$this->_repository = $repository;
}
/** /**
* @param $year * @param $year
@@ -115,38 +145,13 @@ class ReportController extends BaseController
*/ */
public function index() public function index()
{ {
/** @var \FireflyIII\Database\TransactionJournal $journals */ $start = $this->_journals->firstDate();
$journals = App::make('FireflyIII\Database\TransactionJournal'); $months = $this->_reports->listOfMonths(clone $start);
/** @var TransactionJournal $journal */ $years = $this->_reports->listOfYears(clone $start);
$journal = $journals->first(); $title = 'Reports';
if (is_null($journal)) { $mainTitleIcon = 'fa-line-chart';
$date = Carbon::now();
} else {
$date = clone $journal->date;
}
$years = [];
$months = [];
while ($date <= Carbon::now()) {
$years[] = $date->format('Y');
$date->addYear();
}
// months
if (is_null($journal)) {
$date = Carbon::now();
} else {
$date = clone $journal->date;
}
while ($date <= Carbon::now()) {
$months[] = [
'formatted' => $date->format('F Y'),
'month' => intval($date->format('m')),
'year' => intval($date->format('Y')),
];
$date->addMonth();
}
return View::make('reports.index', compact('years', 'months', 'title', 'mainTitleIcon'));
return View::make('reports.index', compact('years', 'months'))->with('title', 'Reports')->with('mainTitleIcon', 'fa-line-chart');
} }
/** /**
@@ -235,40 +240,43 @@ class ReportController extends BaseController
*/ */
public function year($year) public function year($year)
{ {
Config::set('app.debug', false);
try { try {
$date = new Carbon('01-01-' . $year); new Carbon('01-01-' . $year);
} catch (Exception $e) { } catch (Exception $e) {
App::abort(500); App::abort(500);
} }
$date = new Carbon('01-01-' . $year); $date = new Carbon('01-01-' . $year);
$title = 'Reports';
$subTitle = $year;
$subTitleIcon = 'fa-bar-chart';
$mainTitleIcon = 'fa-line-chart';
/** @var \FireflyIII\Database\TransactionJournal $tj */ $balances = $this->_reports->yearBalanceReport($date);
$tj = App::make('FireflyIII\Database\TransactionJournal'); $groupedIncomes = $this->_reports->groupByRevenue($date, 'income');
$groupedExpenses = $this->_reports->groupByRevenue($date, 'expense');
/** @var \FireflyIII\Database\Account $accountRepository */
$accountRepository = App::make('FireflyIII\Database\Account');
/** @var \FireflyIII\Database\Report $reportRepository */ return View::make(
$reportRepository = App::make('FireflyIII\Database\Report'); 'reports.year', compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon')
);
/*
* For this year, get:
* - the sum of all expenses.
* - the sum of all incomes
* - per month, the sum of all expenses
* - per month, the sum of all incomes
* - 2x for shared and not-shared alike.
*
* - balance difference for all accounts.
*/
$accounts = $accountRepository->getAssetAccounts(); $accounts = $accountRepository->getAssetAccounts();
// get some sums going // get some sums going
$summary = []; $summary = [];
/** @var \Account $account */
$accounts->each(
function (\Account $account) {
if ($account->getMeta('accountRole') == 'sharedExpense') {
$account->sharedExpense = true;
} else {
$account->sharedExpense = false;
}
}
);
$end = clone $date; $end = clone $date;
$end->endOfYear(); $end->endOfYear();
while ($date < $end) { while ($date < $end) {
@@ -280,7 +288,7 @@ class ReportController extends BaseController
$expenseShared = 0; $expenseShared = 0;
foreach ($accounts as $account) { foreach ($accounts as $account) {
if ($account->sharedExpense === true) { if ($account->accountRole == 'sharedExpense') {
$incomeShared += $reportRepository->getIncomeByMonth($account, $date); $incomeShared += $reportRepository->getIncomeByMonth($account, $date);
$expenseShared += $reportRepository->getExpenseByMonth($account, $date); $expenseShared += $reportRepository->getExpenseByMonth($account, $date);
} else { } else {

View File

@@ -103,14 +103,14 @@ class TransactionController extends BaseController
/* /*
* respond to a possible given values in the URL. * respond to a possible given values in the URL.
*/ */
$prefilled = Session::has('prefilled') ? Session::get('prefilled') : []; $preFilled = Session::has('preFilled') ? Session::get('preFilled') : [];
$respondTo = ['account_id', 'account_from_id']; $respondTo = ['account_id', 'account_from_id'];
foreach ($respondTo as $r) { foreach ($respondTo as $r) {
if (!is_null(Input::get($r))) { if (!is_null(Input::get($r))) {
$prefilled[$r] = Input::get($r); $preFilled[$r] = Input::get($r);
} }
} }
Session::put('prefilled', $prefilled); Session::put('preFilled', $preFilled);
return View::make('transactions.create')->with('accounts', $assetAccounts)->with('budgets', $budgets)->with('what', $what)->with('piggies', $piggies) return View::make('transactions.create')->with('accounts', $assetAccounts)->with('budgets', $budgets)->with('what', $what)->with('piggies', $piggies)
->with('subTitle', 'Add a new ' . $what); ->with('subTitle', 'Add a new ' . $what);
@@ -244,7 +244,7 @@ class TransactionController extends BaseController
/* /*
* Data to properly display the edit form. * Data to properly display the edit form.
*/ */
$prefilled = [ $preFilled = [
'date' => $journal->date->format('Y-m-d'), 'date' => $journal->date->format('Y-m-d'),
'category' => '', 'category' => '',
'budget_id' => 0, 'budget_id' => 0,
@@ -256,7 +256,7 @@ class TransactionController extends BaseController
*/ */
$category = $journal->categories()->first(); $category = $journal->categories()->first();
if (!is_null($category)) { if (!is_null($category)) {
$prefilled['category'] = $category->name; $preFilled['category'] = $category->name;
} }
/* /*
@@ -267,33 +267,33 @@ class TransactionController extends BaseController
case 'withdrawal': case 'withdrawal':
if (floatval($journal->transactions[0]->amount) < 0) { if (floatval($journal->transactions[0]->amount) < 0) {
// transactions[0] is the asset account that paid for the withdrawal. // transactions[0] is the asset account that paid for the withdrawal.
$prefilled['account_id'] = $journal->transactions[0]->account->id; $preFilled['account_id'] = $journal->transactions[0]->account->id;
$prefilled['expense_account'] = $journal->transactions[1]->account->name; $preFilled['expense_account'] = $journal->transactions[1]->account->name;
$prefilled['amount'] = floatval($journal->transactions[1]->amount); $preFilled['amount'] = floatval($journal->transactions[1]->amount);
} else { } else {
// transactions[1] is the asset account that paid for the withdrawal. // transactions[1] is the asset account that paid for the withdrawal.
$prefilled['account_id'] = $journal->transactions[1]->account->id; $preFilled['account_id'] = $journal->transactions[1]->account->id;
$prefilled['expense_account'] = $journal->transactions[0]->account->name; $preFilled['expense_account'] = $journal->transactions[0]->account->name;
$prefilled['amount'] = floatval($journal->transactions[0]->amount); $preFilled['amount'] = floatval($journal->transactions[0]->amount);
} }
$budget = $journal->budgets()->first(); $budget = $journal->budgets()->first();
if (!is_null($budget)) { if (!is_null($budget)) {
$prefilled['budget_id'] = $budget->id; $preFilled['budget_id'] = $budget->id;
} }
break; break;
case 'deposit': case 'deposit':
if (floatval($journal->transactions[0]->amount) < 0) { if (floatval($journal->transactions[0]->amount) < 0) {
// transactions[0] contains the account the money came from. // transactions[0] contains the account the money came from.
$prefilled['account_id'] = $journal->transactions[1]->account->id; $preFilled['account_id'] = $journal->transactions[1]->account->id;
$prefilled['revenue_account'] = $journal->transactions[0]->account->name; $preFilled['revenue_account'] = $journal->transactions[0]->account->name;
$prefilled['amount'] = floatval($journal->transactions[1]->amount); $preFilled['amount'] = floatval($journal->transactions[1]->amount);
} else { } else {
// transactions[1] contains the account the money came from. // transactions[1] contains the account the money came from.
$prefilled['account_id'] = $journal->transactions[0]->account->id; $preFilled['account_id'] = $journal->transactions[0]->account->id;
$prefilled['revenue_account'] = $journal->transactions[1]->account->name; $preFilled['revenue_account'] = $journal->transactions[1]->account->name;
$prefilled['amount'] = floatval($journal->transactions[0]->amount); $preFilled['amount'] = floatval($journal->transactions[0]->amount);
} }
@@ -301,17 +301,17 @@ class TransactionController extends BaseController
case 'transfer': case 'transfer':
if (floatval($journal->transactions[0]->amount) < 0) { if (floatval($journal->transactions[0]->amount) < 0) {
// zero = from account. // zero = from account.
$prefilled['account_from_id'] = $journal->transactions[0]->account->id; $preFilled['account_from_id'] = $journal->transactions[0]->account->id;
$prefilled['account_to_id'] = $journal->transactions[1]->account->id; $preFilled['account_to_id'] = $journal->transactions[1]->account->id;
$prefilled['amount'] = floatval($journal->transactions[1]->amount); $preFilled['amount'] = floatval($journal->transactions[1]->amount);
} else { } else {
// one = from account // one = from account
$prefilled['account_from_id'] = $journal->transactions[1]->account->id; $preFilled['account_from_id'] = $journal->transactions[1]->account->id;
$prefilled['account_to_id'] = $journal->transactions[0]->account->id; $preFilled['account_to_id'] = $journal->transactions[0]->account->id;
$prefilled['amount'] = floatval($journal->transactions[0]->amount); $preFilled['amount'] = floatval($journal->transactions[0]->amount);
} }
if ($journal->piggybankevents()->count() > 0) { if ($journal->piggybankevents()->count() > 0) {
$prefilled['piggybank_id'] = $journal->piggybankevents()->first()->piggybank_id; $preFilled['piggybank_id'] = $journal->piggybankevents()->first()->piggybank_id;
} }
break; break;
} }
@@ -322,7 +322,7 @@ class TransactionController extends BaseController
return View::make('transactions.edit')->with('journal', $journal)->with('accounts', $accounts)->with( return View::make('transactions.edit')->with('journal', $journal)->with('accounts', $accounts)->with(
'what', $what 'what', $what
)->with('budgets', $budgets)->with('data', $prefilled)->with('piggies', $piggies)->with( )->with('budgets', $budgets)->with('data', $preFilled)->with('piggies', $piggies)->with(
'subTitle', 'Edit ' . $what . ' "' . $journal->description . '"' 'subTitle', 'Edit ' . $what . ' "' . $journal->description . '"'
); );
} }

View File

@@ -16,6 +16,9 @@ class DefaultUserSeeder extends Seeder
User::create( User::create(
['email' => 'acceptance@example.com', 'password' => 'acceptance', 'reset' => null, 'remember_token' => null, 'migrated' => 0] ['email' => 'acceptance@example.com', 'password' => 'acceptance', 'reset' => null, 'remember_token' => null, 'migrated' => 0]
); );
User::create(
['email' => 'functional@example.com', 'password' => 'functional', 'reset' => null, 'remember_token' => null, 'migrated' => 0]
);
} }
} }

View File

@@ -229,10 +229,10 @@ class Form
$options['placeholder'] = ucfirst($name); $options['placeholder'] = ucfirst($name);
/* /*
* Get prefilled value: * Get pre filled value:
*/ */
if (\Session::has('prefilled')) { if (\Session::has('prefilled')) {
$prefilled = \Session::get('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;
} }

View File

@@ -88,57 +88,47 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
/* /*
* Basic query: * Basic query:
*/ */
$query = $this->getUser()->accounts()->accountTypeIn($types)->withMeta(); $query = $this->getUser()->accounts()->accountTypeIn($types)->withMeta()->orderBy('name', 'ASC');;
$set = $query->get(['accounts.*']);
$set->each(
function (\Account $account) {
/* /*
* Without an opening balance, the rest of these queries will fail. * Get last activity date.
*/ */
$account->lastActivityDate = $this->getLastActivity($account);
$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.
*/
$query->where(
function ($q) {
$q->where('transaction_journals.date', '<=', Carbon::now()->format('Y-m-d'));
$q->orWhereNull('transaction_journals.date');
} }
); );
$query->groupBy('accounts.id'); return $set;
/*
* If present, process parameters for sorting:
*/
$query->orderBy('name', 'ASC');
return $query->get(['accounts.*', \DB::Raw('SUM(`transactions`.`amount`) as `balance`')]);
} }
/** /**
* Get all asset accounts. Optional JSON based parameters. * Get all asset accounts. Optional JSON based parameters.
* *
* @param array $parameters * @param array $metaFilter
* *
* @return Collection * @return Collection
*/ */
public function getAssetAccounts() public function getAssetAccounts($metaFilter = [])
{ {
$list = $this->getAccountsByType(['Default account', 'Asset account']); $list = $this->getAccountsByType(['Default account', 'Asset account']);
$list->each( $list->each(
function (\Account $account) { function (\Account $account) {
// get accountRole:
/** @var \AccountMeta $entry */ /** @var \AccountMeta $entry */
foreach ($account->accountmeta as $entry) { $accountRole = $account->accountmeta()->whereName('accountRole')->first();
if ($entry->name == 'accountRole') { if (!$accountRole) {
$account->accountRole = \Config::get('firefly.accountRoles.' . $entry->data); $accountRole = new \AccountMeta;
} $accountRole->account_id = $account->id;
} $accountRole->name = 'accountRole';
if (!isset($account->accountRole)) { $accountRole->data = 'defaultExpense';
$account->accountRole = 'Default expense account'; $accountRole->save();
} }
$account->accountRole = $accountRole->data;
} }
); );
@@ -274,7 +264,8 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
$q->where('accounts.active', 0); $q->where('accounts.active', 0);
} }
); );
})->delete(); }
)->delete();
return true; return true;
@@ -552,19 +543,49 @@ class Account implements CUD, CommonDatabaseCalls, AccountInterface
} }
public function getTransactionJournals(\Account $account, $limit = 50) /**
* @param \Account $account
*
* @return int
*/
public function getLastActivity(\Account $account)
{
$lastActivityKey = 'account.' . $account->id . '.lastActivityDate';
if (\Cache::has($lastActivityKey)) {
return \Cache::get($lastActivityKey);
}
$transaction = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->orderBy('transaction_journals.date', 'DESC')->first();
if ($transaction) {
$date = $transaction->transactionJournal->date;
} else {
$date = 0;
}
\Cache::forever($lastActivityKey, $date);
return $date;
}
public function getTransactionJournals(\Account $account, $limit = 50, $range = 'session')
{ {
$start = \Session::get('start');
$end = \Session::get('end');
$offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0; $offset = intval(\Input::get('page')) > 0 ? intval(\Input::get('page')) * $limit : 0;
$set = $this->getUser()->transactionJournals()->withRelevantData()->leftJoin(
'transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id'
)->where('transactions.account_id', $account->id)->take($limit)->offset($offset)->before($end)->after($start)->orderBy('date', 'DESC')->get(
['transaction_journals.*']
);
$count = $this->getUser()->transactionJournals()->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->before($end)->after($start)->orderBy('date', 'DESC')->where('transactions.account_id', $account->id)->count();
$items = []; $items = [];
$query = $this->getUser()
->transactionJournals()
->withRelevantData()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->orderBy('date', 'DESC');
if ($range == 'session') {
$query->before(\Session::get('end'));
$query->after(\Session::get('start'));
}
$count = $query->count();
$set = $query->take($limit)->offset($offset)->get(['transaction_journals.*']);
foreach ($set as $entry) { foreach ($set as $entry) {
$items[] = $entry; $items[] = $entry;
} }

View File

@@ -42,7 +42,7 @@ class Report implements ReportInterface
$sum = 0; $sum = 0;
// get all journals. // get all journals.
$journals = \TransactionJournal::whereIn( $journals = \TransactionJournal::with(['transactionType','transactions'])->whereIn(
'id', function ($query) use ($account, $start, $end) { 'id', function ($query) use ($account, $start, $end) {
$query->select('transaction_journal_id') $query->select('transaction_journal_id')
->from('transactions') ->from('transactions')
@@ -125,7 +125,7 @@ class Report implements ReportInterface
$sum = 0; $sum = 0;
// get all journals. // get all journals.
$journals = \TransactionJournal::whereIn( $journals = \TransactionJournal::with(['transactionType','transactions'])->whereIn(
'id', function ($query) use ($account, $start, $end) { 'id', function ($query) use ($account, $start, $end) {
$query->select('transaction_journal_id') $query->select('transaction_journal_id')
->from('transactions') ->from('transactions')

View File

@@ -486,6 +486,19 @@ class TransactionJournal implements TransactionJournalInterface, CUD, CommonData
return $this->getUser()->transactionjournals()->with('transactions')->whereIn('id', $ids)->orderBy('date', 'ASC')->get(); return $this->getUser()->transactionjournals()->with('transactions')->whereIn('id', $ids)->orderBy('date', 'ASC')->get();
} }
/**
* @return Carbon
*/
public function firstDate()
{
$journal = $this->first();
if ($journal) {
return $journal->date;
}
return Carbon::now();
}
/** /**
* @return TransactionJournal * @return TransactionJournal
*/ */

View File

@@ -87,6 +87,10 @@ class FF3ServiceProvider extends ServiceProvider
// registration and user mail: // registration and user mail:
$this->app->bind('FireflyIII\Shared\Mail\RegistrationInterface', 'FireflyIII\Shared\Mail\Registration'); $this->app->bind('FireflyIII\Shared\Mail\RegistrationInterface', 'FireflyIII\Shared\Mail\Registration');
// reports
$this->app->bind('FireflyIII\Report\ReportInterface', 'FireflyIII\Report\Report');
// Shortcut so developers don't need to add an Alias in app/config/app.php // Shortcut so developers don't need to add an Alias in app/config/app.php
$this->app->booting( $this->app->booting(
function () { function () {

View File

@@ -57,11 +57,11 @@ class Form
$options['placeholder'] = ucfirst($name); $options['placeholder'] = ucfirst($name);
/* /*
* Get prefilled value: * Get pre filled value:
*/ */
if (\Session::has('prefilled')) { if (\Session::has('preFilled')) {
$prefilled = \Session::get('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;
} }

View File

@@ -0,0 +1,125 @@
<?php
namespace FireflyIII\Report;
use Carbon\Carbon;
use FireflyIII\Database\Account as AccountRepository;
/**
* Class Report
*
* @package FireflyIII\Report
*/
class Report implements ReportInterface
{
/** @var AccountRepository */
protected $_accounts;
/**
* @param AccountRepository $accounts
*/
public function __construct(AccountRepository $accounts)
{
$this->_accounts = $accounts;
}
/**
* @param Carbon $date
* @param string $direction
*
* @return mixed
*/
public function groupByRevenue(Carbon $date, $direction = 'income')
{
$operator = $direction == 'income' ? '<' : '>';
$type = $direction == 'income' ? 'Deposit' : 'Withdrawal';
$order = $direction == 'income' ? 'ASC' : 'DESC';
$start = clone $date;
$end = clone $date;
$start->startOfYear();
$end->endOfYear();
// TODO remove shared accounts
return \TransactionJournal::
leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
->where('transaction_types.type', '=', $type)
->where('transactions.amount', $operator, 0)
->before($end)
->after($start)
->groupBy('accounts.id')
->where('transaction_journals.user_id', \Auth::user()->id)
->orderBy('sum', $order)
->take(10)
->get(['accounts.name', 'transactions.account_id', \DB::Raw('SUM(`transactions`.`amount`) as `sum`')]);
}
/**
* @param Carbon $start
*
* @return array
*/
public function listOfMonths(Carbon $start)
{
$end = Carbon::now();
$months = [];
while ($start <= $end) {
$months[] = [
'formatted' => $start->format('F Y'),
'month' => intval($start->format('m')),
'year' => intval($start->format('Y')),
];
$start->addMonth();
}
return $months;
}
/**
* @param Carbon $start
*
* @return array
*/
public function listOfYears(Carbon $start)
{
$end = Carbon::now();
$years = [];
while ($start <= $end) {
$years[] = $start->format('Y');
$start->addYear();
}
return $years;
}
/**
* @param Carbon $date
*
* @return array
*/
public function yearBalanceReport(Carbon $date)
{
$start = clone $date;
$end = clone $date;
// TODO filter accounts, no shared accounts.
$accounts = $this->_accounts->getAssetAccounts();
$report = [];
$start->startOfYear();
$end->endOfYear();
foreach ($accounts as $account) {
$report[] = [
'start' => \Steam::balance($account, $start),
'end' => \Steam::balance($account, $end),
'account' => $account,
'shared' => $account->accountRole == 'sharedExpense'
];
}
return $report;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace FireflyIII\Report;
use Carbon\Carbon;
/**
* Interface ReportInterface
*
* @package FireflyIII\Report
*/
interface ReportInterface
{
/**
* @param Carbon $date
* @param string $direction
*
* @return mixed
*/
public function groupByRevenue(Carbon $date, $direction = 'income');
/**
* @param Carbon $start
*
* @return array
*/
public function listOfMonths(Carbon $start);
/**
* @param Carbon $start
*
* @return array
*/
public function listOfYears(Carbon $start);
/**
* @param Carbon $date
*
* @return array
*/
public function yearBalanceReport(Carbon $date);
}

View File

@@ -23,13 +23,13 @@ class Steam
*/ */
public function balance(\Account $account, Carbon $date = null) public function balance(\Account $account, Carbon $date = null)
{ {
$latest = false;
if (is_null($date)) { if (is_null($date)) {
$latest = true; $key = 'account.' . $account->id . '.latestBalance';
if (\Cache::has('account.' . $account->id . '.latestBalance')) { } else {
$key = 'account.' . $account->id . '.balanceOn' . $date->format('dmy');
return \Cache::get('account.' . $account->id . '.latestBalance');
} }
if (\Cache::has($key)) {
return \Cache::get($key);
} }
$date = is_null($date) ? Carbon::now() : $date; $date = is_null($date) ? Carbon::now() : $date;
$balance = floatval( $balance = floatval(
@@ -37,9 +37,7 @@ class Steam
'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id' 'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id'
)->where('transaction_journals.date', '<=', $date->format('Y-m-d'))->sum('transactions.amount') )->where('transaction_journals.date', '<=', $date->format('Y-m-d'))->sum('transactions.amount')
); );
if ($latest === true) { \Cache::put($key, $balance, 20160);
\Cache::forever('account.' . $account->id . '.latestBalance', $balance);
}
return $balance; return $balance;
} }

View File

@@ -49,10 +49,13 @@ class TransactionJournal extends Eloquent
* *
* @return float * @return float
*/ */
public function getAmount() public function getAmount(\Account $account = null)
{ {
foreach ($this->transactions as $t) { foreach ($this->transactions as $t) {
if (!is_null($account) && $account->id == $t->account_id) {
return floatval($t->amount);
}
if (floatval($t->amount) > 0) { if (floatval($t->amount) > 0) {
return floatval($t->amount); return floatval($t->amount);
} }

View File

@@ -327,7 +327,6 @@ Route::group(
// user controller // user controller
Route::get('/login', ['uses' => 'UserController@login', 'as' => 'login']); Route::get('/login', ['uses' => 'UserController@login', 'as' => 'login']);
Route::get('/register', ['uses' => 'UserController@register', 'as' => 'register']); Route::get('/register', ['uses' => 'UserController@register', 'as' => 'register']);
Route::get('/verify/{verification}', ['uses' => 'UserController@verify', 'as' => 'verify']);
Route::get('/reset/{reset}', ['uses' => 'UserController@reset', 'as' => 'reset']); Route::get('/reset/{reset}', ['uses' => 'UserController@reset', 'as' => 'reset']);
Route::get('/remindme', ['uses' => 'UserController@remindme', 'as' => 'remindme']); Route::get('/remindme', ['uses' => 'UserController@remindme', 'as' => 'remindme']);
@@ -340,8 +339,8 @@ Route::group(
['before' => 'csrf|guest'], function () { ['before' => 'csrf|guest'], function () {
// user controller // user controller
Route::post('/login', ['uses' => 'UserController@postLogin']); Route::post('/login', ['uses' => 'UserController@postLogin','as' => 'login.post']);
Route::post('/register', ['uses' => 'UserController@postRegister']); Route::post('/register', ['uses' => 'UserController@postRegister','as' => 'register.post']);
Route::post('/remindme', ['uses' => 'UserController@postRemindme']); Route::post('/remindme', ['uses' => 'UserController@postRemindme','as' => 'remindme.post']);
} }
); );

View File

@@ -26,8 +26,8 @@
<div class="panel-body"> <div class="panel-body">
{{Form::ffCheckbox('active','1')}} {{Form::ffCheckbox('active','1')}}
@if($account->accounttype->type == 'Default account' || $account->accounttype->type == 'Asset account') @if($account->accounttype->type == 'Default account' || $account->accounttype->type == 'Asset account')
{{Form::ffBalance('openingbalance')}} {{Form::ffBalance('openingBalance')}}
{{Form::ffDate('openingbalancedate')}} {{Form::ffDate('openingBalanceDate')}}
{{Form::ffSelect('account_role',Config::get('firefly.accountRoles'))}} {{Form::ffSelect('account_role',Config::get('firefly.accountRoles'))}}
@endif @endif
</div> </div>

View File

@@ -21,7 +21,7 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p> <p>
@if($view == 'all') @if($range == 'all')
<a href="{{route('accounts.show',$account->id)}}/session" class="btn btn-default">Stick to date-range</a> <a href="{{route('accounts.show',$account->id)}}/session" class="btn btn-default">Stick to date-range</a>
@else @else
<a href="{{route('accounts.show',$account->id)}}/all" class="btn btn-default">Show all transactions</a> <a href="{{route('accounts.show',$account->id)}}/all" class="btn btn-default">Show all transactions</a>
@@ -74,7 +74,7 @@
@section('scripts') @section('scripts')
<script type="text/javascript"> <script type="text/javascript">
var accountID = {{{$account->id}}}; var accountID = {{{$account->id}}};
var view = '{{{$view}}}'; var view = '{{{$range}}}';
</script> </script>
<!-- load the libraries and scripts necessary for Google Charts: --> <!-- load the libraries and scripts necessary for Google Charts: -->
<script type="text/javascript" src="https://www.google.com/jsapi"></script> <script type="text/javascript" src="https://www.google.com/jsapi"></script>

View File

@@ -26,8 +26,8 @@
@endif @endif
</td> </td>
<td> <td>
@if($account->lastActionDate) @if($account->lastActivityDate)
{{{$account->lastActionDate->format('j F Y')}}} {{{$account->lastActivityDate->format('j F Y')}}}
@else @else
<em>Never</em> <em>Never</em>
@endif @endif

View File

@@ -30,8 +30,8 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
{{Form::ffDate('targetdate')}} {{Form::ffDate('targetdate')}}
{{Form::ffCheckbox('remind_me','1',$prefilled['remind_me'],['label' => 'Remind me'])}} {{Form::ffCheckbox('remind_me','1',$preFilled['remind_me'],['label' => 'Remind me'])}}
{{Form::ffSelect('reminder',$periods,$prefilled['reminder'],['label' => 'Remind every'])}} {{Form::ffSelect('reminder',$periods,$preFilled['reminder'],['label' => 'Remind every'])}}
</div> </div>
</div> </div>

View File

@@ -25,84 +25,71 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-lg-12 col-md-12 col-sm-12"> <div class="col-lg-6 col-md-6 col-sm-6">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
Summary (without shared accounts) Account balance
</div> </div>
<table class="table table-striped"> <table class="table">
<?php
$start = 0;
$end = 0;
$diff = 0;
?>
@foreach($balances as $balance)
<?php
$start += $balance['start'];
$end += $balance['end'];
$diff += ($balance['end']-$balance['start']);
?>
<tr> <tr>
<td></td> <td>
@foreach($summary as $entry) <a href="{{route('accounts.show',$balance['account']->id)}}">{{{$balance['account']->name}}}</a>
<th>{{$entry['month']}}</th> @if($balance['shared'])
@endforeach <small><em>shared</em></small>
<th>Sum</th> @endif
</td>
<td>{{mf($balance['start'])}}</td>
<td>{{mf($balance['end'])}}</td>
<td>{{mf($balance['end']-$balance['start'])}}</td>
</tr> </tr>
@endforeach
<tr> <tr>
<th>In</th> <td><em>Sum of sums</em></td>
<?php $inSum = 0;?> <td>{{mf($start)}}</td>
@foreach($summary as $entry) <td>{{mf($end)}}</td>
<td>{{mf($entry['income'])}}</td> <td>{{mf($diff)}}</td>
<?php $inSum+=$entry['income'];?>
@endforeach
<td>{{mf($inSum)}}</td>
</tr>
<th>Out</th>
<?php $outSum = 0;?>
@foreach($summary as $entry)
<td>{{mf($entry['expense']*-1)}}</td>
<?php $outSum+=$entry['expense']*-1;?>
@endforeach
<td>{{mf($outSum)}}</td>
<tr>
<th>Difference</th>
@foreach($summary as $entry)
<td>{{mf($entry['income']- $entry['expense'])}}</td>
@endforeach
<td>{{mf($inSum + $outSum)}}</td>
</tr> </tr>
</table> </table>
</div> </div>
</div> </div>
</div> <div class="col-lg-3 col-md-3 col-sm-3">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
Summary (shared accounts only) Income
</div> </div>
<table class="table table-striped"> <table class="table">
@foreach($groupedIncomes as $income)
<tr> <tr>
<td></td> <td><a href="{{route('accounts.show',$income->account_id)}}">{{{$income->name}}}</a></td>
@foreach($summary as $entry) <td>{{mf(floatval($income->sum)*-1)}}</td>
<th>{{$entry['month']}}</th>
@endforeach
<th>Sum</th>
</tr> </tr>
@endforeach
</table>
</div>
</div>
<div class="col-lg-3 col-md-3 col-sm-3">
<div class="panel panel-default">
<div class="panel-heading">
Expenses
</div>
<table class="table">
@foreach($groupedExpenses as $expense)
<tr> <tr>
<th>In</th> <td><a href="{{route('accounts.show',$expense->account_id)}}">{{{$expense->name}}}</a></td>
<?php $inSum = 0;?> <td>{{mf(floatval($expense->sum)*-1)}}</td>
@foreach($summary as $entry)
<td>{{mf($entry['incomeShared'])}}</td>
<?php $inSum+=$entry['incomeShared'];?>
@endforeach
<td>{{mf($inSum)}}</td>
</tr> </tr>
<th>Out</th>
<?php $outSum = 0;?>
@foreach($summary as $entry)
<td>{{mf($entry['expenseShared']*-1)}}</td>
<?php $outSum+=$entry['expenseShared']*-1;?>
@endforeach @endforeach
<td>{{mf($outSum)}}</td>
<tr>
<th>Difference</th>
@foreach($summary as $entry)
<td>{{mf($entry['incomeShared']- $entry['expenseShared'])}}</td>
@endforeach
<td>{{mf($inSum + $outSum)}}</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
@@ -115,7 +102,7 @@
Budgets Budgets
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div id="budgets"></div> <!-- <div id="budgets"></div> -->
</div> </div>
</div> </div>
</div> </div>

View File

@@ -10,7 +10,7 @@
{{Form::open()}} {{Form::open(['id' => 'login'])}}
<div class="form-group"> <div class="form-group">
<input type="email" class="form-control" id="inputEmail" name="email" placeholder="E-mail"> <input type="email" class="form-control" id="inputEmail" name="email" placeholder="E-mail">
</div> </div>

View File

@@ -13,3 +13,4 @@ modules:
cleanup: false cleanup: false
Laravel4: Laravel4:
environment: 'testing' environment: 'testing'
filters: false

View File

@@ -1,4 +1,4 @@
<?php //[STAMP] 783e39b9effa232e3a9a3fc0349ec983 <?php //[STAMP] defdb4be0e39e8a2ea8d92c0ff514877
// This class was automatically generated by build task // This class was automatically generated by build task
// You should not change it manually as it will be overwritten on next build // You should not change it manually as it will be overwritten on next build

View File

@@ -1,3 +0,0 @@
<?php
$I = new FunctionalTester($scenario);
$I->wantTo('perform actions and see result');

View File

@@ -1,7 +0,0 @@
<?php
$I = new FunctionalTester($scenario);
$I->wantTo('register a new account');
$I->amOnPage('/register');
$I->submitForm('#register', ['email' => 'noreply@gmail.com']);
$I->see('Password sent!');
$I->seeRecord('users', ['email' => 'noreply@gmail.com']);

View File

@@ -0,0 +1,104 @@
<?php
class UserControllerCest
{
/**
* @param FunctionalTester $I
*/
public function _after(FunctionalTester $I)
{
}
/**
* @param FunctionalTester $I
*/
public function _before(FunctionalTester $I)
{
}
/**
* @param FunctionalTester $I
*/
public function login(FunctionalTester $I)
{
$I->wantTo('login');
$I->amOnPage('/login');
$I->see('Sign In');
$I->submitForm('#login', ['email' => 'functional@example.com','password' => 'functional']);
$I->see('functional@example.com');
}
/**
* @param FunctionalTester $I
*/
public function logout(FunctionalTester $I)
{
$I->wantTo('logout');
#$I->amOnPage('/logout');
#$I->am
}
/**
* @param FunctionalTester $I
*/
public function postLogin(FunctionalTester $I)
{
$I->wantTo('post login');
$I->amOnRoute('login');
}
/**
* @param FunctionalTester $I
*/
public function postRegister(FunctionalTester $I)
{
// @codingStandardsIgnoreStart
$I->wantTo('post-register a new account');
$I->amOnPage('/register');
$token = $I->grabValueFrom('input[name=_token]');
$I->submitForm('#register', ['email' => 'noreply@gmail.com','_token' => $token]);
$I->see('Password sent!');
$I->seeRecord('users', ['email' => 'noreply@gmail.com']);
// @codingStandardsIgnoreEnd
}
/**
* @param FunctionalTester $I
*/
public function postRemindme(FunctionalTester $I)
{
$I->wantTo('get a password reminder');
$I->amOnRoute('remindme');
}
/**
* @param FunctionalTester $I
*/
public function register(FunctionalTester $I)
{
$I->wantTo('register a new account');
$I->amOnRoute('register');
}
/**
* @param FunctionalTester $I
*/
public function remindme(FunctionalTester $I)
{
$I->wantTo('reminded of my password');
$I->amOnRoute('remindme');
}
/**
* @param FunctionalTester $I
*/
public function reset(FunctionalTester $I)
{
$I->wantTo('reset my password');
$I->amOnRoute('reset');
}
}