accounts = new Collection; $this->rules = new Collection; } /** * Execute the console command. * * @return int * @throws \FireflyIII\Exceptions\FireflyException */ public function handle(): int { if (!$this->verifyAccessToken()) { $this->error('Invalid access token.'); return 1; } $result = $this->verifyInput(); if (false === $result) { return 1; } // get transactions from asset accounts. /** @var TransactionCollectorInterface $collector */ $collector = app(TransactionCollectorInterface::class); $collector->setUser($this->getUser()); $collector->setAccounts($this->accounts); $collector->setRange($this->startDate, $this->endDate); $transactions = $collector->getTransactions(); $count = $transactions->count(); $bar = $this->output->createProgressBar($count * $this->rules->count()); $results = new Collection; $this->line(sprintf('Will apply %d rules to %d transactions', $this->rules->count(), $transactions->count())); foreach ($this->rules as $rule) { /** @var Processor $processor */ $processor = app(Processor::class); $processor->make($rule, true); /** @var Transaction $transaction */ foreach ($transactions as $transaction) { /** @var Rule $rule */ $bar->advance(); $result = $processor->handleTransaction($transaction); if (true === $result) { $results->push($transaction); } } } $results = $results->unique( function (Transaction $transaction) { return (int)$transaction->journal_id; } ); $bar->finish(); $this->line(''); if (0 === \count($results)) { $this->line('The rules were fired but did not influence any transactions.'); } if (\count($results) > 0) { $this->line(sprintf('The rules were fired, and influences %d transaction(s).', \count($results))); foreach ($results as $result) { $this->line( vsprintf( 'Transaction #%d: "%s" (%s %s)', [ $result->journal_id, $result->description, $result->transaction_currency_code, round($result->transaction_amount, $result->transaction_currency_dp), ] ) ); } } return 0; } /** * */ private function grabAllRules(): void { if (true === $this->option('all_rules')) { /** @var RuleRepositoryInterface $ruleRepos */ $ruleRepos = app(RuleRepositoryInterface::class); $ruleRepos->setUser($this->getUser()); $this->rules = $ruleRepos->getAll(); } } /** * */ private function parseDates(): void { // parse start date. $startDate = Carbon::create()->startOfMonth(); $startString = $this->option('start_date'); if (null === $startString) { /** @var JournalRepositoryInterface $repository */ $repository = app(JournalRepositoryInterface::class); $repository->setUser($this->getUser()); $first = $repository->firstNull(); if (null !== $first) { $startDate = $first->date; } } if (null !== $startString && '' !== $startString) { $startDate = Carbon::createFromFormat('Y-m-d', $startString); } // parse end date $endDate = Carbon::now(); $endString = $this->option('end_date'); if (null !== $endString && '' !== $endString) { $endDate = Carbon::createFromFormat('Y-m-d', $endString); } if ($startDate > $endDate) { [$endDate, $startDate] = [$startDate, $endDate]; } $this->startDate = $startDate; $this->endDate = $endDate; } /** * @return bool * @throws \FireflyIII\Exceptions\FireflyException */ private function verifyInput(): bool { // verify account. $result = $this->verifyInputAccounts(); if (false === $result) { return $result; } // verify rule groups. $result = $this->verifyRuleGroups(); if (false === $result) { return $result; } // verify rules. $result = $this->verifyRules(); if (false === $result) { return $result; } $this->grabAllRules(); $this->parseDates(); //$this->line('Number of rules found: ' . $this->rules->count()); $this->line('Start date is ' . $this->startDate->format('Y-m-d')); $this->line('End date is ' . $this->endDate->format('Y-m-d')); return true; } /** * @return bool * @throws \FireflyIII\Exceptions\FireflyException */ private function verifyInputAccounts(): bool { $accountString = $this->option('accounts'); if (null === $accountString || '' === $accountString) { $this->error('Please use the --accounts to indicate the accounts to apply rules to.'); return false; } $finalList = new Collection; $accountList = explode(',', $accountString); if (0 === \count($accountList)) { $this->error('Please use the --accounts to indicate the accounts to apply rules to.'); return false; } /** @var AccountRepositoryInterface $accountRepository */ $accountRepository = app(AccountRepositoryInterface::class); $accountRepository->setUser($this->getUser()); foreach ($accountList as $accountId) { $accountId = (int)$accountId; $account = $accountRepository->findNull($accountId); if (null !== $account && \in_array( $account->accountType->type, [AccountType::DEFAULT, AccountType::DEBT, AccountType::ASSET, AccountType::LOAN, AccountType::MORTGAGE], true )) { $finalList->push($account); } } if (0 === $finalList->count()) { $this->error('Please make sure all accounts in --accounts are asset accounts or liabilities.'); return false; } $this->accounts = $finalList; return true; } /** * @return bool * @throws \FireflyIII\Exceptions\FireflyException */ private function verifyRuleGroups(): bool { $ruleGroupString = $this->option('rule_groups'); if (null === $ruleGroupString || '' === $ruleGroupString) { // can be empty. return true; } $finalList = new Collection; $ruleGroupList = explode(',', $ruleGroupString); if (0 === \count($ruleGroupList)) { // can be empty. return true; } /** @var RuleGroupRepositoryInterface $ruleGroupRepos */ $ruleGroupRepos = app(RuleGroupRepositoryInterface::class); $ruleGroupRepos->setUser($this->getUser()); foreach ($ruleGroupList as $ruleGroupId) { $ruleGroupId = (int)$ruleGroupId; $ruleGroup = $ruleGroupRepos->find($ruleGroupId); if (null !== $ruleGroup) { $rules = $ruleGroupRepos->getActiveStoreRules($ruleGroup); $finalList = $finalList->merge($rules); } } $this->rules = $finalList; return true; } /** * @return bool * @throws \FireflyIII\Exceptions\FireflyException */ private function verifyRules(): bool { $ruleString = $this->option('rules'); if (null === $ruleString || '' === $ruleString) { // can be empty. return true; } $finalList = new Collection; $ruleList = explode(',', $ruleString); if (0 === \count($ruleList)) { // can be empty. return true; } /** @var RuleRepositoryInterface $ruleRepos */ $ruleRepos = app(RuleRepositoryInterface::class); $ruleRepos->setUser($this->getUser()); foreach ($ruleList as $ruleId) { $ruleId = (int)$ruleId; $rule = $ruleRepos->find($ruleId); if (null !== $rule) { $finalList->push($rule); } } if ($finalList->count() > 0) { $this->rules = $finalList; } return true; } }