mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Varioux fixes and cleaning up.
This commit is contained in:
parent
9015d6ca16
commit
aa9eb8ca64
@ -1,9 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
|
use Firefly\Helper\Controllers\JsonInterface as JI;
|
||||||
use Firefly\Storage\Budget\BudgetRepositoryInterface as Bud;
|
|
||||||
use Firefly\Storage\Category\CategoryRepositoryInterface as Cat;
|
|
||||||
use Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface as TJRI;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use LaravelBook\Ardent\Builder;
|
use LaravelBook\Ardent\Builder;
|
||||||
|
|
||||||
@ -14,226 +11,60 @@ use LaravelBook\Ardent\Builder;
|
|||||||
*/
|
*/
|
||||||
class JsonController extends BaseController
|
class JsonController extends BaseController
|
||||||
{
|
{
|
||||||
protected $_accounts;
|
/** @var \Firefly\Helper\Controllers\JsonInterface $helper */
|
||||||
protected $_categories;
|
protected $helper;
|
||||||
protected $_budgets;
|
|
||||||
/** @var TJRI $_journals */
|
|
||||||
protected $_journals;
|
|
||||||
|
|
||||||
/**
|
public function __construct(JI $helper)
|
||||||
* @param ARI $accounts
|
|
||||||
* @param Cat $categories
|
|
||||||
* @param Bud $budgets
|
|
||||||
* @param TJRI $journals
|
|
||||||
*/
|
|
||||||
public function __construct(ARI $accounts, Cat $categories, Bud $budgets, TJRI $journals)
|
|
||||||
{
|
{
|
||||||
$this->_accounts = $accounts;
|
$this->helper = $helper;
|
||||||
$this->_categories = $categories;
|
|
||||||
$this->_budgets = $budgets;
|
|
||||||
$this->_journals = $journals;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns a list of categories.
|
||||||
*
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function revenue()
|
public function categories()
|
||||||
{
|
{
|
||||||
$parameters = $this->_datatableParameters();
|
/** @var \Firefly\Storage\Category\EloquentCategoryRepository $categories */
|
||||||
$parameters['transactionTypes'] = ['Deposit'];
|
$categories = App::make('Firefly\Storage\Category\CategoryRepositoryInterface');
|
||||||
$parameters['amount'] = 'positive';
|
$list = $categories->get();
|
||||||
|
$return = [];
|
||||||
$query = $this->_datatableQuery($parameters);
|
foreach ($list as $entry) {
|
||||||
$resultSet = $this->_datatableResultset($parameters, $query);
|
$return[] = $entry->name;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Build return data:
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (Input::get('debug') == 'true') {
|
|
||||||
echo '<pre>';
|
|
||||||
print_r($parameters);
|
|
||||||
echo '<hr>';
|
|
||||||
print_r($resultSet);
|
|
||||||
return '';
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return Response::json($resultSet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Response::json($return);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns a JSON list of all beneficiaries.
|
||||||
*
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function transfers()
|
public function expenseAccounts()
|
||||||
{
|
{
|
||||||
$parameters = $this->_datatableParameters();
|
/** @var \Firefly\Storage\Account\EloquentAccountRepository $accounts */
|
||||||
$parameters['transactionTypes'] = ['Transfer'];
|
$accounts = App::make('Firefly\Storage\Account\AccountRepositoryInterface');
|
||||||
$parameters['amount'] = 'positive';
|
$list = $accounts->getOfTypes(['Expense account', 'Beneficiary account']);
|
||||||
|
$return = [];
|
||||||
$query = $this->_datatableQuery($parameters);
|
foreach ($list as $entry) {
|
||||||
$resultSet = $this->_datatableResultset($parameters, $query);
|
$return[] = $entry->name;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Build return data:
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (Input::get('debug') == 'true') {
|
|
||||||
echo '<pre>';
|
|
||||||
print_r($parameters);
|
|
||||||
echo '<hr>';
|
|
||||||
print_r($resultSet);
|
|
||||||
return '';
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return Response::json($resultSet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Response::json($return);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function _datatableParameters()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Process all parameters!
|
|
||||||
*/
|
|
||||||
$parameters = [
|
|
||||||
'start' => intval(Input::get('start')),
|
|
||||||
'length' => intval(Input::get('length')) < 0 ? 100000 : intval(Input::get('length')),
|
|
||||||
'draw' => intval(Input::get('draw')),
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Columns:
|
|
||||||
*/
|
|
||||||
if (!is_null(Input::get('columns')) && is_array(Input::get('columns'))) {
|
|
||||||
foreach (Input::get('columns') as $column) {
|
|
||||||
$parameters['columns'][] = [
|
|
||||||
'data' => $column['data'],
|
|
||||||
'name' => $column['name'],
|
|
||||||
'searchable' => $column['searchable'] == 'true' ? true : false,
|
|
||||||
'orderable' => $column['orderable'] == 'true' ? true : false,
|
|
||||||
'search' => [
|
|
||||||
'value' => $column['search']['value'],
|
|
||||||
'regex' => $column['search']['regex'] == 'true' ? true : false,
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sorting.
|
|
||||||
*/
|
|
||||||
$parameters['orderOnAccount'] = false;
|
|
||||||
if (!is_null(Input::get('order')) && is_array(Input::get('order'))) {
|
|
||||||
foreach (Input::get('order') as $order) {
|
|
||||||
$columnIndex = intval($order['column']);
|
|
||||||
$columnName = $parameters['columns'][$columnIndex]['name'];
|
|
||||||
$parameters['order'][] = [
|
|
||||||
'name' => $columnName,
|
|
||||||
'dir' => strtoupper($order['dir'])
|
|
||||||
];
|
|
||||||
if ($columnName == 'to' || $columnName == 'from') {
|
|
||||||
$parameters['orderOnAccount'] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Search parameters:
|
|
||||||
*/
|
|
||||||
if (!is_null(Input::get('search')) && is_array(Input::get('search'))) {
|
|
||||||
$search = Input::get('search');
|
|
||||||
$parameters['search'] = [
|
|
||||||
'value' => $search['value'],
|
|
||||||
'regex' => $search['regex'] == 'true' ? true : false
|
|
||||||
];
|
|
||||||
}
|
|
||||||
return $parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $parameters
|
|
||||||
*
|
|
||||||
* @return Builder
|
|
||||||
*/
|
|
||||||
protected function _datatableQuery(array $parameters)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We need the following vars to fine tune the query:
|
|
||||||
*/
|
|
||||||
if ($parameters['amount'] == 'negative') {
|
|
||||||
$operator = '<';
|
|
||||||
$operatorNegated = '>';
|
|
||||||
$function = 'lessThan';
|
|
||||||
} else {
|
|
||||||
$operator = '>';
|
|
||||||
$operatorNegated = '<';
|
|
||||||
$function = 'moreThan';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Build query:
|
|
||||||
*/
|
|
||||||
$query = \TransactionJournal::transactionTypes($parameters['transactionTypes'])->withRelevantData();
|
|
||||||
$query->where('completed',1);
|
|
||||||
/*
|
|
||||||
* This is complex. Join `transactions` twice, once for the "to" account and once for the
|
|
||||||
* "from" account. Then get the amount from one of these (depends on type).
|
|
||||||
*
|
|
||||||
* Only need to do this when there's a sort order for "from" or "to".
|
|
||||||
*
|
|
||||||
* Also need the table prefix for this to work.
|
|
||||||
*/
|
|
||||||
if ($parameters['orderOnAccount'] === true) {
|
|
||||||
$connection = \Config::get('database.default');
|
|
||||||
$prefix = \Config::get('database.connections.' . $connection . '.prefix');
|
|
||||||
// left join first table for "from" account:
|
|
||||||
$query->leftJoin(
|
|
||||||
'transactions AS ' . $prefix . 't1', function ($join) use ($operator) {
|
|
||||||
$join->on('t1.transaction_journal_id', '=', 'transaction_journals.id')
|
|
||||||
->on('t1.amount', $operator, \DB::Raw(0));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
// left join second table for "to" account:
|
|
||||||
$query->leftJoin(
|
|
||||||
'transactions AS ' . $prefix . 't2', function ($join) use ($operatorNegated) {
|
|
||||||
$join->on('t2.transaction_journal_id', '=', 'transaction_journals.id')
|
|
||||||
->on('t2.amount', $operatorNegated, \DB::Raw(0));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// also join accounts twice to get the account's name, which we need for sorting.
|
|
||||||
$query->leftJoin('accounts as ' . $prefix . 'a1', 'a1.id', '=', 't1.account_id');
|
|
||||||
$query->leftJoin('accounts as ' . $prefix . 'a2', 'a2.id', '=', 't2.account_id');
|
|
||||||
} else {
|
|
||||||
// less complex
|
|
||||||
$query->$function(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add sort parameters to query:
|
|
||||||
*/
|
|
||||||
if (isset($parameters['order']) && count($parameters['order']) > 0) {
|
|
||||||
foreach ($parameters['order'] as $order) {
|
|
||||||
$query->orderBy($order['name'], $order['dir']);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$query->defaultSorting();
|
|
||||||
}
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of transactions, expenses only, using the given parameters.
|
* Returns a list of transactions, expenses only, using the given parameters.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function expenses()
|
public function expenses()
|
||||||
{
|
{
|
||||||
@ -241,7 +72,7 @@ class JsonController extends BaseController
|
|||||||
/*
|
/*
|
||||||
* Gets most parameters from the Input::all() array:
|
* Gets most parameters from the Input::all() array:
|
||||||
*/
|
*/
|
||||||
$parameters = $this->_datatableParameters();
|
$parameters = $this->helper->dataTableParameters();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add some more parameters to fine tune the query:
|
* Add some more parameters to fine tune the query:
|
||||||
@ -252,137 +83,58 @@ class JsonController extends BaseController
|
|||||||
/*
|
/*
|
||||||
* Get the query:
|
* Get the query:
|
||||||
*/
|
*/
|
||||||
$query = $this->_datatableQuery($parameters);
|
$query = $this->helper->journalQuery($parameters);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build result set:
|
* Build result set:
|
||||||
*/
|
*/
|
||||||
$resultSet = $this->_datatableResultset($parameters, $query);
|
$resultSet = $this->helper->journalDataset($parameters, $query);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build return data:
|
* Build return data:
|
||||||
*/
|
*/
|
||||||
|
return Response::json($resultSet);
|
||||||
if (Input::get('debug') == 'true') {
|
|
||||||
echo '<pre>';
|
|
||||||
print_r($parameters);
|
|
||||||
echo '<hr>';
|
|
||||||
print_r($resultSet);
|
|
||||||
return '';
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return Response::json($resultSet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function _datatableResultset(array $parameters, Builder $query)
|
public function recurring()
|
||||||
{
|
{
|
||||||
/*
|
$parameters = $this->helper->dataTableParameters();
|
||||||
* Count query:
|
$query = $this->helper->recurringTransactionsQuery($parameters);
|
||||||
*/
|
$resultSet = $this->helper->recurringTransactionsDataset($parameters, $query);
|
||||||
$count = $query->count();
|
return Response::json($resultSet);
|
||||||
|
|
||||||
/*
|
|
||||||
* Update the selection:
|
|
||||||
*/
|
|
||||||
|
|
||||||
$query->take($parameters['length']);
|
|
||||||
$query->skip($parameters['start']);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Input search parameters:
|
|
||||||
*/
|
|
||||||
$filtered = $count;
|
|
||||||
if(strlen($parameters['search']['value']) > 0) {
|
|
||||||
$query->where('transaction_journals.description','LIKE','%'.e($parameters['search']['value']).'%');
|
|
||||||
$filtered = $query->count();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Build return array:
|
|
||||||
*/
|
|
||||||
$data = [
|
|
||||||
'draw' => $parameters['draw'],
|
|
||||||
'recordsTotal' => $count,
|
|
||||||
'recordsFiltered' => $filtered,
|
|
||||||
'data' => [],
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get paginated result set:
|
|
||||||
*/
|
|
||||||
if ($parameters['orderOnAccount'] === true) {
|
|
||||||
/** @var Collection $set */
|
|
||||||
$set = $query->get(
|
|
||||||
[
|
|
||||||
'transaction_journals.*',
|
|
||||||
't1.amount',
|
|
||||||
't1.account_id AS from_id',
|
|
||||||
'a1.name AS from',
|
|
||||||
't2.account_id AS to_id',
|
|
||||||
'a2.name AS to',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
/** @var Collection $set */
|
|
||||||
$set = $query->get(
|
|
||||||
[
|
|
||||||
'transaction_journals.*',
|
|
||||||
'transactions.amount',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Loop set and create entries to return.
|
|
||||||
*/
|
|
||||||
foreach ($set as $entry) {
|
|
||||||
$from = $entry->transactions[0]->account;
|
|
||||||
$to = $entry->transactions[1]->account;
|
|
||||||
$data['data'][] = [
|
|
||||||
'date' => $entry->date->format('j F Y'),
|
|
||||||
'description' => [
|
|
||||||
'description' => $entry->description,
|
|
||||||
'url' => route('transactions.show', $entry->id)
|
|
||||||
],
|
|
||||||
'amount' => floatval($entry->amount),
|
|
||||||
'from' => ['name' => $from->name, 'url' => route('accounts.show', $from->id)],
|
|
||||||
'to' => ['name' => $to->name, 'url' => route('accounts.show', $to->id)],
|
|
||||||
'id' => [
|
|
||||||
'edit' => route('transactions.edit', $entry->id),
|
|
||||||
'delete' => route('transactions.delete', $entry->id)
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
}
|
|
||||||
return $data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a JSON list of all beneficiaries.
|
* @return \Illuminate\Http\JsonResponse|string
|
||||||
*/
|
*/
|
||||||
public function expenseAccounts()
|
public function revenue()
|
||||||
{
|
{
|
||||||
$list = $this->_accounts->getOfTypes(['Expense account', 'Beneficiary account']);
|
$parameters = $this->helper->dataTableParameters();
|
||||||
$return = [];
|
$parameters['transactionTypes'] = ['Deposit'];
|
||||||
foreach ($list as $entry) {
|
$parameters['amount'] = 'positive';
|
||||||
$return[] = $entry->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response::json($return);
|
$query = $this->helper->journalQuery($parameters);
|
||||||
|
$resultSet = $this->helper->journalDataset($parameters, $query);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build return data:
|
||||||
|
*/
|
||||||
|
return Response::json($resultSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a JSON list of all revenue accounts.
|
* Returns a JSON list of all revenue accounts.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function revenueAccounts()
|
public function revenueAccounts()
|
||||||
{
|
{
|
||||||
$list = $this->_accounts->getOfTypes(['Revenue account']);
|
/** @var \Firefly\Storage\Account\EloquentAccountRepository $accounts */
|
||||||
$return = [];
|
$accounts = App::make('Firefly\Storage\Account\AccountRepositoryInterface');
|
||||||
|
$list = $accounts->getOfTypes(['Revenue account']);
|
||||||
|
$return = [];
|
||||||
foreach ($list as $entry) {
|
foreach ($list as $entry) {
|
||||||
$return[] = $entry->name;
|
$return[] = $entry->name;
|
||||||
}
|
}
|
||||||
@ -392,18 +144,23 @@ class JsonController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responds some JSON for typeahead fields.
|
* Returns a list of all transfers.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function categories()
|
public function transfers()
|
||||||
{
|
{
|
||||||
$list = $this->_categories->get();
|
$parameters = $this->helper->dataTableParameters();
|
||||||
$return = [];
|
$parameters['transactionTypes'] = ['Transfer'];
|
||||||
foreach ($list as $entry) {
|
$parameters['amount'] = 'positive';
|
||||||
$return[] = $entry->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response::json($return);
|
$query = $this->helper->journalQuery($parameters);
|
||||||
|
$resultSet = $this->helper->journalDataset($parameters, $query);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build return data:
|
||||||
|
*/
|
||||||
|
return Response::json($resultSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Firefly\Exception\FireflyException;
|
||||||
use Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface as RTR;
|
use Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface as RTR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +52,7 @@ class RecurringController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function destroy(RecurringTransaction $recurringTransaction)
|
public function destroy(RecurringTransaction $recurringTransaction)
|
||||||
{
|
{
|
||||||
Event::fire('recurring.destroy', [$recurringTransaction]);
|
//Event::fire('recurring.destroy', [$recurringTransaction]);
|
||||||
$result = $this->_repository->destroy($recurringTransaction);
|
$result = $this->_repository->destroy($recurringTransaction);
|
||||||
if ($result === true) {
|
if ($result === true) {
|
||||||
Session::flash('success', 'The recurring transaction was deleted.');
|
Session::flash('success', 'The recurring transaction was deleted.');
|
||||||
@ -84,11 +85,7 @@ class RecurringController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$list = $this->_repository->get();
|
return View::make('recurring.index');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return View::make('recurring.index')->with('list', $list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,10 +103,18 @@ class RecurringController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function store()
|
public function store()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
switch (Input::get('post_submit_action')) {
|
||||||
|
default:
|
||||||
|
throw new FireflyException('Method ' . Input::get('post_submit_action') . ' not implemented yet.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$recurringTransaction = $this->_repository->store(Input::all());
|
$recurringTransaction = $this->_repository->store(Input::all());
|
||||||
if ($recurringTransaction->validate()) {
|
|
||||||
|
if ($recurringTransaction->errors()->count() == 0) {
|
||||||
Session::flash('success', 'Recurring transaction "' . $recurringTransaction->name . '" saved!');
|
Session::flash('success', 'Recurring transaction "' . $recurringTransaction->name . '" saved!');
|
||||||
Event::fire('recurring.store', [$recurringTransaction]);
|
//Event::fire('recurring.store', [$recurringTransaction]);
|
||||||
if (Input::get('create') == '1') {
|
if (Input::get('create') == '1') {
|
||||||
return Redirect::route('recurring.create')->withInput();
|
return Redirect::route('recurring.create')->withInput();
|
||||||
} else {
|
} else {
|
||||||
@ -135,7 +140,7 @@ class RecurringController extends BaseController
|
|||||||
$recurringTransaction = $this->_repository->update($recurringTransaction, Input::all());
|
$recurringTransaction = $this->_repository->update($recurringTransaction, Input::all());
|
||||||
if ($recurringTransaction->errors()->count() == 0) {
|
if ($recurringTransaction->errors()->count() == 0) {
|
||||||
Session::flash('success', 'The recurring transaction has been updated.');
|
Session::flash('success', 'The recurring transaction has been updated.');
|
||||||
Event::fire('recurring.update', [$recurringTransaction]);
|
//Event::fire('recurring.update', [$recurringTransaction]);
|
||||||
|
|
||||||
return Redirect::route('recurring.index');
|
return Redirect::route('recurring.index');
|
||||||
} else {
|
} else {
|
||||||
|
369
app/lib/Firefly/Helper/Controllers/Json.php
Normal file
369
app/lib/Firefly/Helper/Controllers/Json.php
Normal file
@ -0,0 +1,369 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Created by PhpStorm.
|
||||||
|
* User: sander
|
||||||
|
* Date: 27/09/14
|
||||||
|
* Time: 07:39
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Firefly\Helper\Controllers;
|
||||||
|
|
||||||
|
use LaravelBook\Ardent\Builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Json
|
||||||
|
*
|
||||||
|
* @package Firefly\Helper\Controllers
|
||||||
|
*/
|
||||||
|
class Json implements JsonInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Grabs all the parameters entered by the DataTables JQuery plugin and creates
|
||||||
|
* a nice array to be used by the other methods. It's also cleaning up and what-not.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function dataTableParameters()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Process all parameters!
|
||||||
|
*/
|
||||||
|
if (intval(\Input::get('length')) < 0) {
|
||||||
|
$length = 10000; // we get them all if no length is defined.
|
||||||
|
} else {
|
||||||
|
$length = intval(\Input::get('length'));
|
||||||
|
}
|
||||||
|
$parameters = [
|
||||||
|
'start' => intval(\Input::get('start')),
|
||||||
|
'length' => $length,
|
||||||
|
'draw' => intval(\Input::get('draw')),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Columns:
|
||||||
|
*/
|
||||||
|
if (!is_null(\Input::get('columns')) && is_array(\Input::get('columns'))) {
|
||||||
|
foreach (\Input::get('columns') as $column) {
|
||||||
|
$parameters['columns'][] = [
|
||||||
|
'data' => $column['data'],
|
||||||
|
'name' => $column['name'],
|
||||||
|
'searchable' => $column['searchable'] == 'true' ? true : false,
|
||||||
|
'orderable' => $column['orderable'] == 'true' ? true : false,
|
||||||
|
'search' => [
|
||||||
|
'value' => $column['search']['value'],
|
||||||
|
'regex' => $column['search']['regex'] == 'true' ? true : false,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sorting.
|
||||||
|
*/
|
||||||
|
$parameters['orderOnAccount'] = false;
|
||||||
|
if (!is_null(\Input::get('order')) && is_array(\Input::get('order'))) {
|
||||||
|
foreach (\Input::get('order') as $order) {
|
||||||
|
$columnIndex = intval($order['column']);
|
||||||
|
$columnName = $parameters['columns'][$columnIndex]['name'];
|
||||||
|
$parameters['order'][] = [
|
||||||
|
'name' => $columnName,
|
||||||
|
'dir' => strtoupper($order['dir'])
|
||||||
|
];
|
||||||
|
if ($columnName == 'to' || $columnName == 'from') {
|
||||||
|
$parameters['orderOnAccount'] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Search parameters:
|
||||||
|
*/
|
||||||
|
$parameters['search'] = [
|
||||||
|
'value' => '',
|
||||||
|
'regex' => false
|
||||||
|
];
|
||||||
|
if (!is_null(\Input::get('search')) && is_array(\Input::get('search'))) {
|
||||||
|
$search = \Input::get('search');
|
||||||
|
$parameters['search'] = [
|
||||||
|
'value' => $search['value'],
|
||||||
|
'regex' => $search['regex'] == 'true' ? true : false
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do some sorting, counting and ordering on the query and return a nicely formatted array
|
||||||
|
* that can be used by the DataTables JQuery plugin.
|
||||||
|
*
|
||||||
|
* @param array $parameters
|
||||||
|
* @param Builder $query
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function journalDataset(array $parameters, Builder $query)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Count query:
|
||||||
|
*/
|
||||||
|
$count = $query->count();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the selection:
|
||||||
|
*/
|
||||||
|
|
||||||
|
$query->take($parameters['length']);
|
||||||
|
if ($parameters['start'] > 0) {
|
||||||
|
$query->skip($parameters['start']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Input search parameters:
|
||||||
|
*/
|
||||||
|
$filtered = $count;
|
||||||
|
if (strlen($parameters['search']['value']) > 0) {
|
||||||
|
$query->where('transaction_journals.description', 'LIKE', '%' . e($parameters['search']['value']) . '%');
|
||||||
|
$filtered = $query->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build return array:
|
||||||
|
*/
|
||||||
|
$data = [
|
||||||
|
'draw' => $parameters['draw'],
|
||||||
|
'recordsTotal' => $count,
|
||||||
|
'recordsFiltered' => $filtered,
|
||||||
|
'data' => [],
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get paginated result set:
|
||||||
|
*/
|
||||||
|
if ($parameters['orderOnAccount'] === true) {
|
||||||
|
/** @var Collection $set */
|
||||||
|
$set = $query->get(
|
||||||
|
[
|
||||||
|
'transaction_journals.*',
|
||||||
|
't1.amount',
|
||||||
|
't1.account_id AS from_id',
|
||||||
|
'a1.name AS from',
|
||||||
|
't2.account_id AS to_id',
|
||||||
|
'a2.name AS to',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
/** @var Collection $set */
|
||||||
|
$set = $query->get(
|
||||||
|
[
|
||||||
|
'transaction_journals.*',
|
||||||
|
'transactions.amount',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop set and create entries to return.
|
||||||
|
*/
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$from = $entry->transactions[0]->account;
|
||||||
|
$to = $entry->transactions[1]->account;
|
||||||
|
$data['data'][] = [
|
||||||
|
'date' => $entry->date->format('j F Y'),
|
||||||
|
'description' => [
|
||||||
|
'description' => $entry->description,
|
||||||
|
'url' => route('transactions.show', $entry->id)
|
||||||
|
],
|
||||||
|
'amount' => floatval($entry->amount),
|
||||||
|
'from' => ['name' => $from->name, 'url' => route('accounts.show', $from->id)],
|
||||||
|
'to' => ['name' => $to->name, 'url' => route('accounts.show', $to->id)],
|
||||||
|
'id' => [
|
||||||
|
'edit' => route('transactions.edit', $entry->id),
|
||||||
|
'delete' => route('transactions.delete', $entry->id)
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds most of the query required to grab transaction journals from the database.
|
||||||
|
* This is useful because all three pages showing different kinds of transactions use
|
||||||
|
* the exact same query with only slight differences.
|
||||||
|
*
|
||||||
|
* @param array $parameters
|
||||||
|
*
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
|
public function journalQuery(array $parameters)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We need the following vars to fine tune the query:
|
||||||
|
*/
|
||||||
|
if ($parameters['amount'] == 'negative') {
|
||||||
|
$operator = '<';
|
||||||
|
$operatorNegated = '>';
|
||||||
|
$function = 'lessThan';
|
||||||
|
} else {
|
||||||
|
$operator = '>';
|
||||||
|
$operatorNegated = '<';
|
||||||
|
$function = 'moreThan';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build query:
|
||||||
|
*/
|
||||||
|
$query = \TransactionJournal::transactionTypes($parameters['transactionTypes'])->withRelevantData();
|
||||||
|
$query->where('user_id', \Auth::user()->id);
|
||||||
|
$query->where('completed', 1);
|
||||||
|
/*
|
||||||
|
* This is complex. Join `transactions` twice, once for the "to" account and once for the
|
||||||
|
* "from" account. Then get the amount from one of these (depends on type).
|
||||||
|
*
|
||||||
|
* Only need to do this when there's a sort order for "from" or "to".
|
||||||
|
*
|
||||||
|
* Also need the table prefix for this to work.
|
||||||
|
*/
|
||||||
|
if ($parameters['orderOnAccount'] === true) {
|
||||||
|
$connection = \Config::get('database.default');
|
||||||
|
$prefix = \Config::get('database.connections.' . $connection . '.prefix');
|
||||||
|
// left join first table for "from" account:
|
||||||
|
$query->leftJoin(
|
||||||
|
'transactions AS ' . $prefix . 't1', function ($join) use ($operator) {
|
||||||
|
$join->on('t1.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->on('t1.amount', $operator, \DB::Raw(0));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// left join second table for "to" account:
|
||||||
|
$query->leftJoin(
|
||||||
|
'transactions AS ' . $prefix . 't2', function ($join) use ($operatorNegated) {
|
||||||
|
$join->on('t2.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->on('t2.amount', $operatorNegated, \DB::Raw(0));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// also join accounts twice to get the account's name, which we need for sorting.
|
||||||
|
$query->leftJoin('accounts as ' . $prefix . 'a1', 'a1.id', '=', 't1.account_id');
|
||||||
|
$query->leftJoin('accounts as ' . $prefix . 'a2', 'a2.id', '=', 't2.account_id');
|
||||||
|
} else {
|
||||||
|
// less complex
|
||||||
|
$query->$function(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add sort parameters to query:
|
||||||
|
*/
|
||||||
|
if (isset($parameters['order']) && count($parameters['order']) > 0) {
|
||||||
|
foreach ($parameters['order'] as $order) {
|
||||||
|
$query->orderBy($order['name'], $order['dir']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$query->defaultSorting();
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do some sorting, counting and ordering on the query and return a nicely formatted array
|
||||||
|
* that can be used by the DataTables JQuery plugin.
|
||||||
|
*
|
||||||
|
* @param array $parameters
|
||||||
|
* @param Builder $query
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function recurringTransactionsDataset(array $parameters, Builder $query)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Count query:
|
||||||
|
*/
|
||||||
|
$count = $query->count();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the selection:
|
||||||
|
*/
|
||||||
|
|
||||||
|
$query->take($parameters['length']);
|
||||||
|
if ($parameters['start'] > 0) {
|
||||||
|
$query->skip($parameters['start']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Input search parameters:
|
||||||
|
*/
|
||||||
|
$filtered = $count;
|
||||||
|
if (strlen($parameters['search']['value']) > 0) {
|
||||||
|
$query->where('recurring_transactions.description', 'LIKE', '%' . e($parameters['search']['value']) . '%');
|
||||||
|
$filtered = $query->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build return array:
|
||||||
|
*/
|
||||||
|
$data = [
|
||||||
|
'draw' => $parameters['draw'],
|
||||||
|
'recordsTotal' => $count,
|
||||||
|
'recordsFiltered' => $filtered,
|
||||||
|
'data' => [],
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get paginated result set:
|
||||||
|
*/
|
||||||
|
/** @var Collection $set */
|
||||||
|
$set = $query->get(
|
||||||
|
[
|
||||||
|
'recurring_transactions.*',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop set and create entries to return.
|
||||||
|
*/
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$data['data'][] = [
|
||||||
|
|
||||||
|
'name' => ['name' => $entry->name,'url' => route('recurring.show',$entry->id)],
|
||||||
|
'match' => explode(' ',$entry->match),
|
||||||
|
'amount_max' => floatval($entry->amount_max),
|
||||||
|
'amount_min' => floatval($entry->amount_min),
|
||||||
|
'date' => $entry->date->format('j F Y'),
|
||||||
|
'active' => intval($entry->active),
|
||||||
|
'automatch' => intval($entry->automatch),
|
||||||
|
'repeat_freq' => $entry->repeat_freq,
|
||||||
|
'id' => [
|
||||||
|
'edit' => route('recurring.edit', $entry->id),
|
||||||
|
'delete' => route('recurring.delete', $entry->id)
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a query that will pick up all recurring transactions from the database.
|
||||||
|
*
|
||||||
|
* @param array $parameters
|
||||||
|
*
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
|
public function recurringTransactionsQuery(array $parameters)
|
||||||
|
{
|
||||||
|
$query = \RecurringTransaction::where('user_id', \Auth::user()->id);
|
||||||
|
|
||||||
|
if (isset($parameters['order']) && count($parameters['order']) > 0) {
|
||||||
|
foreach ($parameters['order'] as $order) {
|
||||||
|
$query->orderBy($order['name'], $order['dir']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$query->orderBy('name', 'ASC');
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
64
app/lib/Firefly/Helper/Controllers/JsonInterface.php
Normal file
64
app/lib/Firefly/Helper/Controllers/JsonInterface.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Firefly\Helper\Controllers;
|
||||||
|
|
||||||
|
use LaravelBook\Ardent\Builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface JsonInterface
|
||||||
|
*
|
||||||
|
* @package Firefly\Helper\Controllers
|
||||||
|
*/
|
||||||
|
interface JsonInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grabs all the parameters entered by the DataTables JQuery plugin and creates
|
||||||
|
* a nice array to be used by the other methods. It's also cleaning up and what-not.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function dataTableParameters();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do some sorting, counting and ordering on the query and return a nicely formatted array
|
||||||
|
* that can be used by the DataTables JQuery plugin.
|
||||||
|
*
|
||||||
|
* @param array $parameters
|
||||||
|
* @param Builder $query
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function journalDataset(array $parameters, Builder $query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds most of the query required to grab transaction journals from the database.
|
||||||
|
* This is useful because all three pages showing different kinds of transactions use
|
||||||
|
* the exact same query with only slight differences.
|
||||||
|
*
|
||||||
|
* @param array $parameters
|
||||||
|
*
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
|
public function journalQuery(array $parameters);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do some sorting, counting and ordering on the query and return a nicely formatted array
|
||||||
|
* that can be used by the DataTables JQuery plugin.
|
||||||
|
*
|
||||||
|
* @param array $parameters
|
||||||
|
* @param Builder $query
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function recurringTransactionsDataset(array $parameters, Builder $query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a query that will pick up all recurring transactions from the database.
|
||||||
|
*
|
||||||
|
* @param array $parameters
|
||||||
|
*
|
||||||
|
* @return Builder
|
||||||
|
*/
|
||||||
|
public function recurringTransactionsQuery(array $parameters);
|
||||||
|
}
|
@ -247,7 +247,8 @@ class Transaction implements TransactionInterface
|
|||||||
/*
|
/*
|
||||||
* Add a custom error when they are the same.
|
* Add a custom error when they are the same.
|
||||||
*/
|
*/
|
||||||
if ($to->id == $from->id) {
|
if ($to->id ==
|
||||||
|
$from->id) {
|
||||||
$bag = new MessageBag;
|
$bag = new MessageBag;
|
||||||
$bag->add('account_from_id', 'The account from cannot be the same as the account to.');
|
$bag->add('account_from_id', 'The account from cannot be the same as the account to.');
|
||||||
return $bag;
|
return $bag;
|
||||||
|
@ -27,6 +27,11 @@ class HelperServiceProvider extends ServiceProvider
|
|||||||
'Firefly\Helper\Controllers\Chart'
|
'Firefly\Helper\Controllers\Chart'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->app->bind(
|
||||||
|
'Firefly\Helper\Controllers\JsonInterface',
|
||||||
|
'Firefly\Helper\Controllers\Json'
|
||||||
|
);
|
||||||
|
|
||||||
$this->app->bind(
|
$this->app->bind(
|
||||||
'Firefly\Helper\Controllers\SearchInterface',
|
'Firefly\Helper\Controllers\SearchInterface',
|
||||||
'Firefly\Helper\Controllers\Search'
|
'Firefly\Helper\Controllers\Search'
|
||||||
|
@ -24,6 +24,26 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo
|
|||||||
$this->_user = \Auth::user();
|
$this->_user = \Auth::user();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \RecurringTransaction $recurringTransaction
|
||||||
|
*
|
||||||
|
* @return bool|mixed
|
||||||
|
*/
|
||||||
|
public function destroy(\RecurringTransaction $recurringTransaction)
|
||||||
|
{
|
||||||
|
$recurringTransaction->delete();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function get()
|
||||||
|
{
|
||||||
|
return $this->_user->recurringtransactions()->get();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Job $job
|
* @param Job $job
|
||||||
* @param array $payload
|
* @param array $payload
|
||||||
@ -115,25 +135,43 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo
|
|||||||
*/
|
*/
|
||||||
public function store($data)
|
public function store($data)
|
||||||
{
|
{
|
||||||
$recurringTransaction = new \RecurringTransaction;
|
$recurringTransaction = new \RecurringTransaction(
|
||||||
$recurringTransaction->user()->associate($this->_user);
|
[
|
||||||
$recurringTransaction->name = $data['name'];
|
'user_id' => $this->_user->id,
|
||||||
$recurringTransaction->match = join(' ', explode(',', $data['match']));
|
'name' => $data['name'],
|
||||||
$recurringTransaction->amount_max = floatval($data['amount_max']);
|
'match' => join(' ', explode(',', $data['match'])),
|
||||||
$recurringTransaction->amount_min = floatval($data['amount_min']);
|
'amount_max' => floatval($data['amount_max']),
|
||||||
|
'amount_min' => floatval($data['amount_min']),
|
||||||
|
'date' => new Carbon($data['date']),
|
||||||
|
'active' => isset($data['active']) ? intval($data['active']) : 0,
|
||||||
|
'automatch' => isset($data['automatch']) ? intval($data['automatch']) : 0,
|
||||||
|
'skip' => isset($data['skip']) ? intval($data['skip']) : 0,
|
||||||
|
'repeat_freq' => $data['repeat_freq'],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
// both amounts zero:
|
// both amounts zero?:
|
||||||
if ($recurringTransaction->amount_max == 0 && $recurringTransaction->amount_min == 0) {
|
if ($recurringTransaction->amount_max == 0 && $recurringTransaction->amount_min == 0) {
|
||||||
$recurringTransaction->errors()->add('amount_max', 'Amount max and min cannot both be zero.');
|
$recurringTransaction->errors()->add('amount_max', 'Amount max and min cannot both be zero.');
|
||||||
|
|
||||||
return $recurringTransaction;
|
return $recurringTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
$recurringTransaction->date = new Carbon($data['date']);
|
if ($recurringTransaction->amount_max < $recurringTransaction->amount_min) {
|
||||||
$recurringTransaction->active = isset($data['active']) ? intval($data['active']) : 0;
|
$recurringTransaction->errors()->add('amount_max', 'Amount max must be more than amount min.');
|
||||||
$recurringTransaction->automatch = isset($data['automatch']) ? intval($data['automatch']) : 0;
|
return $recurringTransaction;
|
||||||
$recurringTransaction->skip = isset($data['skip']) ? intval($data['skip']) : 0;
|
}
|
||||||
$recurringTransaction->repeat_freq = $data['repeat_freq'];
|
|
||||||
|
if ($recurringTransaction->amount_min > $recurringTransaction->amount_max) {
|
||||||
|
$recurringTransaction->errors()->add('amount_max', 'Amount min must be less than amount max.');
|
||||||
|
return $recurringTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($recurringTransaction->date < Carbon::now()) {
|
||||||
|
$recurringTransaction->errors()->add('date', 'Must be in the future.');
|
||||||
|
return $recurringTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($recurringTransaction->validate()) {
|
if ($recurringTransaction->validate()) {
|
||||||
$recurringTransaction->save();
|
$recurringTransaction->save();
|
||||||
@ -142,26 +180,6 @@ class EloquentRecurringTransactionRepository implements RecurringTransactionRepo
|
|||||||
return $recurringTransaction;
|
return $recurringTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param \RecurringTransaction $recurringTransaction
|
|
||||||
*
|
|
||||||
* @return bool|mixed
|
|
||||||
*/
|
|
||||||
public function destroy(\RecurringTransaction $recurringTransaction)
|
|
||||||
{
|
|
||||||
$recurringTransaction->delete();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function get()
|
|
||||||
{
|
|
||||||
return $this->_user->recurringtransactions()->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \RecurringTransaction $recurringTransaction
|
* @param \RecurringTransaction $recurringTransaction
|
||||||
* @param $data
|
* @param $data
|
||||||
|
@ -51,6 +51,7 @@ class RecurringTransaction extends Ardent
|
|||||||
'skip' => 'required|between:0,31',
|
'skip' => 'required|between:0,31',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected $fillable = ['user_id','name','match','amount_min','amount_max','date','repeat_freq','skip','active','automatch'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
|
@ -184,6 +184,7 @@ Route::group(['before' => 'auth'], function () {
|
|||||||
Route::get('/json/expenses', ['uses' => 'JsonController@expenses', 'as' => 'json.expenses']);
|
Route::get('/json/expenses', ['uses' => 'JsonController@expenses', 'as' => 'json.expenses']);
|
||||||
Route::get('/json/revenue', ['uses' => 'JsonController@revenue', 'as' => 'json.revenue']);
|
Route::get('/json/revenue', ['uses' => 'JsonController@revenue', 'as' => 'json.revenue']);
|
||||||
Route::get('/json/transfers', ['uses' => 'JsonController@transfers', 'as' => 'json.transfers']);
|
Route::get('/json/transfers', ['uses' => 'JsonController@transfers', 'as' => 'json.transfers']);
|
||||||
|
Route::get('/json/recurring', ['uses' => 'JsonController@recurring', 'as' => 'json.recurring']);
|
||||||
|
|
||||||
// limit controller:
|
// limit controller:
|
||||||
Route::get('/budgets/limits/create/{budget?}',['uses' => 'LimitController@create','as' => 'budgets.limits.create']);
|
Route::get('/budgets/limits/create/{budget?}',['uses' => 'LimitController@create','as' => 'budgets.limits.create']);
|
||||||
|
@ -1,182 +1,186 @@
|
|||||||
@extends('layouts.default')
|
@extends('layouts.default')
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
|
||||||
<p class="lead">Use recurring transactions to track repeated expenses</p>
|
|
||||||
<p class="text-info">
|
|
||||||
Bla bla.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{Form::open(['class' => 'form-horizontal','url' => route('recurring.store')])}}
|
{{Form::open(['class' => 'form-horizontal','url' => route('recurring.store')])}}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||||
<h4>Mandatory fields</h4>
|
<!-- panel for mandatory fields -->
|
||||||
|
<div class="panel panel-primary">
|
||||||
<!-- name -->
|
<div class="panel-heading">
|
||||||
<div class="form-group">
|
<i class="fa fa-exclamation-circle"></i> Mandatory fields
|
||||||
<label for="name" class="col-sm-4 control-label">Name</label>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<input type="text" name="name" class="form-control" id="name" value="{{Input::old('name')}}" placeholder="Name">
|
|
||||||
@if($errors->has('name'))
|
|
||||||
<p class="text-danger">{{$errors->first('name')}}</p>
|
|
||||||
@else
|
|
||||||
<span class="help-block">For example: rent, gas, insurance</span>
|
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="panel-body">
|
||||||
<div class="form-group">
|
<!-- name -->
|
||||||
<label for="match" class="col-sm-4 control-label">Matches on</label>
|
<div class="form-group">
|
||||||
<div class="col-sm-8">
|
<label for="name" class="col-sm-4 control-label">Name</label>
|
||||||
<input type="text" name="match" class="form-control" id="match" value="{{Input::old('match')}}" data-role="tagsinput">
|
<div class="col-sm-8">
|
||||||
@if($errors->has('match'))
|
<input type="text" name="name" class="form-control" id="name" value="{{Input::old('name')}}" placeholder="Name">
|
||||||
<p class="text-danger">{{$errors->first('match')}}</p>
|
@if($errors->has('name'))
|
||||||
@else
|
<p class="text-danger">{{$errors->first('name')}}</p>
|
||||||
<span class="help-block">For example: rent, [company name]. All matches need to
|
@endif
|
||||||
be present for the recurring transaction to be recognized. This field is not case-sensitive. <em>Press enter after every match</em></span>
|
</div>
|
||||||
@endif
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
</div>
|
<label for="match" class="col-sm-4 control-label">Matches on</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
<div class="form-group">
|
<input type="text" name="match" class="form-control" id="match" value="{{Input::old('match')}}" data-role="tagsinput">
|
||||||
{{ Form::label('amount_min', 'Minimum amount', ['class' => 'col-sm-4 control-label'])}}
|
@if($errors->has('match'))
|
||||||
<div class="col-sm-8">
|
<p class="text-danger">{{$errors->first('match')}}</p>
|
||||||
<div class="input-group">
|
@endif
|
||||||
<span class="input-group-addon">€</span>
|
</div>
|
||||||
{{Form::input('number','amount_min', Input::old('amount_min'), ['step' => 'any', 'class' => 'form-control'])}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if($errors->has('amount_min'))
|
<div class="form-group">
|
||||||
<p class="text-danger">{{$errors->first('amount_min')}}</p>
|
{{ Form::label('amount_min', 'Minimum amount', ['class' => 'col-sm-4 control-label'])}}
|
||||||
@else
|
<div class="col-sm-8">
|
||||||
<span class="help-block">Firefly will only include transactions with a higher amount than this. If your rent
|
<div class="input-group">
|
||||||
is usually around € 500,-, enter <code>450</code> to be safe.</span>
|
<span class="input-group-addon">€</span>
|
||||||
@endif
|
{{Form::input('number','amount_min', Input::old('amount_min'), ['step' => 'any', 'class' => 'form-control'])}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
@if($errors->has('amount_min'))
|
||||||
{{ Form::label('amount_max', 'Maximum amount', ['class' => 'col-sm-4 control-label'])}}
|
<p class="text-danger">{{$errors->first('amount_min')}}</p>
|
||||||
<div class="col-sm-8">
|
@endif
|
||||||
<div class="input-group">
|
</div>
|
||||||
<span class="input-group-addon">€</span>
|
|
||||||
{{Form::input('number','amount_max', Input::old('amount_max'), ['step' => 'any', 'class' => 'form-control'])}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if($errors->has('amount_max'))
|
<div class="form-group">
|
||||||
<p class="text-danger">{{$errors->first('amount_max')}}</p>
|
{{ Form::label('amount_max', 'Maximum amount', ['class' => 'col-sm-4 control-label'])}}
|
||||||
@else
|
<div class="col-sm-8">
|
||||||
<span class="help-block">Firefly will only include transactions with a lower amount than this. If your rent
|
<div class="input-group">
|
||||||
is usually around € 500,-, enter <code>550</code> to be safe.</span>
|
<span class="input-group-addon">€</span>
|
||||||
@endif
|
{{Form::input('number','amount_max', Input::old('amount_max'), ['step' => 'any', 'class' => 'form-control'])}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($errors->has('amount_max'))
|
||||||
|
<p class="text-danger">{{$errors->first('amount_max')}}</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
{{ Form::label('date', 'Date', ['class' => 'col-sm-4 control-label'])}}
|
||||||
|
<div class="col-sm-8">
|
||||||
|
{{ Form::input('date','date', Input::old('date') ?: Carbon\Carbon::now()->addDay()->format('Y-m-d'), ['class'
|
||||||
|
=> 'form-control']) }}
|
||||||
|
@if($errors->has('date'))
|
||||||
|
<p class="text-danger">{{$errors->first('date')}}</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="period" class="col-sm-4 control-label">Recurrence</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
{{Form::select('repeat_freq',$periods,Input::old('repeat_freq') ?: 'monthly',['class' => 'form-control'])}}
|
||||||
|
@if($errors->has('repeat_freq'))
|
||||||
|
<p class="text-danger">{{$errors->first('repeat_freq')}}</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<p>
|
||||||
<div class="form-group">
|
<button type="submit" class="btn btn-lg btn-success">
|
||||||
{{ Form::label('date', 'Date', ['class' => 'col-sm-4 control-label'])}}
|
<i class="fa fa-plus-circle"></i> Store new recurring transaction
|
||||||
<div class="col-sm-8">
|
</button>
|
||||||
{{ Form::input('date','date', Input::old('date') ?: date('Y-m-d'), ['class'
|
</p>
|
||||||
=> 'form-control']) }}
|
|
||||||
@if($errors->has('date'))
|
|
||||||
<p class="text-danger">{{$errors->first('date')}}</p>
|
|
||||||
@else
|
|
||||||
<span class="help-block">Select the next date you expect the transaction to occur.</span>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="period" class="col-sm-4 control-label">Recurrence</label>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
{{Form::select('repeat_freq',$periods,Input::old('repeat_freq') ?: 'monthly',['class' => 'form-control'])}}
|
|
||||||
@if($errors->has('repeat_freq'))
|
|
||||||
<p class="text-danger">{{$errors->first('repeat_freq')}}</p>
|
|
||||||
@else
|
|
||||||
<span class="help-block">Select the period over which this transaction repeats</span>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||||
<h4>Optional fields</h4>
|
<!-- panel for optional fields -->
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="fa fa-smile-o"></i> Optional fields
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
{{ Form::label('skip', 'Skip', ['class' => 'col-sm-4 control-label'])}}
|
||||||
|
<div class="col-sm-8">
|
||||||
|
{{Form::input('number','skip', Input::old('skip') ?: 0, ['class' => 'form-control'])}}
|
||||||
|
|
||||||
<div class="form-group">
|
@if($errors->has('skip'))
|
||||||
{{ Form::label('skip', 'Skip', ['class' => 'col-sm-4 control-label'])}}
|
<p class="text-danger">{{$errors->first('skip')}}</p>
|
||||||
<div class="col-sm-8">
|
@else
|
||||||
{{Form::input('number','skip', Input::old('skip') ?: 0, ['class' => 'form-control'])}}
|
<span class="help-block">Make Firefly skip every <em>n</em> times. Fill in <code>2</code>, and Firefly
|
||||||
|
will match, skip, skip and match a transaction.</span>
|
||||||
@if($errors->has('skip'))
|
@endif
|
||||||
<p class="text-danger">{{$errors->first('skip')}}</p>
|
</div>
|
||||||
@else
|
</div>
|
||||||
<span class="help-block">Make Firefly skip every <em>n</em> times. Fill in <code>2</code>, and Firefly
|
<div class="form-group">
|
||||||
will match, skip, skip and match a transaction.</span>
|
<label for="automatch" class="col-sm-4 control-label">Auto-match</label>
|
||||||
@endif
|
<div class="col-sm-8">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
{{Form::checkbox('automatch',1,Input::old('automatch') == '1' || !Input::old('automatch'))}}
|
||||||
|
Yes
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Firefly will automatically match transactions.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="active" class="col-sm-4 control-label">Active</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
{{Form::checkbox('active',1,Input::old('active') == '1' || !Input::old('active'))}}
|
||||||
|
Yes
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<span class="help-block">This recurring transaction is actually active.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- select budget -->
|
<!-- panel for options -->
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="fa fa-bolt"></i> Options
|
||||||
<!-- select category -->
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
<!-- select beneficiary -->
|
<div class="form-group">
|
||||||
|
<label for="default" class="col-sm-4 control-label">
|
||||||
<div class="form-group">
|
Store
|
||||||
<label for="automatch" class="col-sm-4 control-label">Auto-match</label>
|
</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<div class="checkbox">
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
{{Form::radio('post_submit_action','store',true)}}
|
||||||
|
Store the recurring transaction
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="validate_only" class="col-sm-4 control-label">
|
||||||
|
Validate only
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
{{Form::radio('post_submit_action','validate_only')}}
|
||||||
|
Only validate, do not save
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="return_to_form" class="col-sm-4 control-label">
|
||||||
|
Return here
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="radio">
|
||||||
<label>
|
<label>
|
||||||
{{Form::checkbox('automatch',1,Input::old('automatch') == '1' || !Input::old('automatch'))}}
|
{{Form::radio('post_submit_action','create_another')}}
|
||||||
Yes
|
After storing, return here to create another one.
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<span class="help-block">Firefly will automatically match transactions.</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="active" class="col-sm-4 control-label">Active</label>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<div class="checkbox">
|
|
||||||
<label>
|
|
||||||
{{Form::checkbox('active',1,Input::old('active') == '1' || !Input::old('active'))}}
|
|
||||||
Yes
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<span class="help-block">This recurring transaction is actually active.</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
|
||||||
|
|
||||||
<!-- add another after this one? -->
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="create" class="col-sm-4 control-label"> </label>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<div class="checkbox">
|
|
||||||
<label>
|
|
||||||
{{Form::checkbox('create',1,Input::old('create') == '1')}}
|
|
||||||
Create another (return to this form)
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-offset-4 col-sm-8">
|
|
||||||
<button type="submit" class="btn btn-default btn-success">Create the recurring transaction</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
@extends('layouts.default')
|
@extends('layouts.default')
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
|
||||||
<p class="lead">Use recurring transactions to track repeated expenses</p>
|
|
||||||
<p class="text-info">
|
|
||||||
Bla bla.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{Form::open(['class' => 'form-horizontal','url' => route('recurring.update', $recurringTransaction->id)])}}
|
{{Form::open(['class' => 'form-horizontal','url' => route('recurring.update', $recurringTransaction->id)])}}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||||
<h4>Mandatory fields</h4>
|
<!-- panel for mandatory fields -->
|
||||||
|
<div class="panel panel-primary">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="fa fa-exclamation-circle"></i> Mandatory fields
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
<!-- name -->
|
<!-- name -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name" class="col-sm-4 control-label">Name</label>
|
<label for="name" class="col-sm-4 control-label">Name</label>
|
||||||
@ -23,8 +18,6 @@
|
|||||||
value="{{{Input::old('name') ?: $recurringTransaction->name}}}" placeholder="Name">
|
value="{{{Input::old('name') ?: $recurringTransaction->name}}}" placeholder="Name">
|
||||||
@if($errors->has('name'))
|
@if($errors->has('name'))
|
||||||
<p class="text-danger">{{$errors->first('name')}}</p>
|
<p class="text-danger">{{$errors->first('name')}}</p>
|
||||||
@else
|
|
||||||
<span class="help-block">For example: rent, gas, insurance</span>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -36,9 +29,6 @@
|
|||||||
data-role="tagsinput">
|
data-role="tagsinput">
|
||||||
@if($errors->has('match'))
|
@if($errors->has('match'))
|
||||||
<p class="text-danger">{{$errors->first('match')}}</p>
|
<p class="text-danger">{{$errors->first('match')}}</p>
|
||||||
@else
|
|
||||||
<span class="help-block">For example: rent, [company name]. All matches need to
|
|
||||||
be present for the recurring transaction to be recognized. This field is not case-sensitive.</span>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -54,9 +44,6 @@
|
|||||||
|
|
||||||
@if($errors->has('amount_min'))
|
@if($errors->has('amount_min'))
|
||||||
<p class="text-danger">{{$errors->first('amount_min')}}</p>
|
<p class="text-danger">{{$errors->first('amount_min')}}</p>
|
||||||
@else
|
|
||||||
<span class="help-block">Firefly will only include transactions with a higher amount than this. If your rent
|
|
||||||
is usually around € 500,-, enter <code>450</code> to be safe.</span>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -72,9 +59,6 @@
|
|||||||
|
|
||||||
@if($errors->has('amount_max'))
|
@if($errors->has('amount_max'))
|
||||||
<p class="text-danger">{{$errors->first('amount_max')}}</p>
|
<p class="text-danger">{{$errors->first('amount_max')}}</p>
|
||||||
@else
|
|
||||||
<span class="help-block">Firefly will only include transactions with a lower amount than this.
|
|
||||||
If your rent is usually around € 500,-, enter <code>550</code> to be safe.</span>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -86,8 +70,6 @@
|
|||||||
['class' => 'form-control']) }}
|
['class' => 'form-control']) }}
|
||||||
@if($errors->has('date'))
|
@if($errors->has('date'))
|
||||||
<p class="text-danger">{{$errors->first('date')}}</p>
|
<p class="text-danger">{{$errors->first('date')}}</p>
|
||||||
@else
|
|
||||||
<span class="help-block">Select the next date you expect the transaction to occur.</span>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -99,16 +81,26 @@
|
|||||||
['class' => 'form-control'])}}
|
['class' => 'form-control'])}}
|
||||||
@if($errors->has('repeat_freq'))
|
@if($errors->has('repeat_freq'))
|
||||||
<p class="text-danger">{{$errors->first('repeat_freq')}}</p>
|
<p class="text-danger">{{$errors->first('repeat_freq')}}</p>
|
||||||
@else
|
|
||||||
<span class="help-block">Select the period over which this transaction repeats</span>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
|
||||||
<h4>Optional fields</h4>
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<button type="submit" class="btn btn-lg btn-success">
|
||||||
|
<i class="fa fa-plus-circle"></i> Update recurring transasction
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||||
|
<!-- panel for optional fields -->
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="fa fa-smile-o"></i> Optional fields
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
{{ Form::label('skip', 'Skip', ['class' => 'col-sm-4 control-label'])}}
|
{{ Form::label('skip', 'Skip', ['class' => 'col-sm-4 control-label'])}}
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
@ -117,21 +109,10 @@
|
|||||||
|
|
||||||
@if($errors->has('skip'))
|
@if($errors->has('skip'))
|
||||||
<p class="text-danger">{{$errors->first('skip')}}</p>
|
<p class="text-danger">{{$errors->first('skip')}}</p>
|
||||||
@else
|
|
||||||
<span class="help-block">Make Firefly skip every <em>n</em> times. Fill in <code>2</code>, and Firefly
|
|
||||||
will match, skip, skip and match a transaction.</span>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- select budget -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- select category -->
|
|
||||||
|
|
||||||
<!-- select beneficiary -->
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="automatch" class="col-sm-4 control-label">Auto-match</label>
|
<label for="automatch" class="col-sm-4 control-label">Auto-match</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
@ -159,25 +140,57 @@
|
|||||||
<span class="help-block">This recurring transaction is actually active.</span>
|
<span class="help-block">This recurring transaction is actually active.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<!-- panel for options -->
|
||||||
<div class="col-lg-6 col-md-12 col-sm-6">
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="fa fa-bolt"></i> Options
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="panel-body">
|
||||||
<div class="col-sm-offset-4 col-sm-8">
|
<div class="form-group">
|
||||||
<button type="submit" class="btn btn-default btn-success">Update the recurring transaction</button>
|
<label for="default" class="col-sm-4 control-label">
|
||||||
|
Update
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
{{Form::radio('post_submit_action','store',true)}}
|
||||||
|
Update the recurring transaction
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="validate_only" class="col-sm-4 control-label">
|
||||||
|
Validate only
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
{{Form::radio('post_submit_action','validate_only')}}
|
||||||
|
Only validate, do not save changes
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="return_to_form" class="col-sm-4 control-label">
|
||||||
|
Return here
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
{{Form::radio('post_submit_action','return_to_edit')}}
|
||||||
|
After update, return here again.
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{Form::close()}}
|
{{Form::close()}}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,73 +1,41 @@
|
|||||||
@extends('layouts.default')
|
@extends('layouts.default')
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
|
||||||
<p class="lead">Use recurring transactions to track repeated withdrawals</p>
|
|
||||||
<p class="text-info">We all have bills to pay. Firefly can help you organize those bills into recurring transactions,
|
|
||||||
which are exactly what the name suggests. Firefly can match new (and existing) transactions to such a recurring transaction
|
|
||||||
and help you organize these expenses into manageable groups. The front page of Firefly will show you which recurring
|
|
||||||
transactions you have missed, which are yet to come and which have been paid.</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12 col-sm-12 col-md-12">
|
<div class="col-lg-12 col-sm-12 col-md-12">
|
||||||
<table class="table table-striped">
|
<div class="panel panel-default">
|
||||||
<tr>
|
<div class="panel-heading">
|
||||||
<th>Name</th>
|
<i class="fa {{$mainTitleIcon}}"></i> {{{$title}}}
|
||||||
<th>Matches on</th>
|
</div>
|
||||||
<th>Amount between</th>
|
<div class="panel-body">
|
||||||
<th>Expected every</th>
|
<table class="table table-striped" id="recurringTable">
|
||||||
<th>Next expected match</th>
|
<thead>
|
||||||
<th>Auto-match</th>
|
<tr>
|
||||||
<th>Active</th>
|
<th>name</th>
|
||||||
<th></th>
|
<th>match</th>
|
||||||
</tr>
|
<th>amount_min</th>
|
||||||
@foreach($list as $entry)
|
<th>amount_max</th>
|
||||||
<tr>
|
<th>date</th>
|
||||||
<td><a href="{{route('recurring.show',$entry->id)}}">{{{$entry->name}}}</a></td>
|
<th>active</th>
|
||||||
<td>
|
<th>automatch</th>
|
||||||
@foreach(explode(' ',$entry->match) as $word)
|
<th>repeat_freq</th>
|
||||||
<span class="label label-info">{{{$word}}}</span>
|
<th>id</th>
|
||||||
@endforeach
|
</tr>
|
||||||
</td>
|
</thead>
|
||||||
<td>
|
</table>
|
||||||
{{mf($entry->amount_min)}} –
|
</div>
|
||||||
{{mf($entry->amount_max)}}
|
</div>
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{$entry->repeat_freq}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{$entry->next()->format('d-m-Y')}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
@if($entry->automatch)
|
|
||||||
<span class="glyphicon glyphicon-ok"></span>
|
|
||||||
@else
|
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
@if($entry->active)
|
|
||||||
<span class="glyphicon glyphicon-ok"></span>
|
|
||||||
@else
|
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group btn-group-xs">
|
|
||||||
<a href="{{route('recurring.edit',$entry->id)}}" class="btn btn-default"><span class="glyphicon glyphicon-pencil"></span></a>
|
|
||||||
<a href="{{route('recurring.delete',$entry->id)}}" class="btn btn-danger"><span class="glyphicon glyphicon-trash"></span></a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
<a href="{{route('recurring.create')}}" class="btn btn-success btn-large">Create new recurring transaction</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@stop
|
||||||
|
@section('scripts')
|
||||||
|
<script type="text/javascript">
|
||||||
|
var URL = '{{route('json.recurring')}}';
|
||||||
|
</script>
|
||||||
|
{{HTML::script('assets/javascript/typeahead/bootstrap3-typeahead.min.js')}}
|
||||||
|
{{HTML::script('assets/javascript/datatables/jquery.dataTables.min.js')}}
|
||||||
|
{{HTML::script('assets/javascript/datatables/dataTables.bootstrap.js')}}
|
||||||
|
{{HTML::script('assets/javascript/firefly/recurring.js')}}
|
||||||
|
@stop
|
||||||
|
@section('styles')
|
||||||
|
{{HTML::style('assets/stylesheets/datatables/dataTables.bootstrap.css')}}
|
||||||
@stop
|
@stop
|
@ -12,7 +12,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
<th data-dynatable-column="amount">Amount (€)</th>
|
<th>Amount (€)</th>
|
||||||
<th>From</th>
|
<th>From</th>
|
||||||
<th>To</th>
|
<th>To</th>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
|
112
public/assets/javascript/firefly/recurring.js
Normal file
112
public/assets/javascript/firefly/recurring.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
$(document).ready(function () {
|
||||||
|
$('#recurringTable').DataTable(
|
||||||
|
{
|
||||||
|
serverSide: true,
|
||||||
|
ajax: URL,
|
||||||
|
paging: true,
|
||||||
|
processing: true,
|
||||||
|
order: [],
|
||||||
|
"lengthMenu": [[50, 100, 250, -1], [50, 100, 250, "All"]],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
data: 'name',
|
||||||
|
searchable: true,
|
||||||
|
title: 'Name',
|
||||||
|
render: function (data) {
|
||||||
|
return '<a href="' + data.url + '" title="' + data.name + '">' + data.name + '</a>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'match',
|
||||||
|
data: 'match',
|
||||||
|
searchable: true,
|
||||||
|
title: 'Matches on',
|
||||||
|
render: function (data) {
|
||||||
|
var str = '';
|
||||||
|
for (x in data) {
|
||||||
|
str += '<span class="label label-info">' + data[x] + '</span> ';
|
||||||
|
}
|
||||||
|
return str;//return '<a href="' + data.url + '" title="' + data.name + '">' + data.name + '</a>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'amount_min',
|
||||||
|
data: 'amount_min',
|
||||||
|
searchable: false,
|
||||||
|
title: '→',
|
||||||
|
render: function (data) {
|
||||||
|
return '<span class="text-info">\u20AC ' + data.toFixed(2) + '</span>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'amount_max',
|
||||||
|
data: 'amount_max',
|
||||||
|
searchable: false,
|
||||||
|
title: '←',
|
||||||
|
render: function (data) {
|
||||||
|
return '<span class="text-info">\u20AC ' + data.toFixed(2) + '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'date',
|
||||||
|
data: 'date',
|
||||||
|
title: 'Expected on',
|
||||||
|
searchable: false
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'active',
|
||||||
|
data: 'active',
|
||||||
|
searchable: false,
|
||||||
|
sortable: false,
|
||||||
|
render: function(data) {
|
||||||
|
if(data == 1) {
|
||||||
|
return '<i class="fa fa-check fa-faw"></i>';
|
||||||
|
} else {
|
||||||
|
return '<i class="fa fa-remove fa-faw"></i>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: 'Is active?'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'automatch',
|
||||||
|
data: 'automatch',
|
||||||
|
sortable: false,
|
||||||
|
searchable: false,
|
||||||
|
render: function(data) {
|
||||||
|
if(data == 1) {
|
||||||
|
return '<i class="fa fa-check fa-faw"></i>';
|
||||||
|
} else {
|
||||||
|
return '<i class="fa fa-remove fa-faw"></i>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: 'Automatch?'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'repeat_freq',
|
||||||
|
data: 'repeat_freq',
|
||||||
|
searchable: false,
|
||||||
|
sortable: false,
|
||||||
|
title: 'Repeat frequency'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
data: 'id',
|
||||||
|
searchable: false,
|
||||||
|
sortable: false,
|
||||||
|
title: '',
|
||||||
|
render: function (data, type, full, meta) {
|
||||||
|
return '<div class="btn-group btn-group-xs">' +
|
||||||
|
'<a class="btn btn-default btn-xs" href="' + data.edit + '">' +
|
||||||
|
'<span class="glyphicon glyphicon-pencil"</a>' +
|
||||||
|
'<a class="btn btn-danger btn-xs" href="' + data.delete + '">' +
|
||||||
|
'<span class="glyphicon glyphicon-trash"</a>' +
|
||||||
|
'</a></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
@ -51,6 +51,7 @@ $(document).ready(function () {
|
|||||||
{
|
{
|
||||||
name: 'amount',
|
name: 'amount',
|
||||||
data: 'amount',
|
data: 'amount',
|
||||||
|
'title': 'Amount (\u20AC)',
|
||||||
searchable: false,
|
searchable: false,
|
||||||
render: function (data, type, full, meta) {
|
render: function (data, type, full, meta) {
|
||||||
if (display == 'expenses') {
|
if (display == 'expenses') {
|
||||||
@ -84,6 +85,8 @@ $(document).ready(function () {
|
|||||||
name: 'id',
|
name: 'id',
|
||||||
data: 'id',
|
data: 'id',
|
||||||
searchable: false,
|
searchable: false,
|
||||||
|
sortable: false,
|
||||||
|
title: '',
|
||||||
render: function (data, type, full, meta) {
|
render: function (data, type, full, meta) {
|
||||||
return '<div class="btn-group btn-group-xs">' +
|
return '<div class="btn-group btn-group-xs">' +
|
||||||
'<a class="btn btn-default btn-xs" href="' + data.edit + '">' +
|
'<a class="btn btn-default btn-xs" href="' + data.edit + '">' +
|
||||||
|
Loading…
Reference in New Issue
Block a user