Compare commits

..

29 Commits

Author SHA1 Message Date
github-actions[bot]
3e36287374 Merge pull request #11774 from firefly-iii/release-1771667913
🤖 Automatically merge the PR into the develop branch.
2026-02-21 10:58:39 +01:00
JC5
37c4db2ce9 🤖 Auto commit for release 'develop' on 2026-02-21 2026-02-21 10:58:33 +01:00
James Cole
8e6ff3ceaf Fix small issues reported over mail and from the demo site. 2026-02-21 10:53:14 +01:00
James Cole
6e0e32dc6c You can always grab the latest develop release. 2026-02-21 08:05:01 +01:00
github-actions[bot]
b0e21dd553 Merge pull request #11773 from firefly-iii/release-1771657248
🤖 Automatically merge the PR into the develop branch.
2026-02-21 08:00:55 +01:00
JC5
88291c5f63 🤖 Auto commit for release 'develop' on 2026-02-21 2026-02-21 08:00:48 +01:00
James Cole
a87e10f734 Add a week's delay. 2026-02-21 07:54:23 +01:00
github-actions[bot]
75f42d57f1 Merge pull request #11772 from firefly-iii/release-1771653268
🤖 Automatically merge the PR into the develop branch.
2026-02-21 06:54:36 +01:00
JC5
3f60442281 🤖 Auto commit for release 'develop' on 2026-02-21 2026-02-21 06:54:28 +01:00
James Cole
dd14bb1664 Add 10m slack 2026-02-21 06:48:34 +01:00
James Cole
403a2ce2cd Remove weird repeated line from Mago. 2026-02-21 06:47:26 +01:00
James Cole
e5366dbf6c Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/Services/FireflyIIIOrg/Update/GitHubUpdateRequest.php
2026-02-21 06:44:11 +01:00
James Cole
091f264f3e Remove mago analyse, fix update check. 2026-02-21 06:40:51 +01:00
github-actions[bot]
3ad1420262 Merge pull request #11771 from firefly-iii/release-1771652323
🤖 Automatically merge the PR into the develop branch.
2026-02-21 06:38:50 +01:00
JC5
018f68b789 🤖 Auto commit for release 'develop' on 2026-02-21 2026-02-21 06:38:43 +01:00
James Cole
e23d0de8f9 Fix local update check. 2026-02-21 06:31:42 +01:00
James Cole
04c3bf966d Rebuild update request to use GitHub API. 2026-02-21 06:25:18 +01:00
James Cole
681619f732 Remove unused classes 2026-02-20 20:33:36 +01:00
James Cole
cab298708c Remove unused enums 2026-02-20 20:33:13 +01:00
James Cole
c4392f89d1 Improve code quality, add PHP 8.5 things. 2026-02-20 20:22:13 +01:00
James Cole
36789a310a Tiny changes. 2026-02-20 20:17:10 +01:00
James Cole
e92a1b6dda Add new support guide. 2026-02-20 20:03:11 +01:00
James Cole
1d687a632f Add changelog. 2026-02-20 20:01:25 +01:00
github-actions[bot]
1fa4a1bdc8 Merge pull request #11770 from firefly-iii/release-1771612722
🤖 Automatically merge the PR into the develop branch.
2026-02-20 19:38:50 +01:00
JC5
aee53cffb9 🤖 Auto commit for release 'develop' on 2026-02-20 2026-02-20 19:38:42 +01:00
github-actions[bot]
828b965c98 Merge pull request #11769 from firefly-iii/release-1771605618
🤖 Automatically merge the PR into the develop branch.
2026-02-20 17:40:27 +01:00
JC5
c008cd41db 🤖 Auto commit for release 'develop' on 2026-02-20 2026-02-20 17:40:18 +01:00
James Cole
accac89ffb Upgrade job to PHP 8.5 2026-02-20 17:35:59 +01:00
James Cole
fb79e3b08c Push Firefly III to PHP 8.5 2026-02-20 17:33:53 +01:00
46 changed files with 567 additions and 884 deletions

View File

@@ -43,6 +43,7 @@ return $config->setRules(
// rule sets
'@PHP8x3Migration' => true,
'@PHP8x4Migration' => true,
'@PHP8x5Migration' => true,
'@PhpCsFixer' => true,
'@PhpCsFixer:risky' => true,
'@PSR12' => true,

View File

@@ -1,5 +1,6 @@
{
"require": {
"php": ">=8.5.0",
"friendsofphp/php-cs-fixer": "^3.12"
}
}

View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f1e0b38af4ded66da271a99d2bff5be8",
"content-hash": "35b5ad9b3c4e1ffe78ef9bec73987499",
"packages": [
{
"name": "clue/ndjson-react",
@@ -402,16 +402,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.94.1",
"version": "v3.94.2",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "d1a3634e29916367b885250e1fc4dfd5ffe3b091"
"reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/d1a3634e29916367b885250e1fc4dfd5ffe3b091",
"reference": "d1a3634e29916367b885250e1fc4dfd5ffe3b091",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7787ceff91365ba7d623ec410b8f429cdebb4f63",
"reference": "7787ceff91365ba7d623ec410b8f429cdebb4f63",
"shasum": ""
},
"require": {
@@ -494,7 +494,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.1"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.2"
},
"funding": [
{
@@ -502,7 +502,7 @@
"type": "github"
}
],
"time": "2026-02-18T12:24:42+00:00"
"time": "2026-02-20T16:13:53+00:00"
},
{
"name": "psr/container",
@@ -2683,7 +2683,9 @@
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
"platform": {
"php": ">=8.5.0"
},
"platform-dev": {},
"plugin-api-version": "2.9.0"
}

View File

@@ -13,6 +13,8 @@ If it feels necessary to open an issue first, please do so, before you open a PR
See also: https://docs.firefly-iii.org/explanation/support/#contributing-code
-->
@JC5
This PR fixes issue # (if relevant).

View File

@@ -10,7 +10,7 @@ on:
phpversion:
description: 'PHP version'
required: true
default: '8.4'
default: '8.5'
schedule:
- cron: '0 3 * * MON'
@@ -42,7 +42,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ github.event.inputs.phpversion || '8.4' }}
php-version: ${{ github.event.inputs.phpversion || '8.5' }}
extensions: mbstring, intl, zip, bcmath
- name: Switch and pull
run: |
@@ -177,7 +177,7 @@ jobs:
rm -rf vendor composer.lock
composer update --no-scripts --no-plugins -q
mago format || true
mago analyze --reporting-format=github || true
# mago analyze --reporting-format=github || true
sudo chown -R runner:docker resources/lang
.ci/phpcs.sh || true
- name: Calculate variables

View File

@@ -61,7 +61,7 @@ class TransactionRequest extends FormRequest
public function rules(): array
{
return ['query' => ['required', 'min:1', 'max:255', 'json', new IsValidBulkClause(ClauseType::TRANSACTION)]];
return ['query' => ['required', 'min:1', 'max:255', 'json', new IsValidBulkClause(ClauseType::TRANSACTION->value)]];
}
public function withValidator(Validator $validator): void

View File

@@ -0,0 +1,99 @@
<?php
declare(strict_types=1);
/*
* ChecksForUpdates.php
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Console\Commands\Tools;
use Carbon\Carbon;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequestInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Console\Command;
class ChecksForUpdates extends Command
{
use ShowsFriendlyMessages;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:check-for-updates {--force}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Checks for Firefly III updates';
/**
* Execute the console command.
*/
public function handle(): int
{
$build = Carbon::createFromTimestamp(config('firefly.build_time'), config('app.timezone'));
$version = config('firefly.version');
$this->friendlyLine(sprintf('You are running version "%s", built on %s', $version, $build->format('Y-m-d H:i')));
$permission = FireflyConfig::get('permission_update_check', -1)->data;
if (1 !== $permission && false === $this->option('force')) {
$this->friendlyWarning('Checking for updates is disabled. To overrule, use --force.');
return Command::SUCCESS;
}
if (str_contains(config('firefly.version'), 'develop')) {
$this->friendlyWarning('You are running a development version.');
}
/** @var UpdateRequestInterface $request */
$request = app(UpdateRequestInterface::class);
// stable, alpha or beta
$info = $request->getUpdateInformation($version, $build, 'stable');
if ('' !== $info->getError()) {
$this->friendlyError($info->getError());
return Command::FAILURE;
}
if (!$info->isNewVersionAvailable()) {
$this->friendlyInfo(trans('firefly.no_new_release_available'));
return Command::SUCCESS;
}
// if running develop, slightly different message.
if (str_contains($version, 'develop')) {
$this->friendlyInfo(trans('firefly.update_current_dev_older', ['version' => $version, 'new_version' => $info->getNewVersion()]));
return Command::SUCCESS;
}
$this->friendlyInfo(trans('firefly.update_new_version_alert', [
'your_version' => $version,
'new_version' => $info->getNewVersion(),
'date' => $info->getPublishedAt()->format('Y-m-d H:i:s'),
]));
return Command::SUCCESS;
}
}

View File

@@ -1,50 +0,0 @@
<?php
/*
* AccountBalance.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Entities;
use FireflyIII\Models\Account;
class AccountBalance
{
public string $amount;
public string $currencyId;
public string $id;
public static function fromArray(): self
{
$balance = new self();
$balance->id = (string) random_int(1, 1000);
// $balance->name = (string) random_int(1, 1000);
$balance->amount = (string) random_int(1, 1000);
$balance->currencyId = '1';
return $balance;
}
public function getAccount(): Account
{
return Account::inRandomOrder()->first();
}
}

View File

@@ -27,9 +27,9 @@ namespace FireflyIII\Enums;
/**
* Class ClauseType
*/
class ClauseType
enum ClauseType: string
{
public const string TRANSACTION = 'transaction';
public const string UPDATE = 'update';
public const string WHERE = 'where';
case TRANSACTION = 'transaction';
case UPDATE = 'update';
case WHERE = 'where';
}

View File

@@ -24,7 +24,9 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Update;
use Carbon\Carbon;
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequestInterface;
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateResponse;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Support\Facades\Log;
@@ -38,7 +40,7 @@ trait UpdateTrait
* 'message' => 'A new version is available.
* 'level' => 'info' / 'success' / 'error'
*/
public function getLatestRelease(): array
public function getLatestRelease(): UpdateResponse
{
Log::debug('Now in getLatestRelease()');
@@ -46,7 +48,9 @@ trait UpdateTrait
$checker = app(UpdateRequestInterface::class);
$channelConfig = FireflyConfig::get('update_channel', 'stable');
$channel = (string) $channelConfig->data;
$build = Carbon::createFromTimestamp(config('firefly.build_time'), config('app.timezone'));
$version = config('firefly.version');
return $checker->getUpdateInformation($channel);
return $checker->getUpdateInformation($version, $build, $channel);
}
}

View File

@@ -114,8 +114,27 @@ class UpdateController extends Controller
public function updateCheck(): RedirectResponse
{
$release = $this->getLatestRelease();
$level = 'info';
$message = trans('firefly.no_new_release_available');
if ('' !== $release->getError()) {
$level = 'error';
$message = $release->getError();
}
if ($release->isNewVersionAvailable()) {
// if running develop, slightly different message.
if (str_contains(config('firefly.version'), 'develop')) {
$message = trans('firefly.update_current_dev_older', ['version' => config('firefly.version'), 'new_version' => $release->getNewVersion()]);
}
if (!str_contains(config('firefly.version'), 'develop')) {
$message = trans('firefly.update_new_version_alert', [
'your_version' => config('firefly.version'),
'new_version' => $release->getNewVersion(),
'date' => $release->getPublishedAt()->format('Y-m-d H:i:s'),
]);
}
}
session()->flash($release['level'], $release['message']);
session()->flash($level, $message);
return redirect(route('settings.update-check'));
}

View File

@@ -80,13 +80,13 @@ abstract class Controller extends BaseController
View::share('FF_VERSION', config('firefly.version'));
View::share('FF_BUILD_TIME', config('firefly.build_time'));
// this breaks when running < php 8.5 and is totally intentional.
// $input = ' James is cool';
// $output = $input
// |> trim(...)
// |> (fn (string $string) => str_replace(' ', '-', $string))
// |> (fn (string $string) => str_replace(['.', '/', '…'], '', $string))
// |> strtolower(...);
// this breaks when running < PHP 8.5 and is totally intentional.
$input = ' James is cool';
$output = $input
|> trim(...)
|> (fn (string $string) => str_replace(' ', '-', $string))
|> (fn (string $string) => str_replace(['.', '/', '…'], '', $string))
|> strtolower(...);
// is webhooks enabled?
View::share(

View File

@@ -76,8 +76,27 @@ class ChecksForNewVersion implements ShouldQueue
// last check time was more than a week ago.
Log::debug('Have not checked for a new version in a week!');
$release = $this->getLatestRelease();
$level = 'info';
$message = trans('firefly.no_new_release_available');
if ('' !== $release->getError()) {
$level = 'error';
$message = $release->getError();
}
if ($release->isNewVersionAvailable()) {
// if running develop, slightly different message.
if (str_contains(config('firefly.version'), 'develop')) {
$message = trans('firefly.update_current_dev_older', ['version' => config('firefly.version'), 'new_version' => $release->getNewVersion()]);
}
if (!str_contains(config('firefly.version'), 'develop')) {
$message = trans('firefly.update_new_version_alert', [
'your_version' => config('firefly.version'),
'new_version' => $release->getNewVersion(),
'date' => $release->getPublishedAt()->format('Y-m-d H:i:s'),
]);
}
}
session()->flash($release['level'], $release['message']);
session()->flash($level, $message);
FireflyConfig::set('last_update_check', Carbon::now()->getTimestamp());
}

View File

@@ -81,7 +81,7 @@ class SendsTestNotification
return;
}
Log::debug(sprintf('Will send %s as a notification.', $class));
NotificationSender::send($event->user, new $class());
NotificationSender::send($event->{$type}, new $class());
Log::debug(sprintf('If you see no errors above this line, test notification was sent over channel "%s"', $event->channel));
}
}

View File

@@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Deprecated;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
@@ -32,65 +31,9 @@ class AccountType extends Model
{
use ReturnsIntegerIdTrait;
/** @deprecated */
#[Deprecated]
public const string ASSET = 'Asset account';
protected $casts = ['created_at' => 'datetime', 'updated_at' => 'datetime'];
/** @deprecated */
#[Deprecated]
public const string BENEFICIARY = 'Beneficiary account';
/** @deprecated */
#[Deprecated]
public const string CASH = 'Cash account';
/** @deprecated */
#[Deprecated]
public const string CREDITCARD = 'Credit card';
/** @deprecated */
#[Deprecated]
public const string DEBT = 'Debt';
/** @deprecated */
#[Deprecated]
public const string DEFAULT = 'Default account';
/** @deprecated */
#[Deprecated]
public const string EXPENSE = 'Expense account';
/** @deprecated */
#[Deprecated]
public const string IMPORT = 'Import account';
/** @deprecated */
#[Deprecated]
public const string INITIAL_BALANCE = 'Initial balance account';
/** @deprecated */
#[Deprecated]
public const string LIABILITY_CREDIT = 'Liability credit account';
/** @deprecated */
#[Deprecated]
public const string LOAN = 'Loan';
/** @deprecated */
#[Deprecated]
public const string MORTGAGE = 'Mortgage';
/** @deprecated */
#[Deprecated]
public const string RECONCILIATION = 'Reconciliation account';
/** @deprecated */
#[Deprecated]
public const string REVENUE = 'Revenue account';
protected $casts = ['created_at' => 'datetime', 'updated_at' => 'datetime'];
protected $fillable = ['type'];
protected $fillable = ['type'];
public function accounts(): HasMany
{

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Deprecated;
use FireflyIII\Handlers\Observer\AutoBudgetObserver;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
@@ -39,20 +38,8 @@ class AutoBudget extends Model
use ReturnsIntegerIdTrait;
use SoftDeletes;
/** @deprecated */
#[Deprecated]
public const int AUTO_BUDGET_ADJUSTED = 3;
/** @deprecated */
#[Deprecated]
public const int AUTO_BUDGET_RESET = 1;
/** @deprecated */
#[Deprecated]
public const int AUTO_BUDGET_ROLLOVER = 2;
protected $casts = ['amount' => 'string', 'native_amount' => 'string'];
protected $fillable = ['budget_id', 'amount', 'period', 'native_amount'];
protected $casts = ['amount' => 'string', 'native_amount' => 'string'];
protected $fillable = ['budget_id', 'amount', 'period', 'native_amount'];
public function budget(): BelongsTo
{

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Deprecated;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
@@ -36,23 +35,7 @@ class RecurrenceRepetition extends Model
use ReturnsIntegerIdTrait;
use SoftDeletes;
/** @deprecated */
#[Deprecated]
public const int WEEKEND_DO_NOTHING = 1;
/** @deprecated */
#[Deprecated]
public const int WEEKEND_SKIP_CREATION = 2;
/** @deprecated */
#[Deprecated]
public const int WEEKEND_TO_FRIDAY = 3;
/** @deprecated */
#[Deprecated]
public const int WEEKEND_TO_MONDAY = 4;
protected $casts = [
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
@@ -62,9 +45,9 @@ class RecurrenceRepetition extends Model
'weekend' => 'int',
];
protected $fillable = ['recurrence_id', 'weekend', 'repetition_type', 'repetition_moment', 'repetition_skip'];
protected $fillable = ['recurrence_id', 'weekend', 'repetition_type', 'repetition_moment', 'repetition_skip'];
protected $table = 'recurrences_repetitions';
protected $table = 'recurrences_repetitions';
public function recurrence(): BelongsTo
{

View File

@@ -30,7 +30,6 @@ use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@@ -39,7 +38,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
#[ObservedBy([TransactionObserver::class])]
class Transaction extends Model
{
use HasFactory;
use ReturnsIntegerIdTrait;
use SoftDeletes;

View File

@@ -34,7 +34,6 @@ use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@@ -53,7 +52,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
#[ObservedBy([DeletedTransactionJournalObserver::class])]
class TransactionJournal extends Model
{
use HasFactory;
use ReturnsIntegerIdTrait;
use ReturnsIntegerUserIdTrait;
use SoftDeletes;

View File

@@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Deprecated;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Model;
@@ -36,36 +35,8 @@ class TransactionType extends Model
use ReturnsIntegerIdTrait;
use SoftDeletes;
/** @deprecated */
#[Deprecated]
public const string DEPOSIT = 'Deposit';
/** @deprecated */
#[Deprecated]
public const string INVALID = 'Invalid';
/** @deprecated */
#[Deprecated]
public const string LIABILITY_CREDIT = 'Liability credit';
/** @deprecated */
#[Deprecated]
public const string OPENING_BALANCE = 'Opening balance';
/** @deprecated */
#[Deprecated]
public const string RECONCILIATION = 'Reconciliation';
/** @deprecated */
#[Deprecated]
public const string TRANSFER = 'Transfer';
/** @deprecated */
#[Deprecated]
public const string WITHDRAWAL = 'Withdrawal';
protected $casts = ['created_at' => 'datetime', 'updated_at' => 'datetime', 'deleted_at' => 'datetime'];
protected $fillable = ['type'];
protected $casts = ['created_at' => 'datetime', 'updated_at' => 'datetime', 'deleted_at' => 'datetime'];
protected $fillable = ['type'];
/**
* Route binder. Converts the key in the URL to the specified object (or throw 404).

View File

View File

@@ -1,68 +0,0 @@
<?php
/*
* AccountPolicy.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Policies;
use FireflyIII\Models\Account;
use FireflyIII\User;
use Illuminate\Support\Facades\Log;
class AccountPolicy
{
public function create(): bool
{
return auth()->check();
}
/**
* TODO needs better authentication, also for group.
*/
public function view(User $user, Account $account): bool
{
return auth()->check() && $user->id === $account->user_id;
}
public function viewAccountBalances(User $user, Account $account): bool
{
return $this->view($user, $account);
}
/**
* Everybody can do this, but selection should limit to user.
*/
public function viewAny(): bool
{
Log::debug(__METHOD__);
return auth()->check();
}
/**
* Everybody can do this, but selection should limit to user.
*/
public function viewUser(User $user, Account $account): bool
{
return $this->view($user, $account);
}
}

View File

@@ -1,47 +0,0 @@
<?php
/*
* BalancePolicy.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Policies;
use FireflyIII\Models\Account;
use FireflyIII\User;
class BalancePolicy
{
/**
* TODO needs better authentication.
*/
public function view(User $user, Account $account): bool
{
return auth()->check() && $user->id === $account->user_id;
}
/**
* Everybody can do this, but selection should limit to user.
*/
public function viewAny(): bool
{
return auth()->check();
}
}

View File

@@ -1,59 +0,0 @@
<?php
/*
* UserPolicy.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Policies;
use FireflyIII\User;
class UserPolicy
{
/**
* TODO needs better authentication.
*/
public function view(User $user, User $user1): bool
{
return true;
// return auth()->check() && $user->id === $account->user_id;
}
public function viewAccounts(User $user): bool
{
return true;
// return auth()->check();
}
/**
* Everybody can do this, but selection should limit to user.
*
* @return true
*/
public function viewAny(): bool
{
return true;
// return auth()->check();
}
}

View File

@@ -53,6 +53,7 @@ use FireflyIII\Repositories\UserGroup\UserGroupRepository;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Repositories\Webhook\WebhookRepository;
use FireflyIII\Repositories\Webhook\WebhookRepositoryInterface;
use FireflyIII\Services\FireflyIIIOrg\Update\GitHubUpdateRequest;
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequest;
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequestInterface;
use FireflyIII\Services\Password\PwndVerifierV2;
@@ -191,7 +192,8 @@ class FireflyServiceProvider extends ServiceProvider
$this->app->bind(PopupReportInterface::class, PopupReport::class);
$this->app->bind(ReportHelperInterface::class, ReportHelper::class);
$this->app->bind(FiscalHelperInterface::class, FiscalHelper::class);
$this->app->bind(UpdateRequestInterface::class, UpdateRequest::class);
// $this->app->bind(UpdateRequestInterface::class, UpdateRequest::class);
$this->app->bind(UpdateRequestInterface::class, GitHubUpdateRequest::class);
// webhooks:
$this->app->bind(MessageGeneratorInterface::class, StandardMessageGenerator::class);

View File

@@ -0,0 +1,226 @@
<?php
declare(strict_types=1);
/*
* GitHubUpdateRequest.php
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Services\FireflyIIIOrg\Update;
use Carbon\Carbon;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Log;
use Override;
class GitHubUpdateRequest implements UpdateRequestInterface
{
private string $currentVersion = '1.0.0';
private Carbon $currentBuild;
private string $channel = 'stable';
private bool $localDebug = false;
#[Override]
public function getUpdateInformation(string $currentVersion, Carbon $currentBuild, string $channel): UpdateResponse
{
$this->currentVersion = $currentVersion;
$this->channel = $channel;
$this->currentBuild = $currentBuild;
Log::debug(sprintf('Now in getUpdateInformation(%s, %s)', $currentVersion, $channel));
$response = new UpdateResponse();
$releases = $this->getReleases();
$filtered = $this->filterReleases($releases);
Log::debug(sprintf('Left with %d release(s) to compare', count($filtered)));
if (0 === count($filtered)) {
$response->setNewVersionAvailable(false);
return $response;
}
$newest = $this->getNewest($filtered);
Log::debug(sprintf('Newest release is "%s" released on %s', $newest['version'], $newest['published_at']->format('Y-m-d H:i')));
$response->setNewVersion($newest['version']);
$response->setPublishedAt($newest['published_at']);
// main question, is this release newer than the current one?
// if current version is "develop", compare date.
if (str_contains($currentVersion, 'develop')) {
Log::debug(sprintf('Compare with current version "%s", built on %s', $currentVersion, $currentBuild->format('Y-m-d H:i')));
if ($currentBuild->lt($newest['published_at']) && $currentBuild->diffInMinutes($newest['published_at']) > 10) {
Log::debug(sprintf(
'Current build %s is older than newest build %s, so a new release is available.',
$currentBuild->format('Y-m-d H:i:s e'),
$newest['published_at']->format('Y-m-d H:i:s e')
));
$response->setNewVersionAvailable(true);
return $response;
}
if ($currentBuild->gt($newest['published_at'])) {
Log::debug(sprintf(
'Current build %s is newer than newest build %s, so NO new release is available.',
$currentBuild->format('Y-m-d H:i'),
$newest['published_at']->format('Y-m-d H:i')
));
$response->setNewVersionAvailable(false);
return $response;
}
return $response;
}
// if not, compare version.
$res = version_compare($newest['version'], $currentVersion);
if ($res < 1) {
$response->setNewVersionAvailable(false);
return $response;
}
if (1 === $res) {
$response->setNewVersionAvailable(true);
return $response;
}
return $response;
}
private function filterReleases(array $releases): array
{
$return = [];
$weekAgo = now()->subWeek();
/** @var array $release */
foreach ($releases as $release) {
if ($release['published_at']->lte($this->currentBuild)) {
Log::debug(sprintf('Skip older version "%s"', $release['version']));
continue;
}
// new version must be at least a week old, unless it is a develop release.
if ($release['published_at']->gt($weekAgo) && !str_contains($release['version'], 'develop')) {
Log::debug(sprintf('Skip too new version "%s"', $release['version']));
continue;
}
// if channel is stable, and version is "alpha", continue.
// if channel is stable, and version is "beta", continue.
// if channel is beta, and version is "alpha", continue.
if (('stable' === $this->channel || 'beta' === $this->channel) && str_contains($release['version'], 'alpha')) {
Log::debug(sprintf('Skip version "%s"', $release['version']));
continue;
}
if ('stable' === $this->channel && str_contains($release['version'], 'beta')) {
Log::debug(sprintf('Skip version "%s"', $release['version']));
continue;
}
$return[] = $release;
}
return $return;
}
private function getNewest(array $releases): array
{
$latest = ['version' => '1.0.0', 'published_at' => now(config('app.timezone'))->startOfYear()];
foreach ($releases as $release) {
Log::debug(sprintf('Comparing current version "%s" with latest version "%s"', $release['version'], $latest['version']));
if (str_contains($release['version'], 'develop') || str_contains($latest['version'], 'develop')) {
Log::debug('Compare based on build time.');
// compare build times.
if ($latest['published_at']->lt($release['published_at'])) {
Log::debug(sprintf(
'Current date "%s" is newer than latest date "%s"',
$release['published_at']->format('Y-m-d H:i'),
$latest['published_at']->format('Y-m-d H:i')
));
$latest = $release;
}
}
if (!str_contains($release['version'], 'develop') && !str_contains($latest['version'], 'develop')) {
Log::debug('[a] Compare based on version.');
// compare version.
$res = version_compare($release['version'], $latest['version']);
if (1 === $res) {
Log::debug(sprintf('Version "%s" is newer than version "%s".', $release['version'], $latest['version']));
$latest = $release;
}
}
}
Log::debug(sprintf('Latest version seems to be "%s", released at %s', $latest['version'], $latest['published_at']->format('Y-m-d H:i e')));
return $latest;
}
private function getReleases(): array
{
$client = new Client();
$opts = ['headers' => ['User-Agent' => 'FireflyIII/'.config('firefly.version')]];
$return = [];
$body = '';
if ($this->localDebug && file_exists('json.json')) {
$body = file_get_contents('json.json');
}
if (!$this->localDebug) {
try {
$res = $client->get('https://api.github.com/repos/firefly-iii/firefly-iii/releases', $opts);
} catch (ClientException $e) {
Log::error($e->getMessage());
return [];
}
Log::debug('Successfully contacted GitHub');
$body = (string) $res->getBody();
}
if (!json_validate($body)) {
Log::debug('GitHub returned invalid JSON');
return [];
}
$json = json_decode($body, true);
/** @var array $release */
foreach ($json as $release) {
$version = $release['tag_name'];
$version = 'v' === $version[0] ? substr($version, 1) : $version;
$published = Carbon::parse($release['published_at'], config('app.timezone'));
// always skip "develop" releases, unless user is also running develop.
if (str_contains($version, 'develop') && !str_contains($this->currentVersion, 'develop')) {
Log::debug(sprintf('Skip version "%s"', $release['tag_name']));
continue;
}
$return[] = ['version' => $version, 'published_at' => $published];
}
return $return;
}
}

View File

@@ -24,10 +24,12 @@ declare(strict_types=1);
namespace FireflyIII\Services\FireflyIIIOrg\Update;
use Carbon\Carbon;
/**
* Interface UpdateRequestInterface
*/
interface UpdateRequestInterface
{
public function getUpdateInformation(string $channel): array;
public function getUpdateInformation(string $currentVersion, Carbon $currentBuild, string $channel): UpdateResponse;
}

View File

@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
/*
* UpdateResponse.php
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Services\FireflyIIIOrg\Update;
use Carbon\Carbon;
class UpdateResponse
{
private bool $newVersionAvailable = false;
private string $error = '';
private string $newVersion = '1.0.0';
private Carbon $publishedAt;
public function getError(): string
{
return $this->error;
}
public function getNewVersion(): string
{
return $this->newVersion;
}
public function getPublishedAt(): Carbon
{
return $this->publishedAt;
}
public function isNewVersionAvailable(): bool
{
return $this->newVersionAvailable;
}
public function setError(string $error): void
{
$this->error = $error;
}
public function setNewVersion(string $newVersion): void
{
$this->newVersion = $newVersion;
}
public function setNewVersionAvailable(bool $newVersionAvailable): void
{
$this->newVersionAvailable = $newVersionAvailable;
}
public function setPublishedAt(Carbon $publishedAt): void
{
$this->publishedAt = $publishedAt;
}
}

View File

@@ -75,12 +75,12 @@ class UpdateCheckCronjob extends AbstractCronjob
// last check time was more than a week ago.
Log::debug('Have not checked for a new version in a week!');
$release = $this->getLatestRelease();
if ('error' === $release['level']) {
if ('' !== $release->getError()) {
// get stuff from job:
$this->jobFired = true;
$this->jobErrored = true;
$this->jobSucceeded = false;
$this->message = $release['message'];
$this->message = $release->getError();
return;
}
@@ -88,6 +88,23 @@ class UpdateCheckCronjob extends AbstractCronjob
$this->jobFired = true;
$this->jobErrored = false;
$this->jobSucceeded = false;
$this->message = $release['message'];
$this->message = trans('firefly.no_new_release_available');
if ($release->isNewVersionAvailable()) {
// if running develop, slightly different message.
if (str_contains(config('firefly.version'), 'develop')) {
$this->message = trans('firefly.update_current_dev_older', [
'version' => config('firefly.version'),
'new_version' => $release->getNewVersion(),
]);
}
if (!str_contains(config('firefly.version'), 'develop')) {
$this->message = trans('firefly.update_new_version_alert', [
'your_version' => config('firefly.version'),
'new_version' => $release->getNewVersion(),
'date' => $release->getPublishedAt()->format('Y-m-d H:i:s'),
]);
}
}
}
}

View File

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

View File

@@ -40,86 +40,8 @@ use Override;
class AvailableBudgetEnrichment implements EnrichmentInterface
{
private Collection $collection; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private Collection $collection;
private readonly bool $convertToPrimary;
private array $currencies = [];
private array $currencyIds = [];
private array $ids = [];

View File

@@ -40,46 +40,7 @@ use Illuminate\Support\Facades\Log;
class BudgetLimitEnrichment implements EnrichmentInterface
{
private Collection $collection;
private readonly bool $convertToPrimary; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private readonly bool $convertToPrimary;
private array $currencies = [];
private array $currencyIds = [];
private Carbon $end;

View File

@@ -42,86 +42,8 @@ use Illuminate\Support\Facades\Log;
class PiggyBankEnrichment implements EnrichmentInterface
{
private array $accountIds = []; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $accountIds = [];
private array $accounts = [];
private array $amounts = [];
private Collection $collection;
private array $currencies = [];

View File

@@ -37,86 +37,8 @@ use Illuminate\Support\Facades\Log;
class PiggyBankEventEnrichment implements EnrichmentInterface
{
private array $accountCurrencies = []; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $accountCurrencies = [];
private array $accountIds = [];
private Collection $collection;
private array $currencies = [];
private array $groupIds = [];

View File

@@ -46,46 +46,7 @@ use Illuminate\Support\Facades\Log;
class SubscriptionEnrichment implements EnrichmentInterface
{
private BillDateCalculator $calculator;
private Collection $collection; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private Collection $collection;
private readonly bool $convertToPrimary;
private ?Carbon $end = null;
private array $mappedObjects = [];

View File

@@ -53,85 +53,7 @@ class TransactionGroupEnrichment implements EnrichmentInterface
private array $metaData = [];
private array $notes = [];
private readonly TransactionCurrency $primaryCurrency;
private array $tags = []; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $tags = [];
public function __construct()
{

View File

@@ -42,86 +42,8 @@ use stdClass;
class WebhookEnrichment implements EnrichmentInterface
{
private Collection $collection;
private array $deliveries = []; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
private array $deliveries = [];
private array $ids = [];
private array $responses = [];
private array $triggers = [];
private array $webhookDeliveries = [];

View File

@@ -143,7 +143,6 @@ class AvailableBudgetCalculator
$availableBudget = $this->abRepository->find($this->currency, $start, $end);
$availableBudgets = $this->abRepository->findInRange($this->currency, $start, $end);
Log::debug(sprintf('Found #%d', $availableBudget->id));
foreach ($availableBudgets as $item) {
Log::debug(sprintf(
'findInRange found available budget #%d (%s - %s), will update it.',

View File

@@ -3,7 +3,18 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## v6.4.23
## v6.5.0 - 2026-02-20
> [!IMPORTANT]
> This release is the same as 6.4.23, but only works on PHP 8.5 and higher. To continue using the latest version of Firefly III, you must upgrade to (at least) PHP 8.5.0, or switch to the Docker containers. Read more about Firefly III's release and support schedule in [`releases.md`](releases.md).
### Added
- Support for PHP 8.5
### Removed
- Support for PHP 8.4 and earlier
## v6.4.23 - 2026-02-20
> [!WARNING]
> If no pressing issues get reported, this release will be followed by **v6.5.0**. It will be exactly the same but require PHP 8.5.

View File

@@ -65,7 +65,7 @@
}
],
"require": {
"php": ">=8.4",
"php": ">=8.5",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-fileinfo": "*",
@@ -197,7 +197,7 @@
"php-http/discovery": true
},
"platform": {
"php": "8.4"
"php": "8.5"
},
"audit": {
"ignore": {

6
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "6c4181d945517372c00358f3828806bc",
"content-hash": "350d2b33cd703d3e5731ff7501e20d7c",
"packages": [
{
"name": "bacon/bacon-qr-code",
@@ -13140,7 +13140,7 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=8.4",
"php": ">=8.5",
"ext-bcmath": "*",
"ext-curl": "*",
"ext-fileinfo": "*",
@@ -13159,7 +13159,7 @@
},
"platform-dev": {},
"platform-overrides": {
"php": "8.4"
"php": "8.5"
},
"plugin-api-version": "2.9.0"
}

View File

@@ -25,11 +25,11 @@ declare(strict_types=1);
use FireflyIII\Enums\ClauseType;
return [
ClauseType::TRANSACTION => [
ClauseType::WHERE => [
ClauseType::TRANSACTION->value => [
ClauseType::WHERE->value => [
'account_id' => 'required|numeric|belongsToUser:accounts,id',
],
ClauseType::UPDATE => [
ClauseType::UPDATE->value => [
'account_id' => 'required|numeric|belongsToUser:accounts,id',
],
],

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' => 'develop/2026-02-20',
'build_time' => 1771595732,
'version' => 'develop/2026-02-21',
'build_time' => 1771667789,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used.

12
package-lock.json generated
View File

@@ -3779,9 +3779,9 @@
"license": "MIT"
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7153,9 +7153,9 @@
}
},
"node_modules/i18next": {
"version": "25.8.12",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.12.tgz",
"integrity": "sha512-hw59RF5QaH9i3l47hTXjeLLtzgVO8OtznlTJZbulmaLbz+itA1hIKWHTEiajY9W2SNPzvL8U5nTBVt7SsOGNRA==",
"version": "25.8.13",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.13.tgz",
"integrity": "sha512-E0vzjBY1yM+nsFrtgkjLhST2NBkirkvOVoQa0MSldhsuZ3jUge7ZNpuwG0Cfc74zwo5ZwRzg3uOgT+McBn32iA==",
"funding": [
{
"type": "individual",

View File

@@ -16,7 +16,10 @@ The different alpha and beta builds will be compiled from their corresponding ta
### Minor Release Support Matrix
| Version | Supported |
|----------------------------------|--------------------|
| Firefly III v6.2.x | :white_check_mark: |
| Firefly III v6.5.x | :white_check_mark: |
| Firefly III v6.4.x | :x: |
| Firefly III v6.3.x | :x: |
| Firefly III v6.2.x | :x: |
| Firefly III v6.1.x | :x: |
| Firefly III v6.0.x | :x: |
| Firefly III v5.8.x | :x: |

View File

@@ -331,6 +331,7 @@ return [
'update_newer_version_alert' => 'You are running :your_version, which is newer than the latest release, :new_version.',
'update_check_error' => 'An error occurred while checking for updates: :error',
'unknown_error' => 'Unknown error. Sorry about that.',
'no_new_release_available' => 'There is no newer release available. You are up to date.',
'disabled_but_check' => 'You disabled update checking. So don\'t forget to check for updates yourself every now and then. Thank you!',
'admin_update_channel_title' => 'Update channel',
'admin_update_channel_explain' => 'Firefly III has three update "channels" which determine how ahead of the curve you are in terms of features, enhancements and bugs. Use the "beta" channel if you\'re adventurous and the "alpha" when you like to live life dangerously.',