Compare commits

...

90 Commits

Author SHA1 Message Date
github-actions[bot]
386bb811a8 Merge pull request #11742 from firefly-iii/release-1771230440
🤖 Automatically merge the PR into the develop branch.
2026-02-16 09:27:29 +01:00
JC5
653fa53da2 🤖 Auto commit for release 'develop' on 2026-02-16 2026-02-16 09:27:20 +01:00
Sander Dorigo
63d4572863 Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop 2026-02-16 09:22:36 +01:00
Sander Dorigo
9eb31fc777 Remove check for #11735 2026-02-16 09:22:30 +01:00
github-actions[bot]
7fd33035a6 Merge pull request #11741 from firefly-iii/release-1771230058
🤖 Automatically merge the PR into the develop branch.
2026-02-16 09:21:05 +01:00
JC5
5a87f6b2c0 🤖 Auto commit for release 'develop' on 2026-02-16 2026-02-16 09:20:58 +01:00
Sander Dorigo
cbebd7928f Fix #11738 2026-02-16 09:16:42 +01:00
github-actions[bot]
73089c2084 Merge pull request #11737 from firefly-iii/release-1771214139
🤖 Automatically merge the PR into the develop branch.
2026-02-16 04:55:46 +01:00
JC5
34260f2a4f 🤖 Auto commit for release 'develop' on 2026-02-16 2026-02-16 04:55:39 +01:00
James Cole
c3872aa738 Fix header in changelog. 2026-02-15 19:44:38 +01:00
github-actions[bot]
4bcd163b47 Merge pull request #11732 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2026-02-15 19:42:55 +01:00
github-actions[bot]
31d444292f Merge pull request #11731 from firefly-iii/release-1771180963
🤖 Automatically merge the PR into the develop branch.
2026-02-15 19:42:50 +01:00
JC5
a27e21f002 🤖 Auto commit for release 'v6.4.22' on 2026-02-15 2026-02-15 19:42:43 +01:00
github-actions[bot]
0f7118d5b3 Merge pull request #11730 from firefly-iii/release-1771176353
🤖 Automatically merge the PR into the develop branch.
2026-02-15 18:26:02 +01:00
JC5
4f9a1fde5d 🤖 Auto commit for release 'develop' on 2026-02-15 2026-02-15 18:25:54 +01:00
James Cole
bc596cb1c2 Update changelog and fix calls during startup. 2026-02-15 18:18:47 +01:00
github-actions[bot]
7110556ef0 Merge pull request #11729 from firefly-iii/release-1771170628
🤖 Automatically merge the PR into the develop branch.
2026-02-15 16:50:35 +01:00
JC5
3e1b703dfc 🤖 Auto commit for release 'develop' on 2026-02-15 2026-02-15 16:50:28 +01:00
James Cole
fce0750509 Remove unnecessary package. 2026-02-15 16:43:35 +01:00
github-actions[bot]
f5385d0229 Merge pull request #11727 from firefly-iii/release-1771154935
🤖 Automatically merge the PR into the develop branch.
2026-02-15 12:29:02 +01:00
JC5
8599c4a3c1 🤖 Auto commit for release 'develop' on 2026-02-15 2026-02-15 12:28:55 +01:00
James Cole
d210e7dcdd Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2026-02-15 12:24:46 +01:00
James Cole
8de9e0ba29 Remove checks for null 2026-02-15 12:24:33 +01:00
github-actions[bot]
7fa9e79f2a Merge pull request #11726 from firefly-iii/release-1771154592
🤖 Automatically merge the PR into the develop branch.
2026-02-15 12:23:20 +01:00
JC5
4a5281fd80 🤖 Auto commit for release 'develop' on 2026-02-15 2026-02-15 12:23:13 +01:00
James Cole
ad60974430 Update command so it is really the first attempt to connect. 2026-02-15 12:19:10 +01:00
James Cole
195794881b Catch nulls in dates. 2026-02-15 12:11:25 +01:00
James Cole
3e6a997dd5 Catch preferences with no date info. 2026-02-15 12:09:57 +01:00
James Cole
2eedfd9f26 Merge branch 'main' into develop 2026-02-15 12:06:20 +01:00
James Cole
9ec0515bb6 Fix string pointer 2026-02-15 12:06:05 +01:00
James Cole
6b197eecb9 Remove PR update rule from mergify configuration
Removed the rule for automatically updating PRs before merging.

Signed-off-by: James Cole <james@firefly-iii.org>
2026-02-15 11:58:07 +01:00
github-actions[bot]
591c970882 Merge pull request #11725 from firefly-iii/release-1771152972
🤖 Automatically merge the PR into the develop branch.
2026-02-15 11:56:22 +01:00
JC5
15d91dbe1b 🤖 Auto commit for release 'develop' on 2026-02-15 2026-02-15 11:56:12 +01:00
James Cole
6ff87bf447 Add command that first verifies the database connection. Saves some time booting up. 2026-02-15 11:51:04 +01:00
James Cole
147ce154d8 Remove unused file. 2026-02-15 11:25:26 +01:00
James Cole
2c8be33000 Clean up routes and API calls. 2026-02-15 11:25:12 +01:00
github-actions[bot]
b472890c84 Merge pull request #11724 from firefly-iii/release-1771138148
🤖 Automatically merge the PR into the develop branch.
2026-02-15 07:49:18 +01:00
JC5
2fabcf5193 🤖 Auto commit for release 'develop' on 2026-02-15 2026-02-15 07:49:08 +01:00
James Cole
5ed4e7aa79 Clean up kernel files and middleware. 2026-02-15 07:41:31 +01:00
James Cole
973caad7e4 Clean up providers 2026-02-15 07:27:28 +01:00
github-actions[bot]
d273503a15 Merge pull request #11723 from firefly-iii/release-1771134641
🤖 Automatically merge the PR into the develop branch.
2026-02-15 06:50:49 +01:00
JC5
cc149adb5d 🤖 Auto commit for release 'develop' on 2026-02-15 2026-02-15 06:50:41 +01:00
James Cole
ac8bcb786b Fix https://github.com/firefly-iii/firefly-iii/issues/11720 2026-02-15 06:18:52 +01:00
github-actions[bot]
642deefba5 Merge pull request #11718 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2026-02-14 20:40:32 +01:00
github-actions[bot]
5b13b64fd7 Merge pull request #11717 from firefly-iii/release-1771098019
🤖 Automatically merge the PR into the develop branch.
2026-02-14 20:40:27 +01:00
JC5
653a64d0a8 🤖 Auto commit for release 'v6.4.21' on 2026-02-14 2026-02-14 20:40:19 +01:00
github-actions[bot]
c9dcdc90ec Merge pull request #11716 from firefly-iii/release-1771097648
🤖 Automatically merge the PR into the develop branch.
2026-02-14 20:34:19 +01:00
JC5
1f04888331 🤖 Auto commit for release 'develop' on 2026-02-14 2026-02-14 20:34:08 +01:00
James Cole
28c21ecb7e Update changelog 2026-02-14 20:29:19 +01:00
github-actions[bot]
7382030e61 Merge pull request #11711 from firefly-iii/release-1771075473
🤖 Automatically merge the PR into the develop branch.
2026-02-14 14:24:39 +01:00
JC5
a573e19dbc 🤖 Auto commit for release 'develop' on 2026-02-14 2026-02-14 14:24:33 +01:00
James Cole
b152a2c8d9 Fix #11710 2026-02-14 14:20:24 +01:00
github-actions[bot]
7e14c36fc0 Merge pull request #11709 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2026-02-14 13:38:49 +01:00
github-actions[bot]
58bfc7f8ce Merge pull request #11708 from firefly-iii/release-1771072714
🤖 Automatically merge the PR into the develop branch.
2026-02-14 13:38:43 +01:00
JC5
6b8c005108 🤖 Auto commit for release 'v6.4.20' on 2026-02-14 2026-02-14 13:38:34 +01:00
James Cole
ceb660fd02 Fix missing setting. Restore 8.4 for the moment. Very professional. 2026-02-14 13:33:29 +01:00
James Cole
7fac1e8614 Remove statistics. 2026-02-14 13:25:39 +01:00
github-actions[bot]
809e34f5fe Merge pull request #11707 from firefly-iii/release-1771071314
🤖 Automatically merge the PR into the develop branch.
2026-02-14 13:15:20 +01:00
JC5
73ca57c8c4 🤖 Auto commit for release 'develop' on 2026-02-14 2026-02-14 13:15:14 +01:00
James Cole
63088ffeb1 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2026-02-14 13:10:54 +01:00
James Cole
4e88ebd52d Make Firefly III PHP 8.5 only. 2026-02-14 13:10:41 +01:00
github-actions[bot]
85fd38d146 Merge pull request #11706 from firefly-iii/release-1771070819
🤖 Automatically merge the PR into the develop branch.
2026-02-14 13:07:16 +01:00
JC5
e83d7051eb 🤖 Auto commit for release 'develop' on 2026-02-14 2026-02-14 13:06:59 +01:00
James Cole
567f2dae17 Remove problematic comment repetition by Mago. 2026-02-14 13:02:48 +01:00
github-actions[bot]
c231ae4016 Merge pull request #11705 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2026-02-14 12:55:26 +01:00
github-actions[bot]
fb13a4cdcb Merge pull request #11704 from firefly-iii/release-1771070112
🤖 Automatically merge the PR into the develop branch.
2026-02-14 12:55:21 +01:00
JC5
724042e1d8 🤖 Auto commit for release 'v6.4.19' on 2026-02-14 2026-02-14 12:55:12 +01:00
James Cole
84a30c3c8f Missing ltter. 2026-02-14 12:49:16 +01:00
github-actions[bot]
6c9dac831a Merge pull request #11703 from firefly-iii/release-1771069573
🤖 Automatically merge the PR into the develop branch.
2026-02-14 12:46:20 +01:00
JC5
e605ddb779 🤖 Auto commit for release 'develop' on 2026-02-14 2026-02-14 12:46:13 +01:00
James Cole
4b19ed8f07 Add changelog. 2026-02-14 12:41:28 +01:00
James Cole
57bd8e09d4 Fix #11702 2026-02-14 10:31:01 +01:00
github-actions[bot]
32f1a7c9c2 Merge pull request #11701 from firefly-iii/release-1771057524
🤖 Automatically merge the PR into the develop branch.
2026-02-14 09:25:32 +01:00
JC5
fc5b0db43f 🤖 Auto commit for release 'develop' on 2026-02-14 2026-02-14 09:25:24 +01:00
James Cole
c2721f3f48 Fix https://github.com/firefly-iii/firefly-iii/issues/11700 2026-02-14 08:18:53 +01:00
James Cole
96291c9bce Fix https://github.com/firefly-iii/firefly-iii/issues/11684 2026-02-14 08:17:19 +01:00
James Cole
ab9400aaee Merge branches 'develop' and 'develop' of github.com:firefly-iii/firefly-iii into develop 2026-02-13 08:05:02 +01:00
James Cole
31d1ee11cb Fix https://github.com/firefly-iii/firefly-iii/issues/11694 2026-02-13 08:04:39 +01:00
github-actions[bot]
694dc3816c Merge pull request #11699 from firefly-iii/release-1770965983
🤖 Automatically merge the PR into the develop branch.
2026-02-13 07:59:49 +01:00
JC5
c647fa7b94 🤖 Auto commit for release 'develop' on 2026-02-13 2026-02-13 07:59:43 +01:00
James Cole
022d59bfdd Fix https://github.com/firefly-iii/firefly-iii/issues/11688 2026-02-13 07:33:30 +01:00
James Cole
057b82b471 fix rename of rules when bill name changes. 2026-02-11 07:00:59 +01:00
github-actions[bot]
2872c6592f Merge pull request #11692 from firefly-iii/release-1770751884
🤖 Automatically merge the PR into the develop branch.
2026-02-10 20:31:31 +01:00
JC5
fa02c15f55 🤖 Auto commit for release 'develop' on 2026-02-10 2026-02-10 20:31:24 +01:00
James Cole
c74c8a96b8 Validate directory permissions with a lot of debug logs. 2026-02-10 20:26:41 +01:00
github-actions[bot]
2c2ebae8fa Merge pull request #11691 from firefly-iii/release-1770727195
🤖 Automatically merge the PR into the develop branch.
2026-02-10 13:40:04 +01:00
JC5
aff9afb767 🤖 Auto commit for release 'develop' on 2026-02-10 2026-02-10 13:39:55 +01:00
James Cole
c8e95fe131 Fix audit log entry position. 2026-02-09 20:05:38 +01:00
James Cole
cef514c22b Merge pull request #11680 from firefly-iii/dependabot/composer/develop/mailersend/laravel-driver-3.0.0 2026-02-09 05:57:03 +01:00
dependabot[bot]
9711bc1d04 Bump mailersend/laravel-driver from 2.12.0 to 3.0.0
Bumps [mailersend/laravel-driver](https://github.com/mailersend/mailersend-laravel-driver) from 2.12.0 to 3.0.0.
- [Release notes](https://github.com/mailersend/mailersend-laravel-driver/releases)
- [Commits](https://github.com/mailersend/mailersend-laravel-driver/compare/v2.12.0...v3.0.0)

---
updated-dependencies:
- dependency-name: mailersend/laravel-driver
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-09 03:52:32 +00:00
104 changed files with 1358 additions and 945 deletions

View File

@@ -402,16 +402,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.93.1",
"version": "v3.94.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "b3546ab487c0762c39f308dc1ec0ea2c461fc21a"
"reference": "883b20fb38c7866de9844ab6d0a205c423bde2d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/b3546ab487c0762c39f308dc1ec0ea2c461fc21a",
"reference": "b3546ab487c0762c39f308dc1ec0ea2c461fc21a",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/883b20fb38c7866de9844ab6d0a205c423bde2d4",
"reference": "883b20fb38c7866de9844ab6d0a205c423bde2d4",
"shasum": ""
},
"require": {
@@ -428,7 +428,7 @@
"react/event-loop": "^1.5",
"react/socket": "^1.16",
"react/stream": "^1.4",
"sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
"sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0",
"symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0",
"symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
"symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
@@ -442,18 +442,18 @@
"symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0"
},
"require-dev": {
"facile-it/paraunit": "^1.3.1 || ^2.7",
"infection/infection": "^0.32",
"justinrainbow/json-schema": "^6.6",
"facile-it/paraunit": "^1.3.1 || ^2.7.1",
"infection/infection": "^0.32.3",
"justinrainbow/json-schema": "^6.6.4",
"keradus/cli-executor": "^2.3",
"mikey179/vfsstream": "^1.6.12",
"php-coveralls/php-coveralls": "^2.9",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
"phpunit/phpunit": "^9.6.31 || ^10.5.60 || ^11.5.48",
"php-coveralls/php-coveralls": "^2.9.1",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.7",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.7",
"phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.51",
"symfony/polyfill-php85": "^1.33",
"symfony/var-dumper": "^5.4.48 || ^6.4.26 || ^7.4.0 || ^8.0",
"symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0"
"symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.4",
"symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.1"
},
"suggest": {
"ext-dom": "For handling output formats in XML",
@@ -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.93.1"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.0"
},
"funding": [
{
@@ -502,7 +502,7 @@
"type": "github"
}
],
"time": "2026-01-28T23:50:50+00:00"
"time": "2026-02-11T16:44:33+00:00"
},
{
"name": "psr/container",
@@ -1185,29 +1185,29 @@
},
{
"name": "sebastian/diff",
"version": "7.0.0",
"version": "8.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "7ab1ea946c012266ca32390913653d844ecd085f"
"reference": "a2b6d09d7729ee87d605a439469f9dcc39be5ea3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f",
"reference": "7ab1ea946c012266ca32390913653d844ecd085f",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/a2b6d09d7729ee87d605a439469f9dcc39be5ea3",
"reference": "a2b6d09d7729ee87d605a439469f9dcc39be5ea3",
"shasum": ""
},
"require": {
"php": ">=8.3"
"php": ">=8.4"
},
"require-dev": {
"phpunit/phpunit": "^12.0",
"phpunit/phpunit": "^13.0",
"symfony/process": "^7.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "7.0-dev"
"dev-main": "8.0-dev"
}
},
"autoload": {
@@ -1240,15 +1240,27 @@
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"security": "https://github.com/sebastianbergmann/diff/security/policy",
"source": "https://github.com/sebastianbergmann/diff/tree/7.0.0"
"source": "https://github.com/sebastianbergmann/diff/tree/8.0.0"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/diff",
"type": "tidelift"
}
],
"time": "2025-02-07T04:55:46+00:00"
"time": "2026-02-06T04:42:27+00:00"
},
{
"name": "symfony/console",

7
.github/mergify.yml vendored
View File

@@ -1,11 +1,4 @@
pull_request_rules:
- name: Make sure PR are up to date before merging
description: This automatically updates PRs when they are out-of-date with the
base branch to avoid semantic conflicts (next step is using a merge
queue).
conditions: []
actions:
update:
- name: Close all on main
conditions:
- base=main

View File

@@ -167,7 +167,7 @@ class BasicController extends Controller
],
];
$newIncomes = [
$primary->id => [
$primary->id => [
'currency_id' => $primary->id,
'currency_code' => $primary->code,
'currency_symbol' => $primary->symbol,
@@ -176,7 +176,7 @@ class BasicController extends Controller
],
];
$sums = [
$primary->id => [
$primary->id => [
'currency_id' => $primary->id,
'currency_code' => $primary->code,
'currency_symbol' => $primary->symbol,
@@ -244,7 +244,7 @@ class BasicController extends Controller
// create objects for big array.
$return[] = [
'key' => sprintf('balance-in-%s', $currency->code),
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $sums[$currencyId]['sum'] ?? '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
@@ -258,7 +258,7 @@ class BasicController extends Controller
];
$return[] = [
'key' => sprintf('spent-in-%s', $currency->code),
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $expenses[$currencyId]['sum'] ?? '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
@@ -270,7 +270,7 @@ class BasicController extends Controller
];
$return[] = [
'key' => sprintf('earned-in-%s', $currency->code),
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $incomes[$currencyId]['sum'] ?? '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
@@ -286,7 +286,7 @@ class BasicController extends Controller
// create objects for big array.
$return[] = [
'key' => sprintf('balance-in-%s', $currency->code),
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
@@ -298,7 +298,7 @@ class BasicController extends Controller
];
$return[] = [
'key' => sprintf('spent-in-%s', $currency->code),
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
@@ -310,7 +310,7 @@ class BasicController extends Controller
];
$return[] = [
'key' => sprintf('earned-in-%s', $currency->code),
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
@@ -345,7 +345,7 @@ class BasicController extends Controller
$currencies[$currencyId] ??= $this->currencyRepos->find($currencyId);
$return[$currencyId] = [
'key' => sprintf('left-to-spend-in-%s', $currencies[$currencyId]->code),
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $currencies[$currencyId]->symbol]),
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $currencies[$currencyId]->symbol]),
'no_available_budgets' => false,
'monetary_value' => $availableBudget,
'currency_id' => (string) $currencies[$currencyId]->id,
@@ -386,7 +386,7 @@ class BasicController extends Controller
$return[$currencyId] = [
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]),
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]),
'no_available_budgets' => false,
'monetary_value' => $leftToSpend,
'currency_id' => (string) $row['currency_id'],
@@ -493,7 +493,7 @@ class BasicController extends Controller
// return stuff
$return[] = [
'key' => sprintf('net-worth-in-%s', $data['currency_code']),
'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $data['currency_symbol']]),
'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $data['currency_symbol']]),
'monetary_value' => $amount,
'currency_id' => (string) $data['currency_id'],
'currency_code' => $data['currency_code'],
@@ -507,7 +507,7 @@ class BasicController extends Controller
if (0 === count($return)) {
$return[] = [
'key' => sprintf('net-worth-in-%s', $this->primaryCurrency->code),
'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $this->primaryCurrency->symbol]),
'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $this->primaryCurrency->symbol]),
'monetary_value' => '0',
'currency_id' => (string) $this->primaryCurrency->id,
'currency_code' => $this->primaryCurrency->code,
@@ -533,7 +533,7 @@ class BasicController extends Controller
*/
$paidAmount = $this->billRepository->sumPaidInRange($start, $end);
$unpaidAmount = $this->billRepository->sumUnpaidInRange($start, $end);
$currencies = [$this->primaryCurrency->id => $this->primaryCurrency];
$currencies = [$this->primaryCurrency->id => $this->primaryCurrency];
if ($this->convertToPrimary) {
$converter = new ExchangeRateConverter();
@@ -598,7 +598,7 @@ class BasicController extends Controller
$amount = bcmul((string) $info['sum'], '-1');
$return[] = [
'key' => sprintf('bills-paid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]),
'monetary_value' => $amount,
'currency_id' => (string) $info['id'],
'currency_code' => $info['code'],
@@ -617,7 +617,7 @@ class BasicController extends Controller
$amount = bcmul((string) $info['sum'], '-1');
$return[] = [
'key' => sprintf('bills-unpaid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]),
'monetary_value' => $amount,
'currency_id' => (string) $info['id'],
'currency_code' => $info['code'],
@@ -636,7 +636,7 @@ class BasicController extends Controller
$return[] = [
'key' => sprintf('bills-paid-in-%s', $currency->code),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $currency->symbol]),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
@@ -648,7 +648,7 @@ class BasicController extends Controller
];
$return[] = [
'key' => sprintf('bills-unpaid-in-%s', $currency->code),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $currency->symbol]),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => '0',
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,

View File

@@ -113,7 +113,7 @@ class UpdateRequest extends FormRequest
];
$this->booleanFields = ['reconciled'];
$this->arrayFields = ['tags'];
$data = ['batch_submission' => false];
$data = ['batch_submission' => false];
if ($this->has('transactions')) {
$data['transactions'] = $this->getTransactionData();
}

View File

@@ -63,6 +63,9 @@ class UpdateRequest extends FormRequest
{
/** @var TransactionCurrency $currency */
$currency = $this->route()->parameter('currency_code');
if (is_string($currency)) {
$currency = TransactionCurrency::whereCode($currency)->first();
}
return [
'name' => sprintf('min:1|max:255|unique:transaction_currencies,name,%d', $currency->id),

View File

@@ -56,8 +56,8 @@ class CorrectsGroupAccounts extends Command
}
}
$flags = new TransactionGroupEventFlags();
$flags->applyRules = true;
$flags->fireWebhooks = true;
$flags->applyRules = false;
$flags->fireWebhooks = false;
$flags->recalculateCredit = true;
$objects = new TransactionGroupEventObjects();
foreach ($groups as $groupId) {

View File

@@ -68,7 +68,7 @@ class CorrectsMetaDataFields extends Command
private function rename(string $original, string $update): void
{
$total = DB::table('journal_meta')->where('name', '=', $original)->update(['name' => $update]);
$total = DB::table('journal_meta')->where('name', '=', $original)->update(['name' => $update]);
$this->count += $total;
}
}

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Console\Commands\Integrity;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
class ValidatesFilePermissions extends Command
{
@@ -50,26 +51,39 @@ class ValidatesFilePermissions extends Command
*/
public function handle(): int
{
Log::debug(sprintf('Start of %s', $this->signature));
$directories = [storage_path('upload')];
$errors = false;
/** @var string $directory */
foreach ($directories as $directory) {
Log::debug(sprintf('Processing directory: %s', $directory));
if (!is_dir($directory)) {
$this->friendlyError(sprintf('Directory "%s" cannot found. It is necessary to allow files to be uploaded.', $directory));
$errors = true;
$message = sprintf('Directory "%s" cannot found. It is necessary to allow files to be uploaded.', $directory);
Log::error($message);
$this->friendlyError($message);
$errors = true;
continue;
}
Log::debug('It is a directory!');
if (!is_writable($directory)) {
$this->friendlyError(sprintf('Directory "%s" is not writeable. Uploading attachments may fail silently.', $directory));
$errors = true;
$message = sprintf('Directory "%s" is not writeable. Uploading attachments may fail silently.', $directory);
$this->friendlyError($message);
Log::error($message);
$errors = true;
}
Log::debug('It is writeable!');
Log::debug(sprintf('Done processing %s', $directory));
}
Log::debug('Done with loop.');
if (false === $errors) {
Log::debug('No errors.');
$this->friendlyInfo('All necessary file paths seem to exist, and are writeable.');
}
Log::debug(sprintf('End of %s', $this->signature));
return self::SUCCESS;
}
}

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\System;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Console\Commands\Tools\VerifiesDatabaseConnectionTrait;
use Illuminate\Console\Command;
use PDO;
use PDOException;
@@ -32,6 +33,7 @@ use PDOException;
class CreatesDatabase extends Command
{
use ShowsFriendlyMessages;
use VerifiesDatabaseConnectionTrait;
protected $description = 'Tries to create the database if it doesn\'t exist yet.';
@@ -39,21 +41,27 @@ class CreatesDatabase extends Command
public function handle(): int
{
if ('mysql' !== env('DB_CONNECTION')) { // @phpstan-ignore larastan.noEnvCallsOutsideOfConfig */
$this->friendlyInfo(sprintf('CreateDB does not apply to "%s", skipped.', env('DB_CONNECTION')));
$connected = $this->verifyDatabaseConnection();
if (!$connected) {
$this->friendlyError('Failed to connect to the database. Is it up?');
return Command::FAILURE;
}
if ('mysql' !== config('database.default')) { // @phpstan-ignore larastan.noEnvCallsOutsideOfConfig */
$this->friendlyInfo(sprintf('CreateDB does not apply to "%s", skipped.', config('database.default')));
return 0;
}
// try to set up a raw connection:
$exists = false;
$dsn = sprintf('mysql:host=%s;port=%d;charset=utf8mb4', env('DB_HOST'), env('DB_PORT'));
$exists = false;
$dsn = sprintf('mysql:host=%s;port=%d;charset=utf8mb4', env('DB_HOST'), env('DB_PORT'));
if ('' !== (string) env('DB_SOCKET')) {
$dsn = sprintf('mysql:unix_socket=%s;charset=utf8mb4', env('DB_SOCKET'));
}
$this->friendlyLine(sprintf('DSN is %s', $dsn));
$options = [
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
@@ -71,7 +79,7 @@ class CreatesDatabase extends Command
// only continue when no error.
// with PDO, try to list DB's (
/** @var array $stmt */
$stmt = $pdo->query('SHOW DATABASES;');
$stmt = $pdo->query('SHOW DATABASES;');
// slightly more complex but less error-prone.
foreach ($stmt as $row) {
$name = $row['Database'] ?? false;

View File

@@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
/*
* VerifiesDatabaseConnection.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 FireflyIII\Console\Commands\ShowsFriendlyMessages;
use Illuminate\Console\Command;
class VerifiesDatabaseConnection extends Command
{
use ShowsFriendlyMessages;
use VerifiesDatabaseConnectionTrait;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:verify-database-connection';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command tries to connect to the database.';
/**
* Execute the console command.
*/
public function handle(): int
{
$connected = $this->verifyDatabaseConnection();
if ($connected) {
$this->friendlyPositive('Connected to the database.');
return Command::SUCCESS;
}
$this->friendlyError('Failed to connect to the database. Is it up?');
return Command::FAILURE;
}
}

View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
/*
* VerifiesDatabaseConnectionTrait.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 Exception;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
trait VerifiesDatabaseConnectionTrait
{
protected function verifyDatabaseConnection(): bool
{
$loops = 30;
$loop = 0;
$queries = ['pgsql' => 'SELECT * FROM pg_catalog.pg_tables;', 'sqlite' => 'SELECT name FROM sqlite_schema;', 'mysql' => 'SHOW TABLES;'];
$default = config('database.default');
if (!array_key_exists($default, $queries)) {
$this->friendlyWarning(sprintf('Cannot validate database connection for "%s"', $default));
return true;
}
$query = $queries[$default];
$connected = false;
Log::debug(sprintf('Connecting to database "%s"...', config('database.default')));
while (!$connected && $loop < $loops) {
try {
DB::select($query);
$connected = true;
} catch (QueryException $e) {
Log::error(sprintf('Loop #%d: connection failed: %s', $loop, $e->getMessage()));
$this->friendlyWarning(sprintf('Database connection attempt #%d failed. Sleep for 10 seconds...', $loop + 1));
sleep(10);
} catch (Exception $e) {
Log::error(sprintf('Loop #%d: not connected yet because of a %s: %s', $loop, get_class($e), $e->getMessage()));
$this->friendlyWarning(sprintf('Database connection attempt #%d failed. Sleep for 10 seconds...', $loop + 1));
sleep(10);
}
++$loop;
}
return $connected;
}
}

View File

@@ -110,7 +110,7 @@ class UpgradesBillsToRules extends Command
'active' => true,
'strict' => false,
'stop_processing' => false, // field is no longer used.
'title' => (string) trans('firefly.rule_for_bill_title', ['name' => $bill->name], $languageString),
'title' => (string) trans('firefly.rule_for_bill_title', ['name' => $bill->name], $languageString),
'description' => (string) trans('firefly.rule_for_bill_description', ['name' => $bill->name], $languageString),
'trigger' => 'store-journal',
'triggers' => [['type' => 'description_contains', 'value' => $match]],

View File

@@ -94,6 +94,7 @@ class UpgradesDatabase extends Command
private function callInitialCommands(): void
{
$this->call('firefly-iii:verify-database-connection');
$this->call('migrate', ['--seed' => true, '--force' => true, '--no-interaction' => true]);
$this->call('upgrade:600-pgsql-sequences');
$this->call('upgrade:480-decrypt-all');

View File

@@ -1,69 +0,0 @@
<?php
/**
* Kernel.php
* Copyright (c) 2020 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\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Illuminate\Support\Facades\Log;
use Override;
/**
* File to make sure commands work.
*/
class Kernel extends ConsoleKernel
{
/**
* Register the commands for the application.
*/
#[Override]
protected function commands(): void
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
/**
* Define the application's command schedule.
*/
#[Override]
protected function schedule(Schedule $schedule): void
{
$schedule->call(static function (): void {
Log::error('Firefly III no longer users the Laravel scheduler to do cron jobs! Please read the instructions at https://docs.firefly-iii.org/');
echo "\n";
echo '------------';
echo "\n";
echo wordwrap('Firefly III no longer users the Laravel scheduler to do cron jobs! Please read the instructions here:');
echo "\n";
echo 'https://docs.firefly-iii.org/';
echo "\n\n";
echo 'Disable this cron job!';
echo "\n";
echo '------------';
echo "\n";
})->daily();
}
}

View File

@@ -1,8 +1,10 @@
<?php
declare(strict_types=1);
/*
* api-noauth.php
* Copyright (c) 2021 james@firefly-iii.org
* UpdatedExistingBill.php
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -20,20 +22,21 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Events\Model\Bill;
use Illuminate\Support\Facades\Route;
// Cron job API routes:
use FireflyIII\Http\Middleware\AcceptHeaders;
use FireflyIII\Events\Event;
use FireflyIII\Models\Bill;
use Illuminate\Queue\SerializesModels;
Route::group(
[
'namespace' => 'FireflyIII\Api\V1\Controllers\System',
'prefix' => '',
'as' => 'api.v1.cron.',
'middleware' => [AcceptHeaders::class],
],
static function (): void {
Route::get('{cliToken}', ['uses' => 'CronController@cron', 'as' => 'index']);
}
);
class UpdatedExistingBill extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(
public Bill $bill,
public array $oldData
) {}
}

View File

@@ -157,7 +157,7 @@ class Handler extends ExceptionHandler
return response()->json([
'message' => sprintf('Validation exception: %s', $e->getMessage()),
'errors' => ['field' => 'Field is invalid'],
'errors' => ['field' => 'Field is invalid'],
], $errorCode);
}

View File

@@ -36,13 +36,13 @@ class ConvertsAmountToPrimaryAmount
$primaryAmountField = $params->primaryAmountField;
if (!Amount::convertToPrimary($params->user)) {
Log::debug(sprintf(
'User does not want to do conversion, no need to convert "%s" and store it in field "%s" for %s #%d.',
$params->amountField,
$params->primaryAmountField,
get_class($params->model),
$params->model->id
));
// Log::debug(sprintf(
// 'User does not want to do conversion, no need to convert "%s" and store it in field "%s" for %s #%d.',
// $params->amountField,
// $params->primaryAmountField,
// get_class($params->model),
// $params->model->id
// ));
$params->model->{$primaryAmountField} = null;
$params->model->saveQuietly();

View File

@@ -72,7 +72,7 @@ class DeleteController extends Controller
}
$typeName = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type));
$subTitle = (string) trans(sprintf('firefly.delete_%s_account', $typeName), ['name' => $account->name]);
$subTitle = (string) trans(sprintf('firefly.delete_%s_account', $typeName), ['name' => $account->name]);
$accountList = app('expandedform')->makeSelectListWithEmpty($this->repository->getAccountsByType([$account->accountType->type]));
$objectType = $typeName;
unset($accountList[$account->id]);

View File

@@ -86,7 +86,7 @@ class EditController extends Controller
}
$objectType = config('firefly.shortNamesByFullName')[$account->accountType->type];
$subTitle = (string) trans(sprintf('firefly.edit_%s_account', $objectType), ['name' => $account->name]);
$subTitle = (string) trans(sprintf('firefly.edit_%s_account', $objectType), ['name' => $account->name]);
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
$roles = $this->getRoles();
$liabilityTypes = $this->getLiabilityTypes();

View File

@@ -137,7 +137,7 @@ class ReconcileController extends Controller
);
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);
// various links
$transactionsUrl = route('accounts.reconcile.transactions', [$account->id, '%start%', '%end%']);

View File

@@ -219,7 +219,7 @@ class ShowController extends Controller
$page = (int) $request->get('page');
$pageSize = (int) Preferences::get('listPageSize', 50)->data;
$currency = $this->repository->getAccountCurrency($account) ?? $this->primaryCurrency;
$subTitle = (string) trans('firefly.all_journals_for_account', ['name' => $account->name]);
$subTitle = (string) trans('firefly.all_journals_for_account', ['name' => $account->name]);
$periods = new Collection();
$end->endOfDay();

View File

@@ -115,6 +115,7 @@ class ConfigurationController extends Controller
FireflyConfig::set('enable_external_map', $data['enable_external_map']);
FireflyConfig::set('enable_external_rates', $data['enable_external_rates']);
FireflyConfig::set('allow_webhooks', $data['allow_webhooks']);
FireflyConfig::set('enable_batch_processing', $data['enable_batch_processing']);
FireflyConfig::set('valid_url_protocols', $data['valid_url_protocols']);
FireflyConfig::set('is_demo_site', $data['is_demo_site']);

View File

@@ -94,7 +94,7 @@ class LinkController extends Controller
}
Log::channel('audit')->info(sprintf('User wants to delete link type #%d', $linkType->id));
$subTitle = (string) trans('firefly.delete_link_type', ['name' => $linkType->name]);
$subTitle = (string) trans('firefly.delete_link_type', ['name' => $linkType->name]);
$otherTypes = $this->repository->get();
$count = $this->repository->countJournals($linkType);
$moveTo = [];
@@ -141,7 +141,7 @@ class LinkController extends Controller
return redirect(route('settings.links.index'));
}
$subTitle = (string) trans('firefly.edit_link_type', ['name' => $linkType->name]);
$subTitle = (string) trans('firefly.edit_link_type', ['name' => $linkType->name]);
$subTitleIcon = 'fa-link';
Log::channel('audit')->info(sprintf('User wants to edit link type #%d', $linkType->id));
@@ -181,7 +181,7 @@ class LinkController extends Controller
*/
public function show(LinkType $linkType): Factory|\Illuminate\Contracts\View\View
{
$subTitle = (string) trans('firefly.overview_for_link', ['name' => $linkType->name]);
$subTitle = (string) trans('firefly.overview_for_link', ['name' => $linkType->name]);
$subTitleIcon = 'fa-link';
$links = $this->repository->getJournalLinks($linkType);

View File

@@ -135,7 +135,7 @@ class UserController extends Controller
}
session()->forget('users.edit.fromUpdate');
$subTitle = (string) trans('firefly.edit_user', ['email' => $user->email]);
$subTitle = (string) trans('firefly.edit_user', ['email' => $user->email]);
$subTitleIcon = 'fa-user-o';
$currentUser = auth()->user();
$isAdmin = $this->repository->hasRole($user, 'owner');
@@ -216,7 +216,7 @@ class UserController extends Controller
{
$title = (string) trans('firefly.system_settings');
$mainTitleIcon = 'fa-hand-spock-o';
$subTitle = (string) trans('firefly.single_user_administration', ['email' => $user->email]);
$subTitle = (string) trans('firefly.single_user_administration', ['email' => $user->email]);
$subTitleIcon = 'fa-user';
$information = $this->repository->getUserData($user);

View File

@@ -131,7 +131,7 @@ class AttachmentController extends Controller
public function edit(Request $request, Attachment $attachment): Factory|\Illuminate\Contracts\View\View
{
$subTitleIcon = 'fa-pencil';
$subTitle = (string) trans('firefly.edit_attachment', ['name' => $attachment->filename]);
$subTitle = (string) trans('firefly.edit_attachment', ['name' => $attachment->filename]);
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('attachments.edit.fromUpdate')) {

View File

@@ -190,6 +190,14 @@ class LoginController extends Controller
*/
public function showLoginForm(Request $request): Factory|Redirector|RedirectResponse|View
{
if ('remote_user_guard' === config('auth.defaults.guard')) {
$message = sprintf(
'Firefly III is configured to use the "remote user guard", but was unable to link you to a user. Are you sure the "%s" header is in place?',
config('auth.guard_header')
);
return view('errors.error', ['message' => $message]);
}
Log::channel('audit')->info('Show login form (1.1).');
$count = DB::table('users')->count();
@@ -251,7 +259,7 @@ class LoginController extends Controller
*/
protected function sendFailedLoginResponse(Request $request): void
{
$exception = ValidationException::withMessages([$this->username() => [trans('auth.failed')]]);
$exception = ValidationException::withMessages([$this->username() => [trans('auth.failed')]]);
$exception->redirectTo = route('login');
throw $exception;

View File

@@ -71,7 +71,7 @@ class EditController extends Controller
*/
public function edit(Request $request, Budget $budget): Factory|\Illuminate\Contracts\View\View
{
$subTitle = (string) trans('firefly.edit_budget', ['name' => $budget->name]);
$subTitle = (string) trans('firefly.edit_budget', ['name' => $budget->name]);
$autoBudget = $this->repository->getAutoBudget($budget);
// auto budget types

View File

@@ -73,7 +73,7 @@ class BillController extends Controller
*/
foreach ($paid as $info) {
$amount = $info['sum'];
$label = (string) trans('firefly.paid_in_currency', ['currency' => $info['name']]);
$label = (string) trans('firefly.paid_in_currency', ['currency' => $info['name']]);
$chartData[$label] = ['amount' => $amount, 'currency_symbol' => $info['symbol'], 'currency_code' => $info['code']];
}
@@ -82,7 +82,7 @@ class BillController extends Controller
*/
foreach ($unpaid as $info) {
$amount = $info['sum'];
$label = (string) trans('firefly.unpaid_in_currency', ['currency' => $info['name']]);
$label = (string) trans('firefly.unpaid_in_currency', ['currency' => $info['name']]);
$chartData[$label] = ['amount' => $amount, 'currency_symbol' => $info['symbol'], 'currency_code' => $info['code']];
}

View File

@@ -505,14 +505,14 @@ class BudgetController extends Controller
$preferredRange = Navigation::preferredRangeFormat($start, $end);
$chartData = [
[
'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $currency->name]),
'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $currency->name]),
'type' => 'bar',
'entries' => [],
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,
],
[
'label' => (string) trans('firefly.box_budgeted_in_currency', ['currency' => $currency->name]),
'label' => (string) trans('firefly.box_budgeted_in_currency', ['currency' => $currency->name]),
'type' => 'bar',
'currency_symbol' => $currency->symbol,
'currency_code' => $currency->code,

View File

@@ -171,7 +171,7 @@ class BudgetReportController extends Controller
$chartData[$spentKey] ??= [
'label' => sprintf(
'%s (%s)',
(string) trans('firefly.spent_in_specific_budget', ['budget' => $budget->name]),
(string) trans('firefly.spent_in_specific_budget', ['budget' => $budget->name]),
$currency['currency_name']
),
'type' => 'bar',

View File

@@ -216,7 +216,7 @@ class CategoryReportController extends Controller
$chartData[$spentKey] ??= [
'label' => sprintf(
'%s (%s)',
(string) trans('firefly.spent_in_specific_category', ['category' => $category->name]),
(string) trans('firefly.spent_in_specific_category', ['category' => $category->name]),
$currency['currency_name']
),
'type' => 'bar',
@@ -243,7 +243,7 @@ class CategoryReportController extends Controller
$chartData[$spentKey] ??= [
'label' => sprintf(
'%s (%s)',
(string) trans('firefly.earned_in_specific_category', ['category' => $category->name]),
(string) trans('firefly.earned_in_specific_category', ['category' => $category->name]),
$currency['currency_name']
),
'type' => 'bar',

View File

@@ -162,11 +162,7 @@ class DoubleReportController extends Controller
$name = $this->getCounterpartName($accounts, $account->id, $account->name, $account->iban);
$chartData[$spentKey] ??= [
'label' => sprintf(
'%s (%s)',
(string) trans('firefly.spent_in_specific_double', ['account' => $name]),
$currency['currency_name']
),
'label' => sprintf('%s (%s)', (string) trans('firefly.spent_in_specific_double', ['account' => $name]), $currency['currency_name']),
'type' => 'bar',
'currency_symbol' => $currency['currency_symbol'],
'currency_code' => $currency['currency_code'],
@@ -188,11 +184,7 @@ class DoubleReportController extends Controller
$name = $this->getCounterpartName($accounts, $account->id, $account->name, $account->iban);
$chartData[$earnedKey] ??= [
'label' => sprintf(
'%s (%s)',
(string) trans('firefly.earned_in_specific_double', ['account' => $name]),
$currency['currency_name']
),
'label' => sprintf('%s (%s)', (string) trans('firefly.earned_in_specific_double', ['account' => $name]), $currency['currency_name']),
'type' => 'bar',
'currency_symbol' => $currency['currency_symbol'],
'currency_code' => $currency['currency_code'],

View File

@@ -212,7 +212,7 @@ class ReportController extends Controller
foreach ($data as $currency) {
Log::debug(sprintf('Now processing currency "%s"', $currency['currency_name']));
$income = [
'label' => (string) trans('firefly.box_earned_in_currency', ['currency' => $currency['currency_name']]),
'label' => (string) trans('firefly.box_earned_in_currency', ['currency' => $currency['currency_name']]),
'type' => 'bar',
'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
'currency_id' => $currency['currency_id'],
@@ -221,7 +221,7 @@ class ReportController extends Controller
'entries' => [],
];
$expense = [
'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $currency['currency_name']]),
'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $currency['currency_name']]),
'type' => 'bar',
'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
'currency_id' => $currency['currency_id'],

View File

@@ -220,11 +220,7 @@ class TagReportController extends Controller
// add things to chart Data for each currency:
$spentKey = sprintf('%d-spent', $currency['currency_id']);
$chartData[$spentKey] ??= [
'label' => sprintf(
'%s (%s)',
(string) trans('firefly.spent_in_specific_tag', ['tag' => $tag->tag]),
$currency['currency_name']
),
'label' => sprintf('%s (%s)', (string) trans('firefly.spent_in_specific_tag', ['tag' => $tag->tag]), $currency['currency_name']),
'type' => 'bar',
'currency_symbol' => $currency['currency_symbol'],
'currency_code' => $currency['currency_code'],
@@ -247,11 +243,7 @@ class TagReportController extends Controller
// add things to chart Data for each currency:
$spentKey = sprintf('%d-earned', $currency['currency_id']);
$chartData[$spentKey] ??= [
'label' => sprintf(
'%s (%s)',
(string) trans('firefly.earned_in_specific_tag', ['tag' => $tag->tag]),
$currency['currency_name']
),
'label' => sprintf('%s (%s)', (string) trans('firefly.earned_in_specific_tag', ['tag' => $tag->tag]), $currency['currency_name']),
'type' => 'bar',
'currency_symbol' => $currency['currency_symbol'],
'currency_code' => $currency['currency_code'],

View File

@@ -80,6 +80,14 @@ 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(...);
// is webhooks enabled?
View::share(
'featuringWebhooks',

View File

@@ -183,11 +183,11 @@ class RecurrenceController extends Controller
$result = [
'daily' => ['label' => (string) trans('firefly.recurring_daily'), 'selected' => str_starts_with($preSelected, 'daily')],
$weekly => [
'label' => (string) trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek]),
'label' => (string) trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek]),
'selected' => str_starts_with($preSelected, 'weekly'),
],
$monthly => [
'label' => (string) trans('firefly.recurring_monthly', ['dayOfMonth' => $date->day]),
'label' => (string) trans('firefly.recurring_monthly', ['dayOfMonth' => $date->day]),
'selected' => str_starts_with($preSelected, 'monthly'),
],
$ndom => [
@@ -195,7 +195,7 @@ class RecurrenceController extends Controller
'selected' => str_starts_with($preSelected, 'ndom'),
],
$yearly => [
'label' => (string) trans('firefly.recurring_yearly', ['date' => $yearlyDate]),
'label' => (string) trans('firefly.recurring_yearly', ['date' => $yearlyDate]),
'selected' => str_starts_with($preSelected, 'yearly'),
],
];

View File

@@ -61,7 +61,7 @@ class DeleteController extends Controller
*/
public function delete(ObjectGroup $objectGroup): Factory|View
{
$subTitle = (string) trans('firefly.delete_object_group', ['title' => $objectGroup->title]);
$subTitle = (string) trans('firefly.delete_object_group', ['title' => $objectGroup->title]);
$piggyBanks = $objectGroup->piggyBanks()->count();
// put previous url in session

View File

@@ -64,7 +64,7 @@ class EditController extends Controller
*/
public function edit(ObjectGroup $objectGroup): Factory|View
{
$subTitle = (string) trans('firefly.edit_object_group', ['title' => $objectGroup->title]);
$subTitle = (string) trans('firefly.edit_object_group', ['title' => $objectGroup->title]);
$subTitleIcon = 'fa-pencil';
if (true !== session('object-groups.edit.fromUpdate')) {

View File

@@ -70,7 +70,7 @@ class EditController extends Controller
*/
public function edit(PiggyBank $piggyBank): Factory|\Illuminate\Contracts\View\View
{
$subTitle = (string) trans('firefly.update_piggy_title', ['name' => $piggyBank->name]);
$subTitle = (string) trans('firefly.update_piggy_title', ['name' => $piggyBank->name]);
$subTitleIcon = 'fa-pencil';
$note = $piggyBank->notes()->first();
// Flash some data to fill the form.

View File

@@ -80,7 +80,7 @@ class CreateController extends Controller
public function create(Request $request, ?RuleGroup $ruleGroup = null): Factory|\Illuminate\Contracts\View\View
{
$this->createDefaultRuleGroup();
$preFilled = ['strict' => true];
$preFilled = ['strict' => true];
$oldTriggers = [];
$oldActions = [];
@@ -159,7 +159,7 @@ class CreateController extends Controller
$this->createDefaultRuleGroup();
$preFilled = [
'strict' => true,
'title' => (string) trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]),
'title' => (string) trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]),
'description' => (string) trans('firefly.new_rule_for_bill_description', ['name' => $bill->name]),
];
@@ -221,7 +221,7 @@ class CreateController extends Controller
// collect pre-filled information:
$preFilled = [
'strict' => true,
'title' => (string) trans('firefly.new_rule_for_journal_title', ['description' => $journal->description]),
'title' => (string) trans('firefly.new_rule_for_journal_title', ['description' => $journal->description]),
'description' => (string) trans('firefly.new_rule_for_journal_description', ['description' => $journal->description]),
];

View File

@@ -70,7 +70,7 @@ class EditController extends Controller
$subTitle = (string) trans('firefly.edit_rule_group', ['title' => $ruleGroup->title]);
$hasOldInput = null !== $request->old('_token');
$preFilled = ['active' => $hasOldInput ? (bool) $request->old('active') : $ruleGroup->active];
$preFilled = ['active' => $hasOldInput ? (bool) $request->old('active') : $ruleGroup->active];
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('rule-groups.edit.fromUpdate')) {
$this->rememberPreviousUrl('rule-groups.edit.url');

View File

@@ -87,7 +87,7 @@ class SearchController extends Controller
$excludedWords = $searcher->getExcludedWords();
$operators = $searcher->getOperators();
$invalidOperators = $searcher->getInvalidOperators();
$subTitle = (string) trans('breadcrumbs.search_result', ['query' => $fullQuery]);
$subTitle = (string) trans('breadcrumbs.search_result', ['query' => $fullQuery]);
return view('search.index', [
'words' => $words,

View File

@@ -61,7 +61,7 @@ class InstallController extends Controller
'migrate' => ['--seed' => true, '--force' => true],
'generate-keys' => [], // an exception :(
'firefly-iii:upgrade-database' => [],
'firefly-iii:set-latest-version' => ['--james-is-cool' => true],
'firefly-iii:set-latest-version' => ['--james-is-cool' => true],
'firefly-iii:verify-security-alerts' => [],
];

View File

@@ -134,7 +134,7 @@ class TagController extends Controller
*/
public function edit(Tag $tag): Factory|\Illuminate\Contracts\View\View
{
$subTitle = (string) trans('firefly.edit_tag', ['tag' => $tag->tag]);
$subTitle = (string) trans('firefly.edit_tag', ['tag' => $tag->tag]);
$subTitleIcon = 'fa-tag';
$location = $this->repository->getLocation($tag);
@@ -289,7 +289,7 @@ class TagController extends Controller
$page = (int) $request->get('page');
$pageSize = (int) Preferences::get('listPageSize', 50)->data;
$periods = [];
$subTitle = (string) trans('firefly.all_journals_for_tag', ['tag' => $tag->tag]);
$subTitle = (string) trans('firefly.all_journals_for_tag', ['tag' => $tag->tag]);
$start = $this->repository->firstUseDate($tag) ?? today(config('app.timezone'));
$end = $this->repository->lastUseDate($tag) ?? today(config('app.timezone'));
$attachments = $this->repository->getAttachments($tag);

View File

@@ -103,7 +103,7 @@ class ConvertController extends Controller
$groupTitle = $group->title ?? $first->description;
$groupArray = $transformer->transformObject($group);
$subTitle = (string) trans('firefly.convert_to_'.$destinationType->type, ['description' => $groupTitle]);
$subTitle = (string) trans('firefly.convert_to_'.$destinationType->type, ['description' => $groupTitle]);
$subTitleIcon = 'fa-exchange';
// get a list of asset accounts and liabilities and stuff, in various combinations:

View File

@@ -77,7 +77,7 @@ class DeleteController extends Controller
throw new NotFoundHttpException();
}
$objectType = strtolower($journal->transaction_type_type ?? $journal->transactionType->type);
$subTitle = (string) trans('firefly.delete_'.$objectType, ['description' => $group->title ?? $journal->description]);
$subTitle = (string) trans('firefly.delete_'.$objectType, ['description' => $group->title ?? $journal->description]);
$previous = Steam::getSafePreviousUrl();
// put previous url in session
Log::debug('Will try to remember previous URL');

View File

@@ -91,7 +91,7 @@ class EditController extends Controller
$title = $transactionGroup->transactionJournals()->count() > 1
? $transactionGroup->title
: $transactionGroup->transactionJournals()->first()->description;
$subTitle = (string) trans('firefly.edit_transaction_title', ['description' => $title]);
$subTitle = (string) trans('firefly.edit_transaction_title', ['description' => $title]);
$subTitleIcon = 'fa-plus';
$cash = $repository->getCashAccount();
$previousUrl = $this->rememberPreviousUrl('transactions.edit.url');

View File

@@ -103,10 +103,11 @@ class IndexController extends Controller
$firstJournal = $this->repository->firstNull();
$startPeriod = $firstJournal instanceof TransactionJournal ? $firstJournal->date : new Carbon();
$endPeriod = clone $end;
// limit to 3 years for the time being.
if (now()->diffInYears($startPeriod, true) > 3) {
$startPeriod = now()->subYears(3);
$endPeriod->endOfDay();
// limit to 6 years for the time being.
$max = 6;
if (now()->diffInYears($startPeriod, true) > $max) {
$startPeriod = now()->subYears($max);
}
$periods = $this->getTransactionPeriodOverview($objectType, $startPeriod, $endPeriod);

View File

@@ -78,7 +78,7 @@ class EditController extends Controller
}
$subTitleIcon = 'fa-pencil';
$subTitle = (string) trans('breadcrumbs.edit_currency', ['name' => $currency->name]);
$subTitle = (string) trans('breadcrumbs.edit_currency', ['name' => $currency->name]);
$currency->symbol = htmlentities($currency->symbol);
// is currently enabled (for this user?)
@@ -91,7 +91,7 @@ class EditController extends Controller
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');
$preFilled = ['enabled' => $hasOldInput ? (bool) $request->old('enabled') : $enabled];
$preFilled = ['enabled' => $hasOldInput ? (bool) $request->old('enabled') : $enabled];
$request->session()->flash('preFilled', $preFilled);
Log::channel('audit')->info('Edit currency.', $currency->toArray());

View File

@@ -39,7 +39,7 @@ class EditController extends Controller
public function edit(UserGroup $userGroup)
{
$title = (string) trans('firefly.administrations_page_title');
$subTitle = (string) trans('firefly.administrations_page_edit_sub_title', ['title' => $userGroup->title]);
$subTitle = (string) trans('firefly.administrations_page_edit_sub_title', ['title' => $userGroup->title]);
$mainTitleIcon = 'fa-book';
Log::debug(sprintf('Now at %s', __METHOD__));

View File

@@ -1,65 +0,0 @@
<?php
/**
* Kernel.php
* Copyright (c) 2019 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\Http;
use FireflyIII\Http\Middleware\Authenticate;
use FireflyIII\Http\Middleware\Binder;
use FireflyIII\Http\Middleware\InstallationId;
use FireflyIII\Http\Middleware\RedirectIfAuthenticated;
use FireflyIII\Http\Middleware\StartFireflySession;
use FireflyIII\Http\Middleware\TrimStrings;
use FireflyIII\Http\Middleware\TrustProxies;
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
use Illuminate\Auth\Middleware\Authorize;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\View\Middleware\ShareErrorsFromSession;
/**
* Class Kernel
*/
class Kernel extends HttpKernel
{
protected $middleware = [
// SecureHeaders::class,
CheckForMaintenanceMode::class,
ValidatePostSize::class,
TrimStrings::class,
ConvertEmptyStringsToNull::class,
TrustProxies::class,
InstallationId::class,
];
protected $middlewareAliases = [
'auth' => Authenticate::class,
'auth.basic' => AuthenticateWithBasicAuth::class,
'bindings' => Binder::class,
'can' => Authorize::class,
'guest' => RedirectIfAuthenticated::class,
'throttle' => ThrottleRequests::class,
];
protected $middlewarePriority = [StartFireflySession::class, ShareErrorsFromSession::class, Authenticate::class, Binder::class, Authorize::class];
}

View File

@@ -82,22 +82,25 @@ class Authenticate
protected function authenticate($request, array $guards)
{
if (0 === count($guards)) {
// go for default guard:
// @noinspection PhpUndefinedMethodInspection
if ($this->auth->check()) {
// do an extra check on user object.
/** @noinspection PhpUndefinedMethodInspection */
/** @var User $user */
$user = $this->auth->authenticate();
Log::debug('in Authenticate::authenticate() with zero guards.');
// There are no guards defined, go for the default guard:
if (auth()->check()) {
Log::debug('User is authenticated.');
$user = auth()->user();
$this->validateBlockedUser($user, $guards);
}
return;
}
// @noinspection PhpUndefinedMethodInspection
return $this->auth->authenticate();
$this->auth->authenticate();
if (!$this->auth->check()) {
throw new AuthenticationException('The user is not logged in but must be.', $guards);
}
}
exit('five');
foreach ($guards as $guard) {
exit('six');
if ('api' !== $guard) {
$this->auth->guard($guard)->authenticate();
}
@@ -111,6 +114,7 @@ class Authenticate
}
}
exit('seven');
// this is a massive hack, but if the handler has the oauth exception
// at this point we can report its error instead of a generic one.
$message = 'Unauthenticated.';
@@ -143,5 +147,6 @@ class Authenticate
// @phpstan-ignore-line (thinks function is undefined)
throw new AuthenticationException('Blocked account.', $guards);
}
Log::debug(sprintf('User #%d is not blocked.', $user->id));
}
}

View File

@@ -32,7 +32,7 @@ use Override;
/**
* Class StartFireflySession.
*/
class StartFireflySession extends StartSession
class StartFireflyIIISession extends StartSession
{
/**
* Store the current URL for the request if necessary.

View File

@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
/*
* UpdatesRulesForChangedBill.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\Listeners\Model\Bill;
use FireflyIII\Events\Model\Bill\UpdatedExistingBill;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Log;
class UpdatesRulesForChangedBill implements ShouldQueue
{
public function handle(UpdatedExistingBill $event): void
{
// update rule actions.
if ($event->bill->name !== $event->oldData['name']) {
$this->updateBillTriggersAndActions($event->bill, $event->oldData);
}
}
private function updateBillTriggersAndActions(Bill $bill, array $oldData): void
{
Log::debug(sprintf('Now in updateBillTriggersAndActions(#%d)', $bill->id));
$repository = app(RuleRepositoryInterface::class);
$repository->setUser($bill->user);
$rules = $repository->getAll();
/** @var Rule $rule */
foreach ($rules as $rule) {
$this->updateRule($bill, $rule, $oldData);
}
}
private function updateRule(Bill $bill, Rule $rule, array $oldData): void
{
$triggers = ['bill_is', 'bill_ends', 'bill_starts', 'bill_contains'];
/** @var RuleTrigger $trigger */
foreach ($rule->ruleTriggers as $trigger) {
if (in_array($trigger->trigger_type, $triggers, true) && $trigger->trigger_value === $oldData['name']) {
Log::debug(sprintf('Updated trigger #%d in rule #%d to new subscription name', $trigger->id, $rule->id));
$trigger->trigger_value = $bill->name;
$trigger->save();
}
}
/** @var RuleAction $action */
foreach ($rule->ruleActions as $action) {
if ('link_to_bill' === $action->action_type && $action->action_value === $oldData['name']) {
Log::debug(sprintf('Updated action #%d in rule #%d to new subscription name', $action->id, $rule->id));
$action->action_value = $bill->name;
$action->save();
}
}
}
}

View File

@@ -104,7 +104,9 @@ trait SupportsGroupProcessingTrait
$repository->deleteStatisticsForType(Category::class, $objects->categories, $dates);
$repository->deleteStatisticsForType(Tag::class, $objects->tags, $dates);
// remove if no stuff present:
// remove generic statistics:
$repository->deleteStatisticsForPrefix('all_', $dates);
// remove for no tag, no cat, etc.
if (0 === $objects->budgets->count()) {
Log::debug('No budgets, delete "no_category" stats.');

View File

@@ -149,12 +149,10 @@ class RecalculatesPrimaryCurrencyAmounts
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.user_group_id', $userGroup->id)
->where(static function (Builder $q): void {
$q
->whereNotNull('native_amount')
->orWhereNotNull('native_foreign_amount')
->orWhere('native_amount', '!=', '')
->orWhere('native_foreign_amount', '!=', '')
;
$q->whereNotNull('native_amount')->orWhereNotNull('native_foreign_amount');
if ('pgsql' !== config('database.default')) {
$q->orWhere('native_amount', '!=', '')->orWhere('native_foreign_amount', '!=', '');
}
})
->update(['native_amount' => null, 'native_foreign_amount' => null])
;

View File

@@ -56,7 +56,7 @@ class MFABackupFewLeftNotification extends Notification
*/
public function toMail(User $notifiable): MailMessage
{
$subject = (string) trans('email.mfa_few_backups_left_subject', ['count' => $this->count]);
$subject = (string) trans('email.mfa_few_backups_left_subject', ['count' => $this->count]);
$ip = Request::ip();
$host = Steam::getHostName($ip);
$userAgent = Request::userAgent();

View File

@@ -53,7 +53,7 @@ class MFAManyFailedAttemptsNotification extends Notification
*/
public function toMail(User $notifiable): MailMessage
{
$subject = (string) trans('email.mfa_many_failed_subject', ['count' => $this->count]);
$subject = (string) trans('email.mfa_many_failed_subject', ['count' => $this->count]);
$ip = Request::ip();
$host = Steam::getHostName($ip);
$userAgent = Request::userAgent();

View File

@@ -58,7 +58,7 @@ class SubscriptionsOverdueReminder extends Notification
$info = [];
$count = 0;
foreach ($this->overdue as $item) {
$current = ['bill' => $item['bill']];
$current = ['bill' => $item['bill']];
$current['pay_dates'] = array_map(static fn (string $date): string => new Carbon($date)->isoFormat((string) trans(
'config.month_and_day_moment_js'
)), $item['dates']['pay_dates']);

View File

@@ -34,10 +34,6 @@ use Laravel\Passport\Passport;
*/
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
// 'FireflyIII\Model' => 'FireflyIII\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*

View File

@@ -23,7 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Providers;
use FireflyIII\Http\Middleware\StartFireflySession;
use FireflyIII\Http\Middleware\StartFireflyIIISession;
use Illuminate\Session\SessionManager;
use Illuminate\Support\ServiceProvider;
use Override;
@@ -43,7 +43,7 @@ class FireflySessionProvider extends ServiceProvider
$this->registerSessionDriver();
$this->app->singleton(StartFireflySession::class);
$this->app->singleton(StartFireflyIIISession::class);
}
/**

View File

@@ -42,20 +42,18 @@ class RouteServiceProvider extends ServiceProvider
#[Override]
public function boot(): void
{
$this->routes(function (): void {
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'))
;
Route::prefix('api/v1/cron')
->middleware('api_basic')
->namespace($this->namespace)
->group(base_path('routes/api-noauth.php'))
;
Route::middleware('web')->namespace($this->namespace)->group(base_path('routes/web.php'));
});
// $this->routes(function (): void {
// Route::prefix('api')
// ->middleware('api')
// ->namespace($this->namespace)
// ->group(base_path('routes/api.php'))
// ;
// Route::prefix('api/v1/cron')
// ->middleware('api_basic')
// ->namespace($this->namespace)
// ->group(base_path('routes/api-noauth.php'))
// ;
// Route::middleware('web')->namespace($this->namespace)->group(base_path('routes/web.php'));
// });
}
}

View File

@@ -23,7 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Providers;
use FireflyIII\Http\Middleware\StartFireflySession;
use FireflyIII\Http\Middleware\StartFireflyIIISession;
use Illuminate\Session\SessionServiceProvider as BaseSessionServiceProvider;
use Override;
@@ -42,6 +42,6 @@ class SessionServiceProvider extends BaseSessionServiceProvider
$this->registerSessionDriver();
$this->app->singleton(StartFireflySession::class);
$this->app->singleton(StartFireflyIIISession::class);
}
}

View File

@@ -178,7 +178,7 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
$currencies = [$primaryCurrency->id => $primaryCurrency];
$currencies = [$primaryCurrency->id => $primaryCurrency];
$report = ['accounts' => [], 'sums' => []];
/** @var array $journal */
@@ -232,7 +232,7 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
$currencies = [$primaryCurrency->id => $primaryCurrency];
$currencies = [$primaryCurrency->id => $primaryCurrency];
$report = ['accounts' => [], 'sums' => []];
/** @var array $journal */

View File

@@ -96,7 +96,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
foreach ($set as $bill) {
if ($bill->order !== $current) {
$bill->order = $current;
$bill->save();
$bill->saveQuietly();
}
++$current;
}
@@ -613,7 +613,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
public function setOrder(Bill $bill, int $order): void
{
$bill->order = $order;
$bill->save();
$bill->saveQuietly();
}
/**

View File

@@ -204,7 +204,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
$currencySymbol = $primaryCurrency->symbol;
$currencyDecimalPlaces = $primaryCurrency->decimal_places;
$converter = new ExchangeRateConverter();
$currencies = [$currencyId => $primaryCurrency];
$currencies = [$currencyId => $primaryCurrency];
foreach ($journals as $journal) {
$amount = Steam::negative($journal['amount']);

View File

@@ -49,6 +49,9 @@ class PeriodStatisticRepository implements PeriodStatisticRepositoryInterface, U
#[Override]
public function allInRangeForPrefix(string $prefix, Carbon $start, Carbon $end): Collection
{
Log::debug(sprintf('Collect all statistics where type starts with "%s"', $prefix));
Log::debug(sprintf('Between %s and %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
return $this->userGroup
->periodStatistics()
->where('type', 'LIKE', sprintf('%s%%', $prefix))
@@ -156,6 +159,7 @@ class PeriodStatisticRepository implements PeriodStatisticRepositoryInterface, U
int $count,
string $amount
): PeriodStatistic {
Log::debug(sprintf('Store as type "%s"', sprintf('%s_%s', $prefix, $type)));
$stat = new PeriodStatistic();
$stat->transaction_currency_id = $currencyId;
$stat->user_group_id = $this->getUserGroup()->id;

View File

@@ -102,7 +102,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
{
return $this->user
->rules()
->with(['ruleGroup'])
->with(['ruleGroup', 'ruleTriggers', 'ruleActions'])
->get()
;
}

View File

@@ -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));
@@ -228,7 +228,7 @@ 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.
@@ -257,7 +257,7 @@ trait AccountServiceTrait
'order' => 0,
'amount' => $amount,
'foreign_amount' => null,
'description' => trans('firefly.liability_credit_description', ['account' => $account->name]),
'description' => trans('firefly.liability_credit_description', ['account' => $account->name]),
'budget_id' => null,
'budget_name' => null,
'category_id' => null,
@@ -352,7 +352,7 @@ trait AccountServiceTrait
'order' => 0,
'amount' => $amount,
'foreign_amount' => null,
'description' => trans('firefly.initial_balance_description', ['account' => $account->name]),
'description' => trans('firefly.initial_balance_description', ['account' => $account->name]),
'budget_id' => null,
'budget_name' => null,
'category_id' => null,
@@ -444,7 +444,7 @@ trait AccountServiceTrait
'order' => 0,
'amount' => $amount,
'foreign_amount' => null,
'description' => trans('firefly.initial_balance_description', ['account' => $account->name]),
'description' => trans('firefly.initial_balance_description', ['account' => $account->name]),
'budget_id' => null,
'budget_name' => null,
'category_id' => null,

View File

@@ -37,6 +37,7 @@ use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Rules\UniqueIban;
use FireflyIII\Support\NullArrayObject;
use Illuminate\Database\UniqueConstraintViolationException;
use Illuminate\Support\Facades\Log;
use Safe\Exceptions\JsonException;
@@ -227,7 +228,12 @@ trait JournalServiceTrait
$set = array_unique($set);
Log::debug('End of loop.');
Log::debug(sprintf('Total nr. of tags: %d', count($tags)), $tags);
$journal->tags()->sync($set);
try {
$journal->tags()->sync($set);
} catch (UniqueConstraintViolationException $e) {
Log::error(sprintf('Firefly III could not sync tags: %s', $e->getMessage()));
}
}
/**

View File

@@ -24,12 +24,12 @@ declare(strict_types=1);
namespace FireflyIII\Services\Internal\Update;
use FireflyIII\Events\Model\Bill\UpdatedExistingBill;
use FireflyIII\Factory\TransactionCurrencyFactory;
use FireflyIII\Models\Bill;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups;
use FireflyIII\Services\Internal\Support\BillServiceTrait;
use FireflyIII\Support\Facades\Amount;
@@ -50,6 +50,7 @@ class BillUpdateService
public function update(Bill $bill, array $data): Bill
{
$this->user = $bill->user;
$oldData = $bill->toArray();
if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) {
$factory = app(TransactionCurrencyFactory::class);
@@ -68,13 +69,6 @@ class BillUpdateService
$bill = $this->updateBillProperties($bill, $data);
$bill->save();
$bill->refresh();
// old values
$oldData = [
'name' => $bill->name,
'amount_min' => $bill->amount_min,
'amount_max' => $bill->amount_max,
'transaction_currency_name' => $bill->transactionCurrency->name,
];
// update note:
if (array_key_exists('notes', $data)) {
$this->updateNote($bill, (string) $data['notes']);
@@ -90,12 +84,6 @@ class BillUpdateService
}
}
// update rule actions.
if (array_key_exists('name', $data)) {
$this->updateBillActions($bill, $oldData['name'], $data['name']);
$this->updateBillTriggers($bill, $oldData, $data);
}
// update using name:
if (array_key_exists('object_group_title', $data)) {
$objectGroupTitle = $data['object_group_title'] ?? '';
@@ -127,6 +115,7 @@ class BillUpdateService
$bill->objectGroups()->sync([]);
$bill->save();
}
event(new UpdatedExistingBill($bill, $oldData));
return $bill;
}
@@ -181,39 +170,6 @@ class BillUpdateService
return $bill;
}
private function updateBillTriggers(Bill $bill, array $oldData, array $newData): void
{
Log::debug(sprintf('Now in updateBillTriggers(%d, "%s")', $bill->id, $bill->name));
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$repository->setUser($bill->user);
$rules = $repository->getRulesForBill($bill);
if (0 === $rules->count()) {
Log::debug('Found no rules.');
return;
}
Log::debug(sprintf('Found %d rules', $rules->count()));
$fields = [
'name' => 'description_contains',
'amount_min' => 'amount_more',
'amount_max' => 'amount_less',
'transaction_currency_name' => 'currency_is',
];
foreach ($fields as $field => $ruleTriggerKey) {
if (!array_key_exists($field, $newData)) {
continue;
}
if ($oldData[$field] === $newData[$field]) {
Log::debug(sprintf('Field %s is unchanged ("%s"), continue.', $field, $oldData[$field]));
continue;
}
$this->updateRules($rules, $ruleTriggerKey, $oldData[$field], $newData[$field]);
}
}
private function updateOrder(Bill $bill, int $oldOrder, int $newOrder): void
{
if ($newOrder > $oldOrder) {

View File

@@ -551,7 +551,7 @@ class JournalUpdateService
event(
new TransactionGroupRequestsAuditLogEntry(
$group->user,
$group,
$this->transactionJournal,
'update_amount',
[
'currency_symbol' => $recordCurrency->symbol,
@@ -767,7 +767,7 @@ class JournalUpdateService
event(
new TransactionGroupRequestsAuditLogEntry(
$group->user,
$group,
$this->transactionJournal,
'update_foreign_amount',
[
'currency_symbol' => $recordCurrency->symbol,

View File

@@ -31,6 +31,7 @@ use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Log;
/**
@@ -40,6 +41,7 @@ class RemoteUserGuard implements Guard
{
protected Application $application;
protected ?User $user = null;
private $tried = false;
/**
* Create a new authentication guard.
@@ -49,13 +51,19 @@ class RemoteUserGuard implements Guard
Application $app
) {
$app->get('request');
// Log::debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri()));
Log::debug(sprintf('Created RemoteUserGuard for %s "%s"', $app->get('request')?->getMethod(), $app->get('request')?->getRequestUri()));
$this->application = $app;
}
public function authenticate(): void
{
// Log::debug(sprintf('Now at %s', __METHOD__));
$this->tried = true;
Log::debug(sprintf('Now at %s', __METHOD__));
if (App::runningInConsole()) {
Log::debug('Running in console, will not authenticate.');
return;
}
if ($this->user instanceof User) {
Log::debug(sprintf('%s is found: #%d, "%s".', $this->user::class, $this->user->id, $this->user->email));
@@ -70,10 +78,14 @@ class RemoteUserGuard implements Guard
$userID = request()->server($header) ?? apache_request_headers()[$header] ?? null;
}
// test value for development
// $userID = 'james@firefly';
if (null === $userID || '' === $userID) {
Log::error(sprintf('No user in header "%s".', $header));
throw new FireflyException('The guard header was unexpectedly empty. See the logs.');
// throw new FireflyException('The guard header was unexpectedly empty. See the logs.');
return;
}
Log::debug(sprintf('User ID found in header is "%s"', $userID));
@@ -145,8 +157,18 @@ class RemoteUserGuard implements Guard
public function user(): ?User
{
if (App::runningInConsole()) {
Log::debug('Running in console, will not authenticate.');
return null;
}
if (false === $this->tried) {
Log::debug('Have not tried authentication, do it now.');
$this->authenticate();
}
// Log::debug(sprintf('Now at %s', __METHOD__));
$user = $this->user;
if (!$user instanceof User) {
Log::debug('User is NULL');

View File

@@ -35,18 +35,8 @@ class Calculator
{
public const int DEFAULT_INTERVAL = 1;
private static ?SplObjectStorage $intervalMap = null; // @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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 static array $intervals = [];
private static ?SplObjectStorage $intervalMap = null;
private static array $intervals = [];
public function isAvailablePeriodicity(Periodicity $periodicity): bool
{

View File

@@ -81,14 +81,14 @@ class WholePeriodChartGenerator
$code = $currency['currency_code'];
$name = $currency['currency_name'];
$chartData[sprintf('spent-in-%s', $code)] = [
'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $name]),
'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $name]),
'entries' => [],
'type' => 'bar',
'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
];
$chartData[sprintf('earned-in-%s', $code)] = [
'label' => (string) trans('firefly.box_earned_in_currency', ['currency' => $name]),
'label' => (string) trans('firefly.box_earned_in_currency', ['currency' => $name]),
'entries' => [],
'type' => 'bar',
'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green

View File

@@ -110,6 +110,52 @@ class ExportDataGenerator
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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

@@ -49,7 +49,7 @@ class PiggyBankForm
$piggyBanks = $repository->getPiggyBanksWithAmount();
$title = (string) trans('firefly.default_group_title_name');
$array = [];
$subList = [0 => ['group' => ['title' => $title], 'piggies' => [(string) trans('firefly.none_in_select_list')]]];
$subList = [0 => ['group' => ['title' => $title], 'piggies' => [(string) trans('firefly.none_in_select_list')]]];
/** @var PiggyBank $piggy */
foreach ($piggyBanks as $piggy) {
@@ -60,7 +60,7 @@ class PiggyBankForm
$groupTitle = $group->title;
$groupOrder = $group->order;
}
$subList[$groupOrder] ??= ['group' => ['title' => $groupTitle], 'piggies' => []];
$subList[$groupOrder] ??= ['group' => ['title' => $groupTitle], 'piggies' => []];
$subList[$groupOrder]['piggies'][$piggy->id] = $piggy->name;
}
ksort($subList);

View File

@@ -170,7 +170,7 @@ class AccountBalanceGrouped
{
$this->primary = $primary;
$primaryCurrencyId = $primary->id;
$this->currencies = [$primary->id => $primary]; // currency cache
$this->currencies = [$primary->id => $primary]; // currency cache
$this->data[$primaryCurrencyId] = [
'currency_id' => (string) $primaryCurrencyId,
'currency_symbol' => $primary->symbol,

View File

@@ -157,7 +157,7 @@ trait GetConfigurationData
// previous year:
$yearBegin = today(config('app.timezone'))->subYear()->startOfYear();
$index = (string) trans('firefly.previous_year', ['year' => $yearBegin->year]);
$index = (string) trans('firefly.previous_year', ['year' => $yearBegin->year]);
$ranges[$index] = [$yearBegin, $yearBegin->clone()->endOfYear()];
// everything

View File

@@ -37,7 +37,6 @@ use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\PeriodStatistic\PeriodStatisticRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Navigation;
use FireflyIII\Support\Facades\Steam;
@@ -80,38 +79,8 @@ trait PeriodOverview
protected TagRepositoryInterface $tagRepository;
protected JournalRepositoryInterface $journalRepos;
protected PeriodStatisticRepositoryInterface $periodStatisticRepo;
private Collection $statistics; // temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
private array $transactions; // temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
// temp data holder
private Collection $statistics;
private array $transactions;
/**
* This method returns "period entries", so nov-2015, dec-2015, etc. (this depends on the users session range)
@@ -172,6 +141,34 @@ trait PeriodOverview
return $entries;
}
protected function getGenericPeriod(string $type, string $period, Carbon $start, Carbon $end): array
{
$return = [
'title' => Navigation::periodShow($start, $period),
'route' => route('transactions.index', [$type, $start->format('Y-m-d'), $end->format('Y-m-d')]),
'total_transactions' => 0,
];
$setTypes = [
'withdrawal' => 'spent',
'expenses' => 'spent',
'deposit' => 'earned',
'revenue' => 'earned',
'transfer' => 'transferred',
'transfers' => 'transferred',
];
if (!array_key_exists($type, $setTypes)) {
throw new FireflyException(sprintf('[c] Cannot deal with type "%s"', $type));
}
$setType = $setTypes[$type];
$this->transactions = [];
$set = $this->getSingleGenericPeriodByType($start, $end, $type);
$return['total_transactions'] += $set['count'];
$return[$setType] = $set;
return $return;
}
/**
* Same as above, but for lists that involve transactions without a budget.
*
@@ -257,60 +254,18 @@ trait PeriodOverview
*/
protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array
{
$range = Navigation::getViewRange(true);
$types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType));
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
// properties for cache
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('transactions-period-entries');
$cache->addProperty($transactionType);
if ($cache->has()) {
return $cache->get();
}
$this->periodStatisticRepo = app(PeriodStatisticRepositoryInterface::class);
$range = Navigation::getViewRange(true);
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
/** @var array $dates */
$dates = Navigation::blockPeriods($start, $end, $range);
$entries = [];
$spent = [];
$earned = [];
$transferred = [];
// collect all journals in this period (regardless of type)
$collector = app(GroupCollectorInterface::class);
$collector->setTypes($types)->setRange($start, $end);
$genericSet = $collector->getExtractedJournals();
$loops = 0;
$dates = Navigation::blockPeriods($start, $end, $range);
$entries = [];
$this->statistics = $this->periodStatisticRepo->allInRangeForPrefix('all_', $start, $end);
Log::debug(sprintf('Collected %d statistics', $this->statistics->count()));
foreach ($dates as $currentDate) {
$title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
if ($loops < 10) {
// set to correct array
if ('expenses' === $transactionType || 'withdrawal' === $transactionType) {
$spent = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
}
if ('revenue' === $transactionType || 'deposit' === $transactionType) {
$earned = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
}
if ('transfer' === $transactionType || 'transfers' === $transactionType) {
$transferred = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
}
}
$entries[] = [
'title' => $title,
'route' => route('transactions.index', [
$transactionType,
$currentDate['start']->format('Y-m-d'),
$currentDate['end']->format('Y-m-d'),
]),
'total_transactions' => count($spent) + count($earned) + count($transferred),
'spent' => $this->groupByCurrency($spent),
'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred),
];
++$loops;
$entries[] = $this->getGenericPeriod($transactionType, $currentDate['period'], $currentDate['start'], $currentDate['end']);
}
return $entries;
@@ -357,10 +312,11 @@ trait PeriodOverview
return new Collection();
}
Log::debug(sprintf('Now in filterStatistics("%s")', $type));
return $this->statistics->filter(
static fn (PeriodStatistic $statistic): bool => $statistic->start->eq($start) && $statistic->end->eq($end) && $statistic->type === $type
);
return $this->statistics->filter(static function (PeriodStatistic $statistic) use ($start, $end, $type): bool {
return $statistic->start->isSameSecond($start) && $statistic->end->isSameSecond($end) && $statistic->type === $type;
});
}
private function filterTransactionsByType(TransactionTypeEnum $type, Carbon $start, Carbon $end): array
@@ -422,21 +378,63 @@ trait PeriodOverview
return [$start, $end];
}
private function getSingleGenericPeriodByType(Carbon $start, Carbon $end, string $type): array
{
$filterType = sprintf('all_%s', $type);
$statistics = $this->filterStatistics($start, $end, $filterType);
$types = config(sprintf('firefly.transactionTypesByType.%s', $type));
// nothing found, regenerate them.
if (0 === $statistics->count()) {
if (0 === count($this->transactions)) {
// get collection!
// collect all journals in this period (regardless of type)
$collector = app(GroupCollectorInterface::class);
$collector->setTypes($types)->setRange($start, $end);
$this->transactions = $collector->getExtractedJournals();
Log::debug(sprintf('Going to group %d found journal(s)', count($types)));
}
$grouped = $this->groupByCurrency($this->filterJournalsByDate($this->transactions, $start, $end));
$this->saveGroupedForPrefix('all', $start, $end, $type, $grouped);
return $grouped;
}
$grouped = ['count' => 0];
/** @var PeriodStatistic $statistic */
foreach ($statistics as $statistic) {
$id = (int) $statistic->transaction_currency_id;
$currency = Amount::getTransactionCurrencyById($id);
$grouped[$id] = [
'amount' => (string) $statistic->amount,
'count' => (int) $statistic->count,
'currency_id' => $currency->id,
'currency_name' => $currency->name,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
];
$grouped['count'] += (int) $statistic->count;
}
return $grouped;
}
private function getSingleModelPeriodByType(Model $model, Carbon $start, Carbon $end, string $type): array
{
Log::debug(sprintf(
'Now in getSingleModelPeriodByType(%s #%d, %s %s, %s)',
$model::class,
$model->id,
$start->format('Y-m-d'),
$end->format('Y-m-d'),
$start->format('Y-m-d H:i:s.u'),
$end->format('Y-m-d H:i:s.u'),
$type
));
$statistics = $this->filterStatistics($start, $end, $type);
// nothing found, regenerate them.
if (0 === $statistics->count()) {
Log::debug(sprintf('Found nothing in this period for type "%s"', $type));
Log::debug(sprintf('Found nothing between %s and %s for type "%s"', $start->format('Y-m-d H:i:s.u'), $end->format('Y-m-d H:i:s.u'), $type));
if (0 === count($this->transactions)) {
switch ($model::class) {
default:
@@ -461,7 +459,7 @@ trait PeriodOverview
switch ($type) {
default:
throw new FireflyException(sprintf('Cannot deal with category period type %s', $type));
throw new FireflyException(sprintf('Cannot deal with type %s', $type));
case 'spent':
$result = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $start, $end);
@@ -523,7 +521,7 @@ trait PeriodOverview
switch ($model) {
default:
throw new FireflyException(sprintf('Cannot deal with model of type "%s"', $model));
throw new FireflyException(sprintf('[b] Cannot deal with model of type "%s"', $model));
case 'budget':
// get all expenses without a budget.

View File

@@ -51,6 +51,29 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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
@@ -62,6 +85,29 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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 $currencies = [];
private array $currencyIds = [];
private array $ids = [];

View File

@@ -51,6 +51,29 @@ class BudgetLimitEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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 $currencies = [];
private array $currencyIds = [];
private Carbon $end;

View File

@@ -53,6 +53,29 @@ class PiggyBankEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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
@@ -64,6 +87,29 @@ class PiggyBankEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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 $amounts = [];
private Collection $collection;
private array $currencies = [];

View File

@@ -48,6 +48,29 @@ class PiggyBankEventEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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
@@ -59,6 +82,29 @@ class PiggyBankEventEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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 array $currencies = [];
private array $groupIds = [];

View File

@@ -57,6 +57,29 @@ class SubscriptionEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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 ?Carbon $end = null;
private array $mappedObjects = [];

View File

@@ -75,6 +75,52 @@ class TransactionGroupEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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->dateFields = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date'];

View File

@@ -53,6 +53,29 @@ class WebhookEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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
@@ -64,6 +87,29 @@ class WebhookEnrichment implements EnrichmentInterface
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @phpstan-ignore-line
// @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 $responses = [];
private array $triggers = [];
private array $webhookDeliveries = [];

View File

@@ -51,8 +51,8 @@ class ObjectGroupTransformer extends AbstractTransformer
return [
'id' => (string) $objectGroup->id,
'created_at' => $objectGroup->created_at?->toAtomString(),
'updated_at' => $objectGroup->updated_at?->toAtomString(),
'created_at' => $objectGroup->created_at->toAtomString(),
'updated_at' => $objectGroup->updated_at->toAtomString(),
'title' => $objectGroup->title,
'order' => $objectGroup->order,
'links' => [['rel' => 'self', 'uri' => '/object_groups/'.$objectGroup->id]],

View File

@@ -66,8 +66,8 @@ class PiggyBankEventTransformer extends AbstractTransformer
return [
'id' => (string) $event->id,
'created_at' => $event->created_at?->toAtomString(),
'updated_at' => $event->updated_at?->toAtomString(),
'created_at' => $event->created_at->toAtomString(),
'updated_at' => $event->updated_at->toAtomString(),
'amount' => $amount,
'pc_amount' => $primaryAmount,

View File

@@ -32,11 +32,9 @@ use FireflyIII\Http\Middleware\IsAdmin;
use FireflyIII\Http\Middleware\Range;
use FireflyIII\Http\Middleware\RedirectIfAuthenticated;
use FireflyIII\Http\Middleware\SecureHeaders;
use FireflyIII\Http\Middleware\StartFireflySession;
use FireflyIII\Http\Middleware\TrustProxies;
use FireflyIII\Http\Middleware\StartFireflyIIISession;
use FireflyIII\Http\Middleware\VerifyCsrfToken;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
@@ -47,7 +45,6 @@ use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance;
use Illuminate\Foundation\Http\Middleware\TrimStrings;
use Illuminate\Http\Middleware\HandleCors;
use Illuminate\Http\Middleware\ValidatePostSize;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\View\Middleware\ShareErrorsFromSession;
use Laravel\Passport\Http\Middleware\CreateFreshApiToken;
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
@@ -92,115 +89,99 @@ if (!function_exists('stringIsEqual')) {
$app = Application::configure(basePath: dirname(__DIR__))
->withRouting(
web : __DIR__ . '/../routes/web.php',
api : __DIR__ . '/../routes/api.php',
commands: __DIR__ . '/../routes/console.php',
health : '/up',
)
->withMiddleware(function (Middleware $middleware): void {
// overrule the standard middleware
$middleware->use(
[
InvokeDeferredCallbacks::class,
\Illuminate\Http\Middleware\TrustProxies::class, // use the DEFAULT middleware for this.
HandleCors::class,
PreventRequestsDuringMaintenance::class,
ValidatePostSize::class,
TrimStrings::class,
ConvertEmptyStringsToNull::class,
SecureHeaders::class,
TrustProxies::class,
SecureHeaders::class, // is a Firefly III specific middleware class.
]
);
// overrule the web group
// append and extend the default "web" middleware
// to include our own custom "StartFireflyIIISession" class.
// this class in turns contains a better "previous URL" feature.
// See https://laravel.com/docs/12.x/middleware for the default list.
$middleware->group('web',
[
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartFireflySession::class,
StartFireflyIIISession::class, // this is different.
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
Binder::class, // this is also different.
CreateFreshApiToken::class,
]
);
// new group?
$middleware->appendToGroup('binders-only',
[
Installer::class,
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
Binder::class,
]);
//
$middleware->appendToGroup('user-not-logged-in', [
Installer::class,
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartFireflySession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
Binder::class,
RedirectIfAuthenticated::class,
]);
// the default API group only contains "substitute bindings" middleware
// so here we replace the entire API group and add more sensible stuff.
$middleware->group('api',
[
AcceptHeaders::class,
// EnsureFrontendRequestsAreStateful::class,
'auth:api',
Binder::class,
]
);
$middleware->appendToGroup('api_basic', [AcceptHeaders::class, Binder::class]);
// more
$middleware->appendToGroup('user-logged-in-no-2fa', [
Installer::class,
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartFireflySession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
Binder::class,
Authenticate::class,
]);
// simple auth
// "simple auth" means the user must be logged in and present,
// but does not have to be 2FA authenticated. This is so all users
// can always log out, for example.
$middleware->appendToGroup('user-simple-auth', [
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartFireflySession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
Binder::class,
Authenticate::class,
]);
// user full auth
// This middleware is added for all routes where the user MUST have full authentication.
// this includes 2FA etc.
// incidentally, this group also includes the range middleware and the message thing.
$middleware->appendToGroup('user-full-auth', [
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartFireflySession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
Authenticate::class,
MFAMiddleware::class,
Range::class,
Binder::class,
InterestingMessage::class,
CreateFreshApiToken::class,
]);
// admin
// This middleware is added to ensure that the user is not only logged in and
// authenticated (with MFA and everything), but also admin.
$middleware->appendToGroup('admin', [
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartFireflySession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
Authenticate::class,
// AuthenticateTwoFactor::class,
MFAMiddleware::class,
IsAdmin::class,
Range::class,
Binder::class,
CreateFreshApiToken::class,
InterestingMessage::class,
]);
// api
$middleware->appendToGroup('api', [AcceptHeaders::class, EnsureFrontendRequestsAreStateful::class, 'auth:api,sanctum', Binder::class]);
// api basic,
$middleware->appendToGroup('api_basic', [AcceptHeaders::class, Binder::class]);
// if the user is not logged in, this group applies.
// on top of everything else of course.
$middleware->appendToGroup('user-not-logged-in', [
Installer::class,
RedirectIfAuthenticated::class,
]);
// the "binders only" group does not need or ask for authentication
// it just makes sure strings from routes are bound to objects if possible.
$middleware->group('binders-only',
[
Installer::class,
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
Binder::class,
]);
// $middleware->priority([StartFireflyIIISession::class, ShareErrorsFromSession::class, Authenticate::class, Binder::class, Authorize::class]);
})
->withEvents(discover: [
__DIR__ . '/../app/Listeners',
@@ -225,16 +206,6 @@ $app = Application::configure(basePath: dirname(__DIR__))
|
*/
$app->singleton(
Kernel::class,
FireflyIII\Http\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
FireflyIII\Console\Kernel::class
);
$app->singleton(
ExceptionHandler::class,
Handler::class

71
bootstrap/providers.php Normal file
View File

@@ -0,0 +1,71 @@
<?php
/*
* providers.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/>.
*/
use FireflyIII\Providers\AccountServiceProvider;
use FireflyIII\Providers\AdminServiceProvider;
use FireflyIII\Providers\AppServiceProvider;
use FireflyIII\Providers\AttachmentServiceProvider;
use FireflyIII\Providers\BillServiceProvider;
use FireflyIII\Providers\BudgetServiceProvider;
use FireflyIII\Providers\CategoryServiceProvider;
use FireflyIII\Providers\CurrencyServiceProvider;
use FireflyIII\Providers\FireflyServiceProvider;
use FireflyIII\Providers\JournalServiceProvider;
use FireflyIII\Providers\PiggyBankServiceProvider;
use FireflyIII\Providers\RecurringServiceProvider;
use FireflyIII\Providers\RouteServiceProvider;
use FireflyIII\Providers\RuleGroupServiceProvider;
use FireflyIII\Providers\RuleServiceProvider;
use FireflyIII\Providers\SearchServiceProvider;
use FireflyIII\Providers\TagServiceProvider;
use TwigBridge\ServiceProvider;
return [
// Package Service Providers...
// Application Service Providers...
AppServiceProvider::class,
FireflyIII\Providers\AuthServiceProvider::class,
// FireflyIII\Providers\BroadcastServiceProvider::class,
// EventServiceProvider::class,
RouteServiceProvider::class,
// own stuff:
PragmaRX\Google2FALaravel\ServiceProvider::class,
ServiceProvider::class,
// More service providers.
AccountServiceProvider::class,
AttachmentServiceProvider::class,
BillServiceProvider::class,
BudgetServiceProvider::class,
CategoryServiceProvider::class,
CurrencyServiceProvider::class,
FireflyServiceProvider::class,
JournalServiceProvider::class,
PiggyBankServiceProvider::class,
RuleServiceProvider::class,
RuleGroupServiceProvider::class,
SearchServiceProvider::class,
TagServiceProvider::class,
AdminServiceProvider::class,
RecurringServiceProvider::class,
];

View File

@@ -3,6 +3,70 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## v6.4.22
This release and several previous ones fix authentication problems mainly. Cleaning up the libraries that make up Firefly III's excellent security (with me standing on the shoulders of giants) means that many edge cases that worked in the past no longer worked. Notable issues are listed below.
As far as I know it all works as it should, but feel free to open new issues when necessary. My apologies for the mess.
### Fixed
- Removed Laravel Sanctum as it was unused.
- Migrated away from Laravel 10's kernel and bootstrap structure.
- Fixed remote user guard for console and unauthenticated routes (like `/up` and `health`)
- [Issue 11710](https://github.com/firefly-iii/firefly-iii/issues/11710) (Firefly throws error on startup and when trying to use importer) reported by @avee87
- [Issue 11712](https://github.com/firefly-iii/firefly-iii/issues/11712) (`RemoteUserGuard` regression in v6.4.19 blocks `/health` endpoint and internal Artisan commands) reported by @Dual-0
- [Issue 11720](https://github.com/firefly-iii/firefly-iii/issues/11720) (`RemoteUserGuard` regression from v6.4.19 (including v6.4.21) blocks `/health` endpoint) reported by @rjhenry
## v6.4.21
### Added
- The ability to undo the recording of a database migration, which may help with database issues. [See the docs](https://docs.firefly-iii.org/references/faq/firefly-iii/using/#i-get-errors-about-missing-tables-how-do-i-fix-this)
- Added debug logs to file permission checks.
### Fixed
- View range issue for subscription overview
- Amount log entries were recorded for the transaction group, not the journal
- Subscriptions were not being renamed in rules when their names were changed
- [Issue 11688](https://github.com/firefly-iii/firefly-iii/issues/11688) (Token endpoints returning 401 unauthorized) reported by @molnarti
- [Issue 11694](https://github.com/firefly-iii/firefly-iii/issues/11694) (Foreign currency amount is always positive in transfers) reported by @SledgehammerPL
- [Issue 11684](https://github.com/firefly-iii/firefly-iii/issues/11684) (Transaction summary duplicated after more than 10 rows) reported by @jkmf
- [Issue 11700](https://github.com/firefly-iii/firefly-iii/issues/11700) (Duplicate entry for key 'tag_transaction_journal_tag_id_transaction_journal_id_unique') reported by @beatbesmer
- [Issue 11702](https://github.com/firefly-iii/firefly-iii/issues/11702) (Can't enable displaying primary currency when using Postgres) reported by @absdjfh
- [Issue 11710](https://github.com/firefly-iii/firefly-iii/issues/11710) (Firefly throws error on startup and when trying to use importer) reported by @avee87
## v6.4.20
### Added
- The ability to undo the recording of a database migration, which may help with database issues. [See the docs](https://docs.firefly-iii.org/references/faq/firefly-iii/using/#i-get-errors-about-missing-tables-how-do-i-fix-this)
- Added debug logs to file permission checks.
### Fixed
- View range issue for subscription overview
- Amount log entries were recorded for the transaction group, not the journal
- Subscriptions were not being renamed in rules when their names were changed
- [Issue 11688](https://github.com/firefly-iii/firefly-iii/issues/11688) (Token endpoints returning 401 unauthorized) reported by @molnarti
- [Issue 11694](https://github.com/firefly-iii/firefly-iii/issues/11694) (Foreign currency amount is always positive in transfers) reported by @SledgehammerPL
- [Issue 11684](https://github.com/firefly-iii/firefly-iii/issues/11684) (Transaction summary duplicated after more than 10 rows) reported by @jkmf
- [Issue 11700](https://github.com/firefly-iii/firefly-iii/issues/11700) (Duplicate entry for key 'tag_transaction_journal_tag_id_transaction_journal_id_unique') reported by @beatbesmer
- [Issue 11702](https://github.com/firefly-iii/firefly-iii/issues/11702) (Can't enable displaying primary currency when using Postgres) reported by @absdjfh
## v6.4.19
### Added
- The ability to undo the recording of a database migration, which may help with database issues. [See the docs](https://docs.firefly-iii.org/references/faq/firefly-iii/using/#i-get-errors-about-missing-tables-how-do-i-fix-this)
- Added debug logs to file permission checks
### Fixed
- View range issue for subscription overview
- Amount log entries were recorded for the transaction group, not the journal
- Subscriptions were not being renamed in rules when their names were changed
- [Issue 11688](https://github.com/firefly-iii/firefly-iii/issues/11688) (Token endpoints returning 401 unauthorized) reported by @molnarti
- [Issue 11694](https://github.com/firefly-iii/firefly-iii/issues/11694) (Foreign currency amount is always positive in transfers) reported by @SledgehammerPL
- [Issue 11684](https://github.com/firefly-iii/firefly-iii/issues/11684) (Transaction summary duplicated after more than 10 rows) reported by @jkmf
- [Issue 11700](https://github.com/firefly-iii/firefly-iii/issues/11700) (Duplicate entry for key 'tag_transaction_journal_tag_id_transaction_journal_id_unique') reported by @beatbesmer
- [Issue 11702](https://github.com/firefly-iii/firefly-iii/issues/11702) (Can't enable displaying primary currency when using Postgres) reported by @absdjfh
## v6.4.18
### Fixed

View File

@@ -34,9 +34,6 @@
"transfers",
"management"
],
"platform": {
"php": "8.4"
},
"license": "AGPL-3.0-or-later",
"homepage": "https://github.com/firefly-iii/firefly-iii",
"type": "project",
@@ -93,13 +90,12 @@
"laravel-notification-channels/pushover": "^4.0",
"laravel/framework": "^12",
"laravel/passport": "^12.0",
"laravel/sanctum": "^4.1",
"laravel/slack-notification-channel": "^3.3",
"laravel/ui": "^4.2",
"league/commonmark": "^2",
"league/csv": "^9.10",
"league/fractal": "0.*",
"mailersend/laravel-driver": "^2.12",
"mailersend/laravel-driver": "^3.0",
"nunomaduro/collision": "^8",
"pragmarx/google2fa": "^8.0",
"predis/predis": "^3",

255
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": "72404106289a876b0046dceacbaccf24",
"content-hash": "6c4181d945517372c00358f3828806bc",
"packages": [
{
"name": "bacon/bacon-qr-code",
@@ -130,16 +130,16 @@
},
{
"name": "brick/math",
"version": "0.14.7",
"version": "0.14.8",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "07ff363b16ef8aca9692bba3be9e73fe63f34e50"
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/07ff363b16ef8aca9692bba3be9e73fe63f34e50",
"reference": "07ff363b16ef8aca9692bba3be9e73fe63f34e50",
"url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629",
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629",
"shasum": ""
},
"require": {
@@ -178,7 +178,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.14.7"
"source": "https://github.com/brick/math/tree/0.14.8"
},
"funding": [
{
@@ -186,7 +186,7 @@
"type": "github"
}
],
"time": "2026-02-07T10:57:35+00:00"
"time": "2026-02-10T14:33:43+00:00"
},
{
"name": "carbonphp/carbon-doctrine-types",
@@ -1878,16 +1878,16 @@
},
{
"name": "laravel/framework",
"version": "v12.50.0",
"version": "v12.51.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "174ffed91d794a35a541a5eb7c3785a02a34aaba"
"reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/174ffed91d794a35a541a5eb7c3785a02a34aaba",
"reference": "174ffed91d794a35a541a5eb7c3785a02a34aaba",
"url": "https://api.github.com/repos/laravel/framework/zipball/ce4de3feb211e47c4f959d309ccf8a2733b1bc16",
"reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16",
"shasum": ""
},
"require": {
@@ -2096,7 +2096,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2026-02-04T18:34:13+00:00"
"time": "2026-02-10T18:20:19+00:00"
},
{
"name": "laravel/passport",
@@ -2176,16 +2176,16 @@
},
{
"name": "laravel/prompts",
"version": "v0.3.12",
"version": "v0.3.13",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
"reference": "4861ded9003b7f8a158176a0b7666f74ee761be8"
"reference": "ed8c466571b37e977532fb2fd3c272c784d7050d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/4861ded9003b7f8a158176a0b7666f74ee761be8",
"reference": "4861ded9003b7f8a158176a0b7666f74ee761be8",
"url": "https://api.github.com/repos/laravel/prompts/zipball/ed8c466571b37e977532fb2fd3c272c784d7050d",
"reference": "ed8c466571b37e977532fb2fd3c272c784d7050d",
"shasum": ""
},
"require": {
@@ -2229,72 +2229,9 @@
"description": "Add beautiful and user-friendly forms to your command-line applications.",
"support": {
"issues": "https://github.com/laravel/prompts/issues",
"source": "https://github.com/laravel/prompts/tree/v0.3.12"
"source": "https://github.com/laravel/prompts/tree/v0.3.13"
},
"time": "2026-02-03T06:57:26+00:00"
},
{
"name": "laravel/sanctum",
"version": "v4.3.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/sanctum.git",
"reference": "c978c82b2b8ab685468a7ca35224497d541b775a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/c978c82b2b8ab685468a7ca35224497d541b775a",
"reference": "c978c82b2b8ab685468a7ca35224497d541b775a",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/console": "^11.0|^12.0",
"illuminate/contracts": "^11.0|^12.0",
"illuminate/database": "^11.0|^12.0",
"illuminate/support": "^11.0|^12.0",
"php": "^8.2",
"symfony/console": "^7.0"
},
"require-dev": {
"mockery/mockery": "^1.6",
"orchestra/testbench": "^9.15|^10.8",
"phpstan/phpstan": "^1.10"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laravel\\Sanctum\\SanctumServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Sanctum\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.",
"keywords": [
"auth",
"laravel",
"sanctum"
],
"support": {
"issues": "https://github.com/laravel/sanctum/issues",
"source": "https://github.com/laravel/sanctum"
},
"time": "2026-01-22T22:27:01+00:00"
"time": "2026-02-06T12:17:10+00:00"
},
{
"name": "laravel/serializable-closure",
@@ -3486,29 +3423,29 @@
},
{
"name": "mailersend/laravel-driver",
"version": "v2.12.0",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/mailersend/mailersend-laravel-driver.git",
"reference": "15e1ec41e29e65d3ca226929c65804190aaa93eb"
"reference": "cbda1bdcbd35e54f27a329df3c011389636eb783"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/15e1ec41e29e65d3ca226929c65804190aaa93eb",
"reference": "15e1ec41e29e65d3ca226929c65804190aaa93eb",
"url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/cbda1bdcbd35e54f27a329df3c011389636eb783",
"reference": "cbda1bdcbd35e54f27a329df3c011389636eb783",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/support": "^9.0 || ^10.0 || ^11.0 || ^12.0",
"mailersend/mailersend": "^0.35.0",
"illuminate/support": "^10.0 || ^11.0 || ^12.0",
"mailersend/mailersend": "^0.36.0",
"nyholm/psr7": "^1.5",
"php": ">=8.0",
"php": ">=8.2",
"php-http/guzzle7-adapter": "^1.0",
"symfony/mailer": "^6.0 || ^7.0"
},
"require-dev": {
"orchestra/testbench": "^7.0 || ^9.0 || ^10.0",
"orchestra/testbench": "^9.0 || ^10.0",
"phpunit/phpunit": "^9.0 || ^10.5 || ^12.0"
},
"type": "library",
@@ -3549,28 +3486,28 @@
],
"support": {
"issues": "https://github.com/mailersend/mailersend-laravel-driver/issues",
"source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.12.0"
"source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v3.0.0"
},
"time": "2025-10-28T14:59:16+00:00"
"time": "2026-02-05T12:32:37+00:00"
},
{
"name": "mailersend/mailersend",
"version": "v0.35.0",
"version": "v0.36.0",
"source": {
"type": "git",
"url": "https://github.com/mailersend/mailersend-php.git",
"reference": "f1696cf9e727e9503fbc5882d2a111bd966ad276"
"reference": "0a28852bba61f31c3668a2af6426dc0b2c866432"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/f1696cf9e727e9503fbc5882d2a111bd966ad276",
"reference": "f1696cf9e727e9503fbc5882d2a111bd966ad276",
"url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/0a28852bba61f31c3668a2af6426dc0b2c866432",
"reference": "0a28852bba61f31c3668a2af6426dc0b2c866432",
"shasum": ""
},
"require": {
"beberlei/assert": "^3.2",
"ext-json": "*",
"php": "^7.4 || ^8.0 <8.5",
"php": "^7.4 || ^8.0 <8.6",
"php-http/client-common": "^2.2",
"php-http/discovery": "^1.9",
"php-http/httplug": "^2.1",
@@ -3615,9 +3552,9 @@
],
"support": {
"issues": "https://github.com/mailersend/mailersend-php/issues",
"source": "https://github.com/mailersend/mailersend-php/tree/v0.35.0"
"source": "https://github.com/mailersend/mailersend-php/tree/v0.36.0"
},
"time": "2025-10-28T13:11:43+00:00"
"time": "2026-02-02T09:26:45+00:00"
},
{
"name": "monolog/monolog",
@@ -3894,16 +3831,16 @@
},
{
"name": "nette/utils",
"version": "v4.1.2",
"version": "v4.1.3",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5"
"reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/f76b5dc3d6c6d3043c8d937df2698515b99cbaf5",
"reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5",
"url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe",
"reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe",
"shasum": ""
},
"require": {
@@ -3915,8 +3852,10 @@
},
"require-dev": {
"jetbrains/phpstorm-attributes": "^1.2",
"nette/phpstan-rules": "^1.0",
"nette/tester": "^2.5",
"phpstan/phpstan": "^2.0@stable",
"phpstan/extension-installer": "^1.4@stable",
"phpstan/phpstan": "^2.1@stable",
"tracy/tracy": "^2.9"
},
"suggest": {
@@ -3977,9 +3916,9 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v4.1.2"
"source": "https://github.com/nette/utils/tree/v4.1.3"
},
"time": "2026-02-03T17:21:09+00:00"
"time": "2026-02-13T03:05:33+00:00"
},
{
"name": "nunomaduro/collision",
@@ -5120,16 +5059,16 @@
},
{
"name": "predis/predis",
"version": "v3.3.0",
"version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/predis/predis.git",
"reference": "153097374b39a2f737fe700ebcd725642526cdec"
"reference": "1183f5732e6b10efd33f64984a96726eaecb59aa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/predis/predis/zipball/153097374b39a2f737fe700ebcd725642526cdec",
"reference": "153097374b39a2f737fe700ebcd725642526cdec",
"url": "https://api.github.com/repos/predis/predis/zipball/1183f5732e6b10efd33f64984a96726eaecb59aa",
"reference": "1183f5732e6b10efd33f64984a96726eaecb59aa",
"shasum": ""
},
"require": {
@@ -5171,7 +5110,7 @@
],
"support": {
"issues": "https://github.com/predis/predis/issues",
"source": "https://github.com/predis/predis/tree/v3.3.0"
"source": "https://github.com/predis/predis/tree/v3.4.0"
},
"funding": [
{
@@ -5179,7 +5118,7 @@
"type": "github"
}
],
"time": "2025-11-24T17:48:50+00:00"
"time": "2026-02-11T17:30:28+00:00"
},
{
"name": "psr/cache",
@@ -9646,16 +9585,16 @@
},
{
"name": "thecodingmachine/safe",
"version": "v3.3.0",
"version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/thecodingmachine/safe.git",
"reference": "2cdd579eeaa2e78e51c7509b50cc9fb89a956236"
"reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thecodingmachine/safe/zipball/2cdd579eeaa2e78e51c7509b50cc9fb89a956236",
"reference": "2cdd579eeaa2e78e51c7509b50cc9fb89a956236",
"url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19",
"reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19",
"shasum": ""
},
"require": {
@@ -9765,7 +9704,7 @@
"description": "PHP core functions that throw exceptions instead of returning FALSE on error",
"support": {
"issues": "https://github.com/thecodingmachine/safe/issues",
"source": "https://github.com/thecodingmachine/safe/tree/v3.3.0"
"source": "https://github.com/thecodingmachine/safe/tree/v3.4.0"
},
"funding": [
{
@@ -9776,12 +9715,16 @@
"url": "https://github.com/shish",
"type": "github"
},
{
"url": "https://github.com/silasjoisten",
"type": "github"
},
{
"url": "https://github.com/staabm",
"type": "github"
}
],
"time": "2025-05-14T06:15:44+00:00"
"time": "2026-02-04T18:08:13+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
@@ -10530,16 +10473,16 @@
},
{
"name": "fruitcake/laravel-debugbar",
"version": "v4.0.7",
"version": "v4.0.8",
"source": {
"type": "git",
"url": "https://github.com/fruitcake/laravel-debugbar.git",
"reference": "a9cc62c81cd0bda4ca7410229487638d7df786be"
"reference": "ad7a5b11c11bf7773c9acd04d0fe0d79a229b1c7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruitcake/laravel-debugbar/zipball/a9cc62c81cd0bda4ca7410229487638d7df786be",
"reference": "a9cc62c81cd0bda4ca7410229487638d7df786be",
"url": "https://api.github.com/repos/fruitcake/laravel-debugbar/zipball/ad7a5b11c11bf7773c9acd04d0fe0d79a229b1c7",
"reference": "ad7a5b11c11bf7773c9acd04d0fe0d79a229b1c7",
"shasum": ""
},
"require": {
@@ -10616,7 +10559,7 @@
],
"support": {
"issues": "https://github.com/fruitcake/laravel-debugbar/issues",
"source": "https://github.com/fruitcake/laravel-debugbar/tree/v4.0.7"
"source": "https://github.com/fruitcake/laravel-debugbar/tree/v4.0.8"
},
"funding": [
{
@@ -10628,7 +10571,7 @@
"type": "github"
}
],
"time": "2026-02-06T20:53:50+00:00"
"time": "2026-02-14T13:26:03+00:00"
},
{
"name": "hamcrest/hamcrest-php",
@@ -11198,16 +11141,16 @@
},
{
"name": "php-debugbar/php-debugbar",
"version": "v3.3.1",
"version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/php-debugbar/php-debugbar.git",
"reference": "afdaa2e56aca9d56b5bb2bad041bd2f6002017cf"
"reference": "e50d470344b62a033a76d3d10a803b04c8e3be69"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/afdaa2e56aca9d56b5bb2bad041bd2f6002017cf",
"reference": "afdaa2e56aca9d56b5bb2bad041bd2f6002017cf",
"url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/e50d470344b62a033a76d3d10a803b04c8e3be69",
"reference": "e50d470344b62a033a76d3d10a803b04c8e3be69",
"shasum": ""
},
"require": {
@@ -11284,7 +11227,7 @@
],
"support": {
"issues": "https://github.com/php-debugbar/php-debugbar/issues",
"source": "https://github.com/php-debugbar/php-debugbar/tree/v3.3.1"
"source": "https://github.com/php-debugbar/php-debugbar/tree/v3.4.0"
},
"funding": [
{
@@ -11296,7 +11239,7 @@
"type": "github"
}
],
"time": "2026-02-06T21:09:38+00:00"
"time": "2026-02-14T14:10:26+00:00"
},
{
"name": "php-debugbar/symfony-bridge",
@@ -11414,11 +11357,11 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.38",
"version": "2.1.39",
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/dfaf1f530e1663aa167bc3e52197adb221582629",
"reference": "dfaf1f530e1663aa167bc3e52197adb221582629",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224",
"reference": "c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224",
"shasum": ""
},
"require": {
@@ -11463,25 +11406,25 @@
"type": "github"
}
],
"time": "2026-01-30T17:12:46+00:00"
"time": "2026-02-11T14:48:56+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
"version": "2.0.3",
"version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-deprecation-rules.git",
"reference": "468e02c9176891cc901143da118f09dc9505fc2f"
"reference": "6b5571001a7f04fa0422254c30a0017ec2f2cacc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/468e02c9176891cc901143da118f09dc9505fc2f",
"reference": "468e02c9176891cc901143da118f09dc9505fc2f",
"url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/6b5571001a7f04fa0422254c30a0017ec2f2cacc",
"reference": "6b5571001a7f04fa0422254c30a0017ec2f2cacc",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0",
"phpstan/phpstan": "^2.1.15"
"phpstan/phpstan": "^2.1.39"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.2",
@@ -11506,29 +11449,32 @@
"MIT"
],
"description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.",
"keywords": [
"static analysis"
],
"support": {
"issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues",
"source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/2.0.3"
"source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/2.0.4"
},
"time": "2025-05-14T10:56:57+00:00"
"time": "2026-02-09T13:21:14+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "2.0.8",
"version": "2.0.10",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "1ed9e626a37f7067b594422411539aa807190573"
"reference": "1aba28b697c1e3b6bbec8a1725f8b11b6d3e5a5f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/1ed9e626a37f7067b594422411539aa807190573",
"reference": "1ed9e626a37f7067b594422411539aa807190573",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/1aba28b697c1e3b6bbec8a1725f8b11b6d3e5a5f",
"reference": "1aba28b697c1e3b6bbec8a1725f8b11b6d3e5a5f",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0",
"phpstan/phpstan": "^2.1.29"
"phpstan/phpstan": "^2.1.39"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.2",
@@ -11554,11 +11500,14 @@
"MIT"
],
"description": "Extra strict and opinionated rules for PHPStan",
"keywords": [
"static analysis"
],
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.8"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.10"
},
"time": "2026-01-27T08:10:25+00:00"
"time": "2026-02-11T14:17:32+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -11908,16 +11857,16 @@
},
{
"name": "phpunit/phpunit",
"version": "12.5.10",
"version": "12.5.11",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "1686e30f6b32d35592f878a7f56fd0421d7d56c5"
"reference": "9b518cb40f9474572c9f0178e96ff3dc1cf02bf1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1686e30f6b32d35592f878a7f56fd0421d7d56c5",
"reference": "1686e30f6b32d35592f878a7f56fd0421d7d56c5",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9b518cb40f9474572c9f0178e96ff3dc1cf02bf1",
"reference": "9b518cb40f9474572c9f0178e96ff3dc1cf02bf1",
"shasum": ""
},
"require": {
@@ -11986,7 +11935,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.10"
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.11"
},
"funding": [
{
@@ -12010,7 +11959,7 @@
"type": "tidelift"
}
],
"time": "2026-02-08T07:06:48+00:00"
"time": "2026-02-10T12:32:02+00:00"
},
{
"name": "rector/rector",

View File

@@ -22,59 +22,18 @@
declare(strict_types=1);
use FireflyIII\Providers\AccountServiceProvider;
use FireflyIII\Providers\AdminServiceProvider;
use FireflyIII\Providers\AppServiceProvider;
use FireflyIII\Providers\AttachmentServiceProvider;
use FireflyIII\Providers\BillServiceProvider;
use FireflyIII\Providers\BudgetServiceProvider;
use FireflyIII\Providers\CategoryServiceProvider;
use FireflyIII\Providers\CurrencyServiceProvider;
use FireflyIII\Providers\EventServiceProvider;
use FireflyIII\Providers\FireflyServiceProvider;
use FireflyIII\Providers\JournalServiceProvider;
use FireflyIII\Providers\PiggyBankServiceProvider;
use FireflyIII\Providers\RecurringServiceProvider;
use FireflyIII\Providers\RouteServiceProvider;
use FireflyIII\Providers\RuleGroupServiceProvider;
use FireflyIII\Providers\RuleServiceProvider;
use FireflyIII\Providers\SearchServiceProvider;
use FireflyIII\Providers\SessionServiceProvider;
use FireflyIII\Providers\TagServiceProvider;
use FireflyIII\Support\Facades\AccountForm;
use FireflyIII\Support\Facades\CurrencyForm;
use FireflyIII\Support\Facades\ExpandedForm;
use FireflyIII\Support\Facades\PiggyBankForm;
use FireflyIII\Support\Facades\RuleForm;
use Illuminate\Auth\AuthServiceProvider;
use Illuminate\Auth\Passwords\PasswordResetServiceProvider;
use Illuminate\Broadcasting\BroadcastServiceProvider;
use Illuminate\Bus\BusServiceProvider;
use Illuminate\Cache\CacheServiceProvider;
use Illuminate\Cookie\CookieServiceProvider;
use Illuminate\Database\DatabaseServiceProvider;
use Illuminate\Encryption\EncryptionServiceProvider;
use Illuminate\Filesystem\FilesystemServiceProvider;
use Illuminate\Foundation\Providers\ConsoleSupportServiceProvider;
use Illuminate\Foundation\Providers\FoundationServiceProvider;
use Illuminate\Hashing\HashServiceProvider;
use Illuminate\Mail\MailServiceProvider;
use Illuminate\Notifications\NotificationServiceProvider;
use Illuminate\Pagination\PaginationServiceProvider;
use Illuminate\Pipeline\PipelineServiceProvider;
use Illuminate\Queue\QueueServiceProvider;
use Illuminate\Redis\RedisServiceProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\URL;
use Illuminate\Translation\TranslationServiceProvider;
use Illuminate\Validation\ValidationServiceProvider;
use Illuminate\View\ViewServiceProvider;
use Spatie\Html\Facades\Html;
use TwigBridge\ServiceProvider;
return [
'name' => envNonEmpty('APP_NAME', 'Firefly III'),
@@ -86,61 +45,6 @@ return [
'fallback_locale' => 'en_US',
'key' => env('APP_KEY'),
'cipher' => 'AES-256-CBC',
'providers' => [
// Laravel Framework Service Providers...
AuthServiceProvider::class,
BroadcastServiceProvider::class,
BusServiceProvider::class,
CacheServiceProvider::class,
ConsoleSupportServiceProvider::class,
CookieServiceProvider::class,
DatabaseServiceProvider::class,
EncryptionServiceProvider::class,
FilesystemServiceProvider::class,
FoundationServiceProvider::class,
HashServiceProvider::class,
MailServiceProvider::class,
NotificationServiceProvider::class,
PaginationServiceProvider::class,
PipelineServiceProvider::class,
QueueServiceProvider::class,
RedisServiceProvider::class,
PasswordResetServiceProvider::class,
SessionServiceProvider::class,
TranslationServiceProvider::class,
ValidationServiceProvider::class,
ViewServiceProvider::class,
// Package Service Providers...
// Application Service Providers...
AppServiceProvider::class,
FireflyIII\Providers\AuthServiceProvider::class,
// FireflyIII\Providers\BroadcastServiceProvider::class,
// EventServiceProvider::class,
RouteServiceProvider::class,
// own stuff:
PragmaRX\Google2FALaravel\ServiceProvider::class,
ServiceProvider::class,
// More service providers.
AccountServiceProvider::class,
AttachmentServiceProvider::class,
BillServiceProvider::class,
BudgetServiceProvider::class,
CategoryServiceProvider::class,
CurrencyServiceProvider::class,
FireflyServiceProvider::class,
JournalServiceProvider::class,
PiggyBankServiceProvider::class,
RuleServiceProvider::class,
RuleGroupServiceProvider::class,
SearchServiceProvider::class,
TagServiceProvider::class,
AdminServiceProvider::class,
RecurringServiceProvider::class,
],
'aliases' => [
'Auth' => Auth::class,
'Route' => Route::class,

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-09',
'build_time' => 1770609314,
'version' => 'develop/2026-02-16',
'build_time' => 1771230309,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used.

158
package-lock.json generated
View File

@@ -2152,9 +2152,9 @@
}
},
"node_modules/@fortawesome/fontawesome-free": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.1.0.tgz",
"integrity": "sha512-+WxNld5ZCJHvPQCr/GnzCTVREyStrAJjisUPtUxG5ngDA8TMlPnKp6dddlTpai4+1GNmltAeuk1hJEkBohwZYA==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.2.0.tgz",
"integrity": "sha512-3DguDv/oUE+7vjMeTSOjCSG+KeawgVQOHrKRnvUuqYh1mfArrh7s+s8hXW3e4RerBA1+Wh+hBqf8sJNpqNrBWg==",
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
"engines": {
"node": ">=6"
@@ -3246,9 +3246,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "25.2.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.2.tgz",
"integrity": "sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ==",
"version": "25.2.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
"integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3364,42 +3364,42 @@
}
},
"node_modules/@vue/compiler-core": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz",
"integrity": "sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.28.tgz",
"integrity": "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/shared": "3.5.27",
"entities": "^7.0.0",
"@babel/parser": "^7.29.0",
"@vue/shared": "3.5.28",
"entities": "^7.0.1",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.27.tgz",
"integrity": "sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.28.tgz",
"integrity": "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vue/compiler-core": "3.5.27",
"@vue/shared": "3.5.27"
"@vue/compiler-core": "3.5.28",
"@vue/shared": "3.5.28"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.27.tgz",
"integrity": "sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.28.tgz",
"integrity": "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/compiler-core": "3.5.27",
"@vue/compiler-dom": "3.5.27",
"@vue/compiler-ssr": "3.5.27",
"@vue/shared": "3.5.27",
"@babel/parser": "^7.29.0",
"@vue/compiler-core": "3.5.28",
"@vue/compiler-dom": "3.5.28",
"@vue/compiler-ssr": "3.5.28",
"@vue/shared": "3.5.28",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.21",
"postcss": "^8.5.6",
@@ -3407,14 +3407,14 @@
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.27.tgz",
"integrity": "sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.28.tgz",
"integrity": "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vue/compiler-dom": "3.5.27",
"@vue/shared": "3.5.27"
"@vue/compiler-dom": "3.5.28",
"@vue/shared": "3.5.28"
}
},
"node_modules/@vue/component-compiler-utils": {
@@ -3496,9 +3496,9 @@
"license": "MIT"
},
"node_modules/@vue/shared": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.27.tgz",
"integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.28.tgz",
"integrity": "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==",
"dev": true,
"license": "MIT"
},
@@ -3814,9 +3814,9 @@
}
},
"node_modules/ajv-formats/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4240,6 +4240,22 @@
"dev": true,
"license": "MIT"
},
"node_modules/body-parser/node_modules/qs": {
"version": "6.14.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/bonjour-service": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz",
@@ -4578,9 +4594,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001769",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz",
"integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==",
"version": "1.0.30001770",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz",
"integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==",
"dev": true,
"funding": [
{
@@ -6191,6 +6207,22 @@
"dev": true,
"license": "MIT"
},
"node_modules/express/node_modules/qs": {
"version": "6.14.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -7118,9 +7150,9 @@
}
},
"node_modules/i18next": {
"version": "25.8.4",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.4.tgz",
"integrity": "sha512-a9A0MnUjKvzjEN/26ZY1okpra9kA8MEwzYEz1BNm+IyxUKPRH6ihf0p7vj8YvULwZHKHl3zkJ6KOt4hewxBecQ==",
"version": "25.8.9",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.9.tgz",
"integrity": "sha512-PJ/dVpSXVUs1ZLOLG61V97JTHBqz0FCle41BpgF1z1VCl37kPJfX/ZzMDNDYEgSZxha5SY7ZfWITcNJCrgm7ug==",
"funding": [
{
"type": "individual",
@@ -9717,9 +9749,9 @@
"license": "MIT"
},
"node_modules/qs": {
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
"integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -11033,9 +11065,9 @@
}
},
"node_modules/terser-webpack-plugin/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11801,9 +11833,9 @@
"license": "BSD-2-Clause"
},
"node_modules/webpack": {
"version": "5.105.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz",
"integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==",
"version": "5.105.2",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.2.tgz",
"integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11922,9 +11954,9 @@
}
},
"node_modules/webpack-dev-middleware/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -12039,9 +12071,9 @@
}
},
"node_modules/webpack-dev-server/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -12159,9 +12191,9 @@
}
},
"node_modules/webpack/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -12216,9 +12248,9 @@
}
},
"node_modules/webpack/node_modules/webpack-sources": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz",
"integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz",
"integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==",
"dev": true,
"license": "MIT",
"engines": {

View File

@@ -22,8 +22,8 @@
"not_enough_currencies": "Not enough currencies",
"not_enough_currencies_enabled": "If you have just one currency enabled, there is no need to add exchange rates.",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> has been stored.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> has been stored.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") has been updated.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> er blevet gemt.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") er blevet opdateret.",
"transaction_updated_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID}<\/a> (\"{title}\") has been updated.",
"transaction_new_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID}<\/a> has been stored.",
"transaction_journal_information": "Transaction information",
@@ -31,7 +31,7 @@
"apply_rules_checkbox": "Apply rules",
"fire_webhooks_checkbox": "Fire webhooks",
"no_budget_pointer": "Det ser ud til, at du ikke har oprettet budgetter endnu. Du burde oprette nogle p\u00e5 <a href=\"\/budgets\">budgetsiden<\/a>. Budgetter kan hj\u00e6lpe dig med at holde styr p\u00e5 udgifter.",
"no_bill_pointer": "You seem to have no subscription yet. You should create some on the <a href=\"subscriptions\">subscription<\/a>-page. Subscriptions can help you keep track of expenses.",
"no_bill_pointer": "Det ser ikke ud til, at du har nogle budgetter endnu. Du burde oprette nogle p\u00e5 <a href=\"\/budgets\">budgetsiden<\/a>. Budgetter kan hj\u00e6lpe dig med at holde styr p\u00e5 udgifter.",
"source_account": "Kildekonto",
"hidden_fields_preferences": "You can enable more transaction options in your <a href=\"preferences\">preferences<\/a>.",
"destination_account": "Destinationskonto",
@@ -107,42 +107,42 @@
"multi_account_warning_withdrawal": "Husk, at kildekontoen for efterf\u00f8lgende opdelinger vil blive overstyret af hvad der er defineret i den f\u00f8rste opdeling af tilbagetr\u00e6kningen.",
"multi_account_warning_deposit": "Husk, at destinationskontoen for efterf\u00f8lgende opdelinger vil blive tilsidesat af hvad der er defineret i den f\u00f8rste opsplitning af depositummet.",
"multi_account_warning_transfer": "Husk p\u00e5, at kilden + destination konto for efterf\u00f8lgende opdelinger vil blive overstyret af hvad der er defineret i den f\u00f8rste opdeling af overf\u00f8rslen.",
"webhook_trigger_ANY": "After any event",
"webhook_trigger_ANY": "Efter enhver begivenhed",
"webhook_trigger_STORE_TRANSACTION": "Efter oprettelse af transaktion",
"webhook_trigger_UPDATE_TRANSACTION": "Efter opdatering af transaktion",
"webhook_trigger_DESTROY_TRANSACTION": "Efter sletning af transaktion",
"webhook_trigger_STORE_BUDGET": "After budget creation",
"webhook_trigger_UPDATE_BUDGET": "After budget update",
"webhook_trigger_DESTROY_BUDGET": "After budget delete",
"webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "After budgeted amount change",
"webhook_trigger_STORE_BUDGET": "Efter budgetoprettelse",
"webhook_trigger_UPDATE_BUDGET": "Efter budgetopdatering",
"webhook_trigger_DESTROY_BUDGET": "Efter sletning af budget",
"webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "Efter budgetteret bel\u00f8b \u00e6ndring",
"webhook_response_TRANSACTIONS": "Transaktionsdetaljer",
"webhook_response_RELEVANT": "Relevant details",
"webhook_response_RELEVANT": "Relevante oplysninger",
"webhook_response_ACCOUNTS": "Kontodetaljer",
"webhook_response_NONE": "No details",
"webhook_response_NONE": "Ingen detaljer",
"webhook_delivery_JSON": "JSON",
"actions": "Handlinger",
"meta_data": "Meta data",
"webhook_messages": "Webhook-besked",
"inactive": "Inactive",
"no_webhook_messages": "Der er ingen webhook-beskeder",
"inspect": "Inspect",
"inspect": "Unders\u00f8g",
"create_new_webhook": "Opret ny webhook",
"webhooks": "Webhooks",
"webhook_trigger_form_help": "Indicate on what event the webhook will trigger",
"webhook_response_form_help": "Indicate what the webhook must submit to the URL.",
"webhook_trigger_form_help": "Indik\u00e9r p\u00e5 hvilken begivenhed webhook vil udl\u00f8se",
"webhook_response_form_help": "Angiv, hvad webhook skal indsende til URL.",
"webhook_delivery_form_help": "Hvilket format webhook skal levere data i.",
"webhook_active_form_help": "Webhooken skal v\u00e6re aktiv, ellers vil den ikke blive kaldt.",
"edit_webhook_js": "Rediger webhook \"{title}\"",
"webhook_was_triggered": "The webhook was triggered on the indicated transaction. Please wait for results to appear.",
"webhook_was_triggered": "Webhooken blev udl\u00f8st p\u00e5 den angivne transaktion. Vent venligst p\u00e5 at resultaterne vises.",
"view_message": "Vis besked",
"view_attempts": "Vis mislykkede fors\u00f8g",
"message_content_title": "Webhook-beskedindhold",
"message_content_help": "This is the content of the message that was sent (or tried) using this webhook.",
"message_content_help": "Dette er indholdet af den besked, der blev sendt (eller fors\u00f8gt) ved hj\u00e6lp af denne webhook.",
"attempt_content_title": "Webhook-fors\u00f8g",
"attempt_content_help": "These are all the unsuccessful attempts of this webhook message to submit to the configured URL. After some time, Firefly III will stop trying.",
"attempt_content_help": "Disse er alle de mislykkede fors\u00f8g p\u00e5 at sende denne webhook-meddelelse til den konfigurerede URL. Efter et stykke tid vil Firefly III stoppe med at fors\u00f8ge.",
"no_attempts": "Der er ingen mislykkede fors\u00f8g. Det er en god ting!",
"webhook_attempt_at": "Attempt at {moment}",
"logs": "Logs",
"webhook_attempt_at": "Fors\u00f8g p\u00e5 {moment}",
"logs": "Logfiler",
"response": "Svar",
"visit_webhook_url": "Bes\u00f8g webhook-URL",
"reset_webhook_secret": "Nulstil webhook-hemmelighed",

View File

@@ -107,18 +107,18 @@
"multi_account_warning_withdrawal": "Tenga en cuenta que la cuenta de origen de las divisiones posteriores ser\u00e1 anulada por lo que se defina en la primera divisi\u00f3n del gasto.",
"multi_account_warning_deposit": "Tenga en cuenta que la cuenta de destino de las divisiones posteriores ser\u00e1 anulada por lo que se defina en la primera divisi\u00f3n del retiro.",
"multi_account_warning_transfer": "Tenga en cuenta que la cuenta de origen + destino de divisiones posteriores ser\u00e1 anulada por lo que se defina en la primera divisi\u00f3n de la transferencia.",
"webhook_trigger_ANY": "After any event",
"webhook_trigger_ANY": "Despu\u00e9s de cualquier evento",
"webhook_trigger_STORE_TRANSACTION": "Despu\u00e9s de crear la transacci\u00f3n",
"webhook_trigger_UPDATE_TRANSACTION": "Despu\u00e9s de actualizar la transacci\u00f3n",
"webhook_trigger_DESTROY_TRANSACTION": "Despu\u00e9s de eliminar la transacci\u00f3n",
"webhook_trigger_STORE_BUDGET": "After budget creation",
"webhook_trigger_STORE_BUDGET": "Despu\u00e9s de crear un presupuesto",
"webhook_trigger_UPDATE_BUDGET": "After budget update",
"webhook_trigger_DESTROY_BUDGET": "After budget delete",
"webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "After budgeted amount change",
"webhook_response_TRANSACTIONS": "Detalles de la transacci\u00f3n",
"webhook_response_RELEVANT": "Relevant details",
"webhook_response_ACCOUNTS": "Detalles de la cuenta",
"webhook_response_NONE": "No details",
"webhook_response_NONE": "Sin detalles",
"webhook_delivery_JSON": "JSON",
"actions": "Acciones",
"meta_data": "Meta Datos",

View File

@@ -62,7 +62,7 @@
"destination_account_reconciliation": "\uc870\uc815 \uac70\ub798\uc758 \ubaa9\uc801\uc9c0 \uacc4\uc815\uc740 \ud3b8\uc9d1\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.",
"source_account_reconciliation": "\uc870\uc815 \uac70\ub798\uc758 \ucd9c\ubc1c\uc9c0 \uacc4\uc815\uc740 \ud3b8\uc9d1\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.",
"budget": "\uc608\uc0b0",
"bill": "Subscription",
"bill": "\uad6c\ub3c5",
"you_create_withdrawal": "\ucd9c\uae08\uc744 \uc0dd\uc131\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4.",
"you_create_transfer": "\uc804\uc1a1\uc744 \uc0dd\uc131\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4.",
"you_create_deposit": "\uc785\uae08\uc744 \uc0dd\uc131\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4.",

Some files were not shown because too many files have changed in this diff Show More