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