diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php index f378bc448d..92f1a8e152 100644 --- a/app/Http/Controllers/RuleController.php +++ b/app/Http/Controllers/RuleController.php @@ -62,15 +62,45 @@ class RuleController extends Controller } /** - * @param RuleGroup $ruleGroup + * @param RuleFormRequest $request + * @param RuleRepositoryInterface $repository + * @param RuleGroup $ruleGroup * - * @return View + * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function storeRule(RuleFormRequest $request, RuleGroup $ruleGroup) + public function storeRule(RuleFormRequest $request, RuleRepositoryInterface $repository, RuleGroup $ruleGroup) { - echo '
';
-        var_dump(Input::all());
-        exit();
+
+
+        // process the rule itself:
+        $data = [
+            'rule_group_id'       => intval($request->get('rule_group_id')),
+            'title'               => $request->get('title'),
+            'trigger'             => $request->get('trigger'),
+            'description'         => $request->get('description'),
+            'rule-triggers'       => $request->get('rule-trigger'),
+            'rule-trigger-values' => $request->get('rule-trigger-value'),
+            'rule-trigger-stop'   => $request->get('rule-trigger-stop'),
+            'rule-actions'        => $request->get('rule-action'),
+            'rule-action-values'  => $request->get('rule-action-value'),
+            'rule-action-stop'    => $request->get('rule-action-stop'),
+            'stop_processing'     => $request->get('stop_processing')
+        ];
+
+        $rule = $repository->storeRule($data);
+        Session::flash('success', trans('firefly.stored_new_rule', ['title' => $rule->title]));
+        Preferences::mark();
+
+        if (intval(Input::get('create_another')) === 1) {
+            // set value so create routine will not overwrite URL:
+            Session::put('rules.rule.create.fromStore', true);
+
+            return redirect(route('rules.rule.create', [$request->input('what')]))->withInput();
+        }
+
+        // redirect to previous URL.
+        return redirect(Session::get('rules.rule.create.url'));
+
     }
 
     /**
@@ -260,9 +290,29 @@ class RuleController extends Controller
     }
 
     /**
-     * @param RuleGroup $budget
+     * @param RuleRepositoryInterface $repository
+     * @param Rule                    $rule
      *
-     * @return \Illuminate\View\View
+     * @return View
+     */
+    public function deleteRule(Rule $rule)
+    {
+        $subTitle = trans('firefly.delete_rule', ['title' => $rule->title]);
+
+        // put previous url in session
+        Session::put('rules.rule.delete.url', URL::previous());
+        Session::flash('gaEventCategory', 'rules');
+        Session::flash('gaEventAction', 'delete-rule');
+
+        return view('rules.rule.delete', compact('rule', 'subTitle'));
+    }
+
+
+    /**
+     * @param RuleRepositoryInterface $repository
+     * @param RuleGroup               $ruleGroup
+     *
+     * @return View
      */
     public function deleteRuleGroup(RuleRepositoryInterface $repository, RuleGroup $ruleGroup)
     {
@@ -279,6 +329,25 @@ class RuleController extends Controller
         return view('rules.rule-group.delete', compact('ruleGroup', 'subTitle', 'ruleGroupList'));
     }
 
+    /**
+     * @param Rule                    $rule
+     * @param RuleRepositoryInterface $repository
+     *
+     * @return \Illuminate\Http\RedirectResponse
+     */
+    public function destroyRule(RuleRepositoryInterface $repository, Rule $rule)
+    {
+
+        $title = $rule->title;
+        $repository->destroyRule($rule);
+
+        Session::flash('success', trans('firefly.deleted_rule', ['title' => $title]));
+        Preferences::mark();
+
+
+        return redirect(Session::get('rules.rule.delete.url'));
+    }
+
     /**
      * @param RuleGroup               $ruleGroup
      * @param RuleRepositoryInterface $repository
diff --git a/app/Http/Requests/RuleFormRequest.php b/app/Http/Requests/RuleFormRequest.php
index e8f18055ab..be60f0e06a 100644
--- a/app/Http/Requests/RuleFormRequest.php
+++ b/app/Http/Requests/RuleFormRequest.php
@@ -41,7 +41,7 @@ class RuleFormRequest extends Request
         $validActions  = array_keys(Config::get('firefly.rule-actions'));
 
         // some actions require text:
-        $contextActions = Config::get('firefly.rule-actions-text');
+        $contextActions = join(',', Config::get('firefly.rule-actions-text'));
 
         $titleRule = 'required|between:1,100|uniqueObjectForUser:rule_groups,title';
         if (RuleGroup::find(Input::get('id'))) {
@@ -52,12 +52,17 @@ class RuleFormRequest extends Request
             'title'                => $titleRule,
             'description'          => 'between:1,5000',
             'stop_processing'      => 'boolean',
+            'rule_group_id'        => 'required|belongsToUser:rule_groups',
             'trigger'              => 'required|in:store-journal,update-journal',
             'rule-trigger.*'       => 'required|in:' . join(',', $validTriggers),
-            'rule-trigger-value.*' => 'required|min:1',
+            'rule-trigger-value.*' => 'required|min:1|ruleTriggerValue',
             'rule-action.*'        => 'required|in:' . join(',', $validActions),
-            'rule-action-value.*'  => 'required_if:rule-action.*,' . join(',', $contextActions)
         ];
+        // since Laravel does not support this stuff yet, here's a trick.
+        for ($i = 0; $i < 10; $i++) {
+            $rules['rule-action-value.' . $i] = 'required_if:rule-action.' . $i . ',' . $contextActions . '|ruleActionValue';
+        }
 
+        return $rules;
     }
 }
diff --git a/app/Repositories/Rule/RuleRepository.php b/app/Repositories/Rule/RuleRepository.php
index dbd61abd40..2c5cc8cc5d 100644
--- a/app/Repositories/Rule/RuleRepository.php
+++ b/app/Repositories/Rule/RuleRepository.php
@@ -11,10 +11,10 @@ namespace FireflyIII\Repositories\Rule;
 
 use Auth;
 use FireflyIII\Models\Rule;
+use FireflyIII\Models\RuleAction;
 use FireflyIII\Models\RuleGroup;
 use FireflyIII\Models\RuleTrigger;
 use Illuminate\Support\Collection;
-use Log;
 
 /**
  * Class RuleRepository
@@ -80,6 +80,7 @@ class RuleRepository implements RuleRepositoryInterface
     /**
      * @param Rule  $rule
      * @param array $ids
+     *
      * @return bool
      */
     public function reorderRuleTriggers(Rule $rule, array $ids)
@@ -101,6 +102,7 @@ class RuleRepository implements RuleRepositoryInterface
     /**
      * @param Rule  $rule
      * @param array $ids
+     *
      * @return bool
      */
     public function reorderRuleActions(Rule $rule, array $ids)
@@ -172,6 +174,7 @@ class RuleRepository implements RuleRepositoryInterface
 
     /**
      * @param Rule $rule
+     *
      * @return bool
      */
     public function moveRuleUp(Rule $rule)
@@ -192,6 +195,7 @@ class RuleRepository implements RuleRepositoryInterface
 
     /**
      * @param Rule $rule
+     *
      * @return bool
      */
     public function moveRuleDown(Rule $rule)
@@ -234,6 +238,7 @@ class RuleRepository implements RuleRepositoryInterface
 
     /**
      * @param RuleGroup $ruleGroup
+     *
      * @return bool
      */
     public function moveRuleGroupUp(RuleGroup $ruleGroup)
@@ -254,6 +259,7 @@ class RuleRepository implements RuleRepositoryInterface
 
     /**
      * @param RuleGroup $ruleGroup
+     *
      * @return bool
      */
     public function moveRuleGroupDown(RuleGroup $ruleGroup)
@@ -279,4 +285,128 @@ class RuleRepository implements RuleRepositoryInterface
     {
         return Auth::user()->ruleGroups()->orderBy('order', 'ASC')->get();
     }
+
+    /**
+     * @param array $data
+     *
+     * @return Rule
+     */
+    public function storeRule(array $data)
+    {
+        /** @var RuleGroup $ruleGroup */
+        $ruleGroup = Auth::user()->ruleGroups()->find($data['rule_group_id']);
+
+        // get max order:
+        $order = $this->getHighestOrderInRuleGroup($ruleGroup);
+
+        // start by creating a new rule:
+        $rule = new Rule;
+        $rule->user()->associate(Auth::user());
+
+        $rule->rule_group_id   = $data['rule_group_id'];
+        $rule->order           = ($order + 1);
+        $rule->active          = 1;
+        $rule->stop_processing = intval($data['stop_processing']) == 1;
+        $rule->title           = $data['title'];
+        $rule->description     = strlen($data['description']) > 0 ? $data['description'] : null;
+
+        $rule->save();
+
+        // start storing triggers:
+        $order          = 1;
+        $stopProcessing = false;
+        $this->storeTrigger($rule, 'user_action', $data['trigger'], $stopProcessing, $order);
+        foreach ($data['rule-triggers'] as $index => $trigger) {
+            $value          = $data['rule-trigger-values'][$index];
+            $stopProcessing = isset($data['rule-trigger-stop'][$index]) ? true : false;
+            $this->storeTrigger($rule, $trigger, $value, $stopProcessing, $order);
+            $order++;
+        }
+
+        // same for actions.
+        $order = 1;
+        foreach ($data['rule-actions'] as $index => $action) {
+            $value          = $data['rule-action-values'][$index];
+            $stopProcessing = isset($data['rule-action-stop'][$index]) ? true : false;
+            $this->storeAction($rule, $action, $value, $stopProcessing, $order);
+        }
+
+        return $rule;
+    }
+
+    /**
+     * @param Rule   $rule
+     * @param string $action
+     * @param string $value
+     * @param bool   $stopProcessing
+     * @param int    $order
+     *
+     * @return RuleTrigger
+     */
+    public function storeTrigger(Rule $rule, $action, $value, $stopProcessing, $order)
+    {
+        $ruleTrigger = new RuleTrigger;
+        $ruleTrigger->rule()->associate($rule);
+        $ruleTrigger->order           = $order;
+        $ruleTrigger->active          = 1;
+        $ruleTrigger->stop_processing = $stopProcessing;
+        $ruleTrigger->trigger_type    = $action;
+        $ruleTrigger->trigger_value   = $value;
+        $ruleTrigger->save();
+
+        return $ruleTrigger;
+    }
+
+    /**
+     * @param Rule $rule
+     *
+     * @return bool
+     */
+    public function destroyRule(Rule $rule)
+    {
+        foreach ($rule->ruleTriggers as $trigger) {
+            $trigger->delete();
+        }
+        foreach ($rule->ruleActions as $action) {
+            $action->delete();
+        }
+        $rule->delete();
+
+        return true;
+    }
+
+
+    /**
+     * @param RuleGroup $ruleGroup
+     *
+     * @return int
+     */
+    public function getHighestOrderInRuleGroup(RuleGroup $ruleGroup)
+    {
+        return intval($ruleGroup->rules()->max('order'));
+    }
+
+    /**
+     * @param Rule   $rule
+     * @param string $action
+     * @param string $value
+     * @param bool   $stopProcessing
+     * @param int    $order
+     *
+     * @return RuleAction
+     */
+    public function storeAction(Rule $rule, $action, $value, $stopProcessing, $order)
+    {
+        $ruleAction = new RuleAction;
+        $ruleAction->rule()->associate($rule);
+        $ruleAction->order           = $order;
+        $ruleAction->active          = 1;
+        $ruleAction->stop_processing = $stopProcessing;
+        $ruleAction->action_type     = $action;
+        $ruleAction->action_value    = $value;
+        $ruleAction->save();
+
+
+        return $ruleAction;
+    }
 }
\ No newline at end of file
diff --git a/app/Repositories/Rule/RuleRepositoryInterface.php b/app/Repositories/Rule/RuleRepositoryInterface.php
index 429cf79911..7980a473e1 100644
--- a/app/Repositories/Rule/RuleRepositoryInterface.php
+++ b/app/Repositories/Rule/RuleRepositoryInterface.php
@@ -10,7 +10,9 @@
 namespace FireflyIII\Repositories\Rule;
 
 use FireflyIII\Models\Rule;
+use FireflyIII\Models\RuleAction;
 use FireflyIII\Models\RuleGroup;
+use FireflyIII\Models\RuleTrigger;
 use Illuminate\Support\Collection;
 
 /**
@@ -46,10 +48,17 @@ interface RuleRepositoryInterface
      * @param RuleGroup $ruleGroup
      * @param RuleGroup $moveTo
      *
-     * @return boolean
+     * @return bool
      */
     public function destroyRuleGroup(RuleGroup $ruleGroup, RuleGroup $moveTo = null);
 
+    /**
+     * @param Rule $rule
+     *
+     * @return bool
+     */
+    public function destroyRule(Rule $rule);
+
     /**
      * @param Rule $rule
      * @param array $ids
@@ -103,4 +112,41 @@ interface RuleRepositoryInterface
      */
     public function getRuleGroups();
 
+    /**
+     * @param array $data
+     *
+     * @return Rule
+     */
+    public function storeRule(array $data);
+
+    /**
+     * @param RuleGroup $ruleGroup
+     *
+     * @return int
+     */
+    public function getHighestOrderInRuleGroup(RuleGroup $ruleGroup);
+
+
+    /**
+     * @param Rule $rule
+     * @param string $action
+     * @param string $value
+     * @param bool $stopProcessing
+     * @param int $order
+     *
+     * @return RuleTrigger
+     */
+    public function storeTrigger(Rule $rule, $action, $value, $stopProcessing, $order);
+
+    /**
+     * @param Rule $rule
+     * @param string $action
+     * @param string $value
+     * @param bool $stopProcessing
+     * @param int $order
+     *
+     * @return RuleAction
+     */
+    public function storeAction(Rule $rule, $action, $value, $stopProcessing, $order);
+
 }
\ No newline at end of file
diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php
index 1503518a1d..4d1b62321e 100644
--- a/app/Validation/FireflyValidator.php
+++ b/app/Validation/FireflyValidator.php
@@ -8,7 +8,9 @@ use Crypt;
 use DB;
 use FireflyIII\Models\Account;
 use FireflyIII\Models\AccountType;
+use FireflyIII\Models\Budget;
 use FireflyIII\Models\PiggyBank;
+use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
 use FireflyIII\User;
 use Illuminate\Contracts\Encryption\DecryptException;
 use Illuminate\Validation\Validator;
@@ -39,7 +41,71 @@ class FireflyValidator extends Validator
      * @param $value
      * @param $parameters
      *
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     * @return bool
+     */
+    public function validateRuleTriggerValue($attribute, $value, $parameters)
+    {
+        // loop all rule-triggers.
+        // check if rule-value matches the thing.
+        if (is_array($this->data['rule-trigger'])) {
+            foreach ($this->data['rule-trigger'] as $index => $name) {
+                $value = $this->data['rule-trigger-value'][$index] ?? false;
+                switch ($name) {
+                    default:
+                        return true;
+                    case 'amount_less':
+                        return is_numeric($value);
+                        break;
+                    case 'transaction_type':
+                        echo 'Implement me!';
+                        exit;
+                        break;
+                }
+            }
+        }
+    }
+
+    /**
+     * @param $attribute
+     * @param $value
+     * @param $parameters
+     *
+     * @return bool
+     */
+    public function validateRuleActionValue($attribute, $value, $parameters)
+    {
+        // loop all rule-actions.
+        // check if rule-action-value matches the thing.
+        if (is_array($this->data['rule-action'])) {
+            foreach ($this->data['rule-action'] as $index => $name) {
+                $value = $this->data['rule-action-value'][$index] ?? false;
+                switch ($name) {
+                    default:
+                        return true;
+                    case 'set_budget':
+                        /** @var BudgetRepositoryInterface $repository */
+                        $repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
+                        $budgets    = $repository->getBudgets();
+                        // count budgets, should have at least one
+                        $count = $budgets->filter(
+                            function (Budget $budget) use ($value) {
+                                return $budget->name == $value;
+                            }
+                        )->count();
+
+                        return ($count === 1);
+                }
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * @param $attribute
+     * @param $value
+     * @param $parameters
      *
      * @return bool
      */
diff --git a/public/js/rules/create-edit.js b/public/js/rules/create-edit.js
index 6ba0fa2c2f..13c4027f10 100644
--- a/public/js/rules/create-edit.js
+++ b/public/js/rules/create-edit.js
@@ -30,7 +30,7 @@ function addNewTrigger() {
 
 function addNewAction() {
     "use strict";
-    triggerCount++;
+    actionCount++;
 
     $.getJSON('json/action', {count: actionCount}).success(function (data) {
         //console.log(data.html);
diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php
index b48de632fb..39cc843309 100644
--- a/resources/lang/en_US/firefly.php
+++ b/resources/lang/en_US/firefly.php
@@ -62,6 +62,8 @@ return [
     'save_rules_by_moving'      => 'Save these rule(s) by moving them to another rule group:',
     'make_new_rule'             => 'Make new rule in rule group ":title"',
     'rule_help_stop_processing' => 'When you check this box, later rules in this group will not be executed.',
+    'stored_new_rule'           => 'Stored new rule with title ":title"',
+    'deleted_rule'              => 'Deleted rule with title ":title"',
 
     'trigger'                            => 'Trigger',
     'trigger_value'                      => 'Trigger on value',
diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php
index a8d6c60f32..ec273e435e 100644
--- a/resources/lang/en_US/form.php
+++ b/resources/lang/en_US/form.php
@@ -78,12 +78,14 @@ return [
     'delete_currency'   => 'Delete currency ":name"',
     'delete_journal'    => 'Delete transaction with description ":description"',
     'delete_attachment' => 'Delete attachment ":name"',
+    'delete_rule'       => 'Delete rule ":title"',
     'delete_rule_group' => 'Delete rule group ":title"',
 
     'attachment_areYouSure' => 'Are you sure you want to delete the attachment named ":name"?',
     'account_areYouSure'    => 'Are you sure you want to delete the account named ":name"?',
     'bill_areYouSure'       => 'Are you sure you want to delete the bill named ":name"?',
-    'ruleGroup_areYouSure'  => 'Are you sure you want to delete the rule group titles ":title"?',
+    'rule_areYouSure'       => 'Are you sure you want to delete the rule titled ":title"?',
+    'ruleGroup_areYouSure'  => 'Are you sure you want to delete the rule group titled ":title"?',
     'budget_areYouSure'     => 'Are you sure you want to delete the budget named ":name"?',
     'category_areYouSure'   => 'Are you sure you want to delete the category named ":name"?',
     'currency_areYouSure'   => 'Are you sure you want to delete the currency named ":name"?',
diff --git a/resources/lang/en_US/validation.php b/resources/lang/en_US/validation.php
index 21dbc4ed0e..88e58d3a19 100644
--- a/resources/lang/en_US/validation.php
+++ b/resources/lang/en_US/validation.php
@@ -1,6 +1,8 @@
  'This value is invalid for the selected trigger.',
+    'rule_action_value'       => 'This value is invalid for the selected action.',
     'invalid_domain'          => 'Due to security constraints, you cannot register from this domain.',
     'file_already_attached'   => 'Uploaded file ":name" is already attached to this object.',
     'file_attached'           => 'Succesfully uploaded file ":name".',
diff --git a/resources/views/rules/rule/delete.twig b/resources/views/rules/rule/delete.twig
new file mode 100644
index 0000000000..45571583a4
--- /dev/null
+++ b/resources/views/rules/rule/delete.twig
@@ -0,0 +1,33 @@
+
+{% extends "./layout/default.twig" %}
+
+{% block breadcrumbs %}
+    {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, rule) }}
+{% endblock %}
+
+{% block content %}
+    {{ Form.open({'class' : 'form-horizontal','id' : 'destroy','url' : route('rules.rule.destroy',rule.id) }) }}
+    
+
+
+
+

{{ trans('form.delete_rule', {'title': rule.title}) }}

+
+
+

+ {{ trans('form.permDeleteWarning') }} +

+ +

+ {{ trans('form.rule_areYouSure', {'title': rule.title}) }} +

+
+ +
+
+
+ {{ Form.close|raw }} +{% endblock %}