diff --git a/app/Generator/Report/Account/MonthReportGenerator.php b/app/Generator/Report/Account/MonthReportGenerator.php
index 49f0cbfbd7..4693e71c0d 100644
--- a/app/Generator/Report/Account/MonthReportGenerator.php
+++ b/app/Generator/Report/Account/MonthReportGenerator.php
@@ -44,7 +44,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
      * Generate the report.
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function generate(): string
     {
diff --git a/app/Generator/Report/Audit/MonthReportGenerator.php b/app/Generator/Report/Audit/MonthReportGenerator.php
index 278190c1cb..666738d73a 100644
--- a/app/Generator/Report/Audit/MonthReportGenerator.php
+++ b/app/Generator/Report/Audit/MonthReportGenerator.php
@@ -51,7 +51,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
      * Generates the report.
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function generate(): string
     {
diff --git a/app/Generator/Report/Budget/MonthReportGenerator.php b/app/Generator/Report/Budget/MonthReportGenerator.php
index ff4229ab26..dc9d47c244 100644
--- a/app/Generator/Report/Budget/MonthReportGenerator.php
+++ b/app/Generator/Report/Budget/MonthReportGenerator.php
@@ -64,7 +64,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
      * Generates the report.
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function generate(): string
     {
diff --git a/app/Generator/Report/Category/MonthReportGenerator.php b/app/Generator/Report/Category/MonthReportGenerator.php
index ef187a575b..8957ca3020 100644
--- a/app/Generator/Report/Category/MonthReportGenerator.php
+++ b/app/Generator/Report/Category/MonthReportGenerator.php
@@ -68,7 +68,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
      * Generates the report.
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function generate(): string
     {
diff --git a/app/Generator/Report/Standard/MonthReportGenerator.php b/app/Generator/Report/Standard/MonthReportGenerator.php
index e27f4d79ed..987b0ec304 100644
--- a/app/Generator/Report/Standard/MonthReportGenerator.php
+++ b/app/Generator/Report/Standard/MonthReportGenerator.php
@@ -43,7 +43,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
      * Generates the report.
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function generate(): string
     {
diff --git a/app/Generator/Report/Standard/MultiYearReportGenerator.php b/app/Generator/Report/Standard/MultiYearReportGenerator.php
index ec507b9386..69174d06b8 100644
--- a/app/Generator/Report/Standard/MultiYearReportGenerator.php
+++ b/app/Generator/Report/Standard/MultiYearReportGenerator.php
@@ -42,7 +42,7 @@ class MultiYearReportGenerator implements ReportGeneratorInterface
      * Generates the report.
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function generate(): string
     {
diff --git a/app/Generator/Report/Standard/YearReportGenerator.php b/app/Generator/Report/Standard/YearReportGenerator.php
index 47f92f47ad..ef844a4a85 100644
--- a/app/Generator/Report/Standard/YearReportGenerator.php
+++ b/app/Generator/Report/Standard/YearReportGenerator.php
@@ -42,7 +42,7 @@ class YearReportGenerator implements ReportGeneratorInterface
      * Generates the report.
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function generate(): string
     {
diff --git a/app/Generator/Report/Tag/MonthReportGenerator.php b/app/Generator/Report/Tag/MonthReportGenerator.php
index 1c5affa011..2242381c2d 100644
--- a/app/Generator/Report/Tag/MonthReportGenerator.php
+++ b/app/Generator/Report/Tag/MonthReportGenerator.php
@@ -70,8 +70,8 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
      * Generate the report.
      *
      * @return string
-     * @throws \Throwable
-     * @throws \Throwable
+
+
      */
     public function generate(): string
     {
diff --git a/app/Helpers/Update/UpdateTrait.php b/app/Helpers/Update/UpdateTrait.php
index 64a02b4a51..3d755163b7 100644
--- a/app/Helpers/Update/UpdateTrait.php
+++ b/app/Helpers/Update/UpdateTrait.php
@@ -32,7 +32,6 @@ use Log;
 /**
  * Trait UpdateTrait
  *
- * @package FireflyIII\Helpers\Update
  */
 trait UpdateTrait
 {
diff --git a/app/Http/Controllers/DebugController.php b/app/Http/Controllers/DebugController.php
index 7a70eb50cd..1054918950 100644
--- a/app/Http/Controllers/DebugController.php
+++ b/app/Http/Controllers/DebugController.php
@@ -177,6 +177,8 @@ class DebugController extends Controller
 
     /**
      * @return string
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function routes(): string
     {
diff --git a/app/Http/Controllers/ExportController.php b/app/Http/Controllers/ExportController.php
index 6b45211868..1a532a86ee 100644
--- a/app/Http/Controllers/ExportController.php
+++ b/app/Http/Controllers/ExportController.php
@@ -130,6 +130,8 @@ class ExportController extends Controller
      * @param ExportJobRepositoryInterface $jobs
      *
      * @return JsonResponse
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function postIndex(ExportFormRequest $request, AccountRepositoryInterface $repository, ExportJobRepositoryInterface $jobs): JsonResponse
     {
diff --git a/app/Http/Controllers/HelpController.php b/app/Http/Controllers/HelpController.php
index 3ef04f6969..93ec561d28 100644
--- a/app/Http/Controllers/HelpController.php
+++ b/app/Http/Controllers/HelpController.php
@@ -68,6 +68,8 @@ class HelpController extends Controller
      * @param string $language
      *
      * @return string
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     private function getHelpText(string $route, string $language): string
     {
diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php
index 71d3ec36a3..0cb4a1472a 100644
--- a/app/Http/Controllers/HomeController.php
+++ b/app/Http/Controllers/HomeController.php
@@ -26,8 +26,6 @@ use Carbon\Carbon;
 use FireflyIII\Events\RequestedVersionCheckStatus;
 use FireflyIII\Helpers\Collector\JournalCollectorInterface;
 use FireflyIII\Http\Middleware\Installer;
-use FireflyIII\Http\Middleware\IsDemoUser;
-use FireflyIII\Http\Middleware\IsSandStormUser;
 use FireflyIII\Models\AccountType;
 use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 use FireflyIII\Repositories\Bill\BillRepositoryInterface;
@@ -36,7 +34,6 @@ use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Illuminate\Support\Collection;
 use Log;
-use View;
 
 /**
  * Class HomeController.
@@ -52,9 +49,6 @@ class HomeController extends Controller
         app('view')->share('title', 'Firefly III');
         app('view')->share('mainTitleIcon', 'fa-fire');
         $this->middleware(Installer::class);
-        $this->middleware(IsDemoUser::class)->except(['dateRange', 'index']);
-        $this->middleware(IsSandStormUser::class)->only('routes');
-
     }
 
     /**
@@ -98,7 +92,7 @@ class HomeController extends Controller
     /**
      * @param AccountRepositoryInterface $repository
      *
-     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
+     * @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
      */
     public function index(AccountRepositoryInterface $repository)
     {
@@ -110,10 +104,7 @@ class HomeController extends Controller
         }
         $subTitle     = (string)trans('firefly.welcomeBack');
         $transactions = [];
-        $frontPage    = app('preferences')->get(
-            'frontPageAccounts',
-            $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])->pluck('id')->toArray()
-        );
+        $frontPage    = app('preferences')->get('frontPageAccounts', $repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray());
         /** @var Carbon $start */
         $start = session('start', Carbon::now()->startOfMonth());
         /** @var Carbon $end */
@@ -122,7 +113,6 @@ class HomeController extends Controller
         $accounts = $repository->getAccountsById($frontPage->data);
         $today    = new Carbon;
 
-        // zero bills? Hide some elements from view.
         /** @var BillRepositoryInterface $billRepository */
         $billRepository = app(BillRepositoryInterface::class);
         $billCount      = $billRepository->getBills()->count();
@@ -134,15 +124,11 @@ class HomeController extends Controller
             $transactions[] = [$set, $account];
         }
 
-        // fire check update event:
         /** @var User $user */
         $user = auth()->user();
         event(new RequestedVersionCheckStatus($user));
 
-        return view(
-            'index',
-            compact('count', 'subTitle', 'transactions', 'billCount', 'start', 'end', 'today')
-        );
+        return view('index', compact('count', 'subTitle', 'transactions', 'billCount', 'start', 'end', 'today'));
     }
 
 }
diff --git a/app/Http/Controllers/Import/IndexController.php b/app/Http/Controllers/Import/IndexController.php
index 5c5b8dddc6..27c83fa0b6 100644
--- a/app/Http/Controllers/Import/IndexController.php
+++ b/app/Http/Controllers/Import/IndexController.php
@@ -22,13 +22,12 @@ declare(strict_types=1);
 
 namespace FireflyIII\Http\Controllers\Import;
 
-use FireflyIII\Exceptions\FireflyException;
 use FireflyIII\Http\Controllers\Controller;
 use FireflyIII\Import\Prerequisites\PrerequisitesInterface;
 use FireflyIII\Models\ImportJob;
 use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
 use FireflyIII\Repositories\User\UserRepositoryInterface;
-use FireflyIII\User;
+use FireflyIII\Support\Binder\ImportProvider;
 use Illuminate\Http\Response as LaravelResponse;
 use Log;
 
@@ -37,9 +36,10 @@ use Log;
  */
 class IndexController extends Controller
 {
+    /** @var array */
+    public $providers;
     /** @var ImportJobRepositoryInterface */
     public $repository;
-
     /** @var UserRepositoryInterface */
     public $userRepository;
 
@@ -56,6 +56,7 @@ class IndexController extends Controller
                 app('view')->share('title', (string)trans('firefly.import_index_title'));
                 $this->repository     = app(ImportJobRepositoryInterface::class);
                 $this->userRepository = app(UserRepositoryInterface::class);
+                $this->providers      = ImportProvider::getProviders();
 
                 return $next($request);
             }
@@ -69,57 +70,44 @@ class IndexController extends Controller
      *
      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
      *
-     * @throws FireflyException
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function create(string $importProvider)
     {
         Log::debug(sprintf('Will create job for provider "%s"', $importProvider));
-        // can only create "fake" for demo user.
-        $providers = array_keys($this->getProviders());
-        if (!\in_array($importProvider, $providers, true)) {
-            Log::error(sprintf('%s-provider is disabled. Cannot create job.', $importProvider));
-            session()->flash('warning', (string)trans('import.cannot_create_for_provider', ['provider' => $importProvider]));
-
-            return redirect(route('import.index'));
-        }
 
         $importJob = $this->repository->create($importProvider);
-        Log::debug(sprintf('Created job #%d for provider %s', $importJob->id, $importProvider));
-
         $hasPreReq = (bool)config(sprintf('import.has_prereq.%s', $importProvider));
         $hasConfig = (bool)config(sprintf('import.has_job_config.%s', $importProvider));
-        // if job provider has no prerequisites:
-        if (false === $hasPreReq) {
+
+        Log::debug(sprintf('Created job #%d for provider %s', $importJob->id, $importProvider));
+
+        // no prerequisites and no config:
+        if (false === $hasPreReq && false === $hasConfig) {
+            Log::debug('Provider needs no configuration for job. Job is ready to start.');
+            $this->repository->updateStatus($importJob, 'ready_to_run');
+            Log::debug('Redirect to status-page.');
+
+            return redirect(route('import.job.status.index', [$importJob->key]));
+        }
+
+        // no prerequisites but job has config:
+        if (false === $hasPreReq && false !== $hasConfig) {
             Log::debug('Provider has no prerequisites. Continue.');
-            // if job provider also has no configuration:
-            if (false === $hasConfig) {
-                // @codeCoverageIgnoreStart
-                Log::debug('Provider needs no configuration for job. Job is ready to start.');
-                $this->repository->updateStatus($importJob, 'ready_to_run');
-                Log::debug('Redirect to status-page.');
-
-                return redirect(route('import.job.status.index', [$importJob->key]));
-                // @codeCoverageIgnoreEnd
-            }
-
-            // update job to say "has_prereq".
             $this->repository->setStatus($importJob, 'has_prereq');
-
-            // redirect to job configuration.
             Log::debug('Redirect to configuration.');
 
             return redirect(route('import.job.configuration.index', [$importJob->key]));
         }
+
+        // job has prerequisites:
         Log::debug('Job provider has prerequisites.');
-        // if need to set prerequisites, do that first.
-        $class = (string)config(sprintf('import.prerequisites.%s', $importProvider));
-        if (!class_exists($class)) {
-            throw new FireflyException(sprintf('No class to handle prerequisites for "%s".', $importProvider)); // @codeCoverageIgnore
-        }
         /** @var PrerequisitesInterface $providerPre */
-        $providerPre = app($class);
+        $providerPre = app((string)config(sprintf('import.prerequisites.%s', $importProvider)));
         $providerPre->setUser($importJob->user);
 
+        // and are not filled in:
         if (!$providerPre->isComplete()) {
             Log::debug('Job provider prerequisites are not yet filled in. Redirect to prerequisites-page.');
 
@@ -128,8 +116,10 @@ class IndexController extends Controller
         }
         Log::debug('Prerequisites are complete.');
 
-        // update job to say "has_prereq".
+        // but are filled in:
         $this->repository->setStatus($importJob, 'has_prereq');
+
+        // and has no config:
         if (false === $hasConfig) {
             // @codeCoverageIgnoreStart
             Log::debug('Provider has no configuration. Job is ready to start.');
@@ -139,6 +129,8 @@ class IndexController extends Controller
             return redirect(route('import.job.status.index', [$importJob->key]));
             // @codeCoverageIgnoreEnd
         }
+
+        // but also needs config:
         Log::debug('Job has configuration. Redirect to job-config.');
 
         // Otherwise just redirect to job configuration.
@@ -184,62 +176,10 @@ class IndexController extends Controller
      */
     public function index()
     {
-        $providers    = $this->getProviders();
+        $providers    = $this->providers;
         $subTitle     = (string)trans('import.index_breadcrumb');
         $subTitleIcon = 'fa-home';
 
         return view('import.index', compact('subTitle', 'subTitleIcon', 'providers'));
     }
-
-    /**
-     * @return array
-     */
-    private function getProviders(): array
-    {
-        // get and filter all import routines:
-        /** @var User $user */
-        $user = auth()->user();
-        /** @var array $config */
-        $providerNames = array_keys(config('import.enabled'));
-        $providers     = [];
-        $isDemoUser    = $this->userRepository->hasRole($user, 'demo');
-        $isDebug       = (bool)config('app.debug');
-        foreach ($providerNames as $providerName) {
-            //Log::debug(sprintf('Now with provider %s', $providerName));
-            // only consider enabled providers
-            $enabled        = (bool)config(sprintf('import.enabled.%s', $providerName));
-            $allowedForDemo = (bool)config(sprintf('import.allowed_for_demo.%s', $providerName));
-            $allowedForUser = (bool)config(sprintf('import.allowed_for_user.%s', $providerName));
-            if (false === $enabled) {
-                //Log::debug('Provider is not enabled. NEXT!');
-                continue;
-            }
-
-            if (true === $isDemoUser && false === $allowedForDemo) {
-                //Log::debug('User is demo and this provider is not allowed for demo user. NEXT!');
-                continue;
-            }
-            if (false === $isDemoUser && false === $allowedForUser && false === $isDebug) {
-                //Log::debug('User is not demo and this provider is not allowed for such users. NEXT!');
-                continue; // @codeCoverageIgnore
-            }
-
-            $providers[$providerName] = [
-                'has_prereq' => (bool)config('import.has_prereq.' . $providerName),
-            ];
-            $class                    = (string)config(sprintf('import.prerequisites.%s', $providerName));
-            $result                   = false;
-            if ('' !== $class && class_exists($class)) {
-                //Log::debug('Will not check prerequisites.');
-                /** @var PrerequisitesInterface $object */
-                $object = app($class);
-                $object->setUser($user);
-                $result = $object->isComplete();
-            }
-            $providers[$providerName]['prereq_complete'] = $result;
-        }
-        Log::debug(sprintf('Enabled providers: %s', json_encode(array_keys($providers))));
-
-        return $providers;
-    }
 }
diff --git a/app/Http/Controllers/Import/JobConfigurationController.php b/app/Http/Controllers/Import/JobConfigurationController.php
index e68cafc78a..ae5daddcf3 100644
--- a/app/Http/Controllers/Import/JobConfigurationController.php
+++ b/app/Http/Controllers/Import/JobConfigurationController.php
@@ -66,11 +66,13 @@ class JobConfigurationController extends Controller
      * @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
      *
      * @throws FireflyException
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     *
      */
     public function index(ImportJob $importJob)
     {
         Log::debug('Now in JobConfigurationController::index()');
-        // catch impossible status:
         $allowed = ['has_prereq', 'need_job_config'];
         if (null !== $importJob && !\in_array($importJob->status, $allowed, true)) {
             Log::debug(sprintf('Job has state "%s", but we only accept %s', $importJob->status, json_encode($allowed)));
@@ -91,10 +93,7 @@ class JobConfigurationController extends Controller
             // @codeCoverageIgnoreEnd
         }
 
-        // create configuration class:
         $configurator = $this->makeConfigurator($importJob);
-
-        // is the job already configured?
         if ($configurator->configurationComplete()) {
             Log::debug('Config is complete, set status to ready_to_run.');
             $this->repository->updateStatus($importJob, 'ready_to_run');
@@ -119,6 +118,8 @@ class JobConfigurationController extends Controller
      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
      *
      * @throws FireflyException
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function post(Request $request, ImportJob $importJob)
     {
diff --git a/app/Http/Controllers/Import/PrerequisitesController.php b/app/Http/Controllers/Import/PrerequisitesController.php
index 709d0cc2fe..c705286b95 100644
--- a/app/Http/Controllers/Import/PrerequisitesController.php
+++ b/app/Http/Controllers/Import/PrerequisitesController.php
@@ -22,7 +22,6 @@ declare(strict_types=1);
 
 namespace FireflyIII\Http\Controllers\Import;
 
-use FireflyIII\Exceptions\FireflyException;
 use FireflyIII\Http\Controllers\Controller;
 use FireflyIII\Import\Prerequisites\PrerequisitesInterface;
 use FireflyIII\Models\ImportJob;
@@ -68,7 +67,8 @@ class PrerequisitesController extends Controller
      * @param ImportJob $importJob
      *
      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
-     * @throws FireflyException
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function index(string $importProvider, ImportJob $importJob = null)
     {
@@ -83,9 +83,6 @@ class PrerequisitesController extends Controller
 
         app('view')->share('subTitle', (string)trans('import.prerequisites_breadcrumb_' . $importProvider));
         $class = (string)config(sprintf('import.prerequisites.%s', $importProvider));
-        if (!class_exists($class)) {
-            throw new FireflyException(sprintf('No class to handle prerequisites for "%s".', $importProvider)); // @codeCoverageIgnore
-        }
         /** @var User $user */
         $user = auth()->user();
         /** @var PrerequisitesInterface $object */
@@ -121,8 +118,8 @@ class PrerequisitesController extends Controller
      * @param ImportJob $importJob
      *
      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
-     *
-     * @throws FireflyException
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function post(Request $request, string $importProvider, ImportJob $importJob = null)
     {
@@ -139,9 +136,6 @@ class PrerequisitesController extends Controller
 
 
         $class = (string)config(sprintf('import.prerequisites.%s', $importProvider));
-        if (!class_exists($class)) {
-            throw new FireflyException(sprintf('Cannot find class %s', $class)); // @codeCoverageIgnore
-        }
         /** @var User $user */
         $user = auth()->user();
         /** @var PrerequisitesInterface $object */
diff --git a/app/Http/Controllers/JavascriptController.php b/app/Http/Controllers/JavascriptController.php
index 28568aedd1..fe38a461ae 100644
--- a/app/Http/Controllers/JavascriptController.php
+++ b/app/Http/Controllers/JavascriptController.php
@@ -136,6 +136,7 @@ class JavascriptController extends Controller
 
     /**
      * @return array
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     private function getDateRangeConfig(): array
     {
diff --git a/app/Http/Controllers/Json/AutoCompleteController.php b/app/Http/Controllers/Json/AutoCompleteController.php
index 9472195946..081a76641a 100644
--- a/app/Http/Controllers/Json/AutoCompleteController.php
+++ b/app/Http/Controllers/Json/AutoCompleteController.php
@@ -39,6 +39,9 @@ use Illuminate\Http\JsonResponse;
 
 /**
  * Class AutoCompleteController.
+ *
+ * @SuppressWarnings(PHPMD.TooManyPublicMethods)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class AutoCompleteController extends Controller
 {
diff --git a/app/Http/Controllers/Json/BoxController.php b/app/Http/Controllers/Json/BoxController.php
index 50302790a9..5b0a1f4275 100644
--- a/app/Http/Controllers/Json/BoxController.php
+++ b/app/Http/Controllers/Json/BoxController.php
@@ -22,13 +22,13 @@ declare(strict_types=1);
 
 namespace FireflyIII\Http\Controllers\Json;
 
-use Amount;
 use Carbon\Carbon;
 use FireflyIII\Helpers\Collector\JournalCollectorInterface;
 use FireflyIII\Http\Controllers\Controller;
 use FireflyIII\Models\Account;
 use FireflyIII\Models\AccountType;
 use FireflyIII\Models\Transaction;
+use FireflyIII\Models\TransactionCurrency;
 use FireflyIII\Models\TransactionType;
 use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 use FireflyIII\Repositories\Bill\BillRepositoryInterface;
@@ -47,6 +47,8 @@ class BoxController extends Controller
      * @param BudgetRepositoryInterface $repository
      *
      * @return JsonResponse
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function available(BudgetRepositoryInterface $repository): JsonResponse
     {
@@ -99,6 +101,8 @@ class BoxController extends Controller
      * @param CurrencyRepositoryInterface $repository
      *
      * @return JsonResponse
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function balance(CurrencyRepositoryInterface $repository): JsonResponse
     {
@@ -150,17 +154,18 @@ class BoxController extends Controller
         }
 
         // format amounts:
-        foreach ($sums as $currencyId => $amount) {
+        $keys = array_keys($sums);
+        foreach ($keys as $currencyId) {
             $currency              = $repository->findNull($currencyId);
-            $sums[$currencyId]     = Amount::formatAnything($currency, $sums[$currencyId], false);
-            $incomes[$currencyId]  = Amount::formatAnything($currency, $incomes[$currencyId] ?? '0', false);
-            $expenses[$currencyId] = Amount::formatAnything($currency, $expenses[$currencyId] ?? '0', false);
+            $sums[$currencyId]     = app('amount')->formatAnything($currency, $sums[$currencyId], false);
+            $incomes[$currencyId]  = app('amount')->formatAnything($currency, $incomes[$currencyId] ?? '0', false);
+            $expenses[$currencyId] = app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false);
         }
         if (0 === \count($sums)) {
             $currency                = app('amount')->getDefaultCurrency();
-            $sums[$currency->id]     = Amount::formatAnything($currency, '0', false);
-            $incomes[$currency->id]  = Amount::formatAnything($currency, '0', false);
-            $expenses[$currency->id] = Amount::formatAnything($currency, '0', false);
+            $sums[$currency->id]     = app('amount')->formatAnything($currency, '0', false);
+            $incomes[$currency->id]  = app('amount')->formatAnything($currency, '0', false);
+            $expenses[$currency->id] = app('amount')->formatAnything($currency, '0', false);
         }
 
         $response = [
@@ -214,28 +219,23 @@ class BoxController extends Controller
 
 
     /**
-     * @param AccountRepositoryInterface  $repository
-     *
-     * @param CurrencyRepositoryInterface $currencyRepos
+     * @param AccountRepositoryInterface $repository
      *
      * @return JsonResponse
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
-    public function netWorth(AccountRepositoryInterface $repository, CurrencyRepositoryInterface $currencyRepos): JsonResponse
+    public function netWorth(AccountRepositoryInterface $repository): JsonResponse
     {
         $date = new Carbon(date('Y-m-d')); // needed so its per day.
-        /** @var Carbon $start */
-        $start = session('start', Carbon::now()->startOfMonth());
-        /** @var Carbon $end */
-        $end = session('end', Carbon::now()->endOfMonth());
 
         // start and end in the future? use $end
-        if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
-            $date = $end;
-        }
-        // start and end in the past? use $end
-        if ($start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date)) {
-            $date = $end;
+        if ($this->notInSessionRange($date)) {
+            /** @var Carbon $date */
+            $date = session('end', Carbon::now()->endOfMonth());
         }
+
         // start in the past, end in the future? use $date
         $cache = new CacheProperties;
         $cache->addProperty($date);
@@ -245,20 +245,13 @@ class BoxController extends Controller
         }
         $netWorth = [];
         $accounts = $repository->getActiveAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
-        $currency = app('amount')->getDefaultCurrency();
+
         $balances = app('steam')->balancesByAccounts($accounts, $date);
 
         /** @var Account $account */
         foreach ($accounts as $account) {
-            $accountCurrency = null;
+            $accountCurrency = $this->getCurrencyOrDefault($account);
             $balance         = $balances[$account->id] ?? '0';
-            $currencyId      = (int)$repository->getMetaValue($account, 'currency_id');
-            if (0 !== $currencyId) {
-                $accountCurrency = $currencyRepos->findNull($currencyId);
-            }
-            if (null === $accountCurrency) {
-                $accountCurrency = $currency;
-            }
 
             // if the account is a credit card, subtract the virtual balance from the balance,
             // to better reflect that this is not money that is actually "yours".
@@ -287,4 +280,53 @@ class BoxController extends Controller
 
         return response()->json($return);
     }
+
+    /**
+     * @param Account $account
+     *
+     * @return TransactionCurrency
+     */
+    private function getCurrencyOrDefault(Account $account): TransactionCurrency
+    {
+        /** @var AccountRepositoryInterface $repository */
+        $repository = app(AccountRepositoryInterface::class);
+        /** @var CurrencyRepositoryInterface $currencyRepos */
+        $currencyRepos = app(CurrencyRepositoryInterface::class);
+
+        $currency        = app('amount')->getDefaultCurrency();
+        $accountCurrency = null;
+        $currencyId      = (int)$repository->getMetaValue($account, 'currency_id');
+        if (0 !== $currencyId) {
+            $accountCurrency = $currencyRepos->findNull($currencyId);
+        }
+        if (null === $accountCurrency) {
+            $accountCurrency = $currency;
+        }
+
+        return $accountCurrency;
+    }
+
+    /**
+     * @param Carbon $date
+     *
+     * @return bool
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    private function notInSessionRange(Carbon $date): bool
+    {
+        /** @var Carbon $start */
+        $start = session('start', Carbon::now()->startOfMonth());
+        /** @var Carbon $end */
+        $end    = session('end', Carbon::now()->endOfMonth());
+        $result = false;
+        if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
+            $result = true;
+        }
+        // start and end in the past? use $end
+        if ($start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date)) {
+            $result = true;
+        }
+
+        return $result;
+    }
 }
diff --git a/app/Http/Controllers/Json/FrontpageController.php b/app/Http/Controllers/Json/FrontpageController.php
index c7bf29ec73..b6021c3917 100644
--- a/app/Http/Controllers/Json/FrontpageController.php
+++ b/app/Http/Controllers/Json/FrontpageController.php
@@ -36,7 +36,7 @@ class FrontpageController extends Controller
      * @param PiggyBankRepositoryInterface $repository
      *
      * @return JsonResponse
-     * @throws \Throwable
+
      */
     public function piggyBanks(PiggyBankRepositoryInterface $repository): JsonResponse
     {
diff --git a/app/Http/Controllers/Json/IntroController.php b/app/Http/Controllers/Json/IntroController.php
index 13dd03262c..354310e15a 100644
--- a/app/Http/Controllers/Json/IntroController.php
+++ b/app/Http/Controllers/Json/IntroController.php
@@ -158,6 +158,7 @@ class IntroController
      * @param string $specificPage
      *
      * @return array
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     private function getSpecificSteps(string $route, string $specificPage): array
     {
diff --git a/app/Http/Controllers/Json/ReconcileController.php b/app/Http/Controllers/Json/ReconcileController.php
index a837a210c4..f1e64fefda 100644
--- a/app/Http/Controllers/Json/ReconcileController.php
+++ b/app/Http/Controllers/Json/ReconcileController.php
@@ -42,6 +42,8 @@ use Illuminate\Support\Collection;
 /**
  *
  * Class ReconcileController
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class ReconcileController extends Controller
 {
@@ -84,7 +86,10 @@ class ReconcileController extends Controller
      * @return JsonResponse
      *
      * @throws FireflyException
-     * @throws \Throwable
+
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function overview(Request $request, Account $account, Carbon $start, Carbon $end): JsonResponse
     {
@@ -140,7 +145,7 @@ class ReconcileController extends Controller
      * @return mixed
      *
      * @throws FireflyException
-     * @throws \Throwable
+
      */
     public function transactions(Account $account, Carbon $start, Carbon $end)
     {
diff --git a/app/Http/Controllers/Json/RecurrenceController.php b/app/Http/Controllers/Json/RecurrenceController.php
new file mode 100644
index 0000000000..0192e4f099
--- /dev/null
+++ b/app/Http/Controllers/Json/RecurrenceController.php
@@ -0,0 +1,175 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Http\Controllers\Json;
+
+
+use Carbon\Carbon;
+use FireflyIII\Exceptions\FireflyException;
+use FireflyIII\Http\Controllers\Controller;
+use FireflyIII\Models\RecurrenceRepetition;
+use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+
+/**
+ * Class RecurrenceController
+ */
+class RecurrenceController extends Controller
+{
+    /** @var RecurringRepositoryInterface */
+    private $recurring;
+
+    /**
+     *
+     */
+    public function __construct()
+    {
+        parent::__construct();
+
+        // translations:
+        $this->middleware(
+            function ($request, $next) {
+                $this->recurring = app(RecurringRepositoryInterface::class);
+
+                return $next($request);
+            }
+        );
+    }
+
+    /**
+     * @param Request $request
+     *
+     * @throws FireflyException
+     * @return JsonResponse
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function events(Request $request): JsonResponse
+    {
+        $return           = [];
+        $start            = Carbon::createFromFormat('Y-m-d', $request->get('start'));
+        $end              = Carbon::createFromFormat('Y-m-d', $request->get('end'));
+        $firstDate        = Carbon::createFromFormat('Y-m-d', $request->get('first_date'));
+        $endDate          = '' !== (string)$request->get('end_date') ? Carbon::createFromFormat('Y-m-d', $request->get('end_date')) : null;
+        $endsAt           = (string)$request->get('ends');
+        $repetitionType   = explode(',', $request->get('type'))[0];
+        $repetitions      = (int)$request->get('reps');
+        $repetitionMoment = '';
+        $start->startOfDay();
+
+        // if $firstDate is beyond $end, simply return an empty array.
+        if ($firstDate->gt($end)) {
+            return response()->json([]);
+        }
+        // if $firstDate is beyond start, use that one:
+        $actualStart = clone $firstDate;
+
+        if ($repetitionType === 'weekly' || $repetitionType === 'monthly') {
+            $repetitionMoment = explode(',', $request->get('type'))[1] ?? '1';
+        }
+        if ($repetitionType === 'ndom') {
+            $repetitionMoment = str_ireplace('ndom,', '', $request->get('type'));
+        }
+        if ($repetitionType === 'yearly') {
+            $repetitionMoment = explode(',', $request->get('type'))[1] ?? '2018-01-01';
+        }
+        $repetition                    = new RecurrenceRepetition;
+        $repetition->repetition_type   = $repetitionType;
+        $repetition->repetition_moment = $repetitionMoment;
+        $repetition->repetition_skip   = (int)$request->get('skip');
+        $repetition->weekend           = (int)$request->get('weekend');
+        $actualEnd                     = clone $end;
+
+        switch ($endsAt) {
+            default:
+                throw new FireflyException(sprintf('Cannot generate events for type that ends at "%s".', $endsAt));
+            case 'forever':
+                // simply generate up until $end. No change from default behavior.
+                $occurrences = $this->recurring->getOccurrencesInRange($repetition, $actualStart, $actualEnd);
+                break;
+            case 'until_date':
+                $actualEnd   = $endDate ?? clone $end;
+                $occurrences = $this->recurring->getOccurrencesInRange($repetition, $actualStart, $actualEnd);
+                break;
+            case 'times':
+                $occurrences = $this->recurring->getXOccurrences($repetition, $actualStart, $repetitions);
+                break;
+        }
+
+
+        /** @var Carbon $current */
+        foreach ($occurrences as $current) {
+            if ($current->gte($start)) {
+                $event    = [
+                    'id'        => $repetitionType . $firstDate->format('Ymd'),
+                    'title'     => 'X',
+                    'allDay'    => true,
+                    'start'     => $current->format('Y-m-d'),
+                    'end'       => $current->format('Y-m-d'),
+                    'editable'  => false,
+                    'rendering' => 'background',
+                ];
+                $return[] = $event;
+            }
+        }
+
+        return response()->json($return);
+    }
+
+    /**
+     * @param Request $request
+     *
+     * @return JsonResponse
+     */
+    public function suggest(Request $request): JsonResponse
+    {
+        $today       = new Carbon;
+        $date        = Carbon::createFromFormat('Y-m-d', $request->get('date'));
+        $preSelected = (string)$request->get('pre_select');
+        $result      = [];
+        if ($date > $today || 'true' === (string)$request->get('past')) {
+            $weekly     = sprintf('weekly,%s', $date->dayOfWeekIso);
+            $monthly    = sprintf('monthly,%s', $date->day);
+            $dayOfWeek  = trans(sprintf('config.dow_%s', $date->dayOfWeekIso));
+            $ndom       = sprintf('ndom,%s,%s', $date->weekOfMonth, $date->dayOfWeekIso);
+            $yearly     = sprintf('yearly,%s', $date->format('Y-m-d'));
+            $yearlyDate = $date->formatLocalized(trans('config.month_and_day_no_year'));
+            $result     = [
+                'daily'  => ['label' => (string)trans('firefly.recurring_daily'), 'selected' => 0 === strpos($preSelected, 'daily')],
+                $weekly  => ['label'    => (string)trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek]),
+                             'selected' => 0 === strpos($preSelected, 'weekly')],
+                $monthly => ['label'    => (string)trans('firefly.recurring_monthly', ['dayOfMonth' => $date->day]),
+                             'selected' => 0 === strpos($preSelected, 'monthly')],
+                $ndom    => ['label'    => (string)trans('firefly.recurring_ndom', ['weekday' => $dayOfWeek, 'dayOfMonth' => $date->weekOfMonth]),
+                             'selected' => 0 === strpos($preSelected, 'ndom')],
+                $yearly  => ['label' => (string)trans('firefly.recurring_yearly', ['date' => $yearlyDate]), 'selected' => 0 === strpos($preSelected, 'yearly')],
+            ];
+        }
+
+
+        return response()->json($result);
+    }
+
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/JsonController.php b/app/Http/Controllers/JsonController.php
index ee26ffcc0a..e48fe6192e 100644
--- a/app/Http/Controllers/JsonController.php
+++ b/app/Http/Controllers/JsonController.php
@@ -34,7 +34,7 @@ class JsonController extends Controller
      * @param Request $request
      *
      * @return JsonResponse
-     * @throws \Throwable
+
      */
     public function action(Request $request): JsonResponse
     {
@@ -53,7 +53,7 @@ class JsonController extends Controller
      * @param Request $request
      *
      * @return JsonResponse
-     * @throws \Throwable
+
      */
     public function trigger(Request $request): JsonResponse
     {
diff --git a/app/Http/Controllers/NewUserController.php b/app/Http/Controllers/NewUserController.php
index 267d96beaf..4dee74940d 100644
--- a/app/Http/Controllers/NewUserController.php
+++ b/app/Http/Controllers/NewUserController.php
@@ -97,31 +97,17 @@ class NewUserController extends Controller
             $currency = $currencyRepository->findByCodeNull('EUR');
         }
 
-        // create normal asset account:
-        $this->createAssetAccount($request, $currency);
-
-        // create savings account
-        $this->createSavingsAccount($request, $currency, $language);
-
-        // create cash wallet account
-        $this->createCashWalletAccount($currency, $language);
+        $this->createAssetAccount($request, $currency); // create normal asset account
+        $this->createSavingsAccount($request, $currency, $language); // create savings account
+        $this->createCashWalletAccount($currency, $language); // create cash wallet account
 
         // store currency preference:
         app('preferences')->set('currencyPreference', $currency->code);
         app('preferences')->mark();
 
         // set default optional fields:
-        $visibleFields = [
-            'interest_date'      => true,
-            'book_date'          => false,
-            'process_date'       => false,
-            'due_date'           => false,
-            'payment_date'       => false,
-            'invoice_date'       => false,
-            'internal_reference' => false,
-            'notes'              => true,
-            'attachments'        => true,
-        ];
+        $visibleFields = ['interest_date' => true, 'book_date' => false, 'process_date' => false, 'due_date' => false, 'payment_date' => false,
+                          'invoice_date'  => false, 'internal_reference' => false, 'notes' => true, 'attachments' => true,];
         app('preferences')->set('transaction_journal_optional_fields', $visibleFields);
 
         session()->flash('success', (string)trans('firefly.stored_new_accounts_new_user'));
diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php
index f5133285a6..7a450fb6ba 100644
--- a/app/Http/Controllers/PiggyBankController.php
+++ b/app/Http/Controllers/PiggyBankController.php
@@ -40,6 +40,9 @@ use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
  * Class PiggyBankController.
+ *
+ * @SuppressWarnings(PHPMD.TooManyPublicMethods)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class PiggyBankController extends Controller
 {
@@ -174,6 +177,8 @@ class PiggyBankController extends Controller
      * @param PiggyBank $piggyBank
      *
      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function edit(PiggyBank $piggyBank)
     {
@@ -212,6 +217,8 @@ class PiggyBankController extends Controller
      * @param Request $request
      *
      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function index(Request $request)
     {
diff --git a/app/Http/Controllers/Popup/ReportController.php b/app/Http/Controllers/Popup/ReportController.php
index e93e37755d..9be8443b0e 100644
--- a/app/Http/Controllers/Popup/ReportController.php
+++ b/app/Http/Controllers/Popup/ReportController.php
@@ -23,7 +23,6 @@ declare(strict_types=1);
 namespace FireflyIII\Http\Controllers\Popup;
 
 use Carbon\Carbon;
-use FireflyIII\Exceptions\FireflyException;
 use FireflyIII\Helpers\Collection\BalanceLine;
 use FireflyIII\Helpers\Report\PopupReportInterface;
 use FireflyIII\Http\Controllers\Controller;
@@ -35,9 +34,13 @@ use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Illuminate\Routing\Route;
 use InvalidArgumentException;
+use Log;
+use Throwable;
 
 /**
  * Class ReportController.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class ReportController extends Controller
 {
@@ -79,9 +82,7 @@ class ReportController extends Controller
      * @param Request $request
      *
      * @return JsonResponse
-     *
-     * @throws FireflyException
-     * @throws \Throwable
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function general(Request $request): JsonResponse
     {
@@ -93,7 +94,8 @@ class ReportController extends Controller
 
         switch ($attributes['location']) {
             default:
-                throw new FireflyException('Firefly cannot handle "' . e($attributes['location']) . '" ');
+                $html = sprintf('Firefly III cannot handle "%s"-popups.', $attributes['location']);
+                break;
             case 'budget-spent-amount':
                 $html = $this->budgetSpentAmount($attributes);
                 break;
@@ -119,8 +121,7 @@ class ReportController extends Controller
      *
      * @return string
      *
-     * @throws FireflyException
-     * @throws \Throwable
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     private function balanceAmount(array $attributes): string
     {
@@ -141,51 +142,60 @@ class ReportController extends Controller
                 break;
             case BalanceLine::ROLE_TAGROLE === $role:
                 // row with tag info.
-                throw new FireflyException('Firefly cannot handle this type of info-button (BalanceLine::TagRole)');
+                return 'Firefly cannot handle this type of info-button (BalanceLine::TagRole)';
+        }
+        try {
+            $view = view('popup.report.balance-amount', compact('journals', 'budget', 'account'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render: %s', $e->getMessage()));
+            $view = 'Firefly III could not render the view. Please see the log files.';
         }
-        $view = view('popup.report.balance-amount', compact('journals', 'budget', 'account'))->render();
 
         return $view;
     }
 
     /**
-     * Returns all expenses inside the given budget for the given accounts.
-     *
      * @param array $attributes
      *
      * @return string
-     * @throws \Throwable
      */
     private function budgetSpentAmount(array $attributes): string
     {
         $budget = $this->budgetRepository->findNull((int)$attributes['budgetId']);
         if (null === $budget) {
-            throw new FireflyException('This is an unknown budget. Apologies.');
+            return 'This is an unknown budget. Apologies.';
         }
         $journals = $this->popupHelper->byBudget($budget, $attributes);
-        $view     = view('popup.report.budget-spent-amount', compact('journals', 'budget'))->render();
+        try {
+            $view = view('popup.report.budget-spent-amount', compact('journals', 'budget'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render: %s', $e->getMessage()));
+            $view = 'Firefly III could not render the view. Please see the log files.';
+        }
 
         return $view;
     }
 
     /**
-     * Returns all expenses in category in range.
-     *
      * @param array $attributes
      *
      * @return string
-     * @throws \Throwable
      */
     private function categoryEntry(array $attributes): string
     {
         $category = $this->categoryRepository->findNull((int)$attributes['categoryId']);
 
         if (null === $category) {
-            throw new FireflyException('This is an unknown category. Apologies.');
+            return 'This is an unknown category. Apologies.';
         }
 
         $journals = $this->popupHelper->byCategory($category, $attributes);
-        $view     = view('popup.report.category-entry', compact('journals', 'category'))->render();
+        try {
+            $view = view('popup.report.category-entry', compact('journals', 'category'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render: %s', $e->getMessage()));
+            $view = 'Firefly III could not render the view. Please see the log files.';
+        }
 
         return $view;
     }
@@ -196,18 +206,22 @@ class ReportController extends Controller
      * @param array $attributes
      *
      * @return string
-     * @throws \Throwable
      */
     private function expenseEntry(array $attributes): string
     {
         $account = $this->accountRepository->findNull((int)$attributes['accountId']);
 
         if (null === $account) {
-            throw new FireflyException('This is an unknown account. Apologies.');
+            return 'This is an unknown account. Apologies.';
         }
 
         $journals = $this->popupHelper->byExpenses($account, $attributes);
-        $view     = view('popup.report.expense-entry', compact('journals', 'account'))->render();
+        try {
+            $view = view('popup.report.expense-entry', compact('journals', 'account'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render: %s', $e->getMessage()));
+            $view = 'Firefly III could not render the view. Please see the log files.';
+        }
 
         return $view;
     }
@@ -218,18 +232,22 @@ class ReportController extends Controller
      * @param array $attributes
      *
      * @return string
-     * @throws \Throwable
      */
     private function incomeEntry(array $attributes): string
     {
         $account = $this->accountRepository->findNull((int)$attributes['accountId']);
 
         if (null === $account) {
-            throw new FireflyException('This is an unknown category. Apologies.');
+            return 'This is an unknown category. Apologies.';
         }
 
         $journals = $this->popupHelper->byIncome($account, $attributes);
-        $view     = view('popup.report.income-entry', compact('journals', 'account'))->render();
+        try {
+            $view = view('popup.report.income-entry', compact('journals', 'account'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render: %s', $e->getMessage()));
+            $view = 'Firefly III could not render the view. Please see the log files.';
+        }
 
         return $view;
     }
@@ -238,8 +256,6 @@ class ReportController extends Controller
      * @param array $attributes
      *
      * @return array
-     *
-     * @throws FireflyException
      */
     private function parseAttributes(array $attributes): array
     {
@@ -248,13 +264,19 @@ class ReportController extends Controller
         try {
             $attributes['startDate'] = Carbon::createFromFormat('Ymd', $attributes['startDate']);
         } catch (InvalidArgumentException $e) {
-            throw new FireflyException(sprintf('Could not parse start date "%s": %s', $attributes['startDate'], $e->getMessage()));
+            Log::debug('Not important error message: %s', $e->getMessage());
+            $date = new Carbon;
+            $date->startOfMonth();
+            $attributes['startDate'] = $date;
         }
 
         try {
             $attributes['endDate'] = Carbon::createFromFormat('Ymd', $attributes['endDate']);
         } catch (InvalidArgumentException $e) {
-            throw new FireflyException(sprintf('Could not parse end date "%s": %s', $attributes['endDate'], $e->getMessage()));
+            Log::debug('Not important error message: %s', $e->getMessage());
+            $date = new Carbon;
+            $date->startOfMonth();
+            $attributes['endDate'] = $date;
         }
 
         return $attributes;
diff --git a/app/Http/Controllers/PreferencesController.php b/app/Http/Controllers/PreferencesController.php
index be0d1cc62c..0afca32757 100644
--- a/app/Http/Controllers/PreferencesController.php
+++ b/app/Http/Controllers/PreferencesController.php
@@ -86,6 +86,9 @@ class PreferencesController extends Controller
      * @param Request $request
      *
      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function postIndex(Request $request)
     {
diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php
index db0e0b3023..171809ba37 100644
--- a/app/Http/Controllers/ProfileController.php
+++ b/app/Http/Controllers/ProfileController.php
@@ -49,6 +49,8 @@ use phpseclib\Crypt\RSA;
  * Class ProfileController.
  *
  * @method Guard guard()
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.TooManyPublicMethods)
  */
 class ProfileController extends Controller
 {
@@ -185,10 +187,10 @@ class ProfileController extends Controller
         if ($repository->hasRole($user, 'demo')) {
             return redirect(route('profile.index'));
         }
-        $hasTwoFactorAuthSecret = (null !== app('preferences')->get('twoFactorAuthSecret'));
+        $hasSecret = (null !== app('preferences')->get('twoFactorAuthSecret'));
 
         // if we don't have a valid secret yet, redirect to the code page to get one.
-        if (!$hasTwoFactorAuthSecret) {
+        if (!$hasSecret) {
             return redirect(route('profile.code'));
         }
 
@@ -308,6 +310,8 @@ class ProfileController extends Controller
      * @param TokenFormRequest $request
      *
      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function postCode(TokenFormRequest $request)
     {
@@ -316,7 +320,6 @@ class ProfileController extends Controller
 
         session()->flash('success', (string)trans('firefly.saved_preferences'));
         app('preferences')->mark();
-
         return redirect(route('profile.index'));
     }
 
@@ -366,6 +369,8 @@ class ProfileController extends Controller
      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
      *
      * @throws FireflyException
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function undoEmailChange(UserRepositoryInterface $repository, string $token, string $hash)
     {
@@ -382,8 +387,7 @@ class ProfileController extends Controller
             throw new FireflyException('Invalid token.');
         }
 
-        // found user.
-        // which email address to return to?
+        // found user.which email address to return to?
         $set = app('preferences')->beginsWith($user, 'previous_email_');
         /** @var string $match */
         $match = null;
diff --git a/app/Http/Controllers/Recurring/CreateController.php b/app/Http/Controllers/Recurring/CreateController.php
index 4cc9c77251..6596075f05 100644
--- a/app/Http/Controllers/Recurring/CreateController.php
+++ b/app/Http/Controllers/Recurring/CreateController.php
@@ -69,6 +69,7 @@ class CreateController extends Controller
      * @param Request $request
      *
      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function create(Request $request)
     {
@@ -83,14 +84,11 @@ class CreateController extends Controller
             $this->rememberPreviousUri('recurring.create.uri');
         }
         $request->session()->forget('recurring.create.fromStore');
-
-        // when will it end?
         $repetitionEnds = [
             'forever'    => (string)trans('firefly.repeat_forever'),
             'until_date' => (string)trans('firefly.repeat_until_date'),
             'times'      => (string)trans('firefly.repeat_times'),
         ];
-        // what to do in the weekend?
         $weekendResponses = [
             RecurrenceRepetition::WEEKEND_DO_NOTHING    => (string)trans('firefly.do_nothing'),
             RecurrenceRepetition::WEEKEND_SKIP_CREATION => (string)trans('firefly.skip_transaction'),
@@ -98,8 +96,8 @@ class CreateController extends Controller
             RecurrenceRepetition::WEEKEND_TO_MONDAY     => (string)trans('firefly.jump_to_monday'),
         ];
 
-        // flash some data:
-        $hasOldInput = null !== $request->old('_token');
+
+        $hasOldInput = null !== $request->old('_token'); // flash some data
         $preFilled   = [
             'first_date'       => $tomorrow->format('Y-m-d'),
             'transaction_type' => $hasOldInput ? $request->old('transaction_type') : 'withdrawal',
diff --git a/app/Http/Controllers/Recurring/EditController.php b/app/Http/Controllers/Recurring/EditController.php
index 1305516655..4eed6f3f09 100644
--- a/app/Http/Controllers/Recurring/EditController.php
+++ b/app/Http/Controllers/Recurring/EditController.php
@@ -68,31 +68,29 @@ class EditController extends Controller
     }
 
     /**
+     * todo move to repository
+     * todo handle old repetition type as well.
+     *
      * @param Request    $request
      * @param Recurrence $recurrence
      *
      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
      * @throws \FireflyIII\Exceptions\FireflyException
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function edit(Request $request, Recurrence $recurrence)
     {
-
-
-        // use transformer:
         $transformer = new RecurrenceTransformer(new ParameterBag);
         $array       = $transformer->transform($recurrence);
         $budgets     = app('expandedform')->makeSelectListWithEmpty($this->budgets->getActiveBudgets());
 
-        // get recurrence type:
-        // todo move to repository
-        // todo handle old repetition type as well.
-
-
         /** @var RecurrenceRepetition $repetition */
         $repetition            = $recurrence->recurrenceRepetitions()->first();
-        $currentRepetitionType = $repetition->repetition_type;
+        $currentRepType = $repetition->repetition_type;
         if ('' !== $repetition->repetition_moment) {
-            $currentRepetitionType .= ',' . $repetition->repetition_moment;
+            $currentRepType .= ',' . $repetition->repetition_moment;
         }
 
         // put previous url in session if not redirect from store (not "return_to_edit").
@@ -101,9 +99,7 @@ class EditController extends Controller
         }
         $request->session()->forget('recurrences.edit.fromUpdate');
 
-        // assume repeats forever:
-        $repetitionEnd = 'forever';
-        // types of repetitions:
+        $repetitionEnd  = 'forever';
         $repetitionEnds = [
             'forever'    => (string)trans('firefly.repeat_forever'),
             'until_date' => (string)trans('firefly.repeat_until_date'),
@@ -116,7 +112,6 @@ class EditController extends Controller
             $repetitionEnd = 'times';
         }
 
-        // what to do in the weekend?
         $weekendResponses = [
             RecurrenceRepetition::WEEKEND_DO_NOTHING    => (string)trans('firefly.do_nothing'),
             RecurrenceRepetition::WEEKEND_SKIP_CREATION => (string)trans('firefly.skip_transaction'),
@@ -124,10 +119,8 @@ class EditController extends Controller
             RecurrenceRepetition::WEEKEND_TO_MONDAY     => (string)trans('firefly.jump_to_monday'),
         ];
 
-        // code to handle active-checkboxes
         $hasOldInput = null !== $request->old('_token');
-        // $hasOldInput = false;
-        $preFilled = [
+        $preFilled   = [
             'transaction_type' => strtolower($recurrence->transactionType->type),
             'active'           => $hasOldInput ? (bool)$request->old('active') : $recurrence->active,
             'apply_rules'      => $hasOldInput ? (bool)$request->old('apply_rules') : $recurrence->apply_rules,
@@ -135,7 +128,7 @@ class EditController extends Controller
 
         return view(
             'recurring.edit',
-            compact('recurrence', 'array', 'weekendResponses', 'budgets', 'preFilled', 'currentRepetitionType', 'repetitionEnd', 'repetitionEnds')
+            compact('recurrence', 'array', 'weekendResponses', 'budgets', 'preFilled', 'currentRepType', 'repetitionEnd', 'repetitionEnds')
         );
     }
 
diff --git a/app/Http/Controllers/Recurring/IndexController.php b/app/Http/Controllers/Recurring/IndexController.php
index 07d6489d5f..51e4a0215f 100644
--- a/app/Http/Controllers/Recurring/IndexController.php
+++ b/app/Http/Controllers/Recurring/IndexController.php
@@ -28,10 +28,8 @@ use Carbon\Carbon;
 use FireflyIII\Exceptions\FireflyException;
 use FireflyIII\Http\Controllers\Controller;
 use FireflyIII\Models\Recurrence;
-use FireflyIII\Models\RecurrenceRepetition;
 use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
 use FireflyIII\Transformers\RecurrenceTransformer;
-use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Symfony\Component\HttpFoundation\ParameterBag;
 
@@ -64,98 +62,14 @@ class IndexController extends Controller
         );
     }
 
-
     /**
-     * @param Request $request
+     * TODO: split collection into pages
      *
-     * @throws FireflyException
-     * @return JsonResponse
-     */
-    public function events(Request $request): JsonResponse
-    {
-        $return           = [];
-        $start            = Carbon::createFromFormat('Y-m-d', $request->get('start'));
-        $end              = Carbon::createFromFormat('Y-m-d', $request->get('end'));
-        $firstDate        = Carbon::createFromFormat('Y-m-d', $request->get('first_date'));
-        $endDate          = '' !== (string)$request->get('end_date') ? Carbon::createFromFormat('Y-m-d', $request->get('end_date')) : null;
-        $endsAt           = (string)$request->get('ends');
-        $repetitionType   = explode(',', $request->get('type'))[0];
-        $repetitions      = (int)$request->get('reps');
-        $repetitionMoment = '';
-        $start->startOfDay();
-
-        // if $firstDate is beyond $end, simply return an empty array.
-        if ($firstDate->gt($end)) {
-            return response()->json([]);
-        }
-        // if $firstDate is beyond start, use that one:
-        $actualStart = clone $firstDate;
-
-        switch ($repetitionType) {
-            default:
-                throw new FireflyException(sprintf('Cannot handle repetition type "%s"', $repetitionType));
-            case 'daily':
-                break;
-            case 'weekly':
-            case 'monthly':
-                $repetitionMoment = explode(',', $request->get('type'))[1] ?? '1';
-                break;
-            case 'ndom':
-                $repetitionMoment = str_ireplace('ndom,', '', $request->get('type'));
-                break;
-            case 'yearly':
-                $repetitionMoment = explode(',', $request->get('type'))[1] ?? '2018-01-01';
-                break;
-        }
-        $repetition                    = new RecurrenceRepetition;
-        $repetition->repetition_type   = $repetitionType;
-        $repetition->repetition_moment = $repetitionMoment;
-        $repetition->repetition_skip   = (int)$request->get('skip');
-        $repetition->weekend           = (int)$request->get('weekend');
-
-        $actualEnd = clone $end;
-        switch ($endsAt) {
-            default:
-                throw new FireflyException(sprintf('Cannot generate events for type that ends at "%s".', $endsAt));
-            case 'forever':
-                // simply generate up until $end. No change from default behavior.
-                $occurrences = $this->recurring->getOccurrencesInRange($repetition, $actualStart, $actualEnd);
-                break;
-            case 'until_date':
-                $actualEnd   = $endDate ?? clone $end;
-                $occurrences = $this->recurring->getOccurrencesInRange($repetition, $actualStart, $actualEnd);
-                break;
-            case 'times':
-                $occurrences = $this->recurring->getXOccurrences($repetition, $actualStart, $repetitions);
-                break;
-        }
-
-
-        /** @var Carbon $current */
-        foreach ($occurrences as $current) {
-            if ($current->gte($start)) {
-                $event    = [
-                    'id'        => $repetitionType . $firstDate->format('Ymd'),
-                    'title'     => 'X',
-                    'allDay'    => true,
-                    'start'     => $current->format('Y-m-d'),
-                    'end'       => $current->format('Y-m-d'),
-                    'editable'  => false,
-                    'rendering' => 'background',
-                ];
-                $return[] = $event;
-            }
-        }
-
-        return response()->json($return);
-    }
-
-
-    /**
      * @param Request $request
      *
      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
      * @throws \FireflyIII\Exceptions\FireflyException
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function index(Request $request)
     {
@@ -163,7 +77,6 @@ class IndexController extends Controller
         $pageSize   = (int)app('preferences')->get('listPageSize', 50)->data;
         $collection = $this->recurring->get();
 
-        // TODO: split collection into pages
 
         $transformer = new RecurrenceTransformer(new ParameterBag);
         $recurring   = [];
@@ -206,38 +119,4 @@ class IndexController extends Controller
         return view('recurring.show', compact('recurrence', 'subTitle', 'array', 'transactions'));
     }
 
-    /**
-     * @param Request $request
-     *
-     * @return JsonResponse
-     */
-    public function suggest(Request $request): JsonResponse
-    {
-        $today       = new Carbon;
-        $date        = Carbon::createFromFormat('Y-m-d', $request->get('date'));
-        $preSelected = (string)$request->get('pre_select');
-        $result      = [];
-        if ($date > $today || 'true' === (string)$request->get('past')) {
-            $weekly     = sprintf('weekly,%s', $date->dayOfWeekIso);
-            $monthly    = sprintf('monthly,%s', $date->day);
-            $dayOfWeek  = trans(sprintf('config.dow_%s', $date->dayOfWeekIso));
-            $ndom       = sprintf('ndom,%s,%s', $date->weekOfMonth, $date->dayOfWeekIso);
-            $yearly     = sprintf('yearly,%s', $date->format('Y-m-d'));
-            $yearlyDate = $date->formatLocalized(trans('config.month_and_day_no_year'));
-            $result     = [
-                'daily'  => ['label' => (string)trans('firefly.recurring_daily'), 'selected' => 0 === strpos($preSelected, 'daily')],
-                $weekly  => ['label'    => (string)trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek]),
-                             'selected' => 0 === strpos($preSelected, 'weekly')],
-                $monthly => ['label'    => (string)trans('firefly.recurring_monthly', ['dayOfMonth' => $date->day]),
-                             'selected' => 0 === strpos($preSelected, 'monthly')],
-                $ndom    => ['label'    => (string)trans('firefly.recurring_ndom', ['weekday' => $dayOfWeek, 'dayOfMonth' => $date->weekOfMonth]),
-                             'selected' => 0 === strpos($preSelected, 'ndom')],
-                $yearly  => ['label' => (string)trans('firefly.recurring_yearly', ['date' => $yearlyDate]), 'selected' => 0 === strpos($preSelected, 'yearly')],
-            ];
-        }
-
-
-        return response()->json($result);
-    }
-
 }
\ No newline at end of file
diff --git a/app/Http/Controllers/Report/AccountController.php b/app/Http/Controllers/Report/AccountController.php
index 8e29812af5..80fad5a433 100644
--- a/app/Http/Controllers/Report/AccountController.php
+++ b/app/Http/Controllers/Report/AccountController.php
@@ -41,7 +41,7 @@ class AccountController extends Controller
      *
      * @return mixed|string
      *
-     * @throws \Throwable
+
      */
     public function general(Collection $accounts, Carbon $start, Carbon $end)
     {
diff --git a/app/Http/Controllers/Report/BalanceController.php b/app/Http/Controllers/Report/BalanceController.php
index 992845aa09..be928919e1 100644
--- a/app/Http/Controllers/Report/BalanceController.php
+++ b/app/Http/Controllers/Report/BalanceController.php
@@ -40,7 +40,7 @@ class BalanceController extends Controller
      * @param Carbon     $end
      *
      * @return mixed|string
-     * @throws \Throwable
+
      */
     public function general(Collection $accounts, Carbon $start, Carbon $end)
     {
diff --git a/app/Http/Controllers/Report/BudgetController.php b/app/Http/Controllers/Report/BudgetController.php
index 44ba71d683..cf6e2ac9c6 100644
--- a/app/Http/Controllers/Report/BudgetController.php
+++ b/app/Http/Controllers/Report/BudgetController.php
@@ -41,7 +41,7 @@ class BudgetController extends Controller
      * @param Carbon     $end
      *
      * @return mixed|string
-     * @throws \Throwable
+
      */
     public function general(Collection $accounts, Carbon $start, Carbon $end)
     {
@@ -70,7 +70,7 @@ class BudgetController extends Controller
      * @param Carbon     $end
      *
      * @return mixed|string
-     * @throws \Throwable
+
      */
     public function period(Collection $accounts, Carbon $start, Carbon $end)
     {
diff --git a/app/Http/Controllers/Report/CategoryController.php b/app/Http/Controllers/Report/CategoryController.php
index a37336b0fc..79bd8a726f 100644
--- a/app/Http/Controllers/Report/CategoryController.php
+++ b/app/Http/Controllers/Report/CategoryController.php
@@ -28,6 +28,8 @@ use FireflyIII\Models\Category;
 use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
 use FireflyIII\Support\CacheProperties;
 use Illuminate\Support\Collection;
+use Log;
+use Throwable;
 
 /**
  * Class CategoryController.
@@ -41,7 +43,6 @@ class CategoryController extends Controller
      * @param Carbon     $end
      *
      * @return mixed|string
-     * @throws \Throwable
      */
     public function expenses(Collection $accounts, Carbon $start, Carbon $end)
     {
@@ -60,7 +61,12 @@ class CategoryController extends Controller
         $data[0]    = $repository->periodExpensesNoCategory($accounts, $start, $end);
         $report     = $this->filterReport($data);
         $periods    = app('navigation')->listOfPeriods($start, $end);
-        $result     = view('reports.partials.category-period', compact('report', 'periods'))->render();
+        try {
+            $result = view('reports.partials.category-period', compact('report', 'periods'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
+            $result = 'An error prevented Firefly III from rendering. Apologies.';
+        }
 
         $cache->store($result);
 
@@ -75,7 +81,6 @@ class CategoryController extends Controller
      * @param Carbon     $end
      *
      * @return string
-     * @throws \Throwable
      */
     public function income(Collection $accounts, Carbon $start, Carbon $end): string
     {
@@ -94,8 +99,12 @@ class CategoryController extends Controller
         $data[0]    = $repository->periodIncomeNoCategory($accounts, $start, $end);
         $report     = $this->filterReport($data);
         $periods    = app('navigation')->listOfPeriods($start, $end);
-        $result     = view('reports.partials.category-period', compact('report', 'periods'))->render();
-
+        try {
+            $result = view('reports.partials.category-period', compact('report', 'periods'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
+            $result = 'An error prevented Firefly III from rendering. Apologies.';
+        }
         $cache->store($result);
 
         return $result;
@@ -109,8 +118,7 @@ class CategoryController extends Controller
      *
      * @return mixed|string
      *
-     * @throws \Throwable
-     * @internal param ReportHelperInterface $helper
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function operations(Collection $accounts, Carbon $start, Carbon $end)
     {
@@ -136,17 +144,18 @@ class CategoryController extends Controller
                 $report[$category->id] = ['name' => $category->name, 'spent' => $spent, 'earned' => $earned, 'id' => $category->id];
             }
         }
-        // sort the result
-        // Obtain a list of columns
         $sum = [];
         foreach ($report as $categoryId => $row) {
             $sum[$categoryId] = (float)$row['spent'];
         }
-
         array_multisort($sum, SORT_ASC, $report);
-
-        $result = view('reports.partials.categories', compact('report'))->render();
-        $cache->store($result);
+        try {
+            $result = view('reports.partials.categories', compact('report'))->render();
+            $cache->store($result);
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
+            $result = 'An error prevented Firefly III from rendering. Apologies.';
+        }
 
         return $result;
     }
diff --git a/app/Http/Controllers/Report/ExpenseController.php b/app/Http/Controllers/Report/ExpenseController.php
index 9d5b7276ae..37adf0f446 100644
--- a/app/Http/Controllers/Report/ExpenseController.php
+++ b/app/Http/Controllers/Report/ExpenseController.php
@@ -18,7 +18,6 @@
  * You should have received a copy of the GNU General Public License
  * along with Firefly III. If not, see .
  */
-/** @noinspection MoreThanThreeArgumentsInspection */
 declare(strict_types=1);
 
 namespace FireflyIII\Http\Controllers\Report;
@@ -33,9 +32,13 @@ use FireflyIII\Models\TransactionType;
 use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 use FireflyIII\Support\CacheProperties;
 use Illuminate\Support\Collection;
+use Log;
+use Throwable;
 
 /**
  * Class ExpenseController
+ *
+ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
  */
 class ExpenseController extends Controller
 {
@@ -60,6 +63,7 @@ class ExpenseController extends Controller
     }
 
 
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * Generates the overview per budget.
      *
@@ -69,7 +73,7 @@ class ExpenseController extends Controller
      * @param Carbon     $end
      *
      * @return string
-     * @throws \Throwable
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function budget(Collection $accounts, Collection $expense, Carbon $start, Carbon $end): string
     {
@@ -85,7 +89,7 @@ class ExpenseController extends Controller
         }
         $combined = $this->combineAccounts($expense);
         $all      = new Collection;
-        foreach ($combined as $name => $combi) {
+        foreach ($combined as $combi) {
             $all = $all->merge($combi);
         }
         // now find spent / earned:
@@ -100,13 +104,19 @@ class ExpenseController extends Controller
             }
             $together[$categoryId]['grand_total'] = bcadd($spentInfo['grand_total'], $together[$categoryId]['grand_total']);
         }
-        $result = view('reports.partials.exp-budgets', compact('together'))->render();
+        try {
+            $result = view('reports.partials.exp-budgets', compact('together'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
+            $result = 'An error prevented Firefly III from rendering. Apologies.';
+        }
         $cache->store($result);
 
         return $result;
     }
 
 
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * Generates the overview per category (spent and earned).
      *
@@ -116,7 +126,8 @@ class ExpenseController extends Controller
      * @param Carbon     $end
      *
      * @return string
-     * @throws \Throwable
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function category(Collection $accounts, Collection $expense, Carbon $start, Carbon $end): string
     {
@@ -132,7 +143,7 @@ class ExpenseController extends Controller
         }
         $combined = $this->combineAccounts($expense);
         $all      = new Collection;
-        foreach ($combined as $name => $combi) {
+        foreach ($combined as $combi) {
             $all = $all->merge($combi);
         }
         // now find spent / earned:
@@ -156,14 +167,18 @@ class ExpenseController extends Controller
             }
             $together[$categoryId]['grand_total'] = bcadd($earnedInfo['grand_total'], $together[$categoryId]['grand_total']);
         }
-
-        $result = view('reports.partials.exp-categories', compact('together'))->render();
+        try {
+            $result = view('reports.partials.exp-categories', compact('together'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
+            $result = 'An error prevented Firefly III from rendering. Apologies.';
+        }
         $cache->store($result);
 
         return $result;
     }
 
-
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * Overview of spending
      *
@@ -173,7 +188,6 @@ class ExpenseController extends Controller
      * @param Carbon     $end
      *
      * @return array|mixed|string
-     * @throws \Throwable
      */
     public function spent(Collection $accounts, Collection $expense, Carbon $start, Carbon $end)
     {
@@ -203,14 +217,19 @@ class ExpenseController extends Controller
                 'earned' => $earned,
             ];
         }
-        $result = view('reports.partials.exp-not-grouped', compact('result'))->render();
+        try {
+            $result = view('reports.partials.exp-not-grouped', compact('result'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
+            $result = 'An error prevented Firefly III from rendering. Apologies.';
+        }
         $cache->store($result);
 
         return $result;
         // for period, get spent and earned for each account (by name)
     }
 
-
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $accounts
      * @param Collection $expense
@@ -218,7 +237,6 @@ class ExpenseController extends Controller
      * @param Carbon     $end
      *
      * @return string
-     * @throws \Throwable
      */
     public function topExpense(Collection $accounts, Collection $expense, Carbon $start, Carbon $end): string
     {
@@ -234,7 +252,7 @@ class ExpenseController extends Controller
         }
         $combined = $this->combineAccounts($expense);
         $all      = new Collection;
-        foreach ($combined as $name => $combi) {
+        foreach ($combined as $combi) {
             $all = $all->merge($combi);
         }
         // get all expenses in period:
@@ -248,12 +266,17 @@ class ExpenseController extends Controller
                 return (float)$transaction->transaction_amount;
             }
         );
-        $result = view('reports.partials.top-transactions', compact('sorted'))->render();
+        try {
+            $result = view('reports.partials.top-transactions', compact('sorted'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
+            $result = 'An error prevented Firefly III from rendering. Apologies.';
+        }
         $cache->store($result);
 
         return $result;
     }
-
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $accounts
      * @param Collection $expense
@@ -261,7 +284,6 @@ class ExpenseController extends Controller
      * @param Carbon     $end
      *
      * @return mixed|string
-     * @throws \Throwable
      */
     public function topIncome(Collection $accounts, Collection $expense, Carbon $start, Carbon $end)
     {
@@ -277,7 +299,7 @@ class ExpenseController extends Controller
         }
         $combined = $this->combineAccounts($expense);
         $all      = new Collection;
-        foreach ($combined as $name => $combi) {
+        foreach ($combined as $combi) {
             $all = $all->merge($combi);
         }
         // get all expenses in period:
@@ -291,7 +313,12 @@ class ExpenseController extends Controller
                 return (float)$transaction->transaction_amount;
             }
         );
-        $result = view('reports.partials.top-transactions', compact('sorted'))->render();
+        try {
+            $result = view('reports.partials.top-transactions', compact('sorted'))->render();
+        } catch (Throwable $e) {
+            Log::error(sprintf('Could not render category::expenses: %s', $e->getMessage()));
+            $result = 'An error prevented Firefly III from rendering. Apologies.';
+        }
         $cache->store($result);
 
         return $result;
@@ -320,6 +347,7 @@ class ExpenseController extends Controller
         return $combined;
     }
 
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $assets
      * @param Collection $opposing
@@ -327,6 +355,9 @@ class ExpenseController extends Controller
      * @param Carbon     $end
      *
      * @return array
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     protected function earnedByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array
     {
@@ -381,6 +412,7 @@ class ExpenseController extends Controller
         return $sum;
     }
 
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $assets
      * @param Collection $opposing
@@ -423,6 +455,7 @@ class ExpenseController extends Controller
         return $sum;
     }
 
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $assets
      * @param Collection $opposing
@@ -430,6 +463,8 @@ class ExpenseController extends Controller
      * @param Carbon     $end
      *
      * @return array
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     protected function spentByBudget(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array
     {
@@ -484,6 +519,7 @@ class ExpenseController extends Controller
         return $sum;
     }
 
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $assets
      * @param Collection $opposing
@@ -491,6 +527,9 @@ class ExpenseController extends Controller
      * @param Carbon     $end
      *
      * @return array
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     protected function spentByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array
     {
@@ -545,6 +584,7 @@ class ExpenseController extends Controller
         return $sum;
     }
 
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $assets
      * @param Collection $opposing
diff --git a/app/Http/Controllers/Report/OperationsController.php b/app/Http/Controllers/Report/OperationsController.php
index a13eaa8593..7b7b2719a8 100644
--- a/app/Http/Controllers/Report/OperationsController.php
+++ b/app/Http/Controllers/Report/OperationsController.php
@@ -61,7 +61,7 @@ class OperationsController extends Controller
      * @param Carbon     $end
      *
      * @return mixed|string
-     * @throws \Throwable
+
      */
     public function expenses(Collection $accounts, Carbon $start, Carbon $end)
     {
@@ -88,7 +88,7 @@ class OperationsController extends Controller
      * @param Carbon     $end
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function income(Collection $accounts, Carbon $start, Carbon $end): string
     {
@@ -116,7 +116,7 @@ class OperationsController extends Controller
      * @param Carbon     $end
      *
      * @return mixed|string
-     * @throws \Throwable
+
      */
     public function operations(Collection $accounts, Carbon $start, Carbon $end)
     {
diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php
index 730ec0f0de..416419a6d7 100644
--- a/app/Http/Controllers/ReportController.php
+++ b/app/Http/Controllers/ReportController.php
@@ -19,7 +19,6 @@
  * along with Firefly III. If not, see .
  */
 /** @noinspection CallableParameterUseCaseInTypeContextInspection */
-/** @noinspection MoreThanThreeArgumentsInspection */
 declare(strict_types=1);
 
 namespace FireflyIII\Http\Controllers;
@@ -40,6 +39,7 @@ use Log;
 
 /**
  * Class ReportController.
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class ReportController extends Controller
 {
@@ -68,7 +68,7 @@ class ReportController extends Controller
             }
         );
     }
-
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $accounts
      * @param Collection $expense
@@ -133,6 +133,7 @@ class ReportController extends Controller
         return $generator->generate();
     }
 
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $accounts
      * @param Collection $budgets
@@ -168,6 +169,7 @@ class ReportController extends Controller
         return $generator->generate();
     }
 
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $accounts
      * @param Collection $categories
@@ -259,8 +261,7 @@ class ReportController extends Controller
      * @param string $reportType
      *
      * @return mixed
-     *
-     * @throws \Throwable
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function options(string $reportType)
     {
@@ -291,6 +292,10 @@ class ReportController extends Controller
      * @return RedirectResponse|\Illuminate\Routing\Redirector
      *
      * @throws \FireflyIII\Exceptions\FireflyException
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function postIndex(ReportFormRequest $request)
     {
@@ -358,6 +363,7 @@ class ReportController extends Controller
         return redirect($uri);
     }
 
+    /** @noinspection MoreThanThreeArgumentsInspection */
     /**
      * @param Collection $accounts
      * @param Collection $tags
@@ -395,7 +401,6 @@ class ReportController extends Controller
 
     /**
      * @return string
-     * @throws \Throwable
      */
     private function accountReportOptions(): string
     {
@@ -416,7 +421,6 @@ class ReportController extends Controller
 
     /**
      * @return string
-     * @throws \Throwable
      */
     private function budgetReportOptions(): string
     {
@@ -429,7 +433,6 @@ class ReportController extends Controller
 
     /**
      * @return string
-     * @throws \Throwable
      */
     private function categoryReportOptions(): string
     {
@@ -442,7 +445,6 @@ class ReportController extends Controller
 
     /**
      * @return string
-     * @throws \Throwable
      */
     private function noReportOptions(): string
     {
@@ -451,7 +453,6 @@ class ReportController extends Controller
 
     /**
      * @return string
-     * @throws \Throwable
      */
     private function tagReportOptions(): string
     {
diff --git a/app/Http/Controllers/Rule/CreateController.php b/app/Http/Controllers/Rule/CreateController.php
new file mode 100644
index 0000000000..c5952227f8
--- /dev/null
+++ b/app/Http/Controllers/Rule/CreateController.php
@@ -0,0 +1,250 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Http\Controllers\Rule;
+
+
+use FireflyIII\Http\Controllers\Controller;
+use FireflyIII\Http\Requests\RuleFormRequest;
+use FireflyIII\Models\Bill;
+use FireflyIII\Models\RuleGroup;
+use FireflyIII\Repositories\Bill\BillRepositoryInterface;
+use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
+use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
+use FireflyIII\Support\Http\Controllers\RuleManagement;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+use Log;
+use Throwable;
+
+/**
+ * Class CreateController
+ */
+class CreateController extends Controller
+{
+    use RuleManagement;
+    /** @var BillRepositoryInterface */
+    private $billRepos;
+    /** @var RuleGroupRepositoryInterface */
+    private $ruleRepos;
+
+    /**
+     * RuleController constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+
+        $this->middleware(
+            function ($request, $next) {
+                app('view')->share('title', (string)trans('firefly.rules'));
+                app('view')->share('mainTitleIcon', 'fa-random');
+
+                $this->billRepos = app(BillRepositoryInterface::class);
+                $this->ruleRepos = app(RuleRepositoryInterface::class);
+
+                return $next($request);
+            }
+        );
+    }
+
+    /**
+     * Create a new rule. It will be stored under the given $ruleGroup.
+     *
+     * TODO remove bill from this method, move to separate routine.
+     *
+     * @param Request   $request
+     * @param RuleGroup $ruleGroup
+     *
+     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    public function create(Request $request, RuleGroup $ruleGroup)
+    {
+        $this->createDefaultRuleGroup();
+        $this->createDefaultRule();
+        $bill         = null;
+        $billId       = (int)$request->get('fromBill');
+        $preFilled    = [
+            'strict' => true,
+        ];
+        $oldTriggers  = [];
+        $oldActions   = [];
+        $returnToBill = false;
+
+        if ('true' === $request->get('return')) {
+            $returnToBill = true;
+        }
+
+        // has bill?
+        if ($billId > 0) {
+            $bill = $this->billRepos->find($billId);
+        }
+
+        // has old input?
+        if ($request->old()) {
+            $oldTriggers = $this->getPreviousTriggers($request);
+            $oldActions  = $this->getPreviousActions($request);
+        }
+        // has existing bill refered to in URI?
+        if (null !== $bill && !$request->old()) {
+
+            // create some sensible defaults:
+            $preFilled['title']       = (string)trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]);
+            $preFilled['description'] = (string)trans('firefly.new_rule_for_bill_description', ['name' => $bill->name]);
+
+
+            // get triggers and actions for bill:
+            $oldTriggers = $this->getTriggersForBill($bill);
+            $oldActions  = $this->getActionsForBill($bill);
+        }
+
+        $triggerCount = \count($oldTriggers);
+        $actionCount  = \count($oldActions);
+        $subTitleIcon = 'fa-clone';
+        $subTitle     = (string)trans('firefly.make_new_rule', ['title' => $ruleGroup->title]);
+
+        $request->session()->flash('preFilled', $preFilled);
+
+        // put previous url in session if not redirect from store (not "create another").
+        if (true !== session('rules.create.fromStore')) {
+            $this->rememberPreviousUri('rules.create.uri');
+        }
+        session()->forget('rules.create.fromStore');
+
+        return view(
+            'rules.rule.create',
+            compact(
+                'subTitleIcon', 'oldTriggers', 'returnToBill', 'preFilled', 'bill', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup',
+                'subTitle'
+            )
+        );
+    }
+
+    /**
+     * @param RuleFormRequest $request
+     *
+     * @return RedirectResponse|\Illuminate\Routing\Redirector
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    public function store(RuleFormRequest $request)
+    {
+        $data = $request->getRuleData();
+        $rule = $this->ruleRepos->store($data);
+        session()->flash('success', (string)trans('firefly.stored_new_rule', ['title' => $rule->title]));
+        app('preferences')->mark();
+
+        // redirect to show bill.
+        if ('true' === $request->get('return_to_bill') && (int)$request->get('bill_id') > 0) {
+            return redirect(route('bills.show', [(int)$request->get('bill_id')])); // @codeCoverageIgnore
+        }
+
+        // redirect to new bill creation.
+        if ((int)$request->get('bill_id') > 0) {
+            return redirect($this->getPreviousUri('bills.create.uri')); // @codeCoverageIgnore
+        }
+
+        $redirect = redirect($this->getPreviousUri('rules.create.uri'));
+
+        if (1 === (int)$request->get('create_another')) {
+            // @codeCoverageIgnoreStart
+            session()->put('rules.create.fromStore', true);
+            $redirect = redirect(route('rules.create', [$data['rule_group_id']]))->withInput();
+            // @codeCoverageIgnoreEnd
+        }
+
+        return $redirect;
+    }
+
+    /**
+     * @param Bill $bill
+     *
+     * @return array
+     */
+    private function getActionsForBill(Bill $bill): array
+    {
+        $result = '';
+        try {
+            $result = view(
+                'rules.partials.action',
+                [
+                    'oldAction'  => 'link_to_bill',
+                    'oldValue'   => $bill->name,
+                    'oldChecked' => false,
+                    'count'      => 1,
+                ]
+            )->render();
+            // @codeCoverageIgnoreStart
+        } catch (Throwable $e) {
+            Log::error(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage()));
+            Log::error($e->getTraceAsString());
+            $result = 'Could not render view. See log files.';
+        }
+
+        // @codeCoverageIgnoreEnd
+
+        return [$result];
+    }
+
+    /**
+     * Create fake triggers to match the bill's properties
+     *
+     * @param Bill $bill
+     *
+     * @return array
+     */
+    private function getTriggersForBill(Bill $bill): array
+    {
+        $result   = [];
+        $triggers = ['currency_is', 'amount_more', 'amount_less', 'description_contains'];
+        $values   = [
+            $bill->transactionCurrency()->first()->name,
+            round($bill->amount_min, 12),
+            round($bill->amount_max, 12),
+            $bill->name,
+        ];
+        foreach ($triggers as $index => $trigger) {
+            try {
+                $string = view(
+                    'rules.partials.trigger',
+                    [
+                        'oldTrigger' => $trigger,
+                        'oldValue'   => $values[$index],
+                        'oldChecked' => false,
+                        'count'      => $index + 1,
+                    ]
+                )->render();
+            } catch (Throwable $e) {
+                Log::debug(sprintf('Throwable was thrown in getTriggersForBill(): %s', $e->getMessage()));
+                Log::debug($e->getTraceAsString());
+                $string = '';
+            }
+            if ('' !== $string) {
+                $result[] = $string;
+            }
+        }
+
+        return $result;
+    }
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/Rule/DeleteController.php b/app/Http/Controllers/Rule/DeleteController.php
new file mode 100644
index 0000000000..6f9763c894
--- /dev/null
+++ b/app/Http/Controllers/Rule/DeleteController.php
@@ -0,0 +1,94 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Http\Controllers\Rule;
+
+
+use FireflyIII\Http\Controllers\Controller;
+use FireflyIII\Models\Rule;
+use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
+use Illuminate\Http\RedirectResponse;
+
+/**
+ * Class DeleteController
+ */
+class DeleteController extends Controller
+{
+    /** @var RuleRepositoryInterface */
+    private $ruleRepos;
+
+    /**
+     * RuleController constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+
+        $this->middleware(
+            function ($request, $next) {
+                app('view')->share('title', (string)trans('firefly.rules'));
+                app('view')->share('mainTitleIcon', 'fa-random');
+
+                $this->ruleRepos = app(RuleRepositoryInterface::class);
+
+                return $next($request);
+            }
+        );
+    }
+
+    /**
+     * Delete a given rule.
+     *
+     * @param Rule $rule
+     *
+     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     */
+    public function delete(Rule $rule)
+    {
+        $subTitle = (string)trans('firefly.delete_rule', ['title' => $rule->title]);
+
+        // put previous url in session
+        $this->rememberPreviousUri('rules.delete.uri');
+
+        return view('rules.rule.delete', compact('rule', 'subTitle'));
+    }
+
+    /**
+     * Actually destroy the given rule.
+     *
+     * @param Rule $rule
+     *
+     * @return RedirectResponse
+     */
+    public function destroy(Rule $rule): RedirectResponse
+    {
+        $title = $rule->title;
+        $this->ruleRepos->destroy($rule);
+
+        session()->flash('success', (string)trans('firefly.deleted_rule', ['title' => $title]));
+        app('preferences')->mark();
+
+        return redirect($this->getPreviousUri('rules.delete.uri'));
+    }
+
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/Rule/EditController.php b/app/Http/Controllers/Rule/EditController.php
new file mode 100644
index 0000000000..a91121ab5b
--- /dev/null
+++ b/app/Http/Controllers/Rule/EditController.php
@@ -0,0 +1,219 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Http\Controllers\Rule;
+
+
+use FireflyIII\Http\Controllers\Controller;
+use FireflyIII\Http\Requests\RuleFormRequest;
+use FireflyIII\Models\Rule;
+use FireflyIII\Models\RuleAction;
+use FireflyIII\Models\RuleTrigger;
+use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
+use FireflyIII\Support\Http\Controllers\RuleManagement;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+use Log;
+use Throwable;
+
+/**
+ * Class EditController
+ */
+class EditController extends Controller
+{
+    use RuleManagement;
+
+    /** @var RuleRepositoryInterface */
+    private $ruleRepos;
+
+    /**
+     * RuleController constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+
+        $this->middleware(
+            function ($request, $next) {
+                app('view')->share('title', (string)trans('firefly.rules'));
+                app('view')->share('mainTitleIcon', 'fa-random');
+
+                $this->ruleRepos = app(RuleRepositoryInterface::class);
+
+                return $next($request);
+            }
+        );
+    }
+
+    /**
+     * @param Request $request
+     * @param Rule    $rule
+     *
+     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function edit(Request $request, Rule $rule)
+    {
+        $triggerCount = 0;
+        $actionCount  = 0;
+        $oldActions   = [];
+        $oldTriggers  = [];
+        // has old input?
+        if (\count($request->old()) > 0) {
+            $oldTriggers  = $this->getPreviousTriggers($request);
+            $triggerCount = \count($oldTriggers);
+            $oldActions   = $this->getPreviousActions($request);
+            $actionCount  = \count($oldActions);
+        }
+
+        // overrule old input when it has no rule data:
+        if (0 === $triggerCount && 0 === $actionCount) {
+            $oldTriggers  = $this->getCurrentTriggers($rule);
+            $triggerCount = \count($oldTriggers);
+            $oldActions   = $this->getCurrentActions($rule);
+            $actionCount  = \count($oldActions);
+        }
+
+        $hasOldInput = null !== $request->old('_token');
+        $preFilled   = [
+            'active'          => $hasOldInput ? (bool)$request->old('active') : $rule->active,
+            'stop_processing' => $hasOldInput ? (bool)$request->old('stop_processing') : $rule->stop_processing,
+            'strict'          => $hasOldInput ? (bool)$request->old('strict') : $rule->strict,
+
+        ];
+
+        // get rule trigger for update / store-journal:
+        $primaryTrigger = $this->ruleRepos->getPrimaryTrigger($rule);
+        $subTitle       = (string)trans('firefly.edit_rule', ['title' => $rule->title]);
+
+        // put previous url in session if not redirect from store (not "return_to_edit").
+        if (true !== session('rules.edit.fromUpdate')) {
+            $this->rememberPreviousUri('rules.edit.uri');
+        }
+        session()->forget('rules.edit.fromUpdate');
+
+        $request->session()->flash('preFilled', $preFilled);
+
+        return view('rules.rule.edit', compact('rule', 'subTitle', 'primaryTrigger', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount'));
+    }
+
+    /**
+     * @param RuleFormRequest $request
+     * @param Rule            $rule
+     *
+     * @return RedirectResponse|\Illuminate\Routing\Redirector
+     */
+    public function update(RuleFormRequest $request, Rule $rule)
+    {
+        $data = $request->getRuleData();
+        $this->ruleRepos->update($rule, $data);
+
+        session()->flash('success', (string)trans('firefly.updated_rule', ['title' => $rule->title]));
+        app('preferences')->mark();
+        $redirect = redirect($this->getPreviousUri('rules.edit.uri'));
+        if (1 === (int)$request->get('return_to_edit')) {
+            // @codeCoverageIgnoreStart
+            session()->put('rules.edit.fromUpdate', true);
+
+            $redirect = redirect(route('rules.edit', [$rule->id]))->withInput(['return_to_edit' => 1]);
+            // @codeCoverageIgnoreEnd
+        }
+
+        return $redirect;
+    }
+
+    /**
+     * @param Rule $rule
+     *
+     * @return array
+     *
+     */
+    private function getCurrentActions(Rule $rule): array
+    {
+        $index   = 0;
+        $actions = [];
+
+        /** @var RuleAction $entry */
+        foreach ($rule->ruleActions as $entry) {
+            $count = ($index + 1);
+            try {
+                $actions[] = view(
+                    'rules.partials.action',
+                    [
+                        'oldAction'  => $entry->action_type,
+                        'oldValue'   => $entry->action_value,
+                        'oldChecked' => $entry->stop_processing,
+                        'count'      => $count,
+                    ]
+                )->render();
+                // @codeCoverageIgnoreStart
+            } catch (Throwable $e) {
+                Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage()));
+                Log::error($e->getTraceAsString());
+            }
+            // @codeCoverageIgnoreEnd
+            ++$index;
+        }
+
+        return $actions;
+    }
+
+    /**
+     * @param Rule $rule
+     *
+     * @return array
+     *
+     */
+    private function getCurrentTriggers(Rule $rule): array
+    {
+        $index    = 0;
+        $triggers = [];
+
+        /** @var RuleTrigger $entry */
+        foreach ($rule->ruleTriggers as $entry) {
+            if ('user_action' !== $entry->trigger_type) {
+                $count = ($index + 1);
+                try {
+                    $triggers[] = view(
+                        'rules.partials.trigger',
+                        [
+                            'oldTrigger' => $entry->trigger_type,
+                            'oldValue'   => $entry->trigger_value,
+                            'oldChecked' => $entry->stop_processing,
+                            'count'      => $count,
+                        ]
+                    )->render();
+                    // @codeCoverageIgnoreStart
+                } catch (Throwable $e) {
+                    Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage()));
+                    Log::error($e->getTraceAsString());
+                }
+                // @codeCoverageIgnoreEnd
+                ++$index;
+            }
+        }
+
+        return $triggers;
+    }
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/Rule/IndexController.php b/app/Http/Controllers/Rule/IndexController.php
new file mode 100644
index 0000000000..8d39b8530c
--- /dev/null
+++ b/app/Http/Controllers/Rule/IndexController.php
@@ -0,0 +1,136 @@
+.
+ */
+declare(strict_types=1);
+
+namespace FireflyIII\Http\Controllers\Rule;
+
+use FireflyIII\Http\Controllers\Controller;
+use FireflyIII\Models\Rule;
+use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
+use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
+use FireflyIII\Support\Http\Controllers\RuleManagement;
+use FireflyIII\User;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+
+/**
+ * Class IndexController
+ */
+class IndexController extends Controller
+{
+    use RuleManagement;
+    /** @var RuleGroupRepositoryInterface */
+    private $ruleGroupRepos;
+    /** @var RuleRepositoryInterface */
+    private $ruleRepos;
+
+    /**
+     * RuleController constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        $this->middleware(
+            function ($request, $next) {
+                app('view')->share('title', (string)trans('firefly.rules'));
+                app('view')->share('mainTitleIcon', 'fa-random');
+                $this->ruleGroupRepos = app(RuleGroupRepositoryInterface::class);
+                $this->ruleRepos      = app(RuleRepositoryInterface::class);
+
+                return $next($request);
+            }
+        );
+    }
+
+    /**
+     * @param Rule $rule
+     *
+     * @return RedirectResponse|\Illuminate\Routing\Redirector
+     */
+    public function down(Rule $rule)
+    {
+        $this->ruleRepos->moveDown($rule);
+
+        return redirect(route('rules.index'));
+    }
+
+    /**
+     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     */
+    public function index()
+    {
+        /** @var User $user */
+        $user = auth()->user();
+        $this->createDefaultRuleGroup();
+        $this->createDefaultRule();
+        $ruleGroups = $this->ruleGroupRepos->getRuleGroupsWithRules($user);
+
+        return view('rules.index', compact('ruleGroups'));
+    }
+
+    /**
+     * @param Request $request
+     * @param Rule    $rule
+     *
+     * @return JsonResponse
+     */
+    public function reorderRuleActions(Request $request, Rule $rule): JsonResponse
+    {
+        $ids = $request->get('actions');
+        if (\is_array($ids)) {
+            $this->ruleRepos->reorderRuleActions($rule, $ids);
+        }
+
+        return response()->json('true');
+    }
+
+    /**
+     * @param Request $request
+     * @param Rule    $rule
+     *
+     * @return JsonResponse
+     */
+    public function reorderRuleTriggers(Request $request, Rule $rule): JsonResponse
+    {
+        $ids = $request->get('triggers');
+        if (\is_array($ids)) {
+            $this->ruleRepos->reorderRuleTriggers($rule, $ids);
+        }
+
+        return response()->json('true');
+    }
+
+
+    /**
+     * @param Rule $rule
+     *
+     * @return RedirectResponse|\Illuminate\Routing\Redirector
+     * @SuppressWarnings(PHPMD.ShortMethodName)
+     */
+    public function up(Rule $rule)
+    {
+        $this->ruleRepos->moveUp($rule);
+
+        return redirect(route('rules.index'));
+    }
+
+}
diff --git a/app/Http/Controllers/Rule/SelectController.php b/app/Http/Controllers/Rule/SelectController.php
new file mode 100644
index 0000000000..1c6cb0b04d
--- /dev/null
+++ b/app/Http/Controllers/Rule/SelectController.php
@@ -0,0 +1,283 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Http\Controllers\Rule;
+
+
+use Carbon\Carbon;
+use FireflyIII\Exceptions\FireflyException;
+use FireflyIII\Http\Controllers\Controller;
+use FireflyIII\Http\Requests\SelectTransactionsRequest;
+use FireflyIII\Http\Requests\TestRuleFormRequest;
+use FireflyIII\Jobs\ExecuteRuleOnExistingTransactions;
+use FireflyIII\Models\Rule;
+use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use FireflyIII\Support\Http\Controllers\RuleManagement;
+use FireflyIII\TransactionRules\TransactionMatcher;
+use FireflyIII\User;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Support\Collection;
+use Log;
+use Throwable;
+
+/**
+ * Class SelectController
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class SelectController extends Controller
+{
+    use RuleManagement;
+    /** @var AccountRepositoryInterface */
+    private $accountRepos;
+
+    /**
+     * RuleController constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+
+        $this->middleware(
+            function ($request, $next) {
+                app('view')->share('title', (string)trans('firefly.rules'));
+                app('view')->share('mainTitleIcon', 'fa-random');
+
+                $this->accountRepos = app(AccountRepositoryInterface::class);
+
+                return $next($request);
+            }
+        );
+    }
+
+    /**
+     * Execute the given rule on a set of existing transactions.
+     *
+     * @param SelectTransactionsRequest $request
+     * @param Rule                      $rule
+     *
+     * @return RedirectResponse
+     */
+    public function execute(SelectTransactionsRequest $request, Rule $rule): RedirectResponse
+    {
+        // Get parameters specified by the user
+        /** @var User $user */
+        $user      = auth()->user();
+        $accounts  = $this->accountRepos->getAccountsById($request->get('accounts'));
+        $startDate = new Carbon($request->get('start_date'));
+        $endDate   = new Carbon($request->get('end_date'));
+
+        // Create a job to do the work asynchronously
+        $job = new ExecuteRuleOnExistingTransactions($rule);
+
+        // Apply parameters to the job
+        $job->setUser($user);
+        $job->setAccounts($accounts);
+        $job->setStartDate($startDate);
+        $job->setEndDate($endDate);
+
+        // Dispatch a new job to execute it in a queue
+        $this->dispatch($job);
+
+        // Tell the user that the job is queued
+        session()->flash('success', (string)trans('firefly.applied_rule_selection', ['title' => $rule->title]));
+
+        return redirect()->route('rules.index');
+    }
+
+
+    /**
+     * @param Rule $rule
+     *
+     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     */
+    public function selectTransactions(Rule $rule)
+    {
+        // does the user have shared accounts?
+        $first    = session('first')->format('Y-m-d');
+        $today    = Carbon::create()->format('Y-m-d');
+        $subTitle = (string)trans('firefly.apply_rule_selection', ['title' => $rule->title]);
+
+        return view('rules.rule.select-transactions', compact('first', 'today', 'rule', 'subTitle'));
+    }
+
+
+    /**
+     * This method allows the user to test a certain set of rule triggers. The rule triggers are passed along
+     * using the URL parameters (GET), and are usually put there using a Javascript thing.
+     *
+     * This method will parse and validate those rules and create a "TransactionMatcher" which will attempt
+     * to find transaction journals matching the users input. A maximum range of transactions to try (range) and
+     * a maximum number of transactions to return (limit) are set as well.
+     *
+     * @param TestRuleFormRequest $request
+     *
+     * @return JsonResponse
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testTriggers(TestRuleFormRequest $request): JsonResponse
+    {
+        // build trigger array from response
+        $triggers = $this->getValidTriggerList($request);
+
+        if (0 === \count($triggers)) {
+            return response()->json(['html' => '', 'warning' => (string)trans('firefly.warning_no_valid_triggers')]); // @codeCoverageIgnore
+        }
+
+        $limit                = (int)config('firefly.test-triggers.limit');
+        $range                = (int)config('firefly.test-triggers.range');
+        $matchingTransactions = new Collection;
+        /** @var TransactionMatcher $matcher */
+        $matcher = app(TransactionMatcher::class);
+        $matcher->setLimit($limit);
+        $matcher->setRange($range);
+        $matcher->setTriggers($triggers);
+        try {
+            $matchingTransactions = $matcher->findTransactionsByTriggers();
+            // @codeCoverageIgnoreStart
+        } catch (FireflyException $exception) {
+            Log::error(sprintf('Could not grab transactions in testTriggers(): %s', $exception->getMessage()));
+            Log::error($exception->getTraceAsString());
+        }
+        // @codeCoverageIgnoreStart
+
+
+        // Warn the user if only a subset of transactions is returned
+        $warning = '';
+        if ($matchingTransactions->count() === $limit) {
+            $warning = (string)trans('firefly.warning_transaction_subset', ['max_num_transactions' => $limit]); // @codeCoverageIgnore
+        }
+        if (0 === $matchingTransactions->count()) {
+            $warning = (string)trans('firefly.warning_no_matching_transactions', ['num_transactions' => $range]); // @codeCoverageIgnore
+        }
+
+        // Return json response
+        $view = 'ERROR, see logs.';
+        try {
+            $view = view('list.journals-tiny', ['transactions' => $matchingTransactions])->render();
+            // @codeCoverageIgnoreStart
+        } catch (Throwable $exception) {
+            Log::error(sprintf('Could not render view in testTriggers(): %s', $exception->getMessage()));
+            Log::error($exception->getTraceAsString());
+        }
+
+        // @codeCoverageIgnoreEnd
+
+        return response()->json(['html' => $view, 'warning' => $warning]);
+    }
+
+    /**
+     * This method allows the user to test a certain set of rule triggers. The rule triggers are grabbed from
+     * the rule itself.
+     *
+     * This method will parse and validate those rules and create a "TransactionMatcher" which will attempt
+     * to find transaction journals matching the users input. A maximum range of transactions to try (range) and
+     * a maximum number of transactions to return (limit) are set as well.
+     *
+     * @param Rule $rule
+     *
+     * @return JsonResponse
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testTriggersByRule(Rule $rule): JsonResponse
+    {
+        $triggers = $rule->ruleTriggers;
+
+        if (0 === \count($triggers)) {
+            return response()->json(['html' => '', 'warning' => (string)trans('firefly.warning_no_valid_triggers')]); // @codeCoverageIgnore
+        }
+
+        $limit                = (int)config('firefly.test-triggers.limit');
+        $range                = (int)config('firefly.test-triggers.range');
+        $matchingTransactions = new Collection;
+
+        /** @var TransactionMatcher $matcher */
+        $matcher = app(TransactionMatcher::class);
+        $matcher->setLimit($limit);
+        $matcher->setRange($range);
+        $matcher->setRule($rule);
+        try {
+            $matchingTransactions = $matcher->findTransactionsByRule();
+            // @codeCoverageIgnoreStart
+        } catch (FireflyException $exception) {
+            Log::error(sprintf('Could not grab transactions in testTriggersByRule(): %s', $exception->getMessage()));
+            Log::error($exception->getTraceAsString());
+        }
+        // @codeCoverageIgnoreEnd
+
+        // Warn the user if only a subset of transactions is returned
+        $warning = '';
+        if ($matchingTransactions->count() === $limit) {
+            $warning = (string)trans('firefly.warning_transaction_subset', ['max_num_transactions' => $limit]); // @codeCoverageIgnore
+        }
+        if (0 === $matchingTransactions->count()) {
+            $warning = (string)trans('firefly.warning_no_matching_transactions', ['num_transactions' => $range]); // @codeCoverageIgnore
+        }
+
+        // Return json response
+        $view = 'ERROR, see logs.';
+        try {
+            $view = view('list.journals-tiny', ['transactions' => $matchingTransactions])->render();
+            // @codeCoverageIgnoreStart
+        } catch (Throwable $exception) {
+            Log::error(sprintf('Could not render view in testTriggersByRule(): %s', $exception->getMessage()));
+            Log::error($exception->getTraceAsString());
+        }
+
+        // @codeCoverageIgnoreEnd
+
+        return response()->json(['html' => $view, 'warning' => $warning]);
+    }
+
+
+    /**
+     * @param TestRuleFormRequest $request
+     *
+     * @return array
+     */
+    private function getValidTriggerList(TestRuleFormRequest $request): array
+    {
+        $triggers = [];
+        $data     = [
+            'rule-triggers'       => $request->get('rule-trigger'),
+            'rule-trigger-values' => $request->get('rule-trigger-value'),
+            'rule-trigger-stop'   => $request->get('rule-trigger-stop'),
+        ];
+        if (\is_array($data['rule-triggers'])) {
+            foreach ($data['rule-triggers'] as $index => $triggerType) {
+                $data['rule-trigger-stop'][$index] = (int)($data['rule-trigger-stop'][$index] ?? 0.0);
+                $triggers[]                        = [
+                    'type'           => $triggerType,
+                    'value'          => $data['rule-trigger-values'][$index],
+                    'stopProcessing' => 1 === (int)$data['rule-trigger-stop'][$index],
+                ];
+            }
+        }
+
+        return $triggers;
+    }
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/RuleController.php b/app/Http/Controllers/RuleController.php
deleted file mode 100644
index 7083fa714e..0000000000
--- a/app/Http/Controllers/RuleController.php
+++ /dev/null
@@ -1,875 +0,0 @@
-.
- */
-declare(strict_types=1);
-
-namespace FireflyIII\Http\Controllers;
-
-use Carbon\Carbon;
-use FireflyIII\Exceptions\FireflyException;
-use FireflyIII\Http\Requests\RuleFormRequest;
-use FireflyIII\Http\Requests\SelectTransactionsRequest;
-use FireflyIII\Http\Requests\TestRuleFormRequest;
-use FireflyIII\Jobs\ExecuteRuleOnExistingTransactions;
-use FireflyIII\Models\Bill;
-use FireflyIII\Models\Rule;
-use FireflyIII\Models\RuleAction;
-use FireflyIII\Models\RuleGroup;
-use FireflyIII\Models\RuleTrigger;
-use FireflyIII\Repositories\Account\AccountRepositoryInterface;
-use FireflyIII\Repositories\Bill\BillRepositoryInterface;
-use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
-use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
-use FireflyIII\TransactionRules\TransactionMatcher;
-use FireflyIII\User;
-use Illuminate\Http\JsonResponse;
-use Illuminate\Http\RedirectResponse;
-use Illuminate\Http\Request;
-use Illuminate\Support\Collection;
-use Log;
-use Throwable;
-
-/**
- * Class RuleController.
- */
-class RuleController extends Controller
-{
-    /** @var AccountRepositoryInterface */
-    private $accountRepos;
-    /** @var BillRepositoryInterface */
-    private $billRepos;
-    /** @var RuleGroupRepositoryInterface */
-    private $ruleGroupRepos;
-    /** @var RuleRepositoryInterface */
-    private $ruleRepos;
-
-    /**
-     * RuleController constructor.
-     */
-    public function __construct()
-    {
-        parent::__construct();
-
-        $this->middleware(
-            function ($request, $next) {
-                app('view')->share('title', (string)trans('firefly.rules'));
-                app('view')->share('mainTitleIcon', 'fa-random');
-
-                $this->accountRepos   = app(AccountRepositoryInterface::class);
-                $this->billRepos      = app(BillRepositoryInterface::class);
-                $this->ruleGroupRepos = app(RuleGroupRepositoryInterface::class);
-                $this->ruleRepos      = app(RuleRepositoryInterface::class);
-
-                return $next($request);
-            }
-        );
-    }
-
-    /**
-     * Create a new rule. It will be stored under the given $ruleGroup.
-     *
-     * @param Request   $request
-     * @param RuleGroup $ruleGroup
-     *
-     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
-     */
-    public function create(Request $request, RuleGroup $ruleGroup)
-    {
-        $this->createDefaultRuleGroup();
-        $this->createDefaultRule();
-        $bill         = null;
-        $billId       = (int)$request->get('fromBill');
-        $preFilled    = [
-            'strict' => true,
-        ];
-        $oldTriggers  = [];
-        $oldActions   = [];
-        $returnToBill = false;
-
-        if ('true' === $request->get('return')) {
-            $returnToBill = true;
-        }
-
-        // has bill?
-        if ($billId > 0) {
-            $bill = $this->billRepos->find($billId);
-        }
-
-        // has old input?
-        if ($request->old()) {
-            $oldTriggers = $this->getPreviousTriggers($request);
-            $oldActions  = $this->getPreviousActions($request);
-        }
-        // has existing bill refered to in URI?
-        if (null !== $bill && !$request->old()) {
-
-            // create some sensible defaults:
-            $preFilled['title']       = (string)trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]);
-            $preFilled['description'] = (string)trans('firefly.new_rule_for_bill_description', ['name' => $bill->name]);
-
-
-            // get triggers and actions for bill:
-            $oldTriggers = $this->getTriggersForBill($bill);
-            $oldActions  = $this->getActionsForBill($bill);
-        }
-
-        $triggerCount = \count($oldTriggers);
-        $actionCount  = \count($oldActions);
-        $subTitleIcon = 'fa-clone';
-        $subTitle     = (string)trans('firefly.make_new_rule', ['title' => $ruleGroup->title]);
-
-        $request->session()->flash('preFilled', $preFilled);
-
-        // put previous url in session if not redirect from store (not "create another").
-        if (true !== session('rules.create.fromStore')) {
-            $this->rememberPreviousUri('rules.create.uri');
-        }
-        session()->forget('rules.create.fromStore');
-
-        return view(
-            'rules.rule.create',
-            compact(
-                'subTitleIcon', 'oldTriggers', 'returnToBill', 'preFilled', 'bill', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup',
-                'subTitle'
-            )
-        );
-    }
-
-    /**
-     * Delete a given rule.
-     *
-     * @param Rule $rule
-     *
-     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
-     */
-    public function delete(Rule $rule)
-    {
-        $subTitle = (string)trans('firefly.delete_rule', ['title' => $rule->title]);
-
-        // put previous url in session
-        $this->rememberPreviousUri('rules.delete.uri');
-
-        return view('rules.rule.delete', compact('rule', 'subTitle'));
-    }
-
-    /**
-     * Actually destroy the given rule.
-     *
-     * @param Rule $rule
-     *
-     * @return RedirectResponse
-     */
-    public function destroy(Rule $rule): RedirectResponse
-    {
-        $title = $rule->title;
-        $this->ruleRepos->destroy($rule);
-
-        session()->flash('success', (string)trans('firefly.deleted_rule', ['title' => $title]));
-        app('preferences')->mark();
-
-        return redirect($this->getPreviousUri('rules.delete.uri'));
-    }
-
-    /**
-     * @param Rule $rule
-     *
-     * @return RedirectResponse|\Illuminate\Routing\Redirector
-     */
-    public function down(Rule $rule)
-    {
-        $this->ruleRepos->moveDown($rule);
-
-        return redirect(route('rules.index'));
-    }
-
-    /**
-     * @param Request $request
-     * @param Rule    $rule
-     *
-     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
-     */
-    public function edit(Request $request, Rule $rule)
-    {
-        $triggerCount = 0;
-        $actionCount  = 0;
-        $oldActions   = [];
-        $oldTriggers  = [];
-        // has old input?
-        if (\count($request->old()) > 0) {
-            $oldTriggers  = $this->getPreviousTriggers($request);
-            $triggerCount = \count($oldTriggers);
-            $oldActions   = $this->getPreviousActions($request);
-            $actionCount  = \count($oldActions);
-        }
-
-        // overrule old input when it as no rule data:
-        if (0 === $triggerCount && 0 === $actionCount) {
-            $oldTriggers  = $this->getCurrentTriggers($rule);
-            $triggerCount = \count($oldTriggers);
-            $oldActions   = $this->getCurrentActions($rule);
-            $actionCount  = \count($oldActions);
-        }
-
-        $hasOldInput = null !== $request->old('_token');
-        $preFilled   = [
-            'active'          => $hasOldInput ? (bool)$request->old('active') : $rule->active,
-            'stop_processing' => $hasOldInput ? (bool)$request->old('stop_processing') : $rule->stop_processing,
-            'strict'          => $hasOldInput ? (bool)$request->old('strict') : $rule->strict,
-
-        ];
-
-        // get rule trigger for update / store-journal:
-        $primaryTrigger = $this->ruleRepos->getPrimaryTrigger($rule);
-        $subTitle       = (string)trans('firefly.edit_rule', ['title' => $rule->title]);
-
-        // put previous url in session if not redirect from store (not "return_to_edit").
-        if (true !== session('rules.edit.fromUpdate')) {
-            $this->rememberPreviousUri('rules.edit.uri');
-        }
-        session()->forget('rules.edit.fromUpdate');
-
-        $request->session()->flash('preFilled', $preFilled);
-
-        return view('rules.rule.edit', compact('rule', 'subTitle', 'primaryTrigger', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount'));
-    }
-
-    /**
-     * Execute the given rule on a set of existing transactions.
-     *
-     * @param SelectTransactionsRequest $request
-     * @param Rule                      $rule
-     *
-     * @return RedirectResponse
-     *
-     * @internal param RuleGroup $ruleGroup
-     */
-    public function execute(SelectTransactionsRequest $request, Rule $rule): RedirectResponse
-    {
-        // Get parameters specified by the user
-        /** @var User $user */
-        $user      = auth()->user();
-        $accounts  = $this->accountRepos->getAccountsById($request->get('accounts'));
-        $startDate = new Carbon($request->get('start_date'));
-        $endDate   = new Carbon($request->get('end_date'));
-
-        // Create a job to do the work asynchronously
-        $job = new ExecuteRuleOnExistingTransactions($rule);
-
-        // Apply parameters to the job
-        $job->setUser($user);
-        $job->setAccounts($accounts);
-        $job->setStartDate($startDate);
-        $job->setEndDate($endDate);
-
-        // Dispatch a new job to execute it in a queue
-        $this->dispatch($job);
-
-        // Tell the user that the job is queued
-        session()->flash('success', (string)trans('firefly.applied_rule_selection', ['title' => $rule->title]));
-
-        return redirect()->route('rules.index');
-    }
-
-    /**
-     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
-     */
-    public function index()
-    {
-        /** @var User $user */
-        $user = auth()->user();
-        $this->createDefaultRuleGroup();
-        $this->createDefaultRule();
-        $ruleGroups = $this->ruleGroupRepos->getRuleGroupsWithRules($user);
-
-        return view('rules.index', compact('ruleGroups'));
-    }
-
-    /**
-     * @param Request $request
-     * @param Rule    $rule
-     *
-     * @return JsonResponse
-     */
-    public function reorderRuleActions(Request $request, Rule $rule): JsonResponse
-    {
-        $ids = $request->get('actions');
-        if (\is_array($ids)) {
-            $this->ruleRepos->reorderRuleActions($rule, $ids);
-        }
-
-        return response()->json('true');
-    }
-
-    /**
-     * @param Request $request
-     * @param Rule    $rule
-     *
-     * @return JsonResponse
-     */
-    public function reorderRuleTriggers(Request $request, Rule $rule): JsonResponse
-    {
-        $ids = $request->get('triggers');
-        if (\is_array($ids)) {
-            $this->ruleRepos->reorderRuleTriggers($rule, $ids);
-        }
-
-        return response()->json('true');
-    }
-
-    /**
-     * @param Rule $rule
-     *
-     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
-     */
-    public function selectTransactions(Rule $rule)
-    {
-        // does the user have shared accounts?
-        $first    = session('first')->format('Y-m-d');
-        $today    = Carbon::create()->format('Y-m-d');
-        $subTitle = (string)trans('firefly.apply_rule_selection', ['title' => $rule->title]);
-
-        return view('rules.rule.select-transactions', compact('first', 'today', 'rule', 'subTitle'));
-    }
-
-    /**
-     * @param RuleFormRequest $request
-     *
-     * @return RedirectResponse|\Illuminate\Routing\Redirector
-     */
-    public function store(RuleFormRequest $request)
-    {
-        $data = $request->getRuleData();
-        $rule = $this->ruleRepos->store($data);
-        session()->flash('success', (string)trans('firefly.stored_new_rule', ['title' => $rule->title]));
-        app('preferences')->mark();
-
-        // redirect to show bill.
-        if ('true' === $request->get('return_to_bill') && (int)$request->get('bill_id') > 0) {
-            return redirect(route('bills.show', [(int)$request->get('bill_id')])); // @codeCoverageIgnore
-        }
-
-        // redirect to new bill creation.
-        if ((int)$request->get('bill_id') > 0) {
-            return redirect($this->getPreviousUri('bills.create.uri')); // @codeCoverageIgnore
-        }
-
-        $redirect = redirect($this->getPreviousUri('rules.create.uri'));
-
-        if (1 === (int)$request->get('create_another')) {
-            // @codeCoverageIgnoreStart
-            session()->put('rules.create.fromStore', true);
-            $redirect = redirect(route('rules.create', [$data['rule_group_id']]))->withInput();
-            // @codeCoverageIgnoreEnd
-        }
-
-        return $redirect;
-    }
-
-    /**
-     * This method allows the user to test a certain set of rule triggers. The rule triggers are passed along
-     * using the URL parameters (GET), and are usually put there using a Javascript thing.
-     *
-     * This method will parse and validate those rules and create a "TransactionMatcher" which will attempt
-     * to find transaction journals matching the users input. A maximum range of transactions to try (range) and
-     * a maximum number of transactions to return (limit) are set as well.
-     *
-     * @param TestRuleFormRequest $request
-     *
-     * @return JsonResponse
-     */
-    public function testTriggers(TestRuleFormRequest $request): JsonResponse
-    {
-        // build trigger array from response
-        $triggers = $this->getValidTriggerList($request);
-
-        if (0 === \count($triggers)) {
-            return response()->json(['html' => '', 'warning' => (string)trans('firefly.warning_no_valid_triggers')]); // @codeCoverageIgnore
-        }
-
-        $limit                = (int)config('firefly.test-triggers.limit');
-        $range                = (int)config('firefly.test-triggers.range');
-        $matchingTransactions = new Collection;
-        /** @var TransactionMatcher $matcher */
-        $matcher = app(TransactionMatcher::class);
-        $matcher->setLimit($limit);
-        $matcher->setRange($range);
-        $matcher->setTriggers($triggers);
-        try {
-            $matchingTransactions = $matcher->findTransactionsByTriggers();
-            // @codeCoverageIgnoreStart
-        } catch (FireflyException $exception) {
-            Log::error(sprintf('Could not grab transactions in testTriggers(): %s', $exception->getMessage()));
-            Log::error($exception->getTraceAsString());
-        }
-        // @codeCoverageIgnoreStart
-
-
-        // Warn the user if only a subset of transactions is returned
-        $warning = '';
-        if ($matchingTransactions->count() === $limit) {
-            $warning = (string)trans('firefly.warning_transaction_subset', ['max_num_transactions' => $limit]); // @codeCoverageIgnore
-        }
-        if (0 === $matchingTransactions->count()) {
-            $warning = (string)trans('firefly.warning_no_matching_transactions', ['num_transactions' => $range]); // @codeCoverageIgnore
-        }
-
-        // Return json response
-        $view = 'ERROR, see logs.';
-        try {
-            $view = view('list.journals-tiny', ['transactions' => $matchingTransactions])->render();
-            // @codeCoverageIgnoreStart
-        } catch (Throwable $exception) {
-            Log::error(sprintf('Could not render view in testTriggers(): %s', $exception->getMessage()));
-            Log::error($exception->getTraceAsString());
-        }
-
-        // @codeCoverageIgnoreEnd
-
-        return response()->json(['html' => $view, 'warning' => $warning]);
-    }
-
-    /**
-     * This method allows the user to test a certain set of rule triggers. The rule triggers are grabbed from
-     * the rule itself.
-     *
-     * This method will parse and validate those rules and create a "TransactionMatcher" which will attempt
-     * to find transaction journals matching the users input. A maximum range of transactions to try (range) and
-     * a maximum number of transactions to return (limit) are set as well.
-     *
-     * @param Rule $rule
-     *
-     * @return JsonResponse
-     */
-    public function testTriggersByRule(Rule $rule): JsonResponse
-    {
-        $triggers = $rule->ruleTriggers;
-
-        if (0 === \count($triggers)) {
-            return response()->json(['html' => '', 'warning' => (string)trans('firefly.warning_no_valid_triggers')]); // @codeCoverageIgnore
-        }
-
-        $limit                = (int)config('firefly.test-triggers.limit');
-        $range                = (int)config('firefly.test-triggers.range');
-        $matchingTransactions = new Collection;
-
-        /** @var TransactionMatcher $matcher */
-        $matcher = app(TransactionMatcher::class);
-        $matcher->setLimit($limit);
-        $matcher->setRange($range);
-        $matcher->setRule($rule);
-        try {
-            $matchingTransactions = $matcher->findTransactionsByRule();
-            // @codeCoverageIgnoreStart
-        } catch (FireflyException $exception) {
-            Log::error(sprintf('Could not grab transactions in testTriggersByRule(): %s', $exception->getMessage()));
-            Log::error($exception->getTraceAsString());
-        }
-        // @codeCoverageIgnoreEnd
-
-        // Warn the user if only a subset of transactions is returned
-        $warning = '';
-        if ($matchingTransactions->count() === $limit) {
-            $warning = (string)trans('firefly.warning_transaction_subset', ['max_num_transactions' => $limit]); // @codeCoverageIgnore
-        }
-        if (0 === $matchingTransactions->count()) {
-            $warning = (string)trans('firefly.warning_no_matching_transactions', ['num_transactions' => $range]); // @codeCoverageIgnore
-        }
-
-        // Return json response
-        $view = 'ERROR, see logs.';
-        try {
-            $view = view('list.journals-tiny', ['transactions' => $matchingTransactions])->render();
-            // @codeCoverageIgnoreStart
-        } catch (Throwable $exception) {
-            Log::error(sprintf('Could not render view in testTriggersByRule(): %s', $exception->getMessage()));
-            Log::error($exception->getTraceAsString());
-        }
-
-        // @codeCoverageIgnoreEnd
-
-        return response()->json(['html' => $view, 'warning' => $warning]);
-    }
-
-    /**
-     * @param Rule $rule
-     *
-     * @return RedirectResponse|\Illuminate\Routing\Redirector
-     */
-    public function up(Rule $rule)
-    {
-        $this->ruleRepos->moveUp($rule);
-
-        return redirect(route('rules.index'));
-    }
-
-    /**
-     * @param RuleFormRequest $request
-     * @param Rule            $rule
-     *
-     * @return RedirectResponse|\Illuminate\Routing\Redirector
-     */
-    public function update(RuleFormRequest $request, Rule $rule)
-    {
-        $data = $request->getRuleData();
-        $this->ruleRepos->update($rule, $data);
-
-        session()->flash('success', (string)trans('firefly.updated_rule', ['title' => $rule->title]));
-        app('preferences')->mark();
-        $redirect = redirect($this->getPreviousUri('rules.edit.uri'));
-        if (1 === (int)$request->get('return_to_edit')) {
-            // @codeCoverageIgnoreStart
-            session()->put('rules.edit.fromUpdate', true);
-
-            $redirect = redirect(route('rules.edit', [$rule->id]))->withInput(['return_to_edit' => 1]);
-            // @codeCoverageIgnoreEnd
-        }
-
-        return $redirect;
-    }
-
-    /**
-     *
-     */
-    private function createDefaultRule(): void
-    {
-        if (0 === $this->ruleRepos->count()) {
-            $data = [
-                'rule_group_id'   => $this->ruleRepos->getFirstRuleGroup()->id,
-                'stop-processing' => 0,
-                'title'           => (string)trans('firefly.default_rule_name'),
-                'description'     => (string)trans('firefly.default_rule_description'),
-                'trigger'         => 'store-journal',
-                'strict'          => true,
-                'rule-triggers'   => [
-                    [
-                        'name'            => 'description_is',
-                        'value'           => (string)trans('firefly.default_rule_trigger_description'),
-                        'stop-processing' => false,
-
-                    ],
-                    [
-                        'name'            => 'from_account_is',
-                        'value'           => (string)trans('firefly.default_rule_trigger_from_account'),
-                        'stop-processing' => false,
-
-                    ],
-
-                ],
-                'rule-actions'    => [
-                    [
-                        'name'            => 'prepend_description',
-                        'value'           => (string)trans('firefly.default_rule_action_prepend'),
-                        'stop-processing' => false,
-                    ],
-                    [
-                        'name'            => 'set_category',
-                        'value'           => (string)trans('firefly.default_rule_action_set_category'),
-                        'stop-processing' => false,
-                    ],
-                ],
-            ];
-
-            $this->ruleRepos->store($data);
-        }
-    }
-
-    /**
-     *
-     */
-    private function createDefaultRuleGroup(): void
-    {
-        if (0 === $this->ruleGroupRepos->count()) {
-            $data = [
-                'title'       => (string)trans('firefly.default_rule_group_name'),
-                'description' => (string)trans('firefly.default_rule_group_description'),
-            ];
-
-            $this->ruleGroupRepos->store($data);
-        }
-    }
-
-    /**
-     * @param Bill $bill
-     *
-     * @return array
-     */
-    private function getActionsForBill(Bill $bill): array
-    {
-        $actions = [];
-        try {
-            $actions[] = view(
-                'rules.partials.action',
-                [
-                    'oldAction'  => 'link_to_bill',
-                    'oldValue'   => $bill->name,
-                    'oldChecked' => false,
-                    'count'      => 1,
-                ]
-            )->render();
-            // @codeCoverageIgnoreStart
-        } catch (Throwable $e) {
-            Log::error(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage()));
-            Log::error($e->getTraceAsString());
-        }
-
-        // @codeCoverageIgnoreEnd
-
-        return $actions;
-    }
-
-    /**
-     * @param Rule $rule
-     *
-     * @return array
-     *
-
-     */
-    private function getCurrentActions(Rule $rule): array
-    {
-        $index   = 0;
-        $actions = [];
-
-        /** @var RuleAction $entry */
-        foreach ($rule->ruleActions as $entry) {
-            $count = ($index + 1);
-            try {
-                $actions[] = view(
-                    'rules.partials.action',
-                    [
-                        'oldAction'  => $entry->action_type,
-                        'oldValue'   => $entry->action_value,
-                        'oldChecked' => $entry->stop_processing,
-                        'count'      => $count,
-                    ]
-                )->render();
-                // @codeCoverageIgnoreStart
-            } catch (Throwable $e) {
-                Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage()));
-                Log::error($e->getTraceAsString());
-            }
-            // @codeCoverageIgnoreEnd
-            ++$index;
-        }
-
-        return $actions;
-    }
-
-    /**
-     * @param Rule $rule
-     *
-     * @return array
-     *
-     */
-    private function getCurrentTriggers(Rule $rule): array
-    {
-        $index    = 0;
-        $triggers = [];
-
-        /** @var RuleTrigger $entry */
-        foreach ($rule->ruleTriggers as $entry) {
-            if ('user_action' !== $entry->trigger_type) {
-                $count = ($index + 1);
-                try {
-                    $triggers[] = view(
-                        'rules.partials.trigger',
-                        [
-                            'oldTrigger' => $entry->trigger_type,
-                            'oldValue'   => $entry->trigger_value,
-                            'oldChecked' => $entry->stop_processing,
-                            'count'      => $count,
-                        ]
-                    )->render();
-                    // @codeCoverageIgnoreStart
-                } catch (Throwable $e) {
-                    Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage()));
-                    Log::error($e->getTraceAsString());
-                }
-                // @codeCoverageIgnoreEnd
-                ++$index;
-            }
-        }
-
-        return $triggers;
-    }
-
-    /**
-     * @param Request $request
-     *
-     * @return array
-     *
-     */
-    private function getPreviousActions(Request $request): array
-    {
-        $newIndex = 0;
-        $actions  = [];
-        /** @var array $oldActions */
-        $oldActions = \is_array($request->old('rule-action')) ? $request->old('rule-action') : [];
-        foreach ($oldActions as $index => $entry) {
-            $count   = ($newIndex + 1);
-            $checked = isset($request->old('rule-action-stop')[$index]) ? true : false;
-            try {
-                $actions[] = view(
-                    'rules.partials.action',
-                    [
-                        'oldAction'  => $entry,
-                        'oldValue'   => $request->old('rule-action-value')[$index],
-                        'oldChecked' => $checked,
-                        'count'      => $count,
-                    ]
-                )->render();
-                // @codeCoverageIgnoreStart
-            } catch (Throwable $e) {
-                Log::debug(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage()));
-                Log::error($e->getTraceAsString());
-            }
-            // @codeCoverageIgnoreEnd
-            ++$newIndex;
-        }
-
-        return $actions;
-    }
-
-    /**
-     * @param Request $request
-     *
-     * @return array
-     *
-
-     */
-    private function getPreviousTriggers(Request $request): array
-    {
-        $newIndex = 0;
-        $triggers = [];
-        /** @var array $oldTriggers */
-        $oldTriggers = \is_array($request->old('rule-trigger')) ? $request->old('rule-trigger') : [];
-        foreach ($oldTriggers as $index => $entry) {
-            $count      = ($newIndex + 1);
-            $oldChecked = isset($request->old('rule-trigger-stop')[$index]) ? true : false;
-            try {
-                $triggers[] = view(
-                    'rules.partials.trigger',
-                    [
-                        'oldTrigger' => $entry,
-                        'oldValue'   => $request->old('rule-trigger-value')[$index],
-                        'oldChecked' => $oldChecked,
-                        'count'      => $count,
-                    ]
-                )->render();
-                // @codeCoverageIgnoreStart
-            } catch (Throwable $e) {
-                Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
-                Log::error($e->getTraceAsString());
-            }
-            // @codeCoverageIgnoreEnd
-            ++$newIndex;
-        }
-
-        return $triggers;
-    }
-
-    /**
-     * Create fake triggers to match the bill's properties
-     *
-     * @param Bill $bill
-     *
-     * @return array
-     */
-    private function getTriggersForBill(Bill $bill): array
-    {
-        $triggers = [];
-        /** @noinspection BadExceptionsProcessingInspection */
-        try {
-            $triggers[] = view(
-                'rules.partials.trigger',
-                [
-                    'oldTrigger' => 'currency_is',
-                    'oldValue'   => $bill->transactionCurrency()->first()->name,
-                    'oldChecked' => false,
-                    'count'      => 1,
-                ]
-            )->render();
-
-            $triggers[] = view(
-                'rules.partials.trigger',
-                [
-                    'oldTrigger' => 'amount_more',
-                    'oldValue'   => round($bill->amount_min, 12),
-                    'oldChecked' => false,
-                    'count'      => 2,
-                ]
-            )->render();
-
-            $triggers[] = view(
-                'rules.partials.trigger',
-                [
-                    'oldTrigger' => 'amount_less',
-                    'oldValue'   => round($bill->amount_max, 12),
-                    'oldChecked' => false,
-                    'count'      => 3,
-                ]
-            )->render();
-
-            $triggers[] = view(
-                'rules.partials.trigger',
-                [
-                    'oldTrigger' => 'description_contains',
-                    'oldValue'   => $bill->name, 12,
-                    'oldChecked' => false,
-                    'count'      => 4,
-                ]
-            )->render();
-            // @codeCoverageIgnoreStart
-        } catch (Throwable $e) {
-            Log::debug(sprintf('Throwable was thrown in getTriggersForBill(): %s', $e->getMessage()));
-            Log::debug($e->getTraceAsString());
-        }
-
-        // @codeCoverageIgnoreEnd
-
-        return $triggers;
-    }
-
-    /**
-     * @param TestRuleFormRequest $request
-     *
-     * @return array
-     */
-    private function getValidTriggerList(TestRuleFormRequest $request): array
-    {
-        $triggers = [];
-        $data     = [
-            'rule-triggers'       => $request->get('rule-trigger'),
-            'rule-trigger-values' => $request->get('rule-trigger-value'),
-            'rule-trigger-stop'   => $request->get('rule-trigger-stop'),
-        ];
-        if (\is_array($data['rule-triggers'])) {
-            foreach ($data['rule-triggers'] as $index => $triggerType) {
-                $data['rule-trigger-stop'][$index] = (int)($data['rule-trigger-stop'][$index] ?? 0.0);
-                $triggers[]                        = [
-                    'type'           => $triggerType,
-                    'value'          => $data['rule-trigger-values'][$index],
-                    'stopProcessing' => 1 === (int)$data['rule-trigger-stop'][$index],
-                ];
-            }
-        }
-
-        return $triggers;
-    }
-}
diff --git a/app/Http/Controllers/RuleGroupController.php b/app/Http/Controllers/RuleGroupController.php
index 2516ad77ea..543da778fc 100644
--- a/app/Http/Controllers/RuleGroupController.php
+++ b/app/Http/Controllers/RuleGroupController.php
@@ -35,6 +35,8 @@ use Illuminate\Http\Request;
 
 /**
  * Class RuleGroupController.
+ *
+ * @SuppressWarnings(PHPMD.TooManyPublicMethods)
  */
 class RuleGroupController extends Controller
 {
@@ -231,6 +233,8 @@ class RuleGroupController extends Controller
      * @param RuleGroup                    $ruleGroup
      *
      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
+     *
+     * @SuppressWarnings(PHPMD.ShortMethodName)
      */
     public function up(RuleGroupRepositoryInterface $repository, RuleGroup $ruleGroup)
     {
diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php
index 21f0115c12..a5584a6962 100644
--- a/app/Http/Controllers/SearchController.php
+++ b/app/Http/Controllers/SearchController.php
@@ -73,7 +73,7 @@ class SearchController extends Controller
      * @param SearchInterface $searcher
      *
      * @return \Illuminate\Http\JsonResponse
-     * @throws \Throwable
+
      */
     public function search(Request $request, SearchInterface $searcher): JsonResponse
     {
diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php
index cb43bbb42a..d783fa9fca 100644
--- a/app/Http/Controllers/TagController.php
+++ b/app/Http/Controllers/TagController.php
@@ -166,7 +166,12 @@ class TagController extends Controller
      * @param Tag         $tag
      * @param string|null $moment
      *
+     * TODO will be cleaned up and separated
+     *
      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function show(Request $request, Tag $tag, string $moment = null)
     {
@@ -286,6 +291,8 @@ class TagController extends Controller
      * @param Tag $tag
      *
      * @return Collection
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     private function getPeriodOverview(Tag $tag): Collection
     {
diff --git a/app/Http/Controllers/Transaction/BulkController.php b/app/Http/Controllers/Transaction/BulkController.php
index 2a2a603779..a3ea753677 100644
--- a/app/Http/Controllers/Transaction/BulkController.php
+++ b/app/Http/Controllers/Transaction/BulkController.php
@@ -87,6 +87,8 @@ class BulkController extends Controller
      * @param BulkEditJournalRequest $request
      *
      * @return mixed
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function update(BulkEditJournalRequest $request)
     {
diff --git a/app/Http/Controllers/Transaction/ConvertController.php b/app/Http/Controllers/Transaction/ConvertController.php
index ca11f83e21..d2c99ae19c 100644
--- a/app/Http/Controllers/Transaction/ConvertController.php
+++ b/app/Http/Controllers/Transaction/ConvertController.php
@@ -82,16 +82,14 @@ class ConvertController extends Controller
         $subTitle       = (string)trans('firefly.convert_to_' . $destinationType->type, ['description' => $journal->description]);
         $subTitleIcon   = 'fa-exchange';
 
-        // cannot convert to its own type.
-        if ($sourceType->type === $destinationType->type) {
+        if ($sourceType->type === $destinationType->type) { // cannot convert to its own type.
             Log::debug('This is already a transaction of the expected type..');
             session()->flash('info', (string)trans('firefly.convert_is_already_type_' . $destinationType->type));
 
             return redirect(route('transactions.show', [$journal->id]));
         }
 
-        // cannot convert split.
-        if ($journal->transactions()->count() > 2) {
+        if ($journal->transactions()->count() > 2) { // cannot convert split.
             Log::info('This journal has more than two transactions.');
             session()->flash('error', (string)trans('firefly.cannot_convert_split_journal'));
 
@@ -119,7 +117,8 @@ class ConvertController extends Controller
      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
      *
      * @throws FireflyException
-     * @throws FireflyException
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function postIndex(Request $request, TransactionType $destinationType, TransactionJournal $journal)
     {
@@ -172,6 +171,9 @@ class ConvertController extends Controller
      * @return Account
      *
      * @throws FireflyException
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     private function getDestinationAccount(TransactionJournal $journal, TransactionType $destinationType, array $data): Account
     {
@@ -228,6 +230,9 @@ class ConvertController extends Controller
      * @return Account
      *
      * @throws FireflyException
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     private function getSourceAccount(TransactionJournal $journal, TransactionType $destinationType, array $data): Account
     {
diff --git a/app/Http/Controllers/Transaction/LinkController.php b/app/Http/Controllers/Transaction/LinkController.php
index 34cb561004..d4b4944e49 100644
--- a/app/Http/Controllers/Transaction/LinkController.php
+++ b/app/Http/Controllers/Transaction/LinkController.php
@@ -101,13 +101,7 @@ class LinkController extends Controller
 
         Log::debug('We are here (store)');
         $linkInfo = $request->getLinkInfo();
-        if (0 === $linkInfo['transaction_journal_id']) {
-            session()->flash('error', (string)trans('firefly.invalid_link_selection'));
-
-            return redirect(route('transactions.show', [$journal->id]));
-        }
-        $other = $this->journalRepository->findNull($linkInfo['transaction_journal_id']);
-
+        $other    = $this->journalRepository->findNull($linkInfo['transaction_journal_id']);
         if (null === $other) {
             session()->flash('error', (string)trans('firefly.invalid_link_selection'));
 
diff --git a/app/Http/Controllers/Transaction/MassController.php b/app/Http/Controllers/Transaction/MassController.php
index e8bb3ea05a..7f324c7d39 100644
--- a/app/Http/Controllers/Transaction/MassController.php
+++ b/app/Http/Controllers/Transaction/MassController.php
@@ -42,6 +42,8 @@ use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
  * Class MassController.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class MassController extends Controller
 {
@@ -85,29 +87,24 @@ class MassController extends Controller
      * @param MassDeleteJournalRequest $request
      *
      * @return mixed
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function destroy(MassDeleteJournalRequest $request)
     {
-        $ids = $request->get('confirm_mass_delete');
-        $set = new Collection;
+        $ids   = $request->get('confirm_mass_delete');
+        $count = 0;
         if (\is_array($ids)) {
             /** @var string $journalId */
             foreach ($ids as $journalId) {
                 /** @var TransactionJournal $journal */
                 $journal = $this->repository->findNull((int)$journalId);
                 if (null !== $journal && (int)$journalId === $journal->id) {
-                    $set->push($journal);
+                    $this->repository->destroy($journal);
+                    ++$count;
                 }
             }
         }
-        unset($journal);
-        $count = 0;
 
-        /** @var TransactionJournal $journal */
-        foreach ($set as $journal) {
-            $this->repository->destroy($journal);
-            ++$count;
-        }
 
         app('preferences')->mark();
         session()->flash('success', (string)trans('firefly.mass_deleted_transactions_success', ['amount' => $count]));
@@ -127,20 +124,16 @@ class MassController extends Controller
         $user     = auth()->user();
         $subTitle = (string)trans('firefly.mass_edit_journals');
 
-
         /** @var AccountRepositoryInterface $repository */
         $repository = app(AccountRepositoryInterface::class);
         $accounts   = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
 
-        // get budgets
         /** @var BudgetRepositoryInterface $budgetRepository */
         $budgetRepository = app(BudgetRepositoryInterface::class);
         $budgets          = $budgetRepository->getBudgets();
 
-        // put previous url in session
         $this->rememberPreviousUri('transactions.mass-edit.uri');
 
-        // use the collector to get them.
         $transformer = new TransactionTransformer(new ParameterBag);
         /** @var JournalCollectorInterface $collector */
         $collector = app(JournalCollectorInterface::class);
@@ -148,12 +141,7 @@ class MassController extends Controller
         $collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
         $collector->setJournals($journals);
         $collector->addFilter(TransactionViewFilter::class);
-        $collection = $collector->getJournals();
-
-        // add some filters:
-
-
-        // transform to array
+        $collection   = $collector->getJournals();
         $transactions = $collection->map(
             function (Transaction $transaction) use ($transformer) {
                 $transformed = $transformer->transform($transaction);
@@ -173,6 +161,8 @@ class MassController extends Controller
      * @param JournalRepositoryInterface $repository
      *
      * @return mixed
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function update(MassEditJournalRequest $request, JournalRepositoryInterface $repository)
     {
diff --git a/app/Http/Controllers/Transaction/SingleController.php b/app/Http/Controllers/Transaction/SingleController.php
index 1b7547ba20..c3ed9429d0 100644
--- a/app/Http/Controllers/Transaction/SingleController.php
+++ b/app/Http/Controllers/Transaction/SingleController.php
@@ -41,6 +41,8 @@ use View;
 
 /**
  * Class SingleController.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class SingleController extends Controller
 {
@@ -82,6 +84,8 @@ class SingleController extends Controller
      * @param TransactionJournal $journal
      *
      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function cloneTransaction(TransactionJournal $journal)
     {
@@ -137,6 +141,8 @@ class SingleController extends Controller
      * @param string|null $what
      *
      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function create(Request $request, string $what = null)
     {
@@ -203,8 +209,6 @@ class SingleController extends Controller
      * @param TransactionJournal $transactionJournal
      *
      * @return \Illuminate\Http\RedirectResponse
-     *
-     * @internal param JournalRepositoryInterface $repository
      */
     public function destroy(TransactionJournal $transactionJournal): RedirectResponse
     {
@@ -229,6 +233,9 @@ class SingleController extends Controller
      * @param JournalRepositoryInterface $repository
      *
      * @return mixed
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function edit(TransactionJournal $journal, JournalRepositoryInterface $repository)
     {
@@ -319,6 +326,10 @@ class SingleController extends Controller
      *
      * @return RedirectResponse
      * @throws \FireflyIII\Exceptions\FireflyException
+     *
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function store(JournalFormRequest $request, JournalRepositoryInterface $repository): RedirectResponse
     {
@@ -377,6 +388,9 @@ class SingleController extends Controller
      * @param TransactionJournal         $journal
      *
      * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, TransactionJournal $journal)
     {
diff --git a/app/Http/Controllers/Transaction/SplitController.php b/app/Http/Controllers/Transaction/SplitController.php
index 5b8c69b9c6..7591fcad70 100644
--- a/app/Http/Controllers/Transaction/SplitController.php
+++ b/app/Http/Controllers/Transaction/SplitController.php
@@ -42,6 +42,7 @@ use View;
 
 /**
  * Class SplitController.
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class SplitController extends Controller
 {
@@ -122,6 +123,9 @@ class SplitController extends Controller
      * @param TransactionJournal      $journal
      *
      * @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function update(SplitJournalFormRequest $request, TransactionJournal $journal)
     {
@@ -216,6 +220,8 @@ class SplitController extends Controller
      *
      * @return array
      * @throws FireflyException
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     private function getTransactionDataFromJournal(TransactionJournal $journal): array
     {
@@ -253,6 +259,9 @@ class SplitController extends Controller
      * @param $old
      *
      * @return array
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     private function updateWithPrevious($array, $old): array
     {
diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php
index df344675b4..7a44a3d271 100644
--- a/app/Http/Controllers/TransactionController.php
+++ b/app/Http/Controllers/TransactionController.php
@@ -45,6 +45,8 @@ use View;
 
 /**
  * Class TransactionController.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class TransactionController extends Controller
 {
@@ -174,6 +176,7 @@ class TransactionController extends Controller
      * @param Request $request
      *
      * @return \Illuminate\Http\JsonResponse
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function reorder(Request $request): JsonResponse
     {
@@ -241,6 +244,9 @@ class TransactionController extends Controller
      * @param Carbon $date
      *
      * @return Collection
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     private function getPeriodOverview(string $what, Carbon $date): Collection
     {
@@ -277,7 +283,6 @@ class TransactionController extends Controller
                         'name' => $dateName,
                         'sums' => $sums,
                         'sum'  => $sum,
-
                         'start' => $currentDate['start']->format('Y-m-d'),
                         'end'   => $currentDate['end']->format('Y-m-d'),
                     ]
diff --git a/app/Http/Middleware/StartFireflySession.php b/app/Http/Middleware/StartFireflySession.php
index 4197d6d285..63fbb74996 100644
--- a/app/Http/Middleware/StartFireflySession.php
+++ b/app/Http/Middleware/StartFireflySession.php
@@ -41,7 +41,7 @@ class StartFireflySession extends StartSession
     {
         $uri    = $request->fullUrl();
         $strpos = strpos($uri, 'jscript');
-        if (false === $strpos && 'GET' === $request->method() && $request->route() && !$request->ajax()) {
+        if (false === $strpos && 'GET' === $request->method() && !$request->ajax()) {
             $session->setPreviousUrl($uri);
         }
     }
diff --git a/app/Http/Middleware/TrustProxies.php b/app/Http/Middleware/TrustProxies.php
index f14b84141d..ed9131fb59 100644
--- a/app/Http/Middleware/TrustProxies.php
+++ b/app/Http/Middleware/TrustProxies.php
@@ -40,7 +40,7 @@ class TrustProxies extends Middleware
      *
      * @var array|string
      */
-    protected $proxies;
+    protected $proxies = [];
 
     /**
      * TrustProxies constructor.
@@ -49,17 +49,8 @@ class TrustProxies extends Middleware
      */
     public function __construct(Repository $config)
     {
-        $trustedProxies = env('TRUSTED_PROXIES', null);
-        if (false !== $trustedProxies && null !== $trustedProxies && \strlen($trustedProxies) > 0) {
-            if ('*' === $trustedProxies || '**' === $trustedProxies) {
-                $this->proxies = $trustedProxies;
-
-            }
-            if ('*' !== $trustedProxies && '**' !== $trustedProxies) {
-                $this->proxies = explode(',', $trustedProxies);
-            }
-        }
-
+        $trustedProxies = (string)env('TRUSTED_PROXIES', null);
+        $this->proxies  = explode(',', $trustedProxies);
         parent::__construct($config);
     }
 }
diff --git a/app/Http/Requests/JournalFormRequest.php b/app/Http/Requests/JournalFormRequest.php
index 7c14013d74..ec526a21d4 100644
--- a/app/Http/Requests/JournalFormRequest.php
+++ b/app/Http/Requests/JournalFormRequest.php
@@ -45,6 +45,8 @@ class JournalFormRequest extends Request
      * Returns and validates the data required to store a new journal. Can handle both single transaction journals and split journals.
      *
      * @return array
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function getJournalData(): array
     {
@@ -240,61 +242,79 @@ class JournalFormRequest extends Request
         $type = $data['what'] ?? 'invalid';
         Log::debug(sprintf('Type is %s', $type));
         if ('withdrawal' === $type) {
-
-            $selectedCurrency = (int)($data['amount_currency_id_amount'] ?? 0);
-            $accountCurrency  = (int)($data['source_account_currency'] ?? 0);
-            Log::debug(sprintf('Selected currency is %d, account currency is %d', $selectedCurrency, $accountCurrency));
-            $nativeAmount = (string)($data['native_amount'] ?? '');
-            if ($selectedCurrency !== $accountCurrency && '' === $nativeAmount
-                && 0 !== $selectedCurrency
-                && 0 !== $accountCurrency
-            ) {
-                Log::debug('ADD validation error on native_amount');
-                $validator->errors()->add('native_amount', (string)trans('validation.numeric_native'));
-
-                return;
-            }
+            $this->validateWithdrawal($validator);
         }
 
         // same thing for deposits:
         if ('deposit' === $type) {
-            $selectedCurrency = (int)($data['amount_currency_id_amount'] ?? 0);
-            $accountCurrency  = (int)($data['destination_account_currency'] ?? 0);
-            $nativeAmount     = (string)($data['native_amount'] ?? '');
-            if ($selectedCurrency !== $accountCurrency && '' === $nativeAmount
-                && 0 !== $selectedCurrency
-                && 0 !== $accountCurrency
-            ) {
-                $validator->errors()->add('native_amount', (string)trans('validation.numeric_native'));
-
-                return;
-            }
+            $this->validateDeposit($validator);
         }
 
         // and for transfers
         if ('transfer' === $type) {
+            $this->validateTransfer($validator);
+        }
+    }
 
-            $sourceCurrency      = (int)($data['source_account_currency'] ?? 0);
-            $destinationCurrency = (int)($data['destination_account_currency'] ?? 0);
-            $sourceAmount        = (string)($data['source_amount'] ?? '');
-            $destinationAmount   = (string)($data['destination_amount'] ?? '');
+    /**
+     * @param Validator $validator
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    private function validateDeposit(Validator $validator): void
+    {
+        $selectedCurrency = (int)($data['amount_currency_id_amount'] ?? 0);
+        $accountCurrency  = (int)($data['destination_account_currency'] ?? 0);
+        $nativeAmount     = (string)($data['native_amount'] ?? '');
+        if ($selectedCurrency !== $accountCurrency && '' === $nativeAmount && 0 !== $selectedCurrency && 0 !== $accountCurrency) {
+            $validator->errors()->add('native_amount', (string)trans('validation.numeric_native'));
 
-            Log::debug(sprintf('Source currency is %d, destination currency is %d', $sourceCurrency, $destinationCurrency));
+            return;
+        }
+    }
 
-            if ($sourceCurrency !== $destinationCurrency && '' === $sourceAmount
-                && 0 !== $sourceCurrency
-                && 0 !== $destinationCurrency
-            ) {
-                $validator->errors()->add('source_amount', (string)trans('validation.numeric_source'));
-            }
+    /**
+     * @param Validator $validator
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    private function validateTransfer(Validator $validator): void
+    {
+        $sourceCurrency      = (int)($data['source_account_currency'] ?? 0);
+        $destinationCurrency = (int)($data['destination_account_currency'] ?? 0);
+        $sourceAmount        = (string)($data['source_amount'] ?? '');
+        $destinationAmount   = (string)($data['destination_amount'] ?? '');
 
-            if ($sourceCurrency !== $destinationCurrency && '' === $destinationAmount
-                && 0 !== $sourceCurrency
-                && 0 !== $destinationCurrency
-            ) {
-                $validator->errors()->add('destination_amount', (string)trans('validation.numeric_destination'));
-                $validator->errors()->add('destination_amount', (string)trans('validation.numeric', ['attribute' => 'destination_amount']));
-            }
+        Log::debug(sprintf('Source currency is %d, destination currency is %d', $sourceCurrency, $destinationCurrency));
+
+        if ($sourceCurrency !== $destinationCurrency && '' === $sourceAmount && 0 !== $sourceCurrency && 0 !== $destinationCurrency) {
+            $validator->errors()->add('source_amount', (string)trans('validation.numeric_source'));
+        }
+
+        if ($sourceCurrency !== $destinationCurrency && '' === $destinationAmount && 0 !== $sourceCurrency && 0 !== $destinationCurrency) {
+            $validator->errors()->add('destination_amount', (string)trans('validation.numeric_destination'));
+            $validator->errors()->add('destination_amount', (string)trans('validation.numeric', ['attribute' => 'destination_amount']));
+        }
+
+    }
+
+    /**
+     * @param Validator $validator
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    private function validateWithdrawal(Validator $validator): void
+    {
+        $data             = $validator->getData();
+        $selectedCurrency = (int)($data['amount_currency_id_amount'] ?? 0);
+        $accountCurrency  = (int)($data['source_account_currency'] ?? 0);
+        Log::debug(sprintf('Selected currency is %d, account currency is %d', $selectedCurrency, $accountCurrency));
+        $nativeAmount = (string)($data['native_amount'] ?? '');
+        if ($selectedCurrency !== $accountCurrency && '' === $nativeAmount
+            && 0 !== $selectedCurrency
+            && 0 !== $accountCurrency
+        ) {
+            Log::debug('ADD validation error on native_amount');
+            $validator->errors()->add('native_amount', (string)trans('validation.numeric_native'));
 
             return;
         }
diff --git a/app/Http/Requests/RecurrenceFormRequest.php b/app/Http/Requests/RecurrenceFormRequest.php
index d1ba493c5b..871c96bc8c 100644
--- a/app/Http/Requests/RecurrenceFormRequest.php
+++ b/app/Http/Requests/RecurrenceFormRequest.php
@@ -48,6 +48,9 @@ class RecurrenceFormRequest extends Request
     /**
      * @return array
      * @throws FireflyException
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function getAll(): array
     {
@@ -132,6 +135,10 @@ class RecurrenceFormRequest extends Request
     /**
      * @return array
      * @throws FireflyException
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
      */
     public function rules(): array
     {
@@ -222,6 +229,8 @@ class RecurrenceFormRequest extends Request
 
     /**
      * @return array
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     private function parseRepetitionData(): array
     {
diff --git a/app/Http/Requests/Request.php b/app/Http/Requests/Request.php
index 50a8b5f8fe..e470d7d4a4 100644
--- a/app/Http/Requests/Request.php
+++ b/app/Http/Requests/Request.php
@@ -27,6 +27,8 @@ use Illuminate\Foundation\Http\FormRequest;
 
 /**
  * Class Request.
+ *
+ * @SuppressWarnings(PHPMD.NumberOfChildren)
  */
 class Request extends FormRequest
 {
@@ -71,6 +73,8 @@ class Request extends FormRequest
      * @param string $field
      *
      * @return string
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function string(string $field): string
     {
diff --git a/app/Http/Requests/RuleFormRequest.php b/app/Http/Requests/RuleFormRequest.php
index 7e35f4016a..9248d3c3ce 100644
--- a/app/Http/Requests/RuleFormRequest.php
+++ b/app/Http/Requests/RuleFormRequest.php
@@ -40,6 +40,9 @@ class RuleFormRequest extends Request
 
     /**
      * @return array
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function getRuleData(): array
     {
diff --git a/app/Http/Requests/SplitJournalFormRequest.php b/app/Http/Requests/SplitJournalFormRequest.php
index fec9c93519..588625e1a4 100644
--- a/app/Http/Requests/SplitJournalFormRequest.php
+++ b/app/Http/Requests/SplitJournalFormRequest.php
@@ -40,6 +40,9 @@ class SplitJournalFormRequest extends Request
 
     /**
      * @return array
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function getAll(): array
     {
@@ -147,6 +150,8 @@ class SplitJournalFormRequest extends Request
 
     /**
      * @param Validator $validator
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     protected function sameAccounts(Validator $validator): void
     {
diff --git a/app/Repositories/Recurring/RecurringRepositoryInterface.php b/app/Repositories/Recurring/RecurringRepositoryInterface.php
index d738d768d6..99bbd834a8 100644
--- a/app/Repositories/Recurring/RecurringRepositoryInterface.php
+++ b/app/Repositories/Recurring/RecurringRepositoryInterface.php
@@ -36,7 +36,6 @@ use Illuminate\Support\Collection;
 /**
  * Interface RecurringRepositoryInterface
  *
- * @package FireflyIII\Repositories\Recurring
  */
 interface RecurringRepositoryInterface
 {
diff --git a/app/Services/Internal/Support/RecurringTransactionTrait.php b/app/Services/Internal/Support/RecurringTransactionTrait.php
index b36d7d4c0d..97b4404b3f 100644
--- a/app/Services/Internal/Support/RecurringTransactionTrait.php
+++ b/app/Services/Internal/Support/RecurringTransactionTrait.php
@@ -41,7 +41,6 @@ use Log;
 /**
  * Trait RecurringTransactionTrait
  *
- * @package FireflyIII\Services\Internal\Support
  */
 trait RecurringTransactionTrait
 {
diff --git a/app/Services/Internal/Support/TransactionTypeTrait.php b/app/Services/Internal/Support/TransactionTypeTrait.php
index 204110c66b..b209e7cc61 100644
--- a/app/Services/Internal/Support/TransactionTypeTrait.php
+++ b/app/Services/Internal/Support/TransactionTypeTrait.php
@@ -30,7 +30,6 @@ use Log;
 /**
  * Trait TransactionTypeTrait
  *
- * @package FireflyIII\Services\Internal\Support
  */
 trait TransactionTypeTrait
 {
diff --git a/app/Support/Binder/ImportProvider.php b/app/Support/Binder/ImportProvider.php
index b06cff4dc1..1d3df1bf8e 100644
--- a/app/Support/Binder/ImportProvider.php
+++ b/app/Support/Binder/ImportProvider.php
@@ -23,8 +23,12 @@ declare(strict_types=1);
 namespace FireflyIII\Support\Binder;
 
 use Carbon\Carbon;
+use FireflyIII\Import\Prerequisites\PrerequisitesInterface;
+use FireflyIII\Repositories\User\UserRepositoryInterface;
+use FireflyIII\User;
 use Illuminate\Routing\Route;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Log;
 
 /**
  * Class ImportProvider.
@@ -40,10 +44,63 @@ class ImportProvider implements BinderInterface
      */
     public static function routeBinder(string $value, Route $route): string
     {
-        $providers = array_keys((array)config('import.enabled'));
+        $providers = array_keys(self::getProviders());
         if (\in_array($value, $providers, true)) {
             return $value;
         }
         throw new NotFoundHttpException;
     }
+
+    /**
+     * @return array
+     */
+    public static function getProviders(): array
+    {
+        $repository = app(UserRepositoryInterface::class);
+        // get and filter all import routines:
+        /** @var User $user */
+        $user = auth()->user();
+        /** @var array $config */
+        $providerNames = array_keys(config('import.enabled'));
+        $providers     = [];
+        $isDemoUser    = $repository->hasRole($user, 'demo');
+        $isDebug       = (bool)config('app.debug');
+        foreach ($providerNames as $providerName) {
+            //Log::debug(sprintf('Now with provider %s', $providerName));
+            // only consider enabled providers
+            $enabled        = (bool)config(sprintf('import.enabled.%s', $providerName));
+            $allowedForDemo = (bool)config(sprintf('import.allowed_for_demo.%s', $providerName));
+            $allowedForUser = (bool)config(sprintf('import.allowed_for_user.%s', $providerName));
+            if (false === $enabled) {
+                //Log::debug('Provider is not enabled. NEXT!');
+                continue;
+            }
+
+            if (true === $isDemoUser && false === $allowedForDemo) {
+                //Log::debug('User is demo and this provider is not allowed for demo user. NEXT!');
+                continue;
+            }
+            if (false === $isDemoUser && false === $allowedForUser && false === $isDebug) {
+                //Log::debug('User is not demo and this provider is not allowed for such users. NEXT!');
+                continue; // @codeCoverageIgnore
+            }
+
+            $providers[$providerName] = [
+                'has_prereq' => (bool)config('import.has_prereq.' . $providerName),
+            ];
+            $class                    = (string)config(sprintf('import.prerequisites.%s', $providerName));
+            $result                   = false;
+            if ('' !== $class && class_exists($class)) {
+                //Log::debug('Will not check prerequisites.');
+                /** @var PrerequisitesInterface $object */
+                $object = app($class);
+                $object->setUser($user);
+                $result = $object->isComplete();
+            }
+            $providers[$providerName]['prereq_complete'] = $result;
+        }
+        Log::debug(sprintf('Enabled providers: %s', json_encode(array_keys($providers))));
+
+        return $providers;
+    }
 }
diff --git a/app/Support/ExpandedForm.php b/app/Support/ExpandedForm.php
index bb2bc9c25c..1e1c44cddc 100644
--- a/app/Support/ExpandedForm.php
+++ b/app/Support/ExpandedForm.php
@@ -52,7 +52,7 @@ class ExpandedForm
      * @param null   $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function activeAssetAccountList(string $name, $value = null, array $options = []): string
     {
@@ -93,7 +93,7 @@ class ExpandedForm
      *
      * @return string
      * @throws \FireflyIII\Exceptions\FireflyException
-     * @throws \Throwable
+
      */
     public function amount(string $name, $value = null, array $options = []): string
     {
@@ -106,7 +106,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function amountNoCurrency(string $name, $value = null, array $options = []): string
     {
@@ -145,7 +145,7 @@ class ExpandedForm
      * @param null   $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function assetAccountCheckList(string $name, $options = null): string
     {
@@ -183,7 +183,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function assetAccountList(string $name, $value = null, array $options = []): string
     {
@@ -225,7 +225,7 @@ class ExpandedForm
      *
      * @return string
      * @throws \FireflyIII\Exceptions\FireflyException
-     * @throws \Throwable
+
      */
     public function balance(string $name, $value = null, array $options = []): string
     {
@@ -239,7 +239,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function checkbox(string $name, $value = 1, $checked = null, $options = []): string
     {
@@ -268,7 +268,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function currencyList(string $name, $value = null, array $options = []): string
     {
@@ -293,7 +293,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function currencyListEmpty(string $name, $value = null, array $options = []): string
     {
@@ -320,7 +320,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function date(string $name, $value = null, array $options = []): string
     {
@@ -339,7 +339,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function file(string $name, array $options = []): string
     {
@@ -357,7 +357,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function integer(string $name, $value = null, array $options = []): string
     {
@@ -377,7 +377,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function location(string $name, $value = null, array $options = []): string
     {
@@ -450,7 +450,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function multiRadio(string $name, array $list = [], $selected = null, array $options = []): string
     {
@@ -472,7 +472,7 @@ class ExpandedForm
      *
      * @return string
      * @throws \FireflyIII\Exceptions\FireflyException
-     * @throws \Throwable
+
      */
     public function nonSelectableAmount(string $name, $value = null, array $options = []): string
     {
@@ -501,7 +501,7 @@ class ExpandedForm
      *
      * @return string
      * @throws \FireflyIII\Exceptions\FireflyException
-     * @throws \Throwable
+
      */
     public function nonSelectableBalance(string $name, $value = null, array $options = []): string
     {
@@ -530,7 +530,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function number(string $name, $value = null, array $options = []): string
     {
@@ -551,7 +551,7 @@ class ExpandedForm
      * @param string $name
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function optionsList(string $type, string $name): string
     {
@@ -565,7 +565,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function password(string $name, array $options = null): string
     {
@@ -584,7 +584,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function piggyBankList(string $name, $value = null, array $options = null): string
     {
@@ -610,7 +610,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function ruleGroupList(string $name, $value = null, array $options = []): string
     {
@@ -664,7 +664,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function select(string $name, array $list = [], $selected = null, array $options = []): string
     {
@@ -684,7 +684,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function staticText(string $name, $value, array $options = []): string
     {
@@ -702,7 +702,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function tags(string $name, $value = null, array $options = []): string
     {
@@ -722,7 +722,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function text(string $name, $value = null, array $options = []): string
     {
@@ -741,7 +741,7 @@ class ExpandedForm
      * @param array  $options
      *
      * @return string
-     * @throws \Throwable
+
      */
     public function textarea(string $name, $value = null, array $options = []): string
     {
@@ -843,7 +843,7 @@ class ExpandedForm
      * @return string
      *
      * @throws \FireflyIII\Exceptions\FireflyException
-     * @throws \Throwable
+
      */
     private function currencyField(string $name, string $view, $value = null, array $options = []): string
     {
diff --git a/app/Support/Http/Controllers/DateCalculation.php b/app/Support/Http/Controllers/DateCalculation.php
index 13cb1e221a..80e1ebb1e1 100644
--- a/app/Support/Http/Controllers/DateCalculation.php
+++ b/app/Support/Http/Controllers/DateCalculation.php
@@ -29,7 +29,6 @@ use Log;
 /**
  * Trait DateCalculation
  *
- * @package FireflyIII\Support\Http\Controllers
  */
 trait DateCalculation
 {
diff --git a/app/Support/Http/Controllers/RuleManagement.php b/app/Support/Http/Controllers/RuleManagement.php
new file mode 100644
index 0000000000..6fdfbb3ac9
--- /dev/null
+++ b/app/Support/Http/Controllers/RuleManagement.php
@@ -0,0 +1,177 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Support\Http\Controllers;
+
+use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
+use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
+use Illuminate\Http\Request;
+use Log;
+use Throwable;
+
+/**
+ * Trait RuleManagement
+ *
+ * @package FireflyIII\Support\Http\Controllers
+ */
+trait RuleManagement
+{
+
+    /**
+     *
+     */
+    protected function createDefaultRule(): void
+    {
+        /** @var RuleRepositoryInterface $ruleRepository */
+        $ruleRepository = app(RuleRepositoryInterface::class);
+        if (0 === $ruleRepository->count()) {
+            $data = [
+                'rule_group_id'   => $ruleRepository->getFirstRuleGroup()->id,
+                'stop-processing' => 0,
+                'title'           => (string)trans('firefly.default_rule_name'),
+                'description'     => (string)trans('firefly.default_rule_description'),
+                'trigger'         => 'store-journal',
+                'strict'          => true,
+                'rule-triggers'   => [
+                    [
+                        'name'            => 'description_is',
+                        'value'           => (string)trans('firefly.default_rule_trigger_description'),
+                        'stop-processing' => false,
+
+                    ],
+                    [
+                        'name'            => 'from_account_is',
+                        'value'           => (string)trans('firefly.default_rule_trigger_from_account'),
+                        'stop-processing' => false,
+
+                    ],
+
+                ],
+                'rule-actions'    => [
+                    [
+                        'name'            => 'prepend_description',
+                        'value'           => (string)trans('firefly.default_rule_action_prepend'),
+                        'stop-processing' => false,
+                    ],
+                    [
+                        'name'            => 'set_category',
+                        'value'           => (string)trans('firefly.default_rule_action_set_category'),
+                        'stop-processing' => false,
+                    ],
+                ],
+            ];
+
+            $ruleRepository->store($data);
+        }
+    }
+
+    /**
+     * @param Request $request
+     *
+     * @return array
+     *
+     */
+    protected function getPreviousActions(Request $request): array
+    {
+        $newIndex = 0;
+        $actions  = [];
+        /** @var array $oldActions */
+        $oldActions = \is_array($request->old('rule-action')) ? $request->old('rule-action') : [];
+        foreach ($oldActions as $index => $entry) {
+            $count   = ($newIndex + 1);
+            $checked = isset($request->old('rule-action-stop')[$index]) ? true : false;
+            try {
+                $actions[] = view(
+                    'rules.partials.action',
+                    [
+                        'oldAction'  => $entry,
+                        'oldValue'   => $request->old('rule-action-value')[$index],
+                        'oldChecked' => $checked,
+                        'count'      => $count,
+                    ]
+                )->render();
+                // @codeCoverageIgnoreStart
+            } catch (Throwable $e) {
+                Log::debug(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage()));
+                Log::error($e->getTraceAsString());
+            }
+            // @codeCoverageIgnoreEnd
+            ++$newIndex;
+        }
+
+        return $actions;
+    }
+
+    /**
+     * @param Request $request
+     *
+     * @return array
+     */
+    protected function getPreviousTriggers(Request $request): array
+    {
+        $newIndex = 0;
+        $triggers = [];
+        /** @var array $oldTriggers */
+        $oldTriggers = \is_array($request->old('rule-trigger')) ? $request->old('rule-trigger') : [];
+        foreach ($oldTriggers as $index => $entry) {
+            $count      = ($newIndex + 1);
+            $oldChecked = isset($request->old('rule-trigger-stop')[$index]) ? true : false;
+            try {
+                $triggers[] = view(
+                    'rules.partials.trigger',
+                    [
+                        'oldTrigger' => $entry,
+                        'oldValue'   => $request->old('rule-trigger-value')[$index],
+                        'oldChecked' => $oldChecked,
+                        'count'      => $count,
+                    ]
+                )->render();
+                // @codeCoverageIgnoreStart
+            } catch (Throwable $e) {
+                Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
+                Log::error($e->getTraceAsString());
+            }
+            // @codeCoverageIgnoreEnd
+            ++$newIndex;
+        }
+
+        return $triggers;
+    }
+
+    /**
+     *
+     */
+    private function createDefaultRuleGroup(): void
+    {
+        /** @var RuleGroupRepositoryInterface $repository */
+        $repository = app(RuleGroupRepositoryInterface::class);
+        if (0 === $repository->count()) {
+            $data = [
+                'title'       => (string)trans('firefly.default_rule_group_name'),
+                'description' => (string)trans('firefly.default_rule_group_description'),
+            ];
+
+            $repository->store($data);
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/Support/Import/Information/GetSpectreTokenTrait.php b/app/Support/Import/Information/GetSpectreTokenTrait.php
index 15c10202e4..02ed4c0bf8 100644
--- a/app/Support/Import/Information/GetSpectreTokenTrait.php
+++ b/app/Support/Import/Information/GetSpectreTokenTrait.php
@@ -32,7 +32,6 @@ use Log;
 /**
  * Trait GetSpectreTokenTrait
  *
- * @package FireflyIII\Support\Import\Information
  */
 trait GetSpectreTokenTrait
 {
diff --git a/app/Validation/RecurrenceValidation.php b/app/Validation/RecurrenceValidation.php
index 71ee97daec..6a1fe9c587 100644
--- a/app/Validation/RecurrenceValidation.php
+++ b/app/Validation/RecurrenceValidation.php
@@ -33,7 +33,6 @@ use InvalidArgumentException;
  *
  * Contains advanced validation rules used in validation of new and existing recurrences.
  *
- * @package FireflyIII\Validation
  */
 trait RecurrenceValidation
 {
diff --git a/app/Validation/TransactionValidation.php b/app/Validation/TransactionValidation.php
index 128c740131..ee08ef9ada 100644
--- a/app/Validation/TransactionValidation.php
+++ b/app/Validation/TransactionValidation.php
@@ -33,8 +33,6 @@ use Log;
 
 /**
  * Trait TransactionValidation
- *
- * @package FireflyIII\Validation
  */
 trait TransactionValidation
 {
diff --git a/composer.lock b/composer.lock
index e30d20069c..2a96a6e3a3 100644
--- a/composer.lock
+++ b/composer.lock
@@ -5126,12 +5126,12 @@
             "source": {
                 "type": "git",
                 "url": "https://github.com/Roave/SecurityAdvisories.git",
-                "reference": "731d60f7fc78a8816dae7049df255cd55e30c313"
+                "reference": "053766d789f6393e5bc0896635d35abf8d2d362e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/731d60f7fc78a8816dae7049df255cd55e30c313",
-                "reference": "731d60f7fc78a8816dae7049df255cd55e30c313",
+                "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/053766d789f6393e5bc0896635d35abf8d2d362e",
+                "reference": "053766d789f6393e5bc0896635d35abf8d2d362e",
                 "shasum": ""
             },
             "conflict": {
@@ -5180,7 +5180,7 @@
                 "kreait/firebase-php": ">=3.2,<3.8.1",
                 "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15",
                 "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10",
-                "magento/magento1ce": ">=1.5.0.1,<1.9.3.2",
+                "magento/magento1ce": "<1.9.3.9",
                 "magento/magento1ee": ">=1.9,<1.14.3.2",
                 "magento/product-community-edition": ">=2,<2.2.5",
                 "monolog/monolog": ">=1.8,<1.12",
@@ -5238,7 +5238,8 @@
                 "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3",
                 "titon/framework": ">=0,<9.9.99",
                 "twig/twig": "<1.20",
-                "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.22|>=8,<8.7.5",
+                "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.30|>=8,<8.7.17|>=9,<9.3.2",
+                "typo3/cms-core": ">=8,<8.7.17|>=9,<9.3.2",
                 "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5",
                 "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4",
                 "willdurand/js-translation-bundle": "<2.1.1",
@@ -5287,7 +5288,7 @@
                 }
             ],
             "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it",
-            "time": "2018-07-09T14:09:25+00:00"
+            "time": "2018-07-18T13:51:34+00:00"
         },
         {
             "name": "sebastian/code-unit-reverse-lookup",