Merge branch 'feature/rules' into develop

This commit is contained in:
James Cole 2016-01-12 20:39:49 +01:00
commit 48551e8bf5
16 changed files with 520 additions and 3 deletions

View File

@ -0,0 +1,34 @@
<?php
/**
* RuleController.php
* Copyright (C) 2016 Sander Dorigo
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace FireflyIII\Http\Controllers;
use FireflyIII\Http\Requests;
use View;
/**
* Class RuleController
*
* @package FireflyIII\Http\Controllers
*/
class RuleController extends Controller
{
public function __construct()
{
parent::__construct();
View::share('title', trans('firefly.rules'));
View::share('mainTitleIcon', 'fa-random');
}
public function index()
{
return view('rules.index');
}
}

View File

@ -361,6 +361,16 @@ Breadcrumbs::register(
}
);
/**
* Rules
*/
Breadcrumbs::register(
'rules.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.rules'), route('rules.index'));
}
);
// search
Breadcrumbs::register(
'search', function (BreadCrumbGenerator $breadcrumbs, $query) {

View File

@ -242,6 +242,11 @@ Route::group(
Route::get('/reports', ['uses' => 'ReportController@index', 'as' => 'reports.index']);
Route::get('/reports/report/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'ReportController@report', 'as' => 'reports.report']);
/**
* Rules Controller
*/
Route::get('/rules', ['uses' => 'RuleController@index', 'as' => 'rules.index']);
/**
* Search Controller
*/

View File

@ -34,7 +34,6 @@ use Watson\Validating\ValidatingTrait;
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account hasMetaValue($name, $value)
* @property string $startBalance
* @property string $endBalance
*
*/
class Account extends Model
{

View File

@ -27,6 +27,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property-read Account $account
* @property-read Collection|PiggyBankRepetition[] $piggyBankRepetitions
* @property-read Collection|PiggyBankEvent[] $piggyBankEvents
* @property string $reminder
*/
class PiggyBank extends Model
{

71
app/Models/Rule.php Normal file
View File

@ -0,0 +1,71 @@
<?php
/**
* Rule.php
* Copyright (C) 2016 Sander Dorigo
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace FireflyIII\Models;
use Crypt;
use Illuminate\Database\Eloquent\Model;
/**
* Class Rule
*
* @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $deleted_at
* @property integer $user_id
* @property integer $rule_group_id
* @property integer $order
* @property string $title
* @property string $description
* @property boolean $active
* @property boolean $stop_processing
* @property-read \FireflyIII\User $user
* @property-read \FireflyIII\Models\RuleGroup $ruleGroup
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\RuleAction[] $ruleActions
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\RuleTrigger[] $ruleTriggers
*/
class Rule extends Model
{
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('FireflyIII\User');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function ruleGroup()
{
return $this->belongsTo('FireflyIII\Models\RuleGroup');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function ruleActions()
{
return $this->hasMany('FireflyIII\Models\RuleAction');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function ruleTriggers()
{
return $this->hasMany('FireflyIII\Models\RuleTrigger');
}
}

39
app/Models/RuleAction.php Normal file
View File

@ -0,0 +1,39 @@
<?php
/**
* RuleAction.php
* Copyright (C) 2016 Sander Dorigo
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* Class RuleAction
*
* @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $rule_id
* @property integer $order
* @property boolean $active
* @property boolean $stop_processing
* @property string $action_field
* @property string $action
* @property string $action_value
* @property-read \FireflyIII\Models\Rule $rule
*/
class RuleAction extends Model
{
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function rule()
{
return $this->belongsTo('FireflyIII\Models\Rule');
}
}

48
app/Models/RuleGroup.php Normal file
View File

@ -0,0 +1,48 @@
<?php
/**
* RuleGroup.php
* Copyright (C) 2016 Sander Dorigo
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* Class RuleGroup
*
* @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $deleted_at
* @property integer $user_id
* @property integer $order
* @property string $title
* @property string $description
* @property boolean $active
* @property-read \FireflyIII\User $user
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Rule[] $rules
*/
class RuleGroup extends Model
{
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('FireflyIII\User');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function rules()
{
return $this->hasMany('FireflyIII\Models\Rule');
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* RuleTrigger.php
* Copyright (C) 2016 Sander Dorigo
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* FireflyIII\Models\RuleTrigger
*
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $rule_id
* @property integer $order
* @property string $title
* @property string $trigger_type
* @property string $trigger_value
* @property boolean $active
* @property boolean $stop_processing
* @property-read \FireflyIII\Models\Rule $rule
*/
class RuleTrigger extends Model
{
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function rule()
{
return $this->belongsTo('FireflyIII\Models\Rule');
}
}

View File

@ -9,6 +9,24 @@ use Zizaco\Entrust\Traits\EntrustUserTrait;
* Class User
*
* @package FireflyIII
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $email
* @property string $password
* @property string $remember_token
* @property string $reset
* @property boolean $blocked
* @property string $blocked_code
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Account[] $accounts
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Attachment[] $attachments
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Tag[] $tags
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Bill[] $bills
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Category[] $categories
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Preference[] $preferences
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Role[] $roles
*/
class User extends Authenticatable
{

View File

@ -169,4 +169,47 @@ return [
],
'bindables' => [
// models
'account' => 'FireflyIII\Models\Account',
'attachment' => 'FireflyIII\Models\Attachment',
'bill' => 'FireflyIII\Models\Bill',
'budget' => 'FireflyIII\Models\Budget',
'category' => 'FireflyIII\Models\Category',
'currency' => 'FireflyIII\Models\TransactionCurrency',
'limitrepetition' => 'FireflyIII\Models\LimitRepetition',
'piggyBank' => 'FireflyIII\Models\PiggyBank',
'tj' => 'FireflyIII\Models\TransactionJournal',
'tag' => 'FireflyIII\Models\Tag',
// lists
'accountList' => 'FireflyIII\Support\Binder\AccountList',
'budgetList' => 'FireflyIII\Support\Binder\BudgetList',
'categoryList' => 'FireflyIII\Support\Binder\CategoryList',
// others
'start_date' => 'FireflyIII\Support\Binder\Date',
'end_date' => 'FireflyIII\Support\Binder\Date'
],
'rule-triggers' => [
'from_account_starts' => 'FireflyIII\Rules\Triggers',
'from_account_ends' => 'FireflyIII\Rules\Triggers',
'from_account_is' => 'FireflyIII\Rules\Triggers',
'from_account_contains' => 'FireflyIII\Rules\Triggers',
'to_account_starts' => 'FireflyIII\Rules\Triggers',
'to_account_ends' => 'FireflyIII\Rules\Triggers',
'to_account_is' => 'FireflyIII\Rules\Triggers',
'to_account_contains' => 'FireflyIII\Rules\Triggers',
'transaction_type' => 'FireflyIII\Rules\Triggers',
'amount_less' => 'FireflyIII\Rules\Triggers',
'amount_exactly' => 'FireflyIII\Rules\Triggers',
'amount_exactly_not' => 'FireflyIII\Rules\Triggers',
'amount_more' => 'FireflyIII\Rules\Triggers',
'description_starts' => 'FireflyIII\Rules\Triggers',
'description_ends' => 'FireflyIII\Rules\Triggers',
'description_contains' => 'FireflyIII\Rules\Triggers',
'description_is' => 'FireflyIII\Rules\Triggers',
],
];

View File

@ -0,0 +1,133 @@
<?php
/**
* 2016_01_11_193428_changes_for_v370.php
* Copyright (C) 2016 Sander Dorigo
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class ChangesForV370
*/
class ChangesForV370 extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// new table "rule_groups"
Schema::create(
'rule_groups', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->integer('user_id')->unsigned();
$table->unsignedSmallInteger('order');
$table->string('title', 255);
$table->text('description');
$table->unsignedTinyInteger('active')->default(1);
// connect rule groups to users
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
// order must be unique for rule group:
$table->unique(['user_id', 'order']);
}
);
// new table "rules":
Schema::create(
'rules', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->integer('user_id')->unsigned();
$table->integer('rule_group_id')->unsigned();
$table->unsignedSmallInteger('order');
$table->string('title', 255);
$table->text('description');
$table->unsignedTinyInteger('active')->default(1);
$table->unsignedTinyInteger('stop_processing')->default(0);
// connect rules to users
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
// connect rules to rule groups
$table->foreign('rule_group_id')->references('id')->on('rule_groups')->onDelete('cascade');
// order must be unique for rules:
$table->unique(['user_id', 'order']);
}
);
// new table "rule_triggers"
Schema::create(
'rule_triggers', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('rule_id')->unsigned();
$table->unsignedSmallInteger('order');
$table->string('title', 2048);
$table->string('trigger_type', 50);
$table->string('trigger_value', 255);
$table->unsignedTinyInteger('active')->default(1);
$table->unsignedTinyInteger('stop_processing')->default(0);
// order must be unique for rule triggers:
$table->unique(['rule_id', 'order']);
// connect rule triggers to rules
$table->foreign('rule_id')->references('id')->on('rules')->onDelete('cascade');
}
);
// new table "rule_actions"
Schema::create(
'rule_actions', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('rule_id')->unsigned();
$table->unsignedSmallInteger('order');
$table->unsignedTinyInteger('active')->default(1);
$table->unsignedTinyInteger('stop_processing')->default(0);
$table->string('action_field', 50);
$table->string('action', 50);
$table->string('action_value', 255);
// connect rule actions to rules
$table->foreign('rule_id')->references('id')->on('rules')->onDelete('cascade');
// order must be unique for rule triggers:
$table->unique(['rule_id', 'order']);
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('rule_actions');
Schema::drop('rule_triggers');
Schema::drop('rules');
Schema::drop('rule_groups');
}
}

View File

@ -10,6 +10,9 @@ use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Role;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
@ -33,6 +36,52 @@ class TestDataSeeder extends Seeder
public function __construct()
{
}
public function createRules()
{
// basic rules group. user should always have one
$ruleGroup = new RuleGroup;
$ruleGroup->user()->associate($this->user);
$ruleGroup->order = 1;
$ruleGroup->title = 'Default rules';
$ruleGroup->description = 'All your rules not in a particular group.';
$ruleGroup->active = 1;
$ruleGroup->save();
// a normal rule: saves transactions where description contains "groceries"
// and from account is "MyBank Checking Account"
// send it to Groceries/Groceries
$rule = new Rule;
$rule->user()->associate($this->user);
$rule->ruleGroup()->associate($ruleGroup);
$rule->order = 1;
$rule->title = 'A strange rule for testing.';
$rule->description = 'This rule triggers on transactions with the description "David Bowie" and puts them in the category "Blackstar".';
$rule->active = 1;
$rule->stop_processing = 0;
$rule->save();
// trigger for this rule:
$ruleTrigger = new RuleTrigger;
$ruleTrigger->rule()->associate($rule);
$ruleTrigger->order = 1;
$ruleTrigger->title = 'Groceries';
$ruleTrigger->trigger_type = 'description_contains';
$ruleTrigger->trigger_value = 'groceries';
$ruleTrigger->active = 1;
$ruleTrigger->stop_processing = 0;
// actions for this rule.
// TODO a rule that triggers on something, just like the previous one, but it has "stop_processing" set to 1.
// TODO a rule that triggers on that same thing, but it will not file, because the previous rule made FF skip it.
// TODO rule with specific actions.
// TODO rule with actions and one action has stop_processing and other actions are not processed. Somewhere in test?
}
/**
@ -49,6 +98,8 @@ class TestDataSeeder extends Seeder
$this->createBills();
$this->createPiggybanks();
$this->createRules();
// preference to only see account #1 on frontpage.
$this->createPreferences();
@ -649,7 +700,7 @@ class TestDataSeeder extends Seeder
$fromAccount = $this->findAccount('MyBank Checking Account');
$stores = ['Albert Heijn', 'PLUS', 'Bakker'];
$descriptions = ['Groceries', 'Bought some food', 'Got groceries'];
$descriptions = ['Groceries', 'Bought some groceries', 'Got groceries'];
$category = Category::firstOrCreateEncrypted(['name' => 'Daily groceries', 'user_id' => $this->user->id]);
$budget = Budget::firstOrCreateEncrypted(['name' => 'Groceries', 'user_id' => $this->user->id]);

View File

@ -38,6 +38,9 @@ return [
'new_budget' => 'New budget',
'new_bill' => 'New bill',
// rules
'rules' => 'Rules',
// tags
'store_new_tag' => 'Store new tag',
'update_tag' => 'Update tag',

View File

@ -86,7 +86,7 @@
</li>
<!-- money management -->
<li class="{{ activeRoutePartial('bills') }} {{ activeRoutePartial('piggy-banks') }} treeview">
<li class="{{ activeRoutePartial('bills') }} {{ activeRoutePartial('piggy-banks') }} {{ activeRoutePartial('rules') }} treeview">
<a href="#">
<i class="fa fa-euro fa-fw"></i>
<span>{{ 'moneyManagement'|_ }}</span>
@ -101,6 +101,10 @@
<a href="{{ route('bills.index') }}">
<i class="fa fa-calendar-o fa-fw"></i> {{ 'bills'|_ }}</a>
</li>
<li class="{{ activeRoutePartial('rules') }}">
<a href="{{ route('rules.index') }}">
<i class="fa fa-random fa-fw"></i> {{ 'rules'|_ }}</a>
</li>
</ul>
</li>

View File

@ -0,0 +1,20 @@
{% extends "./layout/default.twig" %}
{% block breadcrumbs %}
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">{{ 'rules'|_ }}</h3>
</div>
<div class="box-body">
Bla bla bla
</div>
</div>
</div>
</div>
{% endblock %}