From d1332eb59256f83937f31b3064b7ec037ea99201 Mon Sep 17 00:00:00 2001 From: JC5 Date: Sun, 7 Dec 2025 17:22:38 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Auto=20commit=20for=20release=20?= =?UTF-8?q?'develop'=20on=202025-12-07?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Integrity/ValidatesFilePermissions.php | 10 +- .../TriggeredStoredTransactionGroup.php | 2 + .../Events/StoredGroupEventHandler.php | 20 ++-- .../RuleGroup/ExecutionController.php | 12 +- .../Internal/Update/JournalUpdateService.php | 111 +++++++++--------- composer.lock | 29 +++-- config/firefly.php | 4 +- package-lock.json | 6 +- 8 files changed, 102 insertions(+), 92 deletions(-) diff --git a/app/Console/Commands/Integrity/ValidatesFilePermissions.php b/app/Console/Commands/Integrity/ValidatesFilePermissions.php index e3849e6aa1..d03a9f876a 100644 --- a/app/Console/Commands/Integrity/ValidatesFilePermissions.php +++ b/app/Console/Commands/Integrity/ValidatesFilePermissions.php @@ -1,4 +1,6 @@ friendlyError(sprintf('Directory "%s" cannot found. It is necessary to allow files to be uploaded.', $uploadDir)); $errors = true; + continue; } if (!is_writable($directory)) { @@ -61,7 +65,7 @@ class ValidatesFilePermissions extends Command $errors = true; } } - if(false === $errors) { + if (false === $errors) { $this->friendlyInfo('All necessary file paths seem to exist, and are writeable.'); } diff --git a/app/Events/Model/TransactionGroup/TriggeredStoredTransactionGroup.php b/app/Events/Model/TransactionGroup/TriggeredStoredTransactionGroup.php index 858119b6b0..769208971f 100644 --- a/app/Events/Model/TransactionGroup/TriggeredStoredTransactionGroup.php +++ b/app/Events/Model/TransactionGroup/TriggeredStoredTransactionGroup.php @@ -1,4 +1,6 @@ transactionGroup->transactionJournals; - $array = []; + $journals = $storedGroupEvent->transactionGroup->transactionJournals; + $array = []; /** @var TransactionJournal $journal */ foreach ($journals as $journal) { $array[] = $journal->id; } - $journalIds = implode(',', $array); + $journalIds = implode(',', $array); Log::debug(sprintf('Add local operator for journal(s): %s', $journalIds)); // collect rules: @@ -86,10 +86,10 @@ class StoredGroupEventHandler // add the groups to the rule engine. // it should run the rules in the group and cancel the group if necessary. - $groups = $ruleGroupRepository->getRuleGroupsWithRules('store-journal'); + $groups = $ruleGroupRepository->getRuleGroupsWithRules('store-journal'); // create and fire rule engine. - $newRuleEngine = app(RuleEngineInterface::class); + $newRuleEngine = app(RuleEngineInterface::class); $newRuleEngine->setUser($storedGroupEvent->transactionGroup->user); $newRuleEngine->addOperator(['type' => 'journal_id', 'value' => $journalIds]); $newRuleEngine->setRuleGroups($groups); @@ -98,7 +98,7 @@ class StoredGroupEventHandler private function recalculateCredit(StoredTransactionGroup $event): void { - $group = $event->transactionGroup; + $group = $event->transactionGroup; /** @var CreditRecalculateService $object */ $object = app(CreditRecalculateService::class); @@ -114,10 +114,10 @@ class StoredGroupEventHandler /** @var TransactionJournal $journal */ foreach ($event->transactionGroup->transactionJournals as $journal) { /** @var null|Transaction $source */ - $source = $journal->transactions()->where('amount', '<', '0')->first(); + $source = $journal->transactions()->where('amount', '<', '0')->first(); /** @var null|Transaction $dest */ - $dest = $journal->transactions()->where('amount', '>', '0')->first(); + $dest = $journal->transactions()->where('amount', '>', '0')->first(); if (null !== $source) { $repository->deleteStatisticsForModel($source->account, $journal->date); @@ -152,14 +152,14 @@ class StoredGroupEventHandler private function triggerWebhooks(StoredTransactionGroup $storedGroupEvent): void { Log::debug(__METHOD__); - $group = $storedGroupEvent->transactionGroup; + $group = $storedGroupEvent->transactionGroup; if (false === $storedGroupEvent->fireWebhooks) { Log::info(sprintf('Will not fire webhooks for transaction group #%d', $group->id)); return; } - $user = $group->user; + $user = $group->user; /** @var MessageGeneratorInterface $engine */ $engine = app(MessageGeneratorInterface::class); diff --git a/app/Http/Controllers/RuleGroup/ExecutionController.php b/app/Http/Controllers/RuleGroup/ExecutionController.php index 3a96f6138c..f066f9f1a4 100644 --- a/app/Http/Controllers/RuleGroup/ExecutionController.php +++ b/app/Http/Controllers/RuleGroup/ExecutionController.php @@ -71,8 +71,9 @@ class ExecutionController extends Controller public function execute(SelectTransactionsRequest $request, RuleGroup $ruleGroup): RedirectResponse { // Get parameters specified by the user - $accounts = $request->get('accounts'); - $set = $this->repository->getAccountsById($accounts); + $accounts = $request->get('accounts'); + $set = $this->repository->getAccountsById($accounts); + /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); $collector->setAccounts($set); @@ -85,12 +86,13 @@ class ExecutionController extends Controller $endDate = new Carbon($request->get('end')); $collector->setEnd($endDate); } - $final = $collector->getGroups(); - $ids = $final->pluck('id')->toArray(); + $final = $collector->getGroups(); + $ids = $final->pluck('id')->toArray(); Log::debug(sprintf('Found %d groups collected from %d account(s)', $final->count(), $set->count())); foreach (array_chunk($ids, 1337) as $setOfIds) { Log::debug(sprintf('Now processing %d groups', count($setOfIds))); $groups = TransactionGroup::whereIn('id', $setOfIds)->get(); + /** @var TransactionGroup $group */ foreach ($groups as $group) { Log::debug(sprintf('Processing group #%d.', $group->id)); @@ -109,7 +111,7 @@ class ExecutionController extends Controller * * @return Factory|View */ - public function selectTransactions(RuleGroup $ruleGroup): Factory | \Illuminate\Contracts\View\View + public function selectTransactions(RuleGroup $ruleGroup): Factory|\Illuminate\Contracts\View\View { $subTitle = (string)trans('firefly.apply_rule_group_selection', ['title' => $ruleGroup->title]); diff --git a/app/Services/Internal/Update/JournalUpdateService.php b/app/Services/Internal/Update/JournalUpdateService.php index 824ab1c2f4..c1ce184cd6 100644 --- a/app/Services/Internal/Update/JournalUpdateService.php +++ b/app/Services/Internal/Update/JournalUpdateService.php @@ -68,7 +68,7 @@ class JournalUpdateService private ?Transaction $destinationTransaction = null; private array $metaDate = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', - 'invoice_date',]; + 'invoice_date', ]; private array $metaString = [ 'sepa_cc', @@ -112,7 +112,7 @@ class JournalUpdateService public function setTransactionGroup(TransactionGroup $transactionGroup): void { - $this->transactionGroup = $transactionGroup; + $this->transactionGroup = $transactionGroup; $this->billRepository->setUser($transactionGroup->user); $this->categoryRepository->setUser($transactionGroup->user); $this->budgetRepository->setUser($transactionGroup->user); @@ -183,8 +183,8 @@ class JournalUpdateService private function hasValidSourceAccount(): bool { - $sourceId = $this->data['source_id'] ?? null; - $sourceName = $this->data['source_name'] ?? null; + $sourceId = $this->data['source_id'] ?? null; + $sourceName = $this->data['source_name'] ?? null; Log::debug(sprintf('Now in hasValidSourceAccount("%s","%s").', $sourceId, $sourceName)); if (!$this->hasFields(['source_id', 'source_name'])) { @@ -199,11 +199,11 @@ class JournalUpdateService // make a new validator. /** @var AccountValidator $validator */ - $validator = app(AccountValidator::class); + $validator = app(AccountValidator::class); $validator->setTransactionType($expectedType); $validator->setUser($this->transactionJournal->user); - $result = $validator->validateSource(['id' => $sourceId, 'name' => $sourceName]); + $result = $validator->validateSource(['id' => $sourceId, 'name' => $sourceName]); Log::debug( sprintf('hasValidSourceAccount(%d, "%s") will return %s', $sourceId, $sourceName, var_export($result, true)) ); @@ -216,7 +216,7 @@ class JournalUpdateService private function hasFields(array $fields): bool { - return array_any($fields, fn($field): bool => array_key_exists($field, $this->data)); + return array_any($fields, fn ($field): bool => array_key_exists($field, $this->data)); } private function getOriginalSourceAccount(): Account @@ -261,8 +261,8 @@ class JournalUpdateService private function hasValidDestinationAccount(): bool { Log::debug('Now in hasValidDestinationAccount().'); - $destId = $this->data['destination_id'] ?? null; - $destName = $this->data['destination_name'] ?? null; + $destId = $this->data['destination_id'] ?? null; + $destName = $this->data['destination_name'] ?? null; if (!$this->hasFields(['destination_id', 'destination_name'])) { Log::debug('No destination info submitted, grab the original data.'); @@ -272,12 +272,12 @@ class JournalUpdateService } // make new account validator. - $expectedType = $this->getExpectedType(); + $expectedType = $this->getExpectedType(); Log::debug(sprintf('(b) Expected type (new or unchanged) is %s', $expectedType)); // make a new validator. /** @var AccountValidator $validator */ - $validator = app(AccountValidator::class); + $validator = app(AccountValidator::class); $validator->setTransactionType($expectedType); $validator->setUser($this->transactionJournal->user); $validator->source = $this->getValidSourceAccount(); @@ -332,7 +332,7 @@ class JournalUpdateService return $this->getOriginalSourceAccount(); } - $sourceInfo = [ + $sourceInfo = [ 'id' => (int)($this->data['source_id'] ?? null), 'name' => $this->data['source_name'] ?? null, 'iban' => $this->data['source_iban'] ?? null, @@ -360,8 +360,8 @@ class JournalUpdateService */ private function updateAccounts(): void { - $source = $this->getValidSourceAccount(); - $destination = $this->getValidDestinationAccount(); + $source = $this->getValidSourceAccount(); + $destination = $this->getValidDestinationAccount(); // cowardly refuse to update if both accounts are the same. if ($source->id === $destination->id) { @@ -374,7 +374,7 @@ class JournalUpdateService $origSourceTransaction->account()->associate($source); $origSourceTransaction->save(); - $destTransaction = $this->getDestinationTransaction(); + $destTransaction = $this->getDestinationTransaction(); $destTransaction->account()->associate($destination); $destTransaction->save(); @@ -396,7 +396,7 @@ class JournalUpdateService return $this->getOriginalDestinationAccount(); } - $destInfo = [ + $destInfo = [ 'id' => (int)($this->data['destination_id'] ?? null), 'name' => $this->data['destination_name'] ?? null, 'iban' => $this->data['destination_iban'] ?? null, @@ -425,7 +425,7 @@ class JournalUpdateService { Log::debug('Now in updateType()'); if ($this->hasFields(['type'])) { - $type = 'opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type']; + $type = 'opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type']; Log::debug( sprintf( 'Trying to change journal #%d from a %s to a %s.', @@ -458,9 +458,9 @@ class JournalUpdateService { $type = $this->transactionJournal->transactionType->type; if (( - array_key_exists('bill_id', $this->data) + array_key_exists('bill_id', $this->data) || array_key_exists('bill_name', $this->data) - ) + ) && TransactionTypeEnum::WITHDRAWAL->value === $type ) { $billId = (int)($this->data['bill_id'] ?? 0); @@ -477,7 +477,7 @@ class JournalUpdateService private function updateField(string $fieldName): void { if (array_key_exists($fieldName, $this->data) && '' !== (string)$this->data[$fieldName]) { - $value = $this->data[$fieldName]; + $value = $this->data[$fieldName]; if ('date' === $fieldName) { if (!$value instanceof Carbon) { @@ -574,7 +574,7 @@ class JournalUpdateService if ($this->hasFields([$field])) { $value = '' === $this->data[$field] ? null : $this->data[$field]; Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value)); - $set = [ + $set = [ 'journal' => $this->transactionJournal, 'name' => $field, 'data' => $value, @@ -593,7 +593,7 @@ class JournalUpdateService if ($this->hasFields([$field])) { try { $value = '' === (string)$this->data[$field] ? null : new Carbon($this->data[$field]); - } catch (InvalidDateException | InvalidFormatException $e) { // @phpstan-ignore-line + } catch (InvalidDateException|InvalidFormatException $e) { // @phpstan-ignore-line Log::debug(sprintf('%s is not a valid date value: %s', $this->data[$field], $e->getMessage())); return; @@ -622,19 +622,19 @@ class JournalUpdateService if (!$this->hasFields(['currency_id', 'currency_code'])) { return; } - $currencyId = $this->data['currency_id'] ?? null; - $currencyCode = $this->data['currency_code'] ?? null; - $currency = $this->currencyRepository->findCurrency($currencyId, $currencyCode); + $currencyId = $this->data['currency_id'] ?? null; + $currencyCode = $this->data['currency_code'] ?? null; + $currency = $this->currencyRepository->findCurrency($currencyId, $currencyCode); // update currency everywhere. $this->transactionJournal->transaction_currency_id = $currency->id; $this->transactionJournal->save(); - $source = $this->getSourceTransaction(); - $source->transaction_currency_id = $currency->id; + $source = $this->getSourceTransaction(); + $source->transaction_currency_id = $currency->id; $source->save(); - $dest = $this->getDestinationTransaction(); - $dest->transaction_currency_id = $currency->id; + $dest = $this->getDestinationTransaction(); + $dest->transaction_currency_id = $currency->id; $dest->save(); // refresh transactions. @@ -650,7 +650,7 @@ class JournalUpdateService return; } - $value = $this->data['amount'] ?? ''; + $value = $this->data['amount'] ?? ''; Log::debug(sprintf('Amount is now "%s"', $value)); try { @@ -664,28 +664,31 @@ class JournalUpdateService $origSourceTransaction->amount = app('steam')->negative($amount); $origSourceTransaction->balance_dirty = true; $origSourceTransaction->save(); - $destTransaction = $this->getDestinationTransaction(); - $originalAmount = $destTransaction->amount; - $destTransaction->amount = app('steam')->positive($amount); - $destTransaction->balance_dirty = true; + $destTransaction = $this->getDestinationTransaction(); + $originalAmount = $destTransaction->amount; + $destTransaction->amount = app('steam')->positive($amount); + $destTransaction->balance_dirty = true; $destTransaction->save(); // refresh transactions. $this->sourceTransaction->refresh(); $this->destinationTransaction->refresh(); Log::debug(sprintf('Updated amount to "%s"', $amount)); - event(new TriggeredAuditLog($this->transactionGroup->user, $this->transactionGroup, 'update_amount', - [ - 'currency_symbol' => $destTransaction->transactionCurrency->symbol, - 'decimal_places' => $destTransaction->transactionCurrency->decimal_places, - 'amount' => $originalAmount, - ], - [ - 'currency_symbol' => $destTransaction->transactionCurrency->symbol, - 'decimal_places' => $destTransaction->transactionCurrency->decimal_places, - 'amount' => $value, - ] - )); + event(new TriggeredAuditLog( + $this->transactionGroup->user, + $this->transactionGroup, + 'update_amount', + [ + 'currency_symbol' => $destTransaction->transactionCurrency->symbol, + 'decimal_places' => $destTransaction->transactionCurrency->decimal_places, + 'amount' => $originalAmount, + ], + [ + 'currency_symbol' => $destTransaction->transactionCurrency->symbol, + 'decimal_places' => $destTransaction->transactionCurrency->decimal_places, + 'amount' => $value, + ] + )); } @@ -724,9 +727,9 @@ class JournalUpdateService // if the transaction is a TRANSFER, and the foreign amount and currency are set (like they seem to be) // the correct fields to update in the destination transaction are NOT the foreign amount and currency // but rather the normal amount and currency. This is new behavior. - $isTransfer = TransactionTypeEnum::TRANSFER->value === $this->transactionJournal->transactionType->type; + $isTransfer = TransactionTypeEnum::TRANSFER->value === $this->transactionJournal->transactionType->type; // also check if it is not between an asset account and a liability, because then the same rule applies. - $isBetween = $this->isBetweenAssetAndLiability(); + $isBetween = $this->isBetweenAssetAndLiability(); if ($isTransfer || $isBetween) { Log::debug('Switch amounts, store in amount and not foreign_amount'); @@ -762,8 +765,8 @@ class JournalUpdateService $source->foreign_amount = null; $source->save(); - $dest->foreign_currency_id = null; - $dest->foreign_amount = null; + $dest->foreign_currency_id = null; + $dest->foreign_amount = null; $dest->save(); Log::debug(sprintf('Foreign amount is "%s" so remove foreign amount info.', $amount)); } @@ -777,7 +780,7 @@ class JournalUpdateService private function isBetweenAssetAndLiability(): bool { /** @var null|Transaction $sourceTransaction */ - $sourceTransaction = $this->transactionJournal->transactions()->where('amount', '<', 0)->first(); + $sourceTransaction = $this->transactionJournal->transactions()->where('amount', '<', 0)->first(); /** @var null|Transaction $destinationTransaction */ $destinationTransaction = $this->transactionJournal->transactions()->where('amount', '>', 0)->first(); @@ -792,15 +795,15 @@ class JournalUpdateService return false; } - $source = $sourceTransaction->account; - $destination = $destinationTransaction->account; + $source = $sourceTransaction->account; + $destination = $destinationTransaction->account; if (null === $source || null === $destination) { Log::warning('Either is false, stop.'); return false; } - $sourceTypes = [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value]; + $sourceTypes = [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value]; // source is liability, destination is asset if (in_array($source->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $destination->accountType->type) { diff --git a/composer.lock b/composer.lock index 0f738f9188..89b32d86fc 100644 --- a/composer.lock +++ b/composer.lock @@ -3543,22 +3543,22 @@ }, { "name": "mailersend/laravel-driver", - "version": "v2.9.1", + "version": "v2.12.0", "source": { "type": "git", "url": "https://github.com/mailersend/mailersend-laravel-driver.git", - "reference": "87fd5ab76808bbaac9221be0d306baef13e98725" + "reference": "15e1ec41e29e65d3ca226929c65804190aaa93eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/87fd5ab76808bbaac9221be0d306baef13e98725", - "reference": "87fd5ab76808bbaac9221be0d306baef13e98725", + "url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/15e1ec41e29e65d3ca226929c65804190aaa93eb", + "reference": "15e1ec41e29e65d3ca226929c65804190aaa93eb", "shasum": "" }, "require": { "ext-json": "*", "illuminate/support": "^9.0 || ^10.0 || ^11.0 || ^12.0", - "mailersend/mailersend": "^0.31.0", + "mailersend/mailersend": "^0.35.0", "nyholm/psr7": "^1.5", "php": ">=8.0", "php-http/guzzle7-adapter": "^1.0", @@ -3606,29 +3606,28 @@ ], "support": { "issues": "https://github.com/mailersend/mailersend-laravel-driver/issues", - "source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.9.1" + "source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.12.0" }, - "time": "2025-04-09T09:33:07+00:00" + "time": "2025-10-28T14:59:16+00:00" }, { "name": "mailersend/mailersend", - "version": "v0.31.0", + "version": "v0.35.0", "source": { "type": "git", "url": "https://github.com/mailersend/mailersend-php.git", - "reference": "513ff83ee768526055ad52987cde401ea7218c67" + "reference": "f1696cf9e727e9503fbc5882d2a111bd966ad276" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/513ff83ee768526055ad52987cde401ea7218c67", - "reference": "513ff83ee768526055ad52987cde401ea7218c67", + "url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/f1696cf9e727e9503fbc5882d2a111bd966ad276", + "reference": "f1696cf9e727e9503fbc5882d2a111bd966ad276", "shasum": "" }, "require": { "beberlei/assert": "^3.2", "ext-json": "*", - "illuminate/collections": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0", - "php": "^7.4|^8.0", + "php": "^7.4 || ^8.0 <8.5", "php-http/client-common": "^2.2", "php-http/discovery": "^1.9", "php-http/httplug": "^2.1", @@ -3673,9 +3672,9 @@ ], "support": { "issues": "https://github.com/mailersend/mailersend-php/issues", - "source": "https://github.com/mailersend/mailersend-php/tree/v0.31.0" + "source": "https://github.com/mailersend/mailersend-php/tree/v0.35.0" }, - "time": "2025-04-03T12:16:11+00:00" + "time": "2025-10-28T13:11:43+00:00" }, { "name": "monolog/monolog", diff --git a/config/firefly.php b/config/firefly.php index 0b8046ea09..9be3e6f6dc 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -78,8 +78,8 @@ return [ 'running_balance_column' => env('USE_RUNNING_BALANCE', false), // see cer.php for exchange rates feature flag. ], - 'version' => 'develop/2025-12-06', - 'build_time' => 1765004025, + 'version' => 'develop/2025-12-07', + 'build_time' => 1765124451, '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 1b4ec416ab..76fe40a3b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4075,9 +4075,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.3.tgz", - "integrity": "sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.4.tgz", + "integrity": "sha512-ZCQ9GEWl73BVm8bu5Fts8nt7MHdbt5vY9bP6WGnUh+r3l8M7CgfyTlwsgCbMC66BNxPr6Xoce3j66Ms5YUQTNA==", "dev": true, "license": "Apache-2.0", "bin": {