Expand search and add operators.

This commit is contained in:
James Cole
2022-09-28 07:35:57 +02:00
parent 6eaed9829b
commit 9b7285ea84
7 changed files with 865 additions and 118 deletions

View File

@@ -62,6 +62,32 @@ trait AttachmentCollection
return $this; return $this;
} }
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameDoesNotContain(string $name): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($name): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
$result = !str_contains(strtolower($attachment['filename']), strtolower($name)) && !str_contains(strtolower($attachment['title']), strtolower($name));
if (true === $result) {
return true;
}
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/** /**
* Has attachments * Has attachments
* *
@@ -135,6 +161,32 @@ trait AttachmentCollection
return $this; return $this;
} }
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameDoesNotEnd(string $name): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($name): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
$result = !str_ends_with(strtolower($attachment['filename']), strtolower($name)) && !str_ends_with(strtolower($attachment['title']), strtolower($name));
if (true === $result) {
return true;
}
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/** /**
* @param string $name * @param string $name
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -161,6 +213,32 @@ trait AttachmentCollection
return $this; return $this;
} }
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameIsNot(string $name): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($name): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
$result = $attachment['filename'] !== $name && $attachment['title'] !== $name;
if (true === $result) {
return true;
}
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/** /**
* @param string $name * @param string $name
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -187,6 +265,32 @@ trait AttachmentCollection
return $this; return $this;
} }
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameDoesNotStart(string $name): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($name): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
$result = !str_starts_with(strtolower($attachment['filename']), strtolower($name)) && !str_starts_with(strtolower($attachment['title']), strtolower($name));
if (true === $result) {
return true;
}
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/** /**
* @param string $value * @param string $value
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -213,6 +317,32 @@ trait AttachmentCollection
return $this; return $this;
} }
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesAreNot(string $value): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($value): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
/** @var Attachment $object */
$object = auth()->user()->attachments()->find($attachment['id']);
$notes = (string) $object->notes()?->first()?->text;
return $notes !== '' && $notes !== $value;
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/** /**
* @param string $value * @param string $value
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -239,6 +369,32 @@ trait AttachmentCollection
return $this; return $this;
} }
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesDoNotContain(string $value): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($value): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
/** @var Attachment $object */
$object = auth()->user()->attachments()->find($attachment['id']);
$notes = (string) $object->notes()?->first()?->text;
return $notes !== '' && !str_contains(strtolower($notes), strtolower($value));
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/** /**
* @param string $value * @param string $value
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -265,6 +421,32 @@ trait AttachmentCollection
return $this; return $this;
} }
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesDoNotEnd(string $value): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($value): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
/** @var Attachment $object */
$object = auth()->user()->attachments()->find($attachment['id']);
$notes = (string) $object->notes()?->first()?->text;
return $notes !== '' && !str_ends_with(strtolower($notes), strtolower($value));
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/** /**
* @param string $value * @param string $value
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -291,6 +473,32 @@ trait AttachmentCollection
return $this; return $this;
} }
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesDoNotStart(string $value): GroupCollectorInterface
{
$this->hasAttachments();
$this->withAttachmentInformation();
$filter = function (int $index, array $object) use ($value): bool {
/** @var array $transaction */
foreach ($object['transactions'] as $transaction) {
/** @var array $attachment */
foreach ($transaction['attachments'] as $attachment) {
/** @var Attachment $object */
$object = auth()->user()->attachments()->find($attachment['id']);
$notes = (string) $object->notes()?->first()?->text;
return $notes !== '' && !str_starts_with(strtolower($notes), strtolower($value));
}
}
return false;
};
$this->postFilters[] = $filter;
return $this;
}
/** /**
* Has attachments * Has attachments
* *

View File

@@ -135,6 +135,18 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function externalIdDoesNotContain(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id');
$this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s%%', $externalId));
return $this;
}
/** /**
* Join table to get tag information. * Join table to get tag information.
*/ */
@@ -160,6 +172,18 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function externalIdDoesNotEnd(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id');
$this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s"', $externalId));
return $this;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -172,6 +196,18 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function externalIdDoesNotStart(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id');
$this->query->where('journal_meta.data', 'LIKE', sprintf('"%s%%', $externalId));
return $this;
}
/** /**
* @param string $url * @param string $url
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -187,6 +223,23 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlDoesNotContain(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = str_replace('\\', '\\\\', trim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s%%', $url));
return $this;
}
/** /**
* @param string $url * @param string $url
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -202,6 +255,23 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlDoesNotEnd(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = str_replace('\\', '\\\\', ltrim($url, '"'));
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s', $url));
return $this;
}
/** /**
* @param string $url * @param string $url
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -219,6 +289,23 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlDoesNotStart(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$url = json_encode($url);
$url = str_replace('\\', '\\\\', rtrim($url, '"'));
//var_dump($url);
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%s%%', $url));
return $this;
}
/** /**
* Where has no tags. * Where has no tags.
* *
@@ -275,6 +362,18 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function internalReferenceDoesNotContain(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s%%', $externalId));
return $this;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -287,6 +386,18 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function internalReferenceDoesNotEnd(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s"', $externalId));
return $this;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -299,6 +410,18 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function internalReferenceDoesNotStart(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->where('journal_meta.data', 'LIKE', sprintf('"%s%%', $externalId));
return $this;
}
/** /**
* @param string $value * @param string $value
* *
@@ -605,6 +728,19 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function excludeExternalId(string $externalId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id');
$this->query->where('journal_meta.data', '!=', sprintf('%s', json_encode($externalId)));
return $this;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -617,6 +753,18 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function excludeExternalUrl(string $url): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', '!=', json_encode($url));
return $this;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -630,6 +778,19 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function excludeInternalReference(string $internalReference): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s%%', $internalReference));
return $this;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -642,6 +803,18 @@ trait MetaCollection
return $this; return $this;
} }
/**
* @inheritDoc
*/
public function excludeRecurrenceId(string $recurringId): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'recurrence_id');
$this->query->where('journal_meta.data', '!=', sprintf('%s', json_encode($recurringId)));
return $this;
}
/** /**
* Limit results to a specific tag. * Limit results to a specific tag.
* *

View File

@@ -79,18 +79,42 @@ interface GroupCollectorInterface
*/ */
public function attachmentNameContains(string $name): GroupCollectorInterface; public function attachmentNameContains(string $name): GroupCollectorInterface;
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameDoesNotContain(string $name): GroupCollectorInterface;
/** /**
* @param string $name * @param string $name
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function attachmentNameEnds(string $name): GroupCollectorInterface; public function attachmentNameEnds(string $name): GroupCollectorInterface;
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameDoesNotEnd(string $name): GroupCollectorInterface;
/** /**
* @param string $name * @param string $name
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function attachmentNameIs(string $name): GroupCollectorInterface; public function attachmentNameIs(string $name): GroupCollectorInterface;
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameIsNot(string $name): GroupCollectorInterface;
/**
* @param string $name
* @return GroupCollectorInterface
*/
public function attachmentNameDoesNotStart(string $name): GroupCollectorInterface;
/** /**
* @param string $name * @param string $name
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -103,12 +127,24 @@ interface GroupCollectorInterface
*/ */
public function attachmentNotesAre(string $value): GroupCollectorInterface; public function attachmentNotesAre(string $value): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesAreNot(string $value): GroupCollectorInterface;
/** /**
* @param string $value * @param string $value
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function attachmentNotesContains(string $value): GroupCollectorInterface; public function attachmentNotesContains(string $value): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesDoNotContain(string $value): GroupCollectorInterface;
/** /**
* @param string $value * @param string $value
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -121,6 +157,18 @@ interface GroupCollectorInterface
*/ */
public function attachmentNotesStarts(string $value): GroupCollectorInterface; public function attachmentNotesStarts(string $value): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesDoNotEnd(string $value): GroupCollectorInterface;
/**
* @param string $value
* @return GroupCollectorInterface
*/
public function attachmentNotesDoNotStart(string $value): GroupCollectorInterface;
/** /**
* @param string $day * @param string $day
* @return GroupCollectorInterface * @return GroupCollectorInterface
@@ -358,36 +406,76 @@ interface GroupCollectorInterface
*/ */
public function externalIdContains(string $externalId): GroupCollectorInterface; public function externalIdContains(string $externalId): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function externalIdDoesNotContain(string $externalId): GroupCollectorInterface;
/** /**
* @param string $externalId * @param string $externalId
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function externalIdEnds(string $externalId): GroupCollectorInterface; public function externalIdEnds(string $externalId): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function externalIdDoesNotEnd(string $externalId): GroupCollectorInterface;
/** /**
* @param string $externalId * @param string $externalId
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function externalIdStarts(string $externalId): GroupCollectorInterface; public function externalIdStarts(string $externalId): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function externalIdDoesNotStart(string $externalId): GroupCollectorInterface;
/** /**
* @param string $url * @param string $url
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function externalUrlContains(string $url): GroupCollectorInterface; public function externalUrlContains(string $url): GroupCollectorInterface;
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlDoesNotContain(string $url): GroupCollectorInterface;
/** /**
* @param string $url * @param string $url
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function externalUrlEnds(string $url): GroupCollectorInterface; public function externalUrlEnds(string $url): GroupCollectorInterface;
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlDoesNotEnd(string $url): GroupCollectorInterface;
/** /**
* @param string $url * @param string $url
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function externalUrlStarts(string $url): GroupCollectorInterface; public function externalUrlStarts(string $url): GroupCollectorInterface;
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function externalUrlDoesNotStart(string $url): GroupCollectorInterface;
/** /**
* Ensure the search will find nothing at all, zero results. * Ensure the search will find nothing at all, zero results.
* *
@@ -477,18 +565,36 @@ interface GroupCollectorInterface
*/ */
public function internalReferenceContains(string $externalId): GroupCollectorInterface; public function internalReferenceContains(string $externalId): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function internalReferenceDoesNotContain(string $externalId): GroupCollectorInterface;
/** /**
* @param string $externalId * @param string $externalId
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function internalReferenceEnds(string $externalId): GroupCollectorInterface; public function internalReferenceEnds(string $externalId): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function internalReferenceDoesNotEnd(string $externalId): GroupCollectorInterface;
/** /**
* @param string $externalId * @param string $externalId
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function internalReferenceStarts(string $externalId): GroupCollectorInterface; public function internalReferenceStarts(string $externalId): GroupCollectorInterface;
/**
* @param string $externalId
* @return GroupCollectorInterface
*/
public function internalReferenceDoesNotStart(string $externalId): GroupCollectorInterface;
/** /**
* Only journals that are reconciled. * Only journals that are reconciled.
* *
@@ -876,12 +982,27 @@ interface GroupCollectorInterface
*/ */
public function setExternalId(string $externalId): GroupCollectorInterface; public function setExternalId(string $externalId): GroupCollectorInterface;
/**
* Look for specific external ID's.
*
* @param string $externalId
*
* @return GroupCollectorInterface
*/
public function excludeExternalId(string $externalId): GroupCollectorInterface;
/** /**
* @param string $url * @param string $url
* @return GroupCollectorInterface * @return GroupCollectorInterface
*/ */
public function setExternalUrl(string $url): GroupCollectorInterface; public function setExternalUrl(string $url): GroupCollectorInterface;
/**
* @param string $url
* @return GroupCollectorInterface
*/
public function excludeExternalUrl(string $url): GroupCollectorInterface;
/** /**
* Limit results to a specific foreign currency. * Limit results to a specific foreign currency.
* *
@@ -909,6 +1030,17 @@ interface GroupCollectorInterface
*/ */
public function setInternalReference(string $externalId): GroupCollectorInterface; public function setInternalReference(string $externalId): GroupCollectorInterface;
/**
* Look for specific external ID's.
*
* @param string $externalId
*
* @return GroupCollectorInterface
*/
public function excludeInternalReference(string $externalId): GroupCollectorInterface;
/** /**
* Limit the result to a set of specific transaction journals. * Limit the result to a set of specific transaction journals.
* *
@@ -1015,6 +1147,13 @@ interface GroupCollectorInterface
*/ */
public function setRecurrenceId(string $recurringId): GroupCollectorInterface; public function setRecurrenceId(string $recurringId): GroupCollectorInterface;
/**
* @param string $recurringId
*
* @return GroupCollectorInterface
*/
public function excludeRecurrenceId(string $recurringId): GroupCollectorInterface;
/** /**
* Search for words in descriptions. * Search for words in descriptions.
* *

View File

@@ -33,7 +33,7 @@ use Log;
*/ */
class ParseDateString class ParseDateString
{ {
private $keywords private array $keywords
= [ = [
'today', 'today',
'yesterday', 'yesterday',
@@ -80,6 +80,7 @@ class ParseDateString
*/ */
public function parseDate(string $date): Carbon public function parseDate(string $date): Carbon
{ {
Log::debug(sprintf('parseDate("%s")', $date));
$date = strtolower($date); $date = strtolower($date);
// parse keywords: // parse keywords:
if (in_array($date, $this->keywords, true)) { if (in_array($date, $this->keywords, true)) {
@@ -118,7 +119,7 @@ class ParseDateString
return new Carbon(sprintf('%d-01-01', $date)); return new Carbon(sprintf('%d-01-01', $date));
} }
throw new FireflyException(sprintf('[d]Not a recognised date format: "%s"', $date)); throw new FireflyException(sprintf('[d] Not a recognised date format: "%s"', $date));
} }
/** /**

View File

@@ -190,7 +190,7 @@ class OperatorQuerySearch implements SearchInterface
case Subquery::class: case Subquery::class:
// loop all notes in subquery: // loop all notes in subquery:
foreach ($searchNode->getNodes() as $subNode) { // @phpstan-ignore-line foreach ($searchNode->getNodes() as $subNode) { // @phpstan-ignore-line
$this->handleSearchNode($subNode); // let's hope it's not too recursive! $this->handleSearchNode($subNode); // let's hope it's not too recursive
} }
break; break;
case Word::class: case Word::class:
@@ -254,8 +254,8 @@ class OperatorQuerySearch implements SearchInterface
private function updateCollector(string $operator, string $value, bool $prohibited): bool private function updateCollector(string $operator, string $value, bool $prohibited): bool
{ {
if ($prohibited) { if ($prohibited) {
Log::debug(sprintf('Operator "%s" is now "%s"', $operator, '!' . $operator)); Log::debug(sprintf('Operator "%s" is now "%s"', $operator, sprintf('-%s', $operator)));
$operator = sprintf('!%s', $operator); $operator = sprintf('-%s', $operator);
} }
Log::debug(sprintf('Now in updateCollector("%s", "%s")', $operator, $value)); Log::debug(sprintf('Now in updateCollector("%s", "%s")', $operator, $value));
@@ -278,97 +278,97 @@ class OperatorQuerySearch implements SearchInterface
case 'account_is': case 'account_is':
$this->searchAccount($value, 3, 4); $this->searchAccount($value, 3, 4);
break; break;
case '!account_is': case '-account_is':
$this->searchAccount($value, 3, 4, true); $this->searchAccount($value, 3, 4, true);
break; break;
case 'account_contains': case 'account_contains':
$this->searchAccount($value, 3, 3); $this->searchAccount($value, 3, 3);
break; break;
case '!account_contains': case '-account_contains':
$this->searchAccount($value, 3, 3, true); $this->searchAccount($value, 3, 3, true);
break; break;
case 'account_ends': case 'account_ends':
$this->searchAccount($value, 3, 2); $this->searchAccount($value, 3, 2);
break; break;
case '!account_ends': case '-account_ends':
$this->searchAccount($value, 3, 2, true); $this->searchAccount($value, 3, 2, true);
break; break;
case 'account_starts': case 'account_starts':
$this->searchAccount($value, 3, 1); $this->searchAccount($value, 3, 1);
break; break;
case '!account_starts': case '-account_starts':
$this->searchAccount($value, 3, 1, true); $this->searchAccount($value, 3, 1, true);
break; break;
case 'account_nr_is': case 'account_nr_is':
$this->searchAccountNr($value, 3, 4); $this->searchAccountNr($value, 3, 4);
break; break;
case '!account_nr_is': case '-account_nr_is':
$this->searchAccountNr($value, 3, 4, true); $this->searchAccountNr($value, 3, 4, true);
break; break;
case 'account_nr_contains': case 'account_nr_contains':
$this->searchAccountNr($value, 3, 3); $this->searchAccountNr($value, 3, 3);
break; break;
case '!account_nr_contains': case '-account_nr_contains':
$this->searchAccountNr($value, 3, 3, true); $this->searchAccountNr($value, 3, 3, true);
break; break;
case 'account_nr_ends': case 'account_nr_ends':
$this->searchAccountNr($value, 3, 2); $this->searchAccountNr($value, 3, 2);
break; break;
case '!account_nr_ends': case '-account_nr_ends':
$this->searchAccountNr($value, 3, 2, true); $this->searchAccountNr($value, 3, 2, true);
break; break;
case 'account_nr_starts': case 'account_nr_starts':
$this->searchAccountNr($value, 3, 1); $this->searchAccountNr($value, 3, 1);
break; break;
case '!account_nr_starts': case '-account_nr_starts':
$this->searchAccountNr($value, 3, 1, true); $this->searchAccountNr($value, 3, 1, true);
break; break;
case 'source_account_starts': case 'source_account_starts':
$this->searchAccount($value, 1, 1); $this->searchAccount($value, 1, 1);
break; break;
case '!source_account_starts': case '-source_account_starts':
$this->searchAccount($value, 1, 1, true); $this->searchAccount($value, 1, 1, true);
break; break;
case 'source_account_ends': case 'source_account_ends':
$this->searchAccount($value, 1, 2); $this->searchAccount($value, 1, 2);
break; break;
case '!source_account_ends': case '-source_account_ends':
$this->searchAccount($value, 1, 2, true); $this->searchAccount($value, 1, 2, true);
break; break;
case 'source_account_is': case 'source_account_is':
$this->searchAccount($value, 1, 4); $this->searchAccount($value, 1, 4);
break; break;
case '!source_account_is': case '-source_account_is':
$this->searchAccount($value, 1, 4, true); $this->searchAccount($value, 1, 4, true);
break; break;
case 'source_account_nr_starts': case 'source_account_nr_starts':
$this->searchAccountNr($value, 1, 1); $this->searchAccountNr($value, 1, 1);
break; break;
case '!source_account_nr_starts': case '-source_account_nr_starts':
$this->searchAccountNr($value, 1, 1, true); $this->searchAccountNr($value, 1, 1, true);
break; break;
case 'source_account_nr_ends': case 'source_account_nr_ends':
$this->searchAccountNr($value, 1, 2); $this->searchAccountNr($value, 1, 2);
break; break;
case '!source_account_nr_ends': case '-source_account_nr_ends':
$this->searchAccountNr($value, 1, 2, true); $this->searchAccountNr($value, 1, 2, true);
break; break;
case 'source_account_nr_is': case 'source_account_nr_is':
$this->searchAccountNr($value, 1, 4); $this->searchAccountNr($value, 1, 4);
break; break;
case '!source_account_nr_is': case '-source_account_nr_is':
$this->searchAccountNr($value, 1, 4, true); $this->searchAccountNr($value, 1, 4, true);
break; break;
case 'source_account_nr_contains': case 'source_account_nr_contains':
$this->searchAccountNr($value, 1, 3); $this->searchAccountNr($value, 1, 3);
break; break;
case '!source_account_nr_contains': case '-source_account_nr_contains':
$this->searchAccountNr($value, 1, 3, true); $this->searchAccountNr($value, 1, 3, true);
break; break;
case 'source_account_contains': case 'source_account_contains':
$this->searchAccount($value, 1, 3); $this->searchAccount($value, 1, 3);
break; break;
case '!source_account_contains': case '-source_account_contains':
$this->searchAccount($value, 1, 3, true); $this->searchAccount($value, 1, 3, true);
break; break;
case 'source_account_id': case 'source_account_id':
@@ -381,7 +381,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!source_account_id': case '-source_account_id':
$account = $this->accountRepository->find((int) $value); $account = $this->accountRepository->find((int) $value);
if (null !== $account) { if (null !== $account) {
$this->collector->excludeSourceAccounts(new Collection([$account])); $this->collector->excludeSourceAccounts(new Collection([$account]));
@@ -395,7 +395,7 @@ class OperatorQuerySearch implements SearchInterface
$parts = explode(',', $value); $parts = explode(',', $value);
$this->collector->setJournalIds($parts); $this->collector->setJournalIds($parts);
break; break;
case '!journal_id': case '-journal_id':
$parts = explode(',', $value); $parts = explode(',', $value);
$this->collector->excludeJournalIds($parts); $this->collector->excludeJournalIds($parts);
break; break;
@@ -403,56 +403,56 @@ class OperatorQuerySearch implements SearchInterface
$parts = explode(',', $value); $parts = explode(',', $value);
$this->collector->setIds($parts); $this->collector->setIds($parts);
break; break;
case '!id': case '-id':
$parts = explode(',', $value); $parts = explode(',', $value);
$this->collector->excludeIds($parts); $this->collector->excludeIds($parts);
break; break;
case 'destination_account_starts': case 'destination_account_starts':
$this->searchAccount($value, 2, 1); $this->searchAccount($value, 2, 1);
break; break;
case '!destination_account_starts': case '-destination_account_starts':
$this->searchAccount($value, 2, 1, true); $this->searchAccount($value, 2, 1, true);
break; break;
case 'destination_account_ends': case 'destination_account_ends':
$this->searchAccount($value, 2, 2); $this->searchAccount($value, 2, 2);
break; break;
case '!destination_account_ends': case '-destination_account_ends':
$this->searchAccount($value, 2, 2, true); $this->searchAccount($value, 2, 2, true);
break; break;
case 'destination_account_nr_starts': case 'destination_account_nr_starts':
$this->searchAccountNr($value, 2, 1); $this->searchAccountNr($value, 2, 1);
break; break;
case '!destination_account_nr_starts': case '-destination_account_nr_starts':
$this->searchAccountNr($value, 2, 1, true); $this->searchAccountNr($value, 2, 1, true);
break; break;
case 'destination_account_nr_ends': case 'destination_account_nr_ends':
$this->searchAccountNr($value, 2, 2); $this->searchAccountNr($value, 2, 2);
break; break;
case '!destination_account_nr_ends': case '-destination_account_nr_ends':
$this->searchAccountNr($value, 2, 2, true); $this->searchAccountNr($value, 2, 2, true);
break; break;
case 'destination_account_nr_is': case 'destination_account_nr_is':
$this->searchAccountNr($value, 2, 4); $this->searchAccountNr($value, 2, 4);
break; break;
case '!destination_account_nr_is': case '-destination_account_nr_is':
$this->searchAccountNr($value, 2, 4, true); $this->searchAccountNr($value, 2, 4, true);
break; break;
case 'destination_account_is': case 'destination_account_is':
$this->searchAccount($value, 2, 4); $this->searchAccount($value, 2, 4);
break; break;
case '!destination_account_is': case '-destination_account_is':
$this->searchAccount($value, 2, 4, true); $this->searchAccount($value, 2, 4, true);
break; break;
case 'destination_account_nr_contains': case 'destination_account_nr_contains':
$this->searchAccountNr($value, 2, 3); $this->searchAccountNr($value, 2, 3);
break; break;
case '!destination_account_nr_contains': case '-destination_account_nr_contains':
$this->searchAccountNr($value, 2, 3, true); $this->searchAccountNr($value, 2, 3, true);
break; break;
case 'destination_account_contains': case 'destination_account_contains':
$this->searchAccount($value, 2, 3); $this->searchAccount($value, 2, 3);
break; break;
case '!destination_account_contains': case '-destination_account_contains':
$this->searchAccount($value, 2, 3, true); $this->searchAccount($value, 2, 3, true);
break; break;
case 'destination_account_id': case 'destination_account_id':
@@ -464,7 +464,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!destination_account_id': case '-destination_account_id':
$account = $this->accountRepository->find((int) $value); $account = $this->accountRepository->find((int) $value);
if (null !== $account) { if (null !== $account) {
$this->collector->excludeDestinationAccounts(new Collection([$account])); $this->collector->excludeDestinationAccounts(new Collection([$account]));
@@ -489,7 +489,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!account_id': case '-account_id':
$parts = explode(',', $value); $parts = explode(',', $value);
$collection = new Collection; $collection = new Collection;
foreach ($parts as $accountId) { foreach ($parts as $accountId) {
@@ -512,7 +512,7 @@ class OperatorQuerySearch implements SearchInterface
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->setSourceAccounts(new Collection([$account])); $this->collector->setSourceAccounts(new Collection([$account]));
break; break;
case '!source_is_cash': case '-source_is_cash':
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->excludeSourceAccounts(new Collection([$account])); $this->collector->excludeSourceAccounts(new Collection([$account]));
break; break;
@@ -520,7 +520,7 @@ class OperatorQuerySearch implements SearchInterface
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->setDestinationAccounts(new Collection([$account])); $this->collector->setDestinationAccounts(new Collection([$account]));
break; break;
case '!destination_is_cash': case '-destination_is_cash':
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->excludeDestinationAccounts(new Collection([$account])); $this->collector->excludeDestinationAccounts(new Collection([$account]));
break; break;
@@ -528,7 +528,7 @@ class OperatorQuerySearch implements SearchInterface
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->setAccounts(new Collection([$account])); $this->collector->setAccounts(new Collection([$account]));
break; break;
case '!account_is_cash': case '-account_is_cash':
$account = $this->getCashAccount(); $account = $this->getCashAccount();
$this->collector->excludeAccounts(new Collection([$account])); $this->collector->excludeAccounts(new Collection([$account]));
break; break;
@@ -538,27 +538,27 @@ class OperatorQuerySearch implements SearchInterface
case 'description_starts': case 'description_starts':
$this->collector->descriptionStarts([$value]); $this->collector->descriptionStarts([$value]);
break; break;
case '!description_starts': case '-description_starts':
$this->collector->descriptionDoesNotStart([$value]); $this->collector->descriptionDoesNotStart([$value]);
break; break;
case 'description_ends': case 'description_ends':
$this->collector->descriptionEnds([$value]); $this->collector->descriptionEnds([$value]);
break; break;
case '!description_ends': case '-description_ends':
$this->collector->descriptionDoesNotEnd([$value]); $this->collector->descriptionDoesNotEnd([$value]);
break; break;
case 'description_contains': case 'description_contains':
$this->words[] = $value; $this->words[] = $value;
return false; return false;
case '!description_contains': case '-description_contains':
$this->prohibitedWords[] = $value; $this->prohibitedWords[] = $value;
break; break;
case 'description_is': case 'description_is':
$this->collector->descriptionIs($value); $this->collector->descriptionIs($value);
break; break;
case '!description_is': case '-description_is':
$this->collector->descriptionIsNot($value); $this->collector->descriptionIsNot($value);
break; break;
// //
@@ -573,7 +573,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!currency_is': case '-currency_is':
$currency = $this->findCurrency($value); $currency = $this->findCurrency($value);
if (null !== $currency) { if (null !== $currency) {
$this->collector->excludeCurrency($currency); $this->collector->excludeCurrency($currency);
@@ -591,7 +591,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!foreign_currency_is': case '-foreign_currency_is':
$currency = $this->findCurrency($value); $currency = $this->findCurrency($value);
if (null !== $currency) { if (null !== $currency) {
$this->collector->excludeForeignCurrency($currency); $this->collector->excludeForeignCurrency($currency);
@@ -604,22 +604,22 @@ class OperatorQuerySearch implements SearchInterface
// attachments // attachments
// //
case 'has_attachments': case 'has_attachments':
case '!has_no_attachments': case '-has_no_attachments':
Log::debug('Set collector to filter on attachments.'); Log::debug('Set collector to filter on attachments.');
$this->collector->hasAttachments(); $this->collector->hasAttachments();
break; break;
case 'has_no_attachments': case 'has_no_attachments':
case '!has_attachments': case '-has_attachments':
Log::debug('Set collector to filter on NO attachments.'); Log::debug('Set collector to filter on NO attachments.');
$this->collector->hasNoAttachments(); $this->collector->hasNoAttachments();
break; break;
// //
// categories // categories
case '!has_any_category': case '-has_any_category':
case 'has_no_category': case 'has_no_category':
$this->collector->withoutCategory(); $this->collector->withoutCategory();
break; break;
case '!has_no_category': case '-has_no_category':
case 'has_any_category': case 'has_any_category':
$this->collector->withCategory(); $this->collector->withCategory();
break; break;
@@ -631,7 +631,7 @@ class OperatorQuerySearch implements SearchInterface
} }
$this->collector->findNothing(); $this->collector->findNothing();
break; break;
case '!category_is': case '-category_is':
$category = $this->categoryRepository->findByName($value); $category = $this->categoryRepository->findByName($value);
if (null !== $category) { if (null !== $category) {
$this->collector->excludeCategory($category); $this->collector->excludeCategory($category);
@@ -647,7 +647,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!category_ends': case '-category_ends':
$result = $this->categoryRepository->categoryEndsWith($value, 1337); $result = $this->categoryRepository->categoryEndsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeCategories($result); $this->collector->excludeCategories($result);
@@ -665,7 +665,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!category_starts': case '-category_starts':
$result = $this->categoryRepository->categoryStartsWith($value, 1337); $result = $this->categoryRepository->categoryStartsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeCategories($result); $this->collector->excludeCategories($result);
@@ -683,7 +683,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!category_contains': case '-category_contains':
$result = $this->categoryRepository->searchCategory($value, 1337); $result = $this->categoryRepository->searchCategory($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeCategories($result); $this->collector->excludeCategories($result);
@@ -695,12 +695,12 @@ class OperatorQuerySearch implements SearchInterface
// //
// budgets // budgets
// //
case '!has_any_budget': case '-has_any_budget':
case 'has_no_budget': case 'has_no_budget':
$this->collector->withoutBudget(); $this->collector->withoutBudget();
break; break;
case 'has_any_budget': case 'has_any_budget':
case '!has_no_budget': case '-has_no_budget':
$this->collector->withBudget(); $this->collector->withBudget();
break; break;
case 'budget_contains': case 'budget_contains':
@@ -712,7 +712,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!budget_contains': case '-budget_contains':
$result = $this->budgetRepository->searchBudget($value, 1337); $result = $this->budgetRepository->searchBudget($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBudgets($result); $this->collector->excludeBudgets($result);
@@ -729,7 +729,7 @@ class OperatorQuerySearch implements SearchInterface
} }
$this->collector->findNothing(); $this->collector->findNothing();
break; break;
case '!budget_is': case '-budget_is':
$budget = $this->budgetRepository->findByName($value); $budget = $this->budgetRepository->findByName($value);
if (null !== $budget) { if (null !== $budget) {
$this->collector->excludeBudget($budget); $this->collector->excludeBudget($budget);
@@ -746,7 +746,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!budget_ends': case '-budget_ends':
$result = $this->budgetRepository->budgetEndsWith($value, 1337); $result = $this->budgetRepository->budgetEndsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBudgets($result); $this->collector->excludeBudgets($result);
@@ -764,7 +764,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!budget_starts': case '-budget_starts':
$result = $this->budgetRepository->budgetStartsWith($value, 1337); $result = $this->budgetRepository->budgetStartsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBudgets($result); $this->collector->excludeBudgets($result);
@@ -776,11 +776,11 @@ class OperatorQuerySearch implements SearchInterface
// //
// bill // bill
// //
case '!has_any_bill': case '-has_any_bill':
case 'has_no_bill': case 'has_no_bill':
$this->collector->withoutBill(); $this->collector->withoutBill();
break; break;
case '!has_no_bill': case '-has_no_bill':
case 'has_any_bill': case 'has_any_bill':
$this->collector->withBill(); $this->collector->withBill();
break; break;
@@ -792,7 +792,7 @@ class OperatorQuerySearch implements SearchInterface
} }
$this->collector->findNothing(); $this->collector->findNothing();
break; break;
case '!bill_contains': case '-bill_contains':
$result = $this->billRepository->searchBill($value, 1337); $result = $this->billRepository->searchBill($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBills($result); $this->collector->excludeBills($result);
@@ -808,7 +808,7 @@ class OperatorQuerySearch implements SearchInterface
} }
$this->collector->findNothing(); $this->collector->findNothing();
break; break;
case '!bill_is': case '-bill_is':
$bill = $this->billRepository->findByName($value); $bill = $this->billRepository->findByName($value);
if (null !== $bill) { if (null !== $bill) {
$this->collector->excludeBills(new Collection([$bill])); $this->collector->excludeBills(new Collection([$bill]));
@@ -825,7 +825,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!bill_ends': case '-bill_ends':
$result = $this->billRepository->billEndsWith($value, 1337); $result = $this->billRepository->billEndsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBills($result); $this->collector->excludeBills($result);
@@ -843,7 +843,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!bill_starts': case '-bill_starts':
$result = $this->billRepository->billStartsWith($value, 1337); $result = $this->billRepository->billStartsWith($value, 1337);
if ($result->count() > 0) { if ($result->count() > 0) {
$this->collector->excludeBills($result); $this->collector->excludeBills($result);
@@ -855,15 +855,15 @@ class OperatorQuerySearch implements SearchInterface
// //
// tags // tags
// //
case '!has_any_tag': case '-has_any_tag':
case 'has_no_tag': case 'has_no_tag':
$this->collector->withoutTags(); $this->collector->withoutTags();
break; break;
case '!has_no_tag': case '-has_no_tag':
case 'has_any_tag': case 'has_any_tag':
$this->collector->hasAnyTag(); $this->collector->hasAnyTag();
break; break;
case '!tag_is_not': case '-tag_is_not':
case 'tag_is': case 'tag_is':
$result = $this->tagRepository->searchTag($value); $result = $this->tagRepository->searchTag($value);
if ($result->count() > 0) { if ($result->count() > 0) {
@@ -875,7 +875,7 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->findNothing(); $this->collector->findNothing();
} }
break; break;
case '!tag_is': case '-tag_is':
case 'tag_is_not': case 'tag_is_not':
$result = $this->tagRepository->searchTag($value); $result = $this->tagRepository->searchTag($value);
if ($result->count() > 0) { if ($result->count() > 0) {
@@ -888,39 +888,39 @@ class OperatorQuerySearch implements SearchInterface
case 'notes_contains': case 'notes_contains':
$this->collector->notesContain($value); $this->collector->notesContain($value);
break; break;
case '!notes_contains': case '-notes_contains':
$this->collector->notesDoNotContain($value); $this->collector->notesDoNotContain($value);
break; break;
case 'notes_starts': case 'notes_starts':
$this->collector->notesStartWith($value); $this->collector->notesStartWith($value);
break; break;
case '!notes_starts': case '-notes_starts':
$this->collector->notesDontStartWith($value); $this->collector->notesDontStartWith($value);
break; break;
case 'notes_ends': case 'notes_ends':
$this->collector->notesEndWith($value); $this->collector->notesEndWith($value);
break; break;
case '!notes_ends': case '-notes_ends':
$this->collector->notesDontEndWith($value); $this->collector->notesDontEndWith($value);
break; break;
case 'notes_is': case 'notes_is':
$this->collector->notesExactly($value); $this->collector->notesExactly($value);
break; break;
case '!notes_is': case '-notes_is':
$this->collector->notesExactlyNot($value); $this->collector->notesExactlyNot($value);
break; break;
case '!any_notes': case '-any_notes':
case 'no_notes': case 'no_notes':
$this->collector->withoutNotes(); $this->collector->withoutNotes();
break; break;
case 'any_notes': case 'any_notes':
case '!no_notes': case '-no_notes':
$this->collector->withAnyNotes(); $this->collector->withAnyNotes();
break; break;
case 'reconciled': case 'reconciled':
$this->collector->isReconciled(); $this->collector->isReconciled();
break; break;
case '!reconciled': case '-reconciled':
$this->collector->isNotReconciled(); $this->collector->isNotReconciled();
break; break;
// //
@@ -934,7 +934,7 @@ class OperatorQuerySearch implements SearchInterface
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->amountIs($amount); $this->collector->amountIs($amount);
break; break;
case '!amount_is': case '-amount_is':
// strip comma's, make dots. // strip comma's, make dots.
Log::debug(sprintf('Original value "%s"', $value)); Log::debug(sprintf('Original value "%s"', $value));
$value = str_replace(',', '.', (string) $value); $value = str_replace(',', '.', (string) $value);
@@ -951,7 +951,7 @@ class OperatorQuerySearch implements SearchInterface
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->foreignAmountIs($amount); $this->collector->foreignAmountIs($amount);
break; break;
case '!foreign_amount_is': case '-foreign_amount_is':
// strip comma's, make dots. // strip comma's, make dots.
$value = str_replace(',', '.', (string) $value); $value = str_replace(',', '.', (string) $value);
@@ -960,7 +960,7 @@ class OperatorQuerySearch implements SearchInterface
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->foreignAmountIsNot($amount); $this->collector->foreignAmountIsNot($amount);
break; break;
case '!amount_more': case '-amount_more':
case 'amount_less': case 'amount_less':
// strip comma's, make dots. // strip comma's, make dots.
$value = str_replace(',', '.', (string) $value); $value = str_replace(',', '.', (string) $value);
@@ -969,7 +969,7 @@ class OperatorQuerySearch implements SearchInterface
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->amountLess($amount); $this->collector->amountLess($amount);
break; break;
case '!foreign_amount_more': case '-foreign_amount_more':
case 'foreign_amount_less': case 'foreign_amount_less':
// strip comma's, make dots. // strip comma's, make dots.
$value = str_replace(',', '.', (string) $value); $value = str_replace(',', '.', (string) $value);
@@ -978,7 +978,7 @@ class OperatorQuerySearch implements SearchInterface
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->foreignAmountLess($amount); $this->collector->foreignAmountLess($amount);
break; break;
case '!amount_less': case '-amount_less':
case 'amount_more': case 'amount_more':
Log::debug(sprintf('Now handling operator "%s"', $operator)); Log::debug(sprintf('Now handling operator "%s"', $operator));
// strip comma's, make dots. // strip comma's, make dots.
@@ -987,7 +987,7 @@ class OperatorQuerySearch implements SearchInterface
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $amount));
$this->collector->amountMore($amount); $this->collector->amountMore($amount);
break; break;
case '!foreign_amount_less': case '-foreign_amount_less':
case 'foreign_amount_more': case 'foreign_amount_more':
Log::debug(sprintf('Now handling operator "%s"', $operator)); Log::debug(sprintf('Now handling operator "%s"', $operator));
// strip comma's, make dots. // strip comma's, make dots.
@@ -1003,158 +1003,158 @@ class OperatorQuerySearch implements SearchInterface
$this->collector->setTypes([ucfirst($value)]); $this->collector->setTypes([ucfirst($value)]);
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
break; break;
case '!transaction_type': case '-transaction_type':
$this->collector->excludeTypes([ucfirst($value)]); $this->collector->excludeTypes([ucfirst($value)]);
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
break; break;
// //
// dates // dates
// //
case '!date_on': case '-date_on':
case 'date_on': case 'date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setExactDateParams($range, $prohibited); $this->setExactDateParams($range, $prohibited);
return false; return false;
case 'date_before': case 'date_before':
case '!date_after': case '-date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setDateBeforeParams($range); $this->setDateBeforeParams($range);
return false; return false;
case 'date_after': case 'date_after':
case '!date_before': case '-date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setDateAfterParams($range); $this->setDateAfterParams($range);
return false; return false;
case 'interest_date_on': case 'interest_date_on':
case '!interest_date_on': case '-interest_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setExactMetaDateParams('interest_date', $range, $prohibited); $this->setExactMetaDateParams('interest_date', $range, $prohibited);
return false; return false;
case 'interest_date_before': case 'interest_date_before':
case '!interest_date_after': case '-interest_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateBeforeParams('interest_date', $range); $this->setMetaDateBeforeParams('interest_date', $range);
return false; return false;
case 'interest_date_after': case 'interest_date_after':
case '!interest_date_before': case '-interest_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateAfterParams('interest_date', $range); $this->setMetaDateAfterParams('interest_date', $range);
return false; return false;
case 'book_date_on': case 'book_date_on':
case '!book_date_on': case '-book_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setExactMetaDateParams('book_date', $range, $prohibited); $this->setExactMetaDateParams('book_date', $range, $prohibited);
return false; return false;
case 'book_date_before': case 'book_date_before':
case '!book_date_after': case '-book_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateBeforeParams('book_date', $range); $this->setMetaDateBeforeParams('book_date', $range);
return false; return false;
case 'book_date_after': case 'book_date_after':
case '!book_date_before': case '-book_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateAfterParams('book_date', $range); $this->setMetaDateAfterParams('book_date', $range);
return false; return false;
case 'process_date_on': case 'process_date_on':
case '!process_date_on': case '-process_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setExactMetaDateParams('process_date', $range, $prohibited); $this->setExactMetaDateParams('process_date', $range, $prohibited);
return false; return false;
case 'process_date_before': case 'process_date_before':
case '!process_date_after': case '-process_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateBeforeParams('process_date', $range); $this->setMetaDateBeforeParams('process_date', $range);
return false; return false;
case 'process_date_after': case 'process_date_after':
case '!process_date_before': case '-process_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateAfterParams('process_date', $range); $this->setMetaDateAfterParams('process_date', $range);
return false; return false;
case 'due_date_on': case 'due_date_on':
case '!due_date_on': case '-due_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setExactMetaDateParams('due_date', $range, $prohibited); $this->setExactMetaDateParams('due_date', $range, $prohibited);
return false; return false;
case 'due_date_before': case 'due_date_before':
case '!due_date_after': case '-due_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateBeforeParams('due_date', $range); $this->setMetaDateBeforeParams('due_date', $range);
return false; return false;
case 'due_date_after': case 'due_date_after':
case '!due_date_before': case '-due_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateAfterParams('due_date', $range); $this->setMetaDateAfterParams('due_date', $range);
return false; return false;
case 'payment_date_on': case 'payment_date_on':
case '!payment_date_on': case '-payment_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setExactMetaDateParams('payment_date', $range, $prohibited); $this->setExactMetaDateParams('payment_date', $range, $prohibited);
return false; return false;
case 'payment_date_before': case 'payment_date_before':
case '!payment_date_after': case '-payment_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateBeforeParams('payment_date', $range); $this->setMetaDateBeforeParams('payment_date', $range);
return false; return false;
case 'payment_date_after': case 'payment_date_after':
case '!payment_date_before': case '-payment_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateAfterParams('payment_date', $range); $this->setMetaDateAfterParams('payment_date', $range);
return false; return false;
case 'invoice_date_on': case 'invoice_date_on':
case '!invoice_date_on': case '-invoice_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setExactMetaDateParams('invoice_date', $range, $prohibited); $this->setExactMetaDateParams('invoice_date', $range, $prohibited);
return false; return false;
case 'invoice_date_before': case 'invoice_date_before':
case '!invoice_date_after': case '-invoice_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateBeforeParams('invoice_date', $range); $this->setMetaDateBeforeParams('invoice_date', $range);
return false; return false;
case 'invoice_date_after': case 'invoice_date_after':
case '!invoice_date_before': case '-invoice_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setMetaDateAfterParams('invoice_date', $range); $this->setMetaDateAfterParams('invoice_date', $range);
return false; return false;
case 'created_at_on': case 'created_at_on':
case '!created_at_on': case '-created_at_on':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setExactObjectDateParams('created_at', $range, $prohibited); $this->setExactObjectDateParams('created_at', $range, $prohibited);
return false; return false;
case 'created_at_before': case 'created_at_before':
case '!created_at_after': case '-created_at_after':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setObjectDateBeforeParams('created_at', $range); $this->setObjectDateBeforeParams('created_at', $range);
return false; return false;
case 'created_at_after': case 'created_at_after':
case '!created_at_before': case '-created_at_before':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setObjectDateAfterParams('created_at', $range); $this->setObjectDateAfterParams('created_at', $range);
return false; return false;
case 'updated_at_on': case 'updated_at_on':
case '!updated_at_on': case '-updated_at_on':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setExactObjectDateParams('updated_at', $range, $prohibited); $this->setExactObjectDateParams('updated_at', $range, $prohibited);
return false; return false;
case 'updated_at_before': case 'updated_at_before':
case '!updated_at_after': case '-updated_at_after':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setObjectDateBeforeParams('updated_at', $range); $this->setObjectDateBeforeParams('updated_at', $range);
return false; return false;
case 'updated_at_after': case 'updated_at_after':
case '!updated_at_before': case '-updated_at_before':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($value);
$this->setObjectDateAfterParams('updated_at', $range); $this->setObjectDateAfterParams('updated_at', $range);
@@ -1162,87 +1162,154 @@ class OperatorQuerySearch implements SearchInterface
// //
// external URL // external URL
// //
case '!any_external_url': case '-any_external_url':
case 'no_external_url': case 'no_external_url':
$this->collector->withoutExternalUrl(); $this->collector->withoutExternalUrl();
break; break;
case '!no_external_url': case '-no_external_url':
case 'any_external_url': case 'any_external_url':
$this->collector->withExternalUrl(); $this->collector->withExternalUrl();
break; break;
case 'external_url_is': case 'external_url_is':
$this->collector->setExternalUrl($value); $this->collector->setExternalUrl($value);
break; break;
case '-external_url_is':
$this->collector->excludeExternalUrl($value);
break;
case 'external_url_contains': case 'external_url_contains':
$this->collector->externalUrlContains($value); $this->collector->externalUrlContains($value);
break; break;
case '-external_url_contains':
$this->collector->externalUrlDoesNotContain($value);
break;
case 'external_url_starts': case 'external_url_starts':
$this->collector->externalUrlStarts($value); $this->collector->externalUrlStarts($value);
break; break;
case '-external_url_starts':
$this->collector->externalUrlDoesNotStart($value);
break;
case 'external_url_ends': case 'external_url_ends':
$this->collector->externalUrlEnds($value); $this->collector->externalUrlEnds($value);
break; break;
case '-external_url_ends':
$this->collector->externalUrlDoesNotEnd($value);
break;
// //
// other fields // other fields
// //
case 'external_id_is': case 'external_id_is':
$this->collector->setExternalId($value); $this->collector->setExternalId($value);
break; break;
case '-external_id_is':
$this->collector->excludeExternalId($value);
break;
case 'recurrence_id': case 'recurrence_id':
$this->collector->setRecurrenceId($value); $this->collector->setRecurrenceId($value);
break; break;
case '-recurrence_id':
$this->collector->excludeRecurrenceId($value);
break;
case 'external_id_contains': case 'external_id_contains':
$this->collector->externalIdContains($value); $this->collector->externalIdContains($value);
break; break;
case '-external_id_contains':
$this->collector->externalIdDoesNotContain($value);
break;
case 'external_id_starts': case 'external_id_starts':
$this->collector->externalIdStarts($value); $this->collector->externalIdStarts($value);
break; break;
case '-external_id_starts':
$this->collector->externalIdDoesNotStart($value);
break;
case 'external_id_ends': case 'external_id_ends':
$this->collector->externalIdEnds($value); $this->collector->externalIdEnds($value);
break; break;
case '-external_id_ends':
$this->collector->externalIdDoesNotEnd($value);
break;
case 'internal_reference_is': case 'internal_reference_is':
$this->collector->setInternalReference($value); $this->collector->setInternalReference($value);
break; break;
case '-internal_reference_is':
$this->collector->excludeInternalReference($value);
break;
case 'internal_reference_contains': case 'internal_reference_contains':
$this->collector->internalReferenceContains($value); $this->collector->internalReferenceContains($value);
break; break;
case '-internal_reference_contains':
$this->collector->internalReferenceDoesNotContain($value);
break;
case 'internal_reference_starts': case 'internal_reference_starts':
$this->collector->internalReferenceStarts($value); $this->collector->internalReferenceStarts($value);
break; break;
case '-internal_reference_starts':
$this->collector->internalReferenceDoesNotStart($value);
break;
case 'internal_reference_ends': case 'internal_reference_ends':
$this->collector->internalReferenceEnds($value); $this->collector->internalReferenceEnds($value);
break; break;
case '-internal_reference_ends':
$this->collector->internalReferenceDoesNotEnd($value);
break;
case 'attachment_name_is': case 'attachment_name_is':
$this->collector->attachmentNameIs($value); $this->collector->attachmentNameIs($value);
break; break;
case '-attachment_name_is':
$this->collector->attachmentNameIsNot($value);
break;
case 'attachment_name_contains': case 'attachment_name_contains':
$this->collector->attachmentNameContains($value); $this->collector->attachmentNameContains($value);
break; break;
case '-attachment_name_contains':
$this->collector->attachmentNameDoesNotContain($value);
break;
case 'attachment_name_starts': case 'attachment_name_starts':
$this->collector->attachmentNameStarts($value); $this->collector->attachmentNameStarts($value);
break; break;
case '-attachment_name_starts':
$this->collector->attachmentNameDoesNotStart($value);
break;
case 'attachment_name_ends': case 'attachment_name_ends':
$this->collector->attachmentNameEnds($value); $this->collector->attachmentNameEnds($value);
break; break;
case '-attachment_name_ends':
$this->collector->attachmentNameDoesNotEnd($value);
break;
case 'attachment_notes_are': case 'attachment_notes_are':
$this->collector->attachmentNotesAre($value); $this->collector->attachmentNotesAre($value);
break; break;
case '-attachment_notes_are':
$this->collector->attachmentNotesAreNot($value);
break;
case 'attachment_notes_contains': case 'attachment_notes_contains':
$this->collector->attachmentNotesContains($value); $this->collector->attachmentNotesContains($value);
break; break;
case '-attachment_notes_contains':
$this->collector->attachmentNotesDoNotContain($value);
break;
case 'attachment_notes_starts': case 'attachment_notes_starts':
$this->collector->attachmentNotesStarts($value); $this->collector->attachmentNotesStarts($value);
break; break;
case '-attachment_notes_starts':
$this->collector->attachmentNotesDoNotStart($value);
break;
case 'attachment_notes_ends': case 'attachment_notes_ends':
$this->collector->attachmentNotesEnds($value); $this->collector->attachmentNotesEnds($value);
break; break;
case '-attachment_notes_ends':
$this->collector->attachmentNotesDoNotEnd($value);
break;
case 'exists': case 'exists':
$this->collector->exists(); $this->collector->exists();
break; break;
case '-exists':
$this->collector->findNothing();
break;
} }
return true; return true;
@@ -1257,9 +1324,9 @@ class OperatorQuerySearch implements SearchInterface
public static function getRootOperator(string $operator): string public static function getRootOperator(string $operator): string
{ {
$original = $operator; $original = $operator;
// if the string starts with "!" (not), we can remove it and recycle // if the string starts with "-" (not), we can remove it and recycle
// the configuration from the original operator. // the configuration from the original operator.
if (str_starts_with($operator, '!')) { if (str_starts_with($operator, '-')) {
$operator = substr($operator, 1); $operator = substr($operator, 1);
} }
@@ -1269,8 +1336,8 @@ class OperatorQuerySearch implements SearchInterface
} }
if (true === $config['alias']) { if (true === $config['alias']) {
$return = $config['alias_for']; $return = $config['alias_for'];
if (str_starts_with($original, '!')) { if (str_starts_with($original, '-')) {
$return = sprintf('!%s', $config['alias_for']); $return = sprintf('-%s', $config['alias_for']);
} }
Log::debug(sprintf('"%s" is an alias for "%s", so return that instead.', $original, $return)); Log::debug(sprintf('"%s" is an alias for "%s", so return that instead.', $original, $return));
@@ -1423,7 +1490,7 @@ class OperatorQuerySearch implements SearchInterface
Log::debug(sprintf('Found %d accounts, will filter.', $accounts->count())); Log::debug(sprintf('Found %d accounts, will filter.', $accounts->count()));
$filtered = $accounts->filter( $filtered = $accounts->filter(
function (Account $account) use ($value, $stringMethod) { function (Account $account) use ($value, $stringMethod) {
// either IBAN or account number! // either IBAN or account number
$ibanMatch = $stringMethod(strtolower((string) $account->iban), strtolower((string) $value)); $ibanMatch = $stringMethod(strtolower((string) $account->iban), strtolower((string) $value));
$accountNrMatch = false; $accountNrMatch = false;
/** @var AccountMeta $meta */ /** @var AccountMeta $meta */

View File

@@ -421,7 +421,8 @@ class General extends AbstractExtension
return new TwigFunction( return new TwigFunction(
'getRootSearchOperator', 'getRootSearchOperator',
static function (string $operator): string { static function (string $operator): string {
return OperatorQuerySearch::getRootOperator($operator); $result = OperatorQuerySearch::getRootOperator($operator);
return str_replace('-', 'not_', $result);
} }
); );
} }

View File

@@ -327,14 +327,17 @@ return [
'search_modifier_reconciled' => 'Transaction is reconciled', 'search_modifier_reconciled' => 'Transaction is reconciled',
'search_modifier_not_reconciled' => 'Transaction is not reconciled', 'search_modifier_not_reconciled' => 'Transaction is not reconciled',
'search_modifier_id' => 'Transaction ID is ":value"', 'search_modifier_id' => 'Transaction ID is ":value"',
'search_modifier_not_id' => 'Transaction ID is not ":value"',
'search_modifier_date_before' => 'Transaction date is before or on ":value"', 'search_modifier_date_before' => 'Transaction date is before or on ":value"',
'search_modifier_date_after' => 'Transaction date is after or on ":value"', 'search_modifier_date_after' => 'Transaction date is after or on ":value"',
'search_modifier_external_id_is' => 'External ID is ":value"', 'search_modifier_external_id_is' => 'External ID is ":value"',
'search_modifier_not_external_id_is' => 'External ID is not ":value"',
'search_modifier_no_external_url' => 'The transaction has no external URL', 'search_modifier_no_external_url' => 'The transaction has no external URL',
'search_modifier_not_any_external_url' => 'The transaction has no external URL', 'search_modifier_not_any_external_url' => 'The transaction has no external URL',
'search_modifier_any_external_url' => 'The transaction must have a (any) external URL', 'search_modifier_any_external_url' => 'The transaction must have a (any) external URL',
'search_modifier_not_no_external_url' => 'The transaction must have a (any) external URL', 'search_modifier_not_no_external_url' => 'The transaction must have a (any) external URL',
'search_modifier_internal_reference_is' => 'Internal reference is ":value"', 'search_modifier_internal_reference_is' => 'Internal reference is ":value"',
'search_modifier_not_internal_reference_is' => 'Internal reference is not ":value"',
'search_modifier_description_starts' => 'Description starts with ":value"', 'search_modifier_description_starts' => 'Description starts with ":value"',
'search_modifier_not_description_starts' => 'Description does not start with ":value"', 'search_modifier_not_description_starts' => 'Description does not start with ":value"',
'search_modifier_description_ends' => 'Description ends on ":value"', 'search_modifier_description_ends' => 'Description ends on ":value"',
@@ -395,6 +398,7 @@ return [
'search_modifier_source_account_nr_is' => 'Source account number (IBAN) is ":value"', 'search_modifier_source_account_nr_is' => 'Source account number (IBAN) is ":value"',
'search_modifier_not_source_account_nr_is' => 'Source account number (IBAN) is not ":value"', 'search_modifier_not_source_account_nr_is' => 'Source account number (IBAN) is not ":value"',
'search_modifier_source_account_nr_contains' => 'Source account number (IBAN) contains ":value"', 'search_modifier_source_account_nr_contains' => 'Source account number (IBAN) contains ":value"',
'search_modifier_not_source_account_nr_contains' => 'Source account number (IBAN) does not contain ":value"',
'search_modifier_source_account_nr_starts' => 'Source account number (IBAN) starts with ":value"', 'search_modifier_source_account_nr_starts' => 'Source account number (IBAN) starts with ":value"',
'search_modifier_not_source_account_nr_starts' => 'Source account number (IBAN) does not start with ":value"', 'search_modifier_not_source_account_nr_starts' => 'Source account number (IBAN) does not start with ":value"',
'search_modifier_source_account_nr_ends' => 'Source account number (IBAN) ends on ":value"', 'search_modifier_source_account_nr_ends' => 'Source account number (IBAN) ends on ":value"',
@@ -414,6 +418,7 @@ return [
'search_modifier_source_is_cash' => 'Source account is the "(cash)" account', 'search_modifier_source_is_cash' => 'Source account is the "(cash)" account',
'search_modifier_not_source_is_cash' => 'Source account is not the "(cash)" account', 'search_modifier_not_source_is_cash' => 'Source account is not the "(cash)" account',
'search_modifier_destination_account_nr_is' => 'Destination account number (IBAN) is ":value"', 'search_modifier_destination_account_nr_is' => 'Destination account number (IBAN) is ":value"',
'search_modifier_not_destination_account_nr_is' => 'Destination account number (IBAN) is ":value"',
'search_modifier_destination_account_nr_contains' => 'Destination account number (IBAN) contains ":value"', 'search_modifier_destination_account_nr_contains' => 'Destination account number (IBAN) contains ":value"',
'search_modifier_not_destination_account_nr_contains' => 'Destination account number (IBAN) does not contain ":value"', 'search_modifier_not_destination_account_nr_contains' => 'Destination account number (IBAN) does not contain ":value"',
'search_modifier_destination_account_nr_starts' => 'Destination account number (IBAN) starts with ":value"', 'search_modifier_destination_account_nr_starts' => 'Destination account number (IBAN) starts with ":value"',
@@ -429,6 +434,7 @@ return [
'search_modifier_bill_is' => 'Bill is ":value"', 'search_modifier_bill_is' => 'Bill is ":value"',
'search_modifier_not_bill_is' => 'Bill is not ":value"', 'search_modifier_not_bill_is' => 'Bill is not ":value"',
'search_modifier_transaction_type' => 'Transaction type is ":value"', 'search_modifier_transaction_type' => 'Transaction type is ":value"',
'search_modifier_not_transaction_type' => 'Transaction type is not ":value"',
'search_modifier_tag_is' => 'Tag is ":value"', 'search_modifier_tag_is' => 'Tag is ":value"',
'search_modifier_not_tag_is' => 'No tag is ":value"', 'search_modifier_not_tag_is' => 'No tag is ":value"',
'search_modifier_date_on_year' => 'Transaction is in year ":value"', 'search_modifier_date_on_year' => 'Transaction is in year ":value"',
@@ -469,6 +475,7 @@ return [
'search_modifier_category_ends' => 'Category ends on ":value"', 'search_modifier_category_ends' => 'Category ends on ":value"',
'search_modifier_not_category_ends' => 'Category does not end on ":value"', 'search_modifier_not_category_ends' => 'Category does not end on ":value"',
'search_modifier_category_starts' => 'Category starts with ":value"', 'search_modifier_category_starts' => 'Category starts with ":value"',
'search_modifier_not_category_starts' => 'Category does not start with ":value"',
'search_modifier_budget_contains' => 'Budget contains ":value"', 'search_modifier_budget_contains' => 'Budget contains ":value"',
'search_modifier_not_budget_contains' => 'Budget does not contain ":value"', 'search_modifier_not_budget_contains' => 'Budget does not contain ":value"',
'search_modifier_budget_ends' => 'Budget ends with ":value"', 'search_modifier_budget_ends' => 'Budget ends with ":value"',
@@ -482,15 +489,25 @@ return [
'search_modifier_bill_starts' => 'Bill starts with ":value"', 'search_modifier_bill_starts' => 'Bill starts with ":value"',
'search_modifier_not_bill_starts' => 'Bill does not start with ":value"', 'search_modifier_not_bill_starts' => 'Bill does not start with ":value"',
'search_modifier_external_id_contains' => 'External ID contains ":value"', 'search_modifier_external_id_contains' => 'External ID contains ":value"',
'search_modifier_not_external_id_contains' => 'External ID does not contain ":value"',
'search_modifier_external_id_ends' => 'External ID ends with ":value"', 'search_modifier_external_id_ends' => 'External ID ends with ":value"',
'search_modifier_not_external_id_ends' => 'External ID does not end with ":value"',
'search_modifier_external_id_starts' => 'External ID starts with ":value"', 'search_modifier_external_id_starts' => 'External ID starts with ":value"',
'search_modifier_not_external_id_starts' => 'External ID does not start with ":value"',
'search_modifier_internal_reference_contains' => 'Internal reference contains ":value"', 'search_modifier_internal_reference_contains' => 'Internal reference contains ":value"',
'search_modifier_not_internal_reference_contains' => 'Internal reference does not contain ":value"',
'search_modifier_internal_reference_ends' => 'Internal reference ends with ":value"', 'search_modifier_internal_reference_ends' => 'Internal reference ends with ":value"',
'search_modifier_internal_reference_starts' => 'Internal reference starts with ":value"', 'search_modifier_internal_reference_starts' => 'Internal reference starts with ":value"',
'search_modifier_not_internal_reference_ends' => 'Internal reference does not end with ":value"',
'search_modifier_not_internal_reference_starts' => 'Internal reference does not start with ":value"',
'search_modifier_external_url_is' => 'External URL is ":value"', 'search_modifier_external_url_is' => 'External URL is ":value"',
'search_modifier_not_external_url_is' => 'External URL is not ":value"',
'search_modifier_external_url_contains' => 'External URL contains ":value"', 'search_modifier_external_url_contains' => 'External URL contains ":value"',
'search_modifier_not_external_url_contains' => 'External URL does not ":value"',
'search_modifier_external_url_ends' => 'External URL ends with ":value"', 'search_modifier_external_url_ends' => 'External URL ends with ":value"',
'search_modifier_not_external_url_ends' => 'External URL does not end with ":value"',
'search_modifier_external_url_starts' => 'External URL starts with ":value"', 'search_modifier_external_url_starts' => 'External URL starts with ":value"',
'search_modifier_not_external_url_starts' => 'External URL does not start with ":value"',
'search_modifier_has_no_attachments' => 'Transaction has no attachments', 'search_modifier_has_no_attachments' => 'Transaction has no attachments',
'search_modifier_not_has_no_attachments' => 'Transaction has attachments', 'search_modifier_not_has_no_attachments' => 'Transaction has attachments',
'search_modifier_not_has_attachments' => 'Transaction has no attachments', 'search_modifier_not_has_attachments' => 'Transaction has no attachments',
@@ -499,12 +516,15 @@ return [
'search_modifier_journal_id' => 'The journal ID is ":value"', 'search_modifier_journal_id' => 'The journal ID is ":value"',
'search_modifier_not_journal_id' => 'The journal ID is not ":value"', 'search_modifier_not_journal_id' => 'The journal ID is not ":value"',
'search_modifier_recurrence_id' => 'The recurring transaction ID is ":value"', 'search_modifier_recurrence_id' => 'The recurring transaction ID is ":value"',
'search_modifier_not_recurrence_id' => 'The recurring transaction ID is not ":value"',
'search_modifier_foreign_amount_is' => 'The foreign amount is ":value"', 'search_modifier_foreign_amount_is' => 'The foreign amount is ":value"',
'search_modifier_not_foreign_amount_is' => 'The foreign amount is not ":value"',
'search_modifier_foreign_amount_less' => 'The foreign amount is less than ":value"', 'search_modifier_foreign_amount_less' => 'The foreign amount is less than ":value"',
'search_modifier_not_foreign_amount_more' => 'The foreign amount is less than ":value"', 'search_modifier_not_foreign_amount_more' => 'The foreign amount is less than ":value"',
'search_modifier_not_foreign_amount_less' => 'The foreign amount is more than ":value"', 'search_modifier_not_foreign_amount_less' => 'The foreign amount is more than ":value"',
'search_modifier_foreign_amount_more' => 'The foreign amount is more than ":value"', 'search_modifier_foreign_amount_more' => 'The foreign amount is more than ":value"',
'search_modifier_exists' => 'Transaction exists (any transaction)', 'search_modifier_exists' => 'Transaction exists (any transaction)',
'search_modifier_not_exists' => 'Transaction does not exist (no transaction)',
// date fields // date fields
'search_modifier_interest_date_on' => 'Transaction interest date is ":value"', 'search_modifier_interest_date_on' => 'Transaction interest date is ":value"',
@@ -644,7 +664,15 @@ return [
'search_modifier_attachment_notes_are' => 'Any attachment\'s notes are ":value"', 'search_modifier_attachment_notes_are' => 'Any attachment\'s notes are ":value"',
'search_modifier_attachment_notes_contains' => 'Any attachment\'s notes contain ":value"', 'search_modifier_attachment_notes_contains' => 'Any attachment\'s notes contain ":value"',
'search_modifier_attachment_notes_starts' => 'Any attachment\'s notes start with ":value"', 'search_modifier_attachment_notes_starts' => 'Any attachment\'s notes start with ":value"',
'search_modifier_attachment_notes_ends' => 'Any attachment\'s notes end is ":value"', 'search_modifier_attachment_notes_ends' => 'Any attachment\'s notes end with ":value"',
'search_modifier_not_attachment_name_is' => 'Any attachment\'s name is not ":value"',
'search_modifier_not_attachment_name_contains' => 'Any attachment\'s name does not contain ":value"',
'search_modifier_not_attachment_name_starts' => 'Any attachment\'s name does not start with ":value"',
'search_modifier_not_attachment_name_ends' => 'Any attachment\'s name does not end with ":value"',
'search_modifier_not_attachment_notes_are' => 'Any attachment\'s notes are not ":value"',
'search_modifier_not_attachment_notes_contains' => 'Any attachment\'s notes do not contain ":value"',
'search_modifier_not_attachment_notes_starts' => 'Any attachment\'s notes start with ":value"',
'search_modifier_not_attachment_notes_ends' => 'Any attachment\'s notes do not end with ":value"',
'update_rule_from_query' => 'Update rule ":rule" from search query', 'update_rule_from_query' => 'Update rule ":rule" from search query',
'create_rule_from_query' => 'Create new rule from search query', 'create_rule_from_query' => 'Create new rule from search query',
'rule_from_search_words' => 'The rule engine has a hard time handling ":string". The suggested rule that fits your search query may give different results. Please verify the rule triggers carefully.', 'rule_from_search_words' => 'The rule engine has a hard time handling ":string". The suggested rule that fits your search query may give different results. Please verify the rule triggers carefully.',
@@ -1001,6 +1029,136 @@ return [
'rule_trigger_exists_choice' => 'Any transaction matches(!)', 'rule_trigger_exists_choice' => 'Any transaction matches(!)',
'rule_trigger_exists' => 'Any transaction matches', 'rule_trigger_exists' => 'Any transaction matches',
// more values for new types:
'rule_trigger_not_account_id' => 'Account ID is not ":trigger_value"',
'rule_trigger_not_source_account_id' => 'Source account ID is not ":trigger_value"',
'rule_trigger_not_destination_account_id' => 'Destination account ID is not ":trigger_value"',
'rule_trigger_not_transaction_type' => 'Transaction type is not ":trigger_value"',
'rule_trigger_not_tag_is' => 'Tag is not ":trigger_value"',
'rule_trigger_not_tag_is_not' => 'Tag is ":trigger_value"',
'rule_trigger_not_description_is' => 'Description is not ":trigger_value"',
'rule_trigger_not_description_contains' => 'Description does not contain',
'rule_trigger_not_description_ends' => 'Description does not end with ":trigger_value"',
'rule_trigger_not_description_starts' => 'Description does not start with ":trigger_value"',
'rule_trigger_not_notes_is' => 'Notes are not ":trigger_value"',
'rule_trigger_not_notes_contains' => 'Notes do not contain ":trigger_value"',
'rule_trigger_not_notes_ends' => 'Notes do not end on ":trigger_value"',
'rule_trigger_not_notes_starts' => 'Notes do not start with ":trigger_value"',
'rule_trigger_not_source_account_is' => 'Source account is not ":trigger_value"',
'rule_trigger_not_source_account_contains' => 'Source account does not contain ":trigger_value"',
'rule_trigger_not_source_account_ends' => 'Source account does not end on ":trigger_value"',
'rule_trigger_not_source_account_starts' => 'Source account does not start with ":trigger_value"',
'rule_trigger_not_source_account_nr_is' => 'Source account number / IBAN is not ":trigger_value"',
'rule_trigger_not_source_account_nr_contains' => 'Source account number / IBAN does not contain ":trigger_value"',
'rule_trigger_not_source_account_nr_ends' => 'Source account number / IBAN does not end on ":trigger_value"',
'rule_trigger_not_source_account_nr_starts' => 'Source account number / IBAN does not start with ":trigger_value"',
'rule_trigger_not_destination_account_is' => 'Destination account is not ":trigger_value"',
'rule_trigger_not_destination_account_contains' => 'Destination account does not contain ":trigger_value"',
'rule_trigger_not_destination_account_ends' => 'Destination account does not end on ":trigger_value"',
'rule_trigger_not_destination_account_starts' => 'Destination account does not start with ":trigger_value"',
'rule_trigger_not_destination_account_nr_is' => 'Destination account number / IBAN is not ":trigger_value"',
'rule_trigger_not_destination_account_nr_contains' => 'Destination account number / IBAN does not contain ":trigger_value"',
'rule_trigger_not_destination_account_nr_ends' => 'Destination account number / IBAN does not end on ":trigger_value"',
'rule_trigger_not_destination_account_nr_starts' => 'Destination account number / IBAN does not start with ":trigger_value"',
'rule_trigger_not_account_is' => 'Neither account is ":trigger_value"',
'rule_trigger_not_account_contains' => 'Neither account contains ":trigger_value"',
'rule_trigger_not_account_ends' => 'Neither account ends on ":trigger_value"',
'rule_trigger_not_account_starts' => 'Neither account starts with ":trigger_value"',
'rule_trigger_not_account_nr_is' => 'Neither account number / IBAN is ":trigger_value"',
'rule_trigger_not_account_nr_contains' => 'Neither account number / IBAN contains ":trigger_value"',
'rule_trigger_not_account_nr_ends' => 'Neither account number / IBAN ends on ":trigger_value"',
'rule_trigger_not_account_nr_starts' => 'Neither account number / IBAN starts with ":trigger_value"',
'rule_trigger_not_category_is' => 'Neither category is ":trigger_value"',
'rule_trigger_not_category_contains' => 'Neither category contains ":trigger_value"',
'rule_trigger_not_category_ends' => 'Neither category ends on ":trigger_value"',
'rule_trigger_not_category_starts' => 'Neither category starts with ":trigger_value"',
'rule_trigger_not_budget_is' => 'Neither budget is ":trigger_value"',
'rule_trigger_not_budget_contains' => 'Neither budget contains ":trigger_value"',
'rule_trigger_not_budget_ends' => 'Neither budget ends on ":trigger_value"',
'rule_trigger_not_budget_starts' => 'Neither budget starts with ":trigger_value"',
'rule_trigger_not_bill_is' => 'Neither bill is ":trigger_value"',
'rule_trigger_not_bill_contains' => 'Neither bill contains ":trigger_value"',
'rule_trigger_not_bill_ends' => 'Neither bill ends on ":trigger_value"',
'rule_trigger_not_bill_starts' => 'Neither bill starts with ":trigger_value"',
'rule_trigger_not_external_id_is' => 'External ID is not ":trigger_value"',
'rule_trigger_not_external_id_contains' => 'External ID does not contain ":trigger_value"',
'rule_trigger_not_external_id_ends' => 'External ID does not end on ":trigger_value"',
'rule_trigger_not_external_id_starts' => 'External ID does not start with ":trigger_value"',
'rule_trigger_not_internal_reference_is' => 'Internal reference is not ":trigger_value"',
'rule_trigger_not_internal_reference_contains' => 'Internal reference does not contain ":trigger_value"',
'rule_trigger_not_internal_reference_ends' => 'Internal reference does not end on ":trigger_value"',
'rule_trigger_not_internal_reference_starts' => 'Internal reference does not start with ":trigger_value"',
'rule_trigger_not_external_url_is' => 'External URL is not ":trigger_value"',
'rule_trigger_not_external_url_contains' => 'External URL does not contain ":trigger_value"',
'rule_trigger_not_external_url_ends' => 'External URL does not end on ":trigger_value"',
'rule_trigger_not_external_url_starts' => 'External URL does not start with ":trigger_value"',
'rule_trigger_not_currency_is' => 'Currency is not ":trigger_value"',
'rule_trigger_not_foreign_currency_is' => 'Foreign currency is not ":trigger_value"',
'rule_trigger_not_id' => 'Transaction ID is not ":trigger_value"',
'rule_trigger_not_journal_id' => 'Transaction journal ID is not ":trigger_value"',
'rule_trigger_not_recurrence_id' => 'Recurrence ID is not ":trigger_value"',
'rule_trigger_not_date_on' => 'Date is not on ":trigger_value"',
'rule_trigger_not_date_before' => 'Date is not before ":trigger_value"',
'rule_trigger_not_date_after' => 'Date is not after ":trigger_value"',
'rule_trigger_not_interest_date_on' => 'Interest date is not on ":trigger_value"',
'rule_trigger_not_interest_date_before' => 'Interest date is not before ":trigger_value"',
'rule_trigger_not_interest_date_after' => 'Interest date is not after ":trigger_value"',
'rule_trigger_not_book_date_on' => 'Book date is not on ":trigger_value"',
'rule_trigger_not_book_date_before' => 'Book date is not before ":trigger_value"',
'rule_trigger_not_book_date_after' => 'Book date is not after ":trigger_value"',
'rule_trigger_not_process_date_on' => 'Process date is not on ":trigger_value"',
'rule_trigger_not_process_date_before' => 'Process date is not before ":trigger_value"',
'rule_trigger_not_process_date_after' => 'Process date is not after ":trigger_value"',
'rule_trigger_not_due_date_on' => 'Due date is not on ":trigger_value"',
'rule_trigger_not_due_date_before' => 'Due date is not before ":trigger_value"',
'rule_trigger_not_due_date_after' => 'Due date is not after ":trigger_value"',
'rule_trigger_not_payment_date_on' => 'Payment date is not on ":trigger_value"',
'rule_trigger_not_payment_date_before' => 'Payment date is not before ":trigger_value"',
'rule_trigger_not_payment_date_after' => 'Payment date is not after ":trigger_value"',
'rule_trigger_not_invoice_date_on' => 'Invoice date is not on ":trigger_value"',
'rule_trigger_not_invoice_date_before' => 'Invoice date is not before ":trigger_value"',
'rule_trigger_not_invoice_date_after' => 'Invoice date is not after ":trigger_value"',
'rule_trigger_not_created_at_on' => 'Transaction is not created on ":trigger_value"',
'rule_trigger_not_created_at_before' => 'Transaction is not created before ":trigger_value"',
'rule_trigger_not_created_at_after' => 'Transaction is not created after ":trigger_value"',
'rule_trigger_not_updated_at_on' => 'Transaction is not updated on ":trigger_value"',
'rule_trigger_not_updated_at_before' => 'Transaction is not updated before ":trigger_value"',
'rule_trigger_not_updated_at_after' => 'Transaction is not updated after ":trigger_value"',
'rule_trigger_not_amount_is' => 'Transaction amount is not ":trigger_value"',
'rule_trigger_not_amount_less' => 'Transaction amount is more than ":trigger_value"',
'rule_trigger_not_amount_more' => 'Transaction amount is less than ":trigger_value"',
'rule_trigger_not_foreign_amount_is' => 'Foreign transaction amount is not ":trigger_value"',
'rule_trigger_not_foreign_amount_less' => 'Foreign transaction amount is more than ":trigger_value"',
'rule_trigger_not_foreign_amount_more' => 'Foreign transaction amount is less than ":trigger_value"',
'rule_trigger_not_attachment_name_is' => 'No attachment is named ":trigger_value"',
'rule_trigger_not_attachment_name_contains' => 'No attachment name contains ":trigger_value"',
'rule_trigger_not_attachment_name_starts' => 'No attachment name starts with ":trigger_value"',
'rule_trigger_not_attachment_name_ends' => 'No attachment name ends on ":trigger_value"',
'rule_trigger_not_attachment_notes_are' => 'No attachment notes are ":trigger_value"',
'rule_trigger_not_attachment_notes_contains' => 'No attachment notes contain ":trigger_value"',
'rule_trigger_not_attachment_notes_starts' => 'No attachment notes start with ":trigger_value"',
'rule_trigger_not_attachment_notes_ends' => 'No attachment notes end on ":trigger_value"',
'rule_trigger_not_reconciled' => 'Transaction is not reconciled',
'rule_trigger_not_exists' => 'Transaction does not exist',
'rule_trigger_not_has_attachments' => 'Transaction has no attachments',
'rule_trigger_not_has_any_category' => 'Transaction has no category',
'rule_trigger_not_has_any_budget' => 'Transaction has no category',
'rule_trigger_not_has_any_bill' => 'Transaction has no bill',
'rule_trigger_not_has_any_tag' => 'Transaction has no tags',
'rule_trigger_not_any_notes' => 'Transaction has no notes',
'rule_trigger_not_any_external_url' => 'Transaction has no external URL',
'rule_trigger_not_has_no_attachments' => 'Transaction has a (any) attachment(s)',
'rule_trigger_not_has_no_category' => 'Transaction has a (any) category',
'rule_trigger_not_has_no_budget' => 'Transaction has a (any) budget',
'rule_trigger_not_has_no_bill' => 'Transaction has a (any) bill',
'rule_trigger_not_has_no_tag' => 'Transaction has a (any) tag',
'rule_trigger_not_no_notes' => 'Transaction has any notes',
'rule_trigger_not_no_external_url' => 'Transaction has an external URL',
'rule_trigger_not_source_is_cash' => 'Source account is a not a cash account',
'rule_trigger_not_destination_is_cash' => 'Destination account is a not a cash account',
'rule_trigger_not_account_is_cash' => 'Neither account is a cash account',
// actions // actions
'rule_action_delete_transaction_choice' => 'DELETE transaction(!)', 'rule_action_delete_transaction_choice' => 'DELETE transaction(!)',
'rule_action_delete_transaction' => 'DELETE transaction(!)', 'rule_action_delete_transaction' => 'DELETE transaction(!)',