mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-11-01 11:31:06 +00:00
Add new rule engine to API commands.
This commit is contained in:
@@ -34,6 +34,7 @@ use FireflyIII\Models\RuleGroup;
|
|||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||||
use FireflyIII\TransactionRules\Engine\RuleEngine;
|
use FireflyIII\TransactionRules\Engine\RuleEngine;
|
||||||
|
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
|
||||||
use FireflyIII\TransactionRules\TransactionMatcher;
|
use FireflyIII\TransactionRules\TransactionMatcher;
|
||||||
use FireflyIII\Transformers\RuleGroupTransformer;
|
use FireflyIII\Transformers\RuleGroupTransformer;
|
||||||
use FireflyIII\Transformers\RuleTransformer;
|
use FireflyIII\Transformers\RuleTransformer;
|
||||||
@@ -316,32 +317,28 @@ class RuleGroupController extends Controller
|
|||||||
|
|
||||||
/** @var Collection $collection */
|
/** @var Collection $collection */
|
||||||
$collection = $this->ruleGroupRepository->getActiveRules($group);
|
$collection = $this->ruleGroupRepository->getActiveRules($group);
|
||||||
$rules = [];
|
|
||||||
/** @var Rule $item */
|
|
||||||
foreach ($collection as $item) {
|
|
||||||
$rules[] = $item->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// start looping.
|
// start looping.
|
||||||
/** @var RuleEngine $ruleEngine */
|
$ruleEngine = app(RuleEngineInterface::class);
|
||||||
$ruleEngine = app(RuleEngine::class);
|
$ruleEngine->setRules($collection);
|
||||||
$ruleEngine->setUser(auth()->user());
|
|
||||||
$ruleEngine->setRulesToApply($rules);
|
|
||||||
$ruleEngine->setTriggerMode(RuleEngine::TRIGGER_STORE);
|
|
||||||
|
|
||||||
/** @var GroupCollectorInterface $collector */
|
// overrule the rule(s) if necessary.
|
||||||
$collector = app(GroupCollectorInterface::class);
|
if (array_key_exists('start', $parameters) && null !== $parameters['start'] ) {
|
||||||
$collector->setAccounts($parameters['accounts']);
|
// add a range:
|
||||||
$collector->setRange($parameters['start_date'], $parameters['end_date']);
|
$ruleEngine->addOperator(['type' => 'date_after', 'value' => $parameters['start']->format('Y-m-d')]);
|
||||||
$journals = $collector->getExtractedJournals();
|
|
||||||
|
|
||||||
/** @var array $journal */
|
|
||||||
foreach ($journals as $journal) {
|
|
||||||
Log::debug('Start of new journal.');
|
|
||||||
$ruleEngine->processJournalArray($journal);
|
|
||||||
Log::debug('Done with all rules for this group + done with journal.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('end', $parameters) && null !== $parameters['end']) {
|
||||||
|
// add a range:
|
||||||
|
$ruleEngine->addOperator(['type' => 'date_before', 'value' => $parameters['end']->format('Y-m-d')]);
|
||||||
|
}
|
||||||
|
if (array_key_exists('accounts', $parameters) && '' !== $parameters['accounts']) {
|
||||||
|
$ruleEngine->addOperator(['type' => 'account_id', 'value' => $parameters['accounts']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// file the rule(s)
|
||||||
|
$ruleEngine->fire();
|
||||||
|
|
||||||
return response()->json([], 204);
|
return response()->json([], 204);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ use Log;
|
|||||||
class RuleGroupTriggerRequest extends FormRequest
|
class RuleGroupTriggerRequest extends FormRequest
|
||||||
{
|
{
|
||||||
use ConvertsDataTypes;
|
use ConvertsDataTypes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authorize logged in users.
|
* Authorize logged in users.
|
||||||
*
|
*
|
||||||
@@ -57,8 +58,8 @@ class RuleGroupTriggerRequest extends FormRequest
|
|||||||
public function getTriggerParameters(): array
|
public function getTriggerParameters(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'start_date' => $this->getDate('start_date'),
|
'start' => $this->getDate('start'),
|
||||||
'end_date' => $this->getDate('end_date'),
|
'end' => $this->getDate('end'),
|
||||||
'accounts' => $this->getAccounts(),
|
'accounts' => $this->getAccounts(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -69,33 +70,17 @@ class RuleGroupTriggerRequest extends FormRequest
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'start_date' => 'required|date',
|
'start' => 'date',
|
||||||
'end_date' => 'required|date|after:start_date',
|
'end' => 'date|after:start',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function getAccounts(): Collection
|
private function getAccounts(): string
|
||||||
{
|
{
|
||||||
$accountList = '' === (string) $this->query('accounts') ? [] : explode(',', $this->query('accounts'));
|
return (string) $this->query('accounts');
|
||||||
$accounts = new Collection;
|
|
||||||
|
|
||||||
/** @var AccountRepositoryInterface $accountRepository */
|
|
||||||
$accountRepository = app(AccountRepositoryInterface::class);
|
|
||||||
|
|
||||||
foreach ($accountList as $accountId) {
|
|
||||||
Log::debug(sprintf('Searching for asset account with id "%s"', $accountId));
|
|
||||||
$account = $accountRepository->findNull((int) $accountId);
|
|
||||||
if ($this->validAccount($account)) {
|
|
||||||
/** @noinspection NullPointerExceptionInspection */
|
|
||||||
Log::debug(sprintf('Found account #%d ("%s") and its an asset account', $account->id, $account->name));
|
|
||||||
$accounts->push($account);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $accounts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,19 +91,7 @@ class RuleGroupTriggerRequest extends FormRequest
|
|||||||
private function getDate(string $field): ?Carbon
|
private function getDate(string $field): ?Carbon
|
||||||
{
|
{
|
||||||
/** @var Carbon $result */
|
/** @var Carbon $result */
|
||||||
$result = null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
|
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Account|null $account
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function validAccount(?Account $account): bool
|
|
||||||
{
|
|
||||||
return null !== $account && AccountType::ASSET === $account->accountType->type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,10 +87,7 @@ class RuleTriggerRequest extends FormRequest
|
|||||||
*/
|
*/
|
||||||
private function getDate(string $field): ?Carbon
|
private function getDate(string $field): ?Carbon
|
||||||
{
|
{
|
||||||
/** @var Carbon $result */
|
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
|
||||||
$result = null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class ConvertToDeposit implements ActionInterface
|
|||||||
*
|
*
|
||||||
* @param TransactionJournal $journal
|
* @param TransactionJournal $journal
|
||||||
* @deprecated
|
* @deprecated
|
||||||
|
* @codeCoverageIgnore
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ class SearchRuleEngine implements RuleEngineInterface
|
|||||||
foreach ($this->rules as $rule) {
|
foreach ($this->rules as $rule) {
|
||||||
$this->fireRule($rule);
|
$this->fireRule($rule);
|
||||||
}
|
}
|
||||||
|
Log::debug('SearchRuleEngine:: done processing all rules!');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,14 +103,17 @@ class SearchRuleEngine implements RuleEngineInterface
|
|||||||
*/
|
*/
|
||||||
private function fireRule(Rule $rule): void
|
private function fireRule(Rule $rule): void
|
||||||
{
|
{
|
||||||
|
Log::debug(sprintf('SearchRuleEngine::fireRule(%d)!', $rule->id));
|
||||||
$searchArray = [];
|
$searchArray = [];
|
||||||
/** @var RuleTrigger $ruleTrigger */
|
/** @var RuleTrigger $ruleTrigger */
|
||||||
foreach ($rule->ruleTriggers as $ruleTrigger) {
|
foreach ($rule->ruleTriggers as $ruleTrigger) {
|
||||||
|
Log::debug(sprintf('SearchRuleEngine:: add a rule trigger: %s:"%s"', $ruleTrigger->trigger_type, $ruleTrigger->trigger_value));
|
||||||
$searchArray[$ruleTrigger->trigger_type] = sprintf('"%s"', $ruleTrigger->trigger_value);
|
$searchArray[$ruleTrigger->trigger_type] = sprintf('"%s"', $ruleTrigger->trigger_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add local operators:
|
// add local operators:
|
||||||
foreach ($this->operators as $operator) {
|
foreach ($this->operators as $operator) {
|
||||||
|
Log::debug(sprintf('SearchRuleEngine:: add local added operator: %s:"%s"', $operator['type'], $operator['value']));
|
||||||
$searchArray[$operator['type']] = sprintf('"%s"', $operator['value']);
|
$searchArray[$operator['type']] = sprintf('"%s"', $operator['value']);
|
||||||
}
|
}
|
||||||
$toJoin = [];
|
$toJoin = [];
|
||||||
@@ -118,20 +122,21 @@ class SearchRuleEngine implements RuleEngineInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
$searchQuery = join(' ', $toJoin);
|
$searchQuery = join(' ', $toJoin);
|
||||||
Log::debug(sprintf('Search query for rule #%d ("%s") = %s', $rule->id, $rule->title, $searchQuery));
|
Log::debug(sprintf('SearchRuleEngine:: Search query for rule #%d ("%s") = %s', $rule->id, $rule->title, $searchQuery));
|
||||||
|
|
||||||
// build and run the search engine.
|
// build and run the search engine.
|
||||||
$searchEngine = app(SearchInterface::class);
|
$searchEngine = app(SearchInterface::class);
|
||||||
$searchEngine->setUser($this->user);
|
$searchEngine->setUser($this->user);
|
||||||
$searchEngine->setPage(1);
|
$searchEngine->setPage(1);
|
||||||
$searchEngine->setLimit(1337);
|
$searchEngine->setLimit(31337);
|
||||||
$searchEngine->parseQuery($searchQuery);
|
$searchEngine->parseQuery($searchQuery);
|
||||||
|
|
||||||
$result = $searchEngine->searchTransactions();
|
$result = $searchEngine->searchTransactions();
|
||||||
$collection = $result->getCollection();
|
$collection = $result->getCollection();
|
||||||
Log::debug(sprintf('Found %d transactions using search engine.', $collection->count()));
|
Log::debug(sprintf('SearchRuleEngine:: Found %d transactions using search engine with query "%s".', $collection->count(), $searchQuery));
|
||||||
|
|
||||||
$this->processResults($rule, $collection);
|
$this->processResults($rule, $collection);
|
||||||
|
Log::debug(sprintf('SearchRuleEngine:: done processing rule #%d', $rule->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,7 +146,7 @@ class SearchRuleEngine implements RuleEngineInterface
|
|||||||
*/
|
*/
|
||||||
private function processResults(Rule $rule, Collection $collection): void
|
private function processResults(Rule $rule, Collection $collection): void
|
||||||
{
|
{
|
||||||
Log::debug('Going to process results.');
|
Log::debug(sprintf('SearchRuleEngine:: Going to process %d results.', $collection->count()));
|
||||||
/** @var array $group */
|
/** @var array $group */
|
||||||
foreach ($collection as $group) {
|
foreach ($collection as $group) {
|
||||||
$this->processTransactionGroup($rule, $group);
|
$this->processTransactionGroup($rule, $group);
|
||||||
@@ -155,7 +160,7 @@ class SearchRuleEngine implements RuleEngineInterface
|
|||||||
*/
|
*/
|
||||||
private function processTransactionGroup(Rule $rule, array $group): void
|
private function processTransactionGroup(Rule $rule, array $group): void
|
||||||
{
|
{
|
||||||
Log::debug(sprintf('Will now execute actions on transaction group #%d', $group['id']));
|
Log::debug(sprintf('SearchRuleEngine:: Will now execute actions on transaction group #%d', $group['id']));
|
||||||
/** @var array $transaction */
|
/** @var array $transaction */
|
||||||
foreach ($group['transactions'] as $transaction) {
|
foreach ($group['transactions'] as $transaction) {
|
||||||
$this->processTransactionJournal($rule, $transaction);
|
$this->processTransactionJournal($rule, $transaction);
|
||||||
@@ -169,7 +174,7 @@ class SearchRuleEngine implements RuleEngineInterface
|
|||||||
*/
|
*/
|
||||||
private function processTransactionJournal(Rule $rule, array $transaction): void
|
private function processTransactionJournal(Rule $rule, array $transaction): void
|
||||||
{
|
{
|
||||||
Log::debug(sprintf('Will now execute actions on transaction journal #%d', $transaction['transaction_journal_id']));
|
Log::debug(sprintf('SearchRuleEngine:: Will now execute actions on transaction journal #%d', $transaction['transaction_journal_id']));
|
||||||
/** @var RuleAction $ruleAction */
|
/** @var RuleAction $ruleAction */
|
||||||
foreach ($rule->ruleActions as $ruleAction) {
|
foreach ($rule->ruleActions as $ruleAction) {
|
||||||
$break = $this->processRuleAction($ruleAction, $transaction);
|
$break = $this->processRuleAction($ruleAction, $transaction);
|
||||||
|
|||||||
Reference in New Issue
Block a user