mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-04-28 10:33:00 +00:00
🤖 Auto commit for release 'develop' on 2026-03-01
This commit is contained in:
3
.ci/php-cs-fixer/composer.lock
generated
3
.ci/php-cs-fixer/composer.lock
generated
@@ -2687,8 +2687,5 @@
|
||||
"php": ">=8.5.0"
|
||||
},
|
||||
"platform-dev": {},
|
||||
"platform-overrides": {
|
||||
"php": "8.5"
|
||||
},
|
||||
"plugin-api-version": "2.9.0"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 [
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user