mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-11-04 05:15:39 +00:00 
			
		
		
		
	Code cleanup.
This commit is contained in:
		@@ -44,7 +44,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
 | 
			
		||||
     * Generate the report.
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    public function generate(): string
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
 | 
			
		||||
     * Generates the report.
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    public function generate(): string
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
 | 
			
		||||
     * Generates the report.
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    public function generate(): string
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
 | 
			
		||||
     * Generates the report.
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    public function generate(): string
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
 | 
			
		||||
     * Generates the report.
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    public function generate(): string
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ class MultiYearReportGenerator implements ReportGeneratorInterface
 | 
			
		||||
     * Generates the report.
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    public function generate(): string
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ class YearReportGenerator implements ReportGeneratorInterface
 | 
			
		||||
     * Generates the report.
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    public function generate(): string
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -70,8 +70,8 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
 | 
			
		||||
     * Generate the report.
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    public function generate(): string
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,6 @@ use Log;
 | 
			
		||||
/**
 | 
			
		||||
 * Trait UpdateTrait
 | 
			
		||||
 *
 | 
			
		||||
 * @package FireflyIII\Helpers\Update
 | 
			
		||||
 */
 | 
			
		||||
trait UpdateTrait
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -177,6 +177,8 @@ class DebugController extends Controller
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return string
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
 | 
			
		||||
     */
 | 
			
		||||
    public function routes(): string
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -136,6 +136,7 @@ class JavascriptController extends Controller
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return array
 | 
			
		||||
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
 | 
			
		||||
     */
 | 
			
		||||
    private function getDateRangeConfig(): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,9 @@ use Illuminate\Http\JsonResponse;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class AutoCompleteController.
 | 
			
		||||
 *
 | 
			
		||||
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
 | 
			
		||||
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 | 
			
		||||
 */
 | 
			
		||||
class AutoCompleteController extends Controller
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ class FrontpageController extends Controller
 | 
			
		||||
     * @param PiggyBankRepositoryInterface $repository
 | 
			
		||||
     *
 | 
			
		||||
     * @return JsonResponse
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    public function piggyBanks(PiggyBankRepositoryInterface $repository): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -158,6 +158,7 @@ class IntroController
 | 
			
		||||
     * @param string $specificPage
 | 
			
		||||
     *
 | 
			
		||||
     * @return array
 | 
			
		||||
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
 | 
			
		||||
     */
 | 
			
		||||
    private function getSpecificSteps(string $route, string $specificPage): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										175
									
								
								app/Http/Controllers/Json/RecurrenceController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								app/Http/Controllers/Json/RecurrenceController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * RecurrenceController.php
 | 
			
		||||
 * Copyright (c) 2018 thegrumpydictator@gmail.com
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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'));
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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',
 | 
			
		||||
 
 | 
			
		||||
@@ -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')
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -41,7 +41,7 @@ class AccountController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @return mixed|string
 | 
			
		||||
     *
 | 
			
		||||
     * @throws \Throwable
 | 
			
		||||
 | 
			
		||||
     */
 | 
			
		||||
    public function general(Collection $accounts, Carbon $start, Carbon $end)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,6 @@
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
/** @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
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,6 @@
 | 
			
		||||
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
/** @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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										250
									
								
								app/Http/Controllers/Rule/CreateController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								app/Http/Controllers/Rule/CreateController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,250 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * CreateController.php
 | 
			
		||||
 * Copyright (c) 2018 thegrumpydictator@gmail.com
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										94
									
								
								app/Http/Controllers/Rule/DeleteController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								app/Http/Controllers/Rule/DeleteController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * DeleteController.php
 | 
			
		||||
 * Copyright (c) 2018 thegrumpydictator@gmail.com
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
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'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										219
									
								
								app/Http/Controllers/Rule/EditController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								app/Http/Controllers/Rule/EditController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,219 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * EditController.php
 | 
			
		||||
 * Copyright (c) 2018 thegrumpydictator@gmail.com
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										136
									
								
								app/Http/Controllers/Rule/IndexController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								app/Http/Controllers/Rule/IndexController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * RuleController.php
 | 
			
		||||
 * Copyright (c) 2018 thegrumpydictator@gmail.com
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
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'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										283
									
								
								app/Http/Controllers/Rule/SelectController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								app/Http/Controllers/Rule/SelectController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,283 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * SelectController.php
 | 
			
		||||
 * Copyright (c) 2018 thegrumpydictator@gmail.com
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,875 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * RuleController.php
 | 
			
		||||
 * Copyright (c) 2017 thegrumpydictator@gmail.com
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -87,6 +87,8 @@ class BulkController extends Controller
 | 
			
		||||
     * @param BulkEditJournalRequest $request
 | 
			
		||||
     *
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
 | 
			
		||||
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
 | 
			
		||||
     */
 | 
			
		||||
    public function update(BulkEditJournalRequest $request)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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'));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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'),
 | 
			
		||||
                    ]
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,9 @@ class RuleFormRequest extends Request
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return array
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
 | 
			
		||||
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
 | 
			
		||||
     */
 | 
			
		||||
    public function getRuleData(): array
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,6 @@ use Illuminate\Support\Collection;
 | 
			
		||||
/**
 | 
			
		||||
 * Interface RecurringRepositoryInterface
 | 
			
		||||
 *
 | 
			
		||||
 * @package FireflyIII\Repositories\Recurring
 | 
			
		||||
 */
 | 
			
		||||
interface RecurringRepositoryInterface
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,6 @@ use Log;
 | 
			
		||||
/**
 | 
			
		||||
 * Trait RecurringTransactionTrait
 | 
			
		||||
 *
 | 
			
		||||
 * @package FireflyIII\Services\Internal\Support
 | 
			
		||||
 */
 | 
			
		||||
trait RecurringTransactionTrait
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,6 @@ use Log;
 | 
			
		||||
/**
 | 
			
		||||
 * Trait TransactionTypeTrait
 | 
			
		||||
 *
 | 
			
		||||
 * @package FireflyIII\Services\Internal\Support
 | 
			
		||||
 */
 | 
			
		||||
trait TransactionTypeTrait
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,6 @@ use Log;
 | 
			
		||||
/**
 | 
			
		||||
 * Trait DateCalculation
 | 
			
		||||
 *
 | 
			
		||||
 * @package FireflyIII\Support\Http\Controllers
 | 
			
		||||
 */
 | 
			
		||||
trait DateCalculation
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										177
									
								
								app/Support/Http/Controllers/RuleManagement.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								app/Support/Http/Controllers/RuleManagement.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,177 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * RuleManagement.php
 | 
			
		||||
 * Copyright (c) 2018 thegrumpydictator@gmail.com
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Firefly III is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -32,7 +32,6 @@ use Log;
 | 
			
		||||
/**
 | 
			
		||||
 * Trait GetSpectreTokenTrait
 | 
			
		||||
 *
 | 
			
		||||
 * @package FireflyIII\Support\Import\Information
 | 
			
		||||
 */
 | 
			
		||||
trait GetSpectreTokenTrait
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,6 @@ use InvalidArgumentException;
 | 
			
		||||
 *
 | 
			
		||||
 * Contains advanced validation rules used in validation of new and existing recurrences.
 | 
			
		||||
 *
 | 
			
		||||
 * @package FireflyIII\Validation
 | 
			
		||||
 */
 | 
			
		||||
trait RecurrenceValidation
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -33,8 +33,6 @@ use Log;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Trait TransactionValidation
 | 
			
		||||
 *
 | 
			
		||||
 * @package FireflyIII\Validation
 | 
			
		||||
 */
 | 
			
		||||
trait TransactionValidation
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										13
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							@@ -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",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user