From 1e733f4c8bc2881e19774b6aa692877ef9c68456 Mon Sep 17 00:00:00 2001 From: James Cole Date: Fri, 12 Jan 2024 18:57:38 +0100 Subject: [PATCH] Fix https://github.com/firefly-iii/firefly-iii/issues/8377 --- .../Collector/Extensions/MetaCollection.php | 48 +++++++++++-------- app/Helpers/Collector/GroupCollector.php | 40 ++++++++-------- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/app/Helpers/Collector/Extensions/MetaCollection.php b/app/Helpers/Collector/Extensions/MetaCollection.php index 5f79b8d0b5..b86a697153 100644 --- a/app/Helpers/Collector/Extensions/MetaCollection.php +++ b/app/Helpers/Collector/Extensions/MetaCollection.php @@ -182,7 +182,7 @@ trait MetaCollection public function excludeInternalReference(string $internalReference): GroupCollectorInterface { - $internalReference = (string) json_encode($internalReference); + $internalReference = (string)json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -203,7 +203,7 @@ trait MetaCollection public function externalIdContains(string $externalId): GroupCollectorInterface { - $externalId = (string) json_encode($externalId); + $externalId = (string)json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -215,7 +215,7 @@ trait MetaCollection public function externalIdDoesNotContain(string $externalId): GroupCollectorInterface { - $externalId = (string) json_encode($externalId); + $externalId = (string)json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -227,7 +227,7 @@ trait MetaCollection public function externalIdDoesNotEnd(string $externalId): GroupCollectorInterface { - $externalId = (string) json_encode($externalId); + $externalId = (string)json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -239,7 +239,7 @@ trait MetaCollection public function externalIdDoesNotStart(string $externalId): GroupCollectorInterface { - $externalId = (string) json_encode($externalId); + $externalId = (string)json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -251,7 +251,7 @@ trait MetaCollection public function externalIdEnds(string $externalId): GroupCollectorInterface { - $externalId = (string) json_encode($externalId); + $externalId = (string)json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -263,7 +263,7 @@ trait MetaCollection public function externalIdStarts(string $externalId): GroupCollectorInterface { - $externalId = (string) json_encode($externalId); + $externalId = (string)json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -276,7 +276,7 @@ trait MetaCollection public function externalUrlContains(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = (string) json_encode($url); + $url = (string)json_encode($url); $url = str_replace('\\', '\\\\', trim($url, '"')); $this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $url)); @@ -287,7 +287,7 @@ trait MetaCollection public function externalUrlDoesNotContain(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = (string) json_encode($url); + $url = (string)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)); @@ -298,7 +298,7 @@ trait MetaCollection public function externalUrlDoesNotEnd(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = (string) json_encode($url); + $url = (string)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)); @@ -309,7 +309,7 @@ trait MetaCollection public function externalUrlDoesNotStart(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = (string) json_encode($url); + $url = (string)json_encode($url); $url = str_replace('\\', '\\\\', rtrim($url, '"')); // var_dump($url); @@ -322,7 +322,7 @@ trait MetaCollection public function externalUrlEnds(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = (string) json_encode($url); + $url = (string)json_encode($url); $url = str_replace('\\', '\\\\', ltrim($url, '"')); $this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s', $url)); @@ -333,7 +333,7 @@ trait MetaCollection public function externalUrlStarts(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = (string) json_encode($url); + $url = (string)json_encode($url); $url = str_replace('\\', '\\\\', rtrim($url, '"')); // var_dump($url); @@ -371,7 +371,7 @@ trait MetaCollection public function internalReferenceContains(string $internalReference): GroupCollectorInterface { - $internalReference = (string) json_encode($internalReference); + $internalReference = (string)json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); // var_dump($internalReference); // exit; @@ -385,7 +385,7 @@ trait MetaCollection public function internalReferenceDoesNotContain(string $internalReference): GroupCollectorInterface { - $internalReference = (string) json_encode($internalReference); + $internalReference = (string)json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -397,7 +397,7 @@ trait MetaCollection public function internalReferenceDoesNotEnd(string $internalReference): GroupCollectorInterface { - $internalReference = (string) json_encode($internalReference); + $internalReference = (string)json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -409,7 +409,7 @@ trait MetaCollection public function internalReferenceDoesNotStart(string $internalReference): GroupCollectorInterface { - $internalReference = (string) json_encode($internalReference); + $internalReference = (string)json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -421,7 +421,7 @@ trait MetaCollection public function internalReferenceEnds(string $internalReference): GroupCollectorInterface { - $internalReference = (string) json_encode($internalReference); + $internalReference = (string)json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -433,7 +433,7 @@ trait MetaCollection public function internalReferenceStarts(string $internalReference): GroupCollectorInterface { - $internalReference = (string) json_encode($internalReference); + $internalReference = (string)json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -629,7 +629,7 @@ trait MetaCollection public function setInternalReference(string $internalReference): GroupCollectorInterface { - $internalReference = (string) json_encode($internalReference); + $internalReference = (string)json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -682,6 +682,7 @@ trait MetaCollection $list = $tags->pluck('tag')->toArray(); $list = array_map('strtolower', $list); $filter = static function (array $object) use ($list): bool|array { + $includedJournals = []; $return = $object; unset($return['transactions']); $return['transactions'] = []; @@ -701,7 +702,12 @@ trait MetaCollection if (in_array(strtolower($tag['name']), $list, true)) { app('log')->debug(sprintf('Transaction has tag "%s" so count++.', $tag['name'])); ++$foundTagCount; - $return['transactions'][] = $transaction; + $journalId = $transaction['transaction_journal_id']; + // #8377 prevent adding a transaction twice when multiple tag searches find this transaction + if (!in_array($journalId, $includedJournals, true)) { + $includedJournals[] = $journalId; + $return['transactions'][] = $transaction; + } } } } diff --git a/app/Helpers/Collector/GroupCollector.php b/app/Helpers/Collector/GroupCollector.php index 4b5201e6bb..6d1907ee83 100644 --- a/app/Helpers/Collector/GroupCollector.php +++ b/app/Helpers/Collector/GroupCollector.php @@ -286,7 +286,7 @@ class GroupCollector implements GroupCollectorInterface foreach ($params as $param) { $replace = sprintf('"%s"', $param); if (is_int($param)) { - $replace = (string) $param; + $replace = (string)$param; } $pos = strpos($query, '?'); if (false !== $pos) { @@ -692,13 +692,13 @@ class GroupCollector implements GroupCollectorInterface /** @var TransactionJournal $augumentedJournal */ foreach ($collection as $augumentedJournal) { - $groupId = (int) $augumentedJournal->transaction_group_id; + $groupId = (int)$augumentedJournal->transaction_group_id; if (!array_key_exists($groupId, $groups)) { // make new array $parsedGroup = $this->parseAugmentedJournal($augumentedJournal); $groupArray = [ - 'id' => (int) $augumentedJournal->transaction_group_id, + 'id' => (int)$augumentedJournal->transaction_group_id, 'user_id' => $augumentedJournal->user_id, 'user_group_id' => $augumentedJournal->user_group_id, // Field transaction_group_title was added by the query. @@ -711,7 +711,7 @@ class GroupCollector implements GroupCollectorInterface 'transactions' => [], ]; // Field transaction_journal_id was added by the query. - $journalId = (int) $augumentedJournal->transaction_journal_id; // @phpstan-ignore-line + $journalId = (int)$augumentedJournal->transaction_journal_id; // @phpstan-ignore-line $groupArray['transactions'][$journalId] = $parsedGroup; $groups[$groupId] = $groupArray; @@ -719,7 +719,7 @@ class GroupCollector implements GroupCollectorInterface } // or parse the rest. // Field transaction_journal_id was added by the query. - $journalId = (int) $augumentedJournal->transaction_journal_id; // @phpstan-ignore-line + $journalId = (int)$augumentedJournal->transaction_journal_id; // @phpstan-ignore-line if (array_key_exists($journalId, $groups[$groupId]['transactions'])) { // append data to existing group + journal (for multiple tags or multiple attachments) $groups[$groupId]['transactions'][$journalId] = $this->mergeTags($groups[$groupId]['transactions'][$journalId], $augumentedJournal); @@ -772,7 +772,7 @@ class GroupCollector implements GroupCollectorInterface $dates = ['interest_date', 'payment_date', 'invoice_date', 'book_date', 'due_date', 'process_date']; if (array_key_exists('meta_name', $result) && in_array($result['meta_name'], $dates, true)) { $name = $result['meta_name']; - if (array_key_exists('meta_data', $result) && '' !== (string) $result['meta_data']) { + if (array_key_exists('meta_data', $result) && '' !== (string)$result['meta_data']) { $result[$name] = Carbon::createFromFormat('!Y-m-d', substr(json_decode($result['meta_data']), 0, 10)); } } @@ -783,9 +783,9 @@ class GroupCollector implements GroupCollectorInterface // convert back to strings because SQLite is dumb like that. $result = $this->convertToStrings($result); - $result['reconciled'] = 1 === (int) $result['reconciled']; + $result['reconciled'] = 1 === (int)$result['reconciled']; if (array_key_exists('tag_id', $result) && null !== $result['tag_id']) { // assume the other fields are present as well. - $tagId = (int) $augumentedJournal['tag_id']; + $tagId = (int)$augumentedJournal['tag_id']; $tagDate = null; try { @@ -795,7 +795,7 @@ class GroupCollector implements GroupCollectorInterface } $result['tags'][$tagId] = [ - 'id' => (int) $result['tag_id'], + 'id' => (int)$result['tag_id'], 'name' => $result['tag_name'], 'date' => $tagDate, 'description' => $result['tag_description'], @@ -804,8 +804,8 @@ class GroupCollector implements GroupCollectorInterface // also merge attachments: if (array_key_exists('attachment_id', $result)) { - $uploaded = 1 === (int) $result['attachment_uploaded']; - $attachmentId = (int) $augumentedJournal['attachment_id']; + $uploaded = 1 === (int)$result['attachment_uploaded']; + $attachmentId = (int)$augumentedJournal['attachment_id']; if (0 !== $attachmentId && $uploaded) { $result['attachments'][$attachmentId] = [ 'id' => $attachmentId, @@ -831,7 +831,7 @@ class GroupCollector implements GroupCollectorInterface private function convertToInteger(array $array): array { foreach ($this->integerFields as $field) { - $array[$field] = array_key_exists($field, $array) ? (int) $array[$field] : null; + $array[$field] = array_key_exists($field, $array) ? (int)$array[$field] : null; } return $array; @@ -840,7 +840,7 @@ class GroupCollector implements GroupCollectorInterface private function convertToStrings(array $array): array { foreach ($this->stringFields as $field) { - $array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (string) $array[$field] : null; + $array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (string)$array[$field] : null; } return $array; @@ -850,7 +850,7 @@ class GroupCollector implements GroupCollectorInterface { $newArray = $newJournal->toArray(); if (array_key_exists('tag_id', $newArray)) { // assume the other fields are present as well. - $tagId = (int) $newJournal['tag_id']; + $tagId = (int)$newJournal['tag_id']; $tagDate = null; @@ -861,7 +861,7 @@ class GroupCollector implements GroupCollectorInterface } $existingJournal['tags'][$tagId] = [ - 'id' => (int) $newArray['tag_id'], + 'id' => (int)$newArray['tag_id'], 'name' => $newArray['tag_name'], 'date' => $tagDate, 'description' => $newArray['tag_description'], @@ -875,7 +875,7 @@ class GroupCollector implements GroupCollectorInterface { $newArray = $newJournal->toArray(); if (array_key_exists('attachment_id', $newArray)) { - $attachmentId = (int) $newJournal['attachment_id']; + $attachmentId = (int)$newJournal['attachment_id']; $existingJournal['attachments'][$attachmentId] = [ 'id' => $attachmentId, @@ -894,7 +894,7 @@ class GroupCollector implements GroupCollectorInterface foreach ($groups as $groudId => $group) { /** @var array $transaction */ foreach ($group['transactions'] as $transaction) { - $currencyId = (int) $transaction['currency_id']; + $currencyId = (int)$transaction['currency_id']; if (null === $transaction['amount']) { throw new FireflyException(sprintf('Amount is NULL for a transaction in group #%d, please investigate.', $groudId)); } @@ -910,7 +910,7 @@ class GroupCollector implements GroupCollectorInterface $groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount']); if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) { - $currencyId = (int) $transaction['foreign_currency_id']; + $currencyId = (int)$transaction['foreign_currency_id']; // set default: if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) { @@ -931,7 +931,6 @@ class GroupCollector implements GroupCollectorInterface private function postFilterCollection(Collection $collection): Collection { $currentCollection = $collection; - app('log')->debug(sprintf('GroupCollector: postFilterCollection has %d filter(s) and %d transaction(s).', count($this->postFilters), count($currentCollection))); /** @@ -1055,7 +1054,6 @@ class GroupCollector implements GroupCollectorInterface ->orderBy('transaction_journals.order', 'ASC') ->orderBy('transaction_journals.id', 'DESC') ->orderBy('transaction_journals.description', 'DESC') - ->orderBy('source.amount', 'DESC') - ; + ->orderBy('source.amount', 'DESC'); } }