Fixed validation and made some new form elements.

This commit is contained in:
Sander Dorigo
2014-10-05 08:27:18 +02:00
parent 4ce978b9f3
commit b3209d3b4d
9 changed files with 528 additions and 280 deletions

View File

@@ -0,0 +1,202 @@
<?php
namespace Firefly\Form;
use Firefly\Exception\FireflyException;
use Illuminate\Support\MessageBag;
class Form
{
/**
* @param $name
* @param null $value
* @param array $options
* @return string
* @throws FireflyException
*/
public static function ffAmount($name, $value = null, array $options = [])
{
$options['step'] = 'any';
$options['min'] = '0.01';
return self::ffInput('number', $name, $value, $options);
}
public static function ffDate($name, $value = null, array $options = [])
{
return self::ffInput('date', $name, $value, $options);
}
/**
* @param $name
* @param array $list
* @param null $selected
* @param array $options
* @return string
* @throws FireflyException
*/
public static function ffSelect($name, array $list = [], $selected = null, array $options = [])
{
return self::ffInput('select', $name, $selected, $options, $list);
}
/**
* @param $name
* @param null $value
* @param array $options
* @return string
* @throws FireflyException
*/
public static function ffText($name, $value = null, array $options = array())
{
return self::ffInput('text', $name, $value, $options);
}
/**
* @param $type
* @param $name
* @param null $value
* @param array $options
* @param array $list
* @return string
* @throws FireflyException
*/
public static function ffInput($type, $name, $value = null, array $options = array(), $list = [])
{
/*
* add some defaults to this method:
*/
$options['class'] = 'form-control';
$options['id'] = 'ffInput_' . $name;
$options['autocomplete'] = 'off';
$options['type'] = 'text';
/*
* Make label and placeholder look nice.
*/
$options['placeholder'] = isset($options['label']) ? $options['label'] : ucfirst($name);
$options['label'] = isset($options['label']) ? $options['label'] : ucfirst($name);
if ($name == 'account_id') {
$options['label'] = 'Asset account';
}
$options['label'] = str_replace(['_'], [' '], $options['label']);
$options['placeholder'] = str_replace(['_'], [' '], $options['placeholder']);
/*
* Get the value.
*/
if (!is_null(\Input::old($name))) {
/*
* Old value overrules $value.
*/
$value = \Input::old($name);
}
/*
* Get errors, warnings and successes from session:
*/
/** @var MessageBag $errors */
$errors = \Session::get('errors');
/** @var MessageBag $warnings */
$warnings = \Session::get('warnings');
/** @var MessageBag $successes */
$successes = \Session::get('successes');
/*
* If errors, add some more classes.
*/
switch (true) {
case (!is_null($errors) && $errors->has($name)):
$classes = 'form-group has-error has-feedback';
break;
case (!is_null($warnings) && $warnings->has($name)):
$classes = 'form-group has-warning has-feedback';
break;
case (!is_null($successes) && $successes->has($name)):
$classes = 'form-group has-success has-feedback';
break;
default:
$classes = 'form-group';
break;
}
/*
* Add some HTML.
*/
$label = isset($options['label']) ? $options['label'] : ucfirst($name);
$html = '<div class="' . $classes . '">';
$html .= '<label for="' . $options['id'] . '" class="col-sm-4 control-label">' . $label . '</label>';
$html .= '<div class="col-sm-8">';
/*
* Switch input type:
*/
switch ($type) {
case 'text':
$html .= \Form::input('text', $name, $value, $options);
break;
case 'number':
$html .= '<div class="input-group"><div class="input-group-addon">&euro;</div>';
$html .= \Form::input('number', $name, $value, $options);
$html .= '</div>';
break;
case 'date':
$html .= \Form::input('date', $name, $value, $options);
break;
case 'select':
$html .= \Form::select($name, $list, $value, $options);
break;
default:
throw new FireflyException('Cannot handle type "' . $type . '" in FFFormBuilder.');
break;
}
/*
* If errors, respond to them:
*/
if (!is_null($errors)) {
if ($errors->has($name)) {
$html .= '<span class="glyphicon glyphicon-remove form-control-feedback"></span>';
$html .= '<p class="text-danger">' . e($errors->first($name)) . '</p>';
}
}
unset($errors);
/*
* If warnings, respond to them:
*/
if (!is_null($warnings)) {
if ($warnings->has($name)) {
$html .= '<span class="glyphicon glyphicon-warning-sign form-control-feedback"></span>';
$html .= '<p class="text-warning">' . e($warnings->first($name)) . '</p>';
}
}
unset($warnings);
/*
* If successes, respond to them:
*/
if (!is_null($successes)) {
if ($successes->has($name)) {
$html .= '<span class="glyphicon glyphicon-ok form-control-feedback"></span>';
$html .= '<p class="text-success">' . e($successes->first($name)) . '</p>';
}
}
unset($successes);
$html .= '</div>';
$html .= '</div>';
return $html;
}
}

View File

@@ -2,6 +2,9 @@
namespace Firefly\Helper\Controllers;
use Carbon\Carbon;
use Exception;
use Firefly\Exception\FireflyException;
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
use Firefly\Storage\Budget\BudgetRepositoryInterface as BRI;
use Firefly\Storage\Category\CategoryRepositoryInterface as CRI;
@@ -36,18 +39,18 @@ class Transaction implements TransactionInterface
/**
* @param TJRI $journals
* @param CRI $categories
* @param BRI $budgets
* @param PRI $piggybanks
* @param ARI $accounts
* @param CRI $categories
* @param BRI $budgets
* @param PRI $piggybanks
* @param ARI $accounts
*/
public function __construct(TJRI $journals, CRI $categories, BRI $budgets, PRI $piggybanks, ARI $accounts)
{
$this->_journals = $journals;
$this->_journals = $journals;
$this->_categories = $categories;
$this->_budgets = $budgets;
$this->_budgets = $budgets;
$this->_piggybanks = $piggybanks;
$this->_accounts = $accounts;
$this->_accounts = $accounts;
$this->overruleUser(\Auth::user());
}
@@ -69,7 +72,7 @@ class Transaction implements TransactionInterface
/**
* @param \TransactionJournal $journal
* @param array $data
* @param array $data
*
* @return MessageBag|\TransactionJournal
*/
@@ -120,7 +123,7 @@ class Transaction implements TransactionInterface
}
if (isset($data['revenue_account'])) {
$from = $this->_accounts->findRevenueAccountByName($data['revenue_account']);
$to = $this->_accounts->findAssetAccountById($data['account_id']);
$to = $this->_accounts->findAssetAccountById($data['account_id']);
}
if (isset($data['account_from_id'])) {
$from = $this->_accounts->findAssetAccountById($data['account_from_id']);
@@ -168,7 +171,7 @@ class Transaction implements TransactionInterface
* Connect budget and category:
*/
$budgetids = !isset($budget) || (isset($budget) && is_null($budget)) ? [] : [$budget->id];
$catids = is_null($category) ? [] : [$category->id];
$catids = is_null($category) ? [] : [$category->id];
$journal->budgets()->sync($budgetids);
$journal->categories()->sync($catids);
$journal->save();
@@ -179,6 +182,186 @@ class Transaction implements TransactionInterface
}
/**
* Returns messages about the validation.
*
* @param array $data
* @return array
* @throws FireflyException
*/
public function validate(array $data)
{
$errors = new MessageBag;
$warnings = new MessageBag;
$successes = new MessageBag;
/*
* Description:
*/
if (strlen($data['description']) == 0) {
$errors->add('description', 'The description should not be this short.');
}
if (strlen($data['description']) > 250) {
$errors->add('description', 'The description should not be this long.');
}
/*
* Amount
*/
if (floatval($data['amount']) <= 0) {
$errors->add('amount', 'The amount cannot be zero or less than zero.');
}
if (floatval($data['amount']) > 10000) {
$warnings->add('amount', 'OK, but that\'s a lot of money dude.');
}
/*
* Date
*/
try {
$date = new Carbon($data['date']);
} catch (Exception $e) {
$errors->add('date', 'The date entered was invalid');
}
if (strlen($data['date']) == 0) {
$errors->add('date', 'The date entered was invalid');
}
if (!$errors->has('date')) {
$successes->add('date', 'OK!');
}
/*
* Category
*/
$category = $this->_categories->findByName($data['category']);
if (strlen($data['category']) == 0) {
$warnings->add('category', 'No category will be created.');
} else {
if (is_null($category)) {
$warnings->add('category', 'Will have to be created.');
} else {
$successes->add('category', 'OK!');
}
}
switch ($data['what']) {
default:
throw new FireflyException('Cannot validate a ' . $data['what']);
break;
case 'deposit':
/*
* Tests for deposit
*/
// asset account
$accountId = isset($data['account_id']) ? intval($data['account_id']) : 0;
$account = $this->_accounts->find($accountId);
if (is_null($account)) {
$errors->add('account_id', 'Cannot find this asset account.');
} else {
$successes->add('account_id', 'OK!');
}
// revenue account:
if (strlen($data['revenue_account']) == 0) {
$warnings->add('revenue_account', 'Revenue account will be "cash".');
} else {
$exp = $this->_accounts->findRevenueAccountByName($data['revenue_account'], false);
if (is_null($exp)) {
$warnings->add('revenue_account', 'Expense account will be created.');
} else {
$successes->add('revenue_account', 'OK!');
}
}
break;
case 'transfer':
// account from
$accountId = isset($data['account_from_id']) ? intval($data['account_from_id']) : 0;
$account = $this->_accounts->find($accountId);
if (is_null($account)) {
$errors->add('account_from_id', 'Cannot find this asset account.');
} else {
$successes->add('account_from_id', 'OK!');
}
unset($accountId);
// account to
$accountId = isset($data['account_to_id']) ? intval($data['account_to_id']) : 0;
$account = $this->_accounts->find($accountId);
if (is_null($account)) {
$errors->add('account_to_id', 'Cannot find this asset account.');
} else {
$successes->add('account_to_id', 'OK!');
}
unset($accountId);
// piggy bank
$piggybankId = isset($data['piggybank_id']) ? intval($data['piggybank_id']) : 0;
$piggybank = $this->_piggybanks->find($piggybankId);
if (is_null($piggybank)) {
$warnings->add('piggybank_id', 'No piggy bank will be modified.');
} else {
$successes->add('piggybank_id', 'OK!');
}
break;
case 'withdrawal':
/*
* Tests for withdrawal
*/
// asset account
$accountId = isset($data['account_id']) ? intval($data['account_id']) : 0;
$account = $this->_accounts->find($accountId);
if (is_null($account)) {
$errors->add('account_id', 'Cannot find this asset account.');
} else {
$successes->add('account_id', 'OK!');
}
// expense account
if (strlen($data['expense_account']) == 0) {
$warnings->add('expense_account', 'Expense account will be "cash".');
} else {
$exp = $this->_accounts->findExpenseAccountByName($data['expense_account'], false);
if (is_null($exp)) {
$warnings->add('expense_account', 'Expense account will be created.');
} else {
$successes->add('expense_account', 'OK!');
}
}
// budget
if (!isset($data['budget_id']) || (isset($data['budget_id']) && intval($data['budget_id']) == 0)) {
$warnings->add('budget_id', 'No budget selected.');
} else {
$budget = $this->_budgets->find(intval($data['budget_id']));
if (is_null($budget)) {
$errors->add('budget_id', 'This budget does not exist');
} else {
$successes->add('budget_id', 'OK!');
}
}
break;
}
if (count($errors->get('description')) == 0) {
$successes->add('description', 'OK!');
}
if (count($errors->get('amount')) == 0) {
$successes->add('amount', 'OK!');
}
return ['errors' => $errors, 'warnings' => $warnings, 'successes' => $successes];
/*
* Tests for deposit
*/
/*
* Tests for transfer
*/
}
/**
* Store a full transaction journal and associated stuff
*
@@ -235,7 +418,7 @@ class Transaction implements TransactionInterface
}
if (isset($data['revenue_account'])) {
$from = $this->_accounts->findRevenueAccountByName($data['revenue_account']);
$to = $this->_accounts->findAssetAccountById($data['account_id']);
$to = $this->_accounts->findAssetAccountById($data['account_id']);
}
if (isset($data['account_from_id'])) {
$from = $this->_accounts->findAssetAccountById($data['account_from_id']);
@@ -247,8 +430,7 @@ class Transaction implements TransactionInterface
/*
* Add a custom error when they are the same.
*/
if ($to->id ==
$from->id) {
if ($to->id == $from->id) {
$bag = new MessageBag;
$bag->add('account_from_id', 'The account from cannot be the same as the account to.');
return $bag;

View File

@@ -19,6 +19,15 @@ interface TransactionInterface {
*/
public function store(array $data);
/**
* Returns messages about the validation.
*
* @param array $data
*
* @return array
*/
public function validate(array $data);
/**
* @param \TransactionJournal $journal
* @param array $data

View File

@@ -83,17 +83,19 @@ interface AccountRepositoryInterface
/**
* @param $name
* @param $create
*
* @return |Account|null
*/
public function findExpenseAccountByName($name);
public function findExpenseAccountByName($name, $create = true);
/**
* @param $name
* @param $create
*
* @return |Account|null
*/
public function findRevenueAccountByName($name);
public function findRevenueAccountByName($name, $create = true);
/**
* @return mixed

View File

@@ -42,7 +42,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
public function destroy(\Account $account)
{
// find all transaction journals related to this account:
$journals = \TransactionJournal::withRelevantData()->accountIs($account)->get(['transaction_journals.*']);
$journals = \TransactionJournal::withRelevantData()->accountIs($account)->get(['transaction_journals.*']);
$accountIDs = [];
/** @var \TransactionJournal $journal */
@@ -58,7 +58,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
if (count($accountIDs) > 0) {
// find the "initial balance" type accounts in this list. Should be just 1.
$query = $this->_user->accounts()->accountTypeIn(['Initial balance account'])
->whereIn('accounts.id', $accountIDs);
->whereIn('accounts.id', $accountIDs);
if ($query->count() == 1) {
$iba = $query->first(['accounts.*']);
$iba->delete();
@@ -90,22 +90,23 @@ class EloquentAccountRepository implements AccountRepositoryInterface
* because when you feed it "Import account" it will always return an import account of that type.
*
* @param $name
* @param $create
*
* @return null|\Account
*/
public function findExpenseAccountByName($name)
public function findExpenseAccountByName($name, $create = true)
{
$cashType = $this->findAccountType('Cash account');
$cashType = $this->findAccountType('Cash account');
$importType = $this->findAccountType('Import account');
// catch Import account:
if ($name == 'Import account') {
$import = $this->firstOrCreate(
[
'name' => 'Import account',
'user_id' => $this->_user->id,
'name' => 'Import account',
'user_id' => $this->_user->id,
'account_type_id' => $importType->id,
'active' => 1
'active' => 1
]
);
return $import;
@@ -118,15 +119,17 @@ class EloquentAccountRepository implements AccountRepositoryInterface
)->first(['accounts.*']);
// create if not found:
if (strlen($name) > 0 && is_null($account)) {
$type = $this->findAccountType('Expense account');
$set = [
'name' => $name,
'user_id' => $this->_user->id,
'active' => 1,
if (strlen($name) > 0 && is_null($account) && $create === true) {
$type = $this->findAccountType('Expense account');
$set = [
'name' => $name,
'user_id' => $this->_user->id,
'active' => 1,
'account_type_id' => $type->id
];
$account = $this->firstOrCreate($set);
} else if (strlen($name) > 0 && is_null($account) && $create === false) {
return null;
}
@@ -138,10 +141,10 @@ class EloquentAccountRepository implements AccountRepositoryInterface
// create cash account as ultimate fall back:
if (is_null($account)) {
$set = [
'name' => 'Cash account',
'user_id' => $this->_user->id,
'active' => 1,
$set = [
'name' => 'Cash account',
'user_id' => $this->_user->id,
'active' => 1,
'account_type_id' => $cashType->id
];
$account = $this->firstOrCreate($set);
@@ -171,52 +174,55 @@ class EloquentAccountRepository implements AccountRepositoryInterface
/**
* @param $name
* @param $create
*
* @return |Account|null
*/
public function findRevenueAccountByName($name)
public function findRevenueAccountByName($name, $create = true)
{
// catch Import account:
if ($name == 'Import account') {
$importType = $this->findAccountType('Import account');
$import = $this->firstOrCreate(
$import = $this->firstOrCreate(
[
'name' => 'Import account',
'user_id' => $this->_user->id,
'name' => 'Import account',
'user_id' => $this->_user->id,
'account_type_id' => $importType->id,
'active' => 1
'active' => 1
]
);
return $import;
}
// find account:
$type = $this->findAccountType('Revenue account');
$type = $this->findAccountType('Revenue account');
$account = $this->_user->accounts()->where('name', $name)->where('account_type_id', $type->id)->first();
// create if not found:
if (strlen($name) > 0) {
$set = [
'name' => $name,
'user_id' => $this->_user->id,
'active' => 1,
if (strlen($name) > 0 && is_null($account) && $create === true) {
$set = [
'name' => $name,
'user_id' => $this->_user->id,
'active' => 1,
'account_type_id' => $type->id
];
$account = $this->firstOrCreate($set);
} else if (strlen($name) > 0 && is_null($account) && $create === false) {
return null;
}
// find cash account as fall back:
if (is_null($account)) {
$cashType = $this->findAccountType('Cash account');
$account = $this->_user->accounts()->where('account_type_id', $cashType->id)->first();
$account = $this->_user->accounts()->where('account_type_id', $cashType->id)->first();
}
// create cash account as ultimate fall back:
if (is_null($account)) {
$set = [
'name' => 'Cash account',
'user_id' => $this->_user->id,
'active' => 1,
$set = [
'name' => 'Cash account',
'user_id' => $this->_user->id,
'active' => 1,
'account_type_id' => $cashType->id
];
$account = $this->firstOrCreate($set);
@@ -232,7 +238,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
public function getByAccountType(\AccountType $type)
{
return $this->_user->accounts()->with('accounttype')->orderBy('name', 'ASC')
->where('account_type_id', $type->id)->get();
->where('account_type_id', $type->id)->get();
}
/**
@@ -307,7 +313,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
return $this->_user->accounts()->accountTypeIn(['Default account', 'Asset account'])->where(
'accounts.active', 1
)
->get(['accounts.*']);
->get(['accounts.*']);
}
/**
@@ -316,7 +322,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
public function getDefault()
{
return $this->_user->accounts()->accountTypeIn(['Default account', 'Asset account'])
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
}
/**
@@ -334,7 +340,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
}
/**
* @param Job $job
* @param Job $job
* @param array $payload
*
* @return mixed
@@ -346,7 +352,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
/** @var \Importmap $importMap */
$importMap = $repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$user = $importMap->user;
$this->overruleUser($user);
/*
@@ -369,17 +375,17 @@ class EloquentAccountRepository implements AccountRepositoryInterface
* find the payload's account type:
*/
$payload['account_type'] = isset($payload['account_type']) ? $payload['account_type'] : 'Expense account';
$type = $this->findAccountType($payload['account_type']);
$type = $this->findAccountType($payload['account_type']);
/*
* Create data array for store() procedure.
*/
$data = [
'account_type' => $type,
'name' => $payload['data']['name'],
'name' => $payload['data']['name'],
];
if (isset($payload['data']['openingbalance'])) {
$data['openingbalance'] = floatval($payload['data']['openingbalance']);
$data['openingbalance'] = floatval($payload['data']['openingbalance']);
$data['openingbalancedate'] = $payload['data']['openingbalancedate'];
}
if (isset($payload['data']['inactive'])) {
@@ -464,7 +470,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
$account->name = $data['name'];
$account->active
= isset($data['active']) && intval($data['active']) >= 0 && intval($data['active']) <= 1 ? intval(
= isset($data['active']) && intval($data['active']) >= 0 && intval($data['active']) <= 1 ? intval(
$data['active']
) : 1;
@@ -474,7 +480,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
// create initial balance, if necessary:
if (isset($data['openingbalance']) && isset($data['openingbalancedate'])) {
$amount = floatval($data['openingbalance']);
$date = new Carbon($data['openingbalancedate']);
$date = new Carbon($data['openingbalancedate']);
if ($amount != 0) {
$this->_createInitialBalance($account, $amount, $date);
}
@@ -491,8 +497,8 @@ class EloquentAccountRepository implements AccountRepositoryInterface
/**
* @param \Account $account
* @param int $amount
* @param Carbon $date
* @param int $amount
* @param Carbon $date
*
* @return bool
* @SuppressWarnings(PHPMD.CamelCaseMethodName)
@@ -518,7 +524,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
$initial = new \Account;
$initial->accountType()->associate($initialBalanceAT);
$initial->user()->associate($this->_user);
$initial->name = $account->name . ' initial balance';
$initial->name = $account->name . ' initial balance';
$initial->active = 0;
if ($initial->validate()) {
$initial->save();
@@ -528,12 +534,12 @@ class EloquentAccountRepository implements AccountRepositoryInterface
$set = [
'account_from_id' => $initial->id,
'account_to_id' => $account->id,
'description' => 'Initial Balance for ' . $account->name,
'what' => 'Opening balance',
'amount' => $amount,
'category' => '',
'date' => $date->format('Y-m-d')
'account_to_id' => $account->id,
'description' => 'Initial Balance for ' . $account->name,
'what' => 'Opening balance',
'amount' => $amount,
'category' => '',
'date' => $date->format('Y-m-d')
];
$transactions->store($set);
@@ -546,7 +552,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
/**
* Takes a transaction/account component and updates the transaction journal to match.
*
* @param Job $job
* @param Job $job
* @param array $payload
*
* @return mixed
@@ -558,7 +564,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
/** @var \Importmap $importMap */
$importMap = $repository->findImportmap($payload['mapID']);
$user = $importMap->user;
$user = $importMap->user;
$this->overruleUser($user);
if ($job->attempts() > 10) {
@@ -579,12 +585,12 @@ class EloquentAccountRepository implements AccountRepositoryInterface
* Prep some vars from the payload
*/
$transactionId = intval($payload['data']['transaction_id']);
$componentId = intval($payload['data']['component_id']);
$componentId = intval($payload['data']['component_id']);
/*
* Find the import map for both:
*/
$accountMap = $repository->findImportEntry($importMap, 'Account', $componentId);
$accountMap = $repository->findImportEntry($importMap, 'Account', $componentId);
$transactionMap = $repository->findImportEntry($importMap, 'Transaction', $transactionId);
/*
@@ -713,7 +719,7 @@ class EloquentAccountRepository implements AccountRepositoryInterface
$journal = $interface->openingBalanceTransaction($account);
if ($journal) {
$journal->date = new Carbon($data['openingbalancedate']);
$journal->date = new Carbon($data['openingbalancedate']);
$journal->transactions[0]->amount = floatval($data['openingbalance']) * -1;
$journal->transactions[1]->amount = floatval($data['openingbalance']);
$journal->transactions[0]->save();