Compare commits

...

94 Commits

Author SHA1 Message Date
github-actions[bot]
d8f05492c3 Merge pull request #10955 from firefly-iii/release-1758652896
🤖 Automatically merge the PR into the develop branch.
2025-09-23 20:41:46 +02:00
JC5
4a264f34fa 🤖 Auto commit for release 'develop' on 2025-09-23 2025-09-23 20:41:36 +02:00
James Cole
5a1413e758 Fix #10954 2025-09-23 20:22:58 +02:00
github-actions[bot]
84dbeeb0ce Merge pull request #10946 from firefly-iii/release-1758511378
🤖 Automatically merge the PR into the develop branch.
2025-09-22 05:23:04 +02:00
JC5
d868dc0945 🤖 Auto commit for release 'develop' on 2025-09-22 2025-09-22 05:22:58 +02:00
James Cole
beecf9c229 Make sure demo user cannot send notifications. 2025-09-21 18:00:23 +02:00
github-actions[bot]
e39ba46398 Merge pull request #10943 from firefly-iii/release-1758470243
🤖 Automatically merge the PR into the develop branch.
2025-09-21 17:57:31 +02:00
JC5
e6b6a3cee5 🤖 Auto commit for release 'develop' on 2025-09-21 2025-09-21 17:57:23 +02:00
James Cole
b5483f6ad3 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-09-21 17:52:16 +02:00
James Cole
a751218d53 Fix rule order for #10938 2025-09-21 17:52:07 +02:00
github-actions[bot]
2af5e6eeef Merge pull request #10942 from firefly-iii/release-1758460508
🤖 Automatically merge the PR into the develop branch.
2025-09-21 15:15:17 +02:00
JC5
013c43f9f2 🤖 Auto commit for release 'develop' on 2025-09-21 2025-09-21 15:15:08 +02:00
James Cole
7e08a1f33c Possible fix for #10940, not sure. 2025-09-21 15:11:16 +02:00
James Cole
e592b56d7a Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-09-21 15:06:32 +02:00
github-actions[bot]
a2479f71fe Merge pull request #10937 from firefly-iii/release-1758437913
🤖 Automatically merge the PR into the develop branch.
2025-09-21 08:58:42 +02:00
JC5
7d3b993b98 🤖 Auto commit for release 'develop' on 2025-09-21 2025-09-21 08:58:33 +02:00
James Cole
90623101a3 Add earned + spent, needs cleaning up still. 2025-09-21 08:54:26 +02:00
github-actions[bot]
e2eca79b25 Merge pull request #10936 from firefly-iii/release-1758436089
🤖 Automatically merge the PR into the develop branch.
2025-09-21 08:28:16 +02:00
JC5
8c0ee8f024 🤖 Auto commit for release 'develop' on 2025-09-21 2025-09-21 08:28:09 +02:00
James Cole
69cae3ae55 Fix autocomplete. 2025-09-21 08:13:13 +02:00
James Cole
8a06298385 Repair charts and balances. 2025-09-21 07:35:46 +02:00
James Cole
acc3c294d8 Fix #10924 2025-09-17 20:46:03 +02:00
James Cole
dbf7dba421 Fix #10916 2025-09-17 20:04:24 +02:00
James Cole
65813f290d Expand changelog. 2025-09-17 13:48:56 +02:00
James Cole
3491fbb99d Force account search to validate it did not just find the source account. #10920 2025-09-17 07:09:40 +02:00
James Cole
cb6b3d5f85 Fix #10891 2025-09-16 21:09:29 +02:00
github-actions[bot]
956d4e09c3 Merge pull request #10917 from firefly-iii/release-1758048927
🤖 Automatically merge the PR into the develop branch.
2025-09-16 20:55:35 +02:00
JC5
6a7c35e7bc 🤖 Auto commit for release 'develop' on 2025-09-16 2025-09-16 20:55:27 +02:00
James Cole
090aecb5f5 Clean up command. 2025-09-16 20:50:25 +02:00
James Cole
b653d63d3d Add new correction command, will probably fix #10833 2025-09-16 20:44:54 +02:00
github-actions[bot]
258dbf4a98 Merge pull request #10913 from firefly-iii/release-1757957159
🤖 Automatically merge the PR into the develop branch.
2025-09-15 19:26:09 +02:00
JC5
53335077ff 🤖 Auto commit for release 'develop' on 2025-09-15 2025-09-15 19:25:59 +02:00
James Cole
ecfb3e2f95 Fix #10854 and another issue (again). 2025-09-15 19:20:51 +02:00
github-actions[bot]
f512e6724e Merge pull request #10911 from firefly-iii/release-1757906627
🤖 Automatically merge the PR into the develop branch.
2025-09-15 05:23:56 +02:00
JC5
de9efb0727 🤖 Auto commit for release 'develop' on 2025-09-15 2025-09-15 05:23:47 +02:00
James Cole
9075fa8ac8 Allow webhooks to be send for budget limit update. 2025-09-14 09:21:32 +02:00
James Cole
768bd892c8 Allow sending of webhooks from budget limit store. 2025-09-14 09:14:41 +02:00
James Cole
9d9483e20f Refactor models. 2025-09-14 09:00:01 +02:00
James Cole
935453796e Allow budget update to have webhooks controlled with "fire_webhooks" 2025-09-14 08:59:00 +02:00
James Cole
c2d3f5da16 Allow budget store to have optional webhook using "fire_webhooks". 2025-09-14 08:55:29 +02:00
James Cole
9e6f9d16e4 Move observers to attributes. 2025-09-14 08:55:08 +02:00
James Cole
fad016f92f Update changelog. 2025-09-14 07:46:46 +02:00
James Cole
30df6684cb Fix another missing filter for #10803 2025-09-14 07:45:54 +02:00
James Cole
4aa911420a Merge branch 'main' into develop 2025-09-13 18:53:00 +02:00
github-actions[bot]
19555a7046 Merge pull request #10907 from firefly-iii/release-1757782324
🤖 Automatically merge the PR into the develop branch.
2025-09-13 18:52:14 +02:00
JC5
e5c409a8fc 🤖 Auto commit for release 'develop' on 2025-09-13 2025-09-13 18:52:04 +02:00
github-actions[bot]
3adf3d2fdb Merge pull request #10906 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-09-13 18:38:12 +02:00
github-actions[bot]
0923d5a23e Merge pull request #10905 from firefly-iii/release-1757781480
🤖 Automatically merge the PR into the develop branch.
2025-09-13 18:38:07 +02:00
JC5
76b8cdc385 🤖 Auto commit for release 'v6.4.0' on 2025-09-13 2025-09-13 18:38:00 +02:00
James Cole
0a27da83eb Merge branch 'main' into develop
# Conflicts:
#	.github/workflows/release.yml
2025-09-13 18:33:47 +02:00
github-actions[bot]
17d6e2be85 Merge pull request #10903 from firefly-iii/release-1757781134
🤖 Automatically merge the PR into the develop branch.
2025-09-13 18:32:20 +02:00
JC5
7381f3eba9 🤖 Auto commit for release 'v6.4.0' on 2025-09-13 2025-09-13 18:32:14 +02:00
James Cole
7f2ef1b8e1 Should not be necessary, but OK/ 2025-09-13 18:28:26 +02:00
github-actions[bot]
9dccae2402 Merge pull request #10901 from firefly-iii/release-1757780827
🤖 Automatically merge the PR into the develop branch.
2025-09-13 18:27:17 +02:00
JC5
073afd5b6e 🤖 Auto commit for release 'v6.4.0' on 2025-09-13 2025-09-13 18:27:07 +02:00
James Cole
4167d85be2 Expand changelog. 2025-09-13 07:30:50 +02:00
James Cole
ee28d1307d Fix #10871 2025-09-13 07:30:30 +02:00
James Cole
7562215666 Add some extra explanation. 2025-09-13 07:24:03 +02:00
github-actions[bot]
0203b918e9 Merge pull request #10899 from firefly-iii/release-1757740712
🤖 Automatically merge the PR into the develop branch.
2025-09-13 07:18:41 +02:00
JC5
ae7c664418 🤖 Auto commit for release 'develop' on 2025-09-13 2025-09-13 07:18:32 +02:00
James Cole
f13e0991fb Fix #10898 2025-09-13 07:13:30 +02:00
James Cole
deae94b658 Set user ID from object, fix #10891 2025-09-11 19:37:34 +02:00
James Cole
c38c752520 Fix #10888 2025-09-10 20:42:15 +02:00
James Cole
28e7df2527 Small php fixes. 2025-09-10 16:16:31 +02:00
James Cole
cb0b42e44b Replace method calls. 2025-09-10 16:07:19 +02:00
James Cole
a3674c4dfe No need to use the exception either. 2025-09-10 07:03:41 +02:00
James Cole
27480561ee Catch random exception because why not. 2025-09-10 07:03:23 +02:00
github-actions[bot]
6ea7152423 Merge pull request #10886 from firefly-iii/release-1757480185
🤖 Automatically merge the PR into the develop branch.
2025-09-10 06:56:34 +02:00
JC5
dab95f7a86 🤖 Auto commit for release 'develop' on 2025-09-10 2025-09-10 06:56:25 +02:00
James Cole
adf34805a8 Shiny release PR. 2025-09-10 06:52:51 +02:00
James Cole
93e926465f Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-09-10 06:51:11 +02:00
github-actions[bot]
5b0be91f93 Merge pull request #10885 from firefly-iii/release-1757479782
🤖 Automatically merge the PR into the develop branch.
2025-09-10 06:49:50 +02:00
JC5
01e7b604da 🤖 Auto commit for release 'develop' on 2025-09-10 2025-09-10 06:49:42 +02:00
James Cole
974a550d22 Merge branch 'main' into develop 2025-09-10 06:44:16 +02:00
James Cole
58d175444b Fix #10883 2025-09-10 06:43:24 +02:00
James Cole
29d8861e96 Merge pull request #10882 from firefly-iii/dependabot/npm_and_yarn/npm_and_yarn-f5c1666f0c 2025-09-10 06:02:57 +02:00
dependabot[bot]
eb832c750f Bump vite in the npm_and_yarn group across 1 directory
Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 7.1.2 to 7.1.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.1.5/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.1.5
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-09 20:59:51 +00:00
James Cole
134770644a Fix amounts in transaction. 2025-09-09 17:14:53 +02:00
James Cole
a9f21c9371 Extra text in the PR. 2025-09-09 15:53:25 +02:00
github-actions[bot]
781947beeb Merge pull request #10879 from firefly-iii/release-1757425805
🤖 Automatically merge the PR into the develop branch.
2025-09-09 15:50:18 +02:00
JC5
9760cd2f97 🤖 Auto commit for release 'develop' on 2025-09-09 2025-09-09 15:50:06 +02:00
James Cole
d317e9ec32 Update changelog. 2025-09-09 15:41:19 +02:00
James Cole
534f7fcadb Merge branch 'main' into develop 2025-09-09 15:36:55 +02:00
James Cole
fb3f7a1d4b Merge pull request #10874 from firefly-iii/dependabot/github_actions/actions/stale-10
Bump actions/stale from 9 to 10
2025-09-08 11:41:37 +02:00
James Cole
bf2c3e3561 Merge pull request #10873 from firefly-iii/dependabot/github_actions/actions/github-script-8
Bump actions/github-script from 7 to 8
2025-09-08 11:41:12 +02:00
github-actions[bot]
b670f81dcd Merge pull request #10875 from firefly-iii/release-1757313349
🤖 Automatically merge the PR into the develop branch.
2025-09-08 08:36:01 +02:00
JC5
7aac1cdf67 🤖 Auto commit for release 'develop' on 2025-09-08 2025-09-08 08:35:49 +02:00
Sander Dorigo
fa0ac8a16c Fix php files 2025-09-08 08:31:09 +02:00
dependabot[bot]
0990b1f0b4 Bump actions/stale from 9 to 10
Bumps [actions/stale](https://github.com/actions/stale) from 9 to 10.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v9...v10)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: '10'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 03:08:14 +00:00
dependabot[bot]
c1922670c8 Bump actions/github-script from 7 to 8
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 8.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 03:08:10 +00:00
James Cole
81cd89d66f Final nestor and phpstan fixes. 2025-09-07 17:42:16 +02:00
James Cole
f5c202543c Clean up code. 2025-09-07 17:31:08 +02:00
James Cole
034f437c6b Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-09-07 17:30:43 +02:00
James Cole
8550ba6138 Remove unused code. 2025-09-07 17:30:34 +02:00
242 changed files with 2346 additions and 4200 deletions

View File

@@ -402,16 +402,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.87.1", "version": "v3.87.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "2f5170365e2a422d0c5421f9c8818b2c078105f6" "reference": "da5f0a7858c79b56fc0b8c36d3efcfe5f37f0992"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2f5170365e2a422d0c5421f9c8818b2c078105f6", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/da5f0a7858c79b56fc0b8c36d3efcfe5f37f0992",
"reference": "2f5170365e2a422d0c5421f9c8818b2c078105f6", "reference": "da5f0a7858c79b56fc0b8c36d3efcfe5f37f0992",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -494,7 +494,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "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.87.2"
}, },
"funding": [ "funding": [
{ {
@@ -502,7 +502,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-09-02T15:27:36+00:00" "time": "2025-09-10T09:51:40+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",

View File

@@ -314,8 +314,9 @@ DEMO_USERNAME=
DEMO_PASSWORD= DEMO_PASSWORD=
# #
# Disable or enable the running balance column data # Disable or enable the running balance column data.
# Please disable this. It's a very experimental feature. # 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 USE_RUNNING_BALANCE=false

View File

@@ -15,7 +15,7 @@ jobs:
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
- name: Prune cancelled/skipped runs - name: Prune cancelled/skipped runs
uses: actions/github-script@v7 uses: actions/github-script@v8
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
script: | script: |
@@ -45,7 +45,7 @@ jobs:
} }
- name: Prune runs older than 3 days - name: Prune runs older than 3 days
uses: actions/github-script@v7 uses: actions/github-script@v8
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
script: | script: |

View File

@@ -250,7 +250,7 @@ jobs:
fi fi
echo "Merge all changes from $BRANCH_NAME back into '$MERGE_INTO' using a PR" 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'" echo "PR URL is '$PR_URL'"
IFS='/' read -ra parts <<< "$PR_URL" IFS='/' read -ra parts <<< "$PR_URL"
PR_NR=$(printf %s\\n "${parts[@]:(-1)}") PR_NR=$(printf %s\\n "${parts[@]:(-1)}")
@@ -272,7 +272,7 @@ jobs:
echo "Also merge everything into main since this is a release." echo "Also merge everything into main since this is a release."
echo 'create PR' 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'" echo "PR URL is '$PR_URL'"
IFS='/' read -ra parts <<< "$PR_URL" IFS='/' read -ra parts <<< "$PR_URL"

View File

@@ -15,7 +15,7 @@ jobs:
actions: write actions: write
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v9 - uses: actions/stale@v10
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: | stale-issue-message: |

View File

@@ -31,9 +31,7 @@ use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Enums\UserRoleEnum; use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\AccountBalanceGrouped; use FireflyIII\Support\Http\Api\AccountBalanceGrouped;
use FireflyIII\Support\Http\Api\CleansChartData; use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter; use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;

View File

@@ -114,7 +114,7 @@ class BudgetController extends Controller
// get all limits: // get all limits:
$limits = $this->blRepository->getBudgetLimits($budget, $start, $end); $limits = $this->blRepository->getBudgetLimits($budget, $start, $end);
$rows = []; $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); $expenses = $this->processExpenses($budget->id, $spent, $start, $end);
$converter = new ExchangeRateConverter(); $converter = new ExchangeRateConverter();
$currencies = [$this->primaryCurrency->id => $this->primaryCurrency]; $currencies = [$this->primaryCurrency->id => $this->primaryCurrency];
@@ -133,9 +133,9 @@ class BudgetController extends Controller
$row['pc_left'] = '0'; $row['pc_left'] = '0';
$row['pc_overspent'] = '0'; $row['pc_overspent'] = '0';
if (null !== $limit) { if ($limit instanceof BudgetLimit) {
$row['budgeted'] = $limit->amount; $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['overspent'] = bcmul($row['left'], '-1');
$row['left'] = 1 === bccomp($row['left'], '0') ? $row['left'] : '0'; $row['left'] = 1 === bccomp($row['left'], '0') ? $row['left'] : '0';
$row['overspent'] = 1 === bccomp($row['overspent'], '0') ? $row['overspent'] : '0'; $row['overspent'] = 1 === bccomp($row['overspent'], '0') ? $row['overspent'] : '0';
@@ -208,7 +208,7 @@ class BudgetController extends Controller
// */ // */
// private function noBudgetLimits(Budget $budget, Carbon $start, Carbon $end): array // 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); // return $this->processExpenses($budget->id, $spent, $start, $end);
// } // }
@@ -290,7 +290,7 @@ class BudgetController extends Controller
// Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__)); // Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
// $end = clone $limit->end_date; // $end = clone $limit->end_date;
// $end->endOfDay(); // $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; // $limitCurrencyId = $limit->transaction_currency_id;
// //
// /** @var array $entry */ // /** @var array $entry */

View File

@@ -232,8 +232,6 @@ abstract class Controller extends BaseController
$baseUrl = sprintf('%s/api/v1', request()->getSchemeAndHttpHost()); $baseUrl = sprintf('%s/api/v1', request()->getSchemeAndHttpHost());
$manager->setSerializer(new JsonApiSerializer($baseUrl)); $manager->setSerializer(new JsonApiSerializer($baseUrl));
// $transformer->collectMetaData(new Collection([$object]));
$resource = new Item($object, $transformer, $key); $resource = new Item($object, $transformer, $key);
return $manager->createData($resource)->toArray(); return $manager->createData($resource)->toArray();

View File

@@ -76,7 +76,7 @@ class BudgetController extends Controller
/** @var Budget $budget */ /** @var Budget $budget */
foreach ($budgets as $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 */ /** @var array $expense */
foreach ($expenses as $expense) { foreach ($expenses as $expense) {

View File

@@ -76,7 +76,7 @@ class CategoryController extends Controller
/** @var Category $category */ /** @var Category $category */
foreach ($categories as $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 */ /** @var array $expense */
foreach ($expenses as $expense) { foreach ($expenses as $expense) {

View File

@@ -76,7 +76,7 @@ class CategoryController extends Controller
/** @var Category $category */ /** @var Category $category */
foreach ($categories as $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 */ /** @var array $expense */
foreach ($expenses as $expense) { foreach ($expenses as $expense) {

View File

@@ -76,7 +76,7 @@ class CategoryController extends Controller
/** @var Category $category */ /** @var Category $category */
foreach ($categories as $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 */ /** @var array $expense */
foreach ($expenses as $expense) { foreach ($expenses as $expense) {

View File

@@ -152,7 +152,7 @@ class ListController extends Controller
// use new group collector: // use new group collector:
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $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) ->withAPIInformation()->setLimit($pageSize)->setPage($this->parameters->get('page'))->setTypes($types)
; ;

View File

@@ -67,7 +67,9 @@ class StoreController extends Controller
*/ */
public function store(StoreRequest $request): JsonResponse 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(); $budget->refresh();
$manager = $this->getManager(); $manager = $this->getManager();

View File

@@ -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 public function update(UpdateRequest $request, Budget $budget): JsonResponse
{ {
$data = $request->getAll(); $data = $request->getAll();
$data['fire_webhooks'] ??= true;
$budget = $this->repository->update($budget, $data); $budget = $this->repository->update($budget, $data);
$manager = $this->getManager(); $manager = $this->getManager();

View File

@@ -70,6 +70,7 @@ class StoreController extends Controller
$data = $request->getAll(); $data = $request->getAll();
$data['start_date'] = $data['start']; $data['start_date'] = $data['start'];
$data['end_date'] = $data['end']; $data['end_date'] = $data['end'];
$data['fire_webhooks'] ??= true;
$data['budget_id'] = $budget->id; $data['budget_id'] = $budget->id;
$budgetLimit = $this->blRepository->store($data); $budgetLimit = $this->blRepository->store($data);

View File

@@ -77,6 +77,7 @@ class UpdateController extends Controller
throw new FireflyException('20028: The budget limit does not belong to the budget.'); throw new FireflyException('20028: The budget limit does not belong to the budget.');
} }
$data = $request->getAll(); $data = $request->getAll();
$data['fire_webhooks'] ??= true;
$data['budget_id'] = $budget->id; $data['budget_id'] = $budget->id;
$budgetLimit = $this->blRepository->update($budgetLimit, $data); $budgetLimit = $this->blRepository->update($budgetLimit, $data);
$manager = $this->getManager(); $manager = $this->getManager();

View File

@@ -70,7 +70,7 @@ class StoreController extends Controller
foreach ($data as $date => $rate) { foreach ($data as $date => $rate) {
$date = Carbon::createFromFormat('Y-m-d', $date); $date = Carbon::createFromFormat('Y-m-d', $date);
$existing = $this->repository->getSpecificRateOnDate($from, $to, $date); $existing = $this->repository->getSpecificRateOnDate($from, $to, $date);
if (null !== $existing) { if ($existing instanceof CurrencyExchangeRate) {
// update existing rate. // update existing rate.
$existing = $this->repository->updateExchangeRate($existing, $rate); $existing = $this->repository->updateExchangeRate($existing, $rate);
$collection->push($existing); $collection->push($existing);
@@ -101,7 +101,7 @@ class StoreController extends Controller
foreach ($data['rates'] as $key => $rate) { foreach ($data['rates'] as $key => $rate) {
$to = Amount::getTransactionCurrencyByCode($key); $to = Amount::getTransactionCurrencyByCode($key);
$existing = $this->repository->getSpecificRateOnDate($from, $to, $date); $existing = $this->repository->getSpecificRateOnDate($from, $to, $date);
if (null !== $existing) { if ($existing instanceof CurrencyExchangeRate) {
// update existing rate. // update existing rate.
$existing = $this->repository->updateExchangeRate($existing, $rate); $existing = $this->repository->updateExchangeRate($existing, $rate);
$collection->push($existing); $collection->push($existing);

View File

@@ -75,7 +75,7 @@ class TriggerController extends Controller
/** @var RuleEngineInterface $ruleEngine */ /** @var RuleEngineInterface $ruleEngine */
$ruleEngine = app(RuleEngineInterface::class); $ruleEngine = app(RuleEngineInterface::class);
$ruleEngine->setRules(new Collection([$rule])); $ruleEngine->setRules(new Collection()->push($rule));
// overrule the rule(s) if necessary. // overrule the rule(s) if necessary.
if (array_key_exists('start', $parameters) && null !== $parameters['start']) { if (array_key_exists('start', $parameters) && null !== $parameters['start']) {
@@ -129,7 +129,7 @@ class TriggerController extends Controller
/** @var RuleEngineInterface $ruleEngine */ /** @var RuleEngineInterface $ruleEngine */
$ruleEngine = app(RuleEngineInterface::class); $ruleEngine = app(RuleEngineInterface::class);
$ruleEngine->setRules(new Collection([$rule])); $ruleEngine->setRules(new Collection()->push($rule));
// overrule the rule(s) if necessary. // overrule the rule(s) if necessary.
if (array_key_exists('start', $parameters) && null !== $parameters['start']) { if (array_key_exists('start', $parameters) && null !== $parameters['start']) {

View File

@@ -133,7 +133,6 @@ class ConfigurationController extends Controller
*/ */
public function show(string $configKey): JsonResponse public function show(string $configKey): JsonResponse
{ {
$data = [];
$dynamic = $this->getDynamicConfiguration(); $dynamic = $this->getDynamicConfiguration();
$shortKey = str_replace('configuration.', '', $configKey); $shortKey = str_replace('configuration.', '', $configKey);
if (str_starts_with($configKey, 'configuration.')) { if (str_starts_with($configKey, 'configuration.')) {

View File

@@ -165,9 +165,9 @@ class ShowController extends Controller
// tell the generator which trigger it should look for // tell the generator which trigger it should look for
$engine->setTrigger(WebhookTrigger::tryFrom($webhook->trigger)); $engine->setTrigger(WebhookTrigger::tryFrom($webhook->trigger));
// tell the generator which objects to process // tell the generator which objects to process
$engine->setObjects(new Collection([$group])); $engine->setObjects(new Collection()->push($group));
// set the webhook to trigger // set the webhook to trigger
$engine->setWebhooks(new Collection([$webhook])); $engine->setWebhooks(new Collection()->push($webhook));
// tell the generator to generate the messages // tell the generator to generate the messages
$engine->generateMessages(); $engine->generateMessages();

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\Account; namespace FireflyIII\Api\V1\Requests\Models\Account;
use Illuminate\Validation\Validator;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Rules\IsValidSortInstruction; use FireflyIII\Rules\IsValidSortInstruction;
@@ -30,7 +31,6 @@ use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
class ShowRequest extends FormRequest class ShowRequest extends FormRequest

View File

@@ -48,17 +48,20 @@ class StoreRequest extends FormRequest
public function getAll(): array public function getAll(): array
{ {
$fields = [ $fields = [
'name' => ['name', 'convertString'], 'name' => ['name', 'convertString'],
'active' => ['active', 'boolean'], 'active' => ['active', 'boolean'],
'order' => ['active', 'convertInteger'], 'order' => ['active', 'convertInteger'],
'notes' => ['notes', 'convertString'], 'notes' => ['notes', 'convertString'],
// auto budget currency: // auto budget currency:
'currency_id' => ['auto_budget_currency_id', 'convertInteger'], 'currency_id' => ['auto_budget_currency_id', 'convertInteger'],
'currency_code' => ['auto_budget_currency_code', 'convertString'], 'currency_code' => ['auto_budget_currency_code', 'convertString'],
'auto_budget_type' => ['auto_budget_type', 'convertString'], 'auto_budget_type' => ['auto_budget_type', 'convertString'],
'auto_budget_amount' => ['auto_budget_amount', 'convertString'], 'auto_budget_amount' => ['auto_budget_amount', 'convertString'],
'auto_budget_period' => ['auto_budget_period', 'convertString'], 'auto_budget_period' => ['auto_budget_period', 'convertString'],
// webhooks
'fire_webhooks' => ['fire_webhooks', 'boolean'],
]; ];
return $this->getAllData($fields); return $this->getAllData($fields);
@@ -70,15 +73,18 @@ class StoreRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'name' => 'required|min:1|max:255|uniqueObjectForUser:budgets,name', 'name' => 'required|min:1|max:255|uniqueObjectForUser:budgets,name',
'active' => [new IsBoolean()], 'active' => [new IsBoolean()],
'currency_id' => 'exists:transaction_currencies,id', 'currency_id' => 'exists:transaction_currencies,id',
'currency_code' => 'exists:transaction_currencies,code', 'currency_code' => 'exists:transaction_currencies,code',
'notes' => 'nullable|min:1|max:32768', 'notes' => 'nullable|min:1|max:32768',
// auto budget info // auto budget info
'auto_budget_type' => 'in:reset,rollover,adjusted,none', '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_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_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()],
]; ];
} }

View File

@@ -50,15 +50,18 @@ class UpdateRequest extends FormRequest
{ {
// this is the way: // this is the way:
$fields = [ $fields = [
'name' => ['name', 'convertString'], 'name' => ['name', 'convertString'],
'active' => ['active', 'boolean'], 'active' => ['active', 'boolean'],
'order' => ['order', 'convertInteger'], 'order' => ['order', 'convertInteger'],
'notes' => ['notes', 'convertString'], 'notes' => ['notes', 'convertString'],
'currency_id' => ['auto_budget_currency_id', 'convertInteger'], 'currency_id' => ['auto_budget_currency_id', 'convertInteger'],
'currency_code' => ['auto_budget_currency_code', 'convertString'], 'currency_code' => ['auto_budget_currency_code', 'convertString'],
'auto_budget_type' => ['auto_budget_type', 'convertString'], 'auto_budget_type' => ['auto_budget_type', 'convertString'],
'auto_budget_amount' => ['auto_budget_amount', 'convertString'], 'auto_budget_amount' => ['auto_budget_amount', 'convertString'],
'auto_budget_period' => ['auto_budget_period', 'convertString'], 'auto_budget_period' => ['auto_budget_period', 'convertString'],
// webhooks
'fire_webhooks' => ['fire_webhooks', 'boolean'],
]; ];
$allData = $this->getAllData($fields); $allData = $this->getAllData($fields);
if (array_key_exists('auto_budget_type', $allData)) { if (array_key_exists('auto_budget_type', $allData)) {
@@ -83,14 +86,17 @@ class UpdateRequest extends FormRequest
$budget = $this->route()->parameter('budget'); $budget = $this->route()->parameter('budget');
return [ return [
'name' => sprintf('min:1|max:100|uniqueObjectForUser:budgets,name,%d', $budget->id), 'name' => sprintf('min:1|max:100|uniqueObjectForUser:budgets,name,%d', $budget->id),
'active' => [new IsBoolean()], 'active' => [new IsBoolean()],
'notes' => 'nullable|min:1|max:32768', 'notes' => 'nullable|min:1|max:32768',
'auto_budget_type' => 'in:reset,rollover,adjusted,none', 'auto_budget_type' => 'in:reset,rollover,adjusted,none',
'auto_budget_currency_id' => 'exists:transaction_currencies,id', 'auto_budget_currency_id' => 'exists:transaction_currencies,id',
'auto_budget_currency_code' => 'exists:transaction_currencies,code', 'auto_budget_currency_code' => 'exists:transaction_currencies,code',
'auto_budget_amount' => ['nullable', new IsValidPositiveAmount()], 'auto_budget_amount' => ['nullable', new IsValidPositiveAmount()],
'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly', 'auto_budget_period' => 'in:daily,weekly,monthly,quarterly,half_year,yearly',
// webhooks
'fire_webhooks' => [new IsBoolean()],
]; ];
} }

View File

@@ -24,10 +24,16 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit; namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit;
use Carbon\Carbon;
use FireflyIII\Factory\TransactionCurrencyFactory;
use FireflyIII\Rules\IsBoolean;
use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/** /**
* Class StoreRequest * Class StoreRequest
@@ -49,6 +55,9 @@ class StoreRequest extends FormRequest
'currency_id' => $this->convertInteger('currency_id'), 'currency_id' => $this->convertInteger('currency_id'),
'currency_code' => $this->convertString('currency_code'), 'currency_code' => $this->convertString('currency_code'),
'notes' => $this->stringWithNewlines('notes'), '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 public function rules(): array
{ {
return [ return [
'start' => 'required|before:end|date', 'start' => 'required|before:end|date',
'end' => 'required|after:start|date', 'end' => 'required|after:start|date',
'amount' => ['required', new IsValidPositiveAmount()], 'amount' => ['required', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
'notes' => 'nullable|min:0|max:32768', '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());
}
}
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit; namespace FireflyIII\Api\V1\Requests\Models\BudgetLimit;
use FireflyIII\Rules\IsBoolean;
use Illuminate\Validation\Validator; use Illuminate\Validation\Validator;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Rules\IsValidPositiveAmount;
@@ -46,12 +47,15 @@ class UpdateRequest extends FormRequest
public function getAll(): array public function getAll(): array
{ {
$fields = [ $fields = [
'start' => ['start', 'date'], 'start' => ['start', 'date'],
'end' => ['end', 'date'], 'end' => ['end', 'date'],
'amount' => ['amount', 'convertString'], 'amount' => ['amount', 'convertString'],
'currency_id' => ['currency_id', 'convertInteger'], 'currency_id' => ['currency_id', 'convertInteger'],
'currency_code' => ['currency_code', 'convertString'], 'currency_code' => ['currency_code', 'convertString'],
'notes' => ['notes', 'stringWithNewlines'], 'notes' => ['notes', 'stringWithNewlines'],
// webhooks
'fire_webhooks' => ['fire_webhooks', 'boolean'],
]; ];
if (false === $this->has('notes')) { if (false === $this->has('notes')) {
// ignore notes, not submitted. // ignore notes, not submitted.
@@ -67,12 +71,15 @@ class UpdateRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'date|after:1970-01-02|before:2038-01-17', 'start' => 'date|after:1970-01-02|before:2038-01-17',
'end' => 'date|after:1970-01-02|before:2038-01-17', 'end' => 'date|after:1970-01-02|before:2038-01-17',
'amount' => ['nullable', new IsValidPositiveAmount()], 'amount' => ['nullable', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
'notes' => 'nullable|min:0|max:32768', 'notes' => 'nullable|min:0|max:32768',
// webhooks
'fire_webhooks' => [new IsBoolean()],
]; ];
} }

View File

@@ -58,8 +58,8 @@ class StoreByCurrenciesRequest extends FormRequest
$data = $validator->getData(); $data = $validator->getData();
foreach ($data as $date => $rate) { foreach ($data as $date => $rate) {
try { try {
$date = Carbon::createFromFormat('Y-m-d', $date); Carbon::createFromFormat('Y-m-d', $date);
} catch (InvalidFormatException $e) { } catch (InvalidFormatException) {
$validator->errors()->add('date', trans('validation.date', ['attribute' => 'date'])); $validator->errors()->add('date', trans('validation.date', ['attribute' => 'date']));
return; return;

View File

@@ -24,13 +24,13 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate; namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
use Illuminate\Validation\Validator;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
class StoreByDateRequest extends FormRequest class StoreByDateRequest extends FormRequest
{ {
@@ -88,7 +88,7 @@ class StoreByDateRequest extends FormRequest
} }
try { try {
$to = Amount::getTransactionCurrencyByCode((string)$key); Amount::getTransactionCurrencyByCode((string)$key);
} catch (FireflyException) { } catch (FireflyException) {
$validator->errors()->add(sprintf('rates.%s', $key), trans('validation.invalid_currency_code', ['code' => $key])); $validator->errors()->add(sprintf('rates.%s', $key), trans('validation.invalid_currency_code', ['code' => $key]));
} }

View File

@@ -24,8 +24,8 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\PiggyBank; namespace FireflyIII\Api\V1\Requests\Models\PiggyBank;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Validation\Validator; use Illuminate\Validation\Validator;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsValidZeroOrMoreAmount; use FireflyIII\Rules\IsValidZeroOrMoreAmount;
@@ -97,7 +97,7 @@ class StoreRequest extends FormRequest
// validate start before end only if both are there. // validate start before end only if both are there.
$data = $validator->getData(); $data = $validator->getData();
$currency = $this->getCurrencyFromData($validator, $data); $currency = $this->getCurrencyFromData($validator, $data);
if (null === $currency) { if (!$currency instanceof TransactionCurrency) {
return; return;
} }
$targetAmount = (string) ($data['target_amount'] ?? '0'); $targetAmount = (string) ($data['target_amount'] ?? '0');

View File

@@ -183,6 +183,7 @@ class StoreRequest extends FormRequest
// basic fields for group: // basic fields for group:
'group_title' => 'min:1|max:1000|nullable', 'group_title' => 'min:1|max:1000|nullable',
'error_if_duplicate_hash' => [new IsBoolean()], 'error_if_duplicate_hash' => [new IsBoolean()],
'fire_webhooks' => [new IsBoolean()],
'apply_rules' => [new IsBoolean()], 'apply_rules' => [new IsBoolean()],
// location rules // location rules

View File

@@ -29,12 +29,15 @@ use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\AccountFactory; use FireflyIII\Factory\AccountFactory;
use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Facades\Log;
class CorrectsAccountTypes extends Command class CorrectsAccountTypes extends Command
{ {
@@ -45,6 +48,7 @@ class CorrectsAccountTypes extends Command
private int $count; private int $count;
private array $expected; private array $expected;
private AccountFactory $factory; private AccountFactory $factory;
private AccountRepositoryInterface $repository;
/** /**
* Execute the console command. * Execute the console command.
@@ -110,7 +114,7 @@ class CorrectsAccountTypes extends Command
if ($resultSet->count() > 0) { if ($resultSet->count() > 0) {
$this->friendlyLine(sprintf('Found %d journals that need to be fixed.', $resultSet->count())); $this->friendlyLine(sprintf('Found %d journals that need to be fixed.', $resultSet->count()));
foreach ($resultSet as $entry) { 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 */ /** @var null|TransactionJournal $journal */
$journal = TransactionJournal::find($entry->id); $journal = TransactionJournal::find($entry->id);
@@ -120,7 +124,7 @@ class CorrectsAccountTypes extends Command
} }
} }
if (0 !== $this->count) { 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)); $this->friendlyInfo(sprintf('Acted on %d transaction(s)', $this->count));
} }
@@ -134,10 +138,10 @@ class CorrectsAccountTypes extends Command
private function inspectJournal(TransactionJournal $journal): void 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(); $transactions = $journal->transactions()->count();
if (2 !== $transactions) { 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)); $this->friendlyError(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $transactions));
return; return;
@@ -151,20 +155,20 @@ class CorrectsAccountTypes extends Command
$destAccountType = $destAccount->accountType->type; $destAccountType = $destAccount->accountType->type;
if (!array_key_exists($type, $this->expected)) { 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)); $this->friendlyError(sprintf('No source/destination info for transaction type %s.', $type));
return; return;
} }
if (!array_key_exists($sourceAccountType, $this->expected[$type])) { 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); $this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
return; return;
} }
$expectedTypes = $this->expected[$type][$sourceAccountType]; $expectedTypes = $this->expected[$type][$sourceAccountType];
if (!in_array($destAccountType, $expectedTypes, true)) { 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); $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 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; ++$this->count;
// variables: // variables:
$sourceType = $source->account->accountType->type; $sourceType = $source->account->accountType->type;
$destinationType = $dest->account->accountType->type; $destinationType = $dest->account->accountType->type;
$combination = sprintf('%s%s%s', $transactionType, $source->account->accountType->type, $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)); Log::debug(sprintf('Combination is "%s"', $combination));
if ($this->shouldBeTransfer($transactionType, $sourceType, $destinationType)) { if ($this->shouldBeTransfer($transactionType, $sourceType, $destinationType)) {
$this->makeTransfer($journal); $this->makeTransfer($journal);
@@ -211,37 +217,45 @@ class CorrectsAccountTypes extends Command
} }
// transaction has no valid source. // transaction has no valid source.
$validSources = array_keys($this->expected[$transactionType]); $validSources = array_keys($this->expected[$transactionType]);
$canCreateSource = $this->canCreateSource($validSources); $canCreateSource = $this->canCreateSource($validSources);
$hasValidSource = $this->hasValidAccountType($validSources, $sourceType); $hasValidSource = $this->hasValidAccountType($validSources, $sourceType);
if (!$hasValidSource && $canCreateSource) { if (!$hasValidSource && $canCreateSource) {
$this->giveNewRevenue($journal, $source); $this->giveNewRevenue($journal, $source);
return; return;
} }
if (!$canCreateSource && !$hasValidSource) { 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); $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); $this->friendlyError($message);
app('log')->debug($message); Log::debug($message);
return; return;
} }
/** @var array $validDestinations */ /** @var array $validDestinations */
$validDestinations = $this->expected[$transactionType][$sourceType] ?? []; $validDestinations = $this->expected[$transactionType][$sourceType] ?? [];
$canCreateDestination = $this->canCreateDestination($validDestinations); $canCreateDestination = $this->canCreateDestination($validDestinations);
$hasValidDestination = $this->hasValidAccountType($validDestinations, $destinationType); $hasValidDestination = $this->hasValidAccountType($validDestinations, $destinationType);
$alternativeDestination = $this->repository->findByName($dest->account->name, $validDestinations);
if (!$hasValidDestination && $canCreateDestination) { if (!$hasValidDestination && $canCreateDestination) {
$this->giveNewExpense($journal, $dest); $this->giveNewExpense($journal, $dest);
return; return;
} }
if (!$canCreateDestination && !$hasValidDestination) { if (!$canCreateDestination && !$hasValidDestination && null === $alternativeDestination) {
app('log')->debug('This transaction type has no destination we can create. Just give error.'); 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); $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); $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(); $journal->save();
$message = sprintf('Converted transaction #%d from a transfer to a withdrawal.', $journal->id); $message = sprintf('Converted transaction #%d from a transfer to a withdrawal.', $journal->id);
$this->friendlyInfo($message); $this->friendlyInfo($message);
app('log')->debug($message); Log::debug($message);
// check it again: // check it again:
$this->inspectJournal($journal); $this->inspectJournal($journal);
} }
@@ -281,7 +295,7 @@ class CorrectsAccountTypes extends Command
$journal->save(); $journal->save();
$message = sprintf('Converted transaction #%d from a transfer to a deposit.', $journal->id); $message = sprintf('Converted transaction #%d from a transfer to a deposit.', $journal->id);
$this->friendlyInfo($message); $this->friendlyInfo($message);
app('log')->debug($message); Log::debug($message);
// check it again: // check it again:
$this->inspectJournal($journal); $this->inspectJournal($journal);
} }
@@ -308,7 +322,7 @@ class CorrectsAccountTypes extends Command
$result->name $result->name
); );
$this->friendlyWarning($message); $this->friendlyWarning($message);
app('log')->debug($message); Log::debug($message);
$this->inspectJournal($journal); $this->inspectJournal($journal);
} }
@@ -335,7 +349,7 @@ class CorrectsAccountTypes extends Command
$result->name $result->name
); );
$this->friendlyWarning($message); $this->friendlyWarning($message);
app('log')->debug($message); Log::debug($message);
$this->inspectJournal($journal); $this->inspectJournal($journal);
} }
@@ -354,14 +368,14 @@ class CorrectsAccountTypes extends Command
private function giveNewRevenue(TransactionJournal $journal, Transaction $source): void 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); $this->factory->setUser($journal->user);
$name = $source->account->name; $name = $source->account->name;
$newSource = $this->factory->findOrCreate($name, AccountTypeEnum::REVENUE->value); $newSource = $this->factory->findOrCreate($name, AccountTypeEnum::REVENUE->value);
$source->account()->associate($newSource); $source->account()->associate($newSource);
$source->save(); $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)); $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); $this->inspectJournal($journal);
} }
@@ -372,14 +386,33 @@ class CorrectsAccountTypes extends Command
private function giveNewExpense(TransactionJournal $journal, Transaction $destination): void 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); $this->factory->setUser($journal->user);
$name = $destination->account->name; $name = $destination->account->name;
$newDestination = $this->factory->findOrCreate($name, AccountTypeEnum::EXPENSE->value); $newDestination = $this->factory->findOrCreate($name, AccountTypeEnum::EXPENSE->value);
$destination->account()->associate($newDestination); $destination->account()->associate($newDestination);
$destination->save(); $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)); $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); $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);
}
} }

View File

@@ -75,7 +75,8 @@ class CorrectsDatabase extends Command
'correction:recalculates-liabilities', 'correction:recalculates-liabilities',
'correction:preferences', 'correction:preferences',
// 'correction:transaction-types', // resource heavy, disabled. // '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', 'firefly-iii:report-integrity',
]; ];
foreach ($commands as $command) { foreach ($commands as $command) {

View File

@@ -57,8 +57,6 @@ class CorrectsPiggyBanks extends Command
$event->transaction_journal_id = null; $event->transaction_journal_id = null;
$event->save(); $event->save();
++$count; ++$count;
continue;
} }
} }
if (0 !== $count) { if (0 !== $count) {

View 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));
}
}
}

View File

@@ -71,7 +71,6 @@ class RestoresOAuthKeys extends Command
$this->storeKeysInDB(); $this->storeKeysInDB();
$this->friendlyInfo('Stored OAuth keys in database.'); $this->friendlyInfo('Stored OAuth keys in database.');
return;
} }
} }

View File

@@ -515,7 +515,7 @@ class ForcesDecimalSize extends Command
continue; continue;
} }
// fix $field by rounding it down correctly. // 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); $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)); $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; continue;
} }
// fix $field by rounding it down correctly. // 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); $correct = bcdiv((string) round((float) $value * $pow), (string) $pow, 12);
$this->friendlyWarning( $this->friendlyWarning(
sprintf('Transaction #%d has foreign amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct) sprintf('Transaction #%d has foreign amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct)

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Console\Commands\System;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Support\System\GeneratesInstallationId; use FireflyIII\Support\System\GeneratesInstallationId;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Random\RandomException;
class OutputsInstructions extends Command class OutputsInstructions extends Command
{ {
@@ -266,7 +267,11 @@ class OutputsInstructions extends Command
]; ];
} }
$random = random_int(0, count($lines) - 1); try {
$random = random_int(0, count($lines) - 1);
} catch (RandomException) {
$random = 0;
}
if ($addQuotes) { if ($addQuotes) {
$this->line(sprintf(' "%s"', $lines[$random])); $this->line(sprintf(' "%s"', $lines[$random]));

View File

@@ -157,7 +157,6 @@ class UpgradesLiabilitiesEight extends Command
$service = new TransactionGroupDestroyService(); $service = new TransactionGroupDestroyService();
$service->destroy($group); $service->destroy($group);
return;
} }
} }

View File

@@ -128,10 +128,6 @@ class GracefulNotFoundHandler extends ExceptionHandler
return redirect(route('categories.index')); return redirect(route('categories.index'));
case 'rules.edit': case 'rules.edit':
$request->session()->reflash();
return redirect(route('rules.index'));
case 'rule-groups.edit': case 'rule-groups.edit':
$request->session()->reflash(); $request->session()->reflash();

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Factory;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -42,7 +43,7 @@ class TransactionCurrencyFactory
$data['code'] = e($data['code']); $data['code'] = e($data['code']);
$data['symbol'] = e($data['symbol']); $data['symbol'] = e($data['symbol']);
$data['name'] = e($data['name']); $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) // if the code already exists (deleted)
// force delete it and then create the transaction: // force delete it and then create the transaction:
$count = TransactionCurrency::withTrashed()->whereCode($data['code'])->count(); $count = TransactionCurrency::withTrashed()->whereCode($data['code'])->count();
@@ -77,7 +78,8 @@ class TransactionCurrencyFactory
public function find(?int $currencyId, ?string $currencyCode): ?TransactionCurrency public function find(?int $currencyId, ?string $currencyCode): ?TransactionCurrency
{ {
$currencyCode = e($currencyCode); $currencyCode = e($currencyCode);
$currencyId = (int) $currencyId; $currencyId = (int)$currencyId;
$currency = null;
if ('' === $currencyCode && 0 === $currencyId) { if ('' === $currencyCode && 0 === $currencyId) {
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!');
@@ -87,22 +89,22 @@ class TransactionCurrencyFactory
// first by ID: // first by ID:
if ($currencyId > 0) { if ($currencyId > 0) {
$currency = TransactionCurrency::find($currencyId); try {
if (null !== $currency) { $currency = Amount::getTransactionCurrencyById($currencyId);
return $currency; } catch (FireflyException) {
Log::warning(sprintf('Currency ID is #%d but found nothing!', $currencyId));
} }
Log::warning(sprintf('Currency ID is %d but found nothing!', $currencyId));
} }
// then by code: // then by code:
if ('' !== $currencyCode) { if ('' !== $currencyCode && null === $currency) {
$currency = TransactionCurrency::whereCode($currencyCode)->first(); try {
if (null !== $currency) { $currency = Amount::getTransactionCurrencyByCode($currencyCode);
return $currency; } catch (FireflyException) {
Log::warning(sprintf('Currency code is "%s" but found nothing!', $currencyCode));
} }
Log::warning(sprintf('Currency code is %d but found nothing!', $currencyCode));
} }
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;
} }
} }

View File

@@ -222,7 +222,7 @@ class TransactionJournalFactory
Log::debug('Source info:', $sourceInfo); Log::debug('Source info:', $sourceInfo);
Log::debug('Destination info:', $destInfo); Log::debug('Destination info:', $destInfo);
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo); $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)'); Log::debug('Done with getAccount(2x)');
@@ -270,7 +270,7 @@ class TransactionJournalFactory
$negative = $transactionFactory->createNegative((string) $row['amount'], (string) $row['foreign_amount']); $negative = $transactionFactory->createNegative((string) $row['amount'], (string) $row['foreign_amount']);
} catch (FireflyException $e) { } catch (FireflyException $e) {
Log::error(sprintf('Exception creating negative transaction: %s', $e->getMessage())); 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); throw new FireflyException($e->getMessage(), 0, $e);
} }
@@ -305,7 +305,7 @@ class TransactionJournalFactory
} catch (FireflyException $e) { } catch (FireflyException $e) {
Log::error(sprintf('Exception creating positive transaction: %s', $e->getMessage())); Log::error(sprintf('Exception creating positive transaction: %s', $e->getMessage()));
$this->forceTrDelete($negative); $this->forceTrDelete($negative);
$this->forceDeleteOnError(new Collection([$journal])); $this->forceDeleteOnError(new Collection()->push($journal));
throw new FireflyException($e->getMessage(), 0, $e); throw new FireflyException($e->getMessage(), 0, $e);
} }

View File

@@ -132,7 +132,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $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() ->withBudgetInformation()->withCategoryInformation()->withBillInformation()->withNotes()
; ;
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();

View File

@@ -32,7 +32,6 @@ use FireflyIII\Notifications\Admin\UserInvitation;
use FireflyIII\Notifications\Admin\VersionCheckResult; use FireflyIII\Notifications\Admin\VersionCheckResult;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable; use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Notifications\Test\OwnerTestNotificationEmail; use FireflyIII\Notifications\Test\OwnerTestNotificationEmail;
use FireflyIII\Notifications\Test\OwnerTestNotificationNtfy;
use FireflyIII\Notifications\Test\OwnerTestNotificationPushover; use FireflyIII\Notifications\Test\OwnerTestNotificationPushover;
use FireflyIII\Notifications\Test\OwnerTestNotificationSlack; use FireflyIII\Notifications\Test\OwnerTestNotificationSlack;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;

View File

@@ -52,7 +52,7 @@ class DestroyedGroupEventHandler
/** @var MessageGeneratorInterface $engine */ /** @var MessageGeneratorInterface $engine */
$engine = app(MessageGeneratorInterface::class); $engine = app(MessageGeneratorInterface::class);
$engine->setUser($user); $engine->setUser($user);
$engine->setObjects(new Collection([$group])); $engine->setObjects(new Collection()->push($group));
$engine->setTrigger(WebhookTrigger::DESTROY_TRANSACTION); $engine->setTrigger(WebhookTrigger::DESTROY_TRANSACTION);
$engine->generateMessages(); $engine->generateMessages();
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__)); Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__));

View File

@@ -116,7 +116,7 @@ class StoredGroupEventHandler
// tell the generator which trigger it should look for // tell the generator which trigger it should look for
$engine->setTrigger(WebhookTrigger::STORE_TRANSACTION); $engine->setTrigger(WebhookTrigger::STORE_TRANSACTION);
// tell the generator which objects to process // 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 // tell the generator to generate the messages
$engine->generateMessages(); $engine->generateMessages();

View File

@@ -163,7 +163,7 @@ class UpdatedGroupEventHandler
/** @var MessageGeneratorInterface $engine */ /** @var MessageGeneratorInterface $engine */
$engine = app(MessageGeneratorInterface::class); $engine = app(MessageGeneratorInterface::class);
$engine->setUser($user); $engine->setUser($user);
$engine->setObjects(new Collection([$group])); $engine->setObjects(new Collection()->push($group));
$engine->setTrigger(WebhookTrigger::UPDATE_TRANSACTION); $engine->setTrigger(WebhookTrigger::UPDATE_TRANSACTION);
$engine->generateMessages(); $engine->generateMessages();

View File

@@ -44,7 +44,6 @@ use FireflyIII\Models\UserRole;
use FireflyIII\Notifications\Admin\UserRegistration as AdminRegistrationNotification; use FireflyIII\Notifications\Admin\UserRegistration as AdminRegistrationNotification;
use FireflyIII\Notifications\Security\UserFailedLoginAttempt; use FireflyIII\Notifications\Security\UserFailedLoginAttempt;
use FireflyIII\Notifications\Test\UserTestNotificationEmail; use FireflyIII\Notifications\Test\UserTestNotificationEmail;
use FireflyIII\Notifications\Test\UserTestNotificationNtfy;
use FireflyIII\Notifications\Test\UserTestNotificationPushover; use FireflyIII\Notifications\Test\UserTestNotificationPushover;
use FireflyIII\Notifications\Test\UserTestNotificationSlack; use FireflyIII\Notifications\Test\UserTestNotificationSlack;
use FireflyIII\Notifications\User\UserLogin; use FireflyIII\Notifications\User\UserLogin;

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\BudgetLimit;
use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter; use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Observers\RecalculatesAvailableBudgetsTrait; use FireflyIII\Support\Observers\RecalculatesAvailableBudgetsTrait;
use FireflyIII\Support\Singleton\PreferencesSingleton;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -44,17 +45,24 @@ class BudgetLimitObserver
$this->updatePrimaryCurrencyAmount($budgetLimit); $this->updatePrimaryCurrencyAmount($budgetLimit);
$this->updateAvailableBudget($budgetLimit); $this->updateAvailableBudget($budgetLimit);
$user = $budgetLimit->budget->user;
/** @var MessageGeneratorInterface $engine */ // this is a lame trick to communicate with the observer.
$engine = app(MessageGeneratorInterface::class); $singleton = PreferencesSingleton::getInstance();
$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__)); if (true === $singleton->getPreference('fire_webhooks_bl_store')) {
event(new RequestedSendWebhookMessages());
$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 private function updatePrimaryCurrencyAmount(BudgetLimit $budgetLimit): void
@@ -82,16 +90,21 @@ class BudgetLimitObserver
$this->updatePrimaryCurrencyAmount($budgetLimit); $this->updatePrimaryCurrencyAmount($budgetLimit);
$this->updateAvailableBudget($budgetLimit); $this->updateAvailableBudget($budgetLimit);
$user = $budgetLimit->budget->user; // this is a lame trick to communicate with the observer.
$singleton = PreferencesSingleton::getInstance();
/** @var MessageGeneratorInterface $engine */ if (true === $singleton->getPreference('fire_webhooks_bl_update')) {
$engine = app(MessageGeneratorInterface::class); $user = $budgetLimit->budget->user;
$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__)); /** @var MessageGeneratorInterface $engine */
event(new RequestedSendWebhookMessages()); $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());
}
} }
} }

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface; use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Support\Observers\RecalculatesAvailableBudgetsTrait; use FireflyIII\Support\Observers\RecalculatesAvailableBudgetsTrait;
use FireflyIII\Support\Singleton\PreferencesSingleton;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -45,32 +46,43 @@ class BudgetObserver
{ {
Log::debug(sprintf('Observe "created" of budget #%d ("%s").', $budget->id, $budget->name)); Log::debug(sprintf('Observe "created" of budget #%d ("%s").', $budget->id, $budget->name));
// fire event. // this is a lame trick to communicate with the observer.
$user = $budget->user; $singleton = PreferencesSingleton::getInstance();
/** @var MessageGeneratorInterface $engine */ if (true === $singleton->getPreference('fire_webhooks_budget_create')) {
$engine = app(MessageGeneratorInterface::class); // fire event.
$engine->setUser($user); $user = $budget->user;
$engine->setObjects(new Collection()->push($budget));
$engine->setTrigger(WebhookTrigger::STORE_BUDGET); /** @var MessageGeneratorInterface $engine */
$engine->generateMessages(); $engine = app(MessageGeneratorInterface::class);
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__)); $engine->setUser($user);
event(new RequestedSendWebhookMessages()); $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 public function updated(Budget $budget): void
{ {
Log::debug(sprintf('Observe "updated" of budget #%d ("%s").', $budget->id, $budget->name)); Log::debug(sprintf('Observe "updated" of budget #%d ("%s").', $budget->id, $budget->name));
$user = $budget->user;
/** @var MessageGeneratorInterface $engine */ // this is a lame trick to communicate with the observer.
$engine = app(MessageGeneratorInterface::class); $singleton = PreferencesSingleton::getInstance();
$engine->setUser($user);
$engine->setObjects(new Collection()->push($budget)); if (true === $singleton->getPreference('fire_webhooks_budget_update')) {
$engine->setTrigger(WebhookTrigger::UPDATE_BUDGET); $user = $budget->user;
$engine->generateMessages();
Log::debug(sprintf('send event RequestedSendWebhookMessages from %s', __METHOD__)); /** @var MessageGeneratorInterface $engine */
event(new RequestedSendWebhookMessages()); $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 public function deleting(Budget $budget): void

View File

@@ -94,7 +94,7 @@ trait AttachmentCollection
static function (EloquentBuilder $q1): void { // @phpstan-ignore-line static function (EloquentBuilder $q1): void { // @phpstan-ignore-line
$q1->where('attachments.attachable_type', TransactionJournal::class); $q1->where('attachments.attachable_type', TransactionJournal::class);
// $q1->where('attachments.uploaded', true); // $q1->where('attachments.uploaded', true);
$q1->whereNull('attachments.deleted_at'); // $q1->whereNull('attachments.deleted_at');
$q1->orWhereNull('attachments.attachable_type'); $q1->orWhereNull('attachments.attachable_type');
} }
) )
@@ -107,6 +107,7 @@ trait AttachmentCollection
$this->fields[] = 'attachments.id as attachment_id'; $this->fields[] = 'attachments.id as attachment_id';
$this->fields[] = 'attachments.filename as attachment_filename'; $this->fields[] = 'attachments.filename as attachment_filename';
$this->fields[] = 'attachments.title as attachment_title'; $this->fields[] = 'attachments.title as attachment_title';
$this->fields[] = 'attachments.deleted_at as attachment_deleted_at';
$this->fields[] = 'attachments.uploaded as attachment_uploaded'; $this->fields[] = 'attachments.uploaded as attachment_uploaded';
$this->joinAttachmentTables(); $this->joinAttachmentTables();

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Collector\Extensions; namespace FireflyIII\Helpers\Collector\Extensions;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
@@ -597,16 +598,16 @@ trait MetaCollection
$foundTagCount = 0; $foundTagCount = 0;
foreach ($object['transactions'] as $transaction) { foreach ($object['transactions'] as $transaction) {
$transactionTagCount = count($transaction['tags']); $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) { 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; return false;
} }
foreach ($transaction['tags'] as $tag) { foreach ($transaction['tags'] as $tag) {
Log::debug(sprintf('"%s" versus', strtolower((string) $tag['name'])), $list); Log::debug(sprintf('"%s" versus', strtolower((string) $tag['name'])), $list);
if (in_array(strtolower((string) $tag['name']), $list, true)) { 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; ++$foundTagCount;
$journalId = $transaction['transaction_journal_id']; $journalId = $transaction['transaction_journal_id'];
// #8377 prevent adding a transaction twice when multiple tag searches find this transaction // #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 public function setTag(Tag $tag): GroupCollectorInterface
{ {
$this->withTagInformation(); $this->withTagInformation();
$this->setTags(new Collection([$tag])); $this->setTags(new Collection()->push($tag));
return $this; return $this;
} }
@@ -775,6 +776,9 @@ trait MetaCollection
$this->withTagInformation(); $this->withTagInformation();
$this->query->whereNotNull('tag_transaction_journal.tag_id'); $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. // this method adds a "postFilter" to the collector.
$list = $tags->pluck('tag')->toArray(); $list = $tags->pluck('tag')->toArray();
$list = array_map('strtolower', $list); $list = array_map('strtolower', $list);
@@ -784,13 +788,13 @@ trait MetaCollection
foreach ($transaction['tags'] as $tag) { foreach ($transaction['tags'] as $tag) {
Log::debug(sprintf('"%s" versus', strtolower((string) $tag['name'])), $list); Log::debug(sprintf('"%s" versus', strtolower((string) $tag['name'])), $list);
if (in_array(strtolower((string) $tag['name']), $list, true)) { 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; 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; return false;
}; };
@@ -812,11 +816,11 @@ trait MetaCollection
$filter = static function (array $object) use ($list): bool { $filter = static function (array $object) use ($list): bool {
Log::debug(sprintf('Now in setWithoutSpecificTags(%s) filter', implode(', ', $list))); Log::debug(sprintf('Now in setWithoutSpecificTags(%s) filter', implode(', ', $list)));
foreach ($object['transactions'] as $transaction) { 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) { foreach ($transaction['tags'] as $tag) {
Log::debug(sprintf('"%s" versus', strtolower((string) $tag['name'])), $list); Log::debug(sprintf('"%s" versus', strtolower((string) $tag['name'])), $list);
if (in_array(strtolower((string) $tag['name']), $list, true)) { 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; return false;
} }
@@ -919,6 +923,8 @@ trait MetaCollection
{ {
$this->withCategoryInformation(); $this->withCategoryInformation();
$this->query->whereNull('category_transaction_journal.category_id'); $this->query->whereNull('category_transaction_journal.category_id');
// better fix for #10507
$this->query->whereNotIn('transaction_types.type', [TransactionTypeEnum::OPENING_BALANCE->value]);
return $this; return $this;
} }

View File

@@ -560,7 +560,7 @@ class GroupCollector implements GroupCollectorInterface
} }
$groups = $this->parseSums($groups); $groups = $this->parseSums($groups);
return new Collection($groups); return new Collection()->push(...$groups);
} }
/** /**
@@ -631,10 +631,11 @@ class GroupCollector implements GroupCollectorInterface
} }
// also merge attachments: // also merge attachments:
if (array_key_exists('attachment_id', $result)) { if (array_key_exists('attachment_id', $result) && null !== $result['attachment_id']) {
$uploaded = 1 === (int)$result['attachment_uploaded']; $uploaded = 1 === (int)$result['attachment_uploaded'];
$attachmentId = (int)$augumentedJournal['attachment_id']; $attachmentId = (int)$augumentedJournal['attachment_id'];
if (0 !== $attachmentId && $uploaded) { $deleted = null !== $result['attachment_deleted_at'];
if (0 !== $attachmentId && $uploaded && !$deleted) {
$result['attachments'][$attachmentId] = [ $result['attachments'][$attachmentId] = [
'id' => $attachmentId, 'id' => $attachmentId,
'filename' => $augumentedJournal['attachment_filename'], 'filename' => $augumentedJournal['attachment_filename'],
@@ -659,7 +660,7 @@ class GroupCollector implements GroupCollectorInterface
private function convertToInteger(array $array): array private function convertToInteger(array $array): array
{ {
foreach ($this->integerFields as $field) { 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; return $array;
@@ -1095,9 +1096,6 @@ class GroupCollector implements GroupCollectorInterface
->whereNull('transaction_groups.deleted_at') ->whereNull('transaction_groups.deleted_at')
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
->whereNull('source.deleted_at') ->whereNull('source.deleted_at')
// #10507 ignore opening balance.
->where('transaction_types.type', '!=', TransactionTypeEnum::OPENING_BALANCE->value)
->whereNotNull('transaction_groups.id') ->whereNotNull('transaction_groups.id')
->whereNull('destination.deleted_at') ->whereNull('destination.deleted_at')
->orderBy('transaction_journals.date', 'DESC') ->orderBy('transaction_journals.date', 'DESC')
@@ -1177,7 +1175,8 @@ class GroupCollector implements GroupCollectorInterface
// include budget ID + name (if any) // include budget ID + name (if any)
->withBudgetInformation() ->withBudgetInformation()
// include bill ID + name (if any) // include bill ID + name (if any)
->withBillInformation(); ->withBillInformation()
;
return $this; return $this;
} }

View File

@@ -31,7 +31,6 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\UserGroup; use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
@@ -49,7 +48,6 @@ use Illuminate\Support\Facades\Log;
class NetWorth implements NetWorthInterface class NetWorth implements NetWorthInterface
{ {
private AccountRepositoryInterface $accountRepository; private AccountRepositoryInterface $accountRepository;
private CurrencyRepositoryInterface $currencyRepos;
private User $user; // @phpstan-ignore-line private User $user; // @phpstan-ignore-line
private ?UserGroup $userGroup = null; private ?UserGroup $userGroup = null;
@@ -131,8 +129,6 @@ class NetWorth implements NetWorthInterface
$this->accountRepository = app(AccountRepositoryInterface::class); $this->accountRepository = app(AccountRepositoryInterface::class);
$this->accountRepository->setUserGroup($userGroup); $this->accountRepository->setUserGroup($userGroup);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->currencyRepos->setUserGroup($this->userGroup);
} }
#[Deprecated] #[Deprecated]

View File

@@ -45,7 +45,7 @@ class PopupReport implements PopupReportInterface
{ {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account])) $collector->setAccounts(new Collection()->push($account))
->withAccountInformation() ->withAccountInformation()
->withBudgetInformation() ->withBudgetInformation()
->withCategoryInformation() ->withCategoryInformation()
@@ -72,7 +72,7 @@ class PopupReport implements PopupReportInterface
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector $collector
->setAccounts(new Collection([$account])) ->setAccounts(new Collection()->push($account))
->setTypes([TransactionTypeEnum::WITHDRAWAL->value]) ->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
->withAccountInformation() ->withAccountInformation()
->withCategoryInformation() ->withCategoryInformation()
@@ -191,7 +191,7 @@ class PopupReport implements PopupReportInterface
// $set = $attributes['accounts'] ?? new Collection; // $set = $attributes['accounts'] ?? new Collection;
// $set->push($account); // $set->push($account);
$collector->setDestinationAccounts(new Collection([$account])) $collector->setDestinationAccounts(new Collection()->push($account))
->setRange($attributes['startDate'], $attributes['endDate']) ->setRange($attributes['startDate'], $attributes['endDate'])
->withAccountInformation() ->withAccountInformation()
->withBudgetInformation() ->withBudgetInformation()
@@ -218,7 +218,7 @@ class PopupReport implements PopupReportInterface
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector $collector
->setSourceAccounts(new Collection([$account])) ->setSourceAccounts(new Collection()->push($account))
->setDestinationAccounts($attributes['accounts']) ->setDestinationAccounts($attributes['accounts'])
->setRange($attributes['startDate'], $attributes['endDate']) ->setRange($attributes['startDate'], $attributes['endDate'])
->setTypes([TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::TRANSFER->value]) ->setTypes([TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::TRANSFER->value])

View File

@@ -86,7 +86,7 @@ class CreateController extends Controller
'latitude' => $hasOldInput ? old('location_latitude') : config('firefly.default_location.latitude'), 'latitude' => $hasOldInput ? old('location_latitude') : config('firefly.default_location.latitude'),
'longitude' => $hasOldInput ? old('location_longitude') : config('firefly.default_location.longitude'), 'longitude' => $hasOldInput ? old('location_longitude') : config('firefly.default_location.longitude'),
'zoom_level' => $hasOldInput ? old('location_zoom_level') : config('firefly.default_location.zoom_level'), '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 = [ $liabilityDirections = [
@@ -106,7 +106,7 @@ class CreateController extends Controller
'preFilled', 'preFilled',
[ [
'currency_id' => $this->primaryCurrency->id, '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 // issue #8321

View File

@@ -143,7 +143,7 @@ class ShowController extends Controller
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector $collector
->setAccounts(new Collection([$account])) ->setAccounts(new Collection()->push($account))
->setLimit($pageSize) ->setLimit($pageSize)
->setPage($page) ->setPage($page)
->withAttachmentInformation() ->withAttachmentInformation()
@@ -221,7 +221,7 @@ class ShowController extends Controller
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $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) // this search will not include transaction groups where this asset account (or liability)
// is just part of ONE of the journals. To force this: // is just part of ONE of the journals. To force this:

View File

@@ -122,6 +122,11 @@ class NotificationController extends Controller
public function testNotification(Request $request): RedirectResponse 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(); $all = $request->all();
$channel = $all['test_submit'] ?? ''; $channel = $all['test_submit'] ?? '';

View File

@@ -203,7 +203,7 @@ class BudgetLimitController extends Controller
if ($request->expectsJson()) { if ($request->expectsJson()) {
$array = $limit->toArray(); $array = $limit->toArray();
// add some extra metadata: // 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['spent'] = $spentArr[$currency->id]['sum'] ?? '0';
$array['left_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, bcadd($array['spent'], (string) $array['amount'])); $array['left_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, bcadd($array['spent'], (string) $array['amount']));
$array['amount_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, $limit['amount']); $array['amount_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, $limit['amount']);
@@ -264,7 +264,7 @@ class BudgetLimitController extends Controller
$limit->start_date, $limit->start_date,
$limit->end_date, $limit->end_date,
null, null,
new Collection([$budgetLimit->budget]), new Collection()->push($budgetLimit->budget),
$budgetLimit->transactionCurrency $budgetLimit->transactionCurrency
); );
$daysLeft = $this->activeDaysLeft($limit->start_date, $limit->end_date); $daysLeft = $this->activeDaysLeft($limit->start_date, $limit->end_date);

View File

@@ -235,7 +235,7 @@ class IndexController extends Controller
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
foreach ($currencies as $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])) { 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]['spent'] = $spentArr[$currency->id]['sum'];
$array['spent'][$currency->id]['currency_id'] = $currency->id; $array['spent'][$currency->id]['currency_id'] = $currency->id;

View File

@@ -235,7 +235,7 @@ class AccountController extends Controller
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account])) $collector->setAccounts(new Collection()->push($account))
->setRange($start, $end) ->setRange($start, $end)
->withBudgetInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value]) ->withBudgetInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
; ;
@@ -322,7 +322,7 @@ class AccountController extends Controller
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $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(); $journals = $collector->getExtractedJournals();
$result = []; $result = [];
$chartData = []; $chartData = [];
@@ -429,7 +429,7 @@ class AccountController extends Controller
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $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(); $journals = $collector->getExtractedJournals();
$result = []; $result = [];
$chartData = []; $chartData = [];

View File

@@ -100,7 +100,7 @@ class BudgetController extends Controller
return response()->json($cache->get()); return response()->json($cache->get());
} }
$step = $this->calculateStep($start, $end); // depending on diff, do something with range of chart. $step = $this->calculateStep($start, $end); // depending on diff, do something with range of chart.
$collection = new Collection([$budget]); $collection = new Collection()->push($budget);
$chartData = []; $chartData = [];
$loopStart = clone $start; $loopStart = clone $start;
$loopStart = Navigation::startOfPeriod($loopStart, $step); $loopStart = Navigation::startOfPeriod($loopStart, $step);
@@ -169,7 +169,7 @@ class BudgetController extends Controller
$locale = app('steam')->getLocale(); $locale = app('steam')->getLocale();
$entries = []; $entries = [];
$amount = $budgetLimit->amount ?? '0'; $amount = $budgetLimit->amount ?? '0';
$budgetCollection = new Collection([$budget]); $budgetCollection = new Collection()->push($budget);
$currency = $budgetLimit->transactionCurrency; $currency = $budgetLimit->transactionCurrency;
if ($this->convertToPrimary) { if ($this->convertToPrimary) {
$amount = $budgetLimit->native_amount ?? $amount; $amount = $budgetLimit->native_amount ?? $amount;
@@ -535,7 +535,7 @@ class BudgetController extends Controller
} }
// get spent amount in this period for this currency. // 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'); $amount = app('steam')->positive($sum[$currency->id]['sum'] ?? '0');
$chartData[0]['entries'][$title] = app('steam')->bcround($amount, $currency->decimal_places); $chartData[0]['entries'][$title] = app('steam')->bcround($amount, $currency->decimal_places);

View File

@@ -163,7 +163,7 @@ class BudgetReportController extends Controller
public function mainChart(Collection $accounts, Budget $budget, Carbon $start, Carbon $end): JsonResponse public function mainChart(Collection $accounts, Budget $budget, Carbon $start, Carbon $end): JsonResponse
{ {
$chartData = []; $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); $format = Navigation::preferredCarbonLocalizedFormat($start, $end);
// loop expenses. // loop expenses.

View File

@@ -174,7 +174,7 @@ class CategoryController extends Controller
$opsRepository = app(OperationsRepositoryInterface::class); $opsRepository = app(OperationsRepositoryInterface::class);
$categoryId = $category->id; $categoryId = $category->id;
// this gives us all currencies // this gives us all currencies
$collection = new Collection([$category]); $collection = new Collection()->push($category);
$expenses = $opsRepository->listExpenses($start, $end, $accounts, $collection); $expenses = $opsRepository->listExpenses($start, $end, $accounts, $collection);
$income = $opsRepository->listIncome($start, $end, $accounts, $collection); $income = $opsRepository->listIncome($start, $end, $accounts, $collection);
} }

View File

@@ -208,8 +208,8 @@ class CategoryReportController extends Controller
public function mainChart(Collection $accounts, Category $category, Carbon $start, Carbon $end): JsonResponse public function mainChart(Collection $accounts, Category $category, Carbon $start, Carbon $end): JsonResponse
{ {
$chartData = []; $chartData = [];
$spent = $this->opsRepository->listExpenses($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([$category])); $earned = $this->opsRepository->listIncome($start, $end, $accounts, new Collection()->push($category));
$format = app('navigation')->preferredCarbonLocalizedFormat($start, $end); $format = app('navigation')->preferredCarbonLocalizedFormat($start, $end);
// loop expenses. // loop expenses.
foreach ($spent as $currency) { foreach ($spent as $currency) {

View File

@@ -150,7 +150,7 @@ class DoubleReportController extends Controller
{ {
$chartData = []; $chartData = [];
$opposing = $this->repository->expandWithDoubles(new Collection([$account])); $opposing = $this->repository->expandWithDoubles(new Collection()->push($account));
$accounts = $accounts->merge($opposing); $accounts = $accounts->merge($opposing);
$spent = $this->opsRepository->listExpenses($start, $end, $accounts); $spent = $this->opsRepository->listExpenses($start, $end, $accounts);
$earned = $this->opsRepository->listIncome($start, $end, $accounts); $earned = $this->opsRepository->listIncome($start, $end, $accounts);

View File

@@ -212,8 +212,8 @@ class TagReportController extends Controller
public function mainChart(Collection $accounts, Tag $tag, Carbon $start, Carbon $end): JsonResponse public function mainChart(Collection $accounts, Tag $tag, Carbon $start, Carbon $end): JsonResponse
{ {
$chartData = []; $chartData = [];
$spent = $this->opsRepository->listExpenses($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([$tag])); $earned = $this->opsRepository->listIncome($start, $end, $accounts, new Collection()->push($tag));
$format = app('navigation')->preferredCarbonLocalizedFormat($start, $end); $format = app('navigation')->preferredCarbonLocalizedFormat($start, $end);
// loop expenses. // loop expenses.

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Http\Controllers;
use FireflyIII\Events\RequestedSendWebhookMessages; use FireflyIII\Events\RequestedSendWebhookMessages;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\RequestInformation; use FireflyIII\Support\Http\Controllers\RequestInformation;
use FireflyIII\Support\Http\Controllers\UserNavigation; use FireflyIII\Support\Http\Controllers\UserNavigation;
@@ -133,7 +134,7 @@ abstract class Controller extends BaseController
$this->primaryCurrency = Amount::getPrimaryCurrency(); $this->primaryCurrency = Amount::getPrimaryCurrency();
$language = Steam::getLanguage(); $language = Steam::getLanguage();
$locale = Steam::getLocale(); $locale = Steam::getLocale();
$darkMode = app('preferences')->get('darkMode', 'browser')->data; $darkMode = Preferences::get('darkMode', 'browser')->data;
$this->convertToPrimary = Amount::convertToPrimary(); $this->convertToPrimary = Amount::convertToPrimary();
$page = $this->getPageName(); $page = $this->getPageName();
$shownDemo = $this->hasSeenDemo(); $shownDemo = $this->hasSeenDemo();

View File

@@ -170,7 +170,7 @@ class HomeController extends Controller
foreach ($accounts as $account) { foreach ($accounts as $account) {
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $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(); $set = $collector->getExtractedJournals();
$transactions[] = ['transactions' => $set, 'account' => $account]; $transactions[] = ['transactions' => $set, 'account' => $account];
} }

View File

@@ -171,7 +171,7 @@ class BoxController extends Controller
$filtered = $allAccounts->filter( $filtered = $allAccounts->filter(
static function (Account $account) use ($accountRepository) { static function (Account $account) use ($accountRepository) {
$includeNetWorth = $accountRepository->getMetaValue($account, 'include_net_worth'); $includeNetWorth = $accountRepository->getMetaValue($account, 'include_net_worth');
$result = null === $includeNetWorth ? true : '1' === $includeNetWorth; $result = null === $includeNetWorth || '1' === $includeNetWorth;
if (false === $result) { if (false === $result) {
app('log')->debug(sprintf('Will not include "%s" in net worth charts.', $account->name)); app('log')->debug(sprintf('Will not include "%s" in net worth charts.', $account->name));
} }

View File

@@ -217,7 +217,7 @@ class ReconcileController extends Controller
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account])) $collector->setAccounts(new Collection()->push($account))
->setRange($selectionStart, $selectionEnd) ->setRange($selectionStart, $selectionEnd)
->withBudgetInformation()->withCategoryInformation()->withAccountInformation() ->withBudgetInformation()->withCategoryInformation()->withAccountInformation()
; ;

View File

@@ -74,7 +74,7 @@ class TriggerController extends Controller
/** @var CreateRecurringTransactions $job */ /** @var CreateRecurringTransactions $job */
$job = app(CreateRecurringTransactions::class); $job = app(CreateRecurringTransactions::class);
$job->setRecurrences(new Collection([$recurrence])); $job->setRecurrences(new Collection()->push($recurrence));
$job->setDate($date); $job->setDate($date);
$job->setForce(false); $job->setForce(false);
$job->handle(); $job->handle();

View File

@@ -291,7 +291,7 @@ class BudgetController extends Controller
$cache->addProperty('budget-period-report'); $cache->addProperty('budget-period-report');
$cache->addProperty($accounts->pluck('id')->toArray()); $cache->addProperty($accounts->pluck('id')->toArray());
if ($cache->has()) { if ($cache->has()) {
// return $cache->get(); return $cache->get();
} }
$periods = Navigation::listOfPeriods($start, $end); $periods = Navigation::listOfPeriods($start, $end);

View File

@@ -152,7 +152,7 @@ class SelectController extends Controller
$newRuleEngine = app(RuleEngineInterface::class); $newRuleEngine = app(RuleEngineInterface::class);
// set rules: // set rules:
$newRuleEngine->setRules(new Collection([$rule])); $newRuleEngine->setRules(new Collection()->push($rule));
$newRuleEngine->setRefreshTriggers(false); $newRuleEngine->setRefreshTriggers(false);
$collection = $newRuleEngine->find(); $collection = $newRuleEngine->find();
$collection = $collection->slice(0, 20); $collection = $collection->slice(0, 20);
@@ -196,7 +196,7 @@ class SelectController extends Controller
$newRuleEngine = app(RuleEngineInterface::class); $newRuleEngine = app(RuleEngineInterface::class);
// set rules: // set rules:
$newRuleEngine->setRules(new Collection([$rule])); $newRuleEngine->setRules(new Collection()->push($rule));
$collection = $newRuleEngine->find(); $collection = $newRuleEngine->find();
$collection = $collection->slice(0, 20); $collection = $collection->slice(0, 20);

View File

@@ -78,7 +78,7 @@ class ExecutionController extends Controller
// set rules: // set rules:
// #10427, file rule group and not the set of rules. // #10427, file rule group and not the set of rules.
$collection = new Collection([$ruleGroup]); $collection = new Collection()->push($ruleGroup);
$newRuleEngine->setRuleGroups($collection); $newRuleEngine->setRuleGroups($collection);
$newRuleEngine->fire(); $newRuleEngine->fire();

View File

@@ -250,10 +250,7 @@ class TagController extends Controller
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withAccountInformation() $collector->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withAccountInformation()->setTag($tag)->withBudgetInformation()->withCategoryInformation()->withAttachmentInformation();
->setTag($tag)->withBudgetInformation()->withCategoryInformation()
->withAttachmentInformation()
;
$groups = $collector->getPaginatedGroups(); $groups = $collector->getPaginatedGroups();
$groups->setPath($path); $groups->setPath($path);
$sums = $this->repository->sumsOfTag($tag, $start, $end); $sums = $this->repository->sumsOfTag($tag, $start, $end);

View File

@@ -146,25 +146,7 @@ class ShowController extends Controller
$attachments = $this->repository->getAttachments($transactionGroup); $attachments = $this->repository->getAttachments($transactionGroup);
$links = $this->repository->getLinks($transactionGroup); $links = $this->repository->getLinks($transactionGroup);
return view( return view('transactions.show', compact('transactionGroup', 'amounts', 'first', 'type', 'logEntries', 'groupLogEntries', 'subTitle', 'splits', 'selectedGroup', 'groupArray', 'events', 'attachments', 'links', 'accounts'));
'transactions.show',
compact(
'transactionGroup',
'amounts',
'first',
'type',
'logEntries',
'groupLogEntries',
'subTitle',
'splits',
'selectedGroup',
'groupArray',
'events',
'attachments',
'links',
'accounts',
)
);
} }
private function getAmounts(array $group): array private function getAmounts(array $group): array

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Requests; namespace FireflyIII\Http\Requests;
use Illuminate\Validation\Validator;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -32,7 +33,6 @@ use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/** /**
* Class PiggyBankStoreRequest. * Class PiggyBankStoreRequest.

View File

@@ -23,8 +23,8 @@ declare(strict_types=1);
namespace FireflyIII\Http\Requests; namespace FireflyIII\Http\Requests;
use FireflyIII\Exceptions\FireflyException;
use Illuminate\Validation\Validator; use Illuminate\Validation\Validator;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;

View File

@@ -269,7 +269,7 @@ class CreateAutoBudgetLimits implements ShouldQueue
// if has one, calculate expenses and use that as a base. // if has one, calculate expenses and use that as a base.
$repository = app(OperationsRepositoryInterface::class); $repository = app(OperationsRepositoryInterface::class);
$repository->setUser($autoBudget->budget->user); $repository->setUser($autoBudget->budget->user);
$spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection([$autoBudget->budget]), $autoBudget->transactionCurrency); $spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection()->push($autoBudget->budget), $autoBudget->transactionCurrency);
$currencyId = $autoBudget->transaction_currency_id; $currencyId = $autoBudget->transaction_currency_id;
$spentAmount = $spent[$currencyId]['sum'] ?? '0'; $spentAmount = $spent[$currencyId]['sum'] ?? '0';
Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount));
@@ -329,7 +329,7 @@ class CreateAutoBudgetLimits implements ShouldQueue
// if has one, calculate expenses and use that as a base. // if has one, calculate expenses and use that as a base.
$repository = app(OperationsRepositoryInterface::class); $repository = app(OperationsRepositoryInterface::class);
$repository->setUser($autoBudget->budget->user); $repository->setUser($autoBudget->budget->user);
$spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection([$autoBudget->budget]), $autoBudget->transactionCurrency); $spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection()->push($autoBudget->budget), $autoBudget->transactionCurrency);
$currencyId = $autoBudget->transaction_currency_id; $currencyId = $autoBudget->transaction_currency_id;
$spentAmount = $spent[$currencyId]['sum'] ?? '0'; $spentAmount = $spent[$currencyId]['sum'] ?? '0';
Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount));

View File

@@ -39,6 +39,7 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use function Safe\json_decode; use function Safe\json_decode;
@@ -74,7 +75,7 @@ class DownloadExchangeRates implements ShouldQueue
$newDate = clone $date; $newDate = clone $date;
$newDate->startOfDay(); $newDate->startOfDay();
$this->date = $newDate; $this->date = $newDate;
app('log')->debug(sprintf('Created new DownloadExchangeRates("%s")', $this->date->format('Y-m-d'))); Log::debug(sprintf('Created new DownloadExchangeRates("%s")', $this->date->format('Y-m-d')));
} }
} }
@@ -83,7 +84,7 @@ class DownloadExchangeRates implements ShouldQueue
*/ */
public function handle(): void public function handle(): void
{ {
app('log')->debug('Now in handle()'); Log::debug('Now in handle()');
$currencies = $this->repository->getCompleteSet(); $currencies = $this->repository->getCompleteSet();
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
@@ -97,7 +98,7 @@ class DownloadExchangeRates implements ShouldQueue
*/ */
private function downloadRates(TransactionCurrency $currency): void private function downloadRates(TransactionCurrency $currency): void
{ {
app('log')->debug(sprintf('Now downloading new exchange rates for currency %s.', $currency->code)); Log::debug(sprintf('Now downloading new exchange rates for currency %s.', $currency->code));
$base = sprintf('%s/%s/%s', (string) config('cer.url'), $this->date->year, $this->date->isoWeek); $base = sprintf('%s/%s/%s', (string) config('cer.url'), $this->date->year, $this->date->isoWeek);
$client = new Client(); $client = new Client();
$url = sprintf('%s/%s.json', $base, $currency->code); $url = sprintf('%s/%s.json', $base, $currency->code);
@@ -105,20 +106,20 @@ class DownloadExchangeRates implements ShouldQueue
try { try {
$res = $client->get($url); $res = $client->get($url);
} catch (ConnectException|RequestException $e) { } catch (ConnectException|RequestException $e) {
app('log')->warning(sprintf('Trying to grab "%s" resulted in error "%s".', $url, $e->getMessage())); Log::warning(sprintf('Trying to grab "%s" resulted in error "%s".', $url, $e->getMessage()));
return; return;
} }
$statusCode = $res->getStatusCode(); $statusCode = $res->getStatusCode();
if (200 !== $statusCode) { if (200 !== $statusCode) {
app('log')->warning(sprintf('Trying to grab "%s" resulted in status code %d.', $url, $statusCode)); Log::warning(sprintf('Trying to grab "%s" resulted in status code %d.', $url, $statusCode));
return; return;
} }
$body = (string) $res->getBody(); $body = (string) $res->getBody();
$json = json_decode($body, true); $json = json_decode($body, true);
if (false === $json || null === $json) { if (false === $json || null === $json) {
app('log')->warning(sprintf('Trying to grab "%s" resulted in bad JSON.', $url)); Log::warning(sprintf('Trying to grab "%s" resulted in bad JSON.', $url));
return; return;
} }
@@ -134,11 +135,11 @@ class DownloadExchangeRates implements ShouldQueue
foreach ($rates as $code => $rate) { foreach ($rates as $code => $rate) {
$to = $this->getCurrency($code); $to = $this->getCurrency($code);
if (!$to instanceof TransactionCurrency) { if (!$to instanceof TransactionCurrency) {
app('log')->debug(sprintf('Currency %s is not in use, do not save rate.', $code)); Log::debug(sprintf('Currency %s is not in use, do not save rate.', $code));
continue; continue;
} }
app('log')->debug(sprintf('Currency %s is in use.', $code)); Log::debug(sprintf('Currency %s is in use.', $code));
$this->saveRate($currency, $to, $date, $rate); $this->saveRate($currency, $to, $date, $rate);
} }
} }
@@ -147,25 +148,25 @@ class DownloadExchangeRates implements ShouldQueue
{ {
// if we have it already, don't bother searching for it again. // if we have it already, don't bother searching for it again.
if (array_key_exists($code, $this->active)) { if (array_key_exists($code, $this->active)) {
app('log')->debug(sprintf('Already know what the result is of searching for %s', $code)); Log::debug(sprintf('Already know what the result is of searching for %s', $code));
return $this->active[$code]; return $this->active[$code];
} }
// find it in the database. // find it in the database.
$currency = $this->repository->findByCode($code); $currency = $this->repository->findByCode($code);
if (!$currency instanceof TransactionCurrency) { if (!$currency instanceof TransactionCurrency) {
app('log')->debug(sprintf('Did not find currency %s.', $code)); Log::debug(sprintf('Did not find currency %s.', $code));
$this->active[$code] = null; $this->active[$code] = null;
return null; return null;
} }
if (false === $currency->enabled) { if (false === $currency->enabled) {
app('log')->debug(sprintf('Currency %s is not enabled.', $code)); Log::debug(sprintf('Currency %s is not enabled.', $code));
$this->active[$code] = null; $this->active[$code] = null;
return null; return null;
} }
app('log')->debug(sprintf('Currency %s is enabled.', $code)); Log::debug(sprintf('Currency %s is enabled.', $code));
$this->active[$code] = $currency; $this->active[$code] = $currency;
return $currency; return $currency;
@@ -177,7 +178,7 @@ class DownloadExchangeRates implements ShouldQueue
$this->repository->setUser($user); $this->repository->setUser($user);
$existing = $this->repository->getExchangeRate($from, $to, $date); $existing = $this->repository->getExchangeRate($from, $to, $date);
if (!$existing instanceof CurrencyExchangeRate) { if (!$existing instanceof CurrencyExchangeRate) {
app('log')->debug(sprintf('Saved rate from %s to %s for user #%d.', $from->code, $to->code, $user->id)); Log::debug(sprintf('Saved rate from %s to %s for user #%d.', $from->code, $to->code, $user->id));
$this->repository->setExchangeRate($from, $to, $date, $rate); $this->repository->setExchangeRate($from, $to, $date, $rate);
} }
} }

View File

@@ -23,11 +23,13 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Attributes\Scope;
use FireflyIII\Enums\AccountTypeEnum; use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Handlers\Observer\AccountObserver;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait; use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -40,6 +42,7 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
#[ObservedBy([AccountObserver::class])]
class Account extends Model class Account extends Model
{ {
use HasFactory; use HasFactory;
@@ -60,7 +63,7 @@ class Account extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$accountId = (int) $value; $accountId = (int)$value;
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
@@ -95,39 +98,6 @@ class Account extends Model
return $this->morphMany(Attachment::class, 'attachable'); return $this->morphMany(Attachment::class, 'attachable');
} }
/**
* Get the account number.
*/
protected function accountNumber(): Attribute
{
return Attribute::make(get: function () {
/** @var null|AccountMeta $metaValue */
$metaValue = $this->accountMeta()
->where('name', 'account_number')
->first()
;
return null !== $metaValue ? $metaValue->data : '';
});
}
public function accountMeta(): HasMany
{
return $this->hasMany(AccountMeta::class);
}
protected function editName(): Attribute
{
return Attribute::make(get: function () {
$name = $this->name;
if (AccountTypeEnum::CASH->value === $this->accountType->type) {
return '';
}
return $name;
});
}
public function locations(): MorphMany public function locations(): MorphMany
{ {
return $this->morphMany(Location::class, 'locatable'); return $this->morphMany(Location::class, 'locatable');
@@ -154,19 +124,9 @@ class Account extends Model
return $this->belongsToMany(PiggyBank::class); return $this->belongsToMany(PiggyBank::class);
} }
#[Scope]
protected function accountTypeIn(EloquentBuilder $query, array $types): void
{
if (false === $this->joinedAccountTypes) {
$query->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id');
$this->joinedAccountTypes = true;
}
$query->whereIn('account_types.type', $types);
}
public function setVirtualBalanceAttribute(mixed $value): void public function setVirtualBalanceAttribute(mixed $value): void
{ {
$value = (string) $value; $value = (string)$value;
if ('' === $value) { if ('' === $value) {
$value = null; $value = null;
} }
@@ -186,42 +146,49 @@ class Account extends Model
protected function accountId(): Attribute protected function accountId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (int) $value, get: static fn ($value) => (int)$value,
); );
} }
/**
* Get the account number.
*/
protected function accountNumber(): Attribute
{
return Attribute::make(get: function () {
/** @var null|AccountMeta $metaValue */
$metaValue = $this->accountMeta()
->where('name', 'account_number')
->first()
;
return null !== $metaValue ? $metaValue->data : '';
});
}
public function accountMeta(): HasMany
{
return $this->hasMany(AccountMeta::class);
}
/** /**
* Get the user ID * Get the user ID
*/ */
protected function accountTypeId(): Attribute protected function accountTypeId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (int) $value, get: static fn ($value) => (int)$value,
); );
} }
protected function iban(): Attribute #[Scope]
protected function accountTypeIn(EloquentBuilder $query, array $types): void
{ {
return Attribute::make( if (false === $this->joinedAccountTypes) {
get: static fn ($value) => null === $value ? null : trim(str_replace(' ', '', (string) $value)), $query->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id');
); $this->joinedAccountTypes = true;
} }
$query->whereIn('account_types.type', $types);
protected function order(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
/**
* Get the virtual balance
*/
protected function virtualBalance(): Attribute
{
return Attribute::make(
get: static fn ($value) => (string) $value,
);
} }
protected function casts(): array protected function casts(): array
@@ -238,4 +205,40 @@ class Account extends Model
'native_virtual_balance' => 'string', 'native_virtual_balance' => 'string',
]; ];
} }
protected function editName(): Attribute
{
return Attribute::make(get: function () {
$name = $this->name;
if (AccountTypeEnum::CASH->value === $this->accountType->type) {
return '';
}
return $name;
});
}
protected function iban(): Attribute
{
return Attribute::make(
get: static fn ($value) => null === $value ? null : trim(str_replace(' ', '', (string)$value)),
);
}
protected function order(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
/**
* Get the virtual balance
*/
protected function virtualBalance(): Attribute
{
return Attribute::make(
get: static fn ($value) => (string)$value,
);
}
} }

View File

@@ -23,8 +23,8 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -43,11 +43,6 @@ class AccountMeta extends Model
return $this->belongsTo(Account::class); return $this->belongsTo(Account::class);
} }
protected function data(): Attribute
{
return Attribute::make(get: fn (mixed $value) => (string) json_decode((string) $value, true), set: fn (mixed $value) => ['data' => json_encode($value)]);
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@@ -55,4 +50,9 @@ class AccountMeta extends Model
'updated_at' => 'datetime', 'updated_at' => 'datetime',
]; ];
} }
protected function data(): Attribute
{
return Attribute::make(get: fn (mixed $value) => (string)json_decode((string)$value, true), set: fn (mixed $value) => ['data' => json_encode($value)]);
}
} }

View File

@@ -32,46 +32,60 @@ class AccountType extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string ASSET = 'Asset account'; public const string ASSET = 'Asset account';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string BENEFICIARY = 'Beneficiary account'; public const string BENEFICIARY = 'Beneficiary account';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string CASH = 'Cash account'; public const string CASH = 'Cash account';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string CREDITCARD = 'Credit card'; public const string CREDITCARD = 'Credit card';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string DEBT = 'Debt'; public const string DEBT = 'Debt';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string DEFAULT = 'Default account'; public const string DEFAULT = 'Default account';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string EXPENSE = 'Expense account'; public const string EXPENSE = 'Expense account';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string IMPORT = 'Import account'; public const string IMPORT = 'Import account';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string INITIAL_BALANCE = 'Initial balance account'; public const string INITIAL_BALANCE = 'Initial balance account';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string LIABILITY_CREDIT = 'Liability credit account'; public const string LIABILITY_CREDIT = 'Liability credit account';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string LOAN = 'Loan'; public const string LOAN = 'Loan';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string MORTGAGE = 'Mortgage'; public const string MORTGAGE = 'Mortgage';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string RECONCILIATION = 'Reconciliation account'; public const string RECONCILIATION = 'Reconciliation account';
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const string REVENUE = 'Revenue account'; public const string REVENUE = 'Revenue account';
protected $casts protected $casts

View File

@@ -23,9 +23,11 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use FireflyIII\Handlers\Observer\AttachmentObserver;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait; use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -34,6 +36,7 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
#[ObservedBy([AttachmentObserver::class])]
class Attachment extends Model class Attachment extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
@@ -50,7 +53,7 @@ class Attachment extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$attachmentId = (int) $value; $attachmentId = (int)$value;
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
@@ -83,7 +86,7 @@ class Attachment extends Model
*/ */
public function fileName(): string public function fileName(): string
{ {
return sprintf('at-%s.data', (string) $this->id); return sprintf('at-%s.data', (string)$this->id);
} }
/** /**
@@ -97,7 +100,7 @@ class Attachment extends Model
protected function attachableId(): Attribute protected function attachableId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (int) $value, get: static fn ($value) => (int)$value,
); );
} }

View File

@@ -48,14 +48,7 @@ class AuditLogEntry extends Model
protected function auditableId(): Attribute protected function auditableId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (int) $value, get: static fn ($value) => (int)$value,
);
}
protected function changerId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
); );
} }
@@ -69,4 +62,11 @@ class AuditLogEntry extends Model
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
]; ];
} }
protected function changerId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
} }

View File

@@ -25,24 +25,30 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Deprecated; use Deprecated;
use FireflyIII\Handlers\Observer\AutoBudgetObserver;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
#[ObservedBy([AutoBudgetObserver::class])]
class AutoBudget extends Model class AutoBudget extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
use SoftDeletes; use SoftDeletes;
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const int AUTO_BUDGET_ADJUSTED = 3; public const int AUTO_BUDGET_ADJUSTED = 3;
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const int AUTO_BUDGET_RESET = 1; public const int AUTO_BUDGET_RESET = 1;
#[Deprecated] /** @deprecated */ #[Deprecated]
/** @deprecated */
public const int AUTO_BUDGET_ROLLOVER = 2; public const int AUTO_BUDGET_ROLLOVER = 2;
protected $casts protected $casts
= [ = [
@@ -64,14 +70,14 @@ class AutoBudget extends Model
protected function amount(): Attribute protected function amount(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (string) $value, get: static fn ($value) => (string)$value,
); );
} }
protected function budgetId(): Attribute protected function budgetId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (int) $value, get: static fn ($value) => (int)$value,
); );
} }
@@ -85,7 +91,7 @@ class AutoBudget extends Model
protected function transactionCurrencyId(): Attribute protected function transactionCurrencyId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (int) $value, get: static fn ($value) => (int)$value,
); );
} }
} }

View File

@@ -24,15 +24,18 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Handlers\Observer\AvailableBudgetObserver;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait; use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
#[ObservedBy([AvailableBudgetObserver::class])]
class AvailableBudget extends Model class AvailableBudget extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
@@ -49,7 +52,7 @@ class AvailableBudget extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$availableBudgetId = (int) $value; $availableBudgetId = (int)$value;
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
@@ -77,10 +80,26 @@ class AvailableBudget extends Model
protected function amount(): Attribute protected function amount(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (string) $value, get: static fn ($value) => (string)$value,
); );
} }
protected function casts(): array
{
return [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'start_date' => 'date',
'end_date' => 'date',
'transaction_currency_id' => 'int',
'amount' => 'string',
'native_amount' => 'string',
'user_id' => 'integer',
'user_group_id' => 'integer',
];
}
protected function endDate(): Attribute protected function endDate(): Attribute
{ {
return Attribute::make( return Attribute::make(
@@ -100,23 +119,7 @@ class AvailableBudget extends Model
protected function transactionCurrencyId(): Attribute protected function transactionCurrencyId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (int) $value, get: static fn ($value) => (int)$value,
); );
} }
protected function casts(): array
{
return [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'start_date' => 'date',
'end_date' => 'date',
'transaction_currency_id' => 'int',
'amount' => 'string',
'native_amount' => 'string',
'user_id' => 'integer',
'user_group_id' => 'integer',
];
}
} }

View File

@@ -24,9 +24,11 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use FireflyIII\Casts\SeparateTimezoneCaster; use FireflyIII\Casts\SeparateTimezoneCaster;
use FireflyIII\Handlers\Observer\BillObserver;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait; use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -36,6 +38,7 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
#[ObservedBy([BillObserver::class])]
class Bill extends Model class Bill extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
@@ -75,7 +78,7 @@ class Bill extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$billId = (int) $value; $billId = (int)$value;
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
@@ -121,7 +124,7 @@ class Bill extends Model
*/ */
public function setAmountMaxAttribute($value): void public function setAmountMaxAttribute($value): void
{ {
$this->attributes['amount_max'] = (string) $value; $this->attributes['amount_max'] = (string)$value;
} }
/** /**
@@ -129,7 +132,7 @@ class Bill extends Model
*/ */
public function setAmountMinAttribute($value): void public function setAmountMinAttribute($value): void
{ {
$this->attributes['amount_min'] = (string) $value; $this->attributes['amount_min'] = (string)$value;
} }
public function transactionCurrency(): BelongsTo public function transactionCurrency(): BelongsTo
@@ -148,7 +151,7 @@ class Bill extends Model
protected function amountMax(): Attribute protected function amountMax(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (string) $value, get: static fn ($value) => (string)$value,
); );
} }
@@ -158,31 +161,7 @@ class Bill extends Model
protected function amountMin(): Attribute protected function amountMin(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (string) $value, get: static fn ($value) => (string)$value,
);
}
protected function order(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
/**
* Get the skip
*/
protected function skip(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
protected function transactionCurrencyId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
); );
} }
@@ -206,4 +185,28 @@ class Bill extends Model
'native_amount_max' => 'string', 'native_amount_max' => 'string',
]; ];
} }
protected function order(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
/**
* Get the skip
*/
protected function skip(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
protected function transactionCurrencyId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
} }

View File

@@ -23,9 +23,11 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use FireflyIII\Handlers\Observer\BudgetObserver;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait; use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -35,6 +37,7 @@ use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
#[ObservedBy([BudgetObserver::class])]
class Budget extends Model class Budget extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
@@ -53,7 +56,7 @@ class Budget extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$budgetId = (int) $value; $budgetId = (int)$value;
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
@@ -106,13 +109,6 @@ class Budget extends Model
return $this->belongsToMany(Transaction::class, 'budget_transaction', 'budget_id'); return $this->belongsToMany(Transaction::class, 'budget_transaction', 'budget_id');
} }
protected function order(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@@ -125,4 +121,11 @@ class Budget extends Model
'user_group_id' => 'integer', 'user_group_id' => 'integer',
]; ];
} }
protected function order(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
} }

View File

@@ -24,13 +24,16 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use FireflyIII\Casts\SeparateTimezoneCaster; use FireflyIII\Casts\SeparateTimezoneCaster;
use FireflyIII\Handlers\Observer\BudgetLimitObserver;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\Relations\MorphMany;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
#[ObservedBy([BudgetLimitObserver::class])]
class BudgetLimit extends Model class BudgetLimit extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
@@ -45,7 +48,7 @@ class BudgetLimit extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$budgetLimitId = (int) $value; $budgetLimitId = (int)$value;
$budgetLimit = self::where('budget_limits.id', $budgetLimitId) $budgetLimit = self::where('budget_limits.id', $budgetLimitId)
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') ->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->where('budgets.user_id', auth()->user()->id) ->where('budgets.user_id', auth()->user()->id)
@@ -83,21 +86,14 @@ class BudgetLimit extends Model
protected function amount(): Attribute protected function amount(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (string) $value, get: static fn ($value) => (string)$value,
); );
} }
protected function budgetId(): Attribute protected function budgetId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (int) $value, get: static fn ($value) => (int)$value,
);
}
protected function transactionCurrencyId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
); );
} }
@@ -113,4 +109,11 @@ class BudgetLimit extends Model
'native_amount' => 'string', 'native_amount' => 'string',
]; ];
} }
protected function transactionCurrencyId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
} }

View File

@@ -24,9 +24,11 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use FireflyIII\Handlers\Observer\CategoryObserver;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait; use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@@ -34,6 +36,7 @@ use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
#[ObservedBy([CategoryObserver::class])]
class Category extends Model class Category extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
@@ -52,7 +55,7 @@ class Category extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$categoryId = (int) $value; $categoryId = (int)$value;
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();

View File

@@ -23,8 +23,8 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@@ -38,14 +38,6 @@ class Configuration extends Model
protected $table = 'configuration'; protected $table = 'configuration';
/**
* TODO can be replaced with native laravel code.
*/
protected function data(): Attribute
{
return Attribute::make(get: fn ($value) => json_decode((string) $value), set: fn ($value) => ['data' => json_encode($value)]);
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@@ -54,4 +46,12 @@ class Configuration extends Model
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
]; ];
} }
/**
* TODO can be replaced with native laravel code.
*/
protected function data(): Attribute
{
return Attribute::make(get: fn ($value) => json_decode((string)$value), set: fn ($value) => ['data' => json_encode($value)]);
}
} }

View File

@@ -37,7 +37,8 @@ class CurrencyExchangeRate extends Model
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
use ReturnsIntegerUserIdTrait; use ReturnsIntegerUserIdTrait;
use SoftDeletes; use SoftDeletes;
protected $fillable = ['user_id', 'from_currency_id', 'to_currency_id', 'date', 'date_tz', 'rate'];
protected $fillable = ['user_id', 'user_group_id', 'from_currency_id', 'to_currency_id', 'date', 'date_tz', 'rate'];
public function fromCurrency(): BelongsTo public function fromCurrency(): BelongsTo
{ {
@@ -54,34 +55,6 @@ class CurrencyExchangeRate extends Model
return $this->belongsTo(User::class); return $this->belongsTo(User::class);
} }
protected function fromCurrencyId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
protected function rate(): Attribute
{
return Attribute::make(
get: static fn ($value) => (string) $value,
);
}
protected function toCurrencyId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
protected function userRate(): Attribute
{
return Attribute::make(
get: static fn ($value) => (string) $value,
);
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@@ -96,4 +69,32 @@ class CurrencyExchangeRate extends Model
'user_rate' => 'string', 'user_rate' => 'string',
]; ];
} }
protected function fromCurrencyId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
protected function rate(): Attribute
{
return Attribute::make(
get: static fn ($value) => (string)$value,
);
}
protected function toCurrencyId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
protected function userRate(): Attribute
{
return Attribute::make(
get: static fn ($value) => (string)$value,
);
}
} }

View File

@@ -53,13 +53,6 @@ class GroupMembership extends Model
return $this->belongsTo(UserRole::class); return $this->belongsTo(UserRole::class);
} }
protected function userRoleId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@@ -69,4 +62,11 @@ class GroupMembership extends Model
'user_group_id' => 'integer', 'user_group_id' => 'integer',
]; ];
} }
protected function userRoleId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
} }

View File

@@ -36,6 +36,7 @@ class InvitedUser extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
use ReturnsIntegerUserIdTrait; use ReturnsIntegerUserIdTrait;
protected $fillable = ['user_group_id', 'user_id', 'email', 'invite_code', 'expires', 'expires_tz', 'redeemed']; protected $fillable = ['user_group_id', 'user_id', 'email', 'invite_code', 'expires', 'expires_tz', 'redeemed'];
/** /**
@@ -44,7 +45,7 @@ class InvitedUser extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$attemptId = (int) $value; $attemptId = (int)$value;
/** @var null|InvitedUser $attempt */ /** @var null|InvitedUser $attempt */
$attempt = self::find($attemptId); $attempt = self::find($attemptId);

View File

@@ -44,7 +44,7 @@ class LinkType extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$linkTypeId = (int) $value; $linkTypeId = (int)$value;
$linkType = self::find($linkTypeId); $linkType = self::find($linkTypeId);
if (null !== $linkType) { if (null !== $linkType) {
return $linkType; return $linkType;

View File

@@ -66,13 +66,6 @@ class Location extends Model
return $this->morphMany(TransactionJournal::class, 'locatable'); return $this->morphMany(TransactionJournal::class, 'locatable');
} }
protected function locatableId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@@ -84,4 +77,11 @@ class Location extends Model
'longitude' => 'float', 'longitude' => 'float',
]; ];
} }
protected function locatableId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
} }

View File

@@ -44,13 +44,6 @@ class Note extends Model
return $this->morphTo(); return $this->morphTo();
} }
protected function noteableId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@@ -59,4 +52,11 @@ class Note extends Model
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
]; ];
} }
protected function noteableId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
} }

View File

@@ -37,6 +37,7 @@ class ObjectGroup extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
use ReturnsIntegerUserIdTrait; use ReturnsIntegerUserIdTrait;
protected $fillable = ['title', 'order', 'user_id', 'user_group_id']; protected $fillable = ['title', 'order', 'user_id', 'user_group_id'];
/** /**
@@ -47,7 +48,7 @@ class ObjectGroup extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$objectGroupId = (int) $value; $objectGroupId = (int)$value;
/** @var null|ObjectGroup $objectGroup */ /** @var null|ObjectGroup $objectGroup */
$objectGroup = self::where('object_groups.id', $objectGroupId) $objectGroup = self::where('object_groups.id', $objectGroupId)
@@ -90,13 +91,6 @@ class ObjectGroup extends Model
return $this->morphedByMany(PiggyBank::class, 'object_groupable'); return $this->morphedByMany(PiggyBank::class, 'object_groupable');
} }
protected function order(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@@ -107,4 +101,11 @@ class ObjectGroup extends Model
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
]; ];
} }
protected function order(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
} }

View File

@@ -23,7 +23,9 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use FireflyIII\Handlers\Observer\PiggyBankObserver;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -34,6 +36,7 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
#[ObservedBy([PiggyBankObserver::class])]
class PiggyBank extends Model class PiggyBank extends Model
{ {
use ReturnsIntegerIdTrait; use ReturnsIntegerIdTrait;
@@ -49,7 +52,7 @@ class PiggyBank extends Model
public static function routeBinder(string $value): self public static function routeBinder(string $value): self
{ {
if (auth()->check()) { if (auth()->check()) {
$piggyBankId = (int) $value; $piggyBankId = (int)$value;
$piggyBank = self::where('piggy_banks.id', $piggyBankId) $piggyBank = self::where('piggy_banks.id', $piggyBankId)
->leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') ->leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
@@ -109,7 +112,7 @@ class PiggyBank extends Model
*/ */
public function setTargetAmountAttribute($value): void public function setTargetAmountAttribute($value): void
{ {
$this->attributes['target_amount'] = (string) $value; $this->attributes['target_amount'] = (string)$value;
} }
public function transactionCurrency(): BelongsTo public function transactionCurrency(): BelongsTo
@@ -120,24 +123,7 @@ class PiggyBank extends Model
protected function accountId(): Attribute protected function accountId(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: static fn ($value) => (int) $value, get: static fn ($value) => (int)$value,
);
}
protected function order(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int) $value,
);
}
/**
* Get the max amount
*/
protected function targetAmount(): Attribute
{
return Attribute::make(
get: static fn ($value) => (string) $value,
); );
} }
@@ -156,4 +142,21 @@ class PiggyBank extends Model
'native_target_amount' => 'string', 'native_target_amount' => 'string',
]; ];
} }
protected function order(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
);
}
/**
* Get the max amount
*/
protected function targetAmount(): Attribute
{
return Attribute::make(
get: static fn ($value) => (string)$value,
);
}
} }

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