mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-23 14:26:58 +00:00
Stuff for recurring transactions [skip ci]
This commit is contained in:
0
app/assets/javascripts/firefly/recurring.js
Normal file
0
app/assets/javascripts/firefly/recurring.js
Normal file
14
app/assets/javascripts/recurring.js
Normal file
14
app/assets/javascripts/recurring.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
||||||
|
// listed below.
|
||||||
|
//
|
||||||
|
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
||||||
|
// can be referenced here using a relative path.
|
||||||
|
//
|
||||||
|
// It's not advisable to add code directly here, but if you do, it'll appear in whatever order it
|
||||||
|
// gets included (e.g. say you have require_tree . then the code will appear after all the directories
|
||||||
|
// but before any files alphabetically greater than 'application.js'
|
||||||
|
//
|
||||||
|
// The available directives right now are require, require_directory, and require_tree
|
||||||
|
//
|
||||||
|
//= require tagsinput/bootstrap-tagsinput.min
|
||||||
|
//= require firefly/recurring
|
48
app/assets/javascripts/tagsinput/bootstrap-tagsinput.css
vendored
Executable file
48
app/assets/javascripts/tagsinput/bootstrap-tagsinput.css
vendored
Executable file
@@ -0,0 +1,48 @@
|
|||||||
|
.bootstrap-tagsinput {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px 6px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #555;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-radius: 4px;
|
||||||
|
max-width: 100%;
|
||||||
|
line-height: 22px;
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
.bootstrap-tagsinput input {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
outline: none;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
width: auto !important;
|
||||||
|
max-width: inherit;
|
||||||
|
}
|
||||||
|
.bootstrap-tagsinput input:focus {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.bootstrap-tagsinput .tag {
|
||||||
|
margin-right: 2px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.bootstrap-tagsinput .tag [data-role="remove"] {
|
||||||
|
margin-left: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.bootstrap-tagsinput .tag [data-role="remove"]:after {
|
||||||
|
content: "x";
|
||||||
|
padding: 0px 2px;
|
||||||
|
}
|
||||||
|
.bootstrap-tagsinput .tag [data-role="remove"]:hover {
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
|
||||||
|
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-tagsinput {width:100%;}
|
7
app/assets/javascripts/tagsinput/bootstrap-tagsinput.min.js
vendored
Executable file
7
app/assets/javascripts/tagsinput/bootstrap-tagsinput.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
13
app/assets/stylesheets/recurring.css
Normal file
13
app/assets/stylesheets/recurring.css
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
||||||
|
* listed below.
|
||||||
|
*
|
||||||
|
* Any Css/Less files within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
||||||
|
* can be referenced here using a relative path.
|
||||||
|
*
|
||||||
|
* It's not advisable to add code directly here, but if you do, it'll appear in whatever order it
|
||||||
|
* gets included (e.g. say you have require_tree . then the code will appear after all the directories
|
||||||
|
* but before any files alphabetically greater than 'application.css'
|
||||||
|
*
|
||||||
|
*= require tagsinput/bootstrap-tagsinput
|
||||||
|
*/
|
@@ -5,21 +5,36 @@ use Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface
|
|||||||
class RecurringController extends BaseController
|
class RecurringController extends BaseController
|
||||||
{
|
{
|
||||||
protected $_repository;
|
protected $_repository;
|
||||||
|
|
||||||
public function __construct(RTR $repository)
|
public function __construct(RTR $repository)
|
||||||
{
|
{
|
||||||
$this->_repository = $repository;
|
$this->_repository = $repository;
|
||||||
View::share('menu', 'home');
|
View::share('menu', 'home');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
|
$periods = \Config::get('firefly.periods_to_text');
|
||||||
|
|
||||||
|
return View::make('recurring.create')->with('periods', $periods);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete()
|
public function delete(RecurringTransaction $recurringTransaction)
|
||||||
{
|
{
|
||||||
|
return View::make('recurring.delete')->with('recurringTransaction', $recurringTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy()
|
public function destroy(RecurringTransaction $recurringTransaction)
|
||||||
{
|
{
|
||||||
|
$result = $this->_repository->destroy($recurringTransaction);
|
||||||
|
if ($result === true) {
|
||||||
|
Session::flash('success', 'The recurring transaction was deleted.');
|
||||||
|
} else {
|
||||||
|
Session::flash('error', 'Could not delete the recurring transaction. Check the logs to be sure.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redirect::route('recurring.index');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function edit()
|
public function edit()
|
||||||
@@ -29,7 +44,8 @@ class RecurringController extends BaseController
|
|||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$list = $this->_repository->get();
|
$list = $this->_repository->get();
|
||||||
return View::make('recurring.index');
|
|
||||||
|
return View::make('recurring.index')->with('list', $list);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show()
|
public function show()
|
||||||
@@ -38,6 +54,21 @@ class RecurringController extends BaseController
|
|||||||
|
|
||||||
public function store()
|
public function store()
|
||||||
{
|
{
|
||||||
|
$recurringTransaction = $this->_repository->store(Input::all());
|
||||||
|
if ($recurringTransaction->id) {
|
||||||
|
Session::flash('success', 'Recurring transaction "' . $recurringTransaction->name . '" saved!');
|
||||||
|
if (Input::get('create') == '1') {
|
||||||
|
return Redirect::route('recurring.create')->withInput();
|
||||||
|
} else {
|
||||||
|
return Redirect::route('recurring.index');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Session::flash(
|
||||||
|
'error', 'Could not save the recurring transaction: ' . $recurringTransaction->errors()->first()
|
||||||
|
);
|
||||||
|
|
||||||
|
return Redirect::route('recurring.create')->withInput()->withErrors($recurringTransaction->errors());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update()
|
public function update()
|
||||||
|
@@ -134,7 +134,7 @@ class Budget implements BudgetInterface
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (count($inRepetition) > 0) {
|
||||||
$query = $budget->transactionjournals()->with(
|
$query = $budget->transactionjournals()->with(
|
||||||
'transactions', 'transactions.account', 'components', 'transactiontype',
|
'transactions', 'transactions.account', 'components', 'transactiontype',
|
||||||
'transactions.account.accounttype'
|
'transactions.account.accounttype'
|
||||||
@@ -143,6 +143,14 @@ class Budget implements BudgetInterface
|
|||||||
)->orderBy('date', 'DESC')->orderBy(
|
)->orderBy('date', 'DESC')->orderBy(
|
||||||
'transaction_journals.id', 'DESC'
|
'transaction_journals.id', 'DESC'
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
$query = $budget->transactionjournals()->with(
|
||||||
|
'transactions', 'transactions.account', 'components', 'transactiontype',
|
||||||
|
'transactions.account.accounttype'
|
||||||
|
)->orderBy('date', 'DESC')->orderBy(
|
||||||
|
'transaction_journals.id', 'DESC'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// build paginator:
|
// build paginator:
|
||||||
$perPage = 25;
|
$perPage = 25;
|
||||||
|
@@ -124,7 +124,7 @@ class EloquentBudgetRepository implements BudgetRepositoryInterface
|
|||||||
}
|
}
|
||||||
$limit->startdate = $startDate;
|
$limit->startdate = $startDate;
|
||||||
$limit->amount = $data['amount'];
|
$limit->amount = $data['amount'];
|
||||||
$limit->repeats = $data['repeats'];
|
$limit->repeats = isset($data['repeats']) ? $data['repeats'] : 0;
|
||||||
$limit->repeat_freq = $data['repeat_freq'];
|
$limit->repeat_freq = $data['repeat_freq'];
|
||||||
if ($limit->validate()) {
|
if ($limit->validate()) {
|
||||||
$limit->save();
|
$limit->save();
|
||||||
|
@@ -7,9 +7,41 @@ use Carbon\Carbon;
|
|||||||
|
|
||||||
class EloquentRecurringTransactionRepository implements RecurringTransactionRepositoryInterface
|
class EloquentRecurringTransactionRepository implements RecurringTransactionRepositoryInterface
|
||||||
{
|
{
|
||||||
|
public function destroy(\RecurringTransaction $recurringTransaction) {
|
||||||
|
$recurringTransaction->delete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public function get() {
|
public function get()
|
||||||
|
{
|
||||||
return \Auth::user()->recurringtransactions()->get();
|
return \Auth::user()->recurringtransactions()->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function store($data)
|
||||||
|
{
|
||||||
|
$recurringTransaction = new \RecurringTransaction;
|
||||||
|
$recurringTransaction->user()->associate(\Auth::user());
|
||||||
|
$recurringTransaction->name = $data['name'];
|
||||||
|
$recurringTransaction->match = join(' ', explode(',', $data['match']));
|
||||||
|
$recurringTransaction->amount_max = floatval($data['amount_max']);
|
||||||
|
$recurringTransaction->amount_min = floatval($data['amount_min']);
|
||||||
|
|
||||||
|
// both amounts zero:
|
||||||
|
if($recurringTransaction->amount_max == 0 && $recurringTransaction->amount_min == 0) {
|
||||||
|
$recurringTransaction->errors()->add('amount_max','Amount max and min cannot both be zero.');
|
||||||
|
return $recurringTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
$recurringTransaction->date = new Carbon($data['date']);
|
||||||
|
$recurringTransaction->active = isset($data['active']) ? intval($data['active']) : 0;
|
||||||
|
$recurringTransaction->automatch = isset($data['automatch']) ? intval($data['automatch']) : 0;
|
||||||
|
$recurringTransaction->skip = isset($data['skip']) ? intval($data['skip']) : 0;
|
||||||
|
$recurringTransaction->repeat_freq = $data['repeat_freq'];
|
||||||
|
|
||||||
|
if($recurringTransaction->validate()) {
|
||||||
|
$recurringTransaction->save();
|
||||||
|
}
|
||||||
|
return $recurringTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -9,5 +9,9 @@ interface RecurringTransactionRepositoryInterface
|
|||||||
|
|
||||||
public function get();
|
public function get();
|
||||||
|
|
||||||
|
public function store($data);
|
||||||
|
|
||||||
|
public function destroy(\RecurringTransaction $recurringTransaction);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@@ -392,7 +392,9 @@ class EloquentTransactionJournalRepository implements TransactionJournalReposito
|
|||||||
|
|
||||||
// do budget:
|
// do budget:
|
||||||
$budget = $budRepository->find($data['budget_id']);
|
$budget = $budRepository->find($data['budget_id']);
|
||||||
|
if(!is_null($budget)) {
|
||||||
$journal->budgets()->attach($budget);
|
$journal->budgets()->attach($budget);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'Deposit':
|
case 'Deposit':
|
||||||
|
@@ -25,9 +25,45 @@ class RecurringTransaction extends Ardent
|
|||||||
'data' => 'string'
|
'data' => 'string'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function getDates()
|
||||||
|
{
|
||||||
|
return ['created_at', 'updated_at', 'date'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next()
|
||||||
|
{
|
||||||
|
$start = clone $this->date;
|
||||||
|
$skip = $this->skip == 0 ? 1 : $this->skip;
|
||||||
|
|
||||||
|
while ($start <= $this->date) {
|
||||||
|
switch ($this->repeat_freq) {
|
||||||
|
case 'daily':
|
||||||
|
$start->addDays($skip);
|
||||||
|
break;
|
||||||
|
case 'weekly':
|
||||||
|
$start->addWeeks($skip);
|
||||||
|
break;
|
||||||
|
case 'monthly':
|
||||||
|
$start->addMonths($skip);
|
||||||
|
break;
|
||||||
|
case 'quarterly':
|
||||||
|
$start->addMonths($skip);
|
||||||
|
break;
|
||||||
|
case 'half-year':
|
||||||
|
$start->addMonths($skip * 6);
|
||||||
|
break;
|
||||||
|
case 'yearly':
|
||||||
|
$this->addYears($skip);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $start;
|
||||||
|
}
|
||||||
|
|
||||||
public function user()
|
public function user()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('User');
|
return $this->belongsTo('User');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -20,6 +20,17 @@ Route::bind('accountname', function($value, $route)
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Route::bind('recurring', function($value, $route)
|
||||||
|
{
|
||||||
|
if(Auth::check()) {
|
||||||
|
return RecurringTransaction::
|
||||||
|
where('id', $value)->
|
||||||
|
where('user_id',Auth::user()->id)->first();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
Route::bind('budget', function($value, $route)
|
Route::bind('budget', function($value, $route)
|
||||||
{
|
{
|
||||||
if(Auth::check()) {
|
if(Auth::check()) {
|
||||||
@@ -136,6 +147,9 @@ Route::group(['before' => 'auth'], function () {
|
|||||||
|
|
||||||
// recurring transactions controller
|
// recurring transactions controller
|
||||||
Route::get('/recurring',['uses' => 'RecurringController@index', 'as' => 'recurring.index']);
|
Route::get('/recurring',['uses' => 'RecurringController@index', 'as' => 'recurring.index']);
|
||||||
|
Route::get('/recurring/create',['uses' => 'RecurringController@create', 'as' => 'recurring.create']);
|
||||||
|
Route::get('/recurring/edit/{recurring}',['uses' => 'RecurringController@edit','as' => 'recurring.edit']);
|
||||||
|
Route::get('/recurring/delete/{recurring}',['uses' => 'RecurringController@delete','as' => 'recurring.delete']);
|
||||||
|
|
||||||
// transaction controller:
|
// transaction controller:
|
||||||
Route::get('/transactions/create/{what}', ['uses' => 'TransactionController@create', 'as' => 'transactions.create'])->where(['what' => 'withdrawal|deposit|transfer']);
|
Route::get('/transactions/create/{what}', ['uses' => 'TransactionController@create', 'as' => 'transactions.create'])->where(['what' => 'withdrawal|deposit|transfer']);
|
||||||
@@ -187,6 +201,11 @@ Route::group(['before' => 'csrf|auth'], function () {
|
|||||||
// profile controller
|
// profile controller
|
||||||
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword']);
|
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword']);
|
||||||
|
|
||||||
|
// recurring controller
|
||||||
|
Route::post('/recurring/store',['uses' => 'RecurringController@store', 'as' => 'recurring.store']);
|
||||||
|
Route::post('/recurring/update/{recurring}',['uses' => 'RecurringController@update','as' => 'recurring.update']);
|
||||||
|
Route::post('/recurring/destroy/{recurring}',['uses' => 'RecurringController@destroy','as' => 'recurring.destroy']);
|
||||||
|
|
||||||
// transaction controller:
|
// transaction controller:
|
||||||
Route::post('/transactions/store/{what}', ['uses' => 'TransactionController@store', 'as' => 'transactions.store'])->where(['what' => 'withdrawal|deposit|transfer']);
|
Route::post('/transactions/store/{what}', ['uses' => 'TransactionController@store', 'as' => 'transactions.store'])->where(['what' => 'withdrawal|deposit|transfer']);
|
||||||
Route::post('/transaction/update/{tj}',['uses' => 'TransactionController@update','as' => 'transactions.update']);
|
Route::post('/transaction/update/{tj}',['uses' => 'TransactionController@update','as' => 'transactions.update']);
|
||||||
|
@@ -35,7 +35,7 @@
|
|||||||
<td>Out</td>
|
<td>Out</td>
|
||||||
<td>
|
<td>
|
||||||
{{mf($show['statistics']['period']['out'])}}
|
{{mf($show['statistics']['period']['out'])}}
|
||||||
<a href="#transactions-thisaccount-this-period-expensesonly"><span class="glyphicon glyphicon-circle-arrow-right"></span></a>
|
<a href="{{route('accounts.show',$account->id)}}#transactions-thisaccount-this-period-expensesonly"><span class="glyphicon glyphicon-circle-arrow-right"></span></a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{mf($show['statistics']['period']['t_out'])}}
|
{{mf($show['statistics']['period']['t_out'])}}
|
||||||
|
@@ -74,7 +74,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<small>
|
<small>
|
||||||
|
<a href="{{route('budgets.show',$budget->id)}}?rep={{$rep->id}}">
|
||||||
{{$rep->periodShow()}}
|
{{$rep->periodShow()}}
|
||||||
|
</a>
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
@if($limit->repeats == 1)
|
@if($limit->repeats == 1)
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
<td>
|
<td>
|
||||||
@foreach($journal->components as $component)
|
@foreach($journal->components as $component)
|
||||||
@if($component->class == 'Budget')
|
@if($component->class == 'Budget')
|
||||||
<a href="#budget-overview-in-month"><span class="glyphicon glyphicon-tasks" title="Budget: {{{$component->name}}}"></span></a>
|
<a href="{{route('budgets.show',$component->id)}}#GETTHEREPSOMEHOW_ORLIMITQUERYbudget-overview-in-month"><span class="glyphicon glyphicon-tasks" title="Budget: {{{$component->name}}}"></span></a>
|
||||||
@endif
|
@endif
|
||||||
@if($component->class == 'Category')
|
@if($component->class == 'Category')
|
||||||
<a href="#category-overview-in-month"><span class="glyphicon glyphicon-tag" title="Category: {{{$component->name}}}"></span></a>
|
<a href="#category-overview-in-month"><span class="glyphicon glyphicon-tag" title="Category: {{{$component->name}}}"></span></a>
|
||||||
|
196
app/views/recurring/create.blade.php
Normal file
196
app/views/recurring/create.blade.php
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
@extends('layouts.default')
|
||||||
|
@section('content')
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||||
|
<h1>Firefly
|
||||||
|
<small>Create a recurring transaction</small>
|
||||||
|
</h1>
|
||||||
|
<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')])}}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6 col-md-12 col-sm-6">
|
||||||
|
<h4>Mandatory fields</h4>
|
||||||
|
|
||||||
|
<!-- name -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name" class="col-sm-4 control-label">Name</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="text" name="name" class="form-control" id="name" value="{{Input::old('name')}}" placeholder="Name">
|
||||||
|
@if($errors->has('name'))
|
||||||
|
<p class="text-danger">{{$errors->first('name')}}</p>
|
||||||
|
@else
|
||||||
|
<span class="help-block">For example: rent, gas, insurance</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="match" class="col-sm-4 control-label">Matches on</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="text" name="match" class="form-control" id="match" value="{{Input::old('match')}}" data-role="tagsinput">
|
||||||
|
@if($errors->has('match'))
|
||||||
|
<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
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
{{ Form::label('amount_min', 'Minimum amount', ['class' => 'col-sm-4 control-label'])}}
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon">€</span>
|
||||||
|
{{Form::input('number','amount_min', Input::old('amount_min'), ['step' => 'any', 'class' => 'form-control'])}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($errors->has('amount_min'))
|
||||||
|
<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
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
{{ Form::label('amount_max', 'Maximum amount', ['class' => 'col-sm-4 control-label'])}}
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon">€</span>
|
||||||
|
{{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>
|
||||||
|
@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
|
||||||
|
</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') ?: date('Y-m-d'), ['class'
|
||||||
|
=> '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 class="col-lg-6 col-md-12 col-sm-6">
|
||||||
|
<h4>Optional fields</h4>
|
||||||
|
|
||||||
|
<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'])}}
|
||||||
|
|
||||||
|
@if($errors->has('skip'))
|
||||||
|
<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
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- select budget -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- select category -->
|
||||||
|
|
||||||
|
<!-- select beneficiary -->
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="automatch" class="col-sm-4 control-label">Auto-match</label>
|
||||||
|
<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 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>
|
||||||
|
|
||||||
|
{{Form::close()}}
|
||||||
|
|
||||||
|
|
||||||
|
@stop
|
||||||
|
@section('styles')
|
||||||
|
<?php echo stylesheet_link_tag('recurring'); ?>
|
||||||
|
@stop
|
||||||
|
@section('scripts')
|
||||||
|
<?php echo javascript_include_tag('recurring'); ?>
|
||||||
|
|
||||||
|
@stop
|
37
app/views/recurring/delete.blade.php
Normal file
37
app/views/recurring/delete.blade.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
@extends('layouts.default')
|
||||||
|
@section('content')
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||||
|
<h1>Firefly
|
||||||
|
<small>Delete recurring transaction "{{{$recurringTransaction->name}}}"</small>
|
||||||
|
</h1>
|
||||||
|
<p class="lead">
|
||||||
|
Remember that deleting something is permanent.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{Form::open(['class' => 'form-horizontal','url' => route('recurring.destroy',$recurringTransaction->id)])}}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||||
|
<p class="text-danger">
|
||||||
|
Press "Delete permanently" If you are sure you want to delete "{{{$recurringTransaction->name}}}".
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<button type="submit" class="btn btn-default btn-danger">Delete permanently</button>
|
||||||
|
<a href="{{route('recurring.index')}}" class="btn-default btn">Cancel</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{{Form::close()}}
|
||||||
|
@stop
|
@@ -5,6 +5,7 @@
|
|||||||
<h1>Firefly
|
<h1>Firefly
|
||||||
<small>Recurring transactions</small>
|
<small>Recurring transactions</small>
|
||||||
</h1>
|
</h1>
|
||||||
|
<p class="lead">Use recurring transactions to track repeated expenses</p>
|
||||||
<p class="text-info">We all have bills to pay. Firefly can help you organize those bills into recurring transactions,
|
<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
|
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
|
and help you organize these expenses into manageable groups. The front page of Firefly will show you which recurring
|
||||||
@@ -22,10 +23,54 @@
|
|||||||
<th>Amount between</th>
|
<th>Amount between</th>
|
||||||
<th>Expected every</th>
|
<th>Expected every</th>
|
||||||
<th>Next expected match</th>
|
<th>Next expected match</th>
|
||||||
<th>Automatch</th>
|
<th>Auto-match</th>
|
||||||
<th>Active</th>
|
<th>Active</th>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@foreach($list as $entry)
|
||||||
|
<tr>
|
||||||
|
<td><a href="#">{{{$entry->name}}}</a></td>
|
||||||
|
<td>
|
||||||
|
@foreach(explode(' ',$entry->match) as $word)
|
||||||
|
<span class="label label-default">{{{$word}}}</span>
|
||||||
|
@endforeach
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{mf($entry->amount_min)}} –
|
||||||
|
{{mf($entry->amount_max)}}
|
||||||
|
</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>
|
</table>
|
||||||
|
<p>
|
||||||
|
<a href="{{route('recurring.create')}}" class="btn btn-success btn-large">Create new recurring transaction</a>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@stop
|
@stop
|
Reference in New Issue
Block a user