mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-10 06:32:05 +00:00
Compare commits
150 Commits
develop-20
...
354bbebbee
Author | SHA1 | Date | |
---|---|---|---|
|
354bbebbee | ||
|
a70fab1e87 | ||
|
b9c93091cd | ||
|
4349f8f303 | ||
|
5088e20f25 | ||
|
3f81aa7403 | ||
|
8885d1dbeb | ||
|
a6ba75d528 | ||
|
667cbb1332 | ||
|
d1bae875f7 | ||
|
c5cf529413 | ||
|
62b9f2785f | ||
|
3b85f87502 | ||
|
87d3d14504 | ||
|
5637573fd0 | ||
|
48255ae6ee | ||
|
ea02986170 | ||
|
f4fbc15ac6 | ||
|
a02c4b42a4 | ||
|
1ff47441ce | ||
|
2cc8568077 | ||
|
408687ec6b | ||
|
308abffb0b | ||
|
6743b3fe83 | ||
|
ac0113e445 | ||
|
0f0a28c3d9 | ||
|
79f2d70211 | ||
|
8a06c0f7ec | ||
|
c54da62005 | ||
|
e5923202af | ||
|
eb6f78406e | ||
|
d61f87f649 | ||
|
33dcce7525 | ||
|
b1d86c3a37 | ||
|
822dee6e70 | ||
|
f6dac83777 | ||
|
d3c557ca22 | ||
|
853a99852e | ||
|
8f24ac4fcd | ||
|
8b09cfb8c9 | ||
|
18ae950d2e | ||
|
69dfbda847 | ||
|
4ec2fcdb8a | ||
|
08879d31ba | ||
|
66d09450d3 | ||
|
74f7c07a76 | ||
|
ae3d0a3e49 | ||
|
61e8d7d7a2 | ||
|
62c5440605 | ||
|
0aa90b9453 | ||
|
855bc2f8e7 | ||
|
d8f05492c3 | ||
|
4a264f34fa | ||
|
5a1413e758 | ||
|
84dbeeb0ce | ||
|
d868dc0945 | ||
|
beecf9c229 | ||
|
e39ba46398 | ||
|
e6b6a3cee5 | ||
|
b5483f6ad3 | ||
|
a751218d53 | ||
|
2af5e6eeef | ||
|
013c43f9f2 | ||
|
7e08a1f33c | ||
|
e592b56d7a | ||
|
a2479f71fe | ||
|
7d3b993b98 | ||
|
90623101a3 | ||
|
e2eca79b25 | ||
|
8c0ee8f024 | ||
|
69cae3ae55 | ||
|
8a06298385 | ||
|
acc3c294d8 | ||
|
dbf7dba421 | ||
|
65813f290d | ||
|
3491fbb99d | ||
|
cb6b3d5f85 | ||
|
956d4e09c3 | ||
|
6a7c35e7bc | ||
|
090aecb5f5 | ||
|
b653d63d3d | ||
|
258dbf4a98 | ||
|
53335077ff | ||
|
ecfb3e2f95 | ||
|
f512e6724e | ||
|
de9efb0727 | ||
|
9075fa8ac8 | ||
|
768bd892c8 | ||
|
9d9483e20f | ||
|
935453796e | ||
|
c2d3f5da16 | ||
|
9e6f9d16e4 | ||
|
fad016f92f | ||
|
30df6684cb | ||
|
4aa911420a | ||
|
19555a7046 | ||
|
e5c409a8fc | ||
|
3adf3d2fdb | ||
|
0923d5a23e | ||
|
76b8cdc385 | ||
|
0a27da83eb | ||
|
17d6e2be85 | ||
|
7381f3eba9 | ||
|
7f2ef1b8e1 | ||
|
9dccae2402 | ||
|
073afd5b6e | ||
|
4167d85be2 | ||
|
ee28d1307d | ||
|
7562215666 | ||
|
0203b918e9 | ||
|
ae7c664418 | ||
|
f13e0991fb | ||
|
deae94b658 | ||
|
c38c752520 | ||
|
28e7df2527 | ||
|
cb0b42e44b | ||
|
a3674c4dfe | ||
|
27480561ee | ||
|
6ea7152423 | ||
|
dab95f7a86 | ||
|
adf34805a8 | ||
|
93e926465f | ||
|
5b0be91f93 | ||
|
01e7b604da | ||
|
974a550d22 | ||
|
58d175444b | ||
|
29d8861e96 | ||
|
eb832c750f | ||
|
134770644a | ||
|
a9f21c9371 | ||
|
781947beeb | ||
|
9760cd2f97 | ||
|
d317e9ec32 | ||
|
534f7fcadb | ||
|
fb3f7a1d4b | ||
|
bf2c3e3561 | ||
|
b670f81dcd | ||
|
7aac1cdf67 | ||
|
fa0ac8a16c | ||
|
0990b1f0b4 | ||
|
c1922670c8 | ||
|
81cd89d66f | ||
|
f5c202543c | ||
|
034f437c6b | ||
|
8550ba6138 | ||
|
a51501025b | ||
|
a9d26e4586 | ||
|
949691935f | ||
|
4835b05304 | ||
|
cce5a73dd2 |
137
.ci/php-cs-fixer/composer.lock
generated
137
.ci/php-cs-fixer/composer.lock
generated
@@ -402,16 +402,16 @@
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.87.1",
|
||||
"version": "v3.88.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "2f5170365e2a422d0c5421f9c8818b2c078105f6"
|
||||
"reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2f5170365e2a422d0c5421f9c8818b2c078105f6",
|
||||
"reference": "2f5170365e2a422d0c5421f9c8818b2c078105f6",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a8d15584bafb0f0d9d938827840060fd4a3ebc99",
|
||||
"reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -438,12 +438,13 @@
|
||||
"symfony/polyfill-mbstring": "^1.33",
|
||||
"symfony/polyfill-php80": "^1.33",
|
||||
"symfony/polyfill-php81": "^1.33",
|
||||
"symfony/polyfill-php84": "^1.33",
|
||||
"symfony/process": "^5.4.47 || ^6.4.24 || ^7.2",
|
||||
"symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"facile-it/paraunit": "^1.3.1 || ^2.7",
|
||||
"infection/infection": "^0.29.14",
|
||||
"infection/infection": "^0.31.0",
|
||||
"justinrainbow/json-schema": "^6.5",
|
||||
"keradus/cli-executor": "^2.2",
|
||||
"mikey179/vfsstream": "^1.6.12",
|
||||
@@ -451,7 +452,6 @@
|
||||
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
|
||||
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
|
||||
"phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34",
|
||||
"symfony/polyfill-php84": "^1.33",
|
||||
"symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2",
|
||||
"symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2"
|
||||
},
|
||||
@@ -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.87.1"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.88.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -502,7 +502,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-09-02T15:27:36+00:00"
|
||||
"time": "2025-09-27T00:24:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
@@ -1252,16 +1252,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v7.3.3",
|
||||
"version": "v7.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7"
|
||||
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7",
|
||||
"reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
|
||||
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1326,7 +1326,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v7.3.3"
|
||||
"source": "https://github.com/symfony/console/tree/v7.3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1346,7 +1346,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-25T06:35:40+00:00"
|
||||
"time": "2025-09-22T15:31:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
@@ -2284,17 +2284,97 @@
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v7.3.3",
|
||||
"name": "symfony/polyfill-php84",
|
||||
"version": "v1.33.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "32241012d521e2e8a9d713adb0812bb773b907f1"
|
||||
"url": "https://github.com/symfony/polyfill-php84.git",
|
||||
"reference": "d8ced4d875142b6a7426000426b8abc631d6b191"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1",
|
||||
"reference": "32241012d521e2e8a9d713adb0812bb773b907f1",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191",
|
||||
"reference": "d8ced4d875142b6a7426000426b8abc631d6b191",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php84\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-24T13:30:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v7.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "f24f8f316367b30810810d4eb30c543d7003ff3b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b",
|
||||
"reference": "f24f8f316367b30810810d4eb30c543d7003ff3b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2326,7 +2406,7 @@
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v7.3.3"
|
||||
"source": "https://github.com/symfony/process/tree/v7.3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2346,7 +2426,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-18T09:42:54+00:00"
|
||||
"time": "2025-09-11T10:12:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
@@ -2495,16 +2575,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v7.3.3",
|
||||
"version": "v7.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c"
|
||||
"reference": "f96476035142921000338bad71e5247fbc138872"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
|
||||
"reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872",
|
||||
"reference": "f96476035142921000338bad71e5247fbc138872",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2519,7 +2599,6 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/emoji": "^7.1",
|
||||
"symfony/error-handler": "^6.4|^7.0",
|
||||
"symfony/http-client": "^6.4|^7.0",
|
||||
"symfony/intl": "^6.4|^7.0",
|
||||
"symfony/translation-contracts": "^2.5|^3.0",
|
||||
@@ -2562,7 +2641,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v7.3.3"
|
||||
"source": "https://github.com/symfony/string/tree/v7.3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2582,7 +2661,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-25T06:35:40+00:00"
|
||||
"time": "2025-09-11T14:36:48+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
@@ -7,21 +7,19 @@ parameters:
|
||||
- ../bootstrap/app.php
|
||||
universalObjectCratesClasses:
|
||||
- Illuminate\Database\Eloquent\Model
|
||||
# TODO: slowly remove these parameters and fix the issues found.
|
||||
reportUnmatchedIgnoredErrors: true
|
||||
ignoreErrors:
|
||||
# TODO: slowly remove these exceptions and fix the issues found.
|
||||
- identifier: varTag.type
|
||||
# all errors below I will never fix.
|
||||
- '#expects view-string\|null, string given#'
|
||||
- '#expects view-string, string given#'
|
||||
- "#Parameter \\#[1-2] \\$num[1-2] of function bc[a-z]+ expects numeric-string, [a-z\\-|&]+ given#"
|
||||
- identifier: missingType.generics # not interesting enough to fix.
|
||||
-
|
||||
identifier: larastan.noEnvCallsOutsideOfConfig
|
||||
path: ../app/Console/Commands/System/CreatesDatabase.php
|
||||
- identifier: missingType.iterableValue # not interesting enough to fix.
|
||||
- identifier: missingType.generics # not interesting enough to fix.
|
||||
- "#Parameter \\#[1-2] \\$num[1-2] of function bc[a-z]+ expects numeric-string, [a-z\\-|&]+ given#"
|
||||
- '#expects view-string, string given#'
|
||||
- '#expects view-string\|null, string given#'
|
||||
|
||||
# phpstan can't handle this so we ignore them.
|
||||
- identifier: varTag.type # needs a custom extension for every repository, not gonna happen.
|
||||
- '#Dynamic call to static method Illuminate#'
|
||||
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::before#' # is custom scope
|
||||
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::after#' # is custom scope
|
||||
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::withTrashed#' # is to allow soft delete
|
||||
|
@@ -314,8 +314,9 @@ DEMO_USERNAME=
|
||||
DEMO_PASSWORD=
|
||||
|
||||
#
|
||||
# Disable or enable the running balance column data
|
||||
# Please disable this. It's a very experimental feature.
|
||||
# Disable or enable the running balance column data.
|
||||
# If you enable this, please also run "php artisan firefly-iii:correct-database"
|
||||
# This will take some time the first run.
|
||||
#
|
||||
USE_RUNNING_BALANCE=false
|
||||
|
||||
|
4
.github/workflows/cleanup.yml
vendored
4
.github/workflows/cleanup.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Prune cancelled/skipped runs
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Prune runs older than 3 days
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -250,7 +250,7 @@ jobs:
|
||||
fi
|
||||
|
||||
echo "Merge all changes from $BRANCH_NAME back into '$MERGE_INTO' using a PR"
|
||||
PR_URL=$(gh pr create -B $MERGE_INTO -H $BRANCH_NAME --title "🤖 Automatic PR to merge all changes into the '$MERGE_INTO' branch." --body '🤖 Created by GitHub action')
|
||||
PR_URL=$(gh pr create -B $MERGE_INTO -H $BRANCH_NAME --title "🤖 Automatic PR to merge all changes into the '$MERGE_INTO' branch." --body '🤖 This PR was created automatically by a GitHub action to merge the changed files into this branch. It will be merged automatically. `Share and enjoy`')
|
||||
echo "PR URL is '$PR_URL'"
|
||||
IFS='/' read -ra parts <<< "$PR_URL"
|
||||
PR_NR=$(printf %s\\n "${parts[@]:(-1)}")
|
||||
@@ -272,7 +272,7 @@ jobs:
|
||||
|
||||
echo "Also merge everything into main since this is a release."
|
||||
echo 'create PR'
|
||||
PR_URL=$(gh pr create -B main -H develop --title "🤖 Automatic PR to merge all changes into the main branch." --body "🤖 Created by GitHub action")
|
||||
PR_URL=$(gh pr create -B main -H develop --title "🤖 Automatic PR to merge all changes into the main branch." --body '🤖 This PR was created automatically by a GitHub action to merge the changed files into this branch. It will be merged automatically. `Share and enjoy`')
|
||||
echo "PR URL is '$PR_URL'"
|
||||
|
||||
IFS='/' read -ra parts <<< "$PR_URL"
|
||||
|
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
actions: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
- uses: actions/stale@v10
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: |
|
||||
|
@@ -28,8 +28,10 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
@@ -96,6 +98,7 @@ class PiggyBankController extends Controller
|
||||
|
||||
/** @var PiggyBank $piggy */
|
||||
foreach ($piggies as $piggy) {
|
||||
/** @var TransactionCurrency $currency */
|
||||
$currency = $piggy->transactionCurrency;
|
||||
$currentAmount = $this->piggyRepository->getCurrentAmount($piggy);
|
||||
$objectGroup = $piggy->objectGroups()->first();
|
||||
@@ -105,8 +108,8 @@ class PiggyBankController extends Controller
|
||||
'name_with_balance' => sprintf(
|
||||
'%s (%s / %s)',
|
||||
$piggy->name,
|
||||
app('amount')->formatAnything($currency, $currentAmount, false),
|
||||
app('amount')->formatAnything($currency, $piggy->target_amount, false),
|
||||
Amount::formatAnything($currency, $currentAmount, false),
|
||||
Amount::formatAnything($currency, $piggy->target_amount, false),
|
||||
),
|
||||
'currency_id' => (string) $currency->id,
|
||||
'currency_name' => $currency->name,
|
||||
|
@@ -31,9 +31,7 @@ use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\AccountBalanceGrouped;
|
||||
use FireflyIII\Support\Http\Api\CleansChartData;
|
||||
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
|
||||
|
@@ -31,10 +31,10 @@ use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\CleansChartData;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
@@ -114,7 +114,7 @@ class BudgetController extends Controller
|
||||
// get all limits:
|
||||
$limits = $this->blRepository->getBudgetLimits($budget, $start, $end);
|
||||
$rows = [];
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, null, new Collection([$budget]));
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, null, new Collection()->push($budget));
|
||||
$expenses = $this->processExpenses($budget->id, $spent, $start, $end);
|
||||
$converter = new ExchangeRateConverter();
|
||||
$currencies = [$this->primaryCurrency->id => $this->primaryCurrency];
|
||||
@@ -133,9 +133,9 @@ class BudgetController extends Controller
|
||||
$row['pc_left'] = '0';
|
||||
$row['pc_overspent'] = '0';
|
||||
|
||||
if (null !== $limit) {
|
||||
if ($limit instanceof BudgetLimit) {
|
||||
$row['budgeted'] = $limit->amount;
|
||||
$row['left'] = bcsub($row['budgeted'], bcmul($row['spent'], '-1'));
|
||||
$row['left'] = bcsub((string) $row['budgeted'], bcmul((string) $row['spent'], '-1'));
|
||||
$row['overspent'] = bcmul($row['left'], '-1');
|
||||
$row['left'] = 1 === bccomp($row['left'], '0') ? $row['left'] : '0';
|
||||
$row['overspent'] = 1 === bccomp($row['overspent'], '0') ? $row['overspent'] : '0';
|
||||
@@ -143,7 +143,7 @@ class BudgetController extends Controller
|
||||
|
||||
// convert data if necessary.
|
||||
if (true === $this->convertToPrimary && $currencyId !== $this->primaryCurrency->id) {
|
||||
$currencies[$currencyId] ??= TransactionCurrency::find($currencyId);
|
||||
$currencies[$currencyId] ??= Amount::getTransactionCurrencyById($currencyId);
|
||||
$row['pc_budgeted'] = $converter->convert($currencies[$currencyId], $this->primaryCurrency, $start, $row['budgeted']);
|
||||
$row['pc_spent'] = $converter->convert($currencies[$currencyId], $this->primaryCurrency, $start, $row['spent']);
|
||||
$row['pc_left'] = $converter->convert($currencies[$currencyId], $this->primaryCurrency, $start, $row['left']);
|
||||
@@ -208,7 +208,7 @@ class BudgetController extends Controller
|
||||
// */
|
||||
// private function noBudgetLimits(Budget $budget, Carbon $start, Carbon $end): array
|
||||
// {
|
||||
// $spent = $this->opsRepository->listExpenses($start, $end, null, new Collection([$budget]));
|
||||
// $spent = $this->opsRepository->listExpenses($start, $end, null, new Collection()->push($budget));
|
||||
//
|
||||
// return $this->processExpenses($budget->id, $spent, $start, $end);
|
||||
// }
|
||||
@@ -231,7 +231,7 @@ class BudgetController extends Controller
|
||||
* @var array $block
|
||||
*/
|
||||
foreach ($spent as $currencyId => $block) {
|
||||
$this->currencies[$currencyId] ??= TransactionCurrency::find($currencyId);
|
||||
$this->currencies[$currencyId] ??= Amount::getTransactionCurrencyById($currencyId);
|
||||
$return[$currencyId] ??= [
|
||||
'currency_id' => (string)$currencyId,
|
||||
'currency_code' => $block['currency_code'],
|
||||
@@ -250,7 +250,9 @@ class BudgetController extends Controller
|
||||
// var_dump($return);
|
||||
/** @var array $journal */
|
||||
foreach ($currentBudgetArray['transaction_journals'] as $journal) {
|
||||
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], (string)$journal['amount']);
|
||||
/** @var numeric-string $amount */
|
||||
$amount = (string)$journal['amount'];
|
||||
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], $amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +290,7 @@ class BudgetController extends Controller
|
||||
// Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
|
||||
// $end = clone $limit->end_date;
|
||||
// $end->endOfDay();
|
||||
// $spent = $this->opsRepository->listExpenses($limit->start_date, $end, null, new Collection([$budget]));
|
||||
// $spent = $this->opsRepository->listExpenses($limit->start_date, $end, null, new Collection()->push($budget));
|
||||
// $limitCurrencyId = $limit->transaction_currency_id;
|
||||
//
|
||||
// /** @var array $entry */
|
||||
|
@@ -232,8 +232,6 @@ abstract class Controller extends BaseController
|
||||
$baseUrl = sprintf('%s/api/v1', request()->getSchemeAndHttpHost());
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
// $transformer->collectMetaData(new Collection([$object]));
|
||||
|
||||
$resource = new Item($object, $transformer, $key);
|
||||
|
||||
return $manager->createData($resource)->toArray();
|
||||
|
@@ -76,7 +76,7 @@ class BudgetController extends Controller
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
$expenses = $this->opsRepository->sumExpenses($start, $end, $assetAccounts, new Collection([$budget]));
|
||||
$expenses = $this->opsRepository->sumExpenses($start, $end, $assetAccounts, new Collection()->push($budget));
|
||||
|
||||
/** @var array $expense */
|
||||
foreach ($expenses as $expense) {
|
||||
|
@@ -76,7 +76,7 @@ class CategoryController extends Controller
|
||||
|
||||
/** @var Category $category */
|
||||
foreach ($categories as $category) {
|
||||
$expenses = $this->opsRepository->sumExpenses($start, $end, $assetAccounts, new Collection([$category]));
|
||||
$expenses = $this->opsRepository->sumExpenses($start, $end, $assetAccounts, new Collection()->push($category));
|
||||
|
||||
/** @var array $expense */
|
||||
foreach ($expenses as $expense) {
|
||||
|
@@ -76,7 +76,7 @@ class CategoryController extends Controller
|
||||
|
||||
/** @var Category $category */
|
||||
foreach ($categories as $category) {
|
||||
$expenses = $this->opsRepository->sumIncome($start, $end, $assetAccounts, new Collection([$category]));
|
||||
$expenses = $this->opsRepository->sumIncome($start, $end, $assetAccounts, new Collection()->push($category));
|
||||
|
||||
/** @var array $expense */
|
||||
foreach ($expenses as $expense) {
|
||||
|
@@ -76,7 +76,7 @@ class CategoryController extends Controller
|
||||
|
||||
/** @var Category $category */
|
||||
foreach ($categories as $category) {
|
||||
$expenses = $this->opsRepository->sumTransfers($start, $end, $assetAccounts, new Collection([$category]));
|
||||
$expenses = $this->opsRepository->sumTransfers($start, $end, $assetAccounts, new Collection()->push($category));
|
||||
|
||||
/** @var array $expense */
|
||||
foreach ($expenses as $expense) {
|
||||
|
@@ -152,7 +152,7 @@ class ListController extends Controller
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($admin)->setAccounts(new Collection([$account]))
|
||||
$collector->setUser($admin)->setAccounts(new Collection()->push($account))
|
||||
->withAPIInformation()->setLimit($pageSize)->setPage($this->parameters->get('page'))->setTypes($types)
|
||||
;
|
||||
|
||||
|
@@ -67,7 +67,9 @@ class StoreController extends Controller
|
||||
*/
|
||||
public function store(StoreRequest $request): JsonResponse
|
||||
{
|
||||
$budget = $this->repository->store($request->getAll());
|
||||
$data = $request->getAll();
|
||||
$data['fire_webhooks'] ??= true;
|
||||
$budget = $this->repository->store($data);
|
||||
$budget->refresh();
|
||||
$manager = $this->getManager();
|
||||
|
||||
|
@@ -57,15 +57,10 @@ class UpdateController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/budgets/updateBudget
|
||||
*
|
||||
* Update a budget.
|
||||
*/
|
||||
public function update(UpdateRequest $request, Budget $budget): JsonResponse
|
||||
{
|
||||
$data = $request->getAll();
|
||||
$data['fire_webhooks'] ??= true;
|
||||
$budget = $this->repository->update($budget, $data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
|
@@ -70,6 +70,7 @@ class StoreController extends Controller
|
||||
$data = $request->getAll();
|
||||
$data['start_date'] = $data['start'];
|
||||
$data['end_date'] = $data['end'];
|
||||
$data['fire_webhooks'] ??= true;
|
||||
$data['budget_id'] = $budget->id;
|
||||
|
||||
$budgetLimit = $this->blRepository->store($data);
|
||||
|
@@ -77,6 +77,7 @@ class UpdateController extends Controller
|
||||
throw new FireflyException('20028: The budget limit does not belong to the budget.');
|
||||
}
|
||||
$data = $request->getAll();
|
||||
$data['fire_webhooks'] ??= true;
|
||||
$data['budget_id'] = $budget->id;
|
||||
$budgetLimit = $this->blRepository->update($budgetLimit, $data);
|
||||
$manager = $this->getManager();
|
||||
|
@@ -72,7 +72,7 @@ class DestroyController extends Controller
|
||||
public function destroySingleByDate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): JsonResponse
|
||||
{
|
||||
$exchangeRate = $this->repository->getSpecificRateOnDate($from, $to, $date);
|
||||
if (null !== $exchangeRate) {
|
||||
if ($exchangeRate instanceof CurrencyExchangeRate) {
|
||||
$this->repository->deleteRate($exchangeRate);
|
||||
}
|
||||
|
||||
|
@@ -95,7 +95,7 @@ class ShowController extends Controller
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$exchangeRate = $this->repository->getSpecificRateOnDate($from, $to, $date);
|
||||
if (null === $exchangeRate) {
|
||||
if (!$exchangeRate instanceof CurrencyExchangeRate) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
|
@@ -33,6 +33,7 @@ use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use FireflyIII\Transformers\ExchangeRateTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -69,7 +70,7 @@ class StoreController extends Controller
|
||||
foreach ($data as $date => $rate) {
|
||||
$date = Carbon::createFromFormat('Y-m-d', $date);
|
||||
$existing = $this->repository->getSpecificRateOnDate($from, $to, $date);
|
||||
if (null !== $existing) {
|
||||
if ($existing instanceof CurrencyExchangeRate) {
|
||||
// update existing rate.
|
||||
$existing = $this->repository->updateExchangeRate($existing, $rate);
|
||||
$collection->push($existing);
|
||||
@@ -98,12 +99,9 @@ class StoreController extends Controller
|
||||
$from = $request->getFromCurrency();
|
||||
$collection = new Collection();
|
||||
foreach ($data['rates'] as $key => $rate) {
|
||||
$to = TransactionCurrency::where('code', $key)->first();
|
||||
if (null === $to) {
|
||||
continue; // should not happen.
|
||||
}
|
||||
$to = Amount::getTransactionCurrencyByCode($key);
|
||||
$existing = $this->repository->getSpecificRateOnDate($from, $to, $date);
|
||||
if (null !== $existing) {
|
||||
if ($existing instanceof CurrencyExchangeRate) {
|
||||
// update existing rate.
|
||||
$existing = $this->repository->updateExchangeRate($existing, $rate);
|
||||
$collection->push($existing);
|
||||
|
@@ -74,7 +74,7 @@ class UpdateController extends Controller
|
||||
public function updateByDate(UpdateRequest $request, TransactionCurrency $from, TransactionCurrency $to, Carbon $date): JsonResponse
|
||||
{
|
||||
$exchangeRate = $this->repository->getSpecificRateOnDate($from, $to, $date);
|
||||
if (null === $exchangeRate) {
|
||||
if (!$exchangeRate instanceof CurrencyExchangeRate) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
$date = $request->getDate();
|
||||
|
@@ -68,10 +68,6 @@ class UpdateController extends Controller
|
||||
$data = $request->getAll();
|
||||
$piggyBank = $this->repository->update($piggyBank, $data);
|
||||
|
||||
if (array_key_exists('current_amount', $data) && '' !== $data['current_amount']) {
|
||||
$this->repository->setCurrentAmount($piggyBank, $data['current_amount']);
|
||||
}
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
|
@@ -75,7 +75,7 @@ class TriggerController extends Controller
|
||||
|
||||
/** @var RuleEngineInterface $ruleEngine */
|
||||
$ruleEngine = app(RuleEngineInterface::class);
|
||||
$ruleEngine->setRules(new Collection([$rule]));
|
||||
$ruleEngine->setRules(new Collection()->push($rule));
|
||||
|
||||
// overrule the rule(s) if necessary.
|
||||
if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
|
||||
@@ -129,7 +129,7 @@ class TriggerController extends Controller
|
||||
|
||||
/** @var RuleEngineInterface $ruleEngine */
|
||||
$ruleEngine = app(RuleEngineInterface::class);
|
||||
$ruleEngine->setRules(new Collection([$rule]));
|
||||
$ruleEngine->setRules(new Collection()->push($rule));
|
||||
|
||||
// overrule the rule(s) if necessary.
|
||||
if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
|
||||
|
@@ -133,7 +133,6 @@ class ConfigurationController extends Controller
|
||||
*/
|
||||
public function show(string $configKey): JsonResponse
|
||||
{
|
||||
$data = [];
|
||||
$dynamic = $this->getDynamicConfiguration();
|
||||
$shortKey = str_replace('configuration.', '', $configKey);
|
||||
if (str_starts_with($configKey, 'configuration.')) {
|
||||
|
@@ -158,18 +158,23 @@ class ShowController extends Controller
|
||||
Log::debug(sprintf('Now in triggerTransaction(%d, %d)', $webhook->id, $group->id));
|
||||
Log::channel('audit')->info(sprintf('User triggers webhook #%d on transaction group #%d.', $webhook->id, $group->id));
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser(auth()->user());
|
||||
|
||||
// tell the generator which trigger it should look for
|
||||
$engine->setTrigger(WebhookTrigger::tryFrom($webhook->trigger));
|
||||
// tell the generator which objects to process
|
||||
$engine->setObjects(new Collection([$group]));
|
||||
// set the webhook to trigger
|
||||
$engine->setWebhooks(new Collection([$webhook]));
|
||||
// tell the generator to generate the messages
|
||||
$engine->generateMessages();
|
||||
/** @var \FireflyIII\Models\WebhookTrigger $trigger */
|
||||
foreach ($webhook->webhookTriggers as $trigger) {
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser(auth()->user());
|
||||
|
||||
// tell the generator which trigger it should look for
|
||||
$engine->setTrigger(WebhookTrigger::tryFrom((int)$trigger->key));
|
||||
// tell the generator which objects to process
|
||||
$engine->setObjects(new Collection()->push($group));
|
||||
// set the webhook to trigger
|
||||
$engine->setWebhooks(new Collection()->push($webhook));
|
||||
// tell the generator to generate the messages
|
||||
$engine->generateMessages();
|
||||
}
|
||||
|
||||
|
||||
// trigger event to send them:
|
||||
Log::debug('send event RequestedSendWebhookMessages from ShowController::triggerTransaction()');
|
||||
|
@@ -46,6 +46,16 @@ class DateRequest extends FormRequest
|
||||
{
|
||||
$start = $this->getCarbonDate('start');
|
||||
$end = $this->getCarbonDate('end');
|
||||
if(null === $start) {
|
||||
$start = now()->startOfMonth();
|
||||
}
|
||||
if(null === $end) {
|
||||
$end = now()->endOfMonth();
|
||||
}
|
||||
// sanity check on dates:
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
|
||||
$start->startOfDay();
|
||||
$end->endOfDay();
|
||||
if ($start->diffInYears($end, true) > 5) {
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Models\Account;
|
||||
|
||||
use Illuminate\Validation\Validator;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Rules\IsValidSortInstruction;
|
||||
@@ -30,7 +31,6 @@ use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Support\Http\Api\AccountFilter;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Validation\Validator;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ShowRequest extends FormRequest
|
||||
|
@@ -48,17 +48,20 @@ class StoreRequest extends FormRequest
|
||||
public function getAll(): array
|
||||
{
|
||||
$fields = [
|
||||
'name' => ['name', 'convertString'],
|
||||
'active' => ['active', 'boolean'],
|
||||
'order' => ['active', 'convertInteger'],
|
||||
'notes' => ['notes', 'convertString'],
|
||||
'name' => ['name', 'convertString'],
|
||||
'active' => ['active', 'boolean'],
|
||||
'order' => ['active', 'convertInteger'],
|
||||
'notes' => ['notes', 'convertString'],
|
||||
|
||||
// auto budget currency:
|
||||
'currency_id' => ['auto_budget_currency_id', 'convertInteger'],
|
||||
'currency_code' => ['auto_budget_currency_code', 'convertString'],
|
||||
'auto_budget_type' => ['auto_budget_type', 'convertString'],
|
||||
'auto_budget_amount' => ['auto_budget_amount', 'convertString'],
|
||||
'auto_budget_period' => ['auto_budget_period', 'convertString'],
|
||||
'currency_id' => ['auto_budget_currency_id', 'convertInteger'],
|
||||
'currency_code' => ['auto_budget_currency_code', 'convertString'],
|
||||
'auto_budget_type' => ['auto_budget_type', 'convertString'],
|
||||
'auto_budget_amount' => ['auto_budget_amount', 'convertString'],
|
||||
'auto_budget_period' => ['auto_budget_period', 'convertString'],
|
||||
|
||||
// webhooks
|
||||
'fire_webhooks' => ['fire_webhooks', 'boolean'],
|
||||
];
|
||||
|
||||
return $this->getAllData($fields);
|
||||
@@ -70,15 +73,18 @@ class StoreRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|min:1|max:255|uniqueObjectForUser:budgets,name',
|
||||
'active' => [new IsBoolean()],
|
||||
'currency_id' => 'exists:transaction_currencies,id',
|
||||
'currency_code' => 'exists:transaction_currencies,code',
|
||||
'notes' => 'nullable|min:1|max:32768',
|
||||
'name' => 'required|min:1|max:255|uniqueObjectForUser:budgets,name',
|
||||
'active' => [new IsBoolean()],
|
||||
'currency_id' => 'exists:transaction_currencies,id',
|
||||
'currency_code' => 'exists:transaction_currencies,code',
|
||||
'notes' => 'nullable|min:1|max:32768',
|
||||
// auto budget info
|
||||
'auto_budget_type' => 'in:reset,rollover,adjusted,none',
|
||||
'auto_budget_amount' => ['required_if:auto_budget_type,reset', 'required_if:auto_budget_type,rollover', 'required_if:auto_budget_type,adjusted', new IsValidPositiveAmount()],
|
||||
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly|required_if:auto_budget_type,reset|required_if:auto_budget_type,rollover|required_if:auto_budget_type,adjusted',
|
||||
'auto_budget_type' => 'in:reset,rollover,adjusted,none',
|
||||
'auto_budget_amount' => ['required_if:auto_budget_type,reset', 'required_if:auto_budget_type,rollover', 'required_if:auto_budget_type,adjusted', new IsValidPositiveAmount()],
|
||||
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly|required_if:auto_budget_type,reset|required_if:auto_budget_type,rollover|required_if:auto_budget_type,adjusted',
|
||||
|
||||
// webhooks
|
||||
'fire_webhooks' => [new IsBoolean()],
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -50,15 +50,18 @@ class UpdateRequest extends FormRequest
|
||||
{
|
||||
// this is the way:
|
||||
$fields = [
|
||||
'name' => ['name', 'convertString'],
|
||||
'active' => ['active', 'boolean'],
|
||||
'order' => ['order', 'convertInteger'],
|
||||
'notes' => ['notes', 'convertString'],
|
||||
'currency_id' => ['auto_budget_currency_id', 'convertInteger'],
|
||||
'currency_code' => ['auto_budget_currency_code', 'convertString'],
|
||||
'auto_budget_type' => ['auto_budget_type', 'convertString'],
|
||||
'auto_budget_amount' => ['auto_budget_amount', 'convertString'],
|
||||
'auto_budget_period' => ['auto_budget_period', 'convertString'],
|
||||
'name' => ['name', 'convertString'],
|
||||
'active' => ['active', 'boolean'],
|
||||
'order' => ['order', 'convertInteger'],
|
||||
'notes' => ['notes', 'convertString'],
|
||||
'currency_id' => ['auto_budget_currency_id', 'convertInteger'],
|
||||
'currency_code' => ['auto_budget_currency_code', 'convertString'],
|
||||
'auto_budget_type' => ['auto_budget_type', 'convertString'],
|
||||
'auto_budget_amount' => ['auto_budget_amount', 'convertString'],
|
||||
'auto_budget_period' => ['auto_budget_period', 'convertString'],
|
||||
|
||||
// webhooks
|
||||
'fire_webhooks' => ['fire_webhooks', 'boolean'],
|
||||
];
|
||||
$allData = $this->getAllData($fields);
|
||||
if (array_key_exists('auto_budget_type', $allData)) {
|
||||
@@ -83,14 +86,17 @@ class UpdateRequest extends FormRequest
|
||||
$budget = $this->route()->parameter('budget');
|
||||
|
||||
return [
|
||||
'name' => sprintf('min:1|max:100|uniqueObjectForUser:budgets,name,%d', $budget->id),
|
||||
'active' => [new IsBoolean()],
|
||||
'notes' => 'nullable|min:1|max:32768',
|
||||
'auto_budget_type' => 'in:reset,rollover,adjusted,none',
|
||||
'auto_budget_currency_id' => 'exists:transaction_currencies,id',
|
||||
'auto_budget_currency_code' => 'exists:transaction_currencies,code',
|
||||
'auto_budget_amount' => ['nullable', new IsValidPositiveAmount()],
|
||||
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly',
|
||||
'name' => sprintf('min:1|max:100|uniqueObjectForUser:budgets,name,%d', $budget->id),
|
||||
'active' => [new IsBoolean()],
|
||||
'notes' => 'nullable|min:1|max:32768',
|
||||
'auto_budget_type' => 'in:reset,rollover,adjusted,none',
|
||||
'auto_budget_currency_id' => 'exists:transaction_currencies,id',
|
||||
'auto_budget_currency_code' => 'exists:transaction_currencies,code',
|
||||
'auto_budget_amount' => ['nullable', new IsValidPositiveAmount()],
|
||||
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly',
|
||||
|
||||
// webhooks
|
||||
'fire_webhooks' => [new IsBoolean()],
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -24,10 +24,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Factory\TransactionCurrencyFactory;
|
||||
use FireflyIII\Rules\IsBoolean;
|
||||
use FireflyIII\Rules\IsValidPositiveAmount;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Class StoreRequest
|
||||
@@ -49,6 +55,9 @@ class StoreRequest extends FormRequest
|
||||
'currency_id' => $this->convertInteger('currency_id'),
|
||||
'currency_code' => $this->convertString('currency_code'),
|
||||
'notes' => $this->stringWithNewlines('notes'),
|
||||
|
||||
// for webhooks:
|
||||
'fire_webhooks' => $this->boolean('fire_webhooks', true),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -58,12 +67,59 @@ class StoreRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'start' => 'required|before:end|date',
|
||||
'end' => 'required|after:start|date',
|
||||
'amount' => ['required', new IsValidPositiveAmount()],
|
||||
'currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
|
||||
'notes' => 'nullable|min:0|max:32768',
|
||||
'start' => 'required|before:end|date',
|
||||
'end' => 'required|after:start|date',
|
||||
'amount' => ['required', new IsValidPositiveAmount()],
|
||||
'currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
|
||||
'notes' => 'nullable|min:0|max:32768',
|
||||
|
||||
// webhooks
|
||||
'fire_webhooks' => [new IsBoolean()],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the validator instance.
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$budget = $this->route()->parameter('budget');
|
||||
$validator->after(
|
||||
static function (Validator $validator) use ($budget): void {
|
||||
if (0 !== count($validator->failed())) {
|
||||
return;
|
||||
}
|
||||
$data = $validator->getData();
|
||||
|
||||
// if no currency has been provided, use the user's default currency:
|
||||
/** @var TransactionCurrencyFactory $factory */
|
||||
$factory = app(TransactionCurrencyFactory::class);
|
||||
$currency = $factory->find($data['currency_id'] ?? null, $data['currency_code'] ?? null);
|
||||
if (null === $currency) {
|
||||
$currency = Amount::getPrimaryCurrency();
|
||||
}
|
||||
$currency->enabled = true;
|
||||
$currency->save();
|
||||
|
||||
// validator already concluded start and end are valid dates:
|
||||
$start = Carbon::parse($data['start'], config('app.timezone'));
|
||||
$end = Carbon::parse($data['end'], config('app.timezone'));
|
||||
|
||||
// find limit with same date range and currency.
|
||||
$limit = $budget->budgetlimits()
|
||||
->where('budget_limits.start_date', $start->format('Y-m-d'))
|
||||
->where('budget_limits.end_date', $end->format('Y-m-d'))
|
||||
->where('budget_limits.transaction_currency_id', $currency->id)
|
||||
->first(['budget_limits.*'])
|
||||
;
|
||||
if (null !== $limit) {
|
||||
$validator->errors()->add('start', trans('validation.limit_exists'));
|
||||
}
|
||||
}
|
||||
);
|
||||
if ($validator->fails()) {
|
||||
Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit;
|
||||
|
||||
use FireflyIII\Rules\IsBoolean;
|
||||
use Illuminate\Validation\Validator;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Rules\IsValidPositiveAmount;
|
||||
@@ -46,12 +47,15 @@ class UpdateRequest extends FormRequest
|
||||
public function getAll(): array
|
||||
{
|
||||
$fields = [
|
||||
'start' => ['start', 'date'],
|
||||
'end' => ['end', 'date'],
|
||||
'amount' => ['amount', 'convertString'],
|
||||
'currency_id' => ['currency_id', 'convertInteger'],
|
||||
'currency_code' => ['currency_code', 'convertString'],
|
||||
'notes' => ['notes', 'stringWithNewlines'],
|
||||
'start' => ['start', 'date'],
|
||||
'end' => ['end', 'date'],
|
||||
'amount' => ['amount', 'convertString'],
|
||||
'currency_id' => ['currency_id', 'convertInteger'],
|
||||
'currency_code' => ['currency_code', 'convertString'],
|
||||
'notes' => ['notes', 'stringWithNewlines'],
|
||||
|
||||
// webhooks
|
||||
'fire_webhooks' => ['fire_webhooks', 'boolean'],
|
||||
];
|
||||
if (false === $this->has('notes')) {
|
||||
// ignore notes, not submitted.
|
||||
@@ -67,12 +71,15 @@ class UpdateRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'start' => 'date|after:1970-01-02|before:2038-01-17',
|
||||
'end' => 'date|after:1970-01-02|before:2038-01-17',
|
||||
'amount' => ['nullable', new IsValidPositiveAmount()],
|
||||
'currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
|
||||
'notes' => 'nullable|min:0|max:32768',
|
||||
'start' => 'date|after:1970-01-02|before:2038-01-17',
|
||||
'end' => 'date|after:1970-01-02|before:2038-01-17',
|
||||
'amount' => ['nullable', new IsValidPositiveAmount()],
|
||||
'currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
|
||||
'notes' => 'nullable|min:0|max:32768',
|
||||
|
||||
// webhooks
|
||||
'fire_webhooks' => [new IsBoolean()],
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -58,8 +58,8 @@ class StoreByCurrenciesRequest extends FormRequest
|
||||
$data = $validator->getData();
|
||||
foreach ($data as $date => $rate) {
|
||||
try {
|
||||
$date = Carbon::createFromFormat('Y-m-d', $date);
|
||||
} catch (InvalidFormatException $e) {
|
||||
Carbon::createFromFormat('Y-m-d', $date);
|
||||
} catch (InvalidFormatException) {
|
||||
$validator->errors()->add('date', trans('validation.date', ['attribute' => 'date']));
|
||||
|
||||
return;
|
||||
|
@@ -24,10 +24,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
|
||||
|
||||
use Illuminate\Validation\Validator;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Validation\Validator;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreByDateRequest extends FormRequest
|
||||
@@ -35,6 +37,9 @@ class StoreByDateRequest extends FormRequest
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return [
|
||||
@@ -45,11 +50,13 @@ class StoreByDateRequest extends FormRequest
|
||||
|
||||
public function getFromCurrency(): TransactionCurrency
|
||||
{
|
||||
return TransactionCurrency::where('code', $this->get('from'))->first();
|
||||
return Amount::getTransactionCurrencyByCode((string)$this->get('from'));
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
@@ -79,8 +86,10 @@ class StoreByDateRequest extends FormRequest
|
||||
|
||||
continue;
|
||||
}
|
||||
$to = TransactionCurrency::where('code', $key)->first();
|
||||
if (null === $to) {
|
||||
|
||||
try {
|
||||
Amount::getTransactionCurrencyByCode((string)$key);
|
||||
} catch (FireflyException) {
|
||||
$validator->errors()->add(sprintf('rates.%s', $key), trans('validation.invalid_currency_code', ['code' => $key]));
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
@@ -42,7 +43,7 @@ class StoreRequest extends FormRequest
|
||||
|
||||
public function getFromCurrency(): TransactionCurrency
|
||||
{
|
||||
return TransactionCurrency::where('code', $this->get('from'))->first();
|
||||
return Amount::getTransactionCurrencyByCode((string) $this->get('from'));
|
||||
}
|
||||
|
||||
public function getRate(): string
|
||||
@@ -52,7 +53,7 @@ class StoreRequest extends FormRequest
|
||||
|
||||
public function getToCurrency(): TransactionCurrency
|
||||
{
|
||||
return TransactionCurrency::where('code', $this->get('to'))->first();
|
||||
return Amount::getTransactionCurrencyByCode((string) $this->get('to'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Requests\Models\PiggyBank;
|
||||
|
||||
use Illuminate\Validation\Validator;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Rules\IsValidZeroOrMoreAmount;
|
||||
@@ -96,7 +97,7 @@ class StoreRequest extends FormRequest
|
||||
// validate start before end only if both are there.
|
||||
$data = $validator->getData();
|
||||
$currency = $this->getCurrencyFromData($validator, $data);
|
||||
if (null === $currency) {
|
||||
if (!$currency instanceof TransactionCurrency) {
|
||||
return;
|
||||
}
|
||||
$targetAmount = (string) ($data['target_amount'] ?? '0');
|
||||
@@ -135,16 +136,10 @@ class StoreRequest extends FormRequest
|
||||
private function getCurrencyFromData(Validator $validator, array $data): ?TransactionCurrency
|
||||
{
|
||||
if (array_key_exists('transaction_currency_code', $data) && '' !== (string) $data['transaction_currency_code']) {
|
||||
$currency = TransactionCurrency::whereCode($data['transaction_currency_code'])->first();
|
||||
if (null !== $currency) {
|
||||
return $currency;
|
||||
}
|
||||
return Amount::getTransactionCurrencyByCode((string) $data['transaction_currency_code']);
|
||||
}
|
||||
if (array_key_exists('transaction_currency_id', $data) && '' !== (string) $data['transaction_currency_id']) {
|
||||
$currency = TransactionCurrency::find((int) $data['transaction_currency_id']);
|
||||
if (null !== $currency) {
|
||||
return $currency;
|
||||
}
|
||||
return Amount::getTransactionCurrencyById((int) $data['transaction_currency_id']);
|
||||
}
|
||||
$validator->errors()->add('transaction_currency_id', trans('validation.require_currency_id_code'));
|
||||
|
||||
|
@@ -183,6 +183,7 @@ class StoreRequest extends FormRequest
|
||||
// basic fields for group:
|
||||
'group_title' => 'min:1|max:1000|nullable',
|
||||
'error_if_duplicate_hash' => [new IsBoolean()],
|
||||
'fire_webhooks' => [new IsBoolean()],
|
||||
'apply_rules' => [new IsBoolean()],
|
||||
|
||||
// location rules
|
||||
|
@@ -64,7 +64,7 @@ class UpdateRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$this->integerFields = ['order', 'currency_id', 'foreign_currency_id', 'transaction_journal_id', 'source_id', 'destination_id', 'budget_id', 'category_id', 'bill_id', 'recurrence_id'];
|
||||
$this->dateFields = ['date', 'interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date'];
|
||||
$this->textareaFields = ['notes'];
|
||||
@@ -97,7 +97,7 @@ class UpdateRequest extends FormRequest
|
||||
*/
|
||||
private function getTransactionData(): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$return = [];
|
||||
|
||||
/** @var null|array $transactions */
|
||||
@@ -181,7 +181,7 @@ class UpdateRequest extends FormRequest
|
||||
private function getDateData(array $current, array $transaction): array
|
||||
{
|
||||
foreach ($this->dateFields as $fieldName) {
|
||||
app('log')->debug(sprintf('Now at date field %s', $fieldName));
|
||||
Log::debug(sprintf('Now at date field %s', $fieldName));
|
||||
if (array_key_exists($fieldName, $transaction)) {
|
||||
Log::debug(sprintf('New value: "%s"', $transaction[$fieldName]));
|
||||
$current[$fieldName] = $this->dateFromValue((string) $transaction[$fieldName]);
|
||||
@@ -247,7 +247,7 @@ class UpdateRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$validProtocols = config('firefly.valid_url_protocols');
|
||||
|
||||
return [
|
||||
@@ -330,7 +330,7 @@ class UpdateRequest extends FormRequest
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
app('log')->debug('Now in withValidator');
|
||||
Log::debug('Now in withValidator');
|
||||
|
||||
/** @var TransactionGroup $transactionGroup */
|
||||
$transactionGroup = $this->route()->parameter('transactionGroup');
|
||||
|
@@ -28,7 +28,6 @@ namespace FireflyIII\Casts;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class SeparateTimezoneCaster
|
||||
|
@@ -29,12 +29,15 @@ use FireflyIII\Enums\AccountTypeEnum;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\AccountFactory;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CorrectsAccountTypes extends Command
|
||||
{
|
||||
@@ -45,6 +48,7 @@ class CorrectsAccountTypes extends Command
|
||||
private int $count;
|
||||
private array $expected;
|
||||
private AccountFactory $factory;
|
||||
private AccountRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
@@ -110,7 +114,7 @@ class CorrectsAccountTypes extends Command
|
||||
if ($resultSet->count() > 0) {
|
||||
$this->friendlyLine(sprintf('Found %d journals that need to be fixed.', $resultSet->count()));
|
||||
foreach ($resultSet as $entry) {
|
||||
app('log')->debug(sprintf('Now fixing journal #%d', $entry->id));
|
||||
Log::debug(sprintf('Now fixing journal #%d', $entry->id));
|
||||
|
||||
/** @var null|TransactionJournal $journal */
|
||||
$journal = TransactionJournal::find($entry->id);
|
||||
@@ -120,7 +124,7 @@ class CorrectsAccountTypes extends Command
|
||||
}
|
||||
}
|
||||
if (0 !== $this->count) {
|
||||
app('log')->debug(sprintf('%d journals had to be fixed.', $this->count));
|
||||
Log::debug(sprintf('%d journals had to be fixed.', $this->count));
|
||||
$this->friendlyInfo(sprintf('Acted on %d transaction(s)', $this->count));
|
||||
}
|
||||
|
||||
@@ -134,10 +138,10 @@ class CorrectsAccountTypes extends Command
|
||||
|
||||
private function inspectJournal(TransactionJournal $journal): void
|
||||
{
|
||||
app('log')->debug(sprintf('Now inspecting journal #%d', $journal->id));
|
||||
Log::debug(sprintf('Now inspecting journal #%d', $journal->id));
|
||||
$transactions = $journal->transactions()->count();
|
||||
if (2 !== $transactions) {
|
||||
app('log')->debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions));
|
||||
Log::debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions));
|
||||
$this->friendlyError(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $transactions));
|
||||
|
||||
return;
|
||||
@@ -151,20 +155,20 @@ class CorrectsAccountTypes extends Command
|
||||
$destAccountType = $destAccount->accountType->type;
|
||||
|
||||
if (!array_key_exists($type, $this->expected)) {
|
||||
app('log')->info(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
$this->friendlyError(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
|
||||
return;
|
||||
}
|
||||
if (!array_key_exists($sourceAccountType, $this->expected[$type])) {
|
||||
app('log')->debug(sprintf('[a] Going to fix journal #%d', $journal->id));
|
||||
Log::debug(sprintf('[a] Going to fix journal #%d', $journal->id));
|
||||
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
|
||||
|
||||
return;
|
||||
}
|
||||
$expectedTypes = $this->expected[$type][$sourceAccountType];
|
||||
if (!in_array($destAccountType, $expectedTypes, true)) {
|
||||
app('log')->debug(sprintf('[b] Going to fix journal #%d', $journal->id));
|
||||
Log::debug(sprintf('[b] Going to fix journal #%d', $journal->id));
|
||||
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
|
||||
}
|
||||
}
|
||||
@@ -181,13 +185,15 @@ class CorrectsAccountTypes extends Command
|
||||
|
||||
private function fixJournal(TransactionJournal $journal, string $transactionType, Transaction $source, Transaction $dest): void
|
||||
{
|
||||
app('log')->debug(sprintf('Going to fix journal #%d', $journal->id));
|
||||
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
$this->repository->setUser($journal->user);
|
||||
++$this->count;
|
||||
// variables:
|
||||
$sourceType = $source->account->accountType->type;
|
||||
$destinationType = $dest->account->accountType->type;
|
||||
$combination = sprintf('%s%s%s', $transactionType, $source->account->accountType->type, $dest->account->accountType->type);
|
||||
app('log')->debug(sprintf('Combination is "%s"', $combination));
|
||||
$sourceType = $source->account->accountType->type;
|
||||
$destinationType = $dest->account->accountType->type;
|
||||
$combination = sprintf('%s%s%s', $transactionType, $source->account->accountType->type, $dest->account->accountType->type);
|
||||
Log::debug(sprintf('Combination is "%s"', $combination));
|
||||
|
||||
if ($this->shouldBeTransfer($transactionType, $sourceType, $destinationType)) {
|
||||
$this->makeTransfer($journal);
|
||||
@@ -211,37 +217,45 @@ class CorrectsAccountTypes extends Command
|
||||
}
|
||||
|
||||
// transaction has no valid source.
|
||||
$validSources = array_keys($this->expected[$transactionType]);
|
||||
$canCreateSource = $this->canCreateSource($validSources);
|
||||
$hasValidSource = $this->hasValidAccountType($validSources, $sourceType);
|
||||
$validSources = array_keys($this->expected[$transactionType]);
|
||||
$canCreateSource = $this->canCreateSource($validSources);
|
||||
$hasValidSource = $this->hasValidAccountType($validSources, $sourceType);
|
||||
if (!$hasValidSource && $canCreateSource) {
|
||||
$this->giveNewRevenue($journal, $source);
|
||||
|
||||
return;
|
||||
}
|
||||
if (!$canCreateSource && !$hasValidSource) {
|
||||
app('log')->debug('This transaction type has no source we can create. Just give error.');
|
||||
Log::debug('This transaction type has no source we can create. Just give error.');
|
||||
$message = sprintf('The source account of %s #%d cannot be of type "%s". Firefly III cannot fix this. You may have to remove the transaction yourself.', $transactionType, $journal->id, $source->account->accountType->type);
|
||||
$this->friendlyError($message);
|
||||
app('log')->debug($message);
|
||||
Log::debug($message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var array $validDestinations */
|
||||
$validDestinations = $this->expected[$transactionType][$sourceType] ?? [];
|
||||
$canCreateDestination = $this->canCreateDestination($validDestinations);
|
||||
$hasValidDestination = $this->hasValidAccountType($validDestinations, $destinationType);
|
||||
$validDestinations = $this->expected[$transactionType][$sourceType] ?? [];
|
||||
$canCreateDestination = $this->canCreateDestination($validDestinations);
|
||||
$hasValidDestination = $this->hasValidAccountType($validDestinations, $destinationType);
|
||||
$alternativeDestination = $this->repository->findByName($dest->account->name, $validDestinations);
|
||||
if (!$hasValidDestination && $canCreateDestination) {
|
||||
$this->giveNewExpense($journal, $dest);
|
||||
|
||||
return;
|
||||
}
|
||||
if (!$canCreateDestination && !$hasValidDestination) {
|
||||
app('log')->debug('This transaction type has no destination we can create. Just give error.');
|
||||
if (!$canCreateDestination && !$hasValidDestination && null === $alternativeDestination) {
|
||||
Log::debug('This transaction type has no destination we can create. Just give error.');
|
||||
$message = sprintf('The destination account of %s #%d cannot be of type "%s". Firefly III cannot fix this. You may have to remove the transaction yourself.', $transactionType, $journal->id, $dest->account->accountType->type);
|
||||
$this->friendlyError($message);
|
||||
app('log')->debug($message);
|
||||
Log::debug($message);
|
||||
}
|
||||
if (!$canCreateDestination && !$hasValidDestination && null !== $alternativeDestination) {
|
||||
Log::debug('This transaction type has no destination we can create, but found alternative with the same name.');
|
||||
$message = sprintf('The destination account of %s #%d cannot be of type "%s". Firefly III found an alternative account. Please make sure this transaction is correct.', $transactionType, $journal->transaction_group_id, $dest->account->accountType->type);
|
||||
$this->friendlyInfo($message);
|
||||
Log::debug($message);
|
||||
$this->giveNewDestinationAccount($journal, $alternativeDestination);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +277,7 @@ class CorrectsAccountTypes extends Command
|
||||
$journal->save();
|
||||
$message = sprintf('Converted transaction #%d from a transfer to a withdrawal.', $journal->id);
|
||||
$this->friendlyInfo($message);
|
||||
app('log')->debug($message);
|
||||
Log::debug($message);
|
||||
// check it again:
|
||||
$this->inspectJournal($journal);
|
||||
}
|
||||
@@ -281,7 +295,7 @@ class CorrectsAccountTypes extends Command
|
||||
$journal->save();
|
||||
$message = sprintf('Converted transaction #%d from a transfer to a deposit.', $journal->id);
|
||||
$this->friendlyInfo($message);
|
||||
app('log')->debug($message);
|
||||
Log::debug($message);
|
||||
// check it again:
|
||||
$this->inspectJournal($journal);
|
||||
}
|
||||
@@ -308,7 +322,7 @@ class CorrectsAccountTypes extends Command
|
||||
$result->name
|
||||
);
|
||||
$this->friendlyWarning($message);
|
||||
app('log')->debug($message);
|
||||
Log::debug($message);
|
||||
$this->inspectJournal($journal);
|
||||
}
|
||||
|
||||
@@ -335,7 +349,7 @@ class CorrectsAccountTypes extends Command
|
||||
$result->name
|
||||
);
|
||||
$this->friendlyWarning($message);
|
||||
app('log')->debug($message);
|
||||
Log::debug($message);
|
||||
$this->inspectJournal($journal);
|
||||
}
|
||||
|
||||
@@ -354,14 +368,14 @@ class CorrectsAccountTypes extends Command
|
||||
|
||||
private function giveNewRevenue(TransactionJournal $journal, Transaction $source): void
|
||||
{
|
||||
app('log')->debug(sprintf('An account of type "%s" could be a valid source.', AccountTypeEnum::REVENUE->value));
|
||||
Log::debug(sprintf('An account of type "%s" could be a valid source.', AccountTypeEnum::REVENUE->value));
|
||||
$this->factory->setUser($journal->user);
|
||||
$name = $source->account->name;
|
||||
$newSource = $this->factory->findOrCreate($name, AccountTypeEnum::REVENUE->value);
|
||||
$source->account()->associate($newSource);
|
||||
$source->save();
|
||||
$this->friendlyPositive(sprintf('Firefly III gave transaction #%d a new source %s: #%d ("%s").', $journal->transaction_group_id, AccountTypeEnum::REVENUE->value, $newSource->id, $newSource->name));
|
||||
app('log')->debug(sprintf('Associated account #%d with transaction #%d', $newSource->id, $source->id));
|
||||
Log::debug(sprintf('Associated account #%d with transaction #%d', $newSource->id, $source->id));
|
||||
$this->inspectJournal($journal);
|
||||
}
|
||||
|
||||
@@ -372,14 +386,33 @@ class CorrectsAccountTypes extends Command
|
||||
|
||||
private function giveNewExpense(TransactionJournal $journal, Transaction $destination): void
|
||||
{
|
||||
app('log')->debug(sprintf('An account of type "%s" could be a valid destination.', AccountTypeEnum::EXPENSE->value));
|
||||
Log::debug(sprintf('An account of type "%s" could be a valid destination.', AccountTypeEnum::EXPENSE->value));
|
||||
$this->factory->setUser($journal->user);
|
||||
$name = $destination->account->name;
|
||||
$newDestination = $this->factory->findOrCreate($name, AccountTypeEnum::EXPENSE->value);
|
||||
$destination->account()->associate($newDestination);
|
||||
$destination->save();
|
||||
$this->friendlyPositive(sprintf('Firefly III gave transaction #%d a new destination %s: #%d ("%s").', $journal->transaction_group_id, AccountTypeEnum::EXPENSE->value, $newDestination->id, $newDestination->name));
|
||||
app('log')->debug(sprintf('Associated account #%d with transaction #%d', $newDestination->id, $destination->id));
|
||||
Log::debug(sprintf('Associated account #%d with transaction #%d', $newDestination->id, $destination->id));
|
||||
$this->inspectJournal($journal);
|
||||
}
|
||||
|
||||
private function giveNewDestinationAccount(TransactionJournal $journal, Account $newDestination): void
|
||||
{
|
||||
$destTransaction = $this->getDestinationTransaction($journal);
|
||||
$oldDest = $destTransaction->account;
|
||||
$destTransaction->account_id = $newDestination->id;
|
||||
$destTransaction->save();
|
||||
$message = sprintf(
|
||||
'Transaction journal #%d, destination account changed from #%d ("%s") to #%d ("%s").',
|
||||
$journal->id,
|
||||
$oldDest->id,
|
||||
$oldDest->name,
|
||||
$newDestination->id,
|
||||
$newDestination->name
|
||||
);
|
||||
$this->friendlyInfo($message);
|
||||
$journal->refresh();
|
||||
Log::debug($message);
|
||||
}
|
||||
}
|
||||
|
@@ -75,7 +75,8 @@ class CorrectsDatabase extends Command
|
||||
'correction:recalculates-liabilities',
|
||||
'correction:preferences',
|
||||
// 'correction:transaction-types', // resource heavy, disabled.
|
||||
'correction:recalculate-pc-amounts', // not necessary, disabled.
|
||||
'correction:recalculate-pc-amounts',
|
||||
'correction:remove-links-to-deleted-objects',
|
||||
'firefly-iii:report-integrity',
|
||||
];
|
||||
foreach ($commands as $command) {
|
||||
|
@@ -57,8 +57,6 @@ class CorrectsPiggyBanks extends Command
|
||||
$event->transaction_journal_id = null;
|
||||
$event->save();
|
||||
++$count;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (0 !== $count) {
|
||||
|
118
app/Console/Commands/Correction/RemovesLinksToDeletedObjects.php
Normal file
118
app/Console/Commands/Correction/RemovesLinksToDeletedObjects.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* RemovesLinksToDeletedObjects.php
|
||||
* Copyright (c) 2025 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\Correction;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class RemovesLinksToDeletedObjects extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'correction:remove-links-to-deleted-objects';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Removes deleted entries from intermediate tables.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$deletedTags = Tag::withTrashed()->whereNotNull('deleted_at')->get('tags.id')->pluck('id')->toArray();
|
||||
$deletedJournals = TransactionJournal::withTrashed()->whereNotNull('deleted_at')->get('transaction_journals.id')->pluck('id')->toArray();
|
||||
$deletedBudgets = Budget::withTrashed()->whereNotNull('deleted_at')->get('budgets.id')->pluck('id')->toArray();
|
||||
$deletedCategories = Category::withTrashed()->whereNotNull('deleted_at')->get('categories.id')->pluck('id')->toArray();
|
||||
|
||||
if (count($deletedTags) > 0) {
|
||||
$this->cleanupTags($deletedTags);
|
||||
}
|
||||
if (count($deletedJournals) > 0) {
|
||||
$this->cleanupJournals($deletedJournals);
|
||||
}
|
||||
if (count($deletedBudgets) > 0) {
|
||||
$this->cleanupBudgets($deletedBudgets);
|
||||
}
|
||||
if (count($deletedCategories) > 0) {
|
||||
$this->cleanupCategories($deletedCategories);
|
||||
}
|
||||
$this->friendlyNeutral('Validated links to deleted objects.');
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function cleanupTags(array $tags): void
|
||||
{
|
||||
$count = DB::table('tag_transaction_journal')->whereIn('tag_id', $tags)->delete();
|
||||
if ($count > 0) {
|
||||
$this->friendlyInfo(sprintf('Removed %d old relationship(s) categories transactions and tags.', $count));
|
||||
}
|
||||
}
|
||||
|
||||
private function cleanupJournals(array $journals): void
|
||||
{
|
||||
$count = DB::table('tag_transaction_journal')->whereIn('transaction_journal_id', $journals)->delete();
|
||||
if ($count > 0) {
|
||||
$this->friendlyInfo(sprintf('Removed %d old relationship(s) between tags and transactions.', $count));
|
||||
}
|
||||
$count = DB::table('budget_transaction_journal')->whereIn('transaction_journal_id', $journals)->delete();
|
||||
if ($count > 0) {
|
||||
$this->friendlyInfo(sprintf('Removed %d old relationship(s) between budgets and transactions.', $count));
|
||||
}
|
||||
$count = DB::table('category_transaction_journal')->whereIn('transaction_journal_id', $journals)->delete();
|
||||
if ($count > 0) {
|
||||
$this->friendlyInfo(sprintf('Removed %d old relationship(s) categories and transactions.', $count));
|
||||
}
|
||||
}
|
||||
|
||||
private function cleanupBudgets(array $budgets): void
|
||||
{
|
||||
$count = DB::table('budget_transaction_journal')->whereIn('budget_id', $budgets)->delete();
|
||||
if ($count > 0) {
|
||||
$this->friendlyInfo(sprintf('Removed %d old relationship(s) between budgets and transactions.', $count));
|
||||
}
|
||||
}
|
||||
|
||||
private function cleanupCategories(array $categories): void
|
||||
{
|
||||
$count = DB::table('category_transaction_journal')->whereIn('category_id', $categories)->delete();
|
||||
if ($count > 0) {
|
||||
$this->friendlyInfo(sprintf('Removed %d old relationship(s) categories categories and transactions.', $count));
|
||||
}
|
||||
}
|
||||
}
|
@@ -71,7 +71,6 @@ class RestoresOAuthKeys extends Command
|
||||
$this->storeKeysInDB();
|
||||
$this->friendlyInfo('Stored OAuth keys in database.');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -515,7 +515,7 @@ class ForcesDecimalSize extends Command
|
||||
continue;
|
||||
}
|
||||
// fix $field by rounding it down correctly.
|
||||
$pow = (float) 10 ** $currency->decimal_places;
|
||||
$pow = 10.0 ** $currency->decimal_places;
|
||||
$correct = bcdiv((string) round((float) $value * $pow), (string) $pow, 12);
|
||||
$this->friendlyWarning(sprintf('Transaction #%d has amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct));
|
||||
|
||||
@@ -546,7 +546,7 @@ class ForcesDecimalSize extends Command
|
||||
continue;
|
||||
}
|
||||
// fix $field by rounding it down correctly.
|
||||
$pow = (float) 10 ** $currency->decimal_places;
|
||||
$pow = 10.0 ** $currency->decimal_places;
|
||||
$correct = bcdiv((string) round((float) $value * $pow), (string) $pow, 12);
|
||||
$this->friendlyWarning(
|
||||
sprintf('Transaction #%d has foreign amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct)
|
||||
|
@@ -26,11 +26,14 @@ namespace FireflyIII\Console\Commands\System;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Support\System\GeneratesInstallationId;
|
||||
use FireflyIII\Support\System\IsOldVersion;
|
||||
use Illuminate\Console\Command;
|
||||
use Random\RandomException;
|
||||
|
||||
class OutputsInstructions extends Command
|
||||
{
|
||||
use GeneratesInstallationId;
|
||||
use IsOldVersion;
|
||||
|
||||
protected $description = 'Instructions in case of upgrade trouble.';
|
||||
|
||||
@@ -57,7 +60,7 @@ class OutputsInstructions extends Command
|
||||
*/
|
||||
private function updateInstructions(): void
|
||||
{
|
||||
$version = (string) config('firefly.version');
|
||||
$version = (string)config('firefly.version');
|
||||
|
||||
/** @var array $config */
|
||||
$config = config('upgrade.text.upgrade');
|
||||
@@ -67,12 +70,12 @@ class OutputsInstructions extends Command
|
||||
foreach (array_keys($config) as $compare) {
|
||||
// if string starts with:
|
||||
if (str_starts_with($version, $compare)) {
|
||||
$text = (string) $config[$compare];
|
||||
$text = (string)$config[$compare];
|
||||
}
|
||||
}
|
||||
|
||||
// validate some settings.
|
||||
if ('' === $text && 'local' === (string) config('app.env')) {
|
||||
if ('' === $text && 'local' === (string)config('app.env')) {
|
||||
$text = 'Please set APP_ENV=production for a safer environment.';
|
||||
}
|
||||
|
||||
@@ -190,7 +193,7 @@ class OutputsInstructions extends Command
|
||||
*/
|
||||
private function installInstructions(): void
|
||||
{
|
||||
$version = (string) config('firefly.version');
|
||||
$version = (string)config('firefly.version');
|
||||
|
||||
/** @var array $config */
|
||||
$config = config('upgrade.text.install');
|
||||
@@ -200,12 +203,12 @@ class OutputsInstructions extends Command
|
||||
foreach (array_keys($config) as $compare) {
|
||||
// if string starts with:
|
||||
if (str_starts_with($version, $compare)) {
|
||||
$text = (string) $config[$compare];
|
||||
$text = (string)$config[$compare];
|
||||
}
|
||||
}
|
||||
|
||||
// validate some settings.
|
||||
if ('' === $text && 'local' === (string) config('app.env')) {
|
||||
if ('' === $text && 'local' === (string)config('app.env')) {
|
||||
$text = 'Please set APP_ENV=production for a safer environment.';
|
||||
}
|
||||
|
||||
@@ -241,14 +244,15 @@ class OutputsInstructions extends Command
|
||||
|
||||
private function someQuote(): void
|
||||
{
|
||||
$lines = [
|
||||
'Forgive yourself for not being at peace.',
|
||||
'Doesn\'t look like anything to me.',
|
||||
'Be proud of what you make.',
|
||||
'Be there or forever wonder.',
|
||||
'A year from now you will wish you had started today.',
|
||||
$lines = [
|
||||
'"Forgive yourself for not being at peace."',
|
||||
'"Doesn\'t look like anything to me."',
|
||||
'"Be proud of what you make."',
|
||||
'"Be there or forever wonder."',
|
||||
'"A year from now you will wish you had started today."',
|
||||
'🇺🇦 Слава Україні!',
|
||||
'🇺🇦 Slava Ukraini!',
|
||||
];
|
||||
$addQuotes = true;
|
||||
|
||||
// fuck the Russian aggression in Ukraine.
|
||||
|
||||
@@ -259,18 +263,16 @@ class OutputsInstructions extends Command
|
||||
// going on, to allow that to happen.
|
||||
|
||||
if ('ru_RU' === config('firefly.default_language')) {
|
||||
$addQuotes = false;
|
||||
$lines = [
|
||||
$lines = [
|
||||
'🇺🇦 Слава Україні!',
|
||||
'🇺🇦 Slava Ukraini!',
|
||||
];
|
||||
}
|
||||
|
||||
$random = random_int(0, count($lines) - 1);
|
||||
if ($addQuotes) {
|
||||
$this->line(sprintf(' "%s"', $lines[$random]));
|
||||
|
||||
return;
|
||||
try {
|
||||
$random = random_int(0, count($lines) - 1);
|
||||
} catch (RandomException) {
|
||||
$random = 0;
|
||||
}
|
||||
$this->line(sprintf(' %s', $lines[$random]));
|
||||
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Console\Commands\System;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class SetsLatestVersion extends Command
|
||||
@@ -45,8 +46,7 @@ class SetsLatestVersion extends Command
|
||||
|
||||
return 0;
|
||||
}
|
||||
app('fireflyconfig')->set('db_version', config('firefly.db_version'));
|
||||
app('fireflyconfig')->set('ff3_version', config('firefly.version'));
|
||||
FireflyConfig::set('ff3_version', config('firefly.version'));
|
||||
$this->friendlyInfo('Updated version.');
|
||||
|
||||
return 0;
|
||||
|
@@ -283,7 +283,7 @@ class ApplyRules extends Command
|
||||
if (null !== $endString && '' !== $endString) {
|
||||
$inputEnd = Carbon::createFromFormat('Y-m-d', $endString);
|
||||
}
|
||||
if (null === $inputEnd || null === $inputStart) {
|
||||
if (!$inputEnd instanceof Carbon || null === $inputStart) {
|
||||
Log::error('Could not parse start or end date in verifyInputDate().');
|
||||
|
||||
return;
|
||||
|
@@ -25,9 +25,11 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Console\Commands\Upgrade;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -65,7 +67,7 @@ class UpgradesCurrencyPreferences extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -104,8 +106,8 @@ class UpgradesCurrencyPreferences extends Command
|
||||
|
||||
private function upgradeUserPreferences(User $user): void
|
||||
{
|
||||
$currencies = TransactionCurrency::get();
|
||||
$enabled = new Collection();
|
||||
$currencies = TransactionCurrency::get();
|
||||
$enabled = new Collection();
|
||||
|
||||
/** @var TransactionCurrency $currency */
|
||||
foreach ($currencies as $currency) {
|
||||
@@ -116,10 +118,11 @@ class UpgradesCurrencyPreferences extends Command
|
||||
$user->currencies()->sync($enabled->pluck('id')->toArray());
|
||||
|
||||
// set the default currency for the user and for the group:
|
||||
$preference = $this->getPreference($user);
|
||||
$primaryCurrency = TransactionCurrency::where('code', $preference)->first();
|
||||
if (null === $primaryCurrency) {
|
||||
// get EUR
|
||||
$preference = $this->getPreference($user);
|
||||
|
||||
try {
|
||||
$primaryCurrency = Amount::getTransactionCurrencyByCode($preference);
|
||||
} catch (FireflyException) {
|
||||
$primaryCurrency = TransactionCurrency::where('code', 'EUR')->first();
|
||||
}
|
||||
$user->currencies()->updateExistingPivot($primaryCurrency->id, ['user_default' => true]);
|
||||
@@ -135,7 +138,7 @@ class UpgradesCurrencyPreferences extends Command
|
||||
}
|
||||
|
||||
if (null !== $preference->data && !is_array($preference->data)) {
|
||||
return (string) $preference->data;
|
||||
return (string)$preference->data;
|
||||
}
|
||||
|
||||
return 'EUR';
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Upgrade;
|
||||
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Safe\Exceptions\InfoException;
|
||||
|
||||
@@ -86,10 +87,8 @@ class UpgradesDatabase extends Command
|
||||
$this->friendlyLine(sprintf('Now executing %s', $command));
|
||||
$this->call($command, $args);
|
||||
}
|
||||
// set new DB version.
|
||||
app('fireflyconfig')->set('db_version', (int) config('firefly.db_version'));
|
||||
// index will set FF3 version.
|
||||
app('fireflyconfig')->set('ff3_version', (string) config('firefly.version'));
|
||||
FireflyConfig::set('ff3_version', (string) config('firefly.version'));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -157,7 +157,6 @@ class UpgradesLiabilitiesEight extends Command
|
||||
$service = new TransactionGroupDestroyService();
|
||||
$service->destroy($group);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -86,6 +86,7 @@ class GracefulNotFoundHandler extends ExceptionHandler
|
||||
return $this->handleAttachment($request, $e);
|
||||
|
||||
case 'bills.show':
|
||||
case 'subscriptions.show':
|
||||
$request->session()->reflash();
|
||||
|
||||
return redirect(route('bills.index'));
|
||||
@@ -128,10 +129,6 @@ class GracefulNotFoundHandler extends ExceptionHandler
|
||||
return redirect(route('categories.index'));
|
||||
|
||||
case 'rules.edit':
|
||||
$request->session()->reflash();
|
||||
|
||||
return redirect(route('rules.index'));
|
||||
|
||||
case 'rule-groups.edit':
|
||||
$request->session()->reflash();
|
||||
|
||||
|
@@ -242,6 +242,7 @@ class PiggyBankFactory
|
||||
}
|
||||
}
|
||||
}
|
||||
Log::debug('Looping all accounts.');
|
||||
|
||||
/** @var array $info */
|
||||
foreach ($accounts as $info) {
|
||||
@@ -251,6 +252,7 @@ class PiggyBankFactory
|
||||
|
||||
continue;
|
||||
}
|
||||
Log::debug(sprintf('Working on account #%d', $account->id));
|
||||
if (array_key_exists('current_amount', $info) && null !== $info['current_amount']) {
|
||||
// an amount is set, first check out if there is a difference with the previous amount.
|
||||
$previous = $toBeLinked[$account->id]['current_amount'] ?? '0';
|
||||
@@ -258,22 +260,24 @@ class PiggyBankFactory
|
||||
|
||||
// create event for difference.
|
||||
if (0 !== bccomp($diff, '0')) {
|
||||
// 2025-10-01 for issue #10990 disable this event.
|
||||
Log::debug(sprintf('[a] Will save event for difference %s (previous value was %s)', $diff, $previous));
|
||||
event(new ChangedAmount($piggyBank, $diff, null, null));
|
||||
// event(new ChangedAmount($piggyBank, $diff, null, null));
|
||||
}
|
||||
|
||||
$toBeLinked[$account->id] = ['current_amount' => $info['current_amount']];
|
||||
Log::debug(sprintf('[a] Will link account #%d with amount %s', $account->id, $info['current_amount']));
|
||||
}
|
||||
if (array_key_exists('current_amount', $info) && null === $info['current_amount']) {
|
||||
// an amount is set, first check out if there is a difference with the previous amount.
|
||||
// no amount is set, first check out if there is a difference with the previous amount.
|
||||
$previous = $toBeLinked[$account->id]['current_amount'] ?? '0';
|
||||
$diff = bcsub('0', $previous);
|
||||
|
||||
// create event for difference.
|
||||
if (0 !== bccomp($diff, '0')) {
|
||||
// 2025-10-01 for issue #10990 disable this event.
|
||||
Log::debug(sprintf('[b] Will save event for difference %s (previous value was %s)', $diff, $previous));
|
||||
event(new ChangedAmount($piggyBank, $diff, null, null));
|
||||
// event(new ChangedAmount($piggyBank, $diff, null, null));
|
||||
}
|
||||
|
||||
// no amount set, use previous amount or go to ZERO.
|
||||
@@ -282,7 +286,8 @@ class PiggyBankFactory
|
||||
|
||||
// create event:
|
||||
Log::debug('linkToAccountIds: Trigger change for positive amount [b].');
|
||||
event(new ChangedAmount($piggyBank, $toBeLinked[$account->id]['current_amount'] ?? '0', null, null));
|
||||
// 2025-10-01 for issue #10990 disable this event.
|
||||
// event(new ChangedAmount($piggyBank, $toBeLinked[$account->id]['current_amount'] ?? '0', null, null));
|
||||
}
|
||||
if (!array_key_exists('current_amount', $info)) {
|
||||
$toBeLinked[$account->id] ??= [];
|
||||
|
@@ -26,7 +26,9 @@ namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class TransactionCurrencyFactory
|
||||
@@ -41,14 +43,14 @@ class TransactionCurrencyFactory
|
||||
$data['code'] = e($data['code']);
|
||||
$data['symbol'] = e($data['symbol']);
|
||||
$data['name'] = e($data['name']);
|
||||
$data['decimal_places'] = (int) $data['decimal_places'];
|
||||
$data['decimal_places'] = (int)$data['decimal_places'];
|
||||
// if the code already exists (deleted)
|
||||
// force delete it and then create the transaction:
|
||||
$count = TransactionCurrency::withTrashed()->whereCode($data['code'])->count();
|
||||
if (1 === $count) {
|
||||
$old = TransactionCurrency::withTrashed()->whereCode($data['code'])->first();
|
||||
$old->forceDelete();
|
||||
app('log')->warning(sprintf('Force deleted old currency with ID #%d and code "%s".', $old->id, $data['code']));
|
||||
Log::warning(sprintf('Force deleted old currency with ID #%d and code "%s".', $old->id, $data['code']));
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -64,8 +66,8 @@ class TransactionCurrencyFactory
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
$result = null;
|
||||
app('log')->error(sprintf('Could not create new currency: %s', $e->getMessage()));
|
||||
app('log')->error($e->getTraceAsString());
|
||||
Log::error(sprintf('Could not create new currency: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
|
||||
throw new FireflyException('400004: Could not store new currency.', 0, $e);
|
||||
}
|
||||
@@ -76,32 +78,33 @@ class TransactionCurrencyFactory
|
||||
public function find(?int $currencyId, ?string $currencyCode): ?TransactionCurrency
|
||||
{
|
||||
$currencyCode = e($currencyCode);
|
||||
$currencyId = (int) $currencyId;
|
||||
$currencyId = (int)$currencyId;
|
||||
$currency = null;
|
||||
|
||||
if ('' === $currencyCode && 0 === $currencyId) {
|
||||
app('log')->debug('Cannot find anything on empty currency code and empty currency ID!');
|
||||
Log::debug('Cannot find anything on empty currency code and empty currency ID!');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// first by ID:
|
||||
if ($currencyId > 0) {
|
||||
$currency = TransactionCurrency::find($currencyId);
|
||||
if (null !== $currency) {
|
||||
return $currency;
|
||||
try {
|
||||
$currency = Amount::getTransactionCurrencyById($currencyId);
|
||||
} catch (FireflyException) {
|
||||
Log::warning(sprintf('Currency ID is #%d but found nothing!', $currencyId));
|
||||
}
|
||||
app('log')->warning(sprintf('Currency ID is %d but found nothing!', $currencyId));
|
||||
}
|
||||
// then by code:
|
||||
if ('' !== $currencyCode) {
|
||||
$currency = TransactionCurrency::whereCode($currencyCode)->first();
|
||||
if (null !== $currency) {
|
||||
return $currency;
|
||||
if ('' !== $currencyCode && null === $currency) {
|
||||
try {
|
||||
$currency = Amount::getTransactionCurrencyByCode($currencyCode);
|
||||
} catch (FireflyException) {
|
||||
Log::warning(sprintf('Currency code is "%s" but found nothing!', $currencyCode));
|
||||
}
|
||||
app('log')->warning(sprintf('Currency code is %d but found nothing!', $currencyCode));
|
||||
}
|
||||
app('log')->warning('Found nothing for currency.');
|
||||
Log::info(sprintf('Found currency #%d based on ID %d and code "%s".', $currency->id, $currencyId, $currencyCode));
|
||||
|
||||
return null;
|
||||
return $currency;
|
||||
}
|
||||
}
|
||||
|
@@ -222,7 +222,7 @@ class TransactionJournalFactory
|
||||
Log::debug('Source info:', $sourceInfo);
|
||||
Log::debug('Destination info:', $destInfo);
|
||||
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
|
||||
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
|
||||
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo, $sourceAccount);
|
||||
Log::debug('Done with getAccount(2x)');
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ class TransactionJournalFactory
|
||||
$negative = $transactionFactory->createNegative((string) $row['amount'], (string) $row['foreign_amount']);
|
||||
} catch (FireflyException $e) {
|
||||
Log::error(sprintf('Exception creating negative transaction: %s', $e->getMessage()));
|
||||
$this->forceDeleteOnError(new Collection([$journal]));
|
||||
$this->forceDeleteOnError(new Collection()->push($journal));
|
||||
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
@@ -305,7 +305,7 @@ class TransactionJournalFactory
|
||||
} catch (FireflyException $e) {
|
||||
Log::error(sprintf('Exception creating positive transaction: %s', $e->getMessage()));
|
||||
$this->forceTrDelete($negative);
|
||||
$this->forceDeleteOnError(new Collection([$journal]));
|
||||
$this->forceDeleteOnError(new Collection()->push($journal));
|
||||
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
|
@@ -132,7 +132,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($this->start, $this->end)->withAccountInformation()
|
||||
$collector->setAccounts(new Collection()->push($account))->setRange($this->start, $this->end)->withAccountInformation()
|
||||
->withBudgetInformation()->withCategoryInformation()->withBillInformation()->withNotes()
|
||||
;
|
||||
$journals = $collector->getExtractedJournals();
|
||||
|
@@ -32,7 +32,6 @@ use FireflyIII\Notifications\Admin\UserInvitation;
|
||||
use FireflyIII\Notifications\Admin\VersionCheckResult;
|
||||
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
|
||||
use FireflyIII\Notifications\Test\OwnerTestNotificationEmail;
|
||||
use FireflyIII\Notifications\Test\OwnerTestNotificationNtfy;
|
||||
use FireflyIII\Notifications\Test\OwnerTestNotificationPushover;
|
||||
use FireflyIII\Notifications\Test\OwnerTestNotificationSlack;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
@@ -52,7 +52,7 @@ class DestroyedGroupEventHandler
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection([$group]));
|
||||
$engine->setObjects(new Collection()->push($group));
|
||||
$engine->setTrigger(WebhookTrigger::DESTROY_TRANSACTION);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
|
@@ -28,6 +28,7 @@ use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\PeriodStatistic\PeriodStatisticRepositoryInterface;
|
||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Support\CreditRecalculateService;
|
||||
use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
|
||||
@@ -36,6 +37,8 @@ use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class StoredGroupEventHandler
|
||||
*
|
||||
* TODO migrate to observer?
|
||||
*/
|
||||
class StoredGroupEventHandler
|
||||
{
|
||||
@@ -44,6 +47,7 @@ class StoredGroupEventHandler
|
||||
$this->processRules($event);
|
||||
$this->recalculateCredit($event);
|
||||
$this->triggerWebhooks($event);
|
||||
$this->removePeriodStatistics($event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,6 +98,26 @@ class StoredGroupEventHandler
|
||||
$object->recalculate();
|
||||
}
|
||||
|
||||
private function removePeriodStatistics(StoredTransactionGroup $event): void
|
||||
{
|
||||
/** @var PeriodStatisticRepositoryInterface $repository */
|
||||
$repository = app(PeriodStatisticRepositoryInterface::class);
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($event->transactionGroup->transactionJournals as $journal) {
|
||||
$source = $journal->transactions()->where('amount', '<', '0')->first();
|
||||
$dest = $journal->transactions()->where('amount', '>', '0')->first();
|
||||
$repository->deleteStatisticsForModel($source->account, $journal->date);
|
||||
$repository->deleteStatisticsForModel($dest->account, $journal->date);
|
||||
foreach ($journal->categories as $category) {
|
||||
$repository->deleteStatisticsForModel($category, $journal->date);
|
||||
}
|
||||
foreach ($journal->tags as $tag) {
|
||||
$repository->deleteStatisticsForModel($tag, $journal->date);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method processes all webhooks that respond to the "stored transaction group" trigger (100)
|
||||
*/
|
||||
@@ -116,7 +140,7 @@ class StoredGroupEventHandler
|
||||
// tell the generator which trigger it should look for
|
||||
$engine->setTrigger(WebhookTrigger::STORE_TRANSACTION);
|
||||
// tell the generator which objects to process
|
||||
$engine->setObjects(new Collection([$group]));
|
||||
$engine->setObjects(new Collection()->push($group));
|
||||
// tell the generator to generate the messages
|
||||
$engine->generateMessages();
|
||||
|
||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\PeriodStatistic\PeriodStatisticRepositoryInterface;
|
||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Support\CreditRecalculateService;
|
||||
use FireflyIII\Support\Models\AccountBalanceCalculator;
|
||||
@@ -49,10 +50,35 @@ class UpdatedGroupEventHandler
|
||||
$this->processRules($event);
|
||||
$this->recalculateCredit($event);
|
||||
$this->triggerWebhooks($event);
|
||||
$this->removePeriodStatistics($event);
|
||||
if ($event->runRecalculations) {
|
||||
$this->updateRunningBalance($event);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO duplicate
|
||||
*/
|
||||
private function removePeriodStatistics(UpdatedTransactionGroup $event): void
|
||||
{
|
||||
/** @var PeriodStatisticRepositoryInterface $repository */
|
||||
$repository = app(PeriodStatisticRepositoryInterface::class);
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($event->transactionGroup->transactionJournals as $journal) {
|
||||
$source = $journal->transactions()->where('amount', '<', '0')->first();
|
||||
$dest = $journal->transactions()->where('amount', '>', '0')->first();
|
||||
$repository->deleteStatisticsForModel($source->account, $journal->date);
|
||||
$repository->deleteStatisticsForModel($dest->account, $journal->date);
|
||||
foreach ($journal->categories as $category) {
|
||||
$repository->deleteStatisticsForModel($category, $journal->date);
|
||||
}
|
||||
foreach ($journal->tags as $tag) {
|
||||
$repository->deleteStatisticsForModel($tag, $journal->date);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,7 +189,7 @@ class UpdatedGroupEventHandler
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection([$group]));
|
||||
$engine->setObjects(new Collection()->push($group));
|
||||
$engine->setTrigger(WebhookTrigger::UPDATE_TRANSACTION);
|
||||
$engine->generateMessages();
|
||||
|
||||
|
@@ -44,7 +44,6 @@ use FireflyIII\Models\UserRole;
|
||||
use FireflyIII\Notifications\Admin\UserRegistration as AdminRegistrationNotification;
|
||||
use FireflyIII\Notifications\Security\UserFailedLoginAttempt;
|
||||
use FireflyIII\Notifications\Test\UserTestNotificationEmail;
|
||||
use FireflyIII\Notifications\Test\UserTestNotificationNtfy;
|
||||
use FireflyIII\Notifications\Test\UserTestNotificationPushover;
|
||||
use FireflyIII\Notifications\Test\UserTestNotificationSlack;
|
||||
use FireflyIII\Notifications\User\UserLogin;
|
||||
|
@@ -62,5 +62,8 @@ class WebhookEventHandler
|
||||
Log::debug(sprintf('Skip message #%d', $message->id));
|
||||
}
|
||||
}
|
||||
|
||||
// clean up sent messages table:
|
||||
WebhookMessage::where('webhook_messages.sent', true)->where('webhook_messages.created_at', '<', now()->subDays(30))->delete();
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\Support\Observers\RecalculatesAvailableBudgetsTrait;
|
||||
use FireflyIII\Support\Singleton\PreferencesSingleton;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@@ -44,17 +45,24 @@ class BudgetLimitObserver
|
||||
$this->updatePrimaryCurrencyAmount($budgetLimit);
|
||||
$this->updateAvailableBudget($budgetLimit);
|
||||
|
||||
$user = $budgetLimit->budget->user;
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budgetLimit));
|
||||
$engine->setTrigger(WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT);
|
||||
$engine->generateMessages();
|
||||
// this is a lame trick to communicate with the observer.
|
||||
$singleton = PreferencesSingleton::getInstance();
|
||||
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
if (true === $singleton->getPreference('fire_webhooks_bl_store')) {
|
||||
|
||||
$user = $budgetLimit->budget->user;
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budgetLimit));
|
||||
$engine->setTrigger(WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT);
|
||||
$engine->generateMessages();
|
||||
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
}
|
||||
}
|
||||
|
||||
private function updatePrimaryCurrencyAmount(BudgetLimit $budgetLimit): void
|
||||
@@ -82,16 +90,21 @@ class BudgetLimitObserver
|
||||
$this->updatePrimaryCurrencyAmount($budgetLimit);
|
||||
$this->updateAvailableBudget($budgetLimit);
|
||||
|
||||
$user = $budgetLimit->budget->user;
|
||||
// this is a lame trick to communicate with the observer.
|
||||
$singleton = PreferencesSingleton::getInstance();
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budgetLimit));
|
||||
$engine->setTrigger(WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT);
|
||||
$engine->generateMessages();
|
||||
if (true === $singleton->getPreference('fire_webhooks_bl_update')) {
|
||||
$user = $budgetLimit->budget->user;
|
||||
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budgetLimit));
|
||||
$engine->setTrigger(WebhookTrigger::STORE_UPDATE_BUDGET_LIMIT);
|
||||
$engine->generateMessages();
|
||||
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||
use FireflyIII\Support\Observers\RecalculatesAvailableBudgetsTrait;
|
||||
use FireflyIII\Support\Singleton\PreferencesSingleton;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@@ -45,32 +46,43 @@ class BudgetObserver
|
||||
{
|
||||
Log::debug(sprintf('Observe "created" of budget #%d ("%s").', $budget->id, $budget->name));
|
||||
|
||||
// fire event.
|
||||
$user = $budget->user;
|
||||
// this is a lame trick to communicate with the observer.
|
||||
$singleton = PreferencesSingleton::getInstance();
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budget));
|
||||
$engine->setTrigger(WebhookTrigger::STORE_BUDGET);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
if (true === $singleton->getPreference('fire_webhooks_budget_create')) {
|
||||
// fire event.
|
||||
$user = $budget->user;
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budget));
|
||||
$engine->setTrigger(WebhookTrigger::STORE_BUDGET);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
}
|
||||
}
|
||||
|
||||
public function updated(Budget $budget): void
|
||||
{
|
||||
Log::debug(sprintf('Observe "updated" of budget #%d ("%s").', $budget->id, $budget->name));
|
||||
$user = $budget->user;
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budget));
|
||||
$engine->setTrigger(WebhookTrigger::UPDATE_BUDGET);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
// this is a lame trick to communicate with the observer.
|
||||
$singleton = PreferencesSingleton::getInstance();
|
||||
|
||||
if (true === $singleton->getPreference('fire_webhooks_budget_update')) {
|
||||
$user = $budget->user;
|
||||
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser($user);
|
||||
$engine->setObjects(new Collection()->push($budget));
|
||||
$engine->setTrigger(WebhookTrigger::UPDATE_BUDGET);
|
||||
$engine->generateMessages();
|
||||
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));
|
||||
event(new RequestedSendWebhookMessages());
|
||||
}
|
||||
}
|
||||
|
||||
public function deleting(Budget $budget): void
|
||||
|
@@ -94,7 +94,7 @@ trait AttachmentCollection
|
||||
static function (EloquentBuilder $q1): void { // @phpstan-ignore-line
|
||||
$q1->where('attachments.attachable_type', TransactionJournal::class);
|
||||
// $q1->where('attachments.uploaded', true);
|
||||
$q1->whereNull('attachments.deleted_at');
|
||||
// $q1->whereNull('attachments.deleted_at');
|
||||
$q1->orWhereNull('attachments.attachable_type');
|
||||
}
|
||||
)
|
||||
@@ -107,6 +107,7 @@ trait AttachmentCollection
|
||||
$this->fields[] = 'attachments.id as attachment_id';
|
||||
$this->fields[] = 'attachments.filename as attachment_filename';
|
||||
$this->fields[] = 'attachments.title as attachment_title';
|
||||
$this->fields[] = 'attachments.deleted_at as attachment_deleted_at';
|
||||
$this->fields[] = 'attachments.uploaded as attachment_uploaded';
|
||||
$this->joinAttachmentTables();
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collector\Extensions;
|
||||
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Budget;
|
||||
@@ -597,16 +598,16 @@ trait MetaCollection
|
||||
$foundTagCount = 0;
|
||||
foreach ($object['transactions'] as $transaction) {
|
||||
$transactionTagCount = count($transaction['tags']);
|
||||
app('log')->debug(sprintf('Transaction #%d has %d tag(s)', $transaction['transaction_journal_id'], $transactionTagCount));
|
||||
Log::debug(sprintf('Transaction #%d has %d tag(s)', $transaction['transaction_journal_id'], $transactionTagCount));
|
||||
if ($transactionTagCount < $expectedTagCount) {
|
||||
app('log')->debug(sprintf('Transaction has %d tag(s), we expect %d tag(s), return false.', $transactionTagCount, $expectedTagCount));
|
||||
Log::debug(sprintf('Transaction has %d tag(s), we expect %d tag(s), return false.', $transactionTagCount, $expectedTagCount));
|
||||
|
||||
return false;
|
||||
}
|
||||
foreach ($transaction['tags'] as $tag) {
|
||||
Log::debug(sprintf('"%s" versus', strtolower((string) $tag['name'])), $list);
|
||||
if (in_array(strtolower((string) $tag['name']), $list, true)) {
|
||||
app('log')->debug(sprintf('Transaction has tag "%s" so count++.', $tag['name']));
|
||||
Log::debug(sprintf('Transaction has tag "%s" so count++.', $tag['name']));
|
||||
++$foundTagCount;
|
||||
$journalId = $transaction['transaction_journal_id'];
|
||||
// #8377 prevent adding a transaction twice when multiple tag searches find this transaction
|
||||
@@ -761,7 +762,7 @@ trait MetaCollection
|
||||
public function setTag(Tag $tag): GroupCollectorInterface
|
||||
{
|
||||
$this->withTagInformation();
|
||||
$this->setTags(new Collection([$tag]));
|
||||
$this->setTags(new Collection()->push($tag));
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -775,6 +776,9 @@ trait MetaCollection
|
||||
$this->withTagInformation();
|
||||
$this->query->whereNotNull('tag_transaction_journal.tag_id');
|
||||
|
||||
// Added this while fixing #10898, not sure why a post filter was ever necessary.
|
||||
$this->query->whereIn('tag_transaction_journal.tag_id', $tags->pluck('id')->toArray());
|
||||
|
||||
// this method adds a "postFilter" to the collector.
|
||||
$list = $tags->pluck('tag')->toArray();
|
||||
$list = array_map('strtolower', $list);
|
||||
@@ -784,13 +788,13 @@ trait MetaCollection
|
||||
foreach ($transaction['tags'] as $tag) {
|
||||
Log::debug(sprintf('"%s" versus', strtolower((string) $tag['name'])), $list);
|
||||
if (in_array(strtolower((string) $tag['name']), $list, true)) {
|
||||
app('log')->debug(sprintf('Transaction has tag "%s" so return true.', $tag['name']));
|
||||
Log::debug(sprintf('Transaction has tag "%s" so return true.', $tag['name']));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
app('log')->debug('Transaction has no tags from the list, so return false.');
|
||||
Log::debug('Transaction has no tags from the list, so return false.');
|
||||
|
||||
return false;
|
||||
};
|
||||
@@ -812,11 +816,11 @@ trait MetaCollection
|
||||
$filter = static function (array $object) use ($list): bool {
|
||||
Log::debug(sprintf('Now in setWithoutSpecificTags(%s) filter', implode(', ', $list)));
|
||||
foreach ($object['transactions'] as $transaction) {
|
||||
app('log')->debug(sprintf('Transaction has %d tag(s)', count($transaction['tags'])));
|
||||
Log::debug(sprintf('Transaction has %d tag(s)', count($transaction['tags'])));
|
||||
foreach ($transaction['tags'] as $tag) {
|
||||
Log::debug(sprintf('"%s" versus', strtolower((string) $tag['name'])), $list);
|
||||
if (in_array(strtolower((string) $tag['name']), $list, true)) {
|
||||
app('log')->debug(sprintf('Transaction has tag "%s", but should not have it, return false.', $tag['name']));
|
||||
Log::debug(sprintf('Transaction has tag "%s", but should not have it, return false.', $tag['name']));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -919,6 +923,8 @@ trait MetaCollection
|
||||
{
|
||||
$this->withCategoryInformation();
|
||||
$this->query->whereNull('category_transaction_journal.category_id');
|
||||
// better fix for #10507
|
||||
$this->query->whereNotIn('transaction_types.type', [TransactionTypeEnum::OPENING_BALANCE->value]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Helpers\Collector;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Carbon\Exceptions\InvalidFormatException;
|
||||
use Closure;
|
||||
use Exception;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
@@ -45,7 +46,6 @@ use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Closure;
|
||||
use Override;
|
||||
|
||||
use function Safe\json_decode;
|
||||
@@ -303,7 +303,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
foreach ($params as $param) {
|
||||
$replace = sprintf('"%s"', $param);
|
||||
if (is_int($param)) {
|
||||
$replace = (string) $param;
|
||||
$replace = (string)$param;
|
||||
}
|
||||
$pos = strpos($query, '?');
|
||||
if (false !== $pos) {
|
||||
@@ -518,13 +518,13 @@ class GroupCollector implements GroupCollectorInterface
|
||||
|
||||
/** @var TransactionJournal $augumentedJournal */
|
||||
foreach ($collection as $augumentedJournal) {
|
||||
$groupId = (int) $augumentedJournal->transaction_group_id;
|
||||
$groupId = (int)$augumentedJournal->transaction_group_id;
|
||||
|
||||
if (!array_key_exists($groupId, $groups)) {
|
||||
// make new array
|
||||
$parsedGroup = $this->parseAugmentedJournal($augumentedJournal);
|
||||
$groupArray = [
|
||||
'id' => (int) $augumentedJournal->transaction_group_id,
|
||||
'id' => (int)$augumentedJournal->transaction_group_id,
|
||||
'user_id' => $augumentedJournal->user_id,
|
||||
'user_group_id' => $augumentedJournal->user_group_id,
|
||||
// Field transaction_group_title was added by the query.
|
||||
@@ -537,7 +537,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
'transactions' => [],
|
||||
];
|
||||
// Field transaction_journal_id was added by the query.
|
||||
$journalId = (int) $augumentedJournal->transaction_journal_id;
|
||||
$journalId = (int)$augumentedJournal->transaction_journal_id;
|
||||
$groupArray['transactions'][$journalId] = $parsedGroup;
|
||||
$groups[$groupId] = $groupArray;
|
||||
|
||||
@@ -545,7 +545,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
}
|
||||
// or parse the rest.
|
||||
// Field transaction_journal_id was added by the query.
|
||||
$journalId = (int) $augumentedJournal->transaction_journal_id;
|
||||
$journalId = (int)$augumentedJournal->transaction_journal_id;
|
||||
if (array_key_exists($journalId, $groups[$groupId]['transactions'])) {
|
||||
// append data to existing group + journal (for multiple tags or multiple attachments)
|
||||
$groups[$groupId]['transactions'][$journalId] = $this->mergeTags($groups[$groupId]['transactions'][$journalId], $augumentedJournal);
|
||||
@@ -560,7 +560,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
}
|
||||
$groups = $this->parseSums($groups);
|
||||
|
||||
return new Collection($groups);
|
||||
return new Collection()->push(...$groups);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -597,8 +597,8 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$dates = ['interest_date', 'payment_date', 'invoice_date', 'book_date', 'due_date', 'process_date'];
|
||||
if (array_key_exists('meta_name', $result) && in_array($result['meta_name'], $dates, true)) {
|
||||
$name = $result['meta_name'];
|
||||
if (array_key_exists('meta_data', $result) && '' !== (string) $result['meta_data']) {
|
||||
$result[$name] = Carbon::createFromFormat('!Y-m-d', substr((string) json_decode((string) $result['meta_data']), 0, 10));
|
||||
if (array_key_exists('meta_data', $result) && '' !== (string)$result['meta_data']) {
|
||||
$result[$name] = Carbon::createFromFormat('!Y-m-d', substr((string)json_decode((string)$result['meta_data']), 0, 10));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,9 +611,9 @@ class GroupCollector implements GroupCollectorInterface
|
||||
// convert back to strings because SQLite is dumb like that.
|
||||
$result = $this->convertToStrings($result);
|
||||
|
||||
$result['reconciled'] = 1 === (int) $result['reconciled'];
|
||||
$result['reconciled'] = 1 === (int)$result['reconciled'];
|
||||
if (array_key_exists('tag_id', $result) && null !== $result['tag_id']) { // assume the other fields are present as well.
|
||||
$tagId = (int) $augumentedJournal['tag_id'];
|
||||
$tagId = (int)$augumentedJournal['tag_id'];
|
||||
$tagDate = null;
|
||||
|
||||
try {
|
||||
@@ -623,7 +623,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
}
|
||||
|
||||
$result['tags'][$tagId] = [
|
||||
'id' => (int) $result['tag_id'],
|
||||
'id' => (int)$result['tag_id'],
|
||||
'name' => $result['tag_name'],
|
||||
'date' => $tagDate,
|
||||
'description' => $result['tag_description'],
|
||||
@@ -631,10 +631,11 @@ class GroupCollector implements GroupCollectorInterface
|
||||
}
|
||||
|
||||
// also merge attachments:
|
||||
if (array_key_exists('attachment_id', $result)) {
|
||||
$uploaded = 1 === (int) $result['attachment_uploaded'];
|
||||
$attachmentId = (int) $augumentedJournal['attachment_id'];
|
||||
if (0 !== $attachmentId && $uploaded) {
|
||||
if (array_key_exists('attachment_id', $result) && null !== $result['attachment_id']) {
|
||||
$uploaded = 1 === (int)$result['attachment_uploaded'];
|
||||
$attachmentId = (int)$augumentedJournal['attachment_id'];
|
||||
$deleted = null !== $result['attachment_deleted_at'];
|
||||
if (0 !== $attachmentId && $uploaded && !$deleted) {
|
||||
$result['attachments'][$attachmentId] = [
|
||||
'id' => $attachmentId,
|
||||
'filename' => $augumentedJournal['attachment_filename'],
|
||||
@@ -659,7 +660,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
private function convertToInteger(array $array): array
|
||||
{
|
||||
foreach ($this->integerFields as $field) {
|
||||
$array[$field] = array_key_exists($field, $array) ? (int) $array[$field] : null;
|
||||
$array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (int)$array[$field] : null;
|
||||
}
|
||||
|
||||
return $array;
|
||||
@@ -668,7 +669,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
private function convertToBoolean(array $array): array
|
||||
{
|
||||
foreach ($this->booleanFields as $field) {
|
||||
$array[$field] = array_key_exists($field, $array) ? (bool) $array[$field] : null;
|
||||
$array[$field] = array_key_exists($field, $array) ? (bool)$array[$field] : null;
|
||||
}
|
||||
|
||||
return $array;
|
||||
@@ -677,7 +678,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
private function convertToStrings(array $array): array
|
||||
{
|
||||
foreach ($this->stringFields as $field) {
|
||||
$array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (string) $array[$field] : null;
|
||||
$array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (string)$array[$field] : null;
|
||||
}
|
||||
|
||||
return $array;
|
||||
@@ -687,7 +688,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
{
|
||||
$newArray = $newJournal->toArray();
|
||||
if (array_key_exists('tag_id', $newArray)) { // assume the other fields are present as well.
|
||||
$tagId = (int) $newJournal['tag_id'];
|
||||
$tagId = (int)$newJournal['tag_id'];
|
||||
|
||||
$tagDate = null;
|
||||
|
||||
@@ -698,7 +699,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
}
|
||||
|
||||
$existingJournal['tags'][$tagId] = [
|
||||
'id' => (int) $newArray['tag_id'],
|
||||
'id' => (int)$newArray['tag_id'],
|
||||
'name' => $newArray['tag_name'],
|
||||
'date' => $tagDate,
|
||||
'description' => $newArray['tag_description'],
|
||||
@@ -712,7 +713,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
{
|
||||
$newArray = $newJournal->toArray();
|
||||
if (array_key_exists('attachment_id', $newArray)) {
|
||||
$attachmentId = (int) $newJournal['attachment_id'];
|
||||
$attachmentId = (int)$newJournal['attachment_id'];
|
||||
|
||||
$existingJournal['attachments'][$attachmentId] = [
|
||||
'id' => $attachmentId,
|
||||
@@ -731,13 +732,13 @@ class GroupCollector implements GroupCollectorInterface
|
||||
foreach ($groups as $groudId => $group) {
|
||||
/** @var array $transaction */
|
||||
foreach ($group['transactions'] as $transaction) {
|
||||
$currencyId = (int) $transaction['currency_id'];
|
||||
$currencyId = (int)$transaction['currency_id'];
|
||||
if (null === $transaction['amount']) {
|
||||
throw new FireflyException(sprintf('Amount is NULL for a transaction in group #%d, please investigate.', $groudId));
|
||||
}
|
||||
$pcAmount = (string) ('' === $transaction['pc_amount'] ? '0' : $transaction['pc_amount']);
|
||||
$pcForeignAmount = (string) ('' === $transaction['pc_foreign_amount'] ? '0' : $transaction['pc_foreign_amount']);
|
||||
$foreignAmount = (string) ('' === $transaction['foreign_amount'] ? '0' : $transaction['foreign_amount']);
|
||||
$pcAmount = (string)('' === $transaction['pc_amount'] ? '0' : $transaction['pc_amount']);
|
||||
$pcForeignAmount = (string)('' === $transaction['pc_foreign_amount'] ? '0' : $transaction['pc_foreign_amount']);
|
||||
$foreignAmount = (string)('' === $transaction['foreign_amount'] ? '0' : $transaction['foreign_amount']);
|
||||
|
||||
// set default:
|
||||
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
|
||||
@@ -748,11 +749,11 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
|
||||
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = '0';
|
||||
}
|
||||
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd((string) $groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount']);
|
||||
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = bcadd((string) $groups[$groudId]['sums'][$currencyId]['pc_amount'], $pcAmount);
|
||||
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd((string)$groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount']);
|
||||
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = bcadd((string)$groups[$groudId]['sums'][$currencyId]['pc_amount'], $pcAmount);
|
||||
|
||||
if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) {
|
||||
$currencyId = (int) $transaction['foreign_currency_id'];
|
||||
$currencyId = (int)$transaction['foreign_currency_id'];
|
||||
|
||||
// set default:
|
||||
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
|
||||
@@ -763,7 +764,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
|
||||
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = '0';
|
||||
}
|
||||
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd((string) $groups[$groudId]['sums'][$currencyId]['amount'], $foreignAmount);
|
||||
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd((string)$groups[$groudId]['sums'][$currencyId]['amount'], $foreignAmount);
|
||||
$groups[$groudId]['sums'][$currencyId]['pc_amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $pcForeignAmount);
|
||||
}
|
||||
}
|
||||
@@ -1095,10 +1096,6 @@ class GroupCollector implements GroupCollectorInterface
|
||||
->whereNull('transaction_groups.deleted_at')
|
||||
->whereNull('transaction_journals.deleted_at')
|
||||
->whereNull('source.deleted_at')
|
||||
|
||||
// #10507 ignore opening balance.
|
||||
->where('transaction_types.type', '!=', TransactionTypeEnum::OPENING_BALANCE->value)
|
||||
|
||||
->whereNotNull('transaction_groups.id')
|
||||
->whereNull('destination.deleted_at')
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
|
@@ -31,7 +31,6 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
@@ -49,7 +48,6 @@ use Illuminate\Support\Facades\Log;
|
||||
class NetWorth implements NetWorthInterface
|
||||
{
|
||||
private AccountRepositoryInterface $accountRepository;
|
||||
private CurrencyRepositoryInterface $currencyRepos;
|
||||
private User $user; // @phpstan-ignore-line
|
||||
private ?UserGroup $userGroup = null;
|
||||
|
||||
@@ -131,8 +129,6 @@ class NetWorth implements NetWorthInterface
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
$this->accountRepository->setUserGroup($userGroup);
|
||||
|
||||
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
$this->currencyRepos->setUserGroup($this->userGroup);
|
||||
}
|
||||
|
||||
#[Deprecated]
|
||||
|
@@ -45,7 +45,7 @@ class PopupReport implements PopupReportInterface
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))
|
||||
$collector->setAccounts(new Collection()->push($account))
|
||||
->withAccountInformation()
|
||||
->withBudgetInformation()
|
||||
->withCategoryInformation()
|
||||
@@ -72,7 +72,7 @@ class PopupReport implements PopupReportInterface
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setAccounts(new Collection()->push($account))
|
||||
->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
|
||||
->withAccountInformation()
|
||||
->withCategoryInformation()
|
||||
@@ -191,7 +191,7 @@ class PopupReport implements PopupReportInterface
|
||||
// $set = $attributes['accounts'] ?? new Collection;
|
||||
// $set->push($account);
|
||||
|
||||
$collector->setDestinationAccounts(new Collection([$account]))
|
||||
$collector->setDestinationAccounts(new Collection()->push($account))
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->withAccountInformation()
|
||||
->withBudgetInformation()
|
||||
@@ -218,7 +218,7 @@ class PopupReport implements PopupReportInterface
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setSourceAccounts(new Collection([$account]))
|
||||
->setSourceAccounts(new Collection()->push($account))
|
||||
->setDestinationAccounts($attributes['accounts'])
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->setTypes([TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::TRANSFER->value])
|
||||
|
@@ -86,7 +86,7 @@ class CreateController extends Controller
|
||||
'latitude' => $hasOldInput ? old('location_latitude') : config('firefly.default_location.latitude'),
|
||||
'longitude' => $hasOldInput ? old('location_longitude') : config('firefly.default_location.longitude'),
|
||||
'zoom_level' => $hasOldInput ? old('location_zoom_level') : config('firefly.default_location.zoom_level'),
|
||||
'has_location' => $hasOldInput ? 'true' === old('location_has_location') : false,
|
||||
'has_location' => $hasOldInput && 'true' === old('location_has_location'),
|
||||
],
|
||||
];
|
||||
$liabilityDirections = [
|
||||
@@ -106,7 +106,7 @@ class CreateController extends Controller
|
||||
'preFilled',
|
||||
[
|
||||
'currency_id' => $this->primaryCurrency->id,
|
||||
'include_net_worth' => $hasOldInput ? (bool) $request->old('include_net_worth') : true,
|
||||
'include_net_worth' => !$hasOldInput || (bool)$request->old('include_net_worth'),
|
||||
]
|
||||
);
|
||||
// issue #8321
|
||||
|
@@ -102,7 +102,7 @@ class ShowController extends Controller
|
||||
|
||||
// make sure dates are end of day and start of day:
|
||||
$start->startOfDay();
|
||||
$end->endOfDay();
|
||||
$end->endOfDay()->milli(0);
|
||||
|
||||
$location = $this->repository->getLocation($account);
|
||||
$attachments = $this->repository->getAttachments($account);
|
||||
@@ -143,7 +143,7 @@ class ShowController extends Controller
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setAccounts(new Collection()->push($account))
|
||||
->setLimit($pageSize)
|
||||
->setPage($page)
|
||||
->withAttachmentInformation()
|
||||
@@ -221,7 +221,7 @@ class ShowController extends Controller
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation();
|
||||
$collector->setAccounts(new Collection()->push($account))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation();
|
||||
|
||||
// this search will not include transaction groups where this asset account (or liability)
|
||||
// is just part of ONE of the journals. To force this:
|
||||
|
@@ -122,6 +122,11 @@ class NotificationController extends Controller
|
||||
|
||||
public function testNotification(Request $request): RedirectResponse
|
||||
{
|
||||
if (true === auth()->user()->hasRole('demo')) {
|
||||
session()->flash('error', (string) trans('firefly.not_available_demo_user'));
|
||||
|
||||
return redirect(route('settings.notification.index'));
|
||||
}
|
||||
|
||||
$all = $request->all();
|
||||
$channel = $all['test_submit'] ?? '';
|
||||
|
@@ -27,6 +27,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Update\UpdateTrait;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -66,8 +67,8 @@ class UpdateController extends Controller
|
||||
{
|
||||
$subTitle = (string) trans('firefly.update_check_title');
|
||||
$subTitleIcon = 'fa-star';
|
||||
$permission = app('fireflyconfig')->get('permission_update_check', -1);
|
||||
$channel = app('fireflyconfig')->get('update_channel', 'stable');
|
||||
$permission = FireflyConfig::get('permission_update_check', -1);
|
||||
$channel = FireflyConfig::get('update_channel', 'stable');
|
||||
$selected = $permission->data;
|
||||
$channelSelected = $channel->data;
|
||||
$options = [
|
||||
@@ -96,9 +97,9 @@ class UpdateController extends Controller
|
||||
$channel = $request->get('update_channel');
|
||||
$channel = in_array($channel, ['stable', 'beta', 'alpha'], true) ? $channel : 'stable';
|
||||
|
||||
app('fireflyconfig')->set('permission_update_check', $checkForUpdates);
|
||||
app('fireflyconfig')->set('last_update_check', Carbon::now()->getTimestamp());
|
||||
app('fireflyconfig')->set('update_channel', $channel);
|
||||
FireflyConfig::set('permission_update_check', $checkForUpdates);
|
||||
FireflyConfig::set('last_update_check', Carbon::now()->getTimestamp());
|
||||
FireflyConfig::set('update_channel', $channel);
|
||||
session()->flash('success', (string) trans('firefly.configuration_updated'));
|
||||
|
||||
return redirect(route('settings.update-check'));
|
||||
|
@@ -203,7 +203,7 @@ class BudgetLimitController extends Controller
|
||||
if ($request->expectsJson()) {
|
||||
$array = $limit->toArray();
|
||||
// add some extra metadata:
|
||||
$spentArr = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection([$budget]), $currency);
|
||||
$spentArr = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection()->push($budget), $currency);
|
||||
$array['spent'] = $spentArr[$currency->id]['sum'] ?? '0';
|
||||
$array['left_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, bcadd($array['spent'], (string) $array['amount']));
|
||||
$array['amount_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, $limit['amount']);
|
||||
@@ -264,7 +264,7 @@ class BudgetLimitController extends Controller
|
||||
$limit->start_date,
|
||||
$limit->end_date,
|
||||
null,
|
||||
new Collection([$budgetLimit->budget]),
|
||||
new Collection()->push($budgetLimit->budget),
|
||||
$budgetLimit->transactionCurrency
|
||||
);
|
||||
$daysLeft = $this->activeDaysLeft($limit->start_date, $limit->end_date);
|
||||
|
@@ -235,7 +235,7 @@ class IndexController extends Controller
|
||||
|
||||
/** @var TransactionCurrency $currency */
|
||||
foreach ($currencies as $currency) {
|
||||
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$current]), $currency, false);
|
||||
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, new Collection()->push($current), $currency, false);
|
||||
if (array_key_exists($currency->id, $spentArr) && array_key_exists('sum', $spentArr[$currency->id])) {
|
||||
$array['spent'][$currency->id]['spent'] = $spentArr[$currency->id]['sum'];
|
||||
$array['spent'][$currency->id]['currency_id'] = $currency->id;
|
||||
|
@@ -92,7 +92,7 @@ class ShowController extends Controller
|
||||
// get first journal ever to set off the budget period overview.
|
||||
$first = $this->journalRepos->firstNull();
|
||||
$firstDate = $first instanceof TransactionJournal ? $first->date : $start;
|
||||
$periods = $this->getNoBudgetPeriodOverview($firstDate, $end);
|
||||
$periods = $this->getNoModelPeriodOverview('budget', $firstDate, $end);
|
||||
$page = (int) $request->get('page');
|
||||
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
|
||||
|
||||
|
@@ -35,6 +35,7 @@ use FireflyIII\Support\Http\Controllers\PeriodOverview;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\View\View;
|
||||
|
||||
/**
|
||||
@@ -74,7 +75,7 @@ class NoCategoryController extends Controller
|
||||
*/
|
||||
public function show(Request $request, ?Carbon $start = null, ?Carbon $end = null)
|
||||
{
|
||||
app('log')->debug('Start of noCategory()');
|
||||
Log::debug('Start of noCategory()');
|
||||
$start ??= session('start');
|
||||
$end ??= session('end');
|
||||
|
||||
@@ -82,14 +83,12 @@ class NoCategoryController extends Controller
|
||||
/** @var Carbon $end */
|
||||
$page = (int) $request->get('page');
|
||||
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
|
||||
$subTitle = trans(
|
||||
'firefly.without_category_between',
|
||||
['start' => $start->isoFormat($this->monthAndDayFormat), 'end' => $end->isoFormat($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getNoCategoryPeriodOverview($start);
|
||||
$subTitle = trans('firefly.without_category_between', ['start' => $start->isoFormat($this->monthAndDayFormat), 'end' => $end->isoFormat($this->monthAndDayFormat)]);
|
||||
$first = $this->journalRepos->firstNull()->date ?? clone $start;
|
||||
$periods = $this->getNoModelPeriodOverview('category', $first, $end);
|
||||
|
||||
app('log')->debug(sprintf('Start for noCategory() is %s', $start->format('Y-m-d')));
|
||||
app('log')->debug(sprintf('End for noCategory() is %s', $end->format('Y-m-d')));
|
||||
Log::debug(sprintf('Start for noCategory() is %s', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('End for noCategory() is %s', $end->format('Y-m-d')));
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
@@ -117,13 +116,13 @@ class NoCategoryController extends Controller
|
||||
$periods = new Collection();
|
||||
$page = (int) $request->get('page');
|
||||
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
|
||||
app('log')->debug('Start of noCategory()');
|
||||
Log::debug('Start of noCategory()');
|
||||
$subTitle = (string) trans('firefly.all_journals_without_category');
|
||||
$first = $this->journalRepos->firstNull();
|
||||
$start = $first instanceof TransactionJournal ? $first->date : new Carbon();
|
||||
$end = today(config('app.timezone'));
|
||||
app('log')->debug(sprintf('Start for noCategory() is %s', $start->format('Y-m-d')));
|
||||
app('log')->debug(sprintf('End for noCategory() is %s', $end->format('Y-m-d')));
|
||||
Log::debug(sprintf('Start for noCategory() is %s', $start->format('Y-m-d')));
|
||||
Log::debug(sprintf('End for noCategory() is %s', $end->format('Y-m-d')));
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
|
@@ -235,7 +235,7 @@ class AccountController extends Controller
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))
|
||||
$collector->setAccounts(new Collection()->push($account))
|
||||
->setRange($start, $end)
|
||||
->withBudgetInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
|
||||
;
|
||||
@@ -322,7 +322,7 @@ class AccountController extends Controller
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->withCategoryInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||
$collector->setAccounts(new Collection()->push($account))->setRange($start, $end)->withCategoryInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$result = [];
|
||||
$chartData = [];
|
||||
@@ -429,7 +429,7 @@ class AccountController extends Controller
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->withCategoryInformation()->setTypes([TransactionTypeEnum::DEPOSIT->value]);
|
||||
$collector->setAccounts(new Collection()->push($account))->setRange($start, $end)->withCategoryInformation()->setTypes([TransactionTypeEnum::DEPOSIT->value]);
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$result = [];
|
||||
$chartData = [];
|
||||
|
@@ -100,7 +100,7 @@ class BudgetController extends Controller
|
||||
return response()->json($cache->get());
|
||||
}
|
||||
$step = $this->calculateStep($start, $end); // depending on diff, do something with range of chart.
|
||||
$collection = new Collection([$budget]);
|
||||
$collection = new Collection()->push($budget);
|
||||
$chartData = [];
|
||||
$loopStart = clone $start;
|
||||
$loopStart = Navigation::startOfPeriod($loopStart, $step);
|
||||
@@ -169,7 +169,7 @@ class BudgetController extends Controller
|
||||
$locale = app('steam')->getLocale();
|
||||
$entries = [];
|
||||
$amount = $budgetLimit->amount ?? '0';
|
||||
$budgetCollection = new Collection([$budget]);
|
||||
$budgetCollection = new Collection()->push($budget);
|
||||
$currency = $budgetLimit->transactionCurrency;
|
||||
if ($this->convertToPrimary) {
|
||||
$amount = $budgetLimit->native_amount ?? $amount;
|
||||
@@ -535,7 +535,7 @@ class BudgetController extends Controller
|
||||
}
|
||||
|
||||
// get spent amount in this period for this currency.
|
||||
$sum = $this->opsRepository->sumExpenses($currentStart, $currentEnd, $accounts, new Collection([$budget]), $currency);
|
||||
$sum = $this->opsRepository->sumExpenses($currentStart, $currentEnd, $accounts, new Collection()->push($budget), $currency);
|
||||
$amount = app('steam')->positive($sum[$currency->id]['sum'] ?? '0');
|
||||
$chartData[0]['entries'][$title] = app('steam')->bcround($amount, $currency->decimal_places);
|
||||
|
||||
|
@@ -163,7 +163,7 @@ class BudgetReportController extends Controller
|
||||
public function mainChart(Collection $accounts, Budget $budget, Carbon $start, Carbon $end): JsonResponse
|
||||
{
|
||||
$chartData = [];
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, new Collection([$budget]));
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, new Collection()->push($budget));
|
||||
$format = Navigation::preferredCarbonLocalizedFormat($start, $end);
|
||||
|
||||
// loop expenses.
|
||||
|
@@ -174,7 +174,7 @@ class CategoryController extends Controller
|
||||
$opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$categoryId = $category->id;
|
||||
// this gives us all currencies
|
||||
$collection = new Collection([$category]);
|
||||
$collection = new Collection()->push($category);
|
||||
$expenses = $opsRepository->listExpenses($start, $end, $accounts, $collection);
|
||||
$income = $opsRepository->listIncome($start, $end, $accounts, $collection);
|
||||
}
|
||||
|
@@ -208,8 +208,8 @@ class CategoryReportController extends Controller
|
||||
public function mainChart(Collection $accounts, Category $category, Carbon $start, Carbon $end): JsonResponse
|
||||
{
|
||||
$chartData = [];
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, new Collection([$category]));
|
||||
$earned = $this->opsRepository->listIncome($start, $end, $accounts, new Collection([$category]));
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, new Collection()->push($category));
|
||||
$earned = $this->opsRepository->listIncome($start, $end, $accounts, new Collection()->push($category));
|
||||
$format = app('navigation')->preferredCarbonLocalizedFormat($start, $end);
|
||||
// loop expenses.
|
||||
foreach ($spent as $currency) {
|
||||
|
@@ -150,7 +150,7 @@ class DoubleReportController extends Controller
|
||||
{
|
||||
$chartData = [];
|
||||
|
||||
$opposing = $this->repository->expandWithDoubles(new Collection([$account]));
|
||||
$opposing = $this->repository->expandWithDoubles(new Collection()->push($account));
|
||||
$accounts = $accounts->merge($opposing);
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts);
|
||||
$earned = $this->opsRepository->listIncome($start, $end, $accounts);
|
||||
|
@@ -212,8 +212,8 @@ class TagReportController extends Controller
|
||||
public function mainChart(Collection $accounts, Tag $tag, Carbon $start, Carbon $end): JsonResponse
|
||||
{
|
||||
$chartData = [];
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, new Collection([$tag]));
|
||||
$earned = $this->opsRepository->listIncome($start, $end, $accounts, new Collection([$tag]));
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, new Collection()->push($tag));
|
||||
$earned = $this->opsRepository->listIncome($start, $end, $accounts, new Collection()->push($tag));
|
||||
$format = app('navigation')->preferredCarbonLocalizedFormat($start, $end);
|
||||
|
||||
// loop expenses.
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Http\Controllers;
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use FireflyIII\Support\Http\Controllers\RequestInformation;
|
||||
use FireflyIII\Support\Http\Controllers\UserNavigation;
|
||||
@@ -133,7 +134,7 @@ abstract class Controller extends BaseController
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
$language = Steam::getLanguage();
|
||||
$locale = Steam::getLocale();
|
||||
$darkMode = app('preferences')->get('darkMode', 'browser')->data;
|
||||
$darkMode = Preferences::get('darkMode', 'browser')->data;
|
||||
$this->convertToPrimary = Amount::convertToPrimary();
|
||||
$page = $this->getPageName();
|
||||
$shownDemo = $this->hasSeenDemo();
|
||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Enums\AccountTypeEnum;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Models\PeriodStatistic;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
@@ -108,6 +109,8 @@ class DebugController extends Controller
|
||||
Artisan::call('route:clear');
|
||||
Artisan::call('view:clear');
|
||||
|
||||
PeriodStatistic::where('id', '>', 0)->delete();
|
||||
|
||||
// also do some recalculations.
|
||||
Artisan::call('correction:recalculates-liabilities');
|
||||
AccountBalanceCalculator::recalculateAll(false);
|
||||
@@ -181,7 +184,6 @@ class DebugController extends Controller
|
||||
$currentDriver = DB::getDriverName();
|
||||
|
||||
return [
|
||||
'db_version' => app('fireflyconfig')->get('db_version', 1)->data,
|
||||
'php_version' => PHP_VERSION,
|
||||
'php_os' => PHP_OS,
|
||||
'uname' => php_uname('m'),
|
||||
|
@@ -170,7 +170,7 @@ class HomeController extends Controller
|
||||
foreach ($accounts as $account) {
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->withAccountInformation()->setRange($start, $end)->setLimit(10)->setPage(1);
|
||||
$collector->setAccounts(new Collection()->push($account))->withAccountInformation()->setRange($start, $end)->setLimit(10)->setPage(1);
|
||||
$set = $collector->getExtractedJournals();
|
||||
$transactions[] = ['transactions' => $set, 'account' => $account];
|
||||
}
|
||||
|
@@ -171,7 +171,7 @@ class BoxController extends Controller
|
||||
$filtered = $allAccounts->filter(
|
||||
static function (Account $account) use ($accountRepository) {
|
||||
$includeNetWorth = $accountRepository->getMetaValue($account, 'include_net_worth');
|
||||
$result = null === $includeNetWorth ? true : '1' === $includeNetWorth;
|
||||
$result = null === $includeNetWorth || '1' === $includeNetWorth;
|
||||
if (false === $result) {
|
||||
app('log')->debug(sprintf('Will not include "%s" in net worth charts.', $account->name));
|
||||
}
|
||||
|
@@ -217,7 +217,7 @@ class ReconcileController extends Controller
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
|
||||
$collector->setAccounts(new Collection([$account]))
|
||||
$collector->setAccounts(new Collection()->push($account))
|
||||
->setRange($selectionStart, $selectionEnd)
|
||||
->withBudgetInformation()->withCategoryInformation()->withAccountInformation()
|
||||
;
|
||||
|
@@ -74,7 +74,7 @@ class TriggerController extends Controller
|
||||
|
||||
/** @var CreateRecurringTransactions $job */
|
||||
$job = app(CreateRecurringTransactions::class);
|
||||
$job->setRecurrences(new Collection([$recurrence]));
|
||||
$job->setRecurrences(new Collection()->push($recurrence));
|
||||
$job->setDate($date);
|
||||
$job->setForce(false);
|
||||
$job->handle();
|
||||
|
@@ -291,7 +291,7 @@ class BudgetController extends Controller
|
||||
$cache->addProperty('budget-period-report');
|
||||
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||
if ($cache->has()) {
|
||||
// return $cache->get();
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
$periods = Navigation::listOfPeriods($start, $end);
|
||||
|
@@ -152,7 +152,7 @@ class SelectController extends Controller
|
||||
$newRuleEngine = app(RuleEngineInterface::class);
|
||||
|
||||
// set rules:
|
||||
$newRuleEngine->setRules(new Collection([$rule]));
|
||||
$newRuleEngine->setRules(new Collection()->push($rule));
|
||||
$newRuleEngine->setRefreshTriggers(false);
|
||||
$collection = $newRuleEngine->find();
|
||||
$collection = $collection->slice(0, 20);
|
||||
@@ -196,7 +196,7 @@ class SelectController extends Controller
|
||||
$newRuleEngine = app(RuleEngineInterface::class);
|
||||
|
||||
// set rules:
|
||||
$newRuleEngine->setRules(new Collection([$rule]));
|
||||
$newRuleEngine->setRules(new Collection()->push($rule));
|
||||
$collection = $newRuleEngine->find();
|
||||
$collection = $collection->slice(0, 20);
|
||||
|
||||
|
@@ -78,7 +78,7 @@ class ExecutionController extends Controller
|
||||
|
||||
// set rules:
|
||||
// #10427, file rule group and not the set of rules.
|
||||
$collection = new Collection([$ruleGroup]);
|
||||
$collection = new Collection()->push($ruleGroup);
|
||||
$newRuleEngine->setRuleGroups($collection);
|
||||
$newRuleEngine->fire();
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\System;
|
||||
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Exception;
|
||||
@@ -81,10 +82,7 @@ class InstallController extends Controller
|
||||
{
|
||||
app('view')->share('FF_VERSION', config('firefly.version'));
|
||||
// index will set FF3 version.
|
||||
app('fireflyconfig')->set('ff3_version', (string) config('firefly.version'));
|
||||
|
||||
// set new DB version.
|
||||
app('fireflyconfig')->set('db_version', (int) config('firefly.db_version'));
|
||||
FireflyConfig::set('ff3_version', (string) config('firefly.version'));
|
||||
|
||||
return view('install.index');
|
||||
}
|
||||
|
@@ -250,10 +250,7 @@ class TagController extends Controller
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
|
||||
$collector->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withAccountInformation()
|
||||
->setTag($tag)->withBudgetInformation()->withCategoryInformation()
|
||||
->withAttachmentInformation()
|
||||
;
|
||||
$collector->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withAccountInformation()->setTag($tag)->withBudgetInformation()->withCategoryInformation()->withAttachmentInformation();
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath($path);
|
||||
$sums = $this->repository->sumsOfTag($tag, $start, $end);
|
||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Update\GroupCloneService;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -76,7 +77,7 @@ class CreateController extends Controller
|
||||
// event!
|
||||
event(new StoredTransactionGroup($newGroup, true, true));
|
||||
|
||||
app('preferences')->mark();
|
||||
Preferences::mark();
|
||||
|
||||
$title = $newGroup->title ?? $newGroup->transactionJournals->first()->description;
|
||||
$link = route('transactions.show', [$newGroup->id]);
|
||||
@@ -103,7 +104,7 @@ class CreateController extends Controller
|
||||
* */
|
||||
public function create(?string $objectType)
|
||||
{
|
||||
app('preferences')->mark();
|
||||
Preferences::mark();
|
||||
|
||||
$sourceId = (int) request()->get('source');
|
||||
$destinationId = (int) request()->get('destination');
|
||||
@@ -114,7 +115,9 @@ class CreateController extends Controller
|
||||
$preFilled = session()->has('preFilled') ? session('preFilled') : [];
|
||||
$subTitle = (string) trans(sprintf('breadcrumbs.create_%s', strtolower((string) $objectType)));
|
||||
$subTitleIcon = 'fa-plus';
|
||||
$optionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data;
|
||||
|
||||
/** @var null|array $optionalFields */
|
||||
$optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data;
|
||||
$allowedOpposingTypes = config('firefly.allowed_opposing_types');
|
||||
$accountToTypes = config('firefly.account_to_transaction');
|
||||
$previousUrl = $this->rememberPreviousUrl('transactions.create.url');
|
||||
|
@@ -146,25 +146,7 @@ class ShowController extends Controller
|
||||
$attachments = $this->repository->getAttachments($transactionGroup);
|
||||
$links = $this->repository->getLinks($transactionGroup);
|
||||
|
||||
return view(
|
||||
'transactions.show',
|
||||
compact(
|
||||
'transactionGroup',
|
||||
'amounts',
|
||||
'first',
|
||||
'type',
|
||||
'logEntries',
|
||||
'groupLogEntries',
|
||||
'subTitle',
|
||||
'splits',
|
||||
'selectedGroup',
|
||||
'groupArray',
|
||||
'events',
|
||||
'attachments',
|
||||
'links',
|
||||
'accounts',
|
||||
)
|
||||
);
|
||||
return view('transactions.show', compact('transactionGroup', 'amounts', 'first', 'type', 'logEntries', 'groupLogEntries', 'subTitle', 'splits', 'selectedGroup', 'groupArray', 'events', 'attachments', 'links', 'accounts'));
|
||||
}
|
||||
|
||||
private function getAmounts(array $group): array
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Support\System\IsOldVersion;
|
||||
use FireflyIII\Support\System\OAuthKeys;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -37,6 +38,8 @@ use Illuminate\Support\Facades\Log;
|
||||
*/
|
||||
class Installer
|
||||
{
|
||||
use IsOldVersion;
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
@@ -65,7 +68,7 @@ class Installer
|
||||
// run installer when no tables are present,
|
||||
// or when old scheme version
|
||||
// or when old firefly version
|
||||
if ($this->hasNoTables() || $this->oldDBVersion() || $this->oldVersion()) {
|
||||
if ($this->hasNoTables() || $this->isOldVersionInstalled()) {
|
||||
return response()->redirectTo(route('installer.index'));
|
||||
}
|
||||
OAuthKeys::verifyKeysRoutine();
|
||||
@@ -126,59 +129,4 @@ class Installer
|
||||
{
|
||||
return false !== stripos($message, 'Base table or view not found');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the "db_version" variable is correct.
|
||||
*/
|
||||
private function oldDBVersion(): bool
|
||||
{
|
||||
// older version in config than database?
|
||||
$configVersion = (int) config('firefly.db_version');
|
||||
$dbVersion = (int) app('fireflyconfig')->getFresh('db_version', 1)->data;
|
||||
if ($configVersion > $dbVersion) {
|
||||
Log::warning(
|
||||
sprintf(
|
||||
'The current configured version (%d) is older than the required version (%d). Redirect to migrate routine.',
|
||||
$dbVersion,
|
||||
$configVersion
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Log::info(sprintf('Configured DB version (%d) equals expected DB version (%d)', $dbVersion, $configVersion));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the "firefly_version" variable is correct.
|
||||
*/
|
||||
private function oldVersion(): bool
|
||||
{
|
||||
// version compare thing.
|
||||
$configVersion = (string) config('firefly.version');
|
||||
$dbVersion = (string) app('fireflyconfig')->getFresh('ff3_version', '1.0')->data;
|
||||
if (str_starts_with($configVersion, 'develop')) {
|
||||
Log::debug('Skipping version check for develop version.');
|
||||
|
||||
return false;
|
||||
}
|
||||
if (1 === version_compare($configVersion, $dbVersion)) {
|
||||
Log::warning(
|
||||
sprintf(
|
||||
'The current configured Firefly III version (%s) is older than the required version (%s). Redirect to migrate routine.',
|
||||
$dbVersion,
|
||||
$configVersion
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Log::info(sprintf('Installed Firefly III version (%s) equals expected Firefly III version (%s)', $dbVersion, $configVersion));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -25,14 +25,15 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\GroupMembership;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Models\Webhook;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@@ -103,7 +104,7 @@ class InterestingMessage
|
||||
|
||||
// send message about newly created transaction group.
|
||||
/** @var null|TransactionGroup $group */
|
||||
$group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int) $transactionGroupId);
|
||||
$group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int)$transactionGroupId);
|
||||
|
||||
if (null === $group) {
|
||||
return;
|
||||
@@ -119,17 +120,17 @@ class InterestingMessage
|
||||
$title = $count > 1 ? $group->title : $journal->description;
|
||||
if ('created' === $message) {
|
||||
session()->flash('success_url', route('transactions.show', [$transactionGroupId]));
|
||||
session()->flash('success', (string) trans('firefly.stored_journal', ['description' => $title]));
|
||||
session()->flash('success', (string)trans('firefly.stored_journal', ['description' => $title]));
|
||||
}
|
||||
if ('updated' === $message) {
|
||||
$type = strtolower((string) $journal->transactionType->type);
|
||||
$type = strtolower((string)$journal->transactionType->type);
|
||||
session()->flash('success_url', route('transactions.show', [$transactionGroupId]));
|
||||
session()->flash('success', (string) trans(sprintf('firefly.updated_%s', $type), ['description' => $title]));
|
||||
session()->flash('success', (string)trans(sprintf('firefly.updated_%s', $type), ['description' => $title]));
|
||||
}
|
||||
if ('no_change' === $message) {
|
||||
$type = strtolower((string) $journal->transactionType->type);
|
||||
$type = strtolower((string)$journal->transactionType->type);
|
||||
session()->flash('warning_url', route('transactions.show', [$transactionGroupId]));
|
||||
session()->flash('warning', (string) trans(sprintf('firefly.no_changes_%s', $type), ['description' => $title]));
|
||||
session()->flash('warning', (string)trans(sprintf('firefly.no_changes_%s', $type), ['description' => $title]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,13 +171,13 @@ class InterestingMessage
|
||||
|
||||
|
||||
if ('deleted' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.flash_administration_deleted', ['title' => $userGroup->title]));
|
||||
session()->flash('success', (string)trans('firefly.flash_administration_deleted', ['title' => $userGroup->title]));
|
||||
}
|
||||
if ('created' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.flash_administration_created', ['title' => $userGroup->title]));
|
||||
session()->flash('success', (string)trans('firefly.flash_administration_created', ['title' => $userGroup->title]));
|
||||
}
|
||||
if ('updated' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.flash_administration_updated', ['title' => $userGroup->title]));
|
||||
session()->flash('success', (string)trans('firefly.flash_administration_updated', ['title' => $userGroup->title]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,13 +206,13 @@ class InterestingMessage
|
||||
return;
|
||||
}
|
||||
if ('deleted' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.account_deleted', ['name' => $account->name]));
|
||||
session()->flash('success', (string)trans('firefly.account_deleted', ['name' => $account->name]));
|
||||
}
|
||||
if ('created' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.stored_new_account', ['name' => $account->name]));
|
||||
session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name]));
|
||||
}
|
||||
if ('updated' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.updated_account', ['name' => $account->name]));
|
||||
session()->flash('success', (string)trans('firefly.updated_account', ['name' => $account->name]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,10 +238,10 @@ class InterestingMessage
|
||||
return;
|
||||
}
|
||||
if ('deleted' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.deleted_bill', ['name' => $bill->name]));
|
||||
session()->flash('success', (string)trans('firefly.deleted_bill', ['name' => $bill->name]));
|
||||
}
|
||||
if ('created' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.stored_new_bill', ['name' => $bill->name]));
|
||||
session()->flash('success', (string)trans('firefly.stored_new_bill', ['name' => $bill->name]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,13 +267,13 @@ class InterestingMessage
|
||||
return;
|
||||
}
|
||||
if ('deleted' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.deleted_webhook', ['title' => $webhook->title]));
|
||||
session()->flash('success', (string)trans('firefly.deleted_webhook', ['title' => $webhook->title]));
|
||||
}
|
||||
if ('updated' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.updated_webhook', ['title' => $webhook->title]));
|
||||
session()->flash('success', (string)trans('firefly.updated_webhook', ['title' => $webhook->title]));
|
||||
}
|
||||
if ('created' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.stored_new_webhook', ['title' => $webhook->title]));
|
||||
session()->flash('success', (string)trans('firefly.stored_new_webhook', ['title' => $webhook->title]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,32 +290,32 @@ class InterestingMessage
|
||||
{
|
||||
// params:
|
||||
// get parameters from request.
|
||||
$code = $request->get('code');
|
||||
$message = $request->get('message');
|
||||
$code = (string) $request->get('code');
|
||||
$message = (string) $request->get('message');
|
||||
|
||||
/** @var null|TransactionCurrency $currency */
|
||||
$currency = TransactionCurrency::whereCode($code)->first();
|
||||
|
||||
if (null === $currency) {
|
||||
try {
|
||||
$currency = Amount::getTransactionCurrencyByCode($code);
|
||||
} catch (FireflyException) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('enabled' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.currency_is_now_enabled', ['name' => $currency->name]));
|
||||
session()->flash('success', (string)trans('firefly.currency_is_now_enabled', ['name' => $currency->name]));
|
||||
}
|
||||
if ('enable_failed' === $message) {
|
||||
session()->flash('error', (string) trans('firefly.could_not_enable_currency', ['name' => $currency->name]));
|
||||
session()->flash('error', (string)trans('firefly.could_not_enable_currency', ['name' => $currency->name]));
|
||||
}
|
||||
if ('disabled' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.currency_is_now_disabled', ['name' => $currency->name]));
|
||||
session()->flash('success', (string)trans('firefly.currency_is_now_disabled', ['name' => $currency->name]));
|
||||
}
|
||||
if ('disable_failed' === $message) {
|
||||
session()->flash('error', (string) trans('firefly.could_not_disable_currency', ['name' => $currency->name]));
|
||||
session()->flash('error', (string)trans('firefly.could_not_disable_currency', ['name' => $currency->name]));
|
||||
}
|
||||
if ('default' === $message) {
|
||||
session()->flash('success', (string) trans('firefly.new_default_currency', ['name' => $currency->name]));
|
||||
session()->flash('success', (string)trans('firefly.new_default_currency', ['name' => $currency->name]));
|
||||
}
|
||||
if ('default_failed' === $message) {
|
||||
session()->flash('error', (string) trans('firefly.default_currency_failed', ['name' => $currency->name]));
|
||||
session()->flash('error', (string)trans('firefly.default_currency_failed', ['name' => $currency->name]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user