From e37ef694913bc775b95b085fbb82da3396fe442e Mon Sep 17 00:00:00 2001 From: JC5 Date: Fri, 6 Feb 2026 18:26:14 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Auto=20commit=20for=20release=20?= =?UTF-8?q?'develop'=20on=202026-02-06?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RuleGroup/ExecutionController.php | 24 +- .../Transaction/ShowController.php | 7 +- .../Budget/BudgetLimitRepository.php | 135 +++++----- .../Internal/Support/AccountServiceTrait.php | 246 +++++++++--------- app/Support/Calendar/Calculator.php | 1 + app/Support/Export/ExportDataGenerator.php | 2 + .../Http/Controllers/PeriodOverview.php | 3 + .../Enrichments/AvailableBudgetEnrichment.php | 2 + .../Enrichments/BudgetLimitEnrichment.php | 1 + .../Enrichments/PiggyBankEnrichment.php | 2 + .../Enrichments/PiggyBankEventEnrichment.php | 2 + .../Enrichments/SubscriptionEnrichment.php | 1 + .../TransactionGroupEnrichment.php | 2 + .../JsonApi/Enrichments/WebhookEnrichment.php | 2 + .../Engine/SearchRuleEngine.php | 5 +- changelog.md | 26 +- composer.lock | 14 +- config/firefly.php | 2 +- 18 files changed, 255 insertions(+), 222 deletions(-) diff --git a/app/Http/Controllers/RuleGroup/ExecutionController.php b/app/Http/Controllers/RuleGroup/ExecutionController.php index 7351d9aed2..3845bd0e55 100644 --- a/app/Http/Controllers/RuleGroup/ExecutionController.php +++ b/app/Http/Controllers/RuleGroup/ExecutionController.php @@ -43,7 +43,7 @@ use Illuminate\View\View; */ class ExecutionController extends Controller { - private readonly AccountRepositoryInterface $repository; + private readonly AccountRepositoryInterface $repository; private readonly RuleGroupRepositoryInterface $ruleGroupRepository; /** @@ -55,7 +55,7 @@ class ExecutionController extends Controller $this->repository = app(AccountRepositoryInterface::class); $this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class); $this->middleware(function ($request, $next) { - app('view')->share('title', (string)trans('firefly.rules')); + app('view')->share('title', (string) trans('firefly.rules')); app('view')->share('mainTitleIcon', 'fa-random'); $this->repository->setUser(auth()->user()); $this->ruleGroupRepository->setUser(auth()->user()); @@ -75,8 +75,8 @@ class ExecutionController extends Controller // start code /** @var User $user */ - $user = auth()->user(); - $accounts = implode(',', $request->get('accounts')); + $user = auth()->user(); + $accounts = implode(',', $request->get('accounts')); // create new rule engine: $newRuleEngine = app(RuleEngineInterface::class); $newRuleEngine->setUser($user); @@ -84,22 +84,22 @@ class ExecutionController extends Controller // add date operators. if (null !== $request->get('start')) { $startDate = new Carbon($request->get('start')); - $newRuleEngine->addOperator(['type' => 'date_after', 'value' => $startDate->format('Y-m-d')]); + $newRuleEngine->addOperator(['type' => 'date_after', 'value' => $startDate->format('Y-m-d')]); } if (null !== $request->get('end')) { $endDate = new Carbon($request->get('end')); - $newRuleEngine->addOperator(['type' => 'date_before', 'value' => $endDate->format('Y-m-d')]); + $newRuleEngine->addOperator(['type' => 'date_before', 'value' => $endDate->format('Y-m-d')]); } // add extra operators: - $newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]); + $newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]); // set rules: - $rules = $this->ruleGroupRepository->getActiveRules($ruleGroup); + $rules = $this->ruleGroupRepository->getActiveRules($ruleGroup); $newRuleEngine->setRules($rules); $newRuleEngine->fire(); - $resultCount = $newRuleEngine->getResults(); + $resultCount = $newRuleEngine->getResults(); // Tell the user that the job is queued session()->flash('success', trans_choice('firefly.applied_rule_group_selection', $resultCount, ['title' => $ruleGroup->title])); @@ -112,10 +112,10 @@ 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]); + $subTitle = (string) trans('firefly.apply_rule_group_selection', ['title' => $ruleGroup->title]); - return view('rules.rule-group.select-transactions', ['ruleGroup' => $ruleGroup, 'subTitle' => $subTitle]); + return view('rules.rule-group.select-transactions', ['ruleGroup' => $ruleGroup, 'subTitle' => $subTitle]); } } diff --git a/app/Http/Controllers/Transaction/ShowController.php b/app/Http/Controllers/Transaction/ShowController.php index 314e08dad5..bb9cceeec1 100644 --- a/app/Http/Controllers/Transaction/ShowController.php +++ b/app/Http/Controllers/Transaction/ShowController.php @@ -192,7 +192,6 @@ class ShowController extends Controller { $amounts = []; foreach ($group['transactions'] as $transaction) { - // add normal amount: $symbol = $transaction['currency_symbol']; $amounts[$symbol] ??= ['amount' => '0', 'symbol' => $symbol, 'decimal_places' => $transaction['currency_decimal_places']]; @@ -214,7 +213,11 @@ class ShowController extends Controller $amounts[$foreignSymbol]['amount'] = bcadd($amounts[$foreignSymbol]['amount'], (string) $transaction['foreign_amount']); } // add primary currency amount, but only if it is not the foreign amount or the current one. - if (null !== $transaction['pc_amount'] && $transaction['currency_id'] !== $this->primaryCurrency->id && $transaction['foreign_currency_code'] !== $this->primaryCurrency->code) { + if ( + null !== $transaction['pc_amount'] + && $transaction['currency_id'] !== $this->primaryCurrency->id + && $transaction['foreign_currency_code'] !== $this->primaryCurrency->code + ) { // same for foreign currency: $primarySymbol = $this->primaryCurrency->symbol; $amounts[$primarySymbol] ??= [ diff --git a/app/Repositories/Budget/BudgetLimitRepository.php b/app/Repositories/Budget/BudgetLimitRepository.php index 1fb9744b59..75f83954bf 100644 --- a/app/Repositories/Budget/BudgetLimitRepository.php +++ b/app/Repositories/Budget/BudgetLimitRepository.php @@ -60,9 +60,9 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup */ public function budgeted(Carbon $start, Carbon $end, TransactionCurrency $currency, ?Collection $budgets = null): string { - $query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') + $query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') // same complex where query as below. - ->where(static function (Builder $q5) use ($start, $end): void { + ->where(static function (Builder $q5) use ($start, $end): void { $q5->where(static function (Builder $q1) use ($start, $end): void { $q1->where(static function (Builder $q2) use ($start, $end): void { $q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d')); @@ -77,10 +77,11 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d')); }); }) - ->where('budget_limits.transaction_currency_id', $currency->id) - ->whereNull('budgets.deleted_at') - ->where('budgets.active', true) - ->where('budgets.user_id', $this->user->id); + ->where('budget_limits.transaction_currency_id', $currency->id) + ->whereNull('budgets.deleted_at') + ->where('budgets.active', true) + ->where('budgets.user_id', $this->user->id) + ; if ($budgets instanceof Collection && $budgets->count() > 0) { $query->whereIn('budget_limits.budget_id', $budgets->pluck('id')->toArray()); } @@ -91,12 +92,13 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup /** @var BudgetLimit $budgetLimit */ foreach ($set as $budgetLimit) { if ($budgetLimit->start_date->isSameDay($start) && $budgetLimit->end_date->isSameDay($end)) { - $result = bcadd((string)$budgetLimit->amount, $result); + $result = bcadd((string) $budgetLimit->amount, $result); + continue; } $period = Period::make($start, $end, precision: Precision::DAY(), boundaries: Boundaries::EXCLUDE_NONE()); $amountPerDay = $this->getDailyAmount($budgetLimit); - $result = bcadd($result, bcmul((string)$period->length(), $amountPerDay)); + $result = bcadd($result, bcmul((string) $period->length(), $amountPerDay)); } return $result; @@ -137,7 +139,8 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup ->where('transaction_currency_id', $currency->id) ->where('start_date', $start->format('Y-m-d')) ->where('end_date', $end->format('Y-m-d')) - ->first(); + ->first() + ; } public function getAllBudgetLimits(?Carbon $start = null, ?Carbon $end = null): Collection @@ -145,17 +148,19 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup // both are NULL: if (!$start instanceof Carbon && !$end instanceof Carbon) { return BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') - ->with(['budget']) - ->where('budgets.user_id', $this->user->id) - ->whereNull('budgets.deleted_at') - ->get(['budget_limits.*']); + ->with(['budget']) + ->where('budgets.user_id', $this->user->id) + ->whereNull('budgets.deleted_at') + ->get(['budget_limits.*']) + ; } // one of the two is NULL. if (!$start instanceof Carbon xor !$end instanceof Carbon) { $query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') - ->with(['budget']) - ->whereNull('budgets.deleted_at') - ->where('budgets.user_id', $this->user->id); + ->with(['budget']) + ->whereNull('budgets.deleted_at') + ->where('budgets.user_id', $this->user->id) + ; if ($end instanceof Carbon) { // end date must be before $end. $query->where('end_date', '<=', $end->format('Y-m-d 00:00:00')); @@ -170,31 +175,32 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup // neither are NULL: return BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') - ->with(['budget']) - ->where('budgets.user_id', $this->user->id) - ->whereNull('budgets.deleted_at') - ->where(static function (Builder $q5) use ($start, $end): void { - $q5->where(static function (Builder $q1) use ($start, $end): void { - $q1->where(static function (Builder $q2) use ($start, $end): void { - $q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d')); - $q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d')); - })->orWhere(static function (Builder $q3) use ($start, $end): void { - $q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d')); - $q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d')); - }); - })->orWhere(static function (Builder $q4) use ($start, $end): void { - // or start is before start AND end is after end. - $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d')); - $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d')); - }); - }) - ->get(['budget_limits.*']); + ->with(['budget']) + ->where('budgets.user_id', $this->user->id) + ->whereNull('budgets.deleted_at') + ->where(static function (Builder $q5) use ($start, $end): void { + $q5->where(static function (Builder $q1) use ($start, $end): void { + $q1->where(static function (Builder $q2) use ($start, $end): void { + $q2->where('budget_limits.end_date', '>=', $start->format('Y-m-d')); + $q2->where('budget_limits.end_date', '<=', $end->format('Y-m-d')); + })->orWhere(static function (Builder $q3) use ($start, $end): void { + $q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d')); + $q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d')); + }); + })->orWhere(static function (Builder $q4) use ($start, $end): void { + // or start is before start AND end is after end. + $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d')); + $q4->where('budget_limits.end_date', '>=', $end->format('Y-m-d')); + }); + }) + ->get(['budget_limits.*']) + ; } public function getAllBudgetLimitsByCurrency(TransactionCurrency $currency, ?Carbon $start = null, ?Carbon $end = null): Collection { return $this->getAllBudgetLimits($start, $end)->filter( - static fn(BudgetLimit $budgetLimit): bool => $budgetLimit->transaction_currency_id === $currency->id + static fn (BudgetLimit $budgetLimit): bool => $budgetLimit->transaction_currency_id === $currency->id ); } @@ -233,7 +239,8 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup ->orWhere(static function (Builder $q3) use ($start, $end): void { $q3->where('budget_limits.start_date', '>=', $start->format('Y-m-d 00:00:00')); $q3->where('budget_limits.start_date', '<=', $end->format('Y-m-d 23:59:59')); - }); + }) + ; })->orWhere(static function (Builder $q4) use ($start, $end): void { // or start is before start AND end is after end. $q4->where('budget_limits.start_date', '<=', $start->format('Y-m-d 23:59:59')); @@ -241,21 +248,22 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup }); }) ->orderBy('budget_limits.start_date', 'DESC') - ->get(['budget_limits.*']); + ->get(['budget_limits.*']) + ; } public function getDailyAmount(BudgetLimit $budgetLimit): string { $limitPeriod = Period::make($budgetLimit->start_date, $budgetLimit->end_date, precision: Precision::DAY(), boundaries: Boundaries::EXCLUDE_NONE()); $days = $limitPeriod->length(); - $amount = bcdiv($budgetLimit->amount, (string)$days, 12); + $amount = bcdiv($budgetLimit->amount, (string) $days, 12); Log::debug(sprintf( - 'Total amount for budget limit #%d is %s. Nr. of days is %d. Amount per day is %s', - $budgetLimit->id, - $budgetLimit->amount, - $days, - $amount - )); + 'Total amount for budget limit #%d is %s. Nr. of days is %d. Amount per day is %s', + $budgetLimit->id, + $budgetLimit->amount, + $days, + $amount + )); return $amount; } @@ -263,7 +271,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup #[Override] public function getNoteText(BudgetLimit $budgetLimit): string { - return (string)$budgetLimit->notes()->first()?->text; + return (string) $budgetLimit->notes()->first()?->text; } #[Override] @@ -290,39 +298,40 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup { // if no currency has been provided, use the user's default currency: /** @var TransactionCurrencyFactory $factory */ - $factory = app(TransactionCurrencyFactory::class); - $currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null); + $factory = app(TransactionCurrencyFactory::class); + $currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($this->user->userGroup); } - $currency->enabled = true; + $currency->enabled = true; $currency->save(); // find the budget: /** @var null|Budget $budget */ - $budget = $this->user->budgets()->find((int)$data['budget_id']); + $budget = $this->user->budgets()->find((int) $data['budget_id']); if (null === $budget) { throw new FireflyException('200004: Budget does not exist.'); } // find limit with same date range and currency. - $limit = $budget + $limit = $budget ->budgetlimits() ->where('budget_limits.start_date', $data['start_date']->format('Y-m-d')) ->where('budget_limits.end_date', $data['end_date']->format('Y-m-d')) ->where('budget_limits.transaction_currency_id', $currency->id) - ->first(['budget_limits.*']); + ->first(['budget_limits.*']) + ; if (null !== $limit) { throw new FireflyException('200027: Budget limit already exists.'); } Log::debug('No existing budget limit, create a new one'); // this is a lame trick to communicate with the observer. - $singleton = PreferencesSingleton::getInstance(); + $singleton = PreferencesSingleton::getInstance(); $singleton->setPreference('fire_webhooks_bl_store', $data['fire_webhooks'] ?? true); // or create one and return it. - $limit = new BudgetLimit(); + $limit = new BudgetLimit(); $limit->budget()->associate($budget); $limit->start_date = $data['start_date']->format('Y-m-d'); $limit->end_date = $data['end_date']->format('Y-m-d'); @@ -332,13 +341,13 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup $limit->transaction_currency_id = $currency->id; $limit->save(); - $noteText = (string)($data['notes'] ?? ''); + $noteText = (string) ($data['notes'] ?? ''); if ('' !== $noteText) { $this->setNoteText($limit, $noteText); } Log::debug(sprintf('Created new budget limit with ID #%d and amount %s', $limit->id, $data['amount'])); - $createWebhookMessages = $data['fire_webhooks'] ?? true; + $createWebhookMessages = $data['fire_webhooks'] ?? true; event(new CreatedBudgetLimit($limit, $createWebhookMessages)); event(new WebhookMessagesRequestSending()); @@ -350,8 +359,8 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup */ public function update(BudgetLimit $budgetLimit, array $data): BudgetLimit { - $budgetLimit->amount = array_key_exists('amount', $data) ? $data['amount'] : $budgetLimit->amount; - $budgetLimit->budget_id = array_key_exists('budget_id', $data) ? $data['budget_id'] : $budgetLimit->budget_id; + $budgetLimit->amount = array_key_exists('amount', $data) ? $data['amount'] : $budgetLimit->amount; + $budgetLimit->budget_id = array_key_exists('budget_id', $data) ? $data['budget_id'] : $budgetLimit->budget_id; if (array_key_exists('start', $data)) { $budgetLimit->start_date = $data['start']->startOfDay(); @@ -363,7 +372,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup } // if no currency has been provided, use the user's default currency: - $currency = null; + $currency = null; // update if relevant: if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) { @@ -375,12 +384,12 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup if (null === $currency) { $currency = $budgetLimit->transactionCurrency ?? Amount::getPrimaryCurrencyByUserGroup($this->user->userGroup); } - $currency->enabled = true; + $currency->enabled = true; $currency->save(); // this is a lame trick to communicate with the observer. // FIXME so don't do that lol. - $singleton = PreferencesSingleton::getInstance(); + $singleton = PreferencesSingleton::getInstance(); $singleton->setPreference('fire_webhooks_bl_update', $data['fire_webhooks'] ?? true); $budgetLimit->transaction_currency_id = $currency->id; @@ -388,9 +397,9 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface, UserGroup // update notes if they exist. if (array_key_exists('notes', $data)) { - $this->setNoteText($budgetLimit, (string)$data['notes']); + $this->setNoteText($budgetLimit, (string) $data['notes']); } - $generateMessages = $data['fire_webhooks'] ?? true; + $generateMessages = $data['fire_webhooks'] ?? true; event(new UpdatedBudgetLimit($budgetLimit, $generateMessages)); event(new WebhookMessagesRequestSending()); diff --git a/app/Services/Internal/Support/AccountServiceTrait.php b/app/Services/Internal/Support/AccountServiceTrait.php index 18e88621cf..1e83a66be9 100644 --- a/app/Services/Internal/Support/AccountServiceTrait.php +++ b/app/Services/Internal/Support/AccountServiceTrait.php @@ -62,8 +62,8 @@ trait AccountServiceTrait if (null === $iban) { return null; } - $data = ['iban' => $iban]; - $rules = ['iban' => 'required|iban']; + $data = ['iban' => $iban]; + $rules = ['iban' => 'required|iban']; $validator = Validator::make($data, $rules); if ($validator->fails()) { Log::info(sprintf('Detected invalid IBAN ("%s"). Return NULL instead.', $iban)); @@ -89,7 +89,7 @@ trait AccountServiceTrait array_key_exists('opening_balance', $data) && '' === $data['opening_balance'] || array_key_exists('opening_balance_date', $data) - && '' === $data['opening_balance_date']; + && '' === $data['opening_balance_date']; } /** @@ -101,14 +101,14 @@ trait AccountServiceTrait */ public function updateMetaData(Account $account, array $data): void { - $fields = $this->validFields; + $fields = $this->validFields; if (AccountTypeEnum::ASSET->value === $account->accountType->type) { $fields = $this->validAssetFields; } // remove currency_id if necessary. - $type = $account->accountType->type; - $list = config('firefly.valid_currency_account_types'); + $type = $account->accountType->type; + $list = config('firefly.valid_currency_account_types'); if (!in_array($type, $list, true)) { $pos = array_search('currency_id', $fields, true); if (false !== $pos) { @@ -150,14 +150,14 @@ trait AccountServiceTrait $data[$field] = $data[$field]->toAtomString(); } - $factory->crud($account, $field, (string)$data[$field]); + $factory->crud($account, $field, (string) $data[$field]); } } } public function updateNote(Account $account, string $note): bool { - $dbNote = $account->notes()->first(); + $dbNote = $account->notes()->first(); if ('' === $note) { $dbNote?->delete(); @@ -178,7 +178,7 @@ trait AccountServiceTrait */ public function validOBData(array $data): bool { - $data['opening_balance'] = (string)($data['opening_balance'] ?? ''); + $data['opening_balance'] = (string) ($data['opening_balance'] ?? ''); if ('' !== $data['opening_balance'] && 0 === bccomp($data['opening_balance'], '0')) { $data['opening_balance'] = ''; } @@ -210,11 +210,11 @@ trait AccountServiceTrait throw new FireflyException('Amount for new liability credit was unexpectedly 0.'); } - $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; + $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; if (is_array($language)) { $language = 'en_US'; } - $language = (string)$language; + $language = (string) $language; // set source and/or destination based on whether the amount is positive or negative. // first, assume the amount is positive and go from there: @@ -228,14 +228,14 @@ trait AccountServiceTrait $sourceId = $account->id; $sourceName = null; $destId = null; - $destName = trans('firefly.liability_credit_description', ['account' => $account->name], $language); + $destName = trans('firefly.liability_credit_description', ['account' => $account->name], $language); } // amount must be positive for the transaction to work. - $amount = Steam::positive($openingBalance); + $amount = Steam::positive($openingBalance); // get or grab currency: - $currency = $this->accountRepository->getAccountCurrency($account); + $currency = $this->accountRepository->getAccountCurrency($account); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } @@ -245,34 +245,34 @@ trait AccountServiceTrait 'user' => $account->user, 'user_group' => $account->user->userGroup, 'transactions' => [[ - 'type' => 'Liability credit', - 'date' => $openingBalanceDate, - 'source_id' => $sourceId, - 'source_name' => $sourceName, - 'destination_id' => $destId, - 'destination_name' => $destName, - 'user' => $account->user, - 'user_group' => $account->user->userGroup, - 'currency_id' => $currency->id, - 'order' => 0, - 'amount' => $amount, - 'foreign_amount' => null, - 'description' => trans('firefly.liability_credit_description', ['account' => $account->name]), - 'budget_id' => null, - 'budget_name' => null, - 'category_id' => null, - 'category_name' => null, - 'piggy_bank_id' => null, - 'piggy_bank_name' => null, - 'reconciled' => false, - 'notes' => null, - 'tags' => [], - ]], + 'type' => 'Liability credit', + 'date' => $openingBalanceDate, + 'source_id' => $sourceId, + 'source_name' => $sourceName, + 'destination_id' => $destId, + 'destination_name' => $destName, + 'user' => $account->user, + 'user_group' => $account->user->userGroup, + 'currency_id' => $currency->id, + 'order' => 0, + 'amount' => $amount, + 'foreign_amount' => null, + 'description' => trans('firefly.liability_credit_description', ['account' => $account->name]), + 'budget_id' => null, + 'budget_name' => null, + 'category_id' => null, + 'category_name' => null, + 'piggy_bank_id' => null, + 'piggy_bank_name' => null, + 'reconciled' => false, + 'notes' => null, + 'tags' => [], + ]], ]; Log::debug('Going for submission in createCreditTransaction', $submission); /** @var TransactionGroupFactory $factory */ - $factory = app(TransactionGroupFactory::class); + $factory = app(TransactionGroupFactory::class); $factory->setUser($account->user); try { @@ -295,11 +295,11 @@ trait AccountServiceTrait protected function createOBGroup(Account $account, array $data): TransactionGroup { Log::debug('Now going to create an OB group.'); - $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; + $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; if (is_array($language)) { $language = 'en_US'; } - $language = (string)$language; + $language = (string) $language; $sourceId = null; $sourceName = null; $destId = null; @@ -307,29 +307,29 @@ trait AccountServiceTrait $amount = array_key_exists('opening_balance', $data) ? $data['opening_balance'] : '0'; // amount is positive. - if (1 === bccomp((string)$amount, '0')) { + if (1 === bccomp((string) $amount, '0')) { Log::debug(sprintf('Amount is %s, which is positive. Source is a new IB account, destination is #%d', $amount, $account->id)); $sourceName = trans('firefly.initial_balance_description', ['account' => $account->name], $language); $destId = $account->id; } // amount is not positive - if (-1 === bccomp((string)$amount, '0')) { + if (-1 === bccomp((string) $amount, '0')) { Log::debug(sprintf('Amount is %s, which is negative. Destination is a new IB account, source is #%d', $amount, $account->id)); $destName = trans('firefly.initial_balance_account', ['account' => $account->name], $language); $sourceId = $account->id; } // amount is 0 - if (0 === bccomp((string)$amount, '0')) { + if (0 === bccomp((string) $amount, '0')) { Log::debug('Amount is zero, so will not make an OB group.'); throw new FireflyException('Amount for new opening balance was unexpectedly 0.'); } // make amount positive, regardless: - $amount = Steam::positive($amount); + $amount = Steam::positive($amount); // get or grab currency: - $currency = $this->accountRepository->getAccountCurrency($account); + $currency = $this->accountRepository->getAccountCurrency($account); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } @@ -340,34 +340,34 @@ trait AccountServiceTrait 'user' => $account->user, 'user_group' => $account->user->userGroup, 'transactions' => [[ - 'type' => 'Opening balance', - 'date' => $data['opening_balance_date'], - 'source_id' => $sourceId, - 'source_name' => $sourceName, - 'destination_id' => $destId, - 'destination_name' => $destName, - 'user' => $account->user, - 'user_group' => $account->user->userGroup, - 'currency_id' => $currency->id, - 'order' => 0, - 'amount' => $amount, - 'foreign_amount' => null, - 'description' => trans('firefly.initial_balance_description', ['account' => $account->name]), - 'budget_id' => null, - 'budget_name' => null, - 'category_id' => null, - 'category_name' => null, - 'piggy_bank_id' => null, - 'piggy_bank_name' => null, - 'reconciled' => false, - 'notes' => null, - 'tags' => [], - ]], + 'type' => 'Opening balance', + 'date' => $data['opening_balance_date'], + 'source_id' => $sourceId, + 'source_name' => $sourceName, + 'destination_id' => $destId, + 'destination_name' => $destName, + 'user' => $account->user, + 'user_group' => $account->user->userGroup, + 'currency_id' => $currency->id, + 'order' => 0, + 'amount' => $amount, + 'foreign_amount' => null, + 'description' => trans('firefly.initial_balance_description', ['account' => $account->name]), + 'budget_id' => null, + 'budget_name' => null, + 'category_id' => null, + 'category_name' => null, + 'piggy_bank_id' => null, + 'piggy_bank_name' => null, + 'reconciled' => false, + 'notes' => null, + 'tags' => [], + ]], ]; Log::debug('Going for submission in createOBGroup', $submission); /** @var TransactionGroupFactory $factory */ - $factory = app(TransactionGroupFactory::class); + $factory = app(TransactionGroupFactory::class); $factory->setUser($account->user); try { @@ -388,15 +388,15 @@ trait AccountServiceTrait protected function createOBGroupV2(Account $account, string $openingBalance, Carbon $openingBalanceDate): TransactionGroup { Log::debug('Now going to create an OB group.'); - $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; + $language = Preferences::getForUser($account->user, 'language', 'en_US')->data; if (is_array($language)) { $language = 'en_US'; } - $language = (string)$language; - $sourceId = null; - $sourceName = null; - $destId = null; - $destName = null; + $language = (string) $language; + $sourceId = null; + $sourceName = null; + $destId = null; + $destName = null; // amount is positive. if (1 === bccomp($openingBalance, '0')) { @@ -418,48 +418,48 @@ trait AccountServiceTrait } // make amount positive, regardless: - $amount = Steam::positive($openingBalance); + $amount = Steam::positive($openingBalance); // get or grab currency: - $currency = $this->accountRepository->getAccountCurrency($account); + $currency = $this->accountRepository->getAccountCurrency($account); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } // submit to factory: - $submission = [ + $submission = [ 'group_title' => null, 'user' => $account->user, 'user_group' => $account->user->userGroup, 'transactions' => [[ - 'type' => 'Opening balance', - 'date' => $openingBalanceDate, - 'source_id' => $sourceId, - 'source_name' => $sourceName, - 'destination_id' => $destId, - 'destination_name' => $destName, - 'user' => $account->user, - 'user_group' => $account->user->userGroup, - 'currency_id' => $currency->id, - 'order' => 0, - 'amount' => $amount, - 'foreign_amount' => null, - 'description' => trans('firefly.initial_balance_description', ['account' => $account->name]), - 'budget_id' => null, - 'budget_name' => null, - 'category_id' => null, - 'category_name' => null, - 'piggy_bank_id' => null, - 'piggy_bank_name' => null, - 'reconciled' => false, - 'notes' => null, - 'tags' => [], - ]], + 'type' => 'Opening balance', + 'date' => $openingBalanceDate, + 'source_id' => $sourceId, + 'source_name' => $sourceName, + 'destination_id' => $destId, + 'destination_name' => $destName, + 'user' => $account->user, + 'user_group' => $account->user->userGroup, + 'currency_id' => $currency->id, + 'order' => 0, + 'amount' => $amount, + 'foreign_amount' => null, + 'description' => trans('firefly.initial_balance_description', ['account' => $account->name]), + 'budget_id' => null, + 'budget_name' => null, + 'category_id' => null, + 'category_name' => null, + 'piggy_bank_id' => null, + 'piggy_bank_name' => null, + 'reconciled' => false, + 'notes' => null, + 'tags' => [], + ]], ]; Log::debug('Going for submission in createOBGroupV2', $submission); /** @var TransactionGroupFactory $factory */ - $factory = app(TransactionGroupFactory::class); + $factory = app(TransactionGroupFactory::class); $factory->setUser($account->user); try { @@ -530,10 +530,10 @@ trait AccountServiceTrait { // find currency, or use default currency instead. /** @var TransactionCurrencyFactory $factory */ - $factory = app(TransactionCurrencyFactory::class); + $factory = app(TransactionCurrencyFactory::class); /** @var null|TransactionCurrency $currency */ - $currency = $factory->find($currencyId, $currencyCode); + $currency = $factory->find($currencyId, $currencyCode); if (null === $currency) { // use default currency: @@ -569,7 +569,7 @@ trait AccountServiceTrait } // if direction is "debit" (I owe this debt), amount is negative. // which means the liability will have a negative balance which the user must fill. - $openingBalance = Steam::negative($openingBalance); + $openingBalance = Steam::negative($openingBalance); // if direction is "credit" (I am owed this debt), amount is positive. // which means the liability will have a positive balance which is drained when its paid back into any asset. @@ -578,21 +578,21 @@ trait AccountServiceTrait } // create if not exists: - $clGroup = $this->getCreditTransaction($account); + $clGroup = $this->getCreditTransaction($account); if (null === $clGroup) { return $this->createCreditTransaction($account, $openingBalance, $openingBalanceDate); } // if exists, update: - $currency = $this->accountRepository->getAccountCurrency($account); + $currency = $this->accountRepository->getAccountCurrency($account); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } // simply grab the first journal and change it: - $journal = $this->getObJournal($clGroup); - $clTransaction = $this->getOBTransaction($journal, $account); - $accountTransaction = $this->getNotOBTransaction($journal, $account); - $journal->date = $openingBalanceDate; + $journal = $this->getObJournal($clGroup); + $clTransaction = $this->getOBTransaction($journal, $account); + $accountTransaction = $this->getNotOBTransaction($journal, $account); + $journal->date = $openingBalanceDate; $journal->transactionCurrency()->associate($currency); // account always gains money: @@ -600,8 +600,8 @@ trait AccountServiceTrait $accountTransaction->transaction_currency_id = $currency->id; // CL account always loses money: - $clTransaction->amount = Steam::negative($openingBalance); - $clTransaction->transaction_currency_id = $currency->id; + $clTransaction->amount = Steam::negative($openingBalance); + $clTransaction->transaction_currency_id = $currency->id; // save both $accountTransaction->save(); $clTransaction->save(); @@ -621,23 +621,23 @@ trait AccountServiceTrait { Log::debug(sprintf('Now in %s', __METHOD__)); // create if not exists: - $obGroup = $this->getOBGroup($account); + $obGroup = $this->getOBGroup($account); if (null === $obGroup) { return $this->createOBGroupV2($account, $openingBalance, $openingBalanceDate); } Log::debug('Update OB group'); // if exists, update: - $currency = $this->accountRepository->getAccountCurrency($account); + $currency = $this->accountRepository->getAccountCurrency($account); if (null === $currency) { $currency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); } // simply grab the first journal and change it: - $journal = $this->getObJournal($obGroup); - $obTransaction = $this->getOBTransaction($journal, $account); - $accountTransaction = $this->getNotOBTransaction($journal, $account); - $journal->date = $openingBalanceDate; + $journal = $this->getObJournal($obGroup); + $obTransaction = $this->getOBTransaction($journal, $account); + $accountTransaction = $this->getNotOBTransaction($journal, $account); + $journal->date = $openingBalanceDate; $journal->transactionCurrency()->associate($currency); // if amount is negative: @@ -648,8 +648,8 @@ trait AccountServiceTrait $accountTransaction->transaction_currency_id = $currency->id; // OB account transaction gains money - $obTransaction->amount = Steam::positive($openingBalance); - $obTransaction->transaction_currency_id = $currency->id; + $obTransaction->amount = Steam::positive($openingBalance); + $obTransaction->transaction_currency_id = $currency->id; } if (-1 === bccomp('0', $openingBalance)) { Log::debug('Amount is positive.'); @@ -658,8 +658,8 @@ trait AccountServiceTrait $accountTransaction->transaction_currency_id = $currency->id; // OB account loses money: - $obTransaction->amount = Steam::negative($openingBalance); - $obTransaction->transaction_currency_id = $currency->id; + $obTransaction->amount = Steam::negative($openingBalance); + $obTransaction->transaction_currency_id = $currency->id; } // save both $accountTransaction->save(); diff --git a/app/Support/Calendar/Calculator.php b/app/Support/Calendar/Calculator.php index c45e4f9c45..b15a3c65ca 100644 --- a/app/Support/Calendar/Calculator.php +++ b/app/Support/Calendar/Calculator.php @@ -38,6 +38,7 @@ class Calculator private static ?SplObjectStorage $intervalMap = null; // @phpstan-ignore-line // @phpstan-ignore-line // @phpstan-ignore-line + // @phpstan-ignore-line private static array $intervals = []; public function isAvailablePeriodicity(Periodicity $periodicity): bool diff --git a/app/Support/Export/ExportDataGenerator.php b/app/Support/Export/ExportDataGenerator.php index 77ce329ee7..87861e3490 100644 --- a/app/Support/Export/ExportDataGenerator.php +++ b/app/Support/Export/ExportDataGenerator.php @@ -94,6 +94,8 @@ class ExportDataGenerator // @phpstan-ignore-line + // @phpstan-ignore-line + public function __construct() { $this->accounts = new Collection(); diff --git a/app/Support/Http/Controllers/PeriodOverview.php b/app/Support/Http/Controllers/PeriodOverview.php index c172835982..63b1d792ed 100644 --- a/app/Support/Http/Controllers/PeriodOverview.php +++ b/app/Support/Http/Controllers/PeriodOverview.php @@ -83,12 +83,15 @@ trait PeriodOverview private Collection $statistics; // temp data holder // temp data holder // temp data holder + // temp data holder private array $transactions; // 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 diff --git a/app/Support/JsonApi/Enrichments/AvailableBudgetEnrichment.php b/app/Support/JsonApi/Enrichments/AvailableBudgetEnrichment.php index 8b6be21ab4..4621f41803 100644 --- a/app/Support/JsonApi/Enrichments/AvailableBudgetEnrichment.php +++ b/app/Support/JsonApi/Enrichments/AvailableBudgetEnrichment.php @@ -43,9 +43,11 @@ class AvailableBudgetEnrichment implements EnrichmentInterface private Collection $collection; // @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 + // @phpstan-ignore-line private array $currencies = []; private array $currencyIds = []; private array $ids = []; diff --git a/app/Support/JsonApi/Enrichments/BudgetLimitEnrichment.php b/app/Support/JsonApi/Enrichments/BudgetLimitEnrichment.php index 59aff751c2..00c5d40512 100644 --- a/app/Support/JsonApi/Enrichments/BudgetLimitEnrichment.php +++ b/app/Support/JsonApi/Enrichments/BudgetLimitEnrichment.php @@ -43,6 +43,7 @@ class BudgetLimitEnrichment implements EnrichmentInterface private readonly bool $convertToPrimary; // @phpstan-ignore-line // @phpstan-ignore-line // @phpstan-ignore-line + // @phpstan-ignore-line private array $currencies = []; private array $currencyIds = []; private Carbon $end; diff --git a/app/Support/JsonApi/Enrichments/PiggyBankEnrichment.php b/app/Support/JsonApi/Enrichments/PiggyBankEnrichment.php index 040ad8dbd5..e3d9a5b9a7 100644 --- a/app/Support/JsonApi/Enrichments/PiggyBankEnrichment.php +++ b/app/Support/JsonApi/Enrichments/PiggyBankEnrichment.php @@ -45,9 +45,11 @@ class PiggyBankEnrichment implements EnrichmentInterface private array $accountIds = []; // @phpstan-ignore-line // @phpstan-ignore-line // @phpstan-ignore-line + // @phpstan-ignore-line private array $accounts = []; // @phpstan-ignore-line // @phpstan-ignore-line // @phpstan-ignore-line + // @phpstan-ignore-line private array $amounts = []; private Collection $collection; private array $currencies = []; diff --git a/app/Support/JsonApi/Enrichments/PiggyBankEventEnrichment.php b/app/Support/JsonApi/Enrichments/PiggyBankEventEnrichment.php index 480ed40b11..462680325b 100644 --- a/app/Support/JsonApi/Enrichments/PiggyBankEventEnrichment.php +++ b/app/Support/JsonApi/Enrichments/PiggyBankEventEnrichment.php @@ -40,9 +40,11 @@ class PiggyBankEventEnrichment implements EnrichmentInterface private array $accountCurrencies = []; // @phpstan-ignore-line // @phpstan-ignore-line // @phpstan-ignore-line + // @phpstan-ignore-line private array $accountIds = []; // @phpstan-ignore-line // @phpstan-ignore-line // @phpstan-ignore-line + // @phpstan-ignore-line private Collection $collection; private array $currencies = []; private array $groupIds = []; diff --git a/app/Support/JsonApi/Enrichments/SubscriptionEnrichment.php b/app/Support/JsonApi/Enrichments/SubscriptionEnrichment.php index 00d7075215..82245d1bee 100644 --- a/app/Support/JsonApi/Enrichments/SubscriptionEnrichment.php +++ b/app/Support/JsonApi/Enrichments/SubscriptionEnrichment.php @@ -49,6 +49,7 @@ class SubscriptionEnrichment implements EnrichmentInterface private Collection $collection; // @phpstan-ignore-line // @phpstan-ignore-line // @phpstan-ignore-line + // @phpstan-ignore-line private readonly bool $convertToPrimary; private ?Carbon $end = null; private array $mappedObjects = []; diff --git a/app/Support/JsonApi/Enrichments/TransactionGroupEnrichment.php b/app/Support/JsonApi/Enrichments/TransactionGroupEnrichment.php index 2148ac7660..5434d75f85 100644 --- a/app/Support/JsonApi/Enrichments/TransactionGroupEnrichment.php +++ b/app/Support/JsonApi/Enrichments/TransactionGroupEnrichment.php @@ -59,6 +59,8 @@ class TransactionGroupEnrichment implements EnrichmentInterface // @phpstan-ignore-line + // @phpstan-ignore-line + public function __construct() { $this->dateFields = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date']; diff --git a/app/Support/JsonApi/Enrichments/WebhookEnrichment.php b/app/Support/JsonApi/Enrichments/WebhookEnrichment.php index 38442d58f1..d4b245677c 100644 --- a/app/Support/JsonApi/Enrichments/WebhookEnrichment.php +++ b/app/Support/JsonApi/Enrichments/WebhookEnrichment.php @@ -45,9 +45,11 @@ class WebhookEnrichment implements EnrichmentInterface private array $deliveries = []; // @phpstan-ignore-line // @phpstan-ignore-line // @phpstan-ignore-line + // @phpstan-ignore-line private array $ids = []; // @phpstan-ignore-line // @phpstan-ignore-line // @phpstan-ignore-line + // @phpstan-ignore-line private array $responses = []; private array $triggers = []; private array $webhookDeliveries = []; diff --git a/app/TransactionRules/Engine/SearchRuleEngine.php b/app/TransactionRules/Engine/SearchRuleEngine.php index cdaa490eb1..ed78800ac9 100644 --- a/app/TransactionRules/Engine/SearchRuleEngine.php +++ b/app/TransactionRules/Engine/SearchRuleEngine.php @@ -100,7 +100,10 @@ class SearchRuleEngine implements RuleEngineInterface foreach ($this->rules as $rule) { // @phpstan-ignore-line $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)); + 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 + )); } 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)); diff --git a/changelog.md b/changelog.md index 478d0addf5..79176d4c7c 100644 --- a/changelog.md +++ b/changelog.md @@ -19,19 +19,19 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed -- #11589 -- #11541 -- #11544 -- #11546 -- #11431 -- #11399 -- #11569 -- #11563 -- #11589 -- #11601 -- #11614 -- #11620 -- #11632 +- [PR 11589](https://github.com/firefly-iii/firefly-iii/pull/11589) (apply user-selected light/dark mode to form elements (checkboxes, date picker) #8613 #7620) reported by @mateuszkulapl +- [Issue 11541](https://github.com/firefly-iii/firefly-iii/issues/11541) (Display running balance fails for transactions between accounts with different currencies) reported by @SledgehammerPL +- [Issue 11544](https://github.com/firefly-iii/firefly-iii/issues/11544) (Clean up events and handlers) reported by @JC5 +- [Issue 11546](https://github.com/firefly-iii/firefly-iii/issues/11546) (Wrong invitation expiry time) reported by @GunoH +- [Discussion 11431](https://github.com/orgs/firefly-iii/discussions/11431) (Settings don't get saved) started by @PVTejas +- [Issue 11399](https://github.com/firefly-iii/firefly-iii/issues/11399) (Unusual behavior in audit logs (multi-currency)) reported by @jgmm81 +- [PR 11569](https://github.com/firefly-iii/firefly-iii/pull/11569) (Fix layout overflow issues with long content in v1 and v2 layouts) reported by @gian21391 +- [Issue 11563](https://github.com/firefly-iii/firefly-iii/issues/11563) (Tag Report/Insight API Endpoint for Tags Non Functional) reported by @Unsantae +- [PR 11589](https://github.com/firefly-iii/firefly-iii/pull/11589) (apply user-selected light/dark mode to form elements (checkboxes, date picker) #8613 #7620) reported by @mateuszkulapl +- [Issue 11601](https://github.com/firefly-iii/firefly-iii/issues/11601) (Only ungrouped piggy banks are listed when creating a transaction) reported by @jgmm81 +- [Issue 11614](https://github.com/firefly-iii/firefly-iii/issues/11614) (Add New Taiwan Dollar to Currency Seeder) reported by @nick322 +- [Issue 11620](https://github.com/firefly-iii/firefly-iii/issues/11620) (Add database indexes to improve reporting query performance) reported by @Zakmaf +- [PR 11632](https://github.com/firefly-iii/firefly-iii/pull/11632) (fix v2 layout dashboard transactions load) reported by @mateuszkulapl - Confirming your new email address would result in an error. ### Security diff --git a/composer.lock b/composer.lock index 6dcb372eff..3819f983ab 100644 --- a/composer.lock +++ b/composer.lock @@ -12014,21 +12014,21 @@ }, { "name": "rector/rector", - "version": "2.3.5", + "version": "2.3.6", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "9442f4037de6a5347ae157fe8e6c7cda9d909070" + "reference": "ca9ebb81d280cd362ea39474dabd42679e32ca6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/9442f4037de6a5347ae157fe8e6c7cda9d909070", - "reference": "9442f4037de6a5347ae157fe8e6c7cda9d909070", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/ca9ebb81d280cd362ea39474dabd42679e32ca6b", + "reference": "ca9ebb81d280cd362ea39474dabd42679e32ca6b", "shasum": "" }, "require": { "php": "^7.4|^8.0", - "phpstan/phpstan": "^2.1.36" + "phpstan/phpstan": "^2.1.38" }, "conflict": { "rector/rector-doctrine": "*", @@ -12062,7 +12062,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/2.3.5" + "source": "https://github.com/rectorphp/rector/tree/2.3.6" }, "funding": [ { @@ -12070,7 +12070,7 @@ "type": "github" } ], - "time": "2026-01-28T15:22:48+00:00" + "time": "2026-02-06T14:25:06+00:00" }, { "name": "sebastian/cli-parser", diff --git a/config/firefly.php b/config/firefly.php index c09258d4bd..4d5dbd3ca2 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -79,7 +79,7 @@ return [ // see cer.php for exchange rates feature flag. ], 'version' => 'develop/2026-02-06', - 'build_time' => 1770383155, + 'build_time' => 1770398635, 'api_version' => '2.1.0', // field is no longer used. 'db_version' => 28, // field is no longer used.