From bb51baaa38d593fd0e904fc2846fb5e0aee45fc3 Mon Sep 17 00:00:00 2001 From: JC5 Date: Sun, 1 Mar 2026 08:08:15 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Auto=20commit=20for=20release=20?= =?UTF-8?q?'develop'=20on=202026-03-01?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .ci/php-cs-fixer/composer.lock | 3 - THANKS.md | 1 + .../Models/Account/ListController.php | 20 +-- .../Models/Transaction/UpdateController.php | 2 +- .../V1/Controllers/System/BatchController.php | 9 +- .../UserRequestedBatchProcessing.php | 4 +- .../Chart/CategoryReportController.php | 25 ++-- .../Controllers/Chart/ReportController.php | 18 +-- .../Controllers/Chart/TagReportController.php | 29 +++-- .../SupportsGroupProcessingTrait.php | 2 +- .../ResolvesJournalAmountAndCurrency.php | 9 +- .../Engine/RuleEngineInterface.php | 5 +- .../Engine/SearchRuleEngine.php | 116 +++++++++--------- config/firefly.php | 4 +- package-lock.json | 18 +-- 15 files changed, 133 insertions(+), 132 deletions(-) diff --git a/.ci/php-cs-fixer/composer.lock b/.ci/php-cs-fixer/composer.lock index 47c6cae3f1..8d5352642d 100644 --- a/.ci/php-cs-fixer/composer.lock +++ b/.ci/php-cs-fixer/composer.lock @@ -2687,8 +2687,5 @@ "php": ">=8.5.0" }, "platform-dev": {}, - "platform-overrides": { - "php": "8.5" - }, "plugin-api-version": "2.9.0" } diff --git a/THANKS.md b/THANKS.md index ec26c694be..7b0b584133 100755 --- a/THANKS.md +++ b/THANKS.md @@ -4,6 +4,7 @@ Over time, many people have contributed to Firefly III. Their efforts are not al Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution. ## 2026 +- Matthew Grove - Cinnamon Pyro - R1DEN - RiDEN diff --git a/app/Api/V1/Controllers/Models/Account/ListController.php b/app/Api/V1/Controllers/Models/Account/ListController.php index 71eb0fdbf6..54b460b6ad 100644 --- a/app/Api/V1/Controllers/Models/Account/ListController.php +++ b/app/Api/V1/Controllers/Models/Account/ListController.php @@ -128,16 +128,16 @@ class ListController extends Controller */ public function transactions(ListRequest $request, Account $account): JsonResponse { - ['limit' => $limit, 'page' => $page, 'start' => $start, 'end' => $end, 'type' => $type] = $request->attributes->all(); - $types = $this->mapTransactionTypes($type ?? 'default'); - $manager = $this->getManager(); + ['limit' => $limit, 'page' => $page, 'start' => $start, 'end' => $end, 'type' => $type] = $request->attributes->all(); + $types = $this->mapTransactionTypes($type ?? 'default'); + $manager = $this->getManager(); /** @var User $admin */ - $admin = auth()->user(); + $admin = auth()->user(); // use new group collector: /** @var GroupCollectorInterface $collector */ - $collector = app(GroupCollectorInterface::class); + $collector = app(GroupCollectorInterface::class); $collector->setUser($admin)->setAccounts(new Collection()->push($account))->withAPIInformation()->setLimit($limit)->setPage($page)->setTypes($types); if (null !== $start) { $collector->setStart($start); @@ -146,18 +146,18 @@ class ListController extends Controller $collector->setEnd($end); } - $paginator = $collector->getPaginatedGroups(); + $paginator = $collector->getPaginatedGroups(); $paginator->setPath(route('api.v1.accounts.transactions', [$account->id]).$this->buildParams()); // enrich - $enrichment = new TransactionGroupEnrichment(); + $enrichment = new TransactionGroupEnrichment(); $enrichment->setUser($admin); - $transactions = $enrichment->enrich($paginator->getCollection()); + $transactions = $enrichment->enrich($paginator->getCollection()); /** @var TransactionGroupTransformer $transformer */ - $transformer = app(TransactionGroupTransformer::class); + $transformer = app(TransactionGroupTransformer::class); - $resource = new FractalCollection($transactions, $transformer, 'transactions'); + $resource = new FractalCollection($transactions, $transformer, 'transactions'); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); diff --git a/app/Api/V1/Controllers/Models/Transaction/UpdateController.php b/app/Api/V1/Controllers/Models/Transaction/UpdateController.php index c3b259e90f..cee5b26ce8 100644 --- a/app/Api/V1/Controllers/Models/Transaction/UpdateController.php +++ b/app/Api/V1/Controllers/Models/Transaction/UpdateController.php @@ -92,7 +92,7 @@ class UpdateController extends Controller $flags->applyRules = $applyRules; $flags->fireWebhooks = $fireWebhooks; $flags->recalculateCredit = $runRecalculations; - $flags->batchSubmission = $data['batch_submission'] ?? false; + $flags->batchSubmission = $data['batch_submission'] ?? false; event(new UpdatedSingleTransactionGroup($flags, $objects)); event(new WebhookMessagesRequestSending()); diff --git a/app/Api/V1/Controllers/System/BatchController.php b/app/Api/V1/Controllers/System/BatchController.php index cd39d9a77e..aee4fdfe44 100644 --- a/app/Api/V1/Controllers/System/BatchController.php +++ b/app/Api/V1/Controllers/System/BatchController.php @@ -54,17 +54,20 @@ class BatchController extends Controller public function finishBatch(Request $request): JsonResponse { Log::debug('Now in finishBatch.'); - $journals = $this->repository->getUncompletedJournals(); + $journals = $this->repository->getUncompletedJournals(); if (0 === count($journals)) { Log::debug('Counted zero journals, return.'); + return response()->json([], 204); } Log::debug(sprintf('Counted %d journals.', count($journals))); + /** @var TransactionJournal $first */ - $first = $journals->first(); - $group = $first?->transactionGroup; + $first = $journals->first(); + $group = $first?->transactionGroup; if (null === $group) { Log::debug('First group is NULL.'); + return response()->json([], 204); } $flags = new TransactionGroupEventFlags(); diff --git a/app/Events/Model/TransactionGroup/UserRequestedBatchProcessing.php b/app/Events/Model/TransactionGroup/UserRequestedBatchProcessing.php index e049a3dde1..4df1c6fe37 100644 --- a/app/Events/Model/TransactionGroup/UserRequestedBatchProcessing.php +++ b/app/Events/Model/TransactionGroup/UserRequestedBatchProcessing.php @@ -30,7 +30,9 @@ class UserRequestedBatchProcessing extends Event { public TransactionGroupEventObjects $objects; - public function __construct(public TransactionGroupEventFlags $flags) { + public function __construct( + public TransactionGroupEventFlags $flags + ) { $this->objects = new TransactionGroupEventObjects(); } } diff --git a/app/Http/Controllers/Chart/CategoryReportController.php b/app/Http/Controllers/Chart/CategoryReportController.php index 5d973b0c20..1e8de112e1 100644 --- a/app/Http/Controllers/Chart/CategoryReportController.php +++ b/app/Http/Controllers/Chart/CategoryReportController.php @@ -102,8 +102,8 @@ class CategoryReportController extends Controller /** @var array $category */ foreach ($currency['categories'] as $category) { foreach ($category['transaction_journals'] as $journal) { - $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); - $title = sprintf('%s (%s)', $category['name'], $journalData['currency_name']); + $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); + $title = sprintf('%s (%s)', $category['name'], $journalData['currency_name']); $result[$title] ??= [ 'amount' => '0', 'currency_symbol' => $journalData['currency_symbol'], @@ -129,8 +129,8 @@ class CategoryReportController extends Controller /** @var array $category */ foreach ($currency['categories'] as $category) { foreach ($category['transaction_journals'] as $journal) { - $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); - $title = sprintf('%s (%s)', $category['name'], $journalData['currency_name']); + $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); + $title = sprintf('%s (%s)', $category['name'], $journalData['currency_name']); $result[$title] ??= [ 'amount' => '0', 'currency_symbol' => $journalData['currency_symbol'], @@ -213,9 +213,9 @@ class CategoryReportController extends Controller // add things to chart Data for each currency: foreach ($currency['categories'] as $currentCategory) { foreach ($currentCategory['transaction_journals'] as $journal) { - $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); - $spentKey = sprintf('%d-spent', $journalData['currency_id']); - $chartData[$spentKey] ??= [ + $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); + $spentKey = sprintf('%d-spent', $journalData['currency_id']); + $chartData[$spentKey] ??= [ 'label' => sprintf( '%s (%s)', (string) trans('firefly.spent_in_specific_category', ['category' => $category->name]), @@ -227,7 +227,7 @@ class CategoryReportController extends Controller 'currency_id' => $journalData['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; - $key = $journal['date']->isoFormat($format); + $key = $journal['date']->isoFormat($format); $chartData[$spentKey]['entries'][$key] ??= '0'; $chartData[$spentKey]['entries'][$key] = bcadd($chartData[$spentKey]['entries'][$key], $journalData['amount']); } @@ -239,9 +239,9 @@ class CategoryReportController extends Controller // add things to chart Data for each currency: foreach ($currency['categories'] as $currentCategory) { foreach ($currentCategory['transaction_journals'] as $journal) { - $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); - $spentKey = sprintf('%d-earned', $journalData['currency_id']); - $chartData[$spentKey] ??= [ + $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); + $spentKey = sprintf('%d-earned', $journalData['currency_id']); + $chartData[$spentKey] ??= [ 'label' => sprintf( '%s (%s)', (string) trans('firefly.earned_in_specific_category', ['category' => $category->name]), @@ -253,7 +253,7 @@ class CategoryReportController extends Controller 'currency_id' => $journalData['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; - $key = $journal['date']->isoFormat($format); + $key = $journal['date']->isoFormat($format); $chartData[$spentKey]['entries'][$key] ??= '0'; $chartData[$spentKey]['entries'][$key] = bcadd($chartData[$spentKey]['entries'][$key], $journalData['amount']); } @@ -340,5 +340,4 @@ class CategoryReportController extends Controller return $return; } - } diff --git a/app/Http/Controllers/Chart/ReportController.php b/app/Http/Controllers/Chart/ReportController.php index 46223164bf..9c56053a4a 100644 --- a/app/Http/Controllers/Chart/ReportController.php +++ b/app/Http/Controllers/Chart/ReportController.php @@ -178,14 +178,14 @@ class ReportController extends Controller // loop. group by currency and by period. /** @var array $journal */ foreach ($journals as $journal) { - $period = $journal['date']->format($format); - $journalData = $this->resolveJournalAmountAndCurrency($journal, $journal); - $currencyId = $journalData['currency_id']; - $currencySymbol = $journalData['currency_symbol']; - $currencyCode = $journalData['currency_code']; - $currencyName = $journalData['currency_name']; - $currencyDecimalPlaces = $journalData['currency_decimal_places']; - $amount = $journalData['amount']; + $period = $journal['date']->format($format); + $journalData = $this->resolveJournalAmountAndCurrency($journal, $journal); + $currencyId = $journalData['currency_id']; + $currencySymbol = $journalData['currency_symbol']; + $currencyCode = $journalData['currency_code']; + $currencyName = $journalData['currency_name']; + $currencyDecimalPlaces = $journalData['currency_decimal_places']; + $amount = $journalData['amount']; $data[$currencyId] ??= [ 'currency_id' => $currencyId, @@ -196,7 +196,7 @@ class ReportController extends Controller ]; $data[$currencyId][$period] ??= ['period' => $period, 'spent' => '0', 'earned' => '0']; // in our outgoing? - $key = 'spent'; + $key = 'spent'; // deposit = incoming // transfer or reconcile or opening balance, and these accounts are the destination. diff --git a/app/Http/Controllers/Chart/TagReportController.php b/app/Http/Controllers/Chart/TagReportController.php index 64504a97af..d11ced17ca 100644 --- a/app/Http/Controllers/Chart/TagReportController.php +++ b/app/Http/Controllers/Chart/TagReportController.php @@ -215,17 +215,21 @@ class TagReportController extends Controller // add things to chart Data for each currency: foreach ($currency['tags'] as $currentTag) { foreach ($currentTag['transaction_journals'] as $journal) { - $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); - $spentKey = sprintf('%d-spent', $journalData['currency_id']); - $chartData[$spentKey] ??= [ - 'label' => sprintf('%s (%s)', (string) trans('firefly.spent_in_specific_tag', ['tag' => $tag->tag]), $journalData['currency_name']), + $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); + $spentKey = sprintf('%d-spent', $journalData['currency_id']); + $chartData[$spentKey] ??= [ + 'label' => sprintf( + '%s (%s)', + (string) trans('firefly.spent_in_specific_tag', ['tag' => $tag->tag]), + $journalData['currency_name'] + ), 'type' => 'bar', 'currency_symbol' => $journalData['currency_symbol'], 'currency_code' => $journalData['currency_code'], 'currency_id' => $journalData['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; - $key = $journal['date']->isoFormat($format); + $key = $journal['date']->isoFormat($format); $chartData[$spentKey]['entries'][$key] ??= '0'; $chartData[$spentKey]['entries'][$key] = bcadd($chartData[$spentKey]['entries'][$key], $journalData['amount']); } @@ -237,17 +241,21 @@ class TagReportController extends Controller // add things to chart Data for each currency: foreach ($currency['tags'] as $currentTag) { foreach ($currentTag['transaction_journals'] as $journal) { - $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); - $spentKey = sprintf('%d-earned', $journalData['currency_id']); - $chartData[$spentKey] ??= [ - 'label' => sprintf('%s (%s)', (string) trans('firefly.earned_in_specific_tag', ['tag' => $tag->tag]), $journalData['currency_name']), + $journalData = $this->resolveJournalAmountAndCurrency($journal, $currency); + $spentKey = sprintf('%d-earned', $journalData['currency_id']); + $chartData[$spentKey] ??= [ + 'label' => sprintf( + '%s (%s)', + (string) trans('firefly.earned_in_specific_tag', ['tag' => $tag->tag]), + $journalData['currency_name'] + ), 'type' => 'bar', 'currency_symbol' => $journalData['currency_symbol'], 'currency_code' => $journalData['currency_code'], 'currency_id' => $journalData['currency_id'], 'entries' => $this->makeEntries($start, $end), ]; - $key = $journal['date']->isoFormat($format); + $key = $journal['date']->isoFormat($format); $chartData[$spentKey]['entries'][$key] ??= '0'; $chartData[$spentKey]['entries'][$key] = bcadd($chartData[$spentKey]['entries'][$key], $journalData['amount']); } @@ -386,5 +394,4 @@ class TagReportController extends Controller return $return; } - } diff --git a/app/Listeners/Model/TransactionGroup/SupportsGroupProcessingTrait.php b/app/Listeners/Model/TransactionGroup/SupportsGroupProcessingTrait.php index 26cc3b66a8..693efdbdc6 100644 --- a/app/Listeners/Model/TransactionGroup/SupportsGroupProcessingTrait.php +++ b/app/Listeners/Model/TransactionGroup/SupportsGroupProcessingTrait.php @@ -55,7 +55,7 @@ trait SupportsGroupProcessingTrait $newRuleEngine = app(RuleEngineInterface::class); $newRuleEngine->setUser($user); $newRuleEngine->setRuleGroups($groups); - foreach($array as $journalId) { + foreach ($array as $journalId) { $newRuleEngine->removeOperator('journal_id'); $newRuleEngine->addOperator(['type' => 'journal_id', 'value' => $journalId]); $newRuleEngine->fire(); diff --git a/app/Support/Http/Controllers/ResolvesJournalAmountAndCurrency.php b/app/Support/Http/Controllers/ResolvesJournalAmountAndCurrency.php index 663fd7886f..bb96490c00 100644 --- a/app/Support/Http/Controllers/ResolvesJournalAmountAndCurrency.php +++ b/app/Support/Http/Controllers/ResolvesJournalAmountAndCurrency.php @@ -42,11 +42,7 @@ trait ResolvesJournalAmountAndCurrency $currencyDecimalPlaces = (int) ($journal['currency_decimal_places'] ?? $currency['currency_decimal_places'] ?? 2); $amount = (string) $journal['amount']; - if ( - $this->convertToPrimary - && null !== $this->primaryCurrency - && $currencyId !== $this->primaryCurrency->id - ) { + if ($this->convertToPrimary && null !== $this->primaryCurrency && $currencyId !== $this->primaryCurrency->id) { $currencyId = $this->primaryCurrency->id; $currencyName = $this->primaryCurrency->name; $currencySymbol = $this->primaryCurrency->symbol; @@ -54,8 +50,7 @@ trait ResolvesJournalAmountAndCurrency $currencyDecimalPlaces = $this->primaryCurrency->decimal_places; $amount = (int) ($journal['foreign_currency_id'] ?? 0) === $this->primaryCurrency->id ? (string) ($journal['foreign_amount'] ?? '0') - : (string) ($journal['pc_amount'] ?? '0') - ; + : (string) ($journal['pc_amount'] ?? '0'); } return [ diff --git a/app/TransactionRules/Engine/RuleEngineInterface.php b/app/TransactionRules/Engine/RuleEngineInterface.php index 7c15468b5c..919e651967 100644 --- a/app/TransactionRules/Engine/RuleEngineInterface.php +++ b/app/TransactionRules/Engine/RuleEngineInterface.php @@ -37,9 +37,6 @@ interface RuleEngineInterface */ public function addOperator(array $operator): void; - public function removeOperator(string $type): void; - - /** * Find all transactions only, dont apply anything. */ @@ -55,6 +52,8 @@ interface RuleEngineInterface */ public function getResults(): int; + public function removeOperator(string $type): void; + public function setRefreshTriggers(bool $refreshTriggers): void; /** diff --git a/app/TransactionRules/Engine/SearchRuleEngine.php b/app/TransactionRules/Engine/SearchRuleEngine.php index 79e11f76f4..cdcef0ccc9 100644 --- a/app/TransactionRules/Engine/SearchRuleEngine.php +++ b/app/TransactionRules/Engine/SearchRuleEngine.php @@ -38,6 +38,7 @@ use FireflyIII\TransactionRules\Factory\ActionFactory; use FireflyIII\User; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Log; +use Override; /** * Class SearchRuleEngine @@ -46,12 +47,12 @@ class SearchRuleEngine implements RuleEngineInterface { private readonly Collection $groups; - private array $operators = []; + private array $operators = []; // always collect the triggers from the database, unless indicated otherwise. - private bool $refreshTriggers = true; - private array $resultCount = []; + private bool $refreshTriggers = true; + private array $resultCount = []; private readonly Collection $rules; - private User $user; + private User $user; public function __construct() { @@ -70,7 +71,7 @@ class SearchRuleEngine implements RuleEngineInterface Log::debug('SearchRuleEngine::find()'); $collection = new Collection(); foreach ($this->rules as $rule) { - $found = new Collection(); + $found = new Collection(); if (true === $rule->strict) { $found = $this->findStrictRule($rule); } @@ -79,7 +80,7 @@ class SearchRuleEngine implements RuleEngineInterface } $collection = $collection->merge($found); } - $result = $collection->unique(); + $result = $collection->unique(); Log::debug(sprintf('SearchRuleEngine::find() returns %d unique transactions.', $result->count())); return $result; @@ -102,9 +103,9 @@ class SearchRuleEngine implements RuleEngineInterface $result = $this->fireRule($rule); if ($result && true === $rule->stop_processing) { Log::debug(sprintf( - 'Rule #%d has triggered and executed, but calls to stop processing. Since not in the context of a group, do not stop.', - $rule->id - )); + 'Rule #%d has triggered and executed, but calls to stop processing. Since not in the context of a group, do not stop.', + $rule->id + )); } if (false === $result && true === $rule->stop_processing) { Log::debug(sprintf('Rule #%d has triggered and changed nothing, but calls to stop processing. Do not stop.', $rule->id)); @@ -134,6 +135,21 @@ class SearchRuleEngine implements RuleEngineInterface return count($this->resultCount); } + #[Override] + public function removeOperator(string $type): void + { + $new = []; + foreach ($this->operators as $operator) { + if ($type === $operator['type']) { + Log::debug(sprintf('Removing operator "%s"', $type)); + + continue; + } + $new[] = $operator; + } + $this->operators = $new; + } + public function setRefreshTriggers(bool $refreshTriggers): void { $this->refreshTriggers = $refreshTriggers; @@ -170,9 +186,10 @@ class SearchRuleEngine implements RuleEngineInterface private function addNotes(array $transaction): array { $transaction['notes'] = ''; - $dbNote = Note::where('noteable_id', (int)$transaction['transaction_journal_id']) - ->where('noteable_type', TransactionJournal::class) - ->first(['notes.*']); + $dbNote = Note::where('noteable_id', (int) $transaction['transaction_journal_id']) + ->where('noteable_type', TransactionJournal::class) + ->first(['notes.*']) + ; if (null !== $dbNote) { $transaction['notes'] = $dbNote->text; } @@ -201,12 +218,12 @@ class SearchRuleEngine implements RuleEngineInterface /** @var RuleTrigger $ruleTrigger */ foreach ($triggers as $ruleTrigger) { Log::debug(sprintf( - 'Now at rule trigger #%d: %s:"%s" (%s).', - $ruleTrigger->id, - $ruleTrigger->trigger_type, - $ruleTrigger->trigger_value, - var_export($ruleTrigger->stop_processing, true) - )); + 'Now at rule trigger #%d: %s:"%s" (%s).', + $ruleTrigger->id, + $ruleTrigger->trigger_type, + $ruleTrigger->trigger_value, + var_export($ruleTrigger->stop_processing, true) + )); if (false === $ruleTrigger->active) { Log::debug('Trigger is not active, continue.'); @@ -244,10 +261,10 @@ class SearchRuleEngine implements RuleEngineInterface $searchEngine->parseQuery(sprintf('%s:%s', $type, $value)); } - $result = $searchEngine->searchTransactions(); - $collection = $result->getCollection(); + $result = $searchEngine->searchTransactions(); + $collection = $result->getCollection(); Log::debug(sprintf('Found in this run, %d transactions', $collection->count())); - $total = $total->merge($collection); + $total = $total->merge($collection); Log::debug(sprintf('Total collection is now %d transactions', $total->count())); ++$count; // if trigger says stop processing, do so. @@ -261,7 +278,7 @@ class SearchRuleEngine implements RuleEngineInterface Log::debug(sprintf('Done running %d trigger(s)', $count)); // make collection unique - $unique = $total->unique(static function (array $group): string { + $unique = $total->unique(static function (array $group): string { $str = ''; foreach ($group['transactions'] as $transaction) { $str = sprintf('%s%d', $str, $transaction['transaction_journal_id']); @@ -283,8 +300,8 @@ class SearchRuleEngine implements RuleEngineInterface private function findStrictRule(Rule $rule): Collection { Log::debug(sprintf('Now in findStrictRule(#%d)', $rule->id ?? 0)); - $searchArray = []; - $triggers = []; + $searchArray = []; + $triggers = []; if ($this->refreshTriggers) { $triggers = $rule->ruleTriggers()->orderBy('order', 'ASC')->get(); } @@ -298,12 +315,12 @@ class SearchRuleEngine implements RuleEngineInterface continue; } $contextSearch = $ruleTrigger->trigger_type; - if (str_starts_with((string)$ruleTrigger->trigger_type, '-')) { - $contextSearch = substr((string)$ruleTrigger->trigger_type, 1); + if (str_starts_with((string) $ruleTrigger->trigger_type, '-')) { + $contextSearch = substr((string) $ruleTrigger->trigger_type, 1); } // if the trigger needs no context, value is different: - $needsContext = (bool)(config(sprintf('search.operators.%s.needs_context', $contextSearch)) ?? true); + $needsContext = (bool) (config(sprintf('search.operators.%s.needs_context', $contextSearch)) ?? true); if (false === $needsContext) { Log::debug(sprintf('SearchRuleEngine:: add a rule trigger (no context): %s:true', $ruleTrigger->trigger_type)); $searchArray[$ruleTrigger->trigger_type][] = 'true'; @@ -319,7 +336,7 @@ class SearchRuleEngine implements RuleEngineInterface Log::debug(sprintf('SearchRuleEngine:: add local added operator: %s:"%s"', $operator['type'], $operator['value'])); $searchArray[$operator['type']][] = sprintf('"%s"', $operator['value']); } - $date = today(config('app.timezone')); + $date = today(config('app.timezone')); if ($this->hasSpecificJournalTrigger($searchArray)) { $date = $this->setDateFromJournalTrigger($searchArray); } @@ -340,7 +357,7 @@ class SearchRuleEngine implements RuleEngineInterface } } - $result = $searchEngine->searchTransactions(); + $result = $searchEngine->searchTransactions(); return $result->getCollection(); } @@ -357,11 +374,7 @@ class SearchRuleEngine implements RuleEngineInterface } if (!$group->relationLoaded('rules')) { Log::debug('Group rules have NOT been pre-loaded, load them NOW.'); - $rules = $group - ->rules() - ->orderBy('rules.order', 'ASC') - ->where('rules.active', true) - ->get(['rules.*']); + $rules = $group->rules()->orderBy('rules.order', 'ASC')->where('rules.active', true)->get(['rules.*']); } Log::debug(sprintf('Going to fire group #%d with %d rule(s)', $group->id, $rules->count())); @@ -429,7 +442,7 @@ class SearchRuleEngine implements RuleEngineInterface $this->processResults($rule, $collection); - $result = $collection->count() > 0; + $result = $collection->count() > 0; if ($result) { Log::debug(sprintf('SearchRuleEngine:: Done. Rule #%d was triggered (on %d transaction(s)).', $rule->id, $collection->count())); @@ -455,7 +468,7 @@ class SearchRuleEngine implements RuleEngineInterface Log::debug('Found a journal_id trigger with 1 journal, true.'); $journalTrigger = true; } - if ('journal_id' === $triggerName && is_string($values) && !str_contains($values,',')) { + if ('journal_id' === $triggerName && is_string($values) && !str_contains($values, ',')) { Log::debug('Found a journal_id trigger with 1 journal, true.'); $journalTrigger = true; } @@ -464,7 +477,7 @@ class SearchRuleEngine implements RuleEngineInterface $dateTrigger = true; } } - $result = $journalTrigger && $dateTrigger; + $result = $journalTrigger && $dateTrigger; Log::debug(sprintf('Result of hasSpecificJournalTrigger is %s.', var_export($result, true))); return $result; @@ -496,11 +509,11 @@ class SearchRuleEngine implements RuleEngineInterface if ($result) { $this->resultCount[$journalId] = array_key_exists($journalId, $this->resultCount) ? $this->resultCount[$journalId]++ : 1; Log::debug(sprintf( - 'Action "%s" on journal #%d was executed, so count a result. Updated transaction journal count is now %d.', - $ruleAction->action_type, - $transaction['transaction_journal_id'] ?? 0, - count($this->resultCount) - )); + 'Action "%s" on journal #%d was executed, so count a result. Updated transaction journal count is now %d.', + $ruleAction->action_type, + $transaction['transaction_journal_id'] ?? 0, + count($this->resultCount) + )); } if (false === $result) { Log::debug(sprintf('Action "%s" reports NO changes were made.', $ruleAction->action_type)); @@ -558,14 +571,14 @@ class SearchRuleEngine implements RuleEngineInterface $journalId = 0; foreach ($array as $triggerName => $values) { if ('journal_id' === $triggerName && is_array($values) && 1 === count($values)) { - $journalId = (int)trim($values[0] ?? '"0"', '"'); // follows format "123". + $journalId = (int) trim($values[0] ?? '"0"', '"'); // follows format "123". Log::debug(sprintf('Found journal ID #%d', $journalId)); } } if (0 !== $journalId) { $repository = app(JournalRepositoryInterface::class); $repository->setUser($this->user); - $journal = $repository->find($journalId); + $journal = $repository->find($journalId); if (null !== $journal) { $date = $journal->date; Log::debug(sprintf('Found journal #%d with date %s.', $journal->id, $journal->date->format('Y-m-d'))); @@ -577,19 +590,4 @@ class SearchRuleEngine implements RuleEngineInterface return today(config('app.timezone')); } - - - #[\Override] - public function removeOperator(string $type): void - { - $new = []; - foreach ($this->operators as $operator) { - if ($type === $operator['type']) { - Log::debug(sprintf('Removing operator "%s"', $type)); - continue; - } - $new[] = $operator; - } - $this->operators = $new; - } } diff --git a/config/firefly.php b/config/firefly.php index 7363516066..226548cade 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -78,8 +78,8 @@ return [ 'running_balance_column' => (bool)envNonEmpty('USE_RUNNING_BALANCE', true), // this is only the default value, is not used. // see cer.php for exchange rates feature flag. ], - 'version' => 'develop/2026-02-28', - 'build_time' => 1772261249, + 'version' => 'develop/2026-03-01', + 'build_time' => 1772348761, 'api_version' => '2.1.0', // field is no longer used. 'db_version' => 28, // field is no longer used. diff --git a/package-lock.json b/package-lock.json index 6406eee97b..aad6cc6673 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3246,9 +3246,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.3.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.2.tgz", - "integrity": "sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==", + "version": "25.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", + "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4597,9 +4597,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001774", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz", - "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==", + "version": "1.0.30001775", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001775.tgz", + "integrity": "sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A==", "dev": true, "funding": [ { @@ -5859,9 +5859,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", "dev": true, "license": "MIT", "dependencies": {