Compare commits

...

16 Commits

Author SHA1 Message Date
github-actions[bot]
8735be2f6b Merge pull request #11676 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2026-02-08 08:27:47 +01:00
github-actions[bot]
0e8cc91308 Merge pull request #11675 from firefly-iii/release-1770535655
🤖 Automatically merge the PR into the develop branch.
2026-02-08 08:27:42 +01:00
JC5
5cbb311e4d 🤖 Auto commit for release 'v6.4.18' on 2026-02-08 2026-02-08 08:27:35 +01:00
James Cole
c334641b90 Add class reference. 2026-02-08 08:21:24 +01:00
James Cole
4c2356881d Remove unused debug logging. 2026-02-08 08:20:50 +01:00
James Cole
d9a0d06712 Clean up some debug logging. 2026-02-08 08:16:33 +01:00
github-actions[bot]
65b9dedc03 Merge pull request #11674 from firefly-iii/release-1770534470
🤖 Automatically merge the PR into the develop branch.
2026-02-08 08:07:56 +01:00
JC5
e46ef138b1 🤖 Auto commit for release 'develop' on 2026-02-08 2026-02-08 08:07:50 +01:00
James Cole
f0fdb57754 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2026-02-08 08:04:05 +01:00
James Cole
09799582aa Remove debug comments. 2026-02-08 08:03:59 +01:00
github-actions[bot]
850c824da1 Merge pull request #11673 from firefly-iii/release-1770531358
🤖 Automatically merge the PR into the develop branch.
2026-02-08 07:16:05 +01:00
JC5
34160da67a 🤖 Auto commit for release 'develop' on 2026-02-08 2026-02-08 07:15:58 +01:00
James Cole
2848a64c13 Fix sponsorship link. 2026-02-08 07:11:24 +01:00
James Cole
998d6bf874 Fix #11668 2026-02-08 06:49:27 +01:00
James Cole
b85200e1f6 Fix #11667 2026-02-08 06:46:14 +01:00
James Cole
6944001887 Fix #11671 2026-02-08 06:22:40 +01:00
34 changed files with 245 additions and 79 deletions

BIN
.github/assets/img/testmu.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -36,6 +36,7 @@ class UpdatedExistingAccount extends Event
* Create a new event instance.
*/
public function __construct(
public Account $account
public Account $account,
public array $oldData
) {}
}

View File

@@ -433,7 +433,7 @@ class GroupCollector implements GroupCollectorInterface
*/
public function getGroups(): Collection
{
Log::debug('Now in getGroups()');
// Log::debug('Now in getGroups()');
if ($this->expandGroupSearch) {
// get group ID's for the query:
$groupIds = $this->getCollectedGroupIds();
@@ -556,7 +556,7 @@ class GroupCollector implements GroupCollectorInterface
if (0 !== count($journalIds)) {
// make all integers.
$integerIDs = array_map(intval(...), $journalIds);
Log::debug(sprintf('GroupCollector: setJournalIds: %s', implode(', ', $integerIDs)));
// Log::debug(sprintf('GroupCollector: setJournalIds: %s', implode(', ', $integerIDs)));
$this->query->whereIn('transaction_journals.id', $integerIDs);
}

View File

@@ -74,8 +74,8 @@ class IndexController extends Controller
$this->cleanupObjectGroups();
$this->repository->correctOrder();
$this->repository->correctTransfers();
$start = session('start');
$end = session('end');
$start = session('start')->clone();
$end = session('end')->clone();
$viewRange = Preferences::get('viewRange', '1M')->data;
// give the end some extra space when the user has last7, last30 or last90.

View File

@@ -167,7 +167,7 @@ class CreateAutoBudgetLimits implements ShouldQueue
/** @var BudgetLimitRepositoryInterface $repository */
$repository = app(BudgetLimitRepositoryInterface::class);
$repository->setUserGroup($autoBudget->budget->user->userGroup);
$repository->setUser($autoBudget->budget->user);
$budgetLimit = $repository->store([
'currency_id' => $autoBudget->transaction_currency_id,

View File

@@ -29,7 +29,11 @@ use FireflyIII\Events\Model\Account\UpdatedExistingAccount;
use FireflyIII\Handlers\ExchangeRate\ConversionParameters;
use FireflyIII\Handlers\ExchangeRate\ConvertsAmountToPrimaryAmount;
use FireflyIII\Models\Account;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Services\Internal\Support\CreditRecalculateService;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Log;
@@ -40,6 +44,89 @@ class UpdatesAccountInformation implements ShouldQueue
{
$this->recalculateCredit($event->account);
$this->updateVirtualBalance($event->account);
if ($event instanceof UpdatedExistingAccount) {
$this->renameRules($event->account, $event->oldData);
}
}
private function correctRuleActions(Account $account, array $oldData, Rule $rule): void
{
$fields = ['set_source_account', 'set_destination_account'];
Log::debug(sprintf('Check if rule #%d actions reference account #%d "%s"', $rule->id, $account->id, $account->name));
$fixed = 0;
/** @var RuleAction $action */
foreach ($rule->ruleActions as $action) {
// fix name:
if ($oldData['name'] === $action->action_value && in_array($action->action_type, $fields, true)) {
Log::debug(sprintf('Rule action #%d "%s" has old account name, replace with new.', $action->id, $action->action_type));
$action->action_value = $account->name;
$action->save();
++$fixed;
}
}
Log::debug(sprintf('Corrected %d action(s) for rule #%d', $fixed, $rule->id));
}
private function correctRuleTriggers(Account $account, array $oldData, Rule $rule): void
{
$nameFields = [
'source_account_is',
'source_account_contains',
'source_account_ends',
'source_account_starts',
'destination_account_is',
'destination_account_contains',
'destination_account_ends',
'destination_account_starts',
'account_is',
'account_contains',
'account_ends',
'account_starts',
];
$numberFields = [
'source_account_nr_is',
'source_account_nr_contains',
'source_account_nr_ends',
'source_account_nr_starts',
'destination_account_nr_is',
'destination_account_nr_contains',
'destination_account_nr_starts',
'account_nr_is',
'account_nr_contains',
'account_nr_ends',
'account_nr_starts',
];
Log::debug(sprintf('Check if rule #%d triggers reference account #%d "%s"', $rule->id, $account->id, $account->name));
$fixed = 0;
/** @var RuleTrigger $trigger */
foreach ($rule->ruleTriggers as $trigger) {
// fix name:
if ($oldData['name'] === $trigger->trigger_value && in_array($trigger->trigger_type, $nameFields, true)) {
Log::debug(sprintf('Rule trigger #%d "%s" has old account name, replace with new.', $trigger->id, $trigger->trigger_type));
$trigger->trigger_value = $account->name;
$trigger->save();
++$fixed;
}
// fix IBAN:
if ($oldData['iban'] === $trigger->trigger_value && in_array($trigger->trigger_type, $numberFields, true)) {
Log::debug(sprintf('Rule trigger #%d "%s" has old account IBAN, replace with new.', $trigger->id, $trigger->trigger_type));
$trigger->trigger_value = $account->iban;
$trigger->save();
++$fixed;
}
// fix account number: // account_number
if ($oldData['account_number'] === $trigger->trigger_value && in_array($trigger->trigger_type, $numberFields, true)) {
Log::debug(sprintf('Rule trigger #%d "%s" has old account account_number, replace with new.', $trigger->id, $trigger->trigger_type));
$trigger->trigger_value = $account->iban;
$trigger->save();
++$fixed;
}
}
Log::debug(sprintf('Corrected %d trigger(s) for rule #%d', $fixed, $rule->id));
}
private function recalculateCredit(Account $account): void
@@ -52,6 +139,20 @@ class UpdatesAccountInformation implements ShouldQueue
$object->recalculate();
}
private function renameRules(Account $account, array $oldData): void
{
Log::debug('Updated account, will now correct rules.');
$repository = app(RuleRepositoryInterface::class);
$repository->setUser($account->user);
$rules = $repository->getAll();
/** @var Rule $rule */
foreach ($rules as $rule) {
$this->correctRuleTriggers($account, $oldData, $rule);
$this->correctRuleActions($account, $oldData, $rule);
}
}
private function updateVirtualBalance(Account $account): void
{
Log::debug('Will updateVirtualBalance');

View File

@@ -40,7 +40,7 @@ trait SupportsGroupProcessingTrait
$first = $set->first();
$journalIds = implode(',', $array);
$user = $first->user;
Log::debug(sprintf('Add local operator for journal(s): %s', $journalIds));
// Log::debug(sprintf('Add local operator for journal(s): %s', $journalIds));
// collect rules:
$ruleGroupRepository = app(RuleGroupRepositoryInterface::class);

View File

@@ -85,7 +85,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?Collection $budgets = null,
?TransactionCurrency $currency = null
): array {
Log::debug(sprintf('Start of %s(%s, %s, array, array, "%s").', __METHOD__, $start->toW3cString(), $end->toW3cString(), $currency?->code));
// Log::debug(sprintf('Start of %s(%s, %s, array, array, "%s").', __METHOD__, $start->toW3cString(), $end->toW3cString(), $currency?->code));
// this collector excludes all transfers TO liabilities (which are also withdrawals)
// because those expenses only become expenses once they move from the liability to the friend.
// 2024-12-24 disable the exclusion for now.
@@ -275,7 +275,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
TransactionCurrency $transactionCurrency,
bool $convertToPrimary = false
): array {
Log::debug(sprintf('Start of %s.', __METHOD__));
// Log::debug(sprintf('Start of %s.', __METHOD__));
$summarizer = new TransactionSummarizer($this->user);
$summarizer->setConvertToPrimary($convertToPrimary);
@@ -290,7 +290,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
public function sumCollectedExpensesByBudget(array $expenses, Budget $budget, bool $convertToPrimary = false): array
{
Log::debug(sprintf('Start of %s.', __METHOD__));
// Log::debug(sprintf('Start of %s.', __METHOD__));
$summarizer = new TransactionSummarizer($this->user);
$summarizer->setConvertToPrimary($convertToPrimary);
@@ -311,7 +311,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?TransactionCurrency $currency = null,
bool $convertToPrimary = false
): array {
Log::debug(sprintf('Start of %s(date, date, array, array, "%s", %s).', __METHOD__, $currency?->code, var_export($convertToPrimary, true)));
// Log::debug(sprintf('Start of %s(date, date, array, array, "%s", %s).', __METHOD__, $currency?->code, var_export($convertToPrimary, true)));
// this collector excludes all transfers TO liabilities (which are also withdrawals)
// because those expenses only become expenses once they move from the liability to the friend.
// 2024-12-24 disable the exclusion for now.

View File

@@ -372,7 +372,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
public function sumCollectedTransactionsByCategory(array $expenses, Category $category, string $method, bool $convertToPrimary = false): array
{
Log::debug(sprintf('Start of %s.', __METHOD__));
// Log::debug(sprintf('Start of %s.', __METHOD__));
$summarizer = new TransactionSummarizer($this->user);
$summarizer->setConvertToPrimary($convertToPrimary);

View File

@@ -195,21 +195,21 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
if (null === $filter) {
return $groups;
}
Log::debug(sprintf('Will filter getRuleGroupsWithRules on "%s".', $filter));
// Log::debug(sprintf('Will filter getRuleGroupsWithRules on "%s".', $filter));
return $groups->map(static function (RuleGroup $group) use ($filter): RuleGroup { // @phpstan-ignore-line
Log::debug(sprintf('Now filtering group #%d', $group->id));
// Log::debug(sprintf('Now filtering group #%d', $group->id));
// filter the rules in the rule group:
$group->rules = $group->rules->filter(static function (Rule $rule) use ($filter, $group): bool {
Log::debug(sprintf('Now filtering rule #%d', $rule->id));
$group->rules = $group->rules->filter(static function (Rule $rule) use ($filter): bool {
// Log::debug(sprintf('Now filtering rule #%d', $rule->id));
foreach ($rule->ruleTriggers as $trigger) {
if ('user_action' === $trigger->trigger_type && $filter === $trigger->trigger_value) {
Log::debug(sprintf('Rule #%d triggers on %s, include it in rule group #%d.', $rule->id, $filter, $group->id));
// Log::debug(sprintf('Rule #%d triggers on %s, include it in rule group #%d.', $rule->id, $filter, $group->id));
return true;
}
}
Log::debug(sprintf('Rule #%d does not trigger on %s, do not include it.', $rule->id, $filter));
// Log::debug(sprintf('Rule #%d does not trigger on %s, do not include it.', $rule->id, $filter));
return false;
});
@@ -251,18 +251,18 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
Log::debug(sprintf('Will filter getRuleGroupsWithRules on "%s".', $filter));
return $groups->map(static function (RuleGroup $group) use ($filter): RuleGroup { // @phpstan-ignore-line
Log::debug(sprintf('Now filtering group #%d', $group->id));
// Log::debug(sprintf('Now filtering group #%d', $group->id));
// filter the rules in the rule group:
$group->rules = $group->rules->filter(static function (Rule $rule) use ($filter, $group): bool {
Log::debug(sprintf('Now filtering rule #%d', $rule->id));
$group->rules = $group->rules->filter(static function (Rule $rule) use ($filter): bool {
// Log::debug(sprintf('Now filtering rule #%d', $rule->id));
foreach ($rule->ruleTriggers as $trigger) {
if ('user_action' === $trigger->trigger_type && $filter === $trigger->trigger_value) {
Log::debug(sprintf('Rule #%d triggers on %s, include it in rule group #%d.', $rule->id, $filter, $group->id));
// Log::debug(sprintf('Rule #%d triggers on %s, include it in rule group #%d.', $rule->id, $filter, $group->id));
return true;
}
}
Log::debug(sprintf('Rule #%d does not trigger on %s, do not include it.', $rule->id, $filter));
// Log::debug(sprintf('Rule #%d does not trigger on %s, do not include it.', $rule->id, $filter));
return false;
});

View File

@@ -78,9 +78,11 @@ class AccountUpdateService
{
Log::debug(sprintf('Now in %s', __METHOD__));
$this->accountRepository->setUser($account->user);
$this->user = $account->user;
$account = $this->updateAccount($account, $data);
$account = $this->updateAccountOrder($account, $data);
$this->user = $account->user;
$oldData = $account->toArray();
$oldData['account_number'] = $this->accountRepository->getMetaValue($account, 'account_number');
$account = $this->updateAccount($account, $data);
$account = $this->updateAccountOrder($account, $data);
// find currency, or use default currency instead.
if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) {
@@ -109,7 +111,7 @@ class AccountUpdateService
// update preferences if inactive:
$this->updatePreferences($account);
event(new UpdatedExistingAccount($account));
event(new UpdatedExistingAccount($account, $oldData));
return $account;
}

View File

@@ -42,6 +42,9 @@ class Calculator
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private static array $intervals = [];
public function isAvailablePeriodicity(Periodicity $periodicity): bool

View File

@@ -102,6 +102,12 @@ class ExportDataGenerator
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
public function __construct()
{
$this->accounts = new Collection();

View File

@@ -87,6 +87,9 @@ trait PeriodOverview
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
private array $transactions; // temp data holder
// temp data holder
@@ -101,6 +104,12 @@ trait PeriodOverview
// temp data holder
// temp data holder
// temp data holder
// temp data holder
/**
* This method returns "period entries", so nov-2015, dec-2015, etc. (this depends on the users session range)
* and for each period, the amount of money spent and earned. This is a complex operation which is cached for

View File

@@ -92,7 +92,7 @@ class AccountEnrichment implements EnrichmentInterface
*/
public function enrich(Collection $collection): Collection
{
Log::debug(sprintf('Now doing account enrichment for %d account(s)', $collection->count()));
// Log::debug(sprintf('Now doing account enrichment for %d account(s)', $collection->count()));
// prep local fields
$this->collection = $collection;

View File

@@ -47,6 +47,9 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private readonly bool $convertToPrimary; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
@@ -54,6 +57,9 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $currencies = [];
private array $currencyIds = [];
private array $ids = [];

View File

@@ -47,6 +47,9 @@ class BudgetLimitEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $currencies = [];
private array $currencyIds = [];
private Carbon $end;

View File

@@ -63,7 +63,7 @@ class CategoryEnrichment implements EnrichmentInterface
public function enrichSingle(array|Model $model): array|Model
{
Log::debug(__METHOD__);
// Log::debug(__METHOD__);
$collection = new Collection()->push($model);
$collection = $this->enrich($collection);

View File

@@ -49,6 +49,9 @@ class PiggyBankEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $accounts = []; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
@@ -56,6 +59,9 @@ class PiggyBankEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $amounts = [];
private Collection $collection;
private array $currencies = [];

View File

@@ -44,6 +44,9 @@ class PiggyBankEventEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $accountIds = []; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
@@ -51,6 +54,9 @@ class PiggyBankEventEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private Collection $collection;
private array $currencies = [];
private array $groupIds = [];

View File

@@ -53,6 +53,9 @@ class SubscriptionEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private readonly bool $convertToPrimary;
private ?Carbon $end = null;
private array $mappedObjects = [];

View File

@@ -67,6 +67,12 @@ class TransactionGroupEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
public function __construct()
{
$this->dateFields = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date'];
@@ -76,7 +82,7 @@ class TransactionGroupEnrichment implements EnrichmentInterface
#[Override]
public function enrich(Collection $collection): Collection
{
Log::debug(sprintf('Now doing account enrichment for %d transaction group(s)', $collection->count()));
// Log::debug(sprintf('Now doing account enrichment for %d transaction group(s)', $collection->count()));
// prep local fields
$this->collection = $collection;
$this->collectJournalIds();

View File

@@ -49,6 +49,9 @@ class WebhookEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $ids = []; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
@@ -56,6 +59,9 @@ class WebhookEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $responses = [];
private array $triggers = [];
private array $webhookDeliveries = [];

View File

@@ -78,7 +78,7 @@ class AccountBalanceCalculator
]);
if (null === $first) {
Log::debug(sprintf('Found no transactions for currency #%d and account #%d, return 0.', $currencyId, $accountId));
// Log::debug(sprintf('Found no transactions for currency #%d and account #%d, return 0.', $currencyId, $accountId));
return '0';
}

View File

@@ -45,7 +45,7 @@ class TransactionSummarizer
public function groupByCurrencyId(array $journals, string $method = 'negative', bool $includeForeign = true): array
{
Log::debug(sprintf('Now in groupByCurrencyId([%d journals], "%s", %s)', count($journals), $method, var_export($includeForeign, true)));
// Log::debug(sprintf('Now in groupByCurrencyId([%d journals], "%s", %s)', count($journals), $method, var_export($includeForeign, true)));
$array = [];
foreach ($journals as $journal) {
$field = 'amount';
@@ -146,7 +146,7 @@ class TransactionSummarizer
// $array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], \FireflyIII\Support\Facades\Steam::{$method}($amount));
// Log::debug(sprintf('Journal #%d adds amount %s %s', $journal['transaction_journal_id'], $currencyCode, $amount));
}
Log::debug('End of sumExpenses.', $array);
// Log::debug('End of sumExpenses.', $array);
return $array;
}
@@ -234,7 +234,7 @@ class TransactionSummarizer
public function setConvertToPrimary(bool $convertToPrimary): void
{
Log::debug(sprintf('Overrule convertToPrimary to become %s', var_export($convertToPrimary, true)));
// Log::debug(sprintf('Overrule convertToPrimary to become %s', var_export($convertToPrimary, true)));
$this->convertToPrimary = $convertToPrimary;
}

View File

@@ -39,14 +39,14 @@ trait ChecksLogin
*/
public function authorize(): bool
{
Log::debug(sprintf('Now in %s', __METHOD__));
// Log::debug(sprintf('Now in %s', __METHOD__));
// Only allow logged-in users
$check = auth()->check();
if (!$check) {
return false;
}
if (!property_exists($this, 'acceptedRoles')) { // @phpstan-ignore-line
Log::debug('Request class has no acceptedRoles array');
Log::debug(sprintf('Request class %s has no acceptedRoles array', static::class));
return true; // check for false already took place.
}
@@ -81,15 +81,15 @@ trait ChecksLogin
{
/** @var User $user */
$user = auth()->user();
Log::debug('Now in getUserGroup()');
// Log::debug('Now in getUserGroup()');
/** @var null|UserGroup $userGroup */
$userGroup = $this->route()?->parameter('userGroup');
if (null === $userGroup) {
Log::debug('Request class has no userGroup parameter, but perhaps there is a parameter.');
// Log::debug('Request class has no userGroup parameter, but perhaps there is a parameter.');
$userGroupId = (int) $this->get('user_group_id');
if (0 === $userGroupId) {
Log::debug(sprintf('Request class has no user_group_id parameter, grab default from user (group #%d).', $user->user_group_id));
// Log::debug(sprintf('Request class has no user_group_id parameter, grab default from user (group #%d).', $user->user_group_id));
$userGroupId = (int) $user->user_group_id;
}
$userGroup = UserGroup::find($userGroupId);
@@ -98,7 +98,8 @@ trait ChecksLogin
return null;
}
Log::debug('Request class has valid user_group_id.');
// Log::debug('Request class has valid user_group_id.');
}
return $userGroup;

View File

@@ -122,11 +122,11 @@ class OperatorQuerySearch implements SearchInterface
if (str_starts_with($original, '-')) {
$return = sprintf('-%s', $config['alias_for']);
}
Log::debug(sprintf('"%s" is an alias for "%s", so return that instead.', $original, $return));
// Log::debug(sprintf('"%s" is an alias for "%s", so return that instead.', $original, $return));
return $return;
}
Log::debug(sprintf('"%s" is not an alias.', $operator));
// Log::debug(sprintf('"%s" is not an alias.', $operator));
return $original;
}
@@ -174,7 +174,7 @@ class OperatorQuerySearch implements SearchInterface
*/
public function parseQuery(string $query): void
{
Log::debug(sprintf('Now in parseQuery("%s")', $query));
// Log::debug(sprintf('Now in parseQuery("%s")', $query));
/** @var QueryParserInterface $parser */
$parser = app(QueryParserInterface::class);

View File

@@ -39,7 +39,7 @@ class QueryParser implements QueryParserInterface
public function parse(string $query): NodeGroup
{
Log::debug(sprintf('Parsing query in QueryParser: "%s"', $query));
// Log::debug(sprintf('Parsing query in QueryParser: "%s"', $query));
$this->query = $query;
$this->position = 0;
@@ -78,7 +78,7 @@ class QueryParser implements QueryParserInterface
}
// char is "
++$this->position;
Log::debug(sprintf('Constructed token: %s', $tokenUnderConstruction));
// Log::debug(sprintf('Constructed token: %s', $tokenUnderConstruction));
return new NodeResult($this->createNode($tokenUnderConstruction, $fieldName, $prohibited), false);
}
@@ -200,11 +200,11 @@ class QueryParser implements QueryParserInterface
$token = rtrim($token, '"');
}
$token = str_replace('\"', '"', $token);
Log::debug(sprintf('Create FieldNode %s:%s (%s)', $fieldName, $token, var_export($prohibited, true)));
// Log::debug(sprintf('Create FieldNode %s:%s (%s)', $fieldName, $token, var_export($prohibited, true)));
return new FieldNode(trim($fieldName), trim($token), $prohibited);
}
Log::debug(sprintf('Create StringNode "%s" (%s)', $token, var_export($prohibited, true)));
// F Now in handleSearchNodeLog::debug(sprintf('Create StringNode "%s" (%s)', $token, var_export($prohibited, true)));
return new StringNode(trim($token), $prohibited);
}

View File

@@ -60,7 +60,7 @@ class SearchRuleEngine implements RuleEngineInterface
public function addOperator(array $operator): void
{
Log::debug('Add extra operator: ', $operator);
// Log::debug('Add extra operator: ', $operator);
$this->operators[] = $operator;
}

View File

@@ -3,6 +3,13 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## v6.4.18
### Fixed
- [Discussion 11671](https://github.com/orgs/firefly-iii/discussions/11671) (Subscriptions Next Expected Match) started by @idgaron
- [Issue 11667](https://github.com/firefly-iii/firefly-iii/issues/11667) (Account names and numbers are not corrected in rules when the account is updated) reported by @Kage1
- [Issue 11668](https://github.com/firefly-iii/firefly-iii/issues/11668) (Auto-budget cron crashes on develop: Call to a member function budgets() on null (BudgetLimitRepository.php:311)) reported by @sykmer
## v6.4.17 - 2026-02-06
### Added

42
composer.lock generated
View File

@@ -130,16 +130,16 @@
},
{
"name": "brick/math",
"version": "0.14.6",
"version": "0.14.7",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "32498d5e1897e7642c0b961ace2df6d7dc9a3bc3"
"reference": "07ff363b16ef8aca9692bba3be9e73fe63f34e50"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/32498d5e1897e7642c0b961ace2df6d7dc9a3bc3",
"reference": "32498d5e1897e7642c0b961ace2df6d7dc9a3bc3",
"url": "https://api.github.com/repos/brick/math/zipball/07ff363b16ef8aca9692bba3be9e73fe63f34e50",
"reference": "07ff363b16ef8aca9692bba3be9e73fe63f34e50",
"shasum": ""
},
"require": {
@@ -178,7 +178,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.14.6"
"source": "https://github.com/brick/math/tree/0.14.7"
},
"funding": [
{
@@ -186,7 +186,7 @@
"type": "github"
}
],
"time": "2026-02-05T07:59:58+00:00"
"time": "2026-02-07T10:57:35+00:00"
},
{
"name": "carbonphp/carbon-doctrine-types",
@@ -3829,16 +3829,16 @@
},
{
"name": "nette/schema",
"version": "v1.3.3",
"version": "v1.3.4",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
"reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004"
"reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004",
"reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004",
"url": "https://api.github.com/repos/nette/schema/zipball/086497a2f34b82fede9b5a41cc8e131d087cd8f7",
"reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7",
"shasum": ""
},
"require": {
@@ -3846,8 +3846,8 @@
"php": "8.1 - 8.5"
},
"require-dev": {
"nette/tester": "^2.5.2",
"phpstan/phpstan-nette": "^2.0@stable",
"nette/tester": "^2.6",
"phpstan/phpstan": "^2.0@stable",
"tracy/tracy": "^2.8"
},
"type": "library",
@@ -3888,9 +3888,9 @@
],
"support": {
"issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.3.3"
"source": "https://github.com/nette/schema/tree/v1.3.4"
},
"time": "2025-10-30T22:57:59+00:00"
"time": "2026-02-08T02:54:00+00:00"
},
{
"name": "nette/utils",
@@ -11908,16 +11908,16 @@
},
{
"name": "phpunit/phpunit",
"version": "12.5.9",
"version": "12.5.10",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "83d4c158526c879b4c5cf7149d27958b6d912373"
"reference": "1686e30f6b32d35592f878a7f56fd0421d7d56c5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/83d4c158526c879b4c5cf7149d27958b6d912373",
"reference": "83d4c158526c879b4c5cf7149d27958b6d912373",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1686e30f6b32d35592f878a7f56fd0421d7d56c5",
"reference": "1686e30f6b32d35592f878a7f56fd0421d7d56c5",
"shasum": ""
},
"require": {
@@ -11931,7 +11931,7 @@
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.3",
"phpunit/php-code-coverage": "^12.5.2",
"phpunit/php-code-coverage": "^12.5.3",
"phpunit/php-file-iterator": "^6.0.1",
"phpunit/php-invoker": "^6.0.0",
"phpunit/php-text-template": "^5.0.0",
@@ -11986,7 +11986,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.9"
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.10"
},
"funding": [
{
@@ -12010,7 +12010,7 @@
"type": "tidelift"
}
],
"time": "2026-02-05T08:01:09+00:00"
"time": "2026-02-08T07:06:48+00:00"
},
{
"name": "rector/rector",

View File

@@ -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' => '6.4.17',
'build_time' => 1770447202,
'version' => '6.4.18',
'build_time' => 1770535525,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used.

6
package-lock.json generated
View File

@@ -3246,9 +3246,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "25.2.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.1.tgz",
"integrity": "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg==",
"version": "25.2.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.2.tgz",
"integrity": "sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -149,13 +149,13 @@ OK, that was a joke. But for real, when you feel Firefly III made your life bett
### Sponsorships
Firefly III is sponsored by LamdaTest. Their support allows me to test Firefly III more easily and introduce even fewer bugs with every release.
Firefly III is sponsored by TestMu AI. Their support allows me to test Firefly III more easily and introduce even fewer bugs with every release.
<p style="font-size:21px; color:black;">Browser testing via
<a href="https://www.lambdatest.com/?utm_source=fireflyiii&utm_medium=sponsor" target="_blank">
<img src="https://www.lambdatest.com/blue-logo.png" style="vertical-align: middle;" width="250" height="45" />
Browser testing via:
<a href="https://www.testmuai.com/?utm_source=fireflyiii&utm_medium=sponsor" target="_blank">
<img src=".github/assets/img/testmu.png" alt="Testmu" style="vertical-align: middle;" width="250" />
</a>
</p>
<!-- END OF SPONSOR TEXT -->