diff --git a/app/Models/Account.php b/app/Models/Account.php index cc52b690db..a9ec862e24 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -155,14 +155,14 @@ class Account extends Model * * @return string */ - public function getAccountNumberAttribute(): ?string + public function getAccountNumberAttribute(): string { /** @var AccountMeta $metaValue */ $metaValue = $this->accountMeta() ->where('name', 'account_number') ->first(); - return $metaValue ? $metaValue->data : null; + return $metaValue ? $metaValue->data : ''; } /** diff --git a/app/TransactionRules/Triggers/FromAccountContains.php b/app/TransactionRules/Triggers/FromAccountContains.php index 3473aeffaa..ec3ed43b2d 100644 --- a/app/TransactionRules/Triggers/FromAccountContains.php +++ b/app/TransactionRules/Triggers/FromAccountContains.php @@ -79,8 +79,8 @@ final class FromAccountContains extends AbstractTrigger implements TriggerInterf if (!(false === $strpos)) { Log::debug( sprintf( - 'RuleTrigger FromAccountContains for journal #%d: "%s" contains "%s", return true.', - $journal->id, $source->name, $this->triggerValue + 'RuleTrigger %s for journal #%d: "%s" contains "%s", return true.', + get_class($this), $journal->id, $source->name, $this->triggerValue ) ); @@ -89,10 +89,8 @@ final class FromAccountContains extends AbstractTrigger implements TriggerInterf Log::debug( sprintf( - 'RuleTrigger FromAccountContains for journal #%d: "%s" does not contain "%s", return false.', - $journal->id, - $source->name, - $this->triggerValue + 'RuleTrigger %s for journal #%d: "%s" does not contain "%s", return false.', + get_class($this), $journal->id, $source->name, $this->triggerValue ) ); diff --git a/app/TransactionRules/Triggers/FromAccountEnds.php b/app/TransactionRules/Triggers/FromAccountEnds.php index e5e70df7ce..86a32ade6e 100644 --- a/app/TransactionRules/Triggers/FromAccountEnds.php +++ b/app/TransactionRules/Triggers/FromAccountEnds.php @@ -82,18 +82,33 @@ final class FromAccountEnds extends AbstractTrigger implements TriggerInterface // if the string to search for is longer than the account name, // it will never be in the account name. if ($searchLength > $nameLength) { - Log::debug(sprintf('RuleTrigger FromAccountEnds for journal #%d: "%s" does not end with "%s", return false.', $journal->id, $name, $search)); + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" does not end with "%s", return false.', + get_class($this), $journal->id, $source->name, $search + ) + ); return false; } if (strtolower($part) === strtolower($search)) { - Log::debug(sprintf('RuleTrigger FromAccountEnds for journal #%d: "%s" ends with "%s", return true.', $journal->id, $name, $search)); + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" ends with "%s", return true.', + get_class($this), $journal->id, $source->name, $search + ) + ); return true; } - Log::debug(sprintf('RuleTrigger FromAccountEnds for journal #%d: "%s" does not end with "%s", return false.', $journal->id, $name, $search)); + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" does not end with "%s", return false.', + get_class($this), $journal->id, $source->name, $search + ) + ); return false; } diff --git a/app/TransactionRules/Triggers/FromAccountIs.php b/app/TransactionRules/Triggers/FromAccountIs.php index baffc421a1..ba5972ea0c 100644 --- a/app/TransactionRules/Triggers/FromAccountIs.php +++ b/app/TransactionRules/Triggers/FromAccountIs.php @@ -77,12 +77,14 @@ final class FromAccountIs extends AbstractTrigger implements TriggerInterface $search = strtolower($this->triggerValue); if (strtolower($source->name) === $search) { - Log::debug(sprintf('RuleTrigger FromAccountIs for journal #%d: "%s" is "%s", return true.', $journal->id, $name, $search)); + Log::debug(sprintf('RuleTrigger %s for journal #%d: "%s" is "%s", return true.', + get_class($this), $journal->id, $source->name, $search)); return true; } - Log::debug(sprintf('RuleTrigger FromAccountIs for journal #%d: "%s" is NOT "%s", return false.', $journal->id, $name, $search)); + Log::debug(sprintf('RuleTrigger %s for journal #%d: "%s" is NOT "%s", return false.', + get_class($this), $journal->id, $source->name, $search)); return false; } diff --git a/app/TransactionRules/Triggers/FromAccountNumberContains.php b/app/TransactionRules/Triggers/FromAccountNumberContains.php index 034a61baaf..6d7a7d27c7 100644 --- a/app/TransactionRules/Triggers/FromAccountNumberContains.php +++ b/app/TransactionRules/Triggers/FromAccountNumberContains.php @@ -80,8 +80,8 @@ final class FromAccountNumberContains extends AbstractTrigger implements Trigger if (!(false === $strpos1) || !(false === $strpos2)) { Log::debug( sprintf( - 'RuleTrigger FromAccountContains for journal #%d: "%s" or "%s" contains "%s", return true.', - $journal->id, $source->iban, $source->account_number, $this->triggerValue + 'RuleTrigger %s for journal #%d: "%s" or "%s" contains "%s", return true.', + get_class($this), $journal->id, $source->iban, $source->account_number, $this->triggerValue ) ); @@ -90,11 +90,8 @@ final class FromAccountNumberContains extends AbstractTrigger implements Trigger Log::debug( sprintf( - 'RuleTrigger FromAccountContains for journal #%d: "%s" and "%s" does not contain "%s", return false.', - $journal->id, - $source->iban, - $source->account_number, - $this->triggerValue + 'RuleTrigger %s for journal #%d: "%s" and "%s" does not contain "%s", return false.', + get_class($this), $journal->id, $source->iban, $source->account_number, $this->triggerValue ) ); diff --git a/app/TransactionRules/Triggers/FromAccountNumberEnds.php b/app/TransactionRules/Triggers/FromAccountNumberEnds.php index c3afaed82f..2228c9fad4 100644 --- a/app/TransactionRules/Triggers/FromAccountNumberEnds.php +++ b/app/TransactionRules/Triggers/FromAccountNumberEnds.php @@ -74,18 +74,18 @@ final class FromAccountNumberEnds extends AbstractTrigger implements TriggerInte /** @var JournalRepositoryInterface $repository */ $repository = app(JournalRepositoryInterface::class); $source = $repository->getSourceAccount($journal); - $search = $this->triggerValue; + $search = strtolower($this->triggerValue); $searchLength = strlen($search); $part1 = substr($source->iban, $searchLength * -1); $part2 = substr($source->account_number, $searchLength * -1); - if (strtolower($part1) === strtolower($search) - || strtolower($part2) === strtolower($search)) { + if (strtolower($part1) === $search + || strtolower($part2) === $search) { Log::debug( sprintf( - 'RuleTrigger FromAccountEnds for journal #%d: "%s" or "%s" ends with "%s", return true.', - $journal->id, $part1, $part2, $search + 'RuleTrigger %s for journal #%d: "%s" or "%s" ends with "%s", return true.', + get_class($this), $journal->id, $part1, $part2, $search ) ); @@ -94,8 +94,8 @@ final class FromAccountNumberEnds extends AbstractTrigger implements TriggerInte Log::debug( sprintf( - 'RuleTrigger FromAccountEnds for journal #%d: "%s" and "%s" do not end with "%s", return false.', - $journal->id, $part1, $part2, $search + 'RuleTrigger %s for journal #%d: "%s" and "%s" do not end with "%s", return false.', + get_class($this), $journal->id, $part1, $part2, $search ) ); diff --git a/app/TransactionRules/Triggers/FromAccountNumberIs.php b/app/TransactionRules/Triggers/FromAccountNumberIs.php index 3ad768645b..71970341a8 100644 --- a/app/TransactionRules/Triggers/FromAccountNumberIs.php +++ b/app/TransactionRules/Triggers/FromAccountNumberIs.php @@ -79,8 +79,8 @@ final class FromAccountNumberIs extends AbstractTrigger implements TriggerInterf if (strtolower($source->iban) === $search || strtolower($source->account_number) === $search) { Log::debug( sprintf( - 'RuleTrigger FromAccountIs for journal #%d: "%s" or "%s" is "%s", return true.', $journal->id, - $source->iban, $source->account_number, $search + 'RuleTrigger %s for journal #%d: "%s" or "%s" is "%s", return true.', $journal->id, + get_class($this), $source->iban, $source->account_number, $search ) ); @@ -89,8 +89,8 @@ final class FromAccountNumberIs extends AbstractTrigger implements TriggerInterf Log::debug( sprintf( - 'RuleTrigger FromAccountIs for journal #%d: "%s" and "%s" is NOT "%s", return false.', $journal->id, $source->iban, $source->account_number, - $search + 'RuleTrigger %s for journal #%d: "%s" and "%s" are NOT "%s", return false.', + get_class($this), $journal->id, $source->iban, $source->account_number, $search ) ); diff --git a/app/TransactionRules/Triggers/FromAccountNumberStarts.php b/app/TransactionRules/Triggers/FromAccountNumberStarts.php index 4343a10427..e9fcabdd8c 100644 --- a/app/TransactionRules/Triggers/FromAccountNumberStarts.php +++ b/app/TransactionRules/Triggers/FromAccountNumberStarts.php @@ -81,8 +81,8 @@ final class FromAccountNumberStarts extends AbstractTrigger implements TriggerIn if ($part1 === $search || $part2 === $search) { Log::debug( sprintf( - 'RuleTrigger FromAccountStarts for journal #%d: "%s" or "%s" starts with "%s", return true.', $journal->id, - $part1, $part2, $search + 'RuleTrigger %s for journal #%d: "%s" or "%s" starts with "%s", return true.', + get_class($this), $journal->id, $part1, $part2, $search ) ); @@ -91,8 +91,8 @@ final class FromAccountNumberStarts extends AbstractTrigger implements TriggerIn Log::debug( sprintf( - 'RuleTrigger FromAccountStarts for journal #%d: "%s" and "%s" do not start with "%s", return false.', - $journal->id, $part1, $part2, $search + 'RuleTrigger %s for journal #%d: "%s" and "%s" do not start with "%s", return false.', + get_class($this), $journal->id, $part1, $part2, $search ) ); diff --git a/app/TransactionRules/Triggers/FromAccountStarts.php b/app/TransactionRules/Triggers/FromAccountStarts.php index 5bbf044ca7..00f75d25e1 100644 --- a/app/TransactionRules/Triggers/FromAccountStarts.php +++ b/app/TransactionRules/Triggers/FromAccountStarts.php @@ -78,12 +78,22 @@ final class FromAccountStarts extends AbstractTrigger implements TriggerInterfac $part = substr($source->name, 0, strlen($search)); if ($part === $search) { - Log::debug(sprintf('RuleTrigger FromAccountStarts for journal #%d: "%s" starts with "%s", return true.', $journal->id, $name, $search)); + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" starts with "%s", return true.', + get_class($this), $journal->id, $source->name, $search + ) + ); return true; } - Log::debug(sprintf('RuleTrigger FromAccountStarts for journal #%d: "%s" does not start with "%s", return false.', $journal->id, $name, $search)); + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" does not start with "%s", return false.', + get_class($this), $journal->id, $source->name, $search + ) + ); return false; } diff --git a/app/TransactionRules/Triggers/ToAccountContains.php b/app/TransactionRules/Triggers/ToAccountContains.php index bd88d52e4b..4754ea7c22 100644 --- a/app/TransactionRules/Triggers/ToAccountContains.php +++ b/app/TransactionRules/Triggers/ToAccountContains.php @@ -22,7 +22,6 @@ declare(strict_types=1); namespace FireflyIII\TransactionRules\Triggers; -use FireflyIII\Models\Account; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use Log; @@ -65,39 +64,32 @@ final class ToAccountContains extends AbstractTrigger implements TriggerInterfac /** * Returns true when to-account contains X - * TODO - * * @param TransactionJournal $journal * * @return bool */ public function triggered(TransactionJournal $journal): bool { - $toAccountName = ''; - /** @var JournalRepositoryInterface $repository */ $repository = app(JournalRepositoryInterface::class); - - /** @var Account $account */ - foreach ($repository->getJournalDestinationAccounts($journal, false) as $account) { - $toAccountName .= strtolower($account->name); - } - - $search = strtolower($this->triggerValue); - $strpos = strpos($toAccountName, $search); + $dest = $repository->getDestinationAccount($journal); + $strpos = stripos($dest->name, $this->triggerValue); if (!(false === $strpos)) { - Log::debug(sprintf('RuleTrigger ToAccountContains for journal #%d: "%s" contains "%s", return true.', $journal->id, $toAccountName, $search)); + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" contains "%s", return true.', + get_class($this), $journal->id, $dest->name, $this->triggerValue + ) + ); return true; } Log::debug( sprintf( - 'RuleTrigger ToAccountContains for journal #%d: "%s" does not contain "%s", return false.', - $journal->id, - $toAccountName, - $search + 'RuleTrigger %s for journal #%d: "%s" does not contain "%s", return false.', + get_class($this), $journal->id, $dest->name, $this->triggerValue ) ); diff --git a/app/TransactionRules/Triggers/ToAccountEnds.php b/app/TransactionRules/Triggers/ToAccountEnds.php index 44faac5d47..2298730bb8 100644 --- a/app/TransactionRules/Triggers/ToAccountEnds.php +++ b/app/TransactionRules/Triggers/ToAccountEnds.php @@ -22,7 +22,6 @@ declare(strict_types=1); namespace FireflyIII\TransactionRules\Triggers; -use FireflyIII\Models\Account; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use Log; @@ -72,37 +71,44 @@ final class ToAccountEnds extends AbstractTrigger implements TriggerInterface */ public function triggered(TransactionJournal $journal): bool { - $toAccountName = ''; - /** @var JournalRepositoryInterface $repository */ - $repository = app(JournalRepositoryInterface::class); - - /** @var Account $account */ - foreach ($repository->getJournalDestinationAccounts($journal, false) as $account) { - $toAccountName .= strtolower($account->name); - } - - $toAccountNameLength = strlen($toAccountName); - $search = strtolower($this->triggerValue); - $searchLength = strlen($search); + $repository = app(JournalRepositoryInterface::class); + $dest = $repository->getDestinationAccount($journal); + $nameLength = strlen($dest->name); + $search = $this->triggerValue; + $searchLength = strlen($search); + $part = substr($dest->name, $searchLength * -1); // if the string to search for is longer than the account name, - // return false - if ($searchLength > $toAccountNameLength) { - Log::debug(sprintf('RuleTrigger ToAccountEnds for journal #%d: "%s" does not end with "%s", return false.', $journal->id, $toAccountName, $search)); + // it will never be in the account name. + if ($searchLength > $nameLength) { + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" does not end with "%s", return false.', + get_class($this), $journal->id, $dest->name, $search + ) + ); return false; } - $part = substr($toAccountName, $searchLength * -1); - - if ($part === $search) { - Log::debug(sprintf('RuleTrigger ToAccountEnds for journal #%d: "%s" ends with "%s", return true.', $journal->id, $toAccountName, $search)); + if (strtolower($part) === strtolower($search)) { + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" ends with "%s", return true.', + get_class($this), $journal->id, $dest->name, $search + ) + ); return true; } - Log::debug(sprintf('RuleTrigger ToAccountEnds for journal #%d: "%s" does not end with "%s", return false.', $journal->id, $toAccountName, $search)); + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" does not end with "%s", return false.', + get_class($this), $journal->id, $dest->name, $search + ) + ); return false; } diff --git a/app/TransactionRules/Triggers/ToAccountIs.php b/app/TransactionRules/Triggers/ToAccountIs.php index a70adc31b3..3f54470788 100644 --- a/app/TransactionRules/Triggers/ToAccountIs.php +++ b/app/TransactionRules/Triggers/ToAccountIs.php @@ -72,25 +72,20 @@ final class ToAccountIs extends AbstractTrigger implements TriggerInterface */ public function triggered(TransactionJournal $journal): bool { - $toAccountName = ''; - /** @var JournalRepositoryInterface $repository */ $repository = app(JournalRepositoryInterface::class); + $dest = $repository->getDestinationAccount($journal); + $search = strtolower($this->triggerValue); - /** @var Account $account */ - foreach ($repository->getJournalDestinationAccounts($journal, false) as $account) { - $toAccountName .= strtolower($account->name); - } - - $search = strtolower($this->triggerValue); - - if ($toAccountName === $search) { - Log::debug(sprintf('RuleTrigger ToAccountIs for journal #%d: "%s" is "%s", return true.', $journal->id, $toAccountName, $search)); + if (strtolower($dest->name) === $search) { + Log::debug(sprintf('RuleTrigger %s for journal #%d: "%s" is "%s", return true.', + get_class($this), $journal->id, $dest->name, $search)); return true; } - Log::debug(sprintf('RuleTrigger ToAccountIs for journal #%d: "%s" is NOT "%s", return false.', $journal->id, $toAccountName, $search)); + Log::debug(sprintf('RuleTrigger %s for journal #%d: "%s" is NOT "%s", return false.', + get_class($this), $journal->id, $dest->name, $search)); return false; } diff --git a/app/TransactionRules/Triggers/ToAccountNumberContains.php b/app/TransactionRules/Triggers/ToAccountNumberContains.php new file mode 100644 index 0000000000..0099c5dcce --- /dev/null +++ b/app/TransactionRules/Triggers/ToAccountNumberContains.php @@ -0,0 +1,100 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\TransactionRules\Triggers; + +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use Log; + +/** + * Class ToAccountNumberContains. + */ +final class ToAccountNumberContains extends AbstractTrigger implements TriggerInterface +{ + /** + * A trigger is said to "match anything", or match any given transaction, + * when the trigger value is very vague or has no restrictions. Easy examples + * are the "AmountMore"-trigger combined with an amount of 0: any given transaction + * has an amount of more than zero! Other examples are all the "Description"-triggers + * which have hard time handling empty trigger values such as "" or "*" (wild cards). + * + * If the user tries to create such a trigger, this method MUST return true so Firefly III + * can stop the storing / updating the trigger. If the trigger is in any way restrictive + * (even if it will still include 99.9% of the users transactions), this method MUST return + * false. + * + * @param mixed $value + * + * @return bool + */ + public static function willMatchEverything($value = null): bool + { + if (null !== $value) { + $res = '' === (string)$value; + if (true === $res) { + Log::error(sprintf('Cannot use %s with "" as a value.', self::class)); + } + + return $res; + } + Log::error(sprintf('Cannot use %s with a null value.', self::class)); + + return true; + } + + /** + * Returns true when from-account contains X + * + * @param TransactionJournal $journal + * + * @return bool + */ + public function triggered(TransactionJournal $journal): bool + { + /** @var JournalRepositoryInterface $repository */ + $repository = app(JournalRepositoryInterface::class); + $dest = $repository->getDestinationAccount($journal); + $strpos1 = stripos($dest->iban, $this->triggerValue); + $strpos2 = stripos($dest->account_number, $this->triggerValue); + + if (!(false === $strpos1) || !(false === $strpos2)) { + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" or "%s" contains "%s", return true.', + get_class($this), $journal->id, $dest->iban, $dest->account_number, $this->triggerValue + ) + ); + + return true; + } + + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" and "%s" does not contain "%s", return false.', + get_class($this), $journal->id, $dest->iban, $dest->account_number, $this->triggerValue + ) + ); + + return false; + } +} diff --git a/app/TransactionRules/Triggers/ToAccountNumberEnds.php b/app/TransactionRules/Triggers/ToAccountNumberEnds.php new file mode 100644 index 0000000000..8e20d8ecfe --- /dev/null +++ b/app/TransactionRules/Triggers/ToAccountNumberEnds.php @@ -0,0 +1,104 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\TransactionRules\Triggers; + +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use Log; + +/** + * Class ToAccountNumberEnds. + */ +final class ToAccountNumberEnds extends AbstractTrigger implements TriggerInterface +{ + /** + * A trigger is said to "match anything", or match any given transaction, + * when the trigger value is very vague or has no restrictions. Easy examples + * are the "AmountMore"-trigger combined with an amount of 0: any given transaction + * has an amount of more than zero! Other examples are all the "Description"-triggers + * which have hard time handling empty trigger values such as "" or "*" (wild cards). + * + * If the user tries to create such a trigger, this method MUST return true so Firefly III + * can stop the storing / updating the trigger. If the trigger is in any way restrictive + * (even if it will still include 99.9% of the users transactions), this method MUST return + * false. + * + * @param mixed $value + * + * @return bool + */ + public static function willMatchEverything($value = null): bool + { + if (null !== $value) { + $res = '' === (string)$value; + if (true === $res) { + Log::error(sprintf('Cannot use %s with "" as a value.', self::class)); + } + + return $res; + } + Log::error(sprintf('Cannot use %s with a null value.', self::class)); + + return true; + } + + /** + * Returns true when from account ends with X + * + * @param TransactionJournal $journal + * + * @return bool + */ + public function triggered(TransactionJournal $journal): bool + { + /** @var JournalRepositoryInterface $repository */ + $repository = app(JournalRepositoryInterface::class); + $dest = $repository->getDestinationAccount($journal); + $search = strtolower($this->triggerValue); + $searchLength = strlen($search); + + $part1 = substr($dest->iban, $searchLength * -1); + $part2 = substr($dest->account_number, $searchLength * -1); + + if (strtolower($part1) === $search + || strtolower($part2) === $search) { + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" or "%s" ends with "%s", return true.', + get_class($this), $journal->id, $part1, $part2, $search + ) + ); + + return true; + } + + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" and "%s" do not end with "%s", return false.', + get_class($this), $journal->id, $part1, $part2, $search + ) + ); + + return false; + } +} diff --git a/app/TransactionRules/Triggers/ToAccountNumberIs.php b/app/TransactionRules/Triggers/ToAccountNumberIs.php new file mode 100644 index 0000000000..0fc44eabc7 --- /dev/null +++ b/app/TransactionRules/Triggers/ToAccountNumberIs.php @@ -0,0 +1,99 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\TransactionRules\Triggers; + +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use Log; + +/** + * Class ToAccountNumberIs. + */ +final class ToAccountNumberIs extends AbstractTrigger implements TriggerInterface +{ + /** + * A trigger is said to "match anything", or match any given transaction, + * when the trigger value is very vague or has no restrictions. Easy examples + * are the "AmountMore"-trigger combined with an amount of 0: any given transaction + * has an amount of more than zero! Other examples are all the "Description"-triggers + * which have hard time handling empty trigger values such as "" or "*" (wild cards). + * + * If the user tries to create such a trigger, this method MUST return true so Firefly III + * can stop the storing / updating the trigger. If the trigger is in any way restrictive + * (even if it will still include 99.9% of the users transactions), this method MUST return + * false. + * + * @param mixed $value + * + * @return bool + */ + public static function willMatchEverything($value = null): bool + { + if (null !== $value) { + $res = '' === (string)$value; + if (true === $res) { + Log::error(sprintf('Cannot use %s with "" as a value.', self::class)); + } + + return $res; + } + Log::error(sprintf('Cannot use %s with a null value.', self::class)); + + return true; + } + + /** + * Returns true when from-account is X. + * + * @param TransactionJournal $journal + * + * @return bool + */ + public function triggered(TransactionJournal $journal): bool + { + /** @var JournalRepositoryInterface $repository */ + $repository = app(JournalRepositoryInterface::class); + $dest = $repository->getDestinationAccount($journal); + $search = strtolower($this->triggerValue); + + if (strtolower($dest->iban) === $search || strtolower($dest->account_number) === $search) { + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" or "%s" is "%s", return true.', $journal->id, + get_class($this), $dest->iban, $dest->account_number, $search + ) + ); + + return true; + } + + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" and "%s" are NOT "%s", return false.', + get_class($this), $journal->id, $dest->iban, $dest->account_number, $search + ) + ); + + return false; + } +} diff --git a/app/TransactionRules/Triggers/ToAccountNumberStarts.php b/app/TransactionRules/Triggers/ToAccountNumberStarts.php new file mode 100644 index 0000000000..618552c9ab --- /dev/null +++ b/app/TransactionRules/Triggers/ToAccountNumberStarts.php @@ -0,0 +1,101 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\TransactionRules\Triggers; + +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use Log; + +/** + * Class FromAccountNumberStarts. + */ +final class ToAccountNumberStarts extends AbstractTrigger implements TriggerInterface +{ + /** + * A trigger is said to "match anything", or match any given transaction, + * when the trigger value is very vague or has no restrictions. Easy examples + * are the "AmountMore"-trigger combined with an amount of 0: any given transaction + * has an amount of more than zero! Other examples are all the "Description"-triggers + * which have hard time handling empty trigger values such as "" or "*" (wild cards). + * + * If the user tries to create such a trigger, this method MUST return true so Firefly III + * can stop the storing / updating the trigger. If the trigger is in any way restrictive + * (even if it will still include 99.9% of the users transactions), this method MUST return + * false. + * + * @param mixed $value + * + * @return bool + */ + public static function willMatchEverything($value = null): bool + { + if (null !== $value) { + $res = '' === (string)$value; + if (true === $res) { + Log::error(sprintf('Cannot use %s with "" as a value.', self::class)); + } + + return $res; + } + Log::error(sprintf('Cannot use %s with a null value.', self::class)); + + return true; + } + + /** + * Returns true when from-account starts with X. + * + * @param TransactionJournal $journal + * + * @return bool + */ + public function triggered(TransactionJournal $journal): bool + { + /** @var JournalRepositoryInterface $repository */ + $repository = app(JournalRepositoryInterface::class); + $dest = $repository->getDestinationAccount($journal); + $search = strtolower($this->triggerValue); + $part1 = strtolower(substr($dest->iban, 0, strlen($search))); + $part2 = strtolower(substr($dest->account_number, 0, strlen($search))); + + if ($part1 === $search || $part2 === $search) { + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" or "%s" starts with "%s", return true.', + get_class($this), $journal->id, $part1, $part2, $search + ) + ); + + return true; + } + + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" and "%s" do not start with "%s", return false.', + get_class($this), $journal->id, $part1, $part2, $search + ) + ); + + return false; + } +} diff --git a/app/TransactionRules/Triggers/ToAccountStarts.php b/app/TransactionRules/Triggers/ToAccountStarts.php index 9d8df60b9d..a96c321239 100644 --- a/app/TransactionRules/Triggers/ToAccountStarts.php +++ b/app/TransactionRules/Triggers/ToAccountStarts.php @@ -72,25 +72,29 @@ final class ToAccountStarts extends AbstractTrigger implements TriggerInterface */ public function triggered(TransactionJournal $journal): bool { - $toAccountName = ''; - /** @var JournalRepositoryInterface $repository */ $repository = app(JournalRepositoryInterface::class); - - /** @var Account $account */ - foreach ($repository->getJournalDestinationAccounts($journal, false) as $account) { - $toAccountName .= strtolower($account->name); - } - - $search = strtolower($this->triggerValue); - $part = substr($toAccountName, 0, strlen($search)); + $dest = $repository->getDestinationAccount($journal); + $search = strtolower($this->triggerValue); + $part = substr($dest->name, 0, strlen($search)); if ($part === $search) { - Log::debug(sprintf('RuleTrigger ToAccountStarts for journal #%d: "%s" starts with "%s", return true.', $journal->id, $toAccountName, $search)); + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" starts with "%s", return true.', + get_class($this), $journal->id, $dest->name, $search + ) + ); return true; } - Log::debug(sprintf('RuleTrigger ToAccountStarts for journal #%d: "%s" does not start with "%s", return false.', $journal->id, $toAccountName, $search)); + + Log::debug( + sprintf( + 'RuleTrigger %s for journal #%d: "%s" does not start with "%s", return false.', + get_class($this), $journal->id, $dest->name, $search + ) + ); return false; } diff --git a/config/firefly.php b/config/firefly.php index 0d9c17637c..5ffcb26960 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -112,6 +112,10 @@ use FireflyIII\TransactionRules\Triggers\TagIs; use FireflyIII\TransactionRules\Triggers\ToAccountContains; use FireflyIII\TransactionRules\Triggers\ToAccountEnds; use FireflyIII\TransactionRules\Triggers\ToAccountIs; +use FireflyIII\TransactionRules\Triggers\ToAccountNumberContains; +use FireflyIII\TransactionRules\Triggers\ToAccountNumberEnds; +use FireflyIII\TransactionRules\Triggers\ToAccountNumberIs; +use FireflyIII\TransactionRules\Triggers\ToAccountNumberStarts; use FireflyIII\TransactionRules\Triggers\ToAccountStarts; use FireflyIII\TransactionRules\Triggers\TransactionType; use FireflyIII\TransactionRules\Triggers\UserAction; @@ -421,10 +425,10 @@ return [ 'to_account_ends' => ToAccountEnds::class, 'to_account_is' => ToAccountIs::class, 'to_account_contains' => ToAccountContains::class, - //'to_account_nr_starts' => ToAccountNumberStarts::class, - //'to_account_nr_ends' => ToAccountNumberEnds::class, - //'to_account_nr_is' => ToAccountNumberIs::class, - //'to_account_nr_contains' => ToAccountNumberContains::class, + 'to_account_nr_starts' => ToAccountNumberStarts::class, + 'to_account_nr_ends' => ToAccountNumberEnds::class, + 'to_account_nr_is' => ToAccountNumberIs::class, + 'to_account_nr_contains' => ToAccountNumberContains::class, 'amount_less' => AmountLess::class, 'amount_exactly' => AmountExactly::class, 'amount_more' => AmountMore::class,