Compare commits

...

10 Commits
3.0.0 ... 3.0.1

Author SHA1 Message Date
James Cole
2e342e47a7 Added unicity to AccountType model. Fixed some tests because of this. 2014-08-31 10:03:24 +02:00
James Cole
58b3334f05 Cleaned up some tests and moved some methods. 2014-08-31 08:59:43 +02:00
James Cole
4cd955e5cf Small text change in login. 2014-08-31 07:33:11 +02:00
James Cole
4dbf410cdf Removed codeception. 2014-08-31 07:32:59 +02:00
James Cole
074e6d52b1 Regenerated all model phpdocs. 2014-08-31 07:32:48 +02:00
James Cole
a0a36c5137 Ran model helper, added some new features. 2014-08-30 14:27:05 +02:00
James Cole
9db4137a1b Revamped the account controller. 2014-08-30 14:26:33 +02:00
James Cole
85f1e744b8 Added a new type of validation to be used for account names. 2014-08-30 14:25:52 +02:00
James Cole
8d90061d90 Included codeception for future use. 2014-08-30 14:25:21 +02:00
James Cole
b20d84e4b8 Fixed the accounts routes to be more strict about the types of accounts they accept. 2014-08-30 14:25:03 +02:00
45 changed files with 1176 additions and 1113 deletions

View File

@@ -40,6 +40,7 @@ return [
# 'Barryvdh\Debugbar\ServiceProvider', # 'Barryvdh\Debugbar\ServiceProvider',
'Firefly\Storage\StorageServiceProvider', 'Firefly\Storage\StorageServiceProvider',
'Firefly\Helper\HelperServiceProvider', 'Firefly\Helper\HelperServiceProvider',
'Firefly\Validation\ValidationServiceProvider',
'Codesleeve\AssetPipeline\AssetPipelineServiceProvider', 'Codesleeve\AssetPipeline\AssetPipelineServiceProvider',
], ],
'manifest' => storage_path() . '/meta', 'manifest' => storage_path() . '/meta',

View File

@@ -5,6 +5,8 @@ use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
/** /**
* Class AccountController * Class AccountController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/ */
class AccountController extends \BaseController class AccountController extends \BaseController
{ {
@@ -27,47 +29,30 @@ class AccountController extends \BaseController
*/ */
public function create() public function create()
{ {
return View::make('accounts.create'); return View::make('accounts.create')->with('title', 'Create account');
} }
/** /**
* @param Account $account * @param Account $account
* *
* @return \Illuminate\View\View * @return $this
*/ */
public function delete(Account $account) public function delete(Account $account)
{ {
$accountType = $account->accountType()->first(); return View::make('accounts.delete')->with('account', $account)
->with('title', 'Delete account "' . $account->name . '"');
if ($accountType->description == 'Initial balance account' || $accountType->description == 'Cash account') {
return \View::make('error')->with(
'message', 'Cannot edit this account type (' . $accountType->description . ').'
);
}
return View::make('accounts.delete')->with('account', $account);
} }
/** /**
* @param Account $account * @param Account $account
* *
* @return \Illuminate\Http\RedirectResponse * @return $this|\Illuminate\Http\RedirectResponse
*/ */
public function destroy(Account $account) public function destroy(Account $account)
{ {
$accountType = $account->accountType()->first();
if ($accountType->description == 'Initial balance account' || $accountType->description == 'Cash account') { $this->_repository->destroy($account);
return View::make('error')->with(
'message', 'Cannot edit this account type (' . $accountType->description . ').'
);
}
$result = $this->_repository->destroy($account);
if ($result === true) {
Session::flash('success', 'The account was deleted.'); Session::flash('success', 'The account was deleted.');
} else {
Session::flash('error', 'Could not delete the account.');
}
return Redirect::route('accounts.index'); return Redirect::route('accounts.index');
@@ -76,54 +61,53 @@ class AccountController extends \BaseController
/** /**
* @param Account $account * @param Account $account
* *
* @return \Illuminate\View\View * @return $this
*/ */
public function edit(Account $account) public function edit(Account $account)
{ {
$accountType = $account->accountType()->first();
if ($accountType->description == 'Initial balance account' || $accountType->description == 'Cash account') {
return View::make('error')->with(
'message', 'Cannot edit this account type (' . $accountType->description . ').'
);
}
$openingBalance = $this->_accounts->openingBalanceTransaction($account); $openingBalance = $this->_accounts->openingBalanceTransaction($account);
return View::make('accounts.edit')->with('account', $account)->with('openingBalance', $openingBalance)->with('title','Edit account "'.$account->name.'"');
return View::make('accounts.edit')->with('account', $account)->with('openingBalance', $openingBalance);
} }
/** /**
* @return \Illuminate\View\View * @return $this
*/ */
public function index() public function index()
{ {
$accounts = $this->_repository->get(); $accounts = $this->_repository->get();
$display = $this->_accounts->index($accounts); $set = [
'personal' => [],
'beneficiaries' => []
];
foreach ($accounts as $account) {
switch ($account->accounttype->type) {
case 'Default account':
$set['personal'][] = $account;
break;
case 'Beneficiary account':
$set['beneficiaries'][] = $account;
break;
}
}
return View::make('accounts.index')->with('accounts', $display); return View::make('accounts.index')->with('accounts', $set)->with('title','All your accounts');
} }
/** /**
* @param Account $account * @param Account $account
* *
* @return \Illuminate\View\View * @return $this
*/ */
public function show(Account $account) public function show(Account $account)
{ {
$accountType = $account->accountType()->first(); $data = $this->_accounts->show($account, 40);
if ($accountType->description == 'Initial balance account' || $accountType->description == 'Cash account') {
return View::make('error')->with(
'message', 'Cannot show this account type (' . $accountType->description . ').'
);
}
$show = $this->_accounts->show($account, 40); return View::make('accounts.show')->with('account', $account)->with('show', $data)->with('title',
'Details for account "' . $account->name . '"');
return View::make('accounts.show')->with('account', $account)->with('show', $show);
} }
/** /**
* @return \Illuminate\Http\RedirectResponse * @return $this|\Illuminate\Http\RedirectResponse
*/ */
public function store() public function store()
{ {
@@ -133,14 +117,14 @@ class AccountController extends \BaseController
if ($account->validate()) { if ($account->validate()) {
// saved! return to wherever. // saved! return to wherever.
Session::flash('success', 'Account "' . $account->name . '" created!'); Session::flash('success', 'Account "' . $account->name . '" created!');
if (Input::get('create') == '1') { if (intval(Input::get('create')) === 1) {
return Redirect::route('accounts.create')->withInput(); return Redirect::route('accounts.create')->withInput();
} else { } else {
return Redirect::route('accounts.index'); return Redirect::route('accounts.index');
} }
} else { } else {
// did not save, return with error: // did not save, return with error:
Session::flash('error', 'Could not save the new account. Please check the form.'); Session::flash('error', 'Could not save the new account: ' . $account->errors()->first());
return Redirect::route('accounts.create')->withErrors($account->errors())->withInput(); return Redirect::route('accounts.create')->withErrors($account->errors())->withInput();
@@ -150,16 +134,10 @@ class AccountController extends \BaseController
/** /**
* @param Account $account * @param Account $account
* *
* @return \Illuminate\Http\RedirectResponse * @return $this|\Illuminate\Http\RedirectResponse
*/ */
public function update(Account $account) public function update(Account $account)
{ {
$accountType = $account->accountType()->first();
if ($accountType->description == 'Initial balance account' || $accountType->description == 'Cash account') {
return View::make('error')->with(
'message', 'Cannot show this account type (' . $accountType->description . ').'
);
}
$account = $this->_repository->update($account, Input::all()); $account = $this->_repository->update($account, Input::all());
if ($account->validate()) { if ($account->validate()) {
Session::flash('success', 'Account "' . $account->name . '" updated.'); Session::flash('success', 'Account "' . $account->name . '" updated.');

View File

@@ -11,6 +11,16 @@ use Illuminate\Database\Schema\Blueprint;
class CreateAccountTypesTable extends Migration class CreateAccountTypesTable extends Migration
{ {
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('account_types');
}
/** /**
* Run the migrations. * Run the migrations.
* *
@@ -22,19 +32,12 @@ class CreateAccountTypesTable extends Migration
'account_types', function (Blueprint $table) { 'account_types', function (Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->timestamps(); $table->timestamps();
$table->string('description', 50); $table->string('type', 50);
$table->boolean('editable');
$table->unique('type');
} }
); );
} }
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('account_types');
}
} }

View File

@@ -11,16 +11,16 @@ class AccountTypeSeeder extends Seeder
DB::table('account_types')->delete(); DB::table('account_types')->delete();
AccountType::create( AccountType::create(
['description' => 'Default account'] ['type' => 'Default account','editable' => true]
); );
AccountType::create( AccountType::create(
['description' => 'Cash account'] ['type' => 'Cash account','editable' => false]
); );
AccountType::create( AccountType::create(
['description' => 'Initial balance account'] ['type' => 'Initial balance account','editable' => false]
); );
AccountType::create( AccountType::create(
['description' => 'Beneficiary account'] ['type' => 'Beneficiary account','editable' => true]
); );
} }

View File

@@ -1,6 +1,6 @@
<?php <?php
return array( return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@@ -87,6 +87,7 @@ return array(
'rule-name' => 'custom-message', 'rule-name' => 'custom-message',
), ),
), ),
'alphabasic' => 'The :attribute field must consist of basic alphanumeric characters.',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@@ -101,4 +102,4 @@ return array(
'attributes' => array(), 'attributes' => array(),
); ];

View File

@@ -2,7 +2,7 @@
namespace Firefly\Helper\Controllers; namespace Firefly\Helper\Controllers;
use Illuminate\Database\Eloquent\Collection; use Firefly\Exception\FireflyException;
/** /**
* Class Account * Class Account
@@ -11,43 +11,6 @@ use Illuminate\Database\Eloquent\Collection;
*/ */
class Account implements AccountInterface class Account implements AccountInterface
{ {
/**
* @param Collection $accounts
*
* @return array|mixed
*/
public function index(Collection $accounts)
{
$list = [
'personal' => [],
'beneficiaries' => [],
'initial' => [],
'cash' => []
];
foreach ($accounts as $account) {
switch ($account->accounttype->description) {
case 'Default account':
$list['personal'][] = $account;
break;
case 'Cash account':
$list['cash'][] = $account;
break;
case 'Initial balance account':
$list['initial'][] = $account;
break;
case 'Beneficiary account':
$list['beneficiaries'][] = $account;
break;
}
}
return $list;
}
/** /**
* @param \Account $account * @param \Account $account
* *
@@ -55,17 +18,12 @@ class Account implements AccountInterface
*/ */
public function openingBalanceTransaction(\Account $account) public function openingBalanceTransaction(\Account $account)
{ {
$transactionType = \TransactionType::where('type', 'Opening balance')->first();
return \TransactionJournal:: return \TransactionJournal::
with( withRelevantData()->account($account)
['transactions' => function ($q) { ->leftJoin('transaction_types', 'transaction_types.id', '=',
$q->orderBy('amount', 'ASC'); 'transaction_journals.transaction_type_id')
}] ->where('transaction_types.type', 'Opening balance')
)->where('transaction_type_id', $transactionType->id) ->first(['transaction_journals.*']);
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)->first(['transaction_journals.*']);
} }
/** /**
@@ -87,29 +45,51 @@ class Account implements AccountInterface
// build a query: // build a query:
$query = \TransactionJournal::with( $query = \TransactionJournal::withRelevantData()->defaultSorting()->account($account)->after($start)
['transactions' => function ($q) { ->before($end);
$q->orderBy('amount', 'ASC'); // filter some:
}, 'transactiontype', 'components' => function ($q) { if (\Input::get('type')) {
$q->orderBy('class'); switch (\Input::get('type')) {
}, 'transactions.account.accounttype'] case 'transactions':
)->orderBy('date', 'DESC')->leftJoin( $query->transactionTypes(['Deposit', 'Withdrawal']);
'transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id' break;
)->where('transactions.account_id', $account->id)->where('date', '>=', $start->format('Y-m-d'))->where( case 'transfers':
'date', '<=', $end->format('Y-m-d') $query->transactionTypes(['Transfer']);
)->orderBy('transaction_journals.id', 'DESC'); break;
default:
throw new FireflyException('No case for type "' . \Input::get('type') . '"!');
break;
}
}
if (\Input::get('show')) {
switch (\Input::get('show')) {
case 'expenses':
case 'out':
$query->lessThan(0);
break;
case 'income':
case 'in':
$query->moreThan(0);
break;
default:
throw new FireflyException('No case for show "' . \Input::get('show') . '"!');
break;
}
}
// build paginator: // build paginator:
$totalItems = $query->count(); $totalItems = $query->count();
$page = intval(\Input::get('page')) > 1 ? intval(\Input::get('page')) : 1; $page = max(1, intval(\Input::get('page')));
$skip = ($page - 1) * $perPage; $skip = ($page - 1) * $perPage;
$result = $query->skip($skip)->take($perPage)->get(['transaction_journals.*']); $result = $query->skip($skip)->take($perPage)->get(['transaction_journals.*']);
// in the mean time, build list of categories, budgets and other accounts:
// get the relevant budgets, categories and accounts from this list:
/** @var $item \TransactionJournal */ /** @var $item \TransactionJournal */
foreach ($result as $item) { foreach ($result as $index => $item) {
$items[] = $item;
foreach ($item->components as $component) { foreach ($item->components as $component) {
if ($component->class == 'Budget') { if ($component->class == 'Budget') {
$stats['budgets'][$component->id] = $component; $stats['budgets'][$component->id] = $component;
@@ -118,59 +98,56 @@ class Account implements AccountInterface
$stats['categories'][$component->id] = $component; $stats['categories'][$component->id] = $component;
} }
} }
// since it is entirely possible the database is messed up somehow
// it might be that a transaction journal has only one transaction.
// this is mainly caused by wrong deletions and other artefacts from the past.
// if it is the case, we remove $item and continue like nothing ever happened.
// this will however, mess up some statisics but we can live with that.
// we might be needing some cleanup routine in the future.
// for now, we simply warn the user of this.
if (count($item->transactions) < 2) {
\Session::flash('warning',
'Some transactions are incomplete; they will not be shown. Statistics may differ.');
unset($result[$index]);
continue;
}
$items[] = $item;
$fromAccount = $item->transactions[0]->account; $fromAccount = $item->transactions[0]->account;
$toAccount = $item->transactions[1]->account; $toAccount = $item->transactions[1]->account;
$stats['accounts'][$fromAccount->id] = $fromAccount; $stats['accounts'][$fromAccount->id] = $fromAccount;
$stats['accounts'][$toAccount->id] = $toAccount; $stats['accounts'][$toAccount->id] = $toAccount;
} }
unset($result, $page);
$paginator = \Paginator::make($items, $totalItems, $perPage); $paginator = \Paginator::make($items, $totalItems, $perPage);
unset($result, $page, $item, $fromAccount, $toAccount);
// statistics
$stats['period']['in'] = floatval(
\Transaction::where('account_id', $account->id)->where('amount', '>', 0)->leftJoin(
'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id'
)->leftJoin(
'transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id'
)->whereIn('transaction_types.type', ['Deposit', 'Withdrawal'])->where(
'transaction_journals.date', '>=', $start->format('Y-m-d')
)->where('transaction_journals.date', '<=', $end->format('Y-m-d'))->sum('amount')
);
$stats['period']['out'] = floatval( // statistics (transactions)
\Transaction::where('account_id', $account->id)->where('amount', '<', 0)->leftJoin( $trIn = floatval(\Transaction::before($end)->after($start)->account($account)->moreThan(0)
'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id' ->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount'));
)->leftJoin( $trOut = floatval(\Transaction::before($end)->after($start)->account($account)->lessThan(0)
'transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id' ->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount'));
)->whereIn('transaction_types.type', ['Deposit', 'Withdrawal'])->where( $trDiff = $trIn + $trOut;
'transaction_journals.date', '>=', $start->format('Y-m-d')
)->where('transaction_journals.date', '<=', $end->format('Y-m-d'))->sum('amount')
);
$stats['period']['diff'] = $stats['period']['in'] + $stats['period']['out'];
$stats['period']['t_in'] = floatval( // statistics (transfers)
\Transaction::where('account_id', $account->id)->where('amount', '>', 0)->leftJoin( $trfIn = floatval(\Transaction::before($end)->after($start)->account($account)->moreThan(0)
'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id' ->transactionTypes(['Transfer'])->sum('transactions.amount'));
)->leftJoin( $trfOut = floatval(\Transaction::before($end)->after($start)->account($account)->lessThan(0)
'transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id' ->transactionTypes(['Transfer'])->sum('transactions.amount'));
)->where('transaction_types.type', 'Transfer')->where( $trfDiff = $trfIn + $trfOut;
'transaction_journals.date', '>=', $start->format('Y-m-d')
)->where('transaction_journals.date', '<=', $end->format('Y-m-d'))->sum('amount')
);
$stats['period']['t_out'] = floatval(
\Transaction::where('account_id', $account->id)->where('amount', '<', 0)->leftJoin(
'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id'
)->leftJoin(
'transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id'
)->where('transaction_types.type', 'Transfer')->where(
'transaction_journals.date', '>=', $start->format('Y-m-d')
)->where('transaction_journals.date', '<=', $end->format('Y-m-d'))->sum('amount')
);
$stats['period']['t_diff'] = $stats['period']['t_in'] + $stats['period']['t_out']; $stats['period'] = [
'in' => $trIn,
'out' => $trOut,
'diff' => $trDiff,
't_in' => $trfIn,
't_out' => $trfOut,
't_diff' => $trfDiff
];
$return = [ $return = [
'journals' => $paginator, 'journals' => $paginator,

View File

@@ -12,15 +12,6 @@ use Illuminate\Database\Eloquent\Collection;
interface AccountInterface interface AccountInterface
{ {
/**
* Build the index:
*
* @param Collection $accounts
*
* @return mixed
*/
public function index(Collection $accounts);
/** /**
* @param \Account $account * @param \Account $account
* *

View File

@@ -36,7 +36,6 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/ */
public function createOrFind($name, \AccountType $type = null) public function createOrFind($name, \AccountType $type = null)
{ {
$account = $this->findByName($name, $type); $account = $this->findByName($name, $type);
if (!$account) { if (!$account) {
$data = [ $data = [
@@ -60,10 +59,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
if (is_null($name) || strlen($name) == 0) { if (is_null($name) || strlen($name) == 0) {
return null; return null;
} }
$type = \AccountType::where('description', 'Beneficiary account')->first(); $type = \AccountType::where('type', 'Beneficiary account')->first();
/** @noinspection PhpParamsInspection */
return $this->createOrFind($name, $type); return $this->createOrFind($name, $type);
} }
@@ -74,38 +70,29 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/ */
public function destroy(\Account $account) public function destroy(\Account $account)
{ {
// find the oldest transaction which also is a "Opening balance" // find all transaction journals related to this account:
$first = \Transaction:: $journals = \TransactionJournal::withRelevantData()->account($account)->get(['transaction_journals.*']);
leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') $accountIDs = [];
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->where('transaction_journals.user_id', \Auth::user()->id)
->where('transaction_types.type', 'Opening balance')
->where('account_id', '!=', $account->id)
->orderBy('transactions.id', 'DESC')->first(['transactions.*']);
$initialbalanceAccount = null;
if (!is_null($first)) {
$initialbalanceAccount = $first->account()->first();
}
// loop the account, find all transaction journals, and delete them:
$transactions = $account->transactions()->with('transactionjournal')->get();
$journals = [];
/** @var \Transaction $transaction */
foreach ($transactions as $transaction) {
$journals[$transaction->transaction_journal_id] = $transaction->transactionJournal;
}
/** @var \TransactionJournal $journal */ /** @var \TransactionJournal $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
// remember the account id's of the transactions involved:
foreach ($journal->transactions as $t) {
$accountIDs[] = $t->account_id;
}
$journal->delete(); $journal->delete();
}
$accountIDs = array_unique($accountIDs);
if (count($accountIDs) > 0) {
// find the "initial balance" type accounts in this list. Should be just 1.
$query = \Auth::user()->accounts()->accountTypeIn(['Initial balance account'])
->whereIn('accounts.id', $accountIDs);
if ($query->count() == 1) {
$iba = $query->first(['accounts.*']);
$iba->delete();
} }
if (!is_null($initialbalanceAccount)) {
$initialbalanceAccount->delete();
} }
$account->delete(); $account->delete();
/** /**
@@ -135,9 +122,10 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/ */
public function findByName($name, \AccountType $type = null) public function findByName($name, \AccountType $type = null)
{ {
$type = is_null($type) ? \AccountType::where('description', 'Default account')->first() : $type; $type = is_null($type) ? \AccountType::where('type', 'Default account')->first() : $type;
return \Auth::user()->accounts()->where('account_type_id', $type->id)->where('name', 'like', '%' . $name . '%') return \Auth::user()->accounts()->where('account_type_id', $type->id)
->where('name', 'like', '%' . $name . '%')
->first(); ->first();
} }
@@ -155,7 +143,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
public function getActiveDefault() public function getActiveDefault()
{ {
return \Auth::user()->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') return \Auth::user()->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.description', 'Default account')->where('accounts.active', 1) ->where('account_types.type', 'Default account')->where('accounts.active', 1)
->get(['accounts.*']); ->get(['accounts.*']);
} }
@@ -168,7 +156,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
$list = \Auth::user()->accounts()->leftJoin( $list = \Auth::user()->accounts()->leftJoin(
'account_types', 'account_types.id', '=', 'accounts.account_type_id' 'account_types', 'account_types.id', '=', 'accounts.account_type_id'
) )
->where('account_types.description', 'Default account')->where('accounts.active', 1) ->where('account_types.type', 'Default account')->where('accounts.active', 1)
->orderBy('accounts.name', 'ASC')->get(['accounts.*']); ->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$return = []; $return = [];
@@ -187,7 +175,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
$list = \Auth::user()->accounts()->leftJoin( $list = \Auth::user()->accounts()->leftJoin(
'account_types', 'account_types.id', '=', 'accounts.account_type_id' 'account_types', 'account_types.id', '=', 'accounts.account_type_id'
) )
->where('account_types.description', 'Beneficiary account')->where('accounts.active', 1) ->where('account_types.type', 'Beneficiary account')->where('accounts.active', 1)
->orderBy('accounts.name', 'ASC')->get(['accounts.*']); ->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
@@ -213,7 +201,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/ */
public function getCashAccount() public function getCashAccount()
{ {
$type = \AccountType::where('description', 'Cash account')->first(); $type = \AccountType::where('type', 'Cash account')->first();
$cash = \Auth::user()->accounts()->where('account_type_id', $type->id)->first(); $cash = \Auth::user()->accounts()->where('account_type_id', $type->id)->first();
return $cash; return $cash;
@@ -226,7 +214,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
public function getDefault() public function getDefault()
{ {
return \Auth::user()->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') return \Auth::user()->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.description', 'Default account') ->where('account_types.type', 'Default account')
->orderBy('accounts.name', 'ASC')->get(['accounts.*']); ->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
} }
@@ -239,10 +227,20 @@ class EloquentAccountRepository implements AccountRepositoryInterface
*/ */
public function store($data) public function store($data)
{ {
$defaultAccountType = \AccountType::where('description', 'Default account')->first(); /**
$accountType = isset($data['account_type']) ? $data['account_type'] : $defaultAccountType; * If the AccountType has been passed through, use it:
*/
if (isset($data['account_type']) && is_object($data['account_type'])
&& get_class($data['account_type']) == 'AccountType'
) {
$accountType = $data['account_type'];
} else {
$accountType = \AccountType::where('type', 'Default account')->first();
}
// create Account: /**
* Create new account:
*/
$account = new \Account; $account = new \Account;
$account->accountType()->associate($accountType); $account->accountType()->associate($accountType);
$account->user()->associate(\Auth::user()); $account->user()->associate(\Auth::user());
@@ -286,7 +284,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
/** @var \Firefly\Helper\Controllers\AccountInterface $interface */ /** @var \Firefly\Helper\Controllers\AccountInterface $interface */
$interface = \App::make('Firefly\Helper\Controllers\AccountInterface'); $interface = \App::make('Firefly\Helper\Controllers\AccountInterface');
if ($account->accounttype->description == 'Default account') { if ($account->accounttype->type == 'Default account') {
$journal = $interface->openingBalanceTransaction($account); $journal = $interface->openingBalanceTransaction($account);
@@ -315,7 +313,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
protected function _createInitialBalance(\Account $account, $amount = 0, Carbon $date) protected function _createInitialBalance(\Account $account, $amount = 0, Carbon $date)
{ {
// get account type: // get account type:
$initialBalanceAT = \AccountType::where('description', 'Initial balance account')->first(); $initialBalanceAT = \AccountType::where('type', 'Initial balance account')->first();
// create new account: // create new account:
$initial = new \Account; $initial = new \Account;

View File

@@ -64,8 +64,8 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
} }
// account types for both: // account types for both:
$toAT = $toAccount->accountType->description; $toAT = $toAccount->accountType->type;
$fromAT = $from->accountType->description; $fromAT = $from->accountType->type;
$journalType = null; $journalType = null;
@@ -287,6 +287,7 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
$fromAccount = $accountRepository->find(intval($data['account_id'])); $fromAccount = $accountRepository->find(intval($data['account_id']));
$toAccount = $accountRepository->createOrFindBeneficiary($data['beneficiary']); $toAccount = $accountRepository->createOrFindBeneficiary($data['beneficiary']);
break; break;
case 'deposit': case 'deposit':
$fromAccount = $accountRepository->createOrFindBeneficiary($data['beneficiary']); $fromAccount = $accountRepository->createOrFindBeneficiary($data['beneficiary']);
$toAccount = $accountRepository->find(intval($data['account_id'])); $toAccount = $accountRepository->find(intval($data['account_id']));
@@ -295,7 +296,6 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
$fromAccount = $accountRepository->find(intval($data['account_from_id'])); $fromAccount = $accountRepository->find(intval($data['account_from_id']));
$toAccount = $accountRepository->find(intval($data['account_to_id'])); $toAccount = $accountRepository->find(intval($data['account_to_id']));
break; break;
} }
// fall back to cash if necessary: // fall back to cash if necessary:

View File

@@ -0,0 +1,22 @@
<?php
namespace Firefly\Validation;
use Illuminate\Validation\Validator;
/**
* Class FireflyValidator
*
* @package Firefly\Validation
*/
class FireflyValidator extends Validator
{
public function validateAlphabasic($attribute, $value, $parameters)
{
$pattern = '/[^a-z_\-0-9 ]/i';
if (preg_match($pattern, $value)) {
return false;
} else {
return true;
}
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Firefly\Validation;
use Illuminate\Support\ServiceProvider;
class ValidationServiceProvider extends ServiceProvider
{
public function boot()
{
$this->app->validator->resolver(
function ($translator, $data, $rules, $messages) {
return new FireflyValidator($translator, $data, $rules, $messages);
}
);
}
public function register()
{
}
}

View File

@@ -1,5 +1,6 @@
<?php <?php
use LaravelBook\Ardent\Ardent as Ardent; use LaravelBook\Ardent\Ardent as Ardent;
use LaravelBook\Ardent\Builder;
/** /**
* Account * Account
@@ -22,6 +23,7 @@ use LaravelBook\Ardent\Ardent as Ardent;
* @method static \Illuminate\Database\Query\Builder|\Account whereAccountTypeId($value) * @method static \Illuminate\Database\Query\Builder|\Account whereAccountTypeId($value)
* @method static \Illuminate\Database\Query\Builder|\Account whereName($value) * @method static \Illuminate\Database\Query\Builder|\Account whereName($value)
* @method static \Illuminate\Database\Query\Builder|\Account whereActive($value) * @method static \Illuminate\Database\Query\Builder|\Account whereActive($value)
* @method static \Account accountTypeIn($types)
*/ */
class Account extends Ardent class Account extends Ardent
{ {
@@ -33,7 +35,7 @@ class Account extends Ardent
*/ */
public static $rules public static $rules
= [ = [
'name' => 'required|between:1,100', 'name' => ['required', 'between:1,100', 'alphabasic'],
'user_id' => 'required|exists:users,id', 'user_id' => 'required|exists:users,id',
'account_type_id' => 'required|exists:account_types,id', 'account_type_id' => 'required|exists:account_types,id',
'active' => 'required|boolean' 'active' => 'required|boolean'
@@ -96,7 +98,8 @@ class Account extends Ardent
public function predict( public function predict(
/** @noinspection PhpUnusedParameterInspection */ /** @noinspection PhpUnusedParameterInspection */
\Carbon\Carbon $date \Carbon\Carbon $date
) { )
{
return null; return null;
} }
@@ -110,4 +113,13 @@ class Account extends Ardent
return $this->belongsTo('User'); return $this->belongsTo('User');
} }
public function scopeAccountTypeIn(Builder $query, array $types) {
if(is_null($this->joinedAccountTypes)) {
$query->leftJoin('account_types','account_types.id','=','accounts.account_type_id');
$this->joinedAccountTypes = true;
}
$query->whereIn('account_types.type',$types);
}
} }

View File

@@ -1,21 +1,28 @@
<?php <?php
/** /**
* AccountType * AccountType
* *
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property \Carbon\Carbon $updated_at
* @property string $description * @property string $type
* @property boolean $editable
* @property-read \Illuminate\Database\Eloquent\Collection|\Account[] $accounts * @property-read \Illuminate\Database\Eloquent\Collection|\Account[] $accounts
* @method static \Illuminate\Database\Query\Builder|\AccountType whereId($value) * @method static \Illuminate\Database\Query\Builder|\AccountType whereId($value)
* @method static \Illuminate\Database\Query\Builder|\AccountType whereCreatedAt($value) * @method static \Illuminate\Database\Query\Builder|\AccountType whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\AccountType whereUpdatedAt($value) * @method static \Illuminate\Database\Query\Builder|\AccountType whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\AccountType whereDescription($value) * @method static \Illuminate\Database\Query\Builder|\AccountType whereType($value)
* @method static \Illuminate\Database\Query\Builder|\AccountType whereEditable($value)
*/ */
class AccountType extends Eloquent class AccountType extends Eloquent
{ {
public static $rules
= [
'type' => ['required', 'between:1,50', 'alphabasic'],
'editable' => 'required|boolean',
];
/** /**
* @return \Illuminate\Database\Eloquent\Relations\HasMany * @return \Illuminate\Database\Eloquent\Relations\HasMany

View File

@@ -23,6 +23,7 @@ use LaravelBook\Ardent\Ardent as Ardent;
* @property-read \Account $account * @property-read \Account $account
* @property-read \Illuminate\Database\Eloquent\Collection|\PiggybankRepetition[] $piggybankrepetitions * @property-read \Illuminate\Database\Eloquent\Collection|\PiggybankRepetition[] $piggybankrepetitions
* @property-read \Illuminate\Database\Eloquent\Collection|\PiggybankEvent[] $piggybankevents * @property-read \Illuminate\Database\Eloquent\Collection|\PiggybankEvent[] $piggybankevents
* @property-read \Illuminate\Database\Eloquent\Collection|\PiggybankReminder[] $piggybankreminders
* @property-read \Illuminate\Database\Eloquent\Collection|\Transaction[] $transactions * @property-read \Illuminate\Database\Eloquent\Collection|\Transaction[] $transactions
* @method static \Illuminate\Database\Query\Builder|\Piggybank whereId($value) * @method static \Illuminate\Database\Query\Builder|\Piggybank whereId($value)
* @method static \Illuminate\Database\Query\Builder|\Piggybank whereCreatedAt($value) * @method static \Illuminate\Database\Query\Builder|\Piggybank whereCreatedAt($value)
@@ -39,7 +40,6 @@ use LaravelBook\Ardent\Ardent as Ardent;
* @method static \Illuminate\Database\Query\Builder|\Piggybank whereReminder($value) * @method static \Illuminate\Database\Query\Builder|\Piggybank whereReminder($value)
* @method static \Illuminate\Database\Query\Builder|\Piggybank whereReminderSkip($value) * @method static \Illuminate\Database\Query\Builder|\Piggybank whereReminderSkip($value)
* @method static \Illuminate\Database\Query\Builder|\Piggybank whereOrder($value) * @method static \Illuminate\Database\Query\Builder|\Piggybank whereOrder($value)
* @property-read \Illuminate\Database\Eloquent\Collection|\PiggybankReminder[] $piggybankreminders
*/ */
class Piggybank extends Ardent class Piggybank extends Ardent
{ {

View File

@@ -2,7 +2,7 @@
use Carbon\Carbon; use Carbon\Carbon;
/** /**
* Class PiggybankReminder * PiggybankReminder
* *
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $created_at

View File

@@ -1,7 +1,6 @@
<?php <?php
use LaravelBook\Ardent\Ardent as Ardent; use LaravelBook\Ardent\Ardent as Ardent;
/** /**
* PiggybankRepetition * PiggybankRepetition
* *

View File

@@ -2,7 +2,6 @@
use LaravelBook\Ardent\Ardent; use LaravelBook\Ardent\Ardent;
/** /**
* Preference * Preference
* *

View File

@@ -18,6 +18,7 @@ use LaravelBook\Ardent\Ardent;
* @property boolean $automatch * @property boolean $automatch
* @property string $repeat_freq * @property string $repeat_freq
* @property integer $skip * @property integer $skip
* @property-read \Illuminate\Database\Eloquent\Collection|\RecurringTransactionReminder[] $reminders
* @property-read \User $user * @property-read \User $user
* @method static \Illuminate\Database\Query\Builder|\RecurringTransaction whereId($value) * @method static \Illuminate\Database\Query\Builder|\RecurringTransaction whereId($value)
* @method static \Illuminate\Database\Query\Builder|\RecurringTransaction whereCreatedAt($value) * @method static \Illuminate\Database\Query\Builder|\RecurringTransaction whereCreatedAt($value)
@@ -32,7 +33,6 @@ use LaravelBook\Ardent\Ardent;
* @method static \Illuminate\Database\Query\Builder|\RecurringTransaction whereAutomatch($value) * @method static \Illuminate\Database\Query\Builder|\RecurringTransaction whereAutomatch($value)
* @method static \Illuminate\Database\Query\Builder|\RecurringTransaction whereRepeatFreq($value) * @method static \Illuminate\Database\Query\Builder|\RecurringTransaction whereRepeatFreq($value)
* @method static \Illuminate\Database\Query\Builder|\RecurringTransaction whereSkip($value) * @method static \Illuminate\Database\Query\Builder|\RecurringTransaction whereSkip($value)
* @property-read \Illuminate\Database\Eloquent\Collection|\RecurringTransactionReminder[] $reminders
*/ */
class RecurringTransaction extends Ardent class RecurringTransaction extends Ardent
{ {

View File

@@ -1,7 +1,7 @@
<?php <?php
/** /**
* Class RecurringTransactionReminder * RecurringTransactionReminder
* *
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $created_at

View File

@@ -3,10 +3,8 @@
use Carbon\Carbon; use Carbon\Carbon;
use Firefly\Database\SingleTableInheritanceEntity; use Firefly\Database\SingleTableInheritanceEntity;
/** /**
* Class Reminder * Reminder
* // reminder for: recurring, piggybank.
* *
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $created_at

View File

@@ -1,6 +1,8 @@
<?php <?php
use Carbon\Carbon;
use LaravelBook\Ardent\Ardent; use LaravelBook\Ardent\Ardent;
use LaravelBook\Ardent\Builder;
/** /**
@@ -28,6 +30,12 @@ use LaravelBook\Ardent\Ardent;
* @method static \Illuminate\Database\Query\Builder|\Transaction whereTransactionJournalId($value) * @method static \Illuminate\Database\Query\Builder|\Transaction whereTransactionJournalId($value)
* @method static \Illuminate\Database\Query\Builder|\Transaction whereDescription($value) * @method static \Illuminate\Database\Query\Builder|\Transaction whereDescription($value)
* @method static \Illuminate\Database\Query\Builder|\Transaction whereAmount($value) * @method static \Illuminate\Database\Query\Builder|\Transaction whereAmount($value)
* @method static \Transaction account($account)
* @method static \Transaction after($date)
* @method static \Transaction before($date)
* @method static \Transaction lessThan($amount)
* @method static \Transaction moreThan($amount)
* @method static \Transaction transactionTypes($types)
*/ */
class Transaction extends Ardent class Transaction extends Ardent
{ {
@@ -81,6 +89,56 @@ class Transaction extends Ardent
return $this->belongsTo('Piggybank'); return $this->belongsTo('Piggybank');
} }
public function scopeAccount(Builder $query, Account $account)
{
$query->where('transactions.account_id', $account->id);
}
public function scopeAfter(Builder $query, Carbon $date)
{
if (is_null($this->joinedJournals)) {
$query->leftJoin('transaction_journals', 'transaction_journals.id', '=',
'transactions.transaction_journal_id');
$this->joinedJournals = true;
}
$query->where('transaction_journals.date', '>=', $date->format('Y-m-d'));
}
public function scopeBefore(Builder $query, Carbon $date)
{
if (is_null($this->joinedJournals)) {
$query->leftJoin('transaction_journals', 'transaction_journals.id', '=',
'transactions.transaction_journal_id');
$this->joinedJournals = true;
}
$query->where('transaction_journals.date', '<=', $date->format('Y-m-d'));
}
public function scopeLessThan(Builder $query, $amount)
{
$query->where('amount', '<', $amount);
}
public function scopeMoreThan(Builder $query, $amount)
{
$query->where('amount', '>', $amount);
}
public function scopeTransactionTypes(Builder $query, array $types)
{
if (is_null($this->joinedJournals)) {
$query->leftJoin('transaction_journals', 'transaction_journals.id', '=',
'transactions.transaction_journal_id');
$this->joinedJournals = true;
}
if (is_null($this->joinedTransactionTypes)) {
$query->leftJoin('transaction_types', 'transaction_types.id', '=',
'transaction_journals.transaction_type_id');
$this->joinedTransactionTypes = true;
}
$query->whereIn('transaction_types.type', $types);
}
/** /**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/ */

View File

@@ -2,20 +2,20 @@
use Carbon\Carbon; use Carbon\Carbon;
use LaravelBook\Ardent\Ardent; use LaravelBook\Ardent\Ardent;
use LaravelBook\Ardent\Builder;
/** /**
* TransactionJournal * TransactionJournal
* *
* @property integer $id * @property integer $id
* @property Carbon $created_at * @property \Carbon\Carbon $created_at
* @property Carbon $updated_at * @property \Carbon\Carbon $updated_at
* @property integer $user_id * @property integer $user_id
* @property integer $transaction_type_id * @property integer $transaction_type_id
* @property integer $transaction_currency_id * @property integer $transaction_currency_id
* @property string $description * @property string $description
* @property boolean $completed * @property boolean $completed
* @property Carbon $date * @property \Carbon\Carbon $date
* @property-read \Illuminate\Database\Eloquent\Collection|\ * @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets * 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\ * @property-read \Illuminate\Database\Eloquent\Collection|\
@@ -34,13 +34,19 @@ use LaravelBook\Ardent\Ardent;
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereDescription($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 whereCompleted($value)
* @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereDate($value) * @method static \Illuminate\Database\Query\Builder|\TransactionJournal whereDate($value)
* @method static \TransactionJournal account($account)
* @method static \TransactionJournal after($date) * @method static \TransactionJournal after($date)
* @method static \TransactionJournal before($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|\ * @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Budget[] $budgets * 'Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\ * @property-read \Illuminate\Database\Eloquent\Collection|\
* 'Category[] $categories * 'Category[] $categories
* @method static \TransactionJournal onDate($date)
*/ */
class TransactionJournal extends Ardent class TransactionJournal extends Ardent
{ {
@@ -91,6 +97,15 @@ class TransactionJournal extends Ardent
return ['created_at', 'updated_at', 'date']; return ['created_at', 'updated_at', 'date'];
} }
public function scopeAccount(Builder $query, \Account $account)
{
if (!isset($this->joinedTransactions)) {
$query->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id');
$this->joinedTransactions = true;
}
$query->where('transactions.account_id', $account->id);
}
/** /**
* @param $query * @param $query
* @param Carbon $date * @param Carbon $date
@@ -113,6 +128,33 @@ class TransactionJournal extends Ardent
return $query->where('date', '<=', $date->format('Y-m-d')); return $query->where('date', '<=', $date->format('Y-m-d'));
} }
public function scopeDefaultSorting(Builder $query)
{
$query->orderBy('date', 'DESC')->orderBy('transaction_journals.id', 'DESC');
}
public function scopeMoreThan(Builder $query, $amount)
{
if (is_null($this->joinedTransactions)) {
$query->leftJoin('transactions', 'transactions.transaction_journal_id', '=',
'transaction_journals.id');
$this->joinedTransactions = true;
}
$query->where('transactions.amount', '>=', $amount);
}
public function scopeLessThan(Builder $query, $amount)
{
if (is_null($this->joinedTransactions)) {
$query->leftJoin('transactions', 'transactions.transaction_journal_id', '=',
'transaction_journals.id');
$this->joinedTransactions = true;
}
$query->where('transactions.amount', '<=', $amount);
}
/** /**
* @param $query * @param $query
* @param Carbon $date * @param Carbon $date
@@ -124,6 +166,33 @@ class TransactionJournal extends Ardent
return $query->where('date', '=', $date->format('Y-m-d')); return $query->where('date', '=', $date->format('Y-m-d'));
} }
public function scopeTransactionTypes(Builder $query, array $types)
{
if (is_null($this->joinedTransactionTypes)) {
$query->leftJoin('transaction_types', 'transaction_types.id', '=',
'transaction_journals.transaction_type_id');
$this->joinedTransactionTypes = true;
}
$query->whereIn('transaction_types.type', $types);
}
/**
* Automatically includes the 'with' parameters to get relevant related
* objects.
*
* @param $query
*/
public function scopeWithRelevantData(Builder $query)
{
$query->with(
['transactions' => function ($q) {
$q->orderBy('amount', 'ASC');
}, 'transactiontype', 'components' => function ($q) {
$q->orderBy('class');
}, 'transactions.account.accounttype']
);
}
/** /**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/ */

View File

@@ -20,6 +20,8 @@ use LaravelBook\Ardent\Ardent;
* @property boolean $migrated * @property boolean $migrated
* @property-read \Illuminate\Database\Eloquent\Collection|\Account[] $accounts * @property-read \Illuminate\Database\Eloquent\Collection|\Account[] $accounts
* @property-read \Illuminate\Database\Eloquent\Collection|\Budget[] $budgets * @property-read \Illuminate\Database\Eloquent\Collection|\Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\Reminder[] $reminders
* @property-read \Illuminate\Database\Eloquent\Collection|\PiggybankReminder[] $piggybankreminders
* @property-read \Illuminate\Database\Eloquent\Collection|\Category[] $categories * @property-read \Illuminate\Database\Eloquent\Collection|\Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\Component[] $components * @property-read \Illuminate\Database\Eloquent\Collection|\Component[] $components
* @property-read \Illuminate\Database\Eloquent\Collection|\Preference[] $preferences * @property-read \Illuminate\Database\Eloquent\Collection|\Preference[] $preferences
@@ -33,8 +35,6 @@ use LaravelBook\Ardent\Ardent;
* @method static \Illuminate\Database\Query\Builder|\User whereReset($value) * @method static \Illuminate\Database\Query\Builder|\User whereReset($value)
* @method static \Illuminate\Database\Query\Builder|\User whereRememberToken($value) * @method static \Illuminate\Database\Query\Builder|\User whereRememberToken($value)
* @method static \Illuminate\Database\Query\Builder|\User whereMigrated($value) * @method static \Illuminate\Database\Query\Builder|\User whereMigrated($value)
* @property-read \Illuminate\Database\Eloquent\Collection|\Reminder[] $reminders
* @property-read \Illuminate\Database\Eloquent\Collection|\PiggybankReminder[] $piggybankreminders
*/ */
class User extends Ardent implements UserInterface, RemindableInterface class User extends Ardent implements UserInterface, RemindableInterface
{ {

View File

@@ -1,23 +1,33 @@
<?php <?php
//use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
// models: // models:
Route::bind('account', function($value, $route) Route::bind('account', function($value, $route)
{ {
if(Auth::check()) { if(Auth::check()) {
return Account:: $account = Account::
where('id', $value)-> leftJoin('account_types','account_types.id','=','accounts.account_type_id')->
where('user_id',Auth::user()->id)->first(); where('account_types.editable',1)->
where('accounts.id', $value)->
where('user_id',Auth::user()->id)->
first(['accounts.*']);
if($account) {
return $account;
} }
return null; }
App::abort(404);
}); });
Route::bind('accountname', function($value, $route) Route::bind('accountname', function($value, $route)
{ {
if(Auth::check()) { if(Auth::check()) {
$type = AccountType::where('description','Default account')->first();
return Account:: return Account::
leftJoin('account_types','account_types.id','=','accounts.account_type_id')->
where('account_types.editable',1)->
where('name', $value)-> where('name', $value)->
where('account_type_id',$type->id)->
where('user_id',Auth::user()->id)->first(); where('user_id',Auth::user()->id)->first();
} }
return null; return null;

View File

@@ -1,452 +0,0 @@
<?php
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class AccountControllerTest
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
* @coversDefaultClass \AccountController
*/
class AccountControllerTest extends TestCase
{
protected $_repository;
protected $_user;
protected $_accounts;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_repository = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface');
$this->_accounts = $this->mock('Firefly\Helper\Controllers\AccountInterface');
$this->_user = m::mock('User', 'Eloquent');
}
public function tearDown()
{
Mockery::close();
}
/**
* @covers ::create
*/
public function testCreate()
{
View::shouldReceive('make')->with('accounts.create')->once();
$this->action('GET', 'AccountController@create');
$this->assertResponseOk();
}
/**
* @covers ::delete
*/
public function testDelete()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'AccountController@delete', $account->id);
$this->assertViewHas('account');
$this->assertResponseOk();
}
/**
* @covers ::delete
*/
public function testDeleteWrongType()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Initial balance account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding:
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'AccountController@delete', $account->id);
$this->assertViewHas('message');
$this->assertResponseOk();
}
/**
* @covers ::destroy
*/
public function testDestroy()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding:
Auth::shouldReceive('user')->once()->andReturn($this->_user);
Auth::shouldReceive('check')->once()->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_repository->shouldReceive('destroy')->once()->andReturn(true);
$this->action('POST', 'AccountController@destroy', $account->id);
$this->assertRedirectedToRoute('accounts.index');
$this->assertSessionHas('success');
}
/**
* @covers ::destroy
*/
public function testDestroyWrongType()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Initial balance account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding:
Auth::shouldReceive('user')->once()->andReturn($this->_user);
Auth::shouldReceive('check')->once()->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->action('POST', 'AccountController@destroy', $account->id);
$this->assertViewHas('message');
$this->assertResponseOk();
}
/**
* @covers ::destroy
*/
public function testDestroyFails()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding:
Auth::shouldReceive('user')->once()->andReturn($this->_user);
Auth::shouldReceive('check')->once()->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_repository->shouldReceive('destroy')->once()->andReturn(false);
$this->action('POST', 'AccountController@destroy', $account->id);
$this->assertRedirectedToRoute('accounts.index');
$this->assertSessionHas('error');
}
public function testEdit()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->_accounts->shouldReceive('openingBalanceTransaction')->once()->andReturn(null);
// test if the view works:
View::shouldReceive('make')->with('accounts.edit')->once()->andReturn(m::self())->shouldReceive('with')->with(
'account', m::any()
)
->andReturn(m::self())->shouldReceive('with')->with('openingBalance', null)->andReturn(m::self());
$this->action('GET', 'AccountController@edit', $account->id);
$this->assertResponseOk();
}
public function testEditWrongType()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Initial balance account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
$this->action('GET', 'AccountController@edit', $account->id);
$this->assertViewHas('message');
$this->assertResponseOk();
}
public function testIndex()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
$collection = new Collection();
$collection->add($account);
$list = [
'personal' => [],
'beneficiaries' => [],
'initial' => [],
'cash' => []
];
$this->_repository->shouldReceive('get')->once()->andReturn($collection);
$this->_accounts->shouldReceive('index')->with($collection)->once()->andReturn($list);
$this->action('GET', 'AccountController@index');
$this->assertResponseOk();
}
public function testShow()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->once()->andReturn($account->email);
$this->session(['start' => new Carbon, 'end' => new Carbon]);
// some more mockery
$paginator = \Paginator::make([], 0, 10);
$data = [
'statistics' => [
'period' => [
'in' => 0,
'out' => 0,
'diff' => 0,
't_in' => 0,
't_out' => 0,
't_diff' => 0
],
'categories' => [],
'budgets' => [],
'accounts' => []
],
'journals' => $paginator,
];
$this->_accounts->shouldReceive('show')->once()->andReturn($data);
$this->action('GET', 'AccountController@show', $account->id);
$this->assertResponseOk();
}
public function testShowWrongType()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Initial balance account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn($account->email);
$this->action('GET', 'AccountController@show', $account->id);
$this->assertViewHas('message');
$this->assertResponseOk();
}
public function testStore()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
$this->_repository->shouldReceive('store')->andReturn($account);
$this->action('POST', 'AccountController@store');
$this->assertRedirectedToRoute('accounts.index');
}
public function testStoreFails()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
unset($account->name);
$this->_repository->shouldReceive('store')->andReturn($account);
$this->action('POST', 'AccountController@store');
$this->assertRedirectedToRoute('accounts.create');
}
public function testStoreRecreate()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
$this->_repository->shouldReceive('store')->andReturn($account);
$this->action('POST', 'AccountController@store', ['create' => '1']);
$this->assertRedirectedToRoute('accounts.create');
}
public function testUpdate()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_repository->shouldReceive('update')->andReturn($account);
$this->action('POST', 'AccountController@update', $account->id);
$this->assertRedirectedToRoute('accounts.index');
}
public function testUpdateWrongType()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Initial balance account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_repository->shouldReceive('update')->andReturn($account);
$this->action('POST', 'AccountController@update', $account->id);
$this->assertViewHas('message');
$this->assertResponseOk();
}
public function testUpdateFails()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = f::create('AccountType');
$accountType->description = 'Default account';
$accountType->save();
$account->accountType()->associate($accountType);
$account->save();
unset($account->name);
// for successful binding.
Auth::shouldReceive('user')->andReturn($this->_user);
Auth::shouldReceive('check')->andReturn(true);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_repository->shouldReceive('update')->andReturn($account);
$this->action('POST', 'AccountController@update', $account->id);
$this->assertRedirectedToRoute('accounts.edit', $account->id);
}
}

View File

@@ -0,0 +1,373 @@
<?php
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use League\FactoryMuffin\Facade as f;
use Mockery as m;
/**
* Class AccountTest
*
* Test EVERYTHING related to accounts. Models, views controllers.
*
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
* @coversDefaultClass \AccountController
*/
class AccountTest extends TestCase
{
protected $_repository;
protected $_user;
protected $_accounts;
public function setUp()
{
parent::setUp();
Artisan::call('migrate');
Artisan::call('db:seed');
$this->_repository = $this->mock('Firefly\Storage\Account\AccountRepositoryInterface');
$this->_accounts = $this->mock('Firefly\Helper\Controllers\AccountInterface');
$this->_user = m::mock('User', 'Eloquent');
}
public function tearDown()
{
Mockery::close();
}
public function testAccountModel()
{
// create account and user:
$account = f::create('Account');
$user = f::create('User');
$user->accounts()->save($account);
// new account? balance should be 0.00
$this->assertEquals(0.0, $account->balance());
// create and link two transactions / piggybanks:
for ($i = 0; $i < 2; $i++) {
$transaction = f::create('Transaction');
$transaction->account()->associate($account);
$transaction->save();
$piggy = f::create('Piggybank');
$piggy->account()->associate($account);
$piggy->save();
}
// test related models
$this->assertCount(2, $account->transactions()->get());
$this->assertCount(2, $account->piggybanks()->get());
// predict should always be null:
$this->assertNull($account->predict(new Carbon));
// user should equal test user:
$this->assertEquals($user->id, $account->user()->first()->id);
$this->assertEquals('testing',\App::environment());
\Log::debug('Hello from test!');
\Log::debug('Number of accounts: ' . \Account::count());
\Log::debug('Number of account types: ' . \AccountType::count());
foreach(\AccountType::get() as $t) {
\Log::debug('AccountType: #'.$t->id.', ' . $t->type);
}
// whatever the account type of this account, searching for it using the
// scope method should return one account:
$accountType = $account->accounttype()->first();
$accounts = $accountType->accounts()->count();
$this->assertCount($accounts, \Account::AccountTypeIn([$accountType->type])->get());
}
/**
* @covers ::create
*/
public function testCreate()
{
// test the view:
View::shouldReceive('make')->once()->with('accounts.create')->andReturn(m::self())
->shouldReceive('with')->once()->with('title', 'Create account');
// call and final test:
$this->action('GET', 'AccountController@create');
$this->assertResponseOk();
}
/**
* @covers ::delete
*/
public function testDelete()
{
// some prep work.
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding with the account to delete:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test the view:
View::shouldReceive('make')->once()->with('accounts.delete')->andReturn(m::self())
->shouldReceive('with')->once()->with('account', m::any())->andReturn(m::self())
->shouldReceive('with')->once()->with('title', 'Delete account "' . $account->name . '"');
// call and final test:
$this->action('GET', 'AccountController@delete', $account->id);
$this->assertResponseOk();
}
/**
* @covers ::destroy
*/
public function testDestroy()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding with the account to destroy:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test if the repository receives an argument:
$this->_repository->shouldReceive('destroy')->once();
// post it:
$this->action('POST', 'AccountController@destroy', $account->id);
$this->assertRedirectedToRoute('accounts.index');
$this->assertSessionHas('success');
}
/**
* @covers ::edit
*/
public function testEdit()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding with the account to edit:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test if the repository works:
$this->_accounts->shouldReceive('openingBalanceTransaction')->once()->with(m::any())->andReturn(null);
// test if the view works:
View::shouldReceive('make')->once()->with('accounts.edit')->andReturn(m::self())
->shouldReceive('with')->once()->with('account', m::any())->andReturn(m::self())
->shouldReceive('with')->once()->with('openingBalance', null)->andReturn(m::self())
->shouldReceive('with')->once()->with('title', 'Edit account "' . $account->name . '"');
$this->action('GET', 'AccountController@edit', $account->id);
$this->assertResponseOk();
}
/**
* @covers ::index
*/
public function testIndex()
{
// two account types:
$personalType = \AccountType::whereType('Default account')->first();
$benType = \AccountType::whereType('Beneficiary account')->first();
// create two accounts:
/** @var \Account $account */
$personal = f::create('Account');
$personal->accountType()->associate($personalType);
$personal->save();
$ben = f::create('Account');
$ben->accountType()->associate($benType);
$ben->save();
/** @var \AccountType $accountType */
$collection = new Collection();
$collection->add($personal);
$collection->add($ben);
$list = [
'personal' => [$personal],
'beneficiaries' => [$ben],
];
// test repository:
$this->_repository->shouldReceive('get')->once()->andReturn($collection);
// test view:
View::shouldReceive('make')->once()->with('accounts.index')->andReturn(m::self())
->shouldReceive('with')->once()->with('accounts', $list)->andReturn(m::self())
->shouldReceive('with')->once()->with('title', 'All your accounts');
$this->action('GET', 'AccountController@index');
$this->assertResponseOk();
}
/**
* @covers ::show
*/
public function testShow()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding with the account to show:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test view:
View::shouldReceive('make')->once()->with('accounts.show')->andReturn(m::self())
->shouldReceive('with')->once()->with('account', m::any())->andReturn(m::self())
->shouldReceive('with')->once()->with('show', [])->andReturn(m::self())
->shouldReceive('with')->once()->with('title', 'Details for account "' . $account->name . '"');
$this->_accounts->shouldReceive('show')->once()->andReturn([]);
$this->action('GET', 'AccountController@show', $account->id);
$this->assertResponseOk();
}
/**
* @covers ::store
*/
public function testStore()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
$this->_repository->shouldReceive('store')->andReturn($account);
$this->action('POST', 'AccountController@store');
$this->assertRedirectedToRoute('accounts.index');
$this->assertSessionHas('success');
}
/**
* @covers ::store
*/
public function testStoreFails()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
unset($account->name);
$this->_repository->shouldReceive('store')->andReturn($account);
$this->action('POST', 'AccountController@store');
$this->assertRedirectedToRoute('accounts.create');
$this->assertSessionHas('error');
}
public function testStoreRecreate()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
$this->_repository->shouldReceive('store')->andReturn($account);
$this->action('POST', 'AccountController@store', ['create' => '1']);
$this->assertRedirectedToRoute('accounts.create');
$this->assertSessionHas('success');
}
public function testUpdate()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
// for successful binding with the account to update:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test
$this->_repository->shouldReceive('update')->andReturn($account);
$this->action('POST', 'AccountController@update', $account->id);
$this->assertRedirectedToRoute('accounts.index');
$this->assertSessionHas('success');
}
public function testUpdateFails()
{
/** @var \Account $account */
$account = f::create('Account');
/** @var \AccountType $accountType */
$accountType = \AccountType::whereType('Default account')->first();
$account->accountType()->associate($accountType);
$account->save();
unset($account->name);
// for successful binding with the account to show:
Auth::shouldReceive('user')->andReturn($this->_user)->between(1, 3);
Auth::shouldReceive('check')->andReturn(true)->between(1, 2);
$this->_user->shouldReceive('getAttribute')->with('id')->once()->andReturn($account->user_id);
$this->_user->shouldReceive('getAttribute')->with('email')->andReturn('some@email');
// test
$this->_repository->shouldReceive('update')->andReturn($account);
$this->action('POST', 'AccountController@update', $account->id);
$this->assertRedirectedToRoute('accounts.edit', $account->id);
$this->assertSessionHas('error');
}
}

View File

@@ -77,10 +77,8 @@ class ChartControllerTest extends TestCase
public function testHomeAccountInfo() public function testHomeAccountInfo()
{ {
$account = f::create('Account'); $account = f::create('Account');
$type = f::create('AccountType'); $accountType = \AccountType::whereType('Default account')->first();
$type->description = 'Default account'; $account->accounttype()->associate($accountType);
$type->save();
$account->accounttype()->associate($type);
$account->save(); $account->save();
// for successful binding: // for successful binding:
Auth::shouldReceive('user')->andReturn($account->user()->first()); Auth::shouldReceive('user')->andReturn($account->user()->first());

View File

@@ -4,15 +4,7 @@ use League\FactoryMuffin\Facade;
Facade::define( Facade::define(
'AccountType', 'AccountType',
[ [
'description' => function () { 'type' => 'unique:word',
$types = [ 'editable' => 1
'Default account',
'Cash account',
'Initial balance account',
'Beneficiary account'
];
return $types[rand(0, 3)];
}
] ]
); );

View File

@@ -7,7 +7,7 @@ Facade::define(
[ [
'account_id' => 'factory|Account', 'account_id' => 'factory|Account',
'name' => 'string', 'name' => 'word',
'targetamount' => 'integer', 'targetamount' => 'integer',
'startdate' => function () { 'startdate' => function () {
$start = new Carbon; $start = new Carbon;

View File

@@ -119,51 +119,51 @@ class ModelTest extends TestCase
} }
/** // /**
* @expectedException \Firefly\Exception\FireflyException // * @expectedException \Firefly\Exception\FireflyException
*/ // */
public function testLimitrepetition() // public function testLimitrepetition()
{ // {
$limit = f::create('Limit'); // $limit = f::create('Limit');
$rep = f::create('LimitRepetition'); // $rep = f::create('LimitRepetition');
$budget = f::create('Budget'); // $budget = f::create('Budget');
$journal = f::create('TransactionJournal'); // $journal = f::create('TransactionJournal');
$one = f::create('Transaction'); // $one = f::create('Transaction');
$two = f::create('Transaction'); // $two = f::create('Transaction');
$one->amount = 300; // $one->amount = 300;
$two->amount = -300; // $two->amount = -300;
//
$rep->limit()->associate($limit); // $rep->limit()->associate($limit);
$limit->budget()->associate($budget); // $limit->budget()->associate($budget);
$journal->transactions()->save($one); // $journal->transactions()->save($one);
$journal->transactions()->save($two); // $journal->transactions()->save($two);
$journal->budgets()->save($budget); // $journal->budgets()->save($budget);
//
$this->assertEquals(($rep->amount - 300), $rep->left()); // $this->assertEquals(($rep->amount - 300), $rep->left());
//
// repeat frequency (not present) for periodOrder // // repeat frequency (not present) for periodOrder
$testDate = new Carbon; // $testDate = new Carbon;
$testDate->startOfMonth(); // $testDate->startOfMonth();
$rep->repeat_freq = null; // $rep->repeat_freq = null;
//
// this test will FAIL because nowadays the $rep has a random thing. // // this test will FAIL because nowadays the $rep has a random thing.
// TODO // // TODO
//
//
//$this->assertEquals($testDate->format('Ymd') . '-3', $rep->periodOrder()); // //$this->assertEquals($testDate->format('Ymd') . '-3', $rep->periodOrder());
//
// repeat frequency (present) for periodOrder // // repeat frequency (present) for periodOrder
$list = ['yearly', 'half-year', 'quarterly', 'monthly', 'weekly', 'daily']; // $list = ['yearly', 'half-year', 'quarterly', 'monthly', 'weekly', 'daily'];
foreach ($list as $index => $entry) { // foreach ($list as $index => $entry) {
$rep->repeat_freq = $entry; // $rep->repeat_freq = $entry;
$this->assertEquals($testDate->format('Ymd') . '-' . $index, $rep->periodOrder()); // $this->assertEquals($testDate->format('Ymd') . '-' . $index, $rep->periodOrder());
} // }
//
// repeat freq (invalid) for periodOrder // // repeat freq (invalid) for periodOrder
$rep->repeat_freq = 'bad'; // $rep->repeat_freq = 'bad';
$rep->periodOrder(); // $rep->periodOrder();
//
} // }
/** /**
* @expectedException \Firefly\Exception\FireflyException * @expectedException \Firefly\Exception\FireflyException

View File

@@ -10,11 +10,14 @@
Accounts are the record holders for transactions and transfers. Money moves Accounts are the record holders for transactions and transfers. Money moves
from one account to another. from one account to another.
</p> </p>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-12 col-sm-12">
<p class="text-info"> <p class="text-info">
In a double-entry bookkeeping system (such as this one) there is a "from" account and a "to" In a double-entry bookkeeping system (such as this one) there is a "from"-account and a "to"-account,
account, even when money is created from thin air (such as interest, or when new accounts already have even when money is created from thin air (such as interest, or when new accounts already have a
a positive balance). positive balance).
</p> </p>
<p class="text-info"><span class="text-danger">This form creates personal accounts only.</span> <p class="text-info"><span class="text-danger">This form creates personal accounts only.</span>

View File

@@ -33,7 +33,7 @@
</div> </div>
<div class="col-lg-6 col-md-6 col-sm-12"> <div class="col-lg-6 col-md-6 col-sm-12">
@if($account->accounttype->description == 'Default account') @if($account->accounttype->type == 'Default account')
<h4>Optional fields</h4> <h4>Optional fields</h4>
<div class="form-group"> <div class="form-group">

View File

@@ -35,22 +35,22 @@
<td>Out</td> <td>Out</td>
<td> <td>
{{mf($show['statistics']['period']['out'])}} {{mf($show['statistics']['period']['out'])}}
<a href="{{route('accounts.show',$account->id)}}#transactions-thisaccount-this-period-expensesonly"><span class="glyphicon glyphicon-circle-arrow-right"></span></a> <a href="{{route('accounts.show',$account->id)}}?type=transactions&amp;show=expenses"><span class="glyphicon glyphicon-circle-arrow-right"></span></a>
</td> </td>
<td> <td>
{{mf($show['statistics']['period']['t_out'])}} {{mf($show['statistics']['period']['t_out'])}}
<a href="#transactions-thisaccount-this-period-transfers-out-only"><span class="glyphicon glyphicon-circle-arrow-right"></span></a> <a href="{{route('accounts.show',$account->id)}}?type=transfers&amp;show=out"><span class="glyphicon glyphicon-circle-arrow-right"></span></a>
</td> </td>
</tr> </tr>
<tr> <tr>
<td>In</td> <td>In</td>
<td> <td>
{{mf($show['statistics']['period']['in'])}} {{mf($show['statistics']['period']['in'])}}
<a href="#transactions-thisaccount-this-period-incomeonly"><span class="glyphicon glyphicon-circle-arrow-right"></span></a> <a href="{{route('accounts.show',$account->id)}}?type=transactions&amp;show=income"><span class="glyphicon glyphicon-circle-arrow-right"></span></a>
</td> </td>
<td> <td>
{{mf($show['statistics']['period']['t_in'])}} {{mf($show['statistics']['period']['t_in'])}}
<a href="#transactions-thisaccount-this-period-transfers-in-only"><span class="glyphicon glyphicon-circle-arrow-right"></span></a> <a href="{{route('accounts.show',$account->id)}}?type=transfers&amp;show=in"><span class="glyphicon glyphicon-circle-arrow-right"></span></a>
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -101,7 +101,7 @@
<h4>Transactions <small> For selected account and period</small></h4> <h4>Transactions <small> For selected account and period</small></h4>
@include('paginated.transactions',['journals' => $show['journals']]) @include('paginated.transactions',['journals' => $show['journals'],'sum' => true])
</div> </div>
</div> </div>

View File

@@ -5,7 +5,11 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<base href="{{URL::route('index')}}/"> <base href="{{URL::route('index')}}/">
<title>Firefly</title> <title>Firefly
@if(isset($title))
// {{{$title}}}
@endif
</title>
<?php echo stylesheet_link_tag(); ?> <?php echo stylesheet_link_tag(); ?>
@yield('styles') @yield('styles')

View File

@@ -50,7 +50,7 @@ $r = Route::current()->getName();
<li class="dropdown"> <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Create ... <span class="caret"></span></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Create ... <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu"> <ul class="dropdown-menu" role="menu">
<li><a href="{{route('transactions.create','withdrawal')}}" title="For when you spend money"><span class="glyphicon glyphicon-arrow-left"></span> Withdrawal</a></li> <li><a href="{{route('accounts.create')}}" title="Create new account"><span class="glyphicon glyphicon-inbox"></span> Account</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>

View File

@@ -29,7 +29,7 @@
<input type="checkbox" name="remember_me" value="1"> Remember login <input type="checkbox" name="remember_me" value="1"> Remember login
</label> </label>
</div> </div>
<button type="submit" class="btn btn-info">Submit</button> <button type="submit" class="btn btn-info">Login</button>
{{Form::close()}} {{Form::close()}}
</div> </div>
</div> </div>

View File

@@ -26,12 +26,12 @@
"codesleeve/asset-pipeline": "~2.0" "codesleeve/asset-pipeline": "~2.0"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "~1.6", "barryvdh/laravel-debugbar": "@stable",
"barryvdh/laravel-ide-helper": "~1.9", "barryvdh/laravel-ide-helper": "@stable",
"mockery/mockery": "~0.9", "mockery/mockery": "@dev",
"satooshi/php-coveralls": "~0.6", "satooshi/php-coveralls": "@stable",
"league/factory-muffin": "~2.0", "league/factory-muffin": "@stable",
"doctrine/dbal": "2.4.*" "doctrine/dbal": "@stable"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [