Compare commits

...

253 Commits

Author SHA1 Message Date
github-actions
481b01e4f7 Auto commit for release 'develop' on 2024-08-26 2024-08-26 05:07:55 +02:00
James Cole
629f70d27d small npm updates 2024-08-25 07:41:19 +02:00
James Cole
57f5ebc0f9 Merge branch 'main' into develop
# Conflicts:
#	package-lock.json
#	resources/assets/v1/package.json
2024-08-25 07:37:50 +02:00
James Cole
b4f51e7b47 Package updates. 2024-08-25 07:36:35 +02:00
James Cole
d78d254e86 Merge pull request #9163 from firefly-iii/dependabot/npm_and_yarn/npm_and_yarn-ba93e5c870
Bump the npm_and_yarn group across 1 directory with 2 updates
2024-08-21 15:42:39 +02:00
dependabot[bot]
eb0c113699 Bump the npm_and_yarn group across 1 directory with 2 updates
Bumps the npm_and_yarn group with 2 updates in the / directory: [axios](https://github.com/axios/axios) and [postcss](https://github.com/postcss/postcss).


Updates `axios` from 1.7.2 to 1.7.4
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.7.2...v1.7.4)

Updates `postcss` from 8.4.40 to 8.4.41
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.40...8.4.41)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: postcss
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-21 13:36:39 +00:00
James Cole
a620b07c00 Fix button in edit mode. 2024-08-19 11:40:00 +02:00
github-actions
cb724145f2 Auto commit for release 'develop' on 2024-08-19 2024-08-19 05:06:45 +02:00
James Cole
8ef17f6686 Fix https://github.com/firefly-iii/firefly-iii/issues/9140 2024-08-16 09:39:29 +02:00
github-actions
debfd9160c Auto commit for release 'develop' on 2024-08-12 2024-08-12 05:07:37 +02:00
James Cole
f2482e4ace Remove comments 2024-08-07 06:04:37 +02:00
github-actions
d98d757f8b Auto commit for release 'develop' on 2024-08-05 2024-08-05 20:37:29 +02:00
James Cole
0c9a41a929 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/JsonApi/V2/Accounts/AccountRepository.php
#	app/JsonApi/V2/Accounts/AccountRequest.php
#	app/JsonApi/V2/Accounts/Capabilities/CrudAccount.php
#	app/Support/Steam.php
2024-08-05 19:48:46 +02:00
James Cole
e26f78bf50 Better error handling and remove some warnings. 2024-08-05 19:45:04 +02:00
github-actions
ed265f68ba Auto commit for release 'develop' on 2024-08-05 2024-08-05 05:06:53 +02:00
James Cole
d2e9b64bf5 Make dialog work. 2024-08-03 18:42:06 +02:00
James Cole
3811aff206 Expand view. 2024-08-03 18:27:19 +02:00
James Cole
762d898fee Fix most of the index with json laravel api endpoints. 2024-08-03 13:15:39 +02:00
James Cole
5e6034fc86 Add some translations. 2024-08-03 07:51:30 +02:00
James Cole
9da10459d6 Add ability to paginate. 2024-08-03 07:28:56 +02:00
James Cole
ff80cedd6b Fix sort params 2024-08-03 06:18:46 +02:00
James Cole
b213148ae8 Allow account endpoint to be filtered on various fields. 2024-08-03 06:00:22 +02:00
James Cole
c8646e20cb gitMerge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop 2024-08-02 16:13:16 +02:00
James Cole
76a41fec50 New API stuff 2024-08-02 13:45:41 +02:00
James Cole
0e705bd038 Expand schema. 2024-08-02 05:39:04 +02:00
James Cole
f33ffb98ff Expand and fix account API 2024-08-01 20:45:42 +02:00
James Cole
faa0d59340 Fix https://github.com/firefly-iii/firefly-iii/issues/9103 2024-07-31 20:40:26 +02:00
James Cole
5af0219884 Fix https://github.com/firefly-iii/firefly-iii/issues/9103 2024-07-31 20:31:52 +02:00
James Cole
dafd99f155 Expand v2 api 2024-07-31 20:19:17 +02:00
James Cole
3560f0388c New method of collecting balance. 2024-07-31 13:09:55 +02:00
James Cole
b2954658d8 Various code cleanup [skip ci] 2024-07-31 08:31:20 +02:00
James Cole
44581d9983 Cleaner model docblock thing [skip ci] 2024-07-31 08:26:43 +02:00
James Cole
02dcfeb227 Remove comments from models, regenerate later [skip ci] 2024-07-31 08:23:09 +02:00
James Cole
d8bafb349d Proper recalculation of balance [skip ci] 2024-07-31 08:20:19 +02:00
James Cole
889598a4c8 Correct transactions for the next release. 2024-07-30 19:48:14 +02:00
James Cole
7e37d10016 New way to store transfers 2024-07-30 18:04:39 +02:00
James Cole
ebaebb09d1 Merge branch 'main' into develop 2024-07-30 06:15:10 +02:00
James Cole
531a3a4b6c Forced disable of model caching 2024-07-30 06:14:43 +02:00
James Cole
b3e313821b Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/Support/Models/AccountBalanceCalculator.php
2024-07-29 19:51:35 +02:00
James Cole
51958af422 Add running balance 2024-07-29 19:51:04 +02:00
James Cole
e3b21ccdba Update pull_request_template.md
Signed-off-by: James Cole <james@firefly-iii.org>
2024-07-29 16:42:55 +02:00
James Cole
31bb208835 Merge pull request #9096 from withbest/develop
chore: fix some comments
2024-07-29 16:39:52 +02:00
withbest
8c97e805a2 chore: fix some comments
Signed-off-by: withbest <seekseat@outlook.com>
2024-07-29 18:19:40 +08:00
github-actions
ac8a43bb37 Auto commit for release 'develop' on 2024-07-29 2024-07-29 05:06:54 +02:00
James Cole
2df4b40a28 Add a command to sync up currency information 2024-07-28 15:13:49 +02:00
James Cole
e06736c254 Returns accounts consistently. 2024-07-28 12:23:45 +02:00
James Cole
ec367e94ce Expand account object api 2024-07-28 07:47:54 +02:00
James Cole
1515dea9fa add user group validation 2024-07-28 07:02:04 +02:00
James Cole
adedf9c17d Merge branch 'main' into develop 2024-07-27 15:43:37 +02:00
James Cole
0b52fb84f1 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2024-07-27 15:42:54 +02:00
James Cole
16e742ae73 Various API updates. 2024-07-27 15:42:43 +02:00
James Cole
1b4471dfae Merge pull request #9090 from firefly-iii/dependabot/composer/develop/symfony/http-client-7.1.3
Bump symfony/http-client from 7.1.2 to 7.1.3
2024-07-27 15:42:12 +02:00
James Cole
ae152ce0a4 Merge pull request #9092 from firefly-iii/dependabot/npm_and_yarn/npm_and_yarn-19f3e7cf70
Bump postcss from 8.4.39 to 8.4.40 in the npm_and_yarn group across 1 directory
2024-07-27 15:41:55 +02:00
James Cole
2aa023f140 Merge pull request #9091 from firefly-iii/dependabot/npm_and_yarn/develop/vue/compiler-sfc-3.4.34
Bump @vue/compiler-sfc from 3.4.33 to 3.4.34
2024-07-27 15:41:47 +02:00
dependabot[bot]
6e2e4c6f08 Bump symfony/http-client from 7.1.2 to 7.1.3
Bumps [symfony/http-client](https://github.com/symfony/http-client) from 7.1.2 to 7.1.3.
- [Release notes](https://github.com/symfony/http-client/releases)
- [Changelog](https://github.com/symfony/http-client/blob/7.1/CHANGELOG.md)
- [Commits](https://github.com/symfony/http-client/compare/v7.1.2...v7.1.3)

---
updated-dependencies:
- dependency-name: symfony/http-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-27 13:33:08 +00:00
James Cole
1c8c038735 Merge pull request #9089 from firefly-iii/dependabot/composer/develop/symfony/mailgun-mailer-7.1.3
Bump symfony/mailgun-mailer from 7.1.2 to 7.1.3
2024-07-27 15:32:43 +02:00
James Cole
4d339a6da8 Merge pull request #9088 from firefly-iii/dependabot/npm_and_yarn/develop/postcss-8.4.40
Bump postcss from 8.4.39 to 8.4.40
2024-07-27 15:31:49 +02:00
James Cole
b7edd4407a Merge pull request #9087 from firefly-iii/dependabot/composer/develop/laravel/framework-11.18.1
Bump laravel/framework from 11.17.0 to 11.18.1
2024-07-27 15:31:34 +02:00
dependabot[bot]
a679a1e94a Bump postcss in the npm_and_yarn group across 1 directory
Bumps the npm_and_yarn group with 1 update in the / directory: [postcss](https://github.com/postcss/postcss).


Updates `postcss` from 8.4.39 to 8.4.40
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.39...8.4.40)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-27 13:30:39 +00:00
James Cole
180451d32f Merge pull request #9086 from firefly-iii/dependabot/github_actions/github/command-1.2.1
Bump github/command from 1.2.0 to 1.2.1
2024-07-27 15:30:04 +02:00
dependabot[bot]
7396f22bca Bump @vue/compiler-sfc from 3.4.33 to 3.4.34
Bumps [@vue/compiler-sfc](https://github.com/vuejs/core/tree/HEAD/packages/compiler-sfc) from 3.4.33 to 3.4.34.
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/commits/v3.4.34/packages/compiler-sfc)

---
updated-dependencies:
- dependency-name: "@vue/compiler-sfc"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-27 13:28:28 +00:00
dependabot[bot]
058019aa84 Bump symfony/mailgun-mailer from 7.1.2 to 7.1.3
Bumps [symfony/mailgun-mailer](https://github.com/symfony/mailgun-mailer) from 7.1.2 to 7.1.3.
- [Release notes](https://github.com/symfony/mailgun-mailer/releases)
- [Changelog](https://github.com/symfony/mailgun-mailer/blob/7.1/CHANGELOG.md)
- [Commits](https://github.com/symfony/mailgun-mailer/compare/v7.1.2...v7.1.3)

---
updated-dependencies:
- dependency-name: symfony/mailgun-mailer
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-27 13:28:11 +00:00
dependabot[bot]
695f83d1d8 Bump postcss from 8.4.39 to 8.4.40
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.39 to 8.4.40.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.39...8.4.40)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-27 13:28:06 +00:00
dependabot[bot]
ac4dfb3baf Bump laravel/framework from 11.17.0 to 11.18.1
Bumps [laravel/framework](https://github.com/laravel/framework) from 11.17.0 to 11.18.1.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/11.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v11.17.0...v11.18.1)

---
updated-dependencies:
- dependency-name: laravel/framework
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-27 13:28:05 +00:00
dependabot[bot]
427001b223 Bump github/command from 1.2.0 to 1.2.1
Bumps [github/command](https://github.com/github/command) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/github/command/releases)
- [Commits](https://github.com/github/command/compare/v1.2.0...v1.2.1)

---
updated-dependencies:
- dependency-name: github/command
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-27 13:27:56 +00:00
James Cole
3117d8b30d Update dependabot.yml
Remove labels.

Signed-off-by: James Cole <james@firefly-iii.org>
2024-07-27 15:27:34 +02:00
James Cole
d19dd2a8b2 Clean up some code, clean routes. [skip ci] 2024-07-26 18:50:41 +02:00
James Cole
de3dcc3fc2 Add "not expected this period" message, fix https://github.com/firefly-iii/firefly-iii/issues/9084 2024-07-26 12:53:13 +02:00
James Cole
077f3e095b Various API changes for v2 2024-07-26 12:52:54 +02:00
James Cole
ad3b0bb320 Time to enable the expression engine. 2024-07-26 04:19:49 +02:00
James Cole
8538741341 Fix https://github.com/orgs/firefly-iii/discussions/9080 2024-07-26 03:57:35 +02:00
James Cole
a0aef5d579 Fix https://github.com/firefly-iii/firefly-iii/issues/9078 2024-07-24 14:57:51 +02:00
github-actions
fdd93427aa Auto commit for release 'develop' on 2024-07-22 2024-07-22 05:07:54 +02:00
github-actions
ac3f6557de Auto commit for release 'develop' on 2024-07-20 2024-07-20 10:36:54 +02:00
github-actions
b0a909150c Auto commit for release 'v6.1.19' on 2024-07-20 2024-07-20 06:56:39 +02:00
James Cole
913f163fe4 Update changelog 2024-07-20 06:51:33 +02:00
github-actions
3126b07b33 Auto commit for release 'develop' on 2024-07-15 2024-07-15 06:18:29 +02:00
James Cole
08ca90cf75 Merge pull request #9049 from firefly-iii/dependabot/npm_and_yarn/develop/sass-1.77.8 2024-07-15 06:15:16 +02:00
James Cole
540ac2a277 Merge pull request #9050 from firefly-iii/dependabot/npm_and_yarn/develop/ag-grid-community/core-32.0.2 2024-07-15 06:15:08 +02:00
dependabot[bot]
ed80bed066 Bump sass from 1.77.6 to 1.77.8
Bumps [sass](https://github.com/sass/dart-sass) from 1.77.6 to 1.77.8.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.77.6...1.77.8)

---
updated-dependencies:
- dependency-name: sass
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-15 04:14:54 +00:00
dependabot[bot]
41d2541c6a Bump @ag-grid-community/core from 32.0.0 to 32.0.2
Bumps [@ag-grid-community/core](https://github.com/ag-grid/ag-grid) from 32.0.0 to 32.0.2.
- [Release notes](https://github.com/ag-grid/ag-grid/releases)
- [Commits](https://github.com/ag-grid/ag-grid/compare/v32.0.0...v32.0.2)

---
updated-dependencies:
- dependency-name: "@ag-grid-community/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-15 04:14:44 +00:00
James Cole
5dedf63498 Merge pull request #9051 from firefly-iii/dependabot/npm_and_yarn/develop/laravel-vite-plugin-1.0.5 2024-07-15 06:14:12 +02:00
James Cole
09bc4f41d2 Merge pull request #9052 from firefly-iii/dependabot/npm_and_yarn/develop/ag-grid-community/infinite-row-model-32.0.2 2024-07-15 06:14:05 +02:00
James Cole
cebf0b5c57 Merge pull request #9053 from firefly-iii/dependabot/npm_and_yarn/develop/ag-grid-community/client-side-row-model-32.0.2 2024-07-15 06:13:57 +02:00
James Cole
1632a57e3e Merge pull request #9054 from firefly-iii/dependabot/composer/develop/barryvdh/laravel-ide-helper-3.1.0 2024-07-15 06:13:49 +02:00
James Cole
744c4be7d1 Merge pull request #9055 from firefly-iii/dependabot/composer/develop/phpunit/phpunit-10.5.27 2024-07-15 06:13:41 +02:00
James Cole
bd99ef3eff Merge pull request #9056 from firefly-iii/dependabot/composer/develop/laravel/framework-11.15.0 2024-07-15 06:13:33 +02:00
dependabot[bot]
8a86f13a5d Bump laravel/framework from 11.14.0 to 11.15.0
Bumps [laravel/framework](https://github.com/laravel/framework) from 11.14.0 to 11.15.0.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/11.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v11.14.0...v11.15.0)

---
updated-dependencies:
- dependency-name: laravel/framework
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-15 03:28:11 +00:00
dependabot[bot]
7418b2f0ee Bump phpunit/phpunit from 10.5.25 to 10.5.27
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.5.25 to 10.5.27.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.5.27/ChangeLog-10.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/10.5.25...10.5.27)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-15 03:27:58 +00:00
dependabot[bot]
a0e9de9312 Bump barryvdh/laravel-ide-helper from 3.0.0 to 3.1.0
Bumps [barryvdh/laravel-ide-helper](https://github.com/barryvdh/laravel-ide-helper) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/barryvdh/laravel-ide-helper/releases)
- [Changelog](https://github.com/barryvdh/laravel-ide-helper/blob/master/CHANGELOG.md)
- [Commits](https://github.com/barryvdh/laravel-ide-helper/compare/v3.0.0...v3.1.0)

---
updated-dependencies:
- dependency-name: barryvdh/laravel-ide-helper
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-15 03:27:52 +00:00
dependabot[bot]
7e23a6f5e8 Bump @ag-grid-community/client-side-row-model from 32.0.0 to 32.0.2
Bumps [@ag-grid-community/client-side-row-model](https://github.com/ag-grid/ag-grid) from 32.0.0 to 32.0.2.
- [Release notes](https://github.com/ag-grid/ag-grid/releases)
- [Commits](https://github.com/ag-grid/ag-grid/compare/v32.0.0...v32.0.2)

---
updated-dependencies:
- dependency-name: "@ag-grid-community/client-side-row-model"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-15 03:11:06 +00:00
dependabot[bot]
44589f8744 Bump @ag-grid-community/infinite-row-model from 32.0.0 to 32.0.2
Bumps [@ag-grid-community/infinite-row-model](https://github.com/ag-grid/ag-grid) from 32.0.0 to 32.0.2.
- [Release notes](https://github.com/ag-grid/ag-grid/releases)
- [Commits](https://github.com/ag-grid/ag-grid/compare/v32.0.0...v32.0.2)

---
updated-dependencies:
- dependency-name: "@ag-grid-community/infinite-row-model"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-15 03:10:52 +00:00
dependabot[bot]
d24531030f Bump laravel-vite-plugin from 1.0.4 to 1.0.5
Bumps [laravel-vite-plugin](https://github.com/laravel/vite-plugin) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/laravel/vite-plugin/releases)
- [Changelog](https://github.com/laravel/vite-plugin/blob/1.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/vite-plugin/compare/v1.0.4...v1.0.5)

---
updated-dependencies:
- dependency-name: laravel-vite-plugin
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-15 03:10:36 +00:00
James Cole
25bdab1346 Add some debug info. 2024-07-10 11:55:02 +02:00
James Cole
41af1c863a Fix https://github.com/firefly-iii/firefly-iii/issues/9009 2024-07-10 11:40:41 +02:00
James Cole
76b3b18cfb Merge pull request #9030 from firefly-iii/dependabot/npm_and_yarn/develop/ag-grid-community/client-side-row-model-32.0.0
Bump @ag-grid-community/client-side-row-model from 31.3.2 to 32.0.0
2024-07-08 13:19:40 +02:00
dependabot[bot]
e6fb2958a9 Bump @ag-grid-community/client-side-row-model from 31.3.2 to 32.0.0
Bumps [@ag-grid-community/client-side-row-model](https://github.com/ag-grid/ag-grid) from 31.3.2 to 32.0.0.
- [Release notes](https://github.com/ag-grid/ag-grid/releases)
- [Commits](https://github.com/ag-grid/ag-grid/compare/v31.3.2...v32.0.0)

---
updated-dependencies:
- dependency-name: "@ag-grid-community/client-side-row-model"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-08 11:19:16 +00:00
James Cole
15b75b322f Merge pull request #9029 from firefly-iii/dependabot/npm_and_yarn/develop/ag-grid-community/infinite-row-model-32.0.0
Bump @ag-grid-community/infinite-row-model from 31.3.2 to 32.0.0
2024-07-08 13:18:28 +02:00
dependabot[bot]
86149d1032 Bump @ag-grid-community/infinite-row-model from 31.3.2 to 32.0.0
Bumps [@ag-grid-community/infinite-row-model](https://github.com/ag-grid/ag-grid) from 31.3.2 to 32.0.0.
- [Release notes](https://github.com/ag-grid/ag-grid/releases)
- [Commits](https://github.com/ag-grid/ag-grid/compare/v31.3.2...v32.0.0)

---
updated-dependencies:
- dependency-name: "@ag-grid-community/infinite-row-model"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-08 11:18:02 +00:00
James Cole
ded142cd9e Merge pull request #9031 from firefly-iii/dependabot/npm_and_yarn/develop/ag-grid-community/core-32.0.0
Bump @ag-grid-community/core from 31.3.2 to 32.0.0
2024-07-08 13:17:12 +02:00
dependabot[bot]
7923eb9ec9 Bump @ag-grid-community/core from 31.3.2 to 32.0.0
Bumps [@ag-grid-community/core](https://github.com/ag-grid/ag-grid) from 31.3.2 to 32.0.0.
- [Release notes](https://github.com/ag-grid/ag-grid/releases)
- [Commits](https://github.com/ag-grid/ag-grid/compare/v31.3.2...v32.0.0)

---
updated-dependencies:
- dependency-name: "@ag-grid-community/core"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-08 10:59:19 +00:00
James Cole
132553c108 Merge pull request #9032 from firefly-iii/dependabot/npm_and_yarn/develop/ag-grid-community/styles-32.0.0
Bump @ag-grid-community/styles from 31.3.2 to 32.0.0
2024-07-08 12:58:14 +02:00
github-actions
c2269fc9a4 Auto commit for release 'develop' on 2024-07-08 2024-07-08 05:07:00 +02:00
dependabot[bot]
aed30d1499 Bump @ag-grid-community/styles from 31.3.2 to 32.0.0
Bumps [@ag-grid-community/styles](https://github.com/ag-grid/ag-grid) from 31.3.2 to 32.0.0.
- [Release notes](https://github.com/ag-grid/ag-grid/releases)
- [Commits](https://github.com/ag-grid/ag-grid/compare/v31.3.2...v32.0.0)

---
updated-dependencies:
- dependency-name: "@ag-grid-community/styles"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-08 03:05:13 +00:00
James Cole
84a1a876e1 Fix https://github.com/firefly-iii/firefly-iii/issues/8844 2024-07-06 18:50:33 +02:00
James Cole
dc675707f9 Fix https://github.com/firefly-iii/firefly-iii/issues/9021 2024-07-06 15:50:20 +02:00
James Cole
d5667c7ef6 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/Support/Http/Api/ExchangeRateConverter.php
2024-07-06 15:43:27 +02:00
James Cole
cba1213dd1 Better cache 2024-07-06 15:42:50 +02:00
James Cole
7219c90957 Fix https://github.com/firefly-iii/firefly-iii/issues/9022 2024-07-06 15:42:33 +02:00
github-actions
af13bd991e Auto commit for release 'develop' on 2024-07-01 2024-07-01 05:06:49 +02:00
James Cole
48e548eb52 Better disable thing. 2024-06-30 18:20:52 +02:00
github-actions
1a19e27f0e Auto commit for release 'develop' on 2024-06-24 2024-06-24 05:07:31 +02:00
James Cole
0cbd22426d Fix https://github.com/firefly-iii/firefly-iii/issues/8986 2024-06-20 18:29:00 +02:00
James Cole
d5e52e99e0 Fix #8981 2024-06-18 19:44:22 +02:00
github-actions
f52978e71f Auto commit for release 'v6.1.18' on 2024-06-17 2024-06-17 20:47:03 +02:00
James Cole
3a3358124d Meta data for new release. 2024-06-17 20:43:02 +02:00
github-actions
929808c633 Auto commit for release 'develop' on 2024-06-17 2024-06-17 05:07:03 +02:00
github-actions
a78df574f3 Auto commit for release 'develop' on 2024-06-16 2024-06-16 20:26:04 +02:00
James Cole
875cad16b6 Possible fix for https://github.com/firefly-iii/firefly-iii/issues/8977 2024-06-16 20:21:39 +02:00
James Cole
7bc30192ca Fix https://github.com/firefly-iii/firefly-iii/issues/8978 2024-06-16 19:27:38 +02:00
github-actions
a1a8968e98 Auto commit for release 'develop' on 2024-06-15 2024-06-15 16:16:40 +02:00
James Cole
6abb74a038 Mondays only [skip ci] 2024-06-15 14:26:59 +02:00
github-actions
2d7d05e985 Auto commit for release 'v6.1.17' on 2024-06-15 2024-06-15 13:07:23 +02:00
github-actions
d426e09474 Merge branch 'develop' 2024-06-15 11:04:29 +00:00
James Cole
72d55cb953 Revert workflow change. 2024-06-15 13:02:53 +02:00
James Cole
73ad865581 Add changelog. 2024-06-15 12:56:41 +02:00
James Cole
fefb52beb7 Weekly develop 2024-06-15 12:50:15 +02:00
James Cole
abd503543b Fix regression error in cookie queue 2024-06-15 12:33:56 +02:00
James Cole
e3eb550581 Add currency because why not. 2024-06-15 09:42:09 +02:00
James Cole
46b780758e Fix https://github.com/firefly-iii/firefly-iii/issues/8927 2024-06-15 09:38:19 +02:00
James Cole
b2c3ee9779 Fix https://github.com/firefly-iii/firefly-iii/issues/8954 2024-06-15 09:29:40 +02:00
James Cole
dca899bcee Fix https://github.com/firefly-iii/firefly-iii/issues/8893 2024-06-15 09:25:41 +02:00
James Cole
9667b8a948 Fix https://github.com/firefly-iii/firefly-iii/issues/8958 2024-06-15 09:17:41 +02:00
James Cole
661f225fe7 Add custom routes for Laravel passport. 2024-06-15 09:15:48 +02:00
github-actions
4c6fe0c8de Auto commit for release 'develop' on 2024-06-13 2024-06-13 05:08:55 +02:00
James Cole
78f457950e Merge pull request #8957 from JeroenED/unlimited-nesting-level
Remove nesting level for markdown
2024-06-11 15:17:43 +02:00
Jeroen De Meerleer
d831cc8df2 Update max nesting level for Markdown converter
Increased the max nesting level to 5 for better parsing.
2024-06-11 15:04:15 +02:00
James Cole
7056406afc Merge pull request #8951 from stevewasiura/patch-3
add icon for delete action
2024-06-11 15:03:09 +02:00
github-actions
c85cfcf3e6 Auto commit for release 'develop' on 2024-06-10 2024-06-10 05:09:13 +02:00
Jeroen De Meerleer
db06d06789 Remove unnecessary option from Markdown converter
The 'max_nesting_level' option was removed from the Markdown converter configuration in order to simplify and optimize the code.
2024-06-07 09:05:38 +02:00
github-actions
a28b990cd1 Auto commit for release 'develop' on 2024-06-06 2024-06-06 05:09:02 +02:00
Steve Wasiura
dab4bfa7a6 add icon for delete action
in workflow of reconciling account, sometimes a record needs to be deleted (i.e. in event of a duplicated transaction from an import or error) and this change adds an icon to the delete route

Signed-off-by: Steve Wasiura <steve@waztech.com>
2024-06-03 22:09:22 -04:00
James Cole
6575236f2b Merge pull request #8949 from firefly-iii/dependabot/github_actions/crowdin/github-action-2
Bump crowdin/github-action from 1 to 2
2024-06-03 07:34:04 +02:00
dependabot[bot]
ad582c8806 Bump crowdin/github-action from 1 to 2
Bumps [crowdin/github-action](https://github.com/crowdin/github-action) from 1 to 2.
- [Release notes](https://github.com/crowdin/github-action/releases)
- [Commits](https://github.com/crowdin/github-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: crowdin/github-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 03:59:42 +00:00
github-actions
452e9cb953 Auto commit for release 'develop' on 2024-06-03 2024-06-03 05:09:54 +02:00
James Cole
a64f137b39 Fix missing locales files. 2024-06-02 07:29:41 +02:00
James Cole
c067d6aab0 Catch division by zero 2024-06-01 05:36:21 +02:00
github-actions
119b9920a6 Auto commit for release 'develop' on 2024-05-30 2024-05-30 05:48:54 +02:00
James Cole
99ed54fce8 Revert steps 2024-05-30 05:45:04 +02:00
James Cole
2ea57cdd38 Merge pull request #8930 from stevewasiura/patch-2
icon title chgd from Deposit to Transfer
2024-05-29 18:00:47 +02:00
James Cole
bb94bdfdaf Merge pull request #8929 from stevewasiura/patch-1
icon title chgd from Deposit to Transfer
2024-05-29 17:59:49 +02:00
Steve Wasiura
4de8398cc2 icon title chgd from Deposit to Transfer
Signed-off-by: Steve Wasiura <steve@waztech.com>
2024-05-29 09:20:39 -04:00
Steve Wasiura
e6e8cd5d8a icon title chgd from Deposit to Transfer
Signed-off-by: Steve Wasiura <steve@waztech.com>
2024-05-29 09:15:53 -04:00
James Cole
0b200309ba Catch empty strings 2024-05-28 05:53:17 +02:00
github-actions
a184548912 Auto commit for release 'develop' on 2024-05-27 2024-05-27 05:08:44 +02:00
James Cole
c987191212 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/Console/Commands/Upgrade/CorrectAccountBalance.php
2024-05-26 15:37:20 +02:00
James Cole
7009b444d9 Skip creation using if statement. 2024-05-26 15:36:30 +02:00
github-actions
06551d5367 Auto commit for release 'develop' on 2024-05-25 2024-05-25 20:18:23 +02:00
James Cole
a20622ac0c Fix https://github.com/firefly-iii/firefly-iii/issues/8911 2024-05-25 11:28:32 +02:00
James Cole
ca38117fca Fix https://github.com/firefly-iii/firefly-iii/issues/8907 2024-05-25 08:10:23 +02:00
James Cole
9478f78d4f Merge branch 'main' into develop 2024-05-25 08:05:45 +02:00
James Cole
5c2397bbae Remove unused workflows. 2024-05-25 08:05:32 +02:00
James Cole
92fefef816 Merge branch 'main' into develop 2024-05-24 05:30:29 +02:00
James Cole
d3ced65524 Remove 2024-05-24 05:30:17 +02:00
James Cole
29eb748831 Merge branch 'main' into develop 2024-05-24 05:22:57 +02:00
github-actions
76df3d5f33 Auto commit for release 'develop' on 2024-05-23 2024-05-23 05:10:54 +02:00
James Cole
252076ec1f Add to cleanup 2024-05-22 06:12:19 +02:00
James Cole
bbec28591f Add workflow that responds to PRs 2024-05-22 06:02:49 +02:00
James Cole
075a360ba6 Add new workflow for issue thing. 2024-05-21 20:20:06 +02:00
James Cole
477524a8ae You could've just asked... 2024-05-21 17:48:54 +02:00
James Cole
dfe055732d Fix https://github.com/firefly-iii/firefly-iii/issues/8907 2024-05-21 17:36:05 +02:00
James Cole
78b611a18d Update .gitignore 2024-05-21 17:28:43 +02:00
James Cole
367bdf65e6 Remove auto-generated language files 2024-05-21 17:25:29 +02:00
James Cole
3fc9caa31a Add git ignore, remove .gitkeep. 2024-05-21 17:24:25 +02:00
James Cole
95a41fcab7 Remove auto-generated language files. 2024-05-21 17:23:07 +02:00
James Cole
58b409fc00 Restore confirmation for data removal. 2024-05-20 20:19:23 +02:00
James Cole
3eaaac09ad Clean up balance chart. 2024-05-20 07:30:41 +02:00
James Cole
bcb672920c Fix chart, uses new filter. 2024-05-20 06:55:36 +02:00
James Cole
79b91e25c2 Expand chart api 2024-05-20 06:49:42 +02:00
github-actions
7170931464 Auto commit for release 'develop' on 2024-05-20 2024-05-20 05:09:44 +02:00
github-actions
c1b5a1a13e Auto commit for release 'develop' on 2024-05-19 2024-05-19 10:37:08 +02:00
James Cole
a6265ce8ab Fix line in job. 2024-05-19 10:28:01 +02:00
github-actions
90109917df Auto commit for release 'v6.1.16' on 2024-05-19 2024-05-19 10:26:25 +02:00
James Cole
0acd54c2b7 Update changelog. 2024-05-19 10:21:03 +02:00
James Cole
c96226b9b4 Add final API changes 2024-05-19 10:17:21 +02:00
James Cole
6d143f1624 Clean up API 2024-05-19 06:36:31 +02:00
James Cole
93324d1154 Remove unused variables 2024-05-18 06:57:38 +02:00
github-actions
a39f0e1891 Auto commit for release 'develop' on 2024-05-18 2024-05-18 06:49:29 +02:00
James Cole
822f609a22 Fix ibans 2024-05-18 06:44:18 +02:00
James Cole
cd7ddd1c61 Add more IBAN filters 2024-05-18 06:42:09 +02:00
James Cole
0b63ba26bb Fix autocomplete entries. 2024-05-18 05:51:02 +02:00
James Cole
94d70cdb62 Fix missing parameters 2024-05-17 20:45:16 +02:00
James Cole
acb3831c8b Add parallel thing 2024-05-16 07:30:07 +02:00
github-actions
c9d9ecede4 Auto commit for release 'develop' on 2024-05-16 2024-05-16 07:22:12 +02:00
James Cole
4eb5873353 Merge branch 'main' into develop 2024-05-16 07:17:18 +02:00
James Cole
7ca39fdb21 Fix commands 2024-05-16 07:16:47 +02:00
James Cole
b8d1d7a8c0 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/Support/Models/AccountBalanceCalculator.php
2024-05-16 07:15:36 +02:00
James Cole
1af79eab30 Clean up commands 2024-05-16 07:14:44 +02:00
github-actions
03be2704ce Auto commit for release 'develop' on 2024-05-16 2024-05-16 05:10:41 +02:00
James Cole
34baea66a7 Merge pull request #8880 from firefly-iii/dependabot/github_actions/github/command-1.2.0 2024-05-14 05:43:54 +02:00
James Cole
0638d109d0 Clean up code. 2024-05-13 20:31:52 +02:00
dependabot[bot]
561e228a2d Bump github/command from 1.1.1 to 1.2.0
Bumps [github/command](https://github.com/github/command) from 1.1.1 to 1.2.0.
- [Release notes](https://github.com/github/command/releases)
- [Commits](https://github.com/github/command/compare/v1.1.1...v1.2.0)

---
updated-dependencies:
- dependency-name: github/command
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-13 03:12:36 +00:00
github-actions
cb5d856769 Auto commit for release 'develop' on 2024-05-13 2024-05-13 05:10:16 +02:00
James Cole
04fe5d1fc4 Correct account balances better. 2024-05-12 18:24:38 +02:00
James Cole
45e9d4f8de Fix auto complete 2024-05-12 17:50:54 +02:00
James Cole
73fdbb6202 Update API endpoints and account autocomplete. 2024-05-12 13:31:33 +02:00
James Cole
e49dbefddd Make the combined combination unique. 2024-05-12 08:10:12 +02:00
James Cole
fc5143337a Add a title to the table, so multiple balances per account are possible. 2024-05-12 08:09:50 +02:00
James Cole
4b3eb6dace Rename command. 2024-05-12 06:26:50 +02:00
James Cole
c741b2a819 Add related models. 2024-05-12 06:25:13 +02:00
James Cole
cebfaa32bf Add routine that caches account balances. Add it to the /flush routine as well. 2024-05-12 06:24:11 +02:00
James Cole
d356d39d43 add account balances with some random data 2024-05-11 20:32:25 +02:00
James Cole
7d9f22d3f4 Merge branch 'api' into develop
# Conflicts:
#	app/JsonApi/V3/Accounts/AccountRepository.php
#	app/JsonApi/V3/Accounts/AccountResource.php
#	app/JsonApi/V3/Accounts/Capabilities/AccountQuery.php
#	app/JsonApi/V3/Users/UserSchema.php
2024-05-10 12:52:44 +02:00
James Cole
c6c8f282e2 Restore previous stuff 2024-05-10 12:51:02 +02:00
James Cole
6a64420721 Refactor resources 2024-05-10 09:42:09 +02:00
James Cole
fcde4e2488 no message 2024-05-10 09:41:53 +02:00
James Cole
aa5c4c20e9 Various messy code. 2024-05-10 09:17:09 +02:00
James Cole
794e31e487 Add some experimental account endpoints using a package 2024-05-10 06:43:18 +02:00
James Cole
16bf186312 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	composer.lock
2024-05-10 06:42:47 +02:00
James Cole
45c722e786 Add config, merge later. 2024-05-10 06:36:57 +02:00
github-actions
36d9e5c3fe Auto commit for release 'develop' on 2024-05-09 2024-05-09 05:10:13 +02:00
James Cole
8d614de67f Possible fix for https://github.com/firefly-iii/firefly-iii/issues/8867 2024-05-08 21:55:14 +02:00
James Cole
d17da670ab Fix connect exception, add some debug logs. 2024-05-06 06:33:12 +02:00
github-actions
5bf4df9ad8 Auto commit for release 'develop' on 2024-05-06 2024-05-06 05:10:30 +02:00
James Cole
07db6b59ce Fix webhooks overview. 2024-05-02 06:15:41 +02:00
github-actions
e16f1cf4ee Auto commit for release 'develop' on 2024-05-02 2024-05-02 05:10:23 +02:00
James Cole
4c80d929ca Possible division by zero? 2024-05-01 06:29:28 +02:00
github-actions
16364d9859 Auto commit for release 'develop' on 2024-04-30 2024-04-30 20:33:00 +02:00
James Cole
c24f6acb2c Fix styles 2024-04-30 20:26:05 +02:00
James Cole
4bd19e0627 Expand and fix sort columns 2024-04-30 20:22:31 +02:00
James Cole
69d839997a Fix sorting and order for account lists. 2024-04-29 20:20:11 +02:00
github-actions
c02c027f4f Auto commit for release 'develop' on 2024-04-29 2024-04-29 06:36:36 +02:00
James Cole
b14606625e Upload corrected file 2024-04-29 06:31:18 +02:00
James Cole
222d7b56c7 Merge pull request #8835 from firefly-iii/dependabot/npm_and_yarn/develop/chartjs-chart-sankey-0.12.1 2024-04-29 06:07:17 +02:00
James Cole
b7f7bf42b2 Merge pull request #8834 from firefly-iii/dependabot/composer/develop/ramsey/uuid-4.7.6 2024-04-29 06:07:09 +02:00
dependabot[bot]
0cbd64d31a Bump chartjs-chart-sankey from 0.12.0 to 0.12.1
Bumps [chartjs-chart-sankey](https://github.com/kurkle/chartjs-chart-sankey) from 0.12.0 to 0.12.1.
- [Release notes](https://github.com/kurkle/chartjs-chart-sankey/releases)
- [Commits](https://github.com/kurkle/chartjs-chart-sankey/compare/v0.12.0...v0.12.1)

---
updated-dependencies:
- dependency-name: chartjs-chart-sankey
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-29 03:55:28 +00:00
dependabot[bot]
60bdae47c4 Bump ramsey/uuid from 4.7.5 to 4.7.6
Bumps [ramsey/uuid](https://github.com/ramsey/uuid) from 4.7.5 to 4.7.6.
- [Release notes](https://github.com/ramsey/uuid/releases)
- [Changelog](https://github.com/ramsey/uuid/blob/4.x/CHANGELOG.md)
- [Commits](https://github.com/ramsey/uuid/compare/4.7.5...4.7.6)

---
updated-dependencies:
- dependency-name: ramsey/uuid
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-29 03:34:37 +00:00
James Cole
ca4b38d905 Add debug thing for tables. 2024-04-28 20:20:18 +02:00
James Cole
3674465f53 Translate stuff 2024-04-28 14:43:23 +02:00
James Cole
b951d4130c Allow account grouping 2024-04-28 14:40:22 +02:00
James Cole
7992b810fd Expand view with several new options. Move cache to api endpoints. 2024-04-28 13:30:42 +02:00
James Cole
c1c0afa40b Expand account index overview. 2024-04-28 09:54:28 +02:00
github-actions
56c9026299 Auto commit for release 'develop' on 2024-04-26 2024-04-26 06:18:27 +02:00
James Cole
021ddfc36b Clear out file to see if develop action picks it up correctly. 2024-04-26 06:13:03 +02:00
James Cole
5bd72f6428 Add command 2024-04-26 05:32:21 +02:00
James Cole
feabfe54f0 First attempt at comma based preference collector 2024-04-26 05:31:02 +02:00
James Cole
565409b486 Remove address 2024-04-25 19:51:15 +02:00
James Cole
f57366da5f Add thanks file. 2024-04-25 19:49:58 +02:00
github-actions
064217ccb0 Auto commit for release 'develop' on 2024-04-25 2024-04-25 05:10:20 +02:00
James Cole
fa3ccbda33 Fix phpstan issues. 2024-04-23 19:40:48 +02:00
github-actions
f43aadf02d Auto commit for release 'v6.1.15' on 2024-04-23 2024-04-23 16:34:26 +02:00
James Cole
3b8a4d3e9b Expand changelog. 2024-04-23 16:27:58 +02:00
James Cole
3d410556ef Fix https://github.com/firefly-iii/firefly-iii/issues/8812 2024-04-23 16:24:46 +02:00
880 changed files with 11879 additions and 159308 deletions

View File

@@ -19,6 +19,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
$current = __DIR__;
$paths = [
@@ -35,6 +37,7 @@ $finder = PhpCsFixer\Finder::create()
$config = new PhpCsFixer\Config();
$config->setParallelConfig(ParallelConfigFactory::detect());
return $config->setRules(
[
// rule sets

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,10 @@
parameters:
scanFiles:
- ../_ide_helper_models.php
universalObjectCratesClasses:
- Illuminate\Database\Eloquent\Model
# TODO: slowly remove these parameters and fix the issues found.
reportUnmatchedIgnoredErrors: false
checkGenericClassInNonGenericObjectType: false # remove this rule when all other issues are solved.
ignoreErrors:
# TODO: slowly remove these exceptions and fix the issues found.
- '#Dynamic call to static method#' # all the Laravel ORM things depend on this.
@@ -11,6 +12,7 @@ parameters:
- '#with no value type specified in iterable type array#' # remove this rule when all other issues are solved.
- '#has no value type specified in iterable type array#' # remove this rule when all other issues are solved.
- '#is not allowed to extend#'
- '#does not specify its types#'
- '#switch is forbidden to use#'
- '#is neither abstract nor final#'
- '#on left side of \?\?\= always exists and is not nullable#'

View File

@@ -299,27 +299,6 @@ DKR_BUILD_LOCALE=false
# Won't significantly speed up things.
DKR_CHECK_SQLITE=true
# Run database creation and migration commands. Disable this only if you're 100% sure the DB exists
# and is up to date.
DKR_RUN_MIGRATION=true
# Run database upgrade commands. Disable this only when you're 100% sure your DB is up-to-date
# with the latest fixes (outside of migrations!)
DKR_RUN_UPGRADE=true
# Verify database integrity. Includes all data checks and verifications.
# Disabling this makes Firefly III assume your DB is intact.
DKR_RUN_VERIFY=true
# Run database reporting commands. When disabled, Firefly III won't go over your data to report current state.
# Disabling this should have no impact on data integrity or safety but it won't warn you of possible issues.
DKR_RUN_REPORT=true
# Generate OAuth2 keys.
# When disabled, Firefly III won't attempt to generate OAuth2 Passport keys. This won't be an issue, IFF (if and only if)
# you had previously generated keys already and they're stored in your database for restoration.
DKR_RUN_PASSPORT_INSTALL=true
# Leave the following configuration vars as is.
# Unless you like to tinker and know what you're doing.
APP_NAME=FireflyIII

View File

@@ -4,6 +4,7 @@ updates:
# Check for updates to GitHub Actions every week
- package-ecosystem: "github-actions"
directory: "/"
labels: []
schedule:
interval: "weekly"
@@ -11,6 +12,7 @@ updates:
- package-ecosystem: "composer"
directory: "/" # Location of package manifests
target-branch: develop
labels: []
versioning-strategy: increase
schedule:
interval: "weekly"
@@ -18,6 +20,7 @@ updates:
# yarn / JS updates
- package-ecosystem: "npm"
directory: "/"
labels: []
target-branch: develop
versioning-strategy: increase
schedule:

View File

@@ -6,6 +6,7 @@ Thank you for submitting new code to Firefly III, or any of the related projects
- Please do not open PRs to "discuss" possible solutions or to "get feedback" on your code. I simply don't have time for that.
- Pull requests for the MAIN branch will be closed.
- DO NOT include translated strings in your PR.
- PRs (or parts thereof) that only fix issues inside code comments will not be accepted.
If it feels necessary to open an issue first, please do so, before you open a PR.

View File

@@ -13,7 +13,7 @@ jobs:
close_duplicates:
runs-on: ubuntu-latest
steps:
- uses: github/command@v1.1.1
- uses: github/command@v1.2.1
id: command
with:
allowed_contexts: "issue"

View File

@@ -8,7 +8,7 @@ on:
required: true
default: 'develop'
schedule:
- cron: '0 3 * * MON,THU'
- cron: '0 3 * * MON'
jobs:
build:
@@ -39,7 +39,7 @@ jobs:
php-version: '8.3'
extensions: mbstring, intl, zip, bcmath
- name: crowdin action
uses: crowdin/github-action@v1
uses: crowdin/github-action@v2
with:
upload_sources: true
download_translations: true
@@ -67,6 +67,15 @@ jobs:
env:
FIREFLY_III_ROOT: /github/workspace
GH_TOKEN: ${{ secrets.CHANGELOG_TOKEN }}
- name: "Create THANKS.md"
id: thank-you
uses: JC5/firefly-iii-dev@main
with:
action: 'ff3:thank-you'
output: ''
env:
FIREFLY_III_ROOT: /github/workspace
GH_TOKEN: ''
- name: Extract changelog
id: extract-changelog
uses: JC5/firefly-iii-dev@main
@@ -116,9 +125,9 @@ jobs:
- name: Build JS
run: |
npm install
npm update
npm run prod --workspace=v1
npm run build --workspace=v2
npm update
- name: Run CI
run: |
rm -rf vendor composer.lock
@@ -245,7 +254,7 @@ jobs:
echo '' >> output.txt
echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)."
echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo "Create default release."
git tag -a $releaseName -m "Here be changelog"

195
THANKS.md Executable file
View File

@@ -0,0 +1,195 @@
# Thank you! :tada: :heart: :tada:
Over time, many people have contributed to Firefly III. Their efforts are not always visible, but always remembered and appreciated.
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
## 2024
- withbest
- Steve Wasiura
- imlonghao
- Rahman Yusuf
- Michael Thomas
- WardenJakx
- kuilin
- Stevie Robinson
- luzpaz
- Lemuel Roberto Bonifácio
- maureenferreira
## 2023
- tieu1991
- Maxco10
- zqye
- Mateus Pereira
- josephbadow
- Christian Desktop
- Edgars
- Hannah K
- noxonad
- Kaijia Feng
- Marc Ordinas i Llopis
- Kuba Turek
- Julien Stébenne
## 2022
- Johannes Zellner
- Janne Heß
- charlesteets
- Nathan PERIER
- Jan Willhaus
- canoine
- Rick Cuddy
- James
- Hugo Meyronneinc
- naveen
- neilnaveen
- naveensrinivasan
- Federico Micelli
- George Hahn
## 2021
- StillLoading
- Igor Rzegocki
- Lorenzo Breda
- Hosh
- Flightkick
- alex6480
- VREEdom
- Hamza FADIL
- Kasper Læssø Sørensen
- Alex
- Jeroen De Meerleer
- Ruben van Erk
- Fabian Zimmermann
- Mirko Berger
- KaihatsuOnline
- MihataBG
## 2020
- Hannes Körber
- Julien Cassagne
- bu4ak
- Viktor Yakovlev
- Oliver Kaufmann
- Arvind Chembarpu
- GrayStrider
- psychowood
- Hosh Sadiq
- emansih
- Aniruddha Maru
- johnny
- sephrat
- bpatath
- Florian Dupret
- Maxim Kurbatov
- Lucas Guima
- Sandro
- Ruben Verhoef
- Daniel Idzerda
- Calum Smith
- Agraphie
- Tomer Shvueli
- Tomer S
## 2019
- Pascal Jungblut
- Justyn Shull
- Timendum
- Nicolas Lœuillet
- Dominic Guhl
- Melroy van den Berg
- Henning Stein
- Jan Klepek
- Jonathan
- Geoffrey “Frogeye” Preud'homme
- Michael Fix
- Juraj Mlich
- Eddybrando Vásquez
- hulloanson
- Will Rouesnel
- lastlink
- Mr. Funk
- Simon Taddiken
- Joris
- Bastiaan Nijkamp
## 2018
- a1ex4
- Daniel Quah
- Marco Lourenço
- Dennis Enderink
- Luca Bognolo
- Mike Conway
- Ben
- Mathieu Post
- George Hertz
- HamuZ HamuZ
- David Meiseles
- Erik Gelderblom
- Luca Vallerini
- Clemens Wijnekus
- Jacob Weisz
- Mateusz Gozdek
- anmol26s
- Kevin Hellemun
- Shashank M Chakravarthy
- Nico Schreiner
- Paul Sohier
- Brenden Conte
- Ben Yanke
- Andrew Prokhorenkov
- devlearner
- Kelvin
- J'informatique
## 2017
- Victor Mosin
- Justin
- Hugo van Duijn
- Lukas Winkler
- Marcin Szymanski
- Jens Kat
- koziolek
- jleeong
- Simon Hanna
- richard & xeli.eu
- Sergey Besedin
- Welbert Serra
- Joris de Vries
- Patrick Kostjens
- Enrico Lamperti
- Christian Musa
- Enno Lohmeier
## 2016
- Sander
- Toon Schoenmakers
- Telyn
- Sander Kleykens
- Tom van der Werf
- Matthew Peck
- Sander Mulders
- Bonno Nachtegaal-Karels
- Niek Haarman
- Edwin
- Thijs Alkemade
- zjean
- Graham Miller
- Robert Horlings
- leander091
## 2015
- Antonio Spinelli
- Colin O'Dell
- RonaldvanMeer
- Richard Ebbers
- Balazs Varkonyi
- Niek van der Kooy
- Ilya Kil
## 2014
- Stewart Malik
- Graham Campbell
Thank you for all your support!

View File

@@ -69,7 +69,7 @@ class UpdateController extends Controller
*/
public function update(UpdateRequest $request, TransactionGroup $transactionGroup): JsonResponse
{
app('log')->debug('Now in update routine for transaction group!');
app('log')->debug('Now in update routine for transaction group');
$data = $request->getAll();
// Fixes 8750.

View File

@@ -34,6 +34,7 @@ use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CurrencyTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use League\Fractal\Resource\Item;
/**
@@ -164,6 +165,7 @@ class UpdateController extends Controller
public function update(UpdateRequest $request, TransactionCurrency $currency): JsonResponse
{
$data = $request->getAll();
Log::debug(__METHOD__, $data);
/** @var User $user */
$user = auth()->user();
@@ -173,6 +175,11 @@ class UpdateController extends Controller
if (array_key_exists('enabled', $data) && false === $data['enabled'] && 1 === count($set) && $set->first()->id === $currency->id) {
return response()->json([], 409);
}
// second safety catch on currency disable.
if (array_key_exists('enabled', $data) && false === $data['enabled'] && $this->repository->currencyInUse($currency)) {
return response()->json([], 409);
}
$currency = $this->repository->update($currency, $data);
app('preferences')->mark();

View File

@@ -32,6 +32,7 @@ use FireflyIII\Models\Preference;
use FireflyIII\Transformers\PreferenceTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
@@ -97,6 +98,34 @@ class PreferencesController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* TODO This endpoint is not documented.
*
* Return a single preference by name.
*
* @param Collection<int, Preference> $collection
*/
public function showList(Collection $collection): JsonResponse
{
$manager = $this->getManager();
$count = $collection->count();
$pageSize = $this->parameters->get('limit');
$preferences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($preferences, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.preferences.show-list').$this->buildParams());
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($preferences, $transformer, self::RESOURCE_KEY);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/preferences/storePreference

View File

@@ -63,7 +63,7 @@ class StoreRequest extends FormRequest
'order' => $this->convertInteger('order'),
'currency_code' => $this->convertString('currency_code'),
'virtual_balance' => $this->convertString('virtual_balance'),
'iban' => $this->convertString('iban'),
'iban' => $this->convertIban('iban'),
'BIC' => $this->convertString('bic'),
'account_number' => $this->convertString('account_number'),
'account_role' => $this->convertString('account_role'),

View File

@@ -51,7 +51,7 @@ class UpdateRequest extends FormRequest
'include_net_worth' => ['include_net_worth', 'boolean'],
'account_type_name' => ['type', 'convertString'],
'virtual_balance' => ['virtual_balance', 'convertString'],
'iban' => ['iban', 'convertString'],
'iban' => ['iban', 'convertIban'],
'BIC' => ['bic', 'convertString'],
'account_number' => ['account_number', 'convertString'],
'account_role' => ['account_role', 'convertString'],

View File

@@ -58,7 +58,7 @@ class StoreRequest extends FormRequest
$models = config('firefly.valid_attachment_models');
$models = array_map(
static function (string $className) {
return str_replace('FireflyIII\\Models\\', '', $className);
return str_replace('FireflyIII\Models\\', '', $className);
},
$models
);

View File

@@ -60,7 +60,7 @@ class UpdateRequest extends FormRequest
$models = config('firefly.valid_attachment_models');
$models = array_map(
static function (string $className) {
return str_replace('FireflyIII\\Models\\', '', $className);
return str_replace('FireflyIII\Models\\', '', $className);
},
$models
);

View File

@@ -103,14 +103,14 @@ class StoreRequest extends FormRequest
// source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string)$object['source_id']),
'source_name' => $this->clearString((string)$object['source_name']),
'source_iban' => $this->clearString((string)$object['source_iban']),
'source_iban' => $this->clearIban((string)$object['source_iban']),
'source_number' => $this->clearString((string)$object['source_number']),
'source_bic' => $this->clearString((string)$object['source_bic']),
// destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string)$object['destination_id']),
'destination_name' => $this->clearString((string)$object['destination_name']),
'destination_iban' => $this->clearString((string)$object['destination_iban']),
'destination_iban' => $this->clearIban((string)$object['destination_iban']),
'destination_number' => $this->clearString((string)$object['destination_number']),
'destination_bic' => $this->clearString((string)$object['destination_bic']),

View File

@@ -28,22 +28,21 @@ use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Autocomplete\AutocompleteRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Models\AccountBalance;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class AccountController
*/
class AccountController extends Controller
{
use AccountFilter;
private AdminAccountRepositoryInterface $adminRepository;
private array $balanceTypes;
private AccountRepositoryInterface $repository;
private AccountRepositoryInterface $repository;
private TransactionCurrency $default;
private ExchangeRateConverter $converter;
/**
* AccountController constructor.
@@ -53,83 +52,88 @@ class AccountController extends Controller
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(AccountRepositoryInterface::class);
$this->adminRepository = app(AdminAccountRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->adminRepository->setUserGroup($userGroup);
}
$userGroup = $this->validateUserGroup($request);
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUserGroup($userGroup);
$this->default = app('amount')->getDefaultCurrency();
$this->converter = app(ExchangeRateConverter::class);
return $next($request);
}
);
$this->balanceTypes = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
}
/**
* Documentation for this endpoint:
* TODO list of checks
* 1. use dates from ParameterBag
* 2. Request validates dates
* 3. Request includes user_group_id
* 4. Endpoint is documented.
* 5. Collector uses user_group_id
*
* @throws FireflyException
* @throws FireflyException
* Documentation: https://api-docs.firefly-iii.org/?urls.primaryName=2.1.0%20(v2)#/autocomplete/getAccountsAC
*/
public function accounts(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$types = $data['types'];
$query = $data['query'];
$date = $this->parameters->get('date') ?? today(config('app.timezone'));
$result = $this->adminRepository->searchAccount((string)$query, $types, $data['limit']);
$defaultCurrency = app('amount')->getDefaultCurrency();
$groupedResult = [];
$allItems = [];
$queryParameters = $request->getParameters();
$result = $this->repository->searchAccount($queryParameters['query'], $queryParameters['account_types'], $queryParameters['size']);
$return = [];
/** @var Account $account */
foreach ($result as $account) {
$nameWithBalance = $account->name;
$currency = $this->repository->getAccountCurrency($account) ?? $defaultCurrency;
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
$balance = app('steam')->balance($account, $date);
$nameWithBalance = sprintf('%s (%s)', $account->name, app('amount')->formatAnything($currency, $balance, false));
}
$type = (string)trans(sprintf('firefly.%s', $account->accountType->type));
$groupedResult[$type] ??= [
'group ' => $type,
'items' => [],
];
$allItems[] = [
'id' => (string)$account->id,
'value' => (string)$account->id,
'name' => $account->name,
'name_with_balance' => $nameWithBalance,
'label' => $nameWithBalance,
'type' => $account->accountType->type,
'currency_id' => (string)$currency->id,
'currency_name' => $currency->name,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
];
$return[] = $this->parseAccount($account);
}
usort(
$allItems,
static function (array $left, array $right): int {
$order = [AccountType::ASSET, AccountType::REVENUE, AccountType::EXPENSE];
$posLeft = (int)array_search($left['type'], $order, true);
$posRight = (int)array_search($right['type'], $order, true);
return response()->json($return);
}
return $posLeft - $posRight;
private function parseAccount(Account $account): array
{
$currency = $this->repository->getAccountCurrency($account);
return [
'id' => (string) $account->id,
'title' => $account->name,
'meta' => [
'type' => $account->accountType->type,
'currency_id' => null === $currency ? null : (string) $currency->id,
'currency_code' => $currency?->code,
'currency_symbol' => $currency?->symbol,
'currency_decimal_places' => $currency?->decimal_places,
'account_balances' => $this->getAccountBalances($account),
],
];
}
private function getAccountBalances(Account $account): array
{
$return = [];
$balances = $this->repository->getAccountBalances($account);
/** @var AccountBalance $balance */
foreach ($balances as $balance) {
try {
$return[] = $this->parseAccountBalance($balance);
} catch (FireflyException $e) {
Log::error(sprintf('Could not parse convert account balance: %s', $e->getMessage()));
}
);
}
return response()->json($allItems);
return $return;
}
/**
* @throws FireflyException
*/
private function parseAccountBalance(AccountBalance $balance): array
{
$currency = $balance->transactionCurrency;
return [
'title' => $balance->title,
'native_amount' => $this->converter->convert($currency, $this->default, today(), $balance->balance),
'amount' => app('steam')->bcround($balance->balance, $currency->decimal_places),
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'native_currency_id' => (string) $this->default->id,
'native_currency_code' => $this->default->code,
'native_currency_symbol' => $this->default->symbol,
'native_currency_decimal_places' => $this->default->decimal_places,
];
}
}

View File

@@ -45,11 +45,7 @@ class CategoryController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(CategoryRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
}
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}
@@ -57,23 +53,18 @@ class CategoryController extends Controller
}
/**
* Documentation for this endpoint:
* TODO list of checks
* 1. use dates from ParameterBag
* 2. Request validates dates
* 3. Request includes user_group_id
* 4. Endpoint is documented.
* 5. Collector uses user_group_id
* Documentation: https://api-docs.firefly-iii.org/?urls.primaryName=2.1.0%20(v2)#/autocomplete/getCategoriesAC
*/
public function categories(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchCategory($data['query'], $this->parameters->get('limit'));
$filtered = $result->map(
$queryParameters = $request->getParameters();
$result = $this->repository->searchCategory($queryParameters['query'], $queryParameters['size']);
$filtered = $result->map(
static function (Category $item) {
return [
'id' => (string)$item->id,
'name' => $item->name,
'id' => (string)$item->id,
'title' => $item->name,
'meta' => [],
];
}
);

View File

@@ -45,11 +45,7 @@ class TagController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(TagRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
}
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}
@@ -57,25 +53,20 @@ class TagController extends Controller
}
/**
* Documentation for this endpoint:
* TODO list of checks
* 1. use dates from ParameterBag
* 2. Request validates dates
* 3. Request includes user_group_id
* 4. Endpoint is documented.
* 5. Collector uses user_group_id
* Documentation: https://api-docs.firefly-iii.org/?urls.primaryName=2.1.0%20(v2)#/autocomplete/getTagsAC
*/
public function tags(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchTag($data['query'], $data['limit']);
$filtered = $result->map(
$queryParameters = $request->getParameters();
$result = $this->repository->searchTag($queryParameters['query'], $queryParameters['size']);
$filtered = $result->map(
static function (Tag $item) {
return [
'id' => (string)$item->id,
'name' => $item->tag,
'value' => (string)$item->id,
'id' => (string) $item->id,
'title' => $item->tag,
'value' => (string) $item->id,
'label' => $item->tag,
'meta' => [],
];
}
);

View File

@@ -45,11 +45,7 @@ class TransactionController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(JournalRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
}
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}
@@ -57,30 +53,25 @@ class TransactionController extends Controller
}
/**
* Documentation for this endpoint:
* TODO list of checks
* 1. use dates from ParameterBag
* 2. Request validates dates
* 3. Request includes user_group_id
* 4. Endpoint is documented.
* 5. Collector uses user_group_id
* Documentation: https://api-docs.firefly-iii.org/?urls.primaryName=2.1.0%20(v2)#/autocomplete/getTransactionsAC
*/
public function transactionDescriptions(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchJournalDescriptions($data['query'], $data['limit']);
$queryParameters = $request->getParameters();
$result = $this->repository->searchJournalDescriptions($queryParameters['query'], $queryParameters['size']);
// limit and unique
$filtered = $result->unique('description');
$array = [];
$filtered = $result->unique('description');
$array = [];
/** @var TransactionJournal $journal */
foreach ($filtered as $journal) {
$array[] = [
'id' => (string)$journal->id,
'transaction_group_id' => (string)$journal->transaction_group_id,
'name' => $journal->description,
'description' => $journal->description,
'id' => (string) $journal->id,
'title' => $journal->description,
'meta' => [
'transaction_group_id' => (string) $journal->transaction_group_id,
],
];
}

View File

@@ -24,19 +24,17 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Chart\DashboardChartRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Api\V2\Request\Chart\ChartRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Support\Chart\ChartData;
use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
/**
* Class AccountController
@@ -44,10 +42,12 @@ use Illuminate\Support\Collection;
class AccountController extends Controller
{
use CleansChartData;
use CollectsAccountsFromFilter;
use ValidatesUserGroupTrait;
private AccountRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
private ChartData $chartData;
private TransactionCurrency $default;
public function __construct()
{
@@ -55,8 +55,9 @@ class AccountController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(AccountRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
$this->repository->setUserGroup($this->validateUserGroup($request));
$this->chartData = new ChartData();
$this->default = app('amount')->getDefaultCurrency();
return $next($request);
}
@@ -64,107 +65,76 @@ class AccountController extends Controller
}
/**
* This endpoint is documented at
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/charts/getChartAccountOverview
*
* The native currency is the preferred currency on the page /currencies.
*
* If a transaction has foreign currency = native currency, the foreign amount will be used, no conversion
* will take place.
*
* TODO validate and set user_group_id from request
* TODO fix documentation
*
* @throws FireflyException
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function dashboard(DashboardChartRequest $request): JsonResponse
public function dashboard(ChartRequest $request): JsonResponse
{
/** @var Carbon $start */
$start = $this->parameters->get('start');
$queryParameters = $request->getParameters();
$accounts = $this->getAccountList($queryParameters);
/** @var Carbon $end */
$end = $this->parameters->get('end');
$end->endOfDay();
/** @var TransactionCurrency $default */
$default = app('amount')->getDefaultCurrency();
$params = $request->getAll();
/** @var Collection $accounts */
$accounts = $params['accounts'];
$chartData = [];
// user's preferences
if (0 === $accounts->count()) {
$defaultSet = $this->repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT])->pluck('id')->toArray();
$frontpage = app('preferences')->get('frontpageAccounts', $defaultSet);
if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) {
$frontpage->data = $defaultSet;
$frontpage->save();
}
$accounts = $this->repository->getAccountsById($frontpage->data);
}
// both options are overruled by "preselected"
if ('all' === $params['preselected']) {
$accounts = $this->repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
}
if ('assets' === $params['preselected']) {
$accounts = $this->repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]);
}
if ('liabilities' === $params['preselected']) {
$accounts = $this->repository->getAccountsByType([AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
}
// move date to end of day
$queryParameters['start']->startOfDay();
$queryParameters['end']->endOfDay();
// loop each account, and collect info:
/** @var Account $account */
foreach ($accounts as $account) {
$currency = $this->repository->getAccountCurrency($account);
if (null === $currency) {
$currency = $default;
}
$currentSet = [
'label' => $account->name,
// the currency that belongs to the account.
'currency_id' => (string)$currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
// the default currency of the user (could be the same!)
'native_currency_id' => (string)$default->id,
'native_currency_code' => $default->code,
'native_currency_symbol' => $default->symbol,
'native_currency_decimal_places' => $default->decimal_places,
'start' => $start->toAtomString(),
'end' => $end->toAtomString(),
'period' => '1D',
'entries' => [],
'native_entries' => [],
];
$currentStart = clone $start;
$range = app('steam')->balanceInRange($account, $start, clone $end, $currency);
$rangeConverted = app('steam')->balanceInRangeConverted($account, $start, clone $end, $default);
$previous = array_values($range)[0];
$previousConverted = array_values($rangeConverted)[0];
while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format] : $previous;
$balanceConverted = array_key_exists($format, $rangeConverted) ? $rangeConverted[$format] : $previousConverted;
$previous = $balance;
$previousConverted = $balanceConverted;
$currentStart->addDay();
$currentSet['entries'][$label] = $balance;
$currentSet['native_entries'][$label] = $balanceConverted;
}
$chartData[] = $currentSet;
$this->renderAccountData($queryParameters, $account);
}
return response()->json($this->clean($chartData));
return response()->json($this->chartData->render());
}
/**
* @throws FireflyException
*/
private function renderAccountData(array $params, Account $account): void
{
$currency = $this->repository->getAccountCurrency($account);
if (null === $currency) {
$currency = $this->default;
}
$currentSet = [
'label' => $account->name,
// the currency that belongs to the account.
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
// the default currency of the user (could be the same!)
'native_currency_id' => (string) $this->default->id,
'native_currency_code' => $this->default->code,
'native_currency_symbol' => $this->default->symbol,
'native_currency_decimal_places' => $this->default->decimal_places,
'date' => $params['start']->toAtomString(),
'start' => $params['start']->toAtomString(),
'end' => $params['end']->toAtomString(),
'period' => '1D',
'entries' => [],
'native_entries' => [],
];
$currentStart = clone $params['start'];
$range = app('steam')->balanceInRange($account, $params['start'], clone $params['end'], $currency);
$rangeConverted = app('steam')->balanceInRangeConverted($account, $params['start'], clone $params['end'], $this->default);
$previous = array_values($range)[0];
$previousConverted = array_values($rangeConverted)[0];
while ($currentStart <= $params['end']) {
$format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format] : $previous;
$balanceConverted = array_key_exists($format, $rangeConverted) ? $rangeConverted[$format] : $previousConverted;
$previous = $balance;
$previousConverted = $balanceConverted;
$currentStart->addDay();
$currentSet['entries'][$label] = $balance;
$currentSet['native_entries'][$label] = $balanceConverted;
}
$this->chartData->add($currentSet);
}
}

View File

@@ -24,18 +24,18 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Chart\BalanceChartRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Api\V2\Request\Chart\ChartRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Support\Chart\ChartData;
use FireflyIII\Support\Http\Api\AccountBalanceGrouped;
use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
/**
* Class BalanceController
@@ -43,7 +43,30 @@ use Illuminate\Support\Collection;
class BalanceController extends Controller
{
use CleansChartData;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
use CollectsAccountsFromFilter;
private AccountRepositoryInterface $repository;
private GroupCollectorInterface $collector;
private ChartData $chartData;
// private TransactionCurrency $default;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(AccountRepositoryInterface::class);
$this->collector = app(GroupCollectorInterface::class);
$userGroup = $this->validateUserGroup($request);
$this->repository->setUserGroup($userGroup);
$this->collector->setUserGroup($userGroup);
$this->chartData = new ChartData();
// $this->default = app('amount')->getDefaultCurrency();
return $next($request);
}
);
}
/**
* The code is practically a duplicate of ReportController::operations.
@@ -54,50 +77,43 @@ class BalanceController extends Controller
* If the transaction being processed is already in native currency OR if the
* foreign amount is in the native currency, the amount will not be converted.
*
* TODO validate and set user_group_id
* TODO collector set group, not user
*
* @throws FireflyException
*/
public function balance(BalanceChartRequest $request): JsonResponse
public function balance(ChartRequest $request): JsonResponse
{
$params = $request->getAll();
$queryParameters = $request->getParameters();
$accounts = $this->getAccountList($queryParameters);
/** @var Carbon $start */
$start = $this->parameters->get('start');
/** @var Carbon $end */
$end = $this->parameters->get('end');
$end->endOfDay();
/** @var Collection $accounts */
$accounts = $params['accounts'];
/** @var string $preferredRange */
$preferredRange = $params['period'];
// move date to end of day
$queryParameters['start']->startOfDay();
$queryParameters['end']->endOfDay();
// prepare for currency conversion and data collection:
/** @var TransactionCurrency $default */
$default = app('amount')->getDefaultCurrency();
$default = app('amount')->getDefaultCurrency();
// get journals for entire period:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setRange($start, $end)->withAccountInformation();
$collector->setXorAccounts($accounts);
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::RECONCILIATION, TransactionType::TRANSFER]);
$journals = $collector->getExtractedJournals();
$object = new AccountBalanceGrouped();
$object->setPreferredRange($preferredRange);
$this->collector->setRange($queryParameters['start'], $queryParameters['end'])
->withAccountInformation()
->setXorAccounts($accounts)
->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::RECONCILIATION, TransactionType::TRANSFER])
;
$journals = $this->collector->getExtractedJournals();
$object = new AccountBalanceGrouped();
$object->setPreferredRange($queryParameters['period']);
$object->setDefault($default);
$object->setAccounts($accounts);
$object->setJournals($journals);
$object->setStart($start);
$object->setEnd($end);
$object->setStart($queryParameters['start']);
$object->setEnd($queryParameters['end']);
$object->groupByCurrencyAndPeriod();
$chartData = $object->convertToChartData();
$data = $object->convertToChartData();
foreach ($data as $entry) {
$this->chartData->add($entry);
}
return response()->json($this->clean($chartData));
return response()->json($this->chartData->render());
}
}

View File

@@ -64,12 +64,9 @@ class BudgetController extends Controller
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->currency = app('amount')->getDefaultCurrency();
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
$this->opsRepository->setUserGroup($userGroup);
}
$this->repository->setUserGroup($userGroup);
$this->opsRepository->setUserGroup($userGroup);
return $next($request);
}
@@ -124,11 +121,11 @@ class BudgetController extends Controller
foreach ($rows as $row) {
$current = [
'label' => $budget->name,
'currency_id' => (string)$row['currency_id'],
'currency_id' => (string) $row['currency_id'],
'currency_code' => $row['currency_code'],
'currency_name' => $row['currency_name'],
'currency_decimal_places' => $row['currency_decimal_places'],
'native_currency_id' => (string)$row['native_currency_id'],
'native_currency_id' => (string) $row['native_currency_id'],
'native_currency_code' => $row['native_currency_code'],
'native_currency_name' => $row['native_currency_name'],
'native_currency_decimal_places' => $row['native_currency_decimal_places'],
@@ -189,12 +186,12 @@ class BudgetController extends Controller
foreach ($array as $currencyId => $block) {
$this->currencies[$currencyId] ??= TransactionCurrency::find($currencyId);
$return[$currencyId] ??= [
'currency_id' => (string)$currencyId,
'currency_id' => (string) $currencyId,
'currency_code' => $block['currency_code'],
'currency_name' => $block['currency_name'],
'currency_symbol' => $block['currency_symbol'],
'currency_decimal_places' => (int)$block['currency_decimal_places'],
'native_currency_id' => (string)$this->currency->id,
'currency_decimal_places' => (int) $block['currency_decimal_places'],
'native_currency_id' => (string) $this->currency->id,
'native_currency_code' => $this->currency->code,
'native_currency_name' => $this->currency->name,
'native_currency_symbol' => $this->currency->symbol,

View File

@@ -57,10 +57,7 @@ class CategoryController extends Controller
function ($request, $next) {
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->accountRepos->setUserGroup($userGroup);
}
$this->accountRepos->setUserGroup($this->validateUserGroup($request));
return $next($request);
}
@@ -100,25 +97,25 @@ class CategoryController extends Controller
/** @var array $journal */
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
$currencyId = (int) $journal['currency_id'];
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
$currencies[$currencyId] = $currency;
$categoryName = null === $journal['category_name'] ? (string)trans('firefly.no_category') : $journal['category_name'];
$categoryName = null === $journal['category_name'] ? (string) trans('firefly.no_category') : $journal['category_name'];
$amount = app('steam')->positive($journal['amount']);
$nativeAmount = $converter->convert($default, $currency, $journal['date'], $amount);
$key = sprintf('%s-%s', $categoryName, $currency->code);
if ((int)$journal['foreign_currency_id'] === $default->id) {
if ((int) $journal['foreign_currency_id'] === $default->id) {
$nativeAmount = app('steam')->positive($journal['foreign_amount']);
}
// create arrays
$return[$key] ??= [
'label' => $categoryName,
'currency_id' => (string)$currency->id,
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'native_currency_id' => (string)$default->id,
'native_currency_id' => (string) $default->id,
'native_currency_code' => $default->code,
'native_currency_name' => $default->name,
'native_currency_symbol' => $default->symbol,
@@ -138,7 +135,7 @@ class CategoryController extends Controller
// order by native amount
usort($return, static function (array $a, array $b) {
return (float)$a['native_amount'] < (float)$b['native_amount'] ? 1 : -1;
return (float) $a['native_amount'] < (float) $b['native_amount'] ? 1 : -1;
});
$converter->summarize();

View File

@@ -157,6 +157,9 @@ class Controller extends BaseController
{
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
// TODO add stuff to path?
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$objects = $paginator->getCollection();

View File

@@ -0,0 +1,111 @@
<?php
/*
* AccountController.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\JsonApi;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\JsonApi\V2\Accounts\AccountCollectionQuery;
use FireflyIII\JsonApi\V2\Accounts\AccountSchema;
use FireflyIII\JsonApi\V2\Accounts\AccountSingleQuery;
use FireflyIII\Models\Account;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Core\Responses\DataResponse;
use LaravelJsonApi\Laravel\Http\Controllers\Actions;
/**
* Class AccountController
*
* This class handles api/v2 requests for accounts.
* Most stuff is default stuff.
*/
class AccountController extends Controller
{
use Actions\AttachRelationship;
use Actions\Destroy;
use Actions\DetachRelationship;
use Actions\FetchMany;
// use Actions\FetchOne;
use Actions\FetchRelated;
use Actions\FetchRelationship;
use Actions\Store;
use Actions\Update;
use Actions\UpdateRelationship;
/**
* Fetch zero to many JSON API resources.
*
* @return Responsable|Response
*/
public function index(AccountSchema $schema, AccountCollectionQuery $request)
{
Log::debug(__METHOD__);
$models = $schema
->repository()
->queryAll()
->withRequest($request)
->get()
;
// do something custom...
return new DataResponse($models);
}
/**
* Fetch zero to one JSON API resource by id.
*
* @return Responsable|Response
*/
public function show(AccountSchema $schema, AccountSingleQuery $request, Account $account)
{
Log::debug(__METHOD__);
$model = $schema->repository()
->queryOne($account)
->withRequest($request)
->first()
;
Log::debug(sprintf('%s again!', __METHOD__));
// do something custom...
return new DataResponse($model);
}
// public function readAccountBalances(AnonymousQuery $query, AccountBalanceSchema $schema, Account $account): Responsable
// {
// $schema = JsonApi::server()->schemas()->schemaFor('account-balances');
//
// $models = $schema
// ->repository()
// ->queryAll()
// ->withRequest($query)
// ->withAccount($account)
// ->get()
// ;
//
// return DataResponse::make($models);
// }
}

View File

@@ -30,6 +30,7 @@ use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Transformers\V2\AccountTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Log;
class IndexController extends Controller
{
@@ -57,21 +58,35 @@ class IndexController extends Controller
}
/**
* TODO the sort instructions need proper repeatable documentation.
* TODO see autocomplete/account controller for list.
*/
public function index(IndexRequest $request): JsonResponse
{
$this->repository->resetAccountOrder();
$types = $request->getAccountTypes();
$instructions = $request->getSortInstructions('accounts');
$accounts = $this->repository->getAccountsByType($types, $instructions);
$pageSize = $this->parameters->get('limit');
$count = $accounts->count();
$accounts = $accounts->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page'));
$transformer = new AccountTransformer();
$types = $request->getAccountTypes();
$sorting = $request->getSortInstructions('accounts');
$filters = $request->getFilterInstructions('accounts');
$accounts = $this->repository->getAccountsByType($types, $sorting, $filters);
$pageSize = $this->parameters->get('limit');
$count = $accounts->count();
$this->parameters->set('sort', $instructions);
// depending on the sort parameters, this list must not be split, because the
// order is calculated in the account transformer and by that time it's too late.
$first = array_key_first($sorting);
$disablePagination = in_array($first, ['last_activity', 'balance', 'balance_difference'], true);
Log::debug(sprintf('Will disable pagination in account index v2? %s', var_export($disablePagination, true)));
if (!$disablePagination) {
$accounts = $accounts->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
}
$paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page'));
$transformer = new AccountTransformer();
$this->parameters->set('disablePagination', $disablePagination);
$this->parameters->set('pageSize', $pageSize);
$this->parameters->set('sort', $sorting);
$this->parameters->set('filters', $filters);
$transformer->setParameters($this->parameters); // give params to transformer
return response()

View File

@@ -45,11 +45,7 @@ class UpdateController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(AccountRepositoryInterface::class);
// new way of user group validation
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
}
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}

View File

@@ -46,12 +46,7 @@ class IndexController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BillRepositoryInterface::class);
// new way of user group validation
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
}
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}

View File

@@ -46,12 +46,7 @@ class ShowController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BillRepositoryInterface::class);
// new way of user group validation
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
}
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}

View File

@@ -45,11 +45,7 @@ class SumController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BillRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
}
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}

View File

@@ -46,11 +46,7 @@ class IndexController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(PiggyBankRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
}
$this->repository->setUserGroup($this->validateUserGroup($request));
return $next($request);
}

View File

@@ -52,10 +52,8 @@ class NetWorthController extends Controller
$this->repository = app(AccountRepositoryInterface::class);
// new way of user group validation
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->netWorth->setUserGroup($userGroup);
$this->repository->setUserGroup($userGroup);
}
$this->netWorth->setUserGroup($userGroup);
$this->repository->setUserGroup($userGroup);
return $next($request);
}

View File

@@ -23,47 +23,68 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Request\Autocomplete;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\AccountType;
use FireflyIII\JsonApi\Rules\IsValidFilter;
use FireflyIII\JsonApi\Rules\IsValidPage;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\ParsesQueryFilters;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use LaravelJsonApi\Core\Query\QueryParameters;
use LaravelJsonApi\Validation\Rule as JsonApiRule;
/**
* Class AutocompleteRequest
*/
class AutocompleteRequest extends FormRequest
{
use AccountFilter;
use ChecksLogin;
use ConvertsDataTypes;
use ParsesQueryFilters;
protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS];
public function getData(): array
/**
* Loops over all possible query parameters (these are shared over ALL auto complete requests)
* and returns a validated array of parameters.
*
* The advantage is a single class. But you may also submit "account types" to an endpoint that doesn't use these.
*/
public function getParameters(): array
{
$types = $this->convertString('types');
$array = [];
if ('' !== $types) {
$array = explode(',', $types);
}
$limit = $this->convertInteger('limit');
$limit = 0 === $limit ? 10 : $limit;
// remove 'initial balance' and another from allowed types. its internal
$array = array_diff($array, [AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION]);
$queryParameters = QueryParameters::cast($this->all());
return [
'types' => $array,
'query' => $this->convertString('query'),
'date' => $this->getCarbonDate('date'),
'limit' => $limit,
'date' => $this->dateOrToday($queryParameters, 'date'),
'query' => $this->arrayOfStrings($queryParameters, 'query'),
'size' => $this->integerFromQueryParams($queryParameters, 'size', 50),
'account_types' => $this->getAccountTypeParameter($this->arrayOfStrings($queryParameters, 'account_types')),
];
}
public function rules(): array
{
return [
'limit' => 'min:0|max:1337',
'fields' => JsonApiRule::notSupported(),
'filter' => ['nullable', 'array', new IsValidFilter(['query', 'date', 'account_types'])],
'include' => JsonApiRule::notSupported(),
'page' => ['nullable', 'array', new IsValidPage(['size'])],
'sort' => JsonApiRule::notSupported(),
];
}
private function getAccountTypeParameter(mixed $types): array
{
if (is_string($types) && str_contains($types, ',')) {
$types = explode(',', $types);
}
if (!is_iterable($types)) {
$types = [$types];
}
$return = [];
foreach ($types as $type) {
$return = array_merge($return, $this->mapAccountTypes($type));
}
return array_unique($return);
}
}

View File

@@ -0,0 +1,118 @@
<?php
/*
* DashboardChartRequest.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V2\Request\Chart;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\JsonApi\Rules\IsValidFilter;
use FireflyIII\Rules\IsFilterValueIn;
use FireflyIII\Support\Http\Api\ParsesQueryFilters;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
use LaravelJsonApi\Core\Query\QueryParameters;
use LaravelJsonApi\Validation\Rule as JsonApiRule;
/**
* Class ChartRequest
*/
class ChartRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
use ParsesQueryFilters;
use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
public function getParameters(): array
{
$queryParameters = QueryParameters::cast($this->all());
return [
'start' => $this->dateOrToday($queryParameters, 'start'),
'end' => $this->dateOrToday($queryParameters, 'end'),
'preselected' => $this->stringFromQueryParams($queryParameters, 'preselected', 'empty'),
'period' => $this->stringFromQueryParams($queryParameters, 'period', '1M'),
'accounts' => $this->arrayOfStrings($queryParameters, 'accounts'),
// preselected heeft maar een paar toegestane waardes, dat moet ook goed gaan.
// 'query' => $this->arrayOfStrings($queryParameters, 'query'),
// 'size' => $this->integerFromQueryParams($queryParameters,'size', 50),
// 'account_types' => $this->getAccountTypeParameter($this->arrayOfStrings($queryParameters, 'account_types')),
];
// collect accounts based on this list?
}
// return [
// 'accounts' => $this->getAccountList(),
// 'preselected' => $this->convertString('preselected'),
// ];
// }
/**
* The rules that the incoming request must be matched against.
*/
public function rules(): array
{
return [
'fields' => JsonApiRule::notSupported(),
'filter' => ['nullable', 'array',
new IsValidFilter(['start', 'end', 'preselected', 'accounts']),
new IsFilterValueIn('preselected', config('firefly.preselected_accounts')),
],
'include' => JsonApiRule::notSupported(),
'page' => JsonApiRule::notSupported(),
'sort' => JsonApiRule::notSupported(),
];
// return [
// 'start' => 'required|date|after:1900-01-01|before:2099-12-31',
// 'end' => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01',
// 'preselected' => sprintf('in:%s', implode(',', config('firefly.preselected_accounts'))),
// 'accounts.*' => 'exists:accounts,id',
// ];
}
public function withValidator(Validator $validator): void
{
$validator->after(
static function (Validator $validator): void {
// validate transaction query data.
$data = $validator->getData();
if (!array_key_exists('accounts', $data)) {
// $validator->errors()->add('accounts', trans('validation.filled', ['attribute' => 'accounts']));
return;
}
if (!is_array($data['accounts'])) {
$validator->errors()->add('accounts', trans('validation.filled', ['attribute' => 'accounts']));
}
}
);
if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray());
}
}
}

View File

@@ -27,6 +27,7 @@ use Carbon\Carbon;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\Support\Request\GetFilterInstructions;
use FireflyIII\Support\Request\GetSortInstructions;
use Illuminate\Foundation\Http\FormRequest;
@@ -40,6 +41,7 @@ class IndexRequest extends FormRequest
use AccountFilter;
use ChecksLogin;
use ConvertsDataTypes;
use GetFilterInstructions;
use GetSortInstructions;
public function getAccountTypes(): array

View File

@@ -60,15 +60,13 @@ class FixIbans extends Command
{
/** @var Account $account */
foreach ($accounts as $account) {
$iban = $account->iban;
if (str_contains($iban, ' ')) {
$iban = app('steam')->filterSpaces((string)$account->iban);
if ('' !== $iban) {
$account->iban = $iban;
$account->save();
$this->friendlyInfo(sprintf('Removed spaces from IBAN of account #%d', $account->id));
++$this->count;
}
$iban = (string) $account->iban;
$newIban = app('steam')->filterSpaces($iban);
if ('' !== $iban && $iban !== $newIban) {
$account->iban = $newIban;
$account->save();
$this->friendlyInfo(sprintf('Removed spaces from IBAN of account #%d', $account->id));
++$this->count;
}
}
}
@@ -81,7 +79,7 @@ class FixIbans extends Command
foreach ($accounts as $account) {
$userId = $account->user_id;
$set[$userId] ??= [];
$iban = (string)$account->iban;
$iban = (string) $account->iban;
if ('' === $iban) {
continue;
}

View File

@@ -26,6 +26,8 @@ namespace FireflyIII\Console\Commands\Correction;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\Models\AccountBalanceCalculator;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
@@ -38,61 +40,18 @@ class FixUnevenAmount extends Command
protected $description = 'Fix journals with uneven amounts.';
protected $signature = 'firefly-iii:fix-uneven-amount';
private int $count;
/**
* Execute the console command.
*/
public function handle(): int
{
$count = 0;
$journals = \DB::table('transactions')
->groupBy('transaction_journal_id')
->whereNull('deleted_at')
->get(['transaction_journal_id', \DB::raw('SUM(amount) AS the_sum')])
;
/** @var \stdClass $entry */
foreach ($journals as $entry) {
$sum = (string)$entry->the_sum;
if (!is_numeric($sum)
|| '' === $sum // @phpstan-ignore-line
|| str_contains($sum, 'e')
|| str_contains($sum, ',')) {
$message = sprintf(
'Journal #%d has an invalid sum ("%s"). No sure what to do.',
$entry->transaction_journal_id,
$entry->the_sum
);
$this->friendlyWarning($message);
app('log')->warning($message);
++$count;
continue;
}
$res = -1;
try {
$res = bccomp($sum, '0');
} catch (\ValueError $e) {
$this->friendlyError(sprintf('Could not bccomp("%s", "0").', $sum));
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
}
if (0 !== $res) {
$message = sprintf(
'Sum of journal #%d is %s instead of zero.',
$entry->transaction_journal_id,
$entry->the_sum
);
$this->friendlyWarning($message);
app('log')->warning($message);
$this->fixJournal($entry->transaction_journal_id);
++$count;
}
}
if (0 === $count) {
$this->friendlyPositive('Database amount integrity is OK');
}
$this->count = 0;
$this->convertOldStyleTransfers();
$this->fixUnevenAmounts();
$this->matchCurrencies();
AccountBalanceCalculator::forceRecalculateAll();
return 0;
}
@@ -118,6 +77,7 @@ class FixUnevenAmount extends Command
);
Transaction::where('transaction_journal_id', $journal->id ?? 0)->forceDelete();
TransactionJournal::where('id', $journal->id ?? 0)->forceDelete();
++$this->count;
return;
}
@@ -139,14 +99,194 @@ class FixUnevenAmount extends Command
Transaction::where('transaction_journal_id', $journal->id ?? 0)->forceDelete();
TransactionJournal::where('id', $journal->id ?? 0)->forceDelete();
++$this->count;
return;
}
// may still be able to salvage this journal if it is a transfer with foreign currency info
if ($this->isForeignCurrencyTransfer($journal)) {
Log::debug(sprintf('Can skip foreign currency transfer #%d.', $journal->id));
return;
}
$message = sprintf('Sum of journal #%d is not zero, journal is broken and now fixed.', $journal->id);
$this->friendlyWarning($message);
app('log')->warning($message);
$destination->amount = $amount;
$destination->save();
$message = sprintf('Corrected amount in transaction journal #%d', $param);
$this->friendlyInfo($message);
++$this->count;
}
private function fixUnevenAmounts(): void
{
$journals = \DB::table('transactions')
->groupBy('transaction_journal_id')
->whereNull('deleted_at')
->get(['transaction_journal_id', \DB::raw('SUM(amount) AS the_sum')])
;
/** @var \stdClass $entry */
foreach ($journals as $entry) {
$sum = (string) $entry->the_sum;
if (!is_numeric($sum)
|| '' === $sum // @phpstan-ignore-line
|| str_contains($sum, 'e')
|| str_contains($sum, ',')) {
$message = sprintf(
'Journal #%d has an invalid sum ("%s"). No sure what to do.',
$entry->transaction_journal_id,
$entry->the_sum
);
$this->friendlyWarning($message);
app('log')->warning($message);
++$this->count;
continue;
}
$res = -1;
try {
$res = bccomp($sum, '0');
} catch (\ValueError $e) {
$this->friendlyError(sprintf('Could not bccomp("%s", "0").', $sum));
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
}
if (0 !== $res) {
$this->fixJournal($entry->transaction_journal_id);
}
}
if (0 === $this->count) {
$this->friendlyPositive('Database amount integrity is OK');
}
}
private function matchCurrencies(): void
{
$journals = TransactionJournal::leftJoin('transactions', 'transaction_journals.id', 'transactions.transaction_journal_id')
->where('transactions.transaction_currency_id', '!=', \DB::raw('transaction_journals.transaction_currency_id'))
->get(['transaction_journals.*'])
;
$count = 0;
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
if (!$this->isForeignCurrencyTransfer($journal)) {
Transaction::where('transaction_journal_id', $journal->id)->update(['transaction_currency_id' => $journal->transaction_currency_id]);
++$count;
continue;
}
Log::debug(sprintf('Can skip foreign currency transfer #%d.', $journal->id));
}
if (0 === $count) {
$this->friendlyPositive('Journal currency integrity is OK');
return;
}
$this->friendlyPositive(sprintf('Fixed %d journal(s) with mismatched currencies.', $journals->count()));
}
private function isForeignCurrencyTransfer(TransactionJournal $journal): bool
{
if (TransactionType::TRANSFER !== $journal->transactionType->type) {
return false;
}
/** @var Transaction $destination */
$destination = $journal->transactions()->where('amount', '>', 0)->first();
/** @var Transaction $source */
$source = $journal->transactions()->where('amount', '<', 0)->first();
// safety catch on NULL should not be necessary, we just had that catch.
// source amount = dest foreign amount
// source currency = dest foreign currency
// dest amount = source foreign currency
// dest currency = source foreign currency
// Log::debug(sprintf('[a] %s', bccomp(app('steam')->positive($source->amount), app('steam')->positive($destination->foreign_amount))));
// Log::debug(sprintf('[b] %s', bccomp(app('steam')->positive($destination->amount), app('steam')->positive($source->foreign_amount))));
// Log::debug(sprintf('[c] %s', var_export($source->transaction_currency_id === $destination->foreign_currency_id,true)));
// Log::debug(sprintf('[d] %s', var_export((int) $destination->transaction_currency_id ===(int) $source->foreign_currency_id, true)));
if (0 === bccomp(app('steam')->positive($source->amount), app('steam')->positive($destination->foreign_amount))
&& $source->transaction_currency_id === $destination->foreign_currency_id
&& 0 === bccomp(app('steam')->positive($destination->amount), app('steam')->positive($source->foreign_amount))
&& (int) $destination->transaction_currency_id === (int) $source->foreign_currency_id
) {
return true;
}
return false;
}
private function convertOldStyleTransfers(): void
{
Log::debug('convertOldStyleTransfers()');
// select transactions with a foreign amount and a foreign currency. and it's a transfer. and they are different.
$transactions = Transaction::distinct()
->whereNotNull('foreign_currency_id')
->whereNotNull('foreign_amount')->get(['transactions.transaction_journal_id'])
;
$count = 0;
Log::debug(sprintf('Found %d potential journal(s)', $transactions->count()));
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
/** @var null|TransactionJournal $journal */
$journal = TransactionJournal::find($transaction->transaction_journal_id);
if (null === $journal) {
Log::debug('Found no journal, continue.');
continue;
}
// needs to be a transfer.
if (TransactionType::TRANSFER !== $journal->transactionType->type) {
Log::debug('Must be a transfer, continue.');
continue;
}
/** @var null|Transaction $destination */
$destination = $journal->transactions()->where('amount', '>', 0)->first();
/** @var null|Transaction $source */
$source = $journal->transactions()->where('amount', '<', 0)->first();
if (null === $destination || null === $source) {
Log::debug('Source or destination transaction is NULL, continue.');
// will be picked up later.
continue;
}
if ($source->transaction_currency_id === $destination->transaction_currency_id) {
Log::debug('Ready to swap data between transactions.');
$destination->foreign_currency_id = $source->transaction_currency_id;
$destination->foreign_amount = app('steam')->positive($source->amount);
$destination->transaction_currency_id = $source->foreign_currency_id;
$destination->amount = app('steam')->positive($source->foreign_amount);
$destination->balance_dirty = true;
$source->balance_dirty = true;
$destination->save();
$source->save();
$this->friendlyWarning(sprintf('Corrected foreign amounts of transfer #%d.', $journal->id));
++$count;
}
}
if (0 === $count) {
$this->friendlyPositive('No "old style" foreign currency transfers.');
return;
}
}
}

View File

@@ -80,7 +80,7 @@ class CreateGroupMemberships extends Command
// check if membership exists
$userGroup = UserGroup::where('title', $user->email)->first();
if (null === $userGroup) {
$userGroup = UserGroup::create(['title' => $user->email, 'default_administration' => true]);
$userGroup = UserGroup::create(['title' => $user->email]);
}
$userRole = UserRole::where('title', UserRoleEnum::OWNER->value)->first();

View File

@@ -115,7 +115,7 @@ class UpdateGroupInformation extends Command
return;
}
if (0 !== $result) {
$this->friendlyPositive(sprintf('User #%d: Moved %d %s objects to the correct group.', $user->id, $result, str_replace('FireflyIII\\Models\\', '', $className)));
$this->friendlyPositive(sprintf('User #%d: Moved %d %s objects to the correct group.', $user->id, $result, str_replace('FireflyIII\Models\\', '', $className)));
}
}
}

View File

@@ -111,7 +111,7 @@ class ForceDecimalSize extends Command
{
// switch stuff based on database connection:
$this->operator = 'REGEXP';
$this->regularExpression = '\'\\\\.[\\\\d]{%d}[1-9]+\'';
$this->regularExpression = '\'\\\.[\\\d]{%d}[1-9]+\'';
$this->cast = 'CHAR';
if ('pgsql' === config('database.default')) {
$this->operator = 'SIMILAR TO';
@@ -119,7 +119,7 @@ class ForceDecimalSize extends Command
$this->cast = 'TEXT';
}
if ('sqlite' === config('database.default')) {
$this->regularExpression = '"\\.[\d]{%d}[1-9]+"';
$this->regularExpression = '"\.[\d]{%d}[1-9]+"';
}
}
@@ -307,7 +307,7 @@ class ForceDecimalSize extends Command
/** @var string $field */
foreach ($fields as $field) {
$value = $item->{$field};
if (null === $value) {
if (null === $value || '' === $value) {
continue;
}
// fix $field by rounding it down correctly.

View File

@@ -0,0 +1,70 @@
<?php
/*
* CorrectAccountBalance.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands\Upgrade;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Support\Models\AccountBalanceCalculator;
use Illuminate\Console\Command;
/**
* Class CorrectionSkeleton
*/
class CorrectAccountBalance extends Command
{
use ShowsFriendlyMessages;
public const string CONFIG_NAME = '610_correct_balances';
protected $description = 'Recalculate all account balance amounts';
protected $signature = 'firefly-iii:correct-account-balance {--F|force : Force the execution of this command.}';
public function handle(): int
{
if ($this->isExecuted() && true !== $this->option('force')) {
$this->friendlyInfo('This command has already been executed.');
return 0;
}
$this->friendlyWarning('This command has been disabled.');
$this->markAsExecuted();
// $this->correctBalanceAmounts();
return 0;
}
private function correctBalanceAmounts(): void
{
AccountBalanceCalculator::recalculateAll();
}
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
return (bool)$configVar?->data;
}
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}

View File

@@ -90,7 +90,7 @@ class OtherCurrenciesCorrections extends Command
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
return (bool) $configVar->data;
}
return false;
@@ -120,7 +120,7 @@ class OtherCurrenciesCorrections extends Command
$this->journalRepos->setUser($journal->user);
$this->cliRepos->setUser($journal->user);
$leadTransaction = $this->getLeadTransaction($journal);
$leadTransaction = $this->getLeadTransaction($journal);
if (null === $leadTransaction) {
$this->friendlyError(sprintf('Could not reliably determine which transaction is in the lead for transaction journal #%d.', $journal->id));
@@ -128,8 +128,9 @@ class OtherCurrenciesCorrections extends Command
return;
}
$account = $leadTransaction->account;
$currency = $this->getCurrency($account);
$account = $leadTransaction->account;
$currency = $this->getCurrency($account);
$isMultiCurrency = $this->isMultiCurrency($account);
if (null === $currency) {
$this->friendlyError(
sprintf(
@@ -145,14 +146,14 @@ class OtherCurrenciesCorrections extends Command
}
// fix each transaction:
$journal->transactions->each(
static function (Transaction $transaction) use ($currency): void {
static function (Transaction $transaction) use ($currency, $isMultiCurrency): void {
if (null === $transaction->transaction_currency_id) {
$transaction->transaction_currency_id = $currency->id;
$transaction->save();
}
// when mismatch in transaction:
if ($transaction->transaction_currency_id !== $currency->id) {
if ($transaction->transaction_currency_id !== $currency->id && !$isMultiCurrency) {
$transaction->foreign_currency_id = $transaction->transaction_currency_id;
$transaction->foreign_amount = $transaction->amount;
$transaction->transaction_currency_id = $currency->id;
@@ -161,7 +162,9 @@ class OtherCurrenciesCorrections extends Command
}
);
// also update the journal, of course:
$journal->transaction_currency_id = $currency->id;
if (!$isMultiCurrency) {
$journal->transaction_currency_id = $currency->id;
}
++$this->count;
$journal->save();
}
@@ -239,4 +242,14 @@ class OtherCurrenciesCorrections extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
private function isMultiCurrency(Account $account): bool
{
$value = $this->accountRepos->getMetaValue($account, 'is_multi_currency', false);
if (false === $value || null === $value) {
return false;
}
return '1' === $value;
}
}

View File

@@ -65,6 +65,7 @@ class UpgradeDatabase extends Command
'firefly-iii:budget-limit-periods',
'firefly-iii:migrate-rule-actions',
'firefly-iii:restore-oauth-keys',
'firefly-iii:correct-account-balance',
// also just in case, some integrity commands:
'firefly-iii:create-group-memberships',
'firefly-iii:upgrade-group-information',

View File

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

View File

@@ -36,6 +36,8 @@ use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException as LaravelValidationException;
use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException;
use LaravelJsonApi\Core\Exceptions\JsonApiException;
use LaravelJsonApi\Exceptions\ExceptionParser;
use League\OAuth2\Server\Exception\OAuthServerException;
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
use Symfony\Component\HttpFoundation\Response;
@@ -63,8 +65,19 @@ class Handler extends ExceptionHandler
HttpException::class,
SuspiciousOperationException::class,
BadHttpHeaderException::class,
JsonApiException::class,
];
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->renderable(
ExceptionParser::make()->renderable()
);
}
/**
* Render an exception into an HTTP response. It's complex but lucky for us, we never use it because
* Firefly III never crashes.
@@ -79,15 +92,23 @@ class Handler extends ExceptionHandler
public function render($request, \Throwable $e): Response
{
$expectsJson = $request->expectsJson();
// if the user requests anything /api/, assume the user wants to see JSON.
if (str_starts_with($request->getRequestUri(), '/api/')) {
app('log')->debug('API endpoint, always assume user wants JSON.');
$expectsJson = true;
}
app('log')->debug('Now in Handler::render()');
if ($e instanceof JsonApiException) {
// ignore it: controller will handle it.
app('log')->debug(sprintf(
'Return to parent to handle JsonApiException(%d)',
$e->getCode()
));
return parent::render($request, $e);
}
if ($e instanceof LaravelValidationException && $expectsJson) {
// ignore it: controller will handle it.
app('log')->debug(sprintf('Return to parent to handle LaravelValidationException(%d)', $e->status));
return parent::render($request, $e);

View File

@@ -43,7 +43,7 @@ class AttachmentFactory
public function create(array $data): ?Attachment
{
// append if necessary.
$model = !str_contains($data['attachable_type'], 'FireflyIII') ? sprintf('FireflyIII\\Models\\%s', $data['attachable_type'])
$model = !str_contains($data['attachable_type'], 'FireflyIII') ? sprintf('FireflyIII\Models\%s', $data['attachable_type'])
: $data['attachable_type'];
// get journal instead of transaction.

View File

@@ -47,6 +47,7 @@ use FireflyIII\Support\NullArrayObject;
use FireflyIII\User;
use FireflyIII\Validation\AccountValidator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class TransactionJournalFactory
@@ -261,8 +262,24 @@ class TransactionJournalFactory
$transactionFactory->setForeignCurrency($foreignCurrency);
$transactionFactory->setReconciled($row['reconciled'] ?? false);
// if the foreign currency is set and is different, and the transaction type is a transfer,
// Firefly III will save the foreign currency information in such a way that both
// asset accounts can look at the "amount" and "transaction_currency_id" column and
// see the currency they expect to see.
$amount = (string)$row['amount'];
$foreignAmount = (string)$row['foreign_amount'];
if (null !== $foreignCurrency && $foreignCurrency->id !== $currency->id
&& TransactionType::TRANSFER === $type->type
) {
$transactionFactory->setCurrency($foreignCurrency);
$transactionFactory->setForeignCurrency($currency);
$amount = (string)$row['foreign_amount'];
$foreignAmount = (string)$row['amount'];
Log::debug('Swap native/foreign amounts in transfer for new save method.');
}
try {
$transactionFactory->createPositive((string)$row['amount'], (string)$row['foreign_amount']);
$transactionFactory->createPositive($amount, $foreignAmount);
} catch (FireflyException $e) {
app('log')->error(sprintf('Exception creating positive transaction: %s', $e->getMessage()));
$this->forceTrDelete($negative);

View File

@@ -24,6 +24,8 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Transaction;
use FireflyIII\Support\Models\AccountBalanceCalculator;
use Illuminate\Support\Facades\Log;
/**
* Class TransactionObserver
@@ -35,4 +37,22 @@ class TransactionObserver
app('log')->debug('Observe "deleting" of a transaction.');
$transaction?->transactionJournal?->delete();
}
public function updated(Transaction $transaction): void
{
Log::debug('Observe "updated" of a transaction.');
if (1 === bccomp($transaction->amount, '0')) {
Log::debug('Trigger recalculateForJournal');
AccountBalanceCalculator::recalculateForJournal($transaction->transactionJournal);
}
}
public function created(Transaction $transaction): void
{
Log::debug('Observe "created" of a transaction.');
if (1 === bccomp($transaction->amount, '0')) {
Log::debug('Trigger recalculateForJournal');
AccountBalanceCalculator::recalculateForJournal($transaction->transactionJournal);
}
}
}

View File

@@ -717,7 +717,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $internalReference));
$this->query->where('journal_meta.data', '=', $internalReference);
return $this;
}

View File

@@ -805,7 +805,7 @@ class GroupCollector implements GroupCollectorInterface
return 'zzz';
}
exit('here we are');
exit('here we are 2');
});
}

View File

@@ -121,7 +121,7 @@ class LoginController extends Controller
// Copied directly from AuthenticatesUsers, but with logging added:
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// to log in and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
Log::channel('audit')->warning(sprintf('Login failed. Attempt for user "%s" failed.', $request->get($this->username())));
@@ -233,7 +233,7 @@ class LoginController extends Controller
$storeInCookie = config('google2fa.store_in_cookie', false);
if (false !== $storeInCookie) {
$cookieName = config('google2fa.cookie_name', 'google2fa_token');
request()->cookies->set($cookieName, 'invalid');
\Cookie::queue(\Cookie::make($cookieName, 'invalid-'.time()));
}
$usernameField = $this->username();

View File

@@ -185,7 +185,7 @@ class BudgetLimitController extends Controller
$array['amount_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, $limit['amount']);
$array['days_left'] = (string)$this->activeDaysLeft($start, $end);
// left per day:
$array['left_per_day'] = bcdiv(bcadd($array['spent'], $array['amount']), $array['days_left']);
$array['left_per_day'] = 0 === bccomp('0', $array['days_left']) ? bcadd($array['spent'], $array['amount']) : bcdiv(bcadd($array['spent'], $array['amount']), $array['days_left']);
// left per day formatted.
$array['left_per_day_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, $array['left_per_day']);

View File

@@ -30,6 +30,7 @@ use FireflyIII\Http\Middleware\IsDemoUser;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\Http\Controllers\GetConfigurationData;
use FireflyIII\Support\Models\AccountBalanceCalculator;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
@@ -86,14 +87,15 @@ class DebugController extends Controller
{
app('preferences')->mark();
$request->session()->forget(['start', 'end', '_previous', 'viewRange', 'range', 'is_custom_range', 'temp-mfa-secret', 'temp-mfa-codes']);
app('log')->debug('Call cache:clear...');
Artisan::call('cache:clear');
app('log')->debug('Call config:clear...');
Artisan::call('config:clear');
app('log')->debug('Call route:clear...');
Artisan::call('route:clear');
app('log')->debug('Call twig:clean...');
Artisan::call('view:clear');
// also do some recalculations.
Artisan::call('firefly-iii:trigger-credit-recalculation');
AccountBalanceCalculator::forceRecalculateAll();
try {
Artisan::call('twig:clean');
@@ -101,7 +103,6 @@ class DebugController extends Controller
throw new FireflyException($e->getMessage(), 0, $e);
}
app('log')->debug('Call view:clear...');
Artisan::call('view:clear');
return redirect(route('index'));

View File

@@ -65,7 +65,7 @@ class HomeController extends Controller
$stringEnd = '';
try {
$stringStart = e((string)$request->get('start'));
$stringStart = e((string) $request->get('start'));
$start = Carbon::createFromFormat('Y-m-d', $stringStart);
} catch (InvalidFormatException $e) {
app('log')->error(sprintf('Start: could not parse date string "%s" so ignore it.', $stringStart));
@@ -73,7 +73,7 @@ class HomeController extends Controller
}
try {
$stringEnd = e((string)$request->get('end'));
$stringEnd = e((string) $request->get('end'));
$end = Carbon::createFromFormat('Y-m-d', $stringEnd);
} catch (InvalidFormatException $e) {
app('log')->error(sprintf('End could not parse date string "%s" so ignore it.', $stringEnd));
@@ -92,7 +92,7 @@ class HomeController extends Controller
app('log')->debug('dateRange: Received dateRange', ['start' => $stringStart, 'end' => $stringEnd, 'label' => $request->get('label')]);
// check if the label is "everything" or "Custom range" which will betray
// a possible problem with the budgets.
if ($label === (string)trans('firefly.everything') || $label === (string)trans('firefly.customRange')) {
if ($label === (string) trans('firefly.everything') || $label === (string) trans('firefly.customRange')) {
$isCustomRange = true;
app('log')->debug('Range is now marked as "custom".');
}
@@ -100,7 +100,7 @@ class HomeController extends Controller
$diff = $start->diffInDays($end, true) + 1;
if ($diff > 366) {
$request->session()->flash('warning', (string)trans('firefly.warning_much_data', ['days' => (int)$diff]));
$request->session()->flash('warning', (string) trans('firefly.warning_much_data', ['days' => (int) $diff]));
}
$request->session()->put('is_custom_range', $isCustomRange);
@@ -128,10 +128,10 @@ class HomeController extends Controller
return redirect(route('new-user.index'));
}
if ('v1' === (string)config('view.layout')) {
if ('v1' === (string) config('view.layout')) {
return $this->indexV1($repository);
}
if ('v2' === (string)config('view.layout')) {
if ('v2' === (string) config('view.layout')) {
return $this->indexV2();
}
@@ -141,8 +141,9 @@ class HomeController extends Controller
private function indexV1(AccountRepositoryInterface $repository): mixed
{
$types = config('firefly.accountTypesByIdentifier.asset');
$pageTitle = (string) trans('firefly.main_dashboard_page_title');
$count = $repository->count($types);
$subTitle = (string)trans('firefly.welcome_back');
$subTitle = (string) trans('firefly.welcome_back');
$transactions = [];
$frontpage = app('preferences')->getFresh('frontpageAccounts', $repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray());
$frontpageArray = $frontpage->data;
@@ -151,8 +152,9 @@ class HomeController extends Controller
}
/** @var Carbon $start */
/** @var Carbon $end */
$start = session('start', today(config('app.timezone'))->startOfMonth());
/** @var Carbon $end */
$end = session('end', today(config('app.timezone'))->endOfMonth());
$accounts = $repository->getAccountsById($frontpageArray);
$today = today(config('app.timezone'));
@@ -176,20 +178,21 @@ class HomeController extends Controller
$user = auth()->user();
event(new RequestedVersionCheckStatus($user));
return view('index', compact('count', 'subTitle', 'transactions', 'billCount', 'start', 'end', 'today'));
return view('index', compact('count', 'subTitle', 'transactions', 'billCount', 'start', 'end', 'today', 'pageTitle'));
}
private function indexV2(): mixed
{
$subTitle = (string)trans('firefly.welcome_back');
$subTitle = (string) trans('firefly.welcome_back');
$pageTitle = (string) trans('firefly.main_dashboard_page_title');
$start = session('start', today(config('app.timezone'))->startOfMonth());
$end = session('end', today(config('app.timezone'))->endOfMonth());
$start = session('start', today(config('app.timezone'))->startOfMonth());
$end = session('end', today(config('app.timezone'))->endOfMonth());
/** @var User $user */
$user = auth()->user();
$user = auth()->user();
event(new RequestedVersionCheckStatus($user));
return view('index', compact('subTitle', 'start', 'end'));
return view('index', compact('subTitle', 'start', 'end', 'pageTitle'));
}
}

View File

@@ -81,6 +81,8 @@ class ReconcileController extends Controller
if ($end->lt($start)) {
[$start, $end] = [$end, $start];
}
$end->endOfDay();
$start->startOfDay();
$route = route('accounts.reconcile.submit', [$account->id, $start->format('Ymd'), $end->format('Ymd')]);
$selectedIds = $request->get('journals') ?? [];

View File

@@ -81,7 +81,12 @@ class RecurrenceController extends Controller
$skip = $skip < 0 || $skip > 31 ? 0 : $skip;
$weekend = $weekend < 1 || $weekend > 4 ? 1 : $weekend;
if (null === $start || null === $end || null === $firstDate || null === $endDate) {
if (null === $endDate) {
// safety catch:
$endDate = now()->addYear();
}
if (null === $start || null === $end || null === $firstDate) {
return response()->json();
}

View File

@@ -120,7 +120,7 @@ class PreferencesController extends Controller
// list of locales also has "equal" which makes it equal to whatever the language is.
try {
$locales = json_decode((string)file_get_contents(resource_path(sprintf('lang/%s/locales.json', $language))), true, 512, JSON_THROW_ON_ERROR);
$locales = json_decode((string)file_get_contents(resource_path(sprintf('locales/%s/locales.json', $language))), true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
app('log')->error($e->getMessage());
$locales = [];

View File

@@ -84,6 +84,7 @@ class ShowController extends Controller
$transformer->setParameters(new ParameterBag());
$array = $transformer->transform($recurrence);
$groups = $this->recurring->getTransactions($recurrence);
$today = today(config('app.timezone'));
$array['repeat_until'] = null !== $array['repeat_until'] ? new Carbon($array['repeat_until']) : null;

View File

@@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Transaction;
use Exception;
use FireflyIII\Events\UpdatedTransactionGroup;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
@@ -65,7 +64,7 @@ class ConvertController extends Controller
$this->middleware(
function ($request, $next) {
$this->accountRepository = app(AccountRepositoryInterface::class);
app('view')->share('title', (string)trans('firefly.transactions'));
app('view')->share('title', (string) trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-exchange');
return $next($request);
@@ -95,7 +94,7 @@ class ConvertController extends Controller
$groupTitle = $group->title ?? $first->description;
$groupArray = $transformer->transformObject($group);
$subTitle = (string)trans('firefly.convert_to_'.$destinationType->type, ['description' => $groupTitle]);
$subTitle = (string) trans('firefly.convert_to_'.$destinationType->type, ['description' => $groupTitle]);
$subTitleIcon = 'fa-exchange';
// get a list of asset accounts and liabilities and stuff, in various combinations:
@@ -111,7 +110,7 @@ class ConvertController extends Controller
if ($sourceType->type === $destinationType->type) { // cannot convert to its own type.
app('log')->debug('This is already a transaction of the expected type..');
session()->flash('info', (string)trans('firefly.convert_is_already_type_'.$destinationType->type));
session()->flash('info', (string) trans('firefly.convert_is_already_type_'.$destinationType->type));
return redirect(route('transactions.show', [$group->id]));
}
@@ -147,7 +146,7 @@ class ConvertController extends Controller
// group accounts:
/** @var Account $account */
foreach ($accountList as $account) {
$role = (string)$this->accountRepository->getMetaValue($account, 'account_role');
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
$name = $account->name;
if ('' === $role) {
$role = 'no_account_type';
@@ -165,7 +164,7 @@ class ConvertController extends Controller
$role = 'revenue_account';
}
$key = (string)trans('firefly.opt_group_'.$role);
$key = (string) trans('firefly.opt_group_'.$role);
$grouped[$key][$account->id] = $name;
}
@@ -184,7 +183,7 @@ class ConvertController extends Controller
// group accounts:
/** @var Account $account */
foreach ($accountList as $account) {
$role = (string)$this->accountRepository->getMetaValue($account, 'account_role');
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
$name = $account->name;
if ('' === $role) {
$role = 'no_account_type';
@@ -202,7 +201,7 @@ class ConvertController extends Controller
$role = 'expense_account';
}
$key = (string)trans('firefly.opt_group_'.$role);
$key = (string) trans('firefly.opt_group_'.$role);
$grouped[$key][$account->id] = $name;
}
@@ -225,7 +224,7 @@ class ConvertController extends Controller
$balance = app('steam')->balance($account, today());
$currency = $this->accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
$role = 'l_'.$account->accountType->type;
$key = (string)trans('firefly.opt_group_'.$role);
$key = (string) trans('firefly.opt_group_'.$role);
$grouped[$key][$account->id] = $account->name.' ('.app('amount')->formatAnything($currency, $balance, false).')';
}
@@ -247,12 +246,12 @@ class ConvertController extends Controller
foreach ($accountList as $account) {
$balance = app('steam')->balance($account, today());
$currency = $this->accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
$role = (string)$this->accountRepository->getMetaValue($account, 'account_role');
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
if ('' === $role) {
$role = 'no_account_type';
}
$key = (string)trans('firefly.opt_group_'.$role);
$key = (string) trans('firefly.opt_group_'.$role);
$grouped[$key][$account->id] = $account->name.' ('.app('amount')->formatAnything($currency, $balance, false).')';
}
@@ -285,7 +284,7 @@ class ConvertController extends Controller
// correct transfers:
$group->refresh();
session()->flash('success', (string)trans('firefly.converted_to_'.$destinationType->type));
session()->flash('success', (string) trans('firefly.converted_to_'.$destinationType->type));
event(new UpdatedTransactionGroup($group, true, true));
return redirect(route('transactions.show', [$group->id]));
@@ -306,11 +305,11 @@ class ConvertController extends Controller
$destinationId = $data['destination_id'][$journal->id] ?? null;
$destinationName = $data['destination_name'][$journal->id] ?? null;
// double check its not an empty string.
$sourceId = '' === $sourceId || null === $sourceId ? null : (int)$sourceId;
$sourceName = '' === $sourceName ? null : (string)$sourceName;
$destinationId = '' === $destinationId || null === $destinationId ? null : (int)$destinationId;
$destinationName = '' === $destinationName ? null : (string)$destinationName;
// double check it's not an empty string.
$sourceId = '' === $sourceId || null === $sourceId ? null : (int) $sourceId;
$sourceName = '' === $sourceName ? null : (string) $sourceName;
$destinationId = '' === $destinationId || null === $destinationId ? null : (int) $destinationId;
$destinationName = '' === $destinationName ? null : (string) $destinationName;
$validSource = $validator->validateSource(['id' => $sourceId, 'name' => $sourceName]);
$validDestination = $validator->validateDestination(['id' => $destinationId, 'name' => $destinationName]);
@@ -331,6 +330,19 @@ class ConvertController extends Controller
'type' => $transactionType->type,
];
// also set the currency to the currency of the source account, in case you're converting a deposit into a transfer.
if (TransactionType::TRANSFER === $transactionType->type && TransactionType::DEPOSIT === $journal->transactionType->type) {
$source = $this->accountRepository->find((int) $sourceId);
$sourceCurrency = $this->accountRepository->getAccountCurrency($source);
$dest = $this->accountRepository->find((int) $destinationId);
$destCurrency = $this->accountRepository->getAccountCurrency($dest);
if (null !== $sourceCurrency && null !== $destCurrency && $sourceCurrency->code !== $destCurrency->code) {
$update['currency_id'] = $sourceCurrency->id;
$update['foreign_currency_id'] = $destCurrency->id;
$update['foreign_amount'] = '1'; // not the best solution but at this point the amount is hard to get.
}
}
/** @var JournalUpdateService $service */
$service = app(JournalUpdateService::class);
$service->setTransactionJournal($journal);

View File

@@ -27,6 +27,7 @@ use Carbon\Carbon;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Http\Controllers\RequestInformation;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/**
* Class SessionFilter.
@@ -63,6 +64,7 @@ class Range
{
// ignore preference. set the range to be the current month:
if (!app('session')->has('start') && !app('session')->has('end')) {
Log::debug('setRange: Session has no start or end.');
$viewRange = app('preferences')->get('viewRange', '1M')->data;
if (is_array($viewRange)) {
$viewRange = '1M';
@@ -76,6 +78,8 @@ class Range
app('session')->put('end', $end);
}
if (!app('session')->has('first')) {
Log::debug('setRange: Session has no "first".');
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$journal = $repository->firstNull();

View File

@@ -28,4 +28,9 @@ use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
/**
* Class VerifyCsrfToken.
*/
class VerifyCsrfToken extends Middleware {}
class VerifyCsrfToken extends Middleware
{
protected $except = [
'oauth/token',
];
}

View File

@@ -57,7 +57,7 @@ class AccountFormRequest extends FormRequest
'account_type_name' => $this->convertString('objectType'),
'currency_id' => $this->convertInteger('currency_id'),
'virtual_balance' => $this->convertString('virtual_balance'),
'iban' => $this->convertString('iban'),
'iban' => $this->convertIban('iban'),
'BIC' => $this->convertString('BIC'),
'account_number' => $this->convertString('account_number'),
'account_role' => $this->convertString('account_role'),

View File

@@ -361,11 +361,17 @@ class CreateRecurringTransactions implements ShouldQueue
// create transaction array and send to factory.
$groupTitle = null;
$count = $recurrence->recurrenceTransactions->count();
if ($count > 1) {
// #8844, if there is one recurrence transaction, use the first title as the title.
if (1 === $count) {
/** @var RecurrenceTransaction $first */
$first = $recurrence->recurrenceTransactions()->first();
$groupTitle = $first->description;
}
// #8844, if there are more, use the recurrence transaction itself.
if ($count > 1) {
$groupTitle = $recurrence->title;
}
if (0 === $count) {
app('log')->error('No transactions to be created in this recurrence. Cannot continue.');
@@ -411,12 +417,12 @@ class CreateRecurringTransactions implements ShouldQueue
/** @var RecurrenceTransaction $transaction */
foreach ($transactions as $index => $transaction) {
$single = [
'type' => null === $first->transactionType ? strtolower($recurrence->transactionType->type) : strtolower($first->transactionType->type),
'type' => null === $transaction?->transactionType?->type ? strtolower($recurrence->transactionType->type) : strtolower($transaction->transactionType->type),
'date' => $date,
'user' => $recurrence->user_id,
'currency_id' => $transaction->transaction_currency_id,
'currency_code' => null,
'description' => $first->description,
'description' => $transaction->description,
'amount' => $transaction->amount,
'budget_id' => $this->repository->getBudget($transaction),
'budget_name' => null,

View File

@@ -29,6 +29,7 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Bus\Queueable;
@@ -100,7 +101,7 @@ class DownloadExchangeRates implements ShouldQueue
try {
$res = $client->get($url);
} catch (RequestException $e) {
} catch (ConnectException|RequestException $e) {
app('log')->warning(sprintf('Trying to grab "%s" resulted in error "%d".', $url, $e->getMessage()));
return;

View File

@@ -130,12 +130,12 @@ class MailError extends Job implements ShouldQueue
}
if (file_exists($file)) {
Log::debug(sprintf('Read file in "%s"', $file));
$limits = json_decode(file_get_contents($file), true);
$limits = json_decode((string)file_get_contents($file), true);
}
// limit reached?
foreach ($types as $type => $info) {
Log::debug(sprintf('Now checking limit "%s"', $type), $info);
if (!isset($limits[$type])) {
if (!array_key_exists($type, $limits)) {
Log::debug(sprintf('Limit "%s" reset to zero, did not exist yet.', $type));
$limits[$type] = [
'time' => time(),

View File

@@ -0,0 +1,53 @@
<?php
/*
* IsValidFilter.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\JsonApi\Rules;
use Illuminate\Contracts\Validation\ValidationRule;
class IsValidFilter implements ValidationRule
{
private array $allowed;
public function __construct(array $keys)
{
$this->allowed = $keys;
$this->allowed[] = 'user_group_id';
}
#[\Override]
public function validate(string $attribute, mixed $value, \Closure $fail): void
{
if ('filter' !== $attribute) {
$fail('validation.bad_api_filter')->translate();
}
if (!is_array($value)) {
$value = explode(',', $value);
}
foreach ($value as $key => $val) {
if (!in_array($key, $this->allowed, true)) {
$fail('validation.bad_api_filter')->translate(['filter' => $key]);
}
}
}
}

View File

@@ -0,0 +1,52 @@
<?php
/*
* IsValidFilter.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\JsonApi\Rules;
use Illuminate\Contracts\Validation\ValidationRule;
class IsValidPage implements ValidationRule
{
private array $allowed;
public function __construct(array $keys)
{
$this->allowed = $keys;
}
#[\Override]
public function validate(string $attribute, mixed $value, \Closure $fail): void
{
if ('page' !== $attribute) {
$fail('validation.bad_api_filter')->translate();
}
if (!is_array($value)) {
$value = explode(',', $value);
}
foreach ($value as $key => $val) {
if (!in_array($key, $this->allowed, true)) {
$fail('validation.bad_api_page')->translate();
}
}
}
}

View File

@@ -0,0 +1,45 @@
<?php
/*
* AccountBalanceRepository.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\AccountBalances;
use FireflyIII\Entities\AccountBalance;
use LaravelJsonApi\Contracts\Store\QueriesAll;
use LaravelJsonApi\NonEloquent\AbstractRepository;
class AccountBalanceRepository extends AbstractRepository implements QueriesAll
{
#[\Override]
public function find(string $resourceId): ?object
{
return AccountBalance::fromArray();
}
public function queryAll(): Capabilities\AccountBalanceQuery
{
return Capabilities\AccountBalanceQuery::make()
->withServer($this->server)
->withSchema($this->schema)
;
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\AccountBalances;
use Illuminate\Http\Request;
use LaravelJsonApi\Core\Resources\JsonApiResource;
class AccountBalanceResource extends JsonApiResource
{
/**
* Get the resource id.
*/
public function id(): string
{
return $this->resource->id;
}
/**
* Get the resource's attributes.
*
* @param null|Request $request
*/
public function attributes($request): iterable
{
return [
'name' => $this->resource->amount,
'amount' => $this->resource->amount,
];
}
/**
* Get the resource's relationships.
*
* @param null|Request $request
*/
public function relationships($request): iterable
{
return [
$this->relation('account')->withData($this->resource->getAccount()),
];
}
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\AccountBalances;
use FireflyIII\Entities\AccountBalance;
use LaravelJsonApi\Core\Schema\Schema;
use LaravelJsonApi\Eloquent\Fields\Relations\HasOne;
use LaravelJsonApi\NonEloquent\Fields\Attribute;
use LaravelJsonApi\NonEloquent\Fields\ID;
class AccountBalanceSchema extends Schema
{
/**
* The model the schema corresponds to.
*/
public static string $model = AccountBalance::class;
/**
* Get the resource fields.
*/
public function fields(): array
{
return [
ID::make(),
Attribute::make('name'),
Attribute::make('amount'),
HasOne::make('account'),
];
}
/**
* Get the resource filters.
*/
public function filters(): array
{
return [
// Filter::make('id'),
];
}
public function repository(): AccountBalanceRepository
{
return AccountBalanceRepository::make()
->withServer($this->server)
->withSchema($this)
;
}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* AccountBalanceQuery.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\AccountBalances\Capabilities;
use FireflyIII\Entities\AccountBalance;
use FireflyIII\Models\Account;
use LaravelJsonApi\NonEloquent\Capabilities\QueryAll;
class AccountBalanceQuery extends QueryAll
{
private Account $account;
/**
* QuerySites constructor.
*/
public function __construct()
{
parent::__construct();
}
public function get(): iterable
{
return [
AccountBalance::fromArray(),
AccountBalance::fromArray(),
AccountBalance::fromArray(),
AccountBalance::fromArray(),
];
}
public function withAccount(Account $account): self
{
$this->account = $account;
return $this;
}
}

View File

@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Models\Account;
use FireflyIII\Rules\Account\IsValidAccountType;
use FireflyIII\Rules\IsAllowedGroupAction;
use FireflyIII\Rules\IsDateOrTime;
use FireflyIII\Rules\IsValidDateRange;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Laravel\Http\Requests\ResourceQuery;
use LaravelJsonApi\Validation\Rule as JsonApiRule;
class AccountCollectionQuery extends ResourceQuery
{
/**
* Get the validation rules that apply to the request query parameters.
*/
public function rules(): array
{
Log::debug(__METHOD__);
$validFilters = config('api.valid_api_filters')[Account::class];
return [
'fields' => [
'nullable',
'array',
JsonApiRule::fieldSets(),
],
'userGroupId' => [
'nullable',
'integer',
new IsAllowedGroupAction(Account::class, request()->method()),
],
'startPeriod' => [
'nullable',
'date',
new IsDateOrTime(),
new IsValidDateRange(),
],
'endPeriod' => [
'nullable',
'date',
new IsDateOrTime(),
new IsValidDateRange(),
],
'filter' => [
'nullable',
'array',
JsonApiRule::filter($validFilters),
new IsValidAccountType(),
],
'include' => [
'nullable',
'string',
JsonApiRule::includePaths(),
],
'page' => [
'nullable',
'array',
JsonApiRule::page(),
],
'sort' => [
'nullable',
'string',
JsonApiRule::sort(),
],
'withCount' => [
'nullable',
'string',
JsonApiRule::countable(),
],
];
}
}

View File

@@ -0,0 +1,112 @@
<?php
/*
* AccountRepository.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Models\Account;
use FireflyIII\Support\JsonApi\Concerns\UsergroupAware;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Contracts\Store\CreatesResources;
use LaravelJsonApi\Contracts\Store\QueriesAll;
use LaravelJsonApi\NonEloquent\AbstractRepository;
use LaravelJsonApi\NonEloquent\Capabilities\CrudRelations;
use LaravelJsonApi\NonEloquent\Concerns\HasCrudCapability;
use LaravelJsonApi\NonEloquent\Concerns\HasRelationsCapability;
/**
* Class AccountRepository
*
* The repository collects a single or many (account) objects from the database and returns them to the
* account resource. The account resource links all account properties to the JSON properties.
*
* For the queryAll thing, a separate query is constructed that does the actual querying of the database.
* This is necessary because the user can't just query all accounts (it would return other user's data)
* and because we also need to collect all kinds of metadata, like the currency and user info.
*/
class AccountRepository extends AbstractRepository implements QueriesAll, CreatesResources
{
use HasCrudCapability;
use HasRelationsCapability;
use UsergroupAware;
/**
* SiteRepository constructor.
*/
public function __construct()
{
Log::debug(__METHOD__);
}
public function exists(string $resourceId): bool
{
$result = null !== Account::find((int) $resourceId);
Log::debug(sprintf('%s: %s', __METHOD__, var_export($result, true)));
return $result;
}
public function find(string $resourceId): ?object
{
exit(__METHOD__);
Log::debug(__METHOD__);
// throw new \RuntimeException('trace me');
$account = Account::find((int) $resourceId);
if (null === $account) {
return null;
}
// enrich the collected data
$enrichment = new AccountEnrichment();
return $enrichment->enrichSingle($account);
}
public function queryAll(): Capabilities\AccountQuery
{
Log::debug(__METHOD__);
return Capabilities\AccountQuery::make()
->withUserGroup($this->userGroup)
->withServer($this->server)
->withSchema($this->schema)
;
}
protected function crud(): Capabilities\CrudAccount
{
Log::debug(__METHOD__);
return Capabilities\CrudAccount::make();
}
/**
* TODO piggy banks
* TODO transactions
*/
protected function relations(): CrudRelations
{
Log::debug(__METHOD__);
return Capabilities\CrudAccountRelations::make();
}
}

View File

@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Rules\Account\IsUniqueAccount;
use FireflyIII\Rules\IsBoolean;
use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Rules\UniqueAccountNumber;
use FireflyIII\Rules\UniqueIban;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Laravel\Http\Requests\ResourceRequest;
class AccountRequest extends ResourceRequest
{
use ConvertsDataTypes;
/**
* Get the validation rules for the resource.
*/
public function rules(): array
{
Log::debug(__METHOD__);
$accountRoles = implode(',', config('firefly.accountRoles'));
$ccPaymentTypes = implode(',', array_keys(config('firefly.ccTypes')));
$types = implode(',', array_keys(config('firefly.subTitlesByIdentifier')));
$type = $this->convertString('type');
// var_dump($types);exit;
return [
'name' => ['required', 'max:1024', 'min:1'], // , new IsUniqueAccount()
'account_type' => ['required', 'max:1024', 'min:1', sprintf('in:%s', $types)],
// 'iban' => ['iban', 'nullable', new UniqueIban(null, $type)],
// 'bic' => 'bic|nullable',
// 'account_number' => ['min:1', 'max:255', 'nullable', new UniqueAccountNumber(null, $type)],
// 'opening_balance' => 'numeric|required_with:opening_balance_date|nullable',
// 'opening_balance_date' => 'date|required_with:opening_balance|nullable',
// 'virtual_balance' => 'numeric|nullable',
// 'order' => 'numeric|nullable',
// 'currency_id' => 'numeric|exists:transaction_currencies,id',
// 'currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
// 'active' => [new IsBoolean()],
// 'include_net_worth' => [new IsBoolean()],
// 'account_role' => sprintf('nullable|in:%s|required_if:type,asset', $accountRoles),
// 'credit_card_type' => sprintf('nullable|in:%s|required_if:account_role,ccAsset', $ccPaymentTypes),
// 'monthly_payment_date' => 'nullable|date|required_if:account_role,ccAsset|required_if:credit_card_type,monthlyFull',
// 'liability_type' => 'nullable|required_if:type,liability|required_if:type,liabilities|in:loan,debt,mortgage',
// 'liability_amount' => ['required_with:liability_start_date', new IsValidPositiveAmount()],
// 'liability_start_date' => 'required_with:liability_amount|date',
// 'liability_direction' => 'nullable|required_if:type,liability|required_if:type,liabilities|in:credit,debit',
// 'interest' => 'min:0|max:100|numeric',
// 'interest_period' => sprintf('nullable|in:%s', implode(',', config('firefly.interest_periods'))),
// 'notes' => 'min:0|max:32768',
];
}
}

View File

@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Models\Account;
use Illuminate\Http\Request;
use LaravelJsonApi\Core\Resources\JsonApiResource;
/**
* @property Account $resource
*/
class AccountResource extends JsonApiResource
{
/**
* Get the resource id.
*/
public function id(): string
{
return (string) $this->resource->id;
}
/**
* Get the resource's attributes.
*
* @param null|Request $request
*/
public function attributes($request): iterable
{
// Log::debug(__METHOD__);
return [
'created_at' => $this->resource->created_at,
'updated_at' => $this->resource->updated_at,
'name' => $this->resource->name,
'active' => $this->resource->active,
'order' => $this->resource->order,
'iban' => $this->resource->iban,
'account_type' => $this->resource->account_type_string,
'account_role' => $this->resource->account_role,
'account_number' => '' === $this->resource->account_number ? null : $this->resource->account_number,
// currency (if the account has a currency setting, otherwise NULL).
'currency_id' => $this->resource->currency_id,
'currency_name' => $this->resource->currency_name,
'currency_code' => $this->resource->currency_code,
'currency_symbol' => $this->resource->currency_symbol,
'currency_decimal_places' => $this->resource->currency_decimal_places,
'is_multi_currency' => '1' === $this->resource->is_multi_currency,
// balances
'balance' => $this->resource->balance,
'native_balance' => $this->resource->native_balance,
// liability things
'liability_direction' => $this->resource->liability_direction,
'interest' => $this->resource->interest,
'interest_period' => $this->resource->interest_period,
'current_debt' => $this->resource->current_debt, // TODO may be removed in the future.
// other things
'last_activity' => $this->resource->last_activity,
// object group
'object_group_id' => $this->resource->object_group_id,
'object_group_title' => $this->resource->object_group_title,
'object_group_order' => $this->resource->object_group_order,
];
}
/**
* Get the resource's relationships.
*
* @param null|Request $request
*/
public function relationships($request): iterable
{
return [
$this->relation('user')->withData($this->resource->user),
];
}
}

View File

@@ -0,0 +1,115 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Models\Account;
use Illuminate\Http\Request;
use LaravelJsonApi\Core\Resources\JsonApiResource;
/**
* @property Account $resource
*
* This class collects the resources attributes, the account in this case.
* Generally speaking, each property here is directly related to a property on the account object itself.
* However, many properties are collected from other sources, like the user or the currency.
* As a result, the account repository is where it's at, which is where the collection takes place and is optimised.
*/
class AccountResourceOld extends JsonApiResource
{
/**
* Get the resource's attributes.
*
* @param null|Request $request
*/
public function attributes($request): iterable
{
// fields removed here have been migrated.
return [
'created_at' => $this->resource->created_at,
'updated_at' => $this->resource->updated_at,
'name' => $this->resource->name,
// 'virtual_balance' => $this->resource->virtual_balance,
// 'native_balance' => $this->resource->native_balance,
// 'user' => $this->resource->user_array,
// 'balances' => []
//
// balance (in currency, on date)
// 'current_balance' => $this->resource->current_balance,
// 'current_balance' => app('steam')->bcround(app('steam')->balance($account, $date), $decimalPlaces),
// 'current_balance_date' => $date->toAtomString(),
// 'notes' => $this->repository->getNoteText($account),
// 'monthly_payment_date' => $monthlyPaymentDate,
// 'credit_card_type' => $creditCardType,
// 'account_number' => $this->repository->getMetaValue($account, 'account_number'),
// 'bic' => $this->repository->getMetaValue($account, 'BIC'),
// 'opening_balance' => $openingBalance,
// 'opening_balance_date' => $openingBalanceDate,
// 'liability_type' => $liabilityType,
// 'liability_direction' => $liabilityDirection,
// 'interest' => $interest,
// 'interest_period' => $interestPeriod,
// 'current_debt' => $this->repository->getMetaValue($account, 'current_debt'),
// 'include_net_worth' => $includeNetWorth,
// 'longitude' => $longitude,
// 'latitude' => $latitude,
// 'zoom_level' => $zoomLevel,
// 'order' => $order,
// 'native_currency_id' => (string) $this->default->id,
// 'native_currency_code' => $this->default->code,
// 'native_currency_symbol' => $this->default->symbol,
// 'native_currency_decimal_places' => $this->default->decimal_places,
//
// // balance:
// 'current_balance' => $balance,
// 'native_current_balance' => $nativeBalance,
// 'current_balance_date' => $this->getDate()->endOfDay()->toAtomString(),
//
// // balance difference
// 'balance_difference' => $balanceDiff,
// 'native_balance_difference' => $nativeBalanceDiff,
// 'balance_difference_start' => $diffStart,
// 'balance_difference_end' => $diffEnd,
//
//
// // liability stuff
// 'liability_type' => $liabilityType,
//
// // object group
// 'object_group_id' => null !== $objectGroupId ? (string) $objectGroupId : null,
// 'object_group_order' => $objectGroupOrder,
// 'object_group_title' => $objectGroupTitle,
// 'notes' => $this->repository->getNoteText($account),
// 'monthly_payment_date' => $monthlyPaymentDate,
// 'credit_card_type' => $creditCardType,
// 'bic' => $this->repository->getMetaValue($account, 'BIC'),
// 'virtual_balance' => number_format((float) $account->virtual_balance, $decimalPlaces, '.', ''),
// 'opening_balance' => $openingBalance,
// 'opening_balance_date' => $openingBalanceDate,
// 'include_net_worth' => $includeNetWorth,
// 'longitude' => $longitude,
// 'latitude' => $latitude,
// 'zoom_level' => $zoomLevel,
];
}
/**
* Get the resource's relationships.
*
* @param null|Request $request
*/
public function relationships($request): iterable
{
return [
$this->relation('user')->withData($this->resource->user),
$this->relation('currency')->withData($this->resource->transactionCurrency),
// $this->relation('account_balances')->withData($this->resource->balances),
];
}
}

View File

@@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Models\Account;
use FireflyIII\Support\JsonApi\Concerns\UsergroupAware;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Core\Schema\Schema;
use LaravelJsonApi\Eloquent\Fields\Relations\HasOne;
use LaravelJsonApi\NonEloquent\Fields\Attribute;
use LaravelJsonApi\NonEloquent\Fields\ID;
use LaravelJsonApi\NonEloquent\Filters\Filter;
use LaravelJsonApi\NonEloquent\Pagination\EnumerablePagination;
class AccountSchema extends Schema
{
use UsergroupAware;
/**
* The model the schema corresponds to.
*/
public static string $model = Account::class;
/**
* Get the resource fields.
*/
public function fields(): array
{
Log::debug(__METHOD__);
return [
ID::make(),
Attribute::make('created_at'),
Attribute::make('updated_at'),
// basic info and meta data
Attribute::make('name')->sortable(),
Attribute::make('active')->sortable(),
Attribute::make('order')->sortable(),
Attribute::make('iban')->sortable(),
Attribute::make('account_type'),
Attribute::make('account_role'),
Attribute::make('account_number')->sortable(),
// currency
Attribute::make('currency_id'),
Attribute::make('currency_name'),
Attribute::make('currency_code'),
Attribute::make('currency_symbol'),
Attribute::make('currency_decimal_places'),
Attribute::make('is_multi_currency'),
// balance
Attribute::make('balance')->sortable(),
Attribute::make('native_balance')->sortable(),
// liability things
Attribute::make('liability_direction'),
Attribute::make('interest'),
Attribute::make('interest_period'),
// Attribute::make('current_debt')->sortable(),
// TODO credit card fields.
// dynamic data
Attribute::make('last_activity')->sortable(),
Attribute::make('balance_difference')->sortable(), // only used for sort.
// group
Attribute::make('object_group_id'),
Attribute::make('object_group_title'),
Attribute::make('object_group_order'),
// relations.
HasOne::make('user')->readOnly(),
];
}
/**
* Get the resource filters.
*/
public function filters(): array
{
Log::debug(__METHOD__);
$array = [];
$config = config('api.valid_api_filters')[Account::class];
foreach ($config as $entry) {
$array[] = Filter::make($entry);
}
return $array;
}
public function repository(): AccountRepository
{
Log::debug(__METHOD__);
$this->setUserGroup($this->server->getUsergroup());
return AccountRepository::make()
->withServer($this->server)
->withSchema($this)
->withUserGroup($this->userGroup)
;
}
public function pagination(): EnumerablePagination
{
Log::debug(__METHOD__);
return EnumerablePagination::make();
}
}

View File

@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Models\Account;
use LaravelJsonApi\Eloquent\Contracts\Paginator;
use LaravelJsonApi\Eloquent\Fields\Boolean;
use LaravelJsonApi\Eloquent\Fields\DateTime;
use LaravelJsonApi\Eloquent\Fields\ID;
use LaravelJsonApi\Eloquent\Fields\Number;
use LaravelJsonApi\Eloquent\Fields\Relations\HasMany;
use LaravelJsonApi\Eloquent\Fields\Relations\HasOne;
use LaravelJsonApi\Eloquent\Fields\Str;
use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
use LaravelJsonApi\Eloquent\Pagination\PagePagination;
use LaravelJsonApi\Eloquent\Schema;
/**
* Class AccountSchema
*
* This is the schema of all fields that an account exposes to the world.
* Fields do not have to have a relation to the actual model.
* Fields mentioned here still need to be filled in by the AccountResource.
*/
class AccountSchemaOld extends Schema
{
/**
* The model the schema corresponds to.
*/
public static string $model = Account::class;
/**
* Get the resource fields.
*/
public function fields(): array
{
return [
ID::make(),
DateTime::make('created_at')->sortable()->readOnly(),
DateTime::make('updated_at')->sortable()->readOnly(),
Str::make('name')->sortable(),
// Str::make('account_type'),
// Str::make('virtual_balance'),
// Str::make('iban'),
// Boolean::make('active'),
// Number::make('order'),
HasOne::make('user')->readOnly(),
// HasMany::make('account_balances'),
];
}
/**
* Filters mentioned here can be used to filter the results.
* TODO write down exactly how this works.
*/
public function filters(): array
{
return [
WhereIdIn::make($this),
];
}
/**
* Get the resource paginator.
*/
public function pagination(): ?Paginator
{
return PagePagination::make();
}
}

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Laravel\Http\Requests\ResourceQuery;
use LaravelJsonApi\Validation\Rule as JsonApiRule;
class AccountSingleQuery extends ResourceQuery
{
/**
* Get the validation rules that apply to the request query parameters.
*/
public function rules(): array
{
Log::debug(__METHOD__);
return [
'fields' => [
'nullable',
'array',
JsonApiRule::fieldSets(),
],
'filter' => [
'nullable',
'array',
JsonApiRule::filter()->forget('id'),
],
'include' => [
'nullable',
'string',
JsonApiRule::includePaths(),
],
'page' => JsonApiRule::notSupported(),
'sort' => JsonApiRule::notSupported(),
'withCount' => [
'nullable',
'string',
JsonApiRule::countable(),
],
];
}
}

View File

@@ -0,0 +1,141 @@
<?php
/*
* AccountQuery.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts\Capabilities;
use FireflyIII\Models\Account;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\JsonApi\CollectsCustomParameters;
use FireflyIII\Support\JsonApi\Concerns\UsergroupAware;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Support\JsonApi\ExpandsQuery;
use FireflyIII\Support\JsonApi\FiltersPagination;
use FireflyIII\Support\JsonApi\SortsCollection;
use FireflyIII\Support\JsonApi\SortsQueryResults;
use FireflyIII\Support\JsonApi\ValidateSortParameters;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Contracts\Pagination\Page;
use LaravelJsonApi\Contracts\Store\HasPagination;
use LaravelJsonApi\NonEloquent\Capabilities\QueryAll;
class AccountQuery extends QueryAll implements HasPagination
{
use AccountFilter;
use CollectsCustomParameters;
use ExpandsQuery;
use FiltersPagination;
use SortsCollection;
use SortsQueryResults;
use UsergroupAware;
use ValidateSortParameters;
// use PaginatesEnumerables;
#[\Override]
/**
* This method returns all accounts, given a bunch of filters and sort fields, together with pagination.
*
* It is only used on the index, and nowhere else.
*/
public function get(): iterable
{
Log::debug(__METHOD__);
// collect sort options
$sort = $this->queryParameters->sortFields();
// collect pagination based on the page
$pagination = $this->filtersPagination($this->queryParameters->page());
// check if we need all accounts, regardless of pagination
// This is necessary when the user wants to sort on specific params.
$needsAll = $this->needsFullDataset(Account::class, $sort);
// params that were not recognised, may be my own custom stuff.
$otherParams = $this->getOtherParams($this->queryParameters->unrecognisedParameters());
// start the query
$query = $this->userGroup->accounts();
// add sort and filter parameters to the query.
$query = $this->addSortParams(Account::class, $query, $sort);
$query = $this->addFilterParams(Account::class, $query, $this->queryParameters->filter());
// collect the result.
$collection = $query->get(['accounts.*']);
// sort the data after the query, and return it right away.
$collection = $this->sortCollection(Account::class, $collection, $sort);
// if the entire collection needs to be enriched and sorted, do so now:
$totalCount = $collection->count();
Log::debug(sprintf('Total is %d', $totalCount));
if ($needsAll) {
Log::debug('Needs the entire collection');
// enrich the entire collection
$enrichment = new AccountEnrichment();
$enrichment->setStart($otherParams['start'] ?? null);
$enrichment->setEnd($otherParams['end'] ?? null);
$collection = $enrichment->enrich($collection);
// TODO sort the set based on post-query sort options:
$collection = $this->postQuerySort(Account::class, $collection, $sort);
// take the current page from the enriched set.
$currentPage = $collection->skip(($pagination['number'] - 1) * $pagination['size'])->take($pagination['size']);
}
if (!$needsAll) {
Log::debug('Needs only partial collection');
// take from the collection the filtered page + page number:
$currentPage = $collection->skip(($pagination['number'] - 1) * $pagination['size'])->take($pagination['size']);
// enrich only the current page.
$enrichment = new AccountEnrichment();
$enrichment->setStart($otherParams['start'] ?? null);
$enrichment->setEnd($otherParams['end'] ?? null);
$currentPage = $enrichment->enrich($currentPage);
}
// get current page?
Log::debug(sprintf('Skip %d, take %d', ($pagination['number'] - 1) * $pagination['size'], $pagination['size']));
// $currentPage = $collection->skip(($pagination['number'] - 1) * $pagination['size'])->take($pagination['size']);
Log::debug(sprintf('New collection size: %d', $currentPage->count()));
// TODO add filters after the query, if there are filters that cannot be applied to the database
// TODO same for sort things.
return new LengthAwarePaginator($currentPage, $totalCount, $pagination['size'], $pagination['number']);
}
#[\Override]
public function paginate(array $page): Page
{
exit('here weare');
// TODO: Implement paginate() method.
}
#[\Override]
public function getOrPaginate(?array $page): iterable
{
exit('here weare');
// TODO: Implement getOrPaginate() method.
}
}

View File

@@ -0,0 +1,60 @@
<?php
/*
* CrudAccount.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts\Capabilities;
use FireflyIII\Models\Account;
use FireflyIII\Support\JsonApi\CollectsCustomParameters;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\NonEloquent\Capabilities\CrudResource;
class CrudAccount extends CrudResource
{
use CollectsCustomParameters;
/**
* Read the supplied site.
*/
public function read(Account $account): ?Account
{
$otherParams = $this->getOtherParams($this->request->query->all());
Log::debug(__METHOD__);
// enrich the collected data
$enrichment = new AccountEnrichment();
// set start and date, if present.
$enrichment->setStart($otherParams['start'] ?? null);
$enrichment->setEnd($otherParams['end'] ?? null);
return $enrichment->enrichSingle($account);
}
public function create(array $validatedData): Account
{
var_dump($validatedData);
exit;
}
}

View File

@@ -1,7 +1,7 @@
<?php
/**
* api.php
* Copyright (c) 2019 james@firefly-iii.org
/*
* CrudAccountRelations.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -16,21 +16,13 @@
* 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/>.
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
/*
* PLEASE DO NOT EDIT THIS FILE DIRECTLY.
* YOUR CHANGES WILL BE OVERWRITTEN!
* YOUR PR WITH CHANGES TO THIS FILE WILL BE REJECTED!
*
* GO TO CROWDIN TO FIX OR CHANGE TRANSLATIONS!
*
* https://crowdin.com/project/firefly-iii
*
*/
namespace FireflyIII\JsonApi\V2\Accounts\Capabilities;
return [
];
use LaravelJsonApi\NonEloquent\Capabilities\CrudRelations;
class CrudAccountRelations extends CrudRelations {}

53
app/JsonApi/V2/Server.php Normal file
View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2;
use FireflyIII\JsonApi\V2\Accounts\AccountSchema;
use FireflyIII\JsonApi\V2\Users\UserSchema;
use FireflyIII\Support\JsonApi\Concerns\UsergroupAware;
use FireflyIII\Support\JsonApi\Concerns\UserGroupDetectable;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Core\Server\Server as BaseServer;
/**
* Class Server
*
* This class serves as a generic class for the v2 API "server".
*/
class Server extends BaseServer
{
use UsergroupAware;
use UserGroupDetectable;
/**
* The base URI namespace for this server.
*/
protected string $baseUri = '/api/v2';
/**
* Bootstrap the server when it is handling an HTTP request.
*/
public function serving(): void
{
Log::debug(__METHOD__);
// at this point the user may not actually have access to this user group.
$res = $this->detectUserGroup();
$this->setUserGroup($res);
}
/**
* Get the server's list of schemas.
*/
protected function allSchemas(): array
{
// Log::debug(__METHOD__);
return [
AccountSchema::class,
UserSchema::class,
// AccountBalanceSchema::class,
];
}
}

View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Users;
use FireflyIII\Models\User;
use Illuminate\Http\Request;
use LaravelJsonApi\Core\Resources\JsonApiResource;
/**
* @property User $resource
*/
class UserResource extends JsonApiResource
{
/**
* Get the resource's attributes.
*
* @param null|Request $request
*/
public function attributes($request): iterable
{
return [
'created_at' => $this->resource->created_at,
'updated_at' => $this->resource->updated_at,
'email' => $this->resource->email,
];
}
/**
* Get the resource's relationships.
*
* @param null|Request $request
*/
public function relationships($request): iterable
{
return [
// @TODO
];
}
}

View File

@@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Users;
use FireflyIII\User;
use LaravelJsonApi\Eloquent\Contracts\Paginator;
use LaravelJsonApi\Eloquent\Fields\DateTime;
use LaravelJsonApi\Eloquent\Fields\ID;
use LaravelJsonApi\Eloquent\Fields\Relations\HasMany;
use LaravelJsonApi\Eloquent\Fields\Str;
use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
use LaravelJsonApi\Eloquent\Pagination\PagePagination;
use LaravelJsonApi\Eloquent\Schema;
class UserSchema extends Schema
{
/**
* The model the schema corresponds to.
*/
public static string $model = User::class;
/**
* Get the resource fields.
*/
public function fields(): array
{
return [
ID::make(),
DateTime::make('created_at')->sortable()->readOnly(),
DateTime::make('updated_at')->sortable()->readOnly(),
Str::make('email'),
HasMany::make('accounts'),
];
}
/**
* Get the resource filters.
*/
public function filters(): array
{
return [
WhereIdIn::make($this),
];
}
/**
* Get the resource paginator.
*/
public function pagination(): ?Paginator
{
return PagePagination::make();
}
}

View File

@@ -23,14 +23,12 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -38,84 +36,14 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class Account
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property null|Carbon $deleted_at
* @property int $user_id
* @property int $account_type_id
* @property string $name
* @property string $virtual_balance
* @property null|string $iban
* @property bool $active
* @property bool $encrypted
* @property int $order
* @property AccountMeta[]|Collection $accountMeta
* @property null|int $account_meta_count
* @property AccountType $accountType
* @property Attachment[]|Collection $attachments
* @property null|int $attachments_count
* @property string $account_number
* @property string $edit_name
* @property Collection|Location[] $locations
* @property null|int $locations_count
* @property Collection|Note[] $notes
* @property null|int $notes_count
* @property Collection|ObjectGroup[] $objectGroups
* @property null|int $object_groups_count
* @property Collection|PiggyBank[] $piggyBanks
* @property null|int $piggy_banks_count
* @property Collection|Transaction[] $transactions
* @property null|int $transactions_count
* @property User $user
*
* @method static EloquentBuilder|Account accountTypeIn($types)
* @method static EloquentBuilder|Account newModelQuery()
* @method static EloquentBuilder|Account newQuery()
* @method static Builder|Account onlyTrashed()
* @method static EloquentBuilder|Account query()
* @method static EloquentBuilder|Account whereAccountTypeId($value)
* @method static EloquentBuilder|Account whereActive($value)
* @method static EloquentBuilder|Account whereCreatedAt($value)
* @method static EloquentBuilder|Account whereDeletedAt($value)
* @method static EloquentBuilder|Account whereEncrypted($value)
* @method static EloquentBuilder|Account whereIban($value)
* @method static EloquentBuilder|Account whereId($value)
* @method static EloquentBuilder|Account whereName($value)
* @method static EloquentBuilder|Account whereOrder($value)
* @method static EloquentBuilder|Account whereUpdatedAt($value)
* @method static EloquentBuilder|Account whereUserId($value)
* @method static EloquentBuilder|Account whereVirtualBalance($value)
* @method static Builder|Account withTrashed()
* @method static Builder|Account withoutTrashed()
*
* @property Carbon $lastActivityDate
* @property string $startBalance
* @property string $endBalance
* @property string $difference
* @property string $interest
* @property string $interestPeriod
* @property string $accountTypeString
* @property Location $location
* @property string $liability_direction
* @property string $current_debt
* @property int $user_group_id
*
* @method static EloquentBuilder|Account whereUserGroupId($value)
*
* @property null|UserGroup $userGroup
* @property mixed $account_id
*
* @mixin Eloquent
* @mixin IdeHelperAccount
*/
class Account extends Model
{
use Cachable;
use HasFactory;
use ReturnsIntegerIdTrait;
use ReturnsIntegerUserIdTrait;
@@ -144,7 +72,7 @@ class Account extends Model
public static function routeBinder(string $value): self
{
if (auth()->check()) {
$accountId = (int)$value;
$accountId = (int) $value;
/** @var User $user */
$user = auth()->user();
@@ -193,6 +121,11 @@ class Account extends Model
return $this->hasMany(AccountMeta::class);
}
public function accountBalances(): HasMany
{
return $this->hasMany(AccountBalance::class);
}
public function getEditNameAttribute(): string
{
$name = $this->name;
@@ -241,7 +174,7 @@ class Account extends Model
public function setVirtualBalanceAttribute(mixed $value): void
{
$value = (string)$value;
$value = (string) $value;
if ('' === $value) {
$value = null;
}
@@ -261,7 +194,7 @@ class Account extends Model
protected function accountId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
get: static fn ($value) => (int) $value,
);
}
@@ -271,21 +204,21 @@ class Account extends Model
protected function accountTypeId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
get: static fn ($value) => (int) $value,
);
}
protected function iban(): Attribute
{
return Attribute::make(
get: static fn ($value) => null === $value ? null : trim(str_replace(' ', '', (string)$value)),
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: static fn ($value) => (int) $value,
);
}
@@ -295,7 +228,7 @@ class Account extends Model
protected function virtualBalance(): Attribute
{
return Attribute::make(
get: static fn ($value) => (string)$value,
get: static fn ($value) => (string) $value,
);
}
}

View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @mixin IdeHelperAccountBalance
*/
class AccountBalance extends Model
{
use HasFactory;
protected $fillable = ['account_id', 'title', 'transaction_currency_id', 'balance'];
public function account(): BelongsTo
{
return $this->belongsTo(Account::class);
}
public function transactionCurrency(): BelongsTo
{
return $this->belongsTo(TransactionCurrency::class);
}
}

View File

@@ -23,35 +23,12 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* Class AccountMeta
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property int $account_id
* @property string $name
* @property mixed $data
* @property Account $account
*
* @method static Builder|AccountMeta newModelQuery()
* @method static Builder|AccountMeta newQuery()
* @method static Builder|AccountMeta query()
* @method static Builder|AccountMeta whereAccountId($value)
* @method static Builder|AccountMeta whereCreatedAt($value)
* @method static Builder|AccountMeta whereData($value)
* @method static Builder|AccountMeta whereId($value)
* @method static Builder|AccountMeta whereName($value)
* @method static Builder|AccountMeta whereUpdatedAt($value)
*
* @mixin Eloquent
* @mixin IdeHelperAccountMeta
*/
class AccountMeta extends Model
{

View File

@@ -23,33 +23,12 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* FireflyIII\Models\AccountType
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property string $type
* @property Account[]|Collection $accounts
* @property null|int $accounts_count
*
* @method static Builder|AccountType newModelQuery()
* @method static Builder|AccountType newQuery()
* @method static Builder|AccountType query()
* @method static Builder|AccountType whereCreatedAt($value)
* @method static Builder|AccountType whereId($value)
* @method static Builder|AccountType whereType($value)
* @method static Builder|AccountType whereUpdatedAt($value)
*
* @mixin Eloquent
* @mixin IdeHelperAccountType
*/
class AccountType extends Model
{

View File

@@ -23,71 +23,19 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* FireflyIII\Models\Attachment
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property null|Carbon $deleted_at
* @property int $user_id
* @property int $attachable_id
* @property string $attachable_type
* @property bool $file_exists
* @property string $md5
* @property string $filename
* @property null|string $title
* @property null|string $description
* @property string $mime
* @property int|string $size
* @property bool $uploaded
* @property string $notes_text
* @property \Eloquent|Model $attachable
* @property Collection|Note[] $notes
* @property null|int $notes_count
* @property User $user
*
* @method static \Illuminate\Database\Eloquent\Builder|Attachment newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Attachment newQuery()
* @method static Builder|Attachment onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|Attachment query()
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereAttachableId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereAttachableType($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereDescription($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereFilename($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereMd5($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereMime($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereSize($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereTitle($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereUploaded($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereUserId($value)
* @method static Builder|Attachment withTrashed()
* @method static Builder|Attachment withoutTrashed()
*
* @property int $user_group_id
*
* @method static \Illuminate\Database\Eloquent\Builder|Attachment whereUserGroupId($value)
*
* @mixin Eloquent
* @mixin IdeHelperAttachment
*/
class Attachment extends Model
{

View File

@@ -24,53 +24,14 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class AuditLogEntry
*
* @property \Eloquent|Model $auditable
* @property \Eloquent|Model $changer
*
* @method static Builder|AuditLogEntry newModelQuery()
* @method static Builder|AuditLogEntry newQuery()
* @method static \Illuminate\Database\Query\Builder|AuditLogEntry onlyTrashed()
* @method static Builder|AuditLogEntry query()
* @method static \Illuminate\Database\Query\Builder|AuditLogEntry withTrashed()
* @method static \Illuminate\Database\Query\Builder|AuditLogEntry withoutTrashed()
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property null|Carbon $deleted_at
* @property int $auditable_id
* @property string $auditable_type
* @property int $changer_id
* @property string $changer_type
* @property string $action
* @property null|array $before
* @property null|array $after
*
* @method static Builder|AuditLogEntry whereAction($value)
* @method static Builder|AuditLogEntry whereAfter($value)
* @method static Builder|AuditLogEntry whereAuditableId($value)
* @method static Builder|AuditLogEntry whereAuditableType($value)
* @method static Builder|AuditLogEntry whereBefore($value)
* @method static Builder|AuditLogEntry whereChangerId($value)
* @method static Builder|AuditLogEntry whereChangerType($value)
* @method static Builder|AuditLogEntry whereCreatedAt($value)
* @method static Builder|AuditLogEntry whereDeletedAt($value)
* @method static Builder|AuditLogEntry whereId($value)
* @method static Builder|AuditLogEntry whereUpdatedAt($value)
*
* @mixin Eloquent
* @mixin IdeHelperAuditLogEntry
*/
class AuditLogEntry extends Model
{

View File

@@ -24,47 +24,14 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
/**
* FireflyIII\Models\AutoBudget
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property null|Carbon $deleted_at
* @property int $budget_id
* @property int $transaction_currency_id
* @property int|string $auto_budget_type
* @property string $amount
* @property string $period
* @property Budget $budget
* @property TransactionCurrency $transactionCurrency
*
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget newQuery()
* @method static Builder|AutoBudget onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget query()
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget whereAmount($value)
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget whereAutoBudgetType($value)
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget whereBudgetId($value)
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget wherePeriod($value)
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget whereTransactionCurrencyId($value)
* @method static \Illuminate\Database\Eloquent\Builder|AutoBudget whereUpdatedAt($value)
* @method static Builder|AutoBudget withTrashed()
* @method static Builder|AutoBudget withoutTrashed()
*
* @mixin Eloquent
* @mixin IdeHelperAutoBudget
*/
class AutoBudget extends Model
{

View File

@@ -23,8 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User;
@@ -32,45 +30,10 @@ use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* FireflyIII\Models\AvailableBudget
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property null|Carbon $deleted_at
* @property int $user_id
* @property int $transaction_currency_id
* @property string $amount
* @property Carbon $start_date
* @property Carbon $end_date
* @property TransactionCurrency $transactionCurrency
* @property User $user
*
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget newQuery()
* @method static Builder|AvailableBudget onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget query()
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget whereAmount($value)
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget whereEndDate($value)
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget whereStartDate($value)
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget whereTransactionCurrencyId($value)
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget whereUserId($value)
* @method static Builder|AvailableBudget withTrashed()
* @method static Builder|AvailableBudget withoutTrashed()
*
* @property int $user_group_id
*
* @method static \Illuminate\Database\Eloquent\Builder|AvailableBudget whereUserGroupId($value)
*
* @mixin Eloquent
* @mixin IdeHelperAvailableBudget
*/
class AvailableBudget extends Model
{

View File

@@ -23,88 +23,20 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* FireflyIII\Models\Bill
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property null|Carbon $deleted_at
* @property int $user_id
* @property int $transaction_currency_id
* @property string $name
* @property string $match
* @property string $amount_min
* @property string $amount_max
* @property Carbon $date
* @property null|Carbon $end_date
* @property null|Carbon $extension_date
* @property string $repeat_freq
* @property int $skip
* @property bool $automatch
* @property bool $active
* @property bool $name_encrypted
* @property bool $match_encrypted
* @property int $order
* @property Attachment[]|Collection $attachments
* @property null|int $attachments_count
* @property Collection|Note[] $notes
* @property null|int $notes_count
* @property Collection|ObjectGroup[] $objectGroups
* @property null|int $object_groups_count
* @property null|TransactionCurrency $transactionCurrency
* @property Collection|TransactionJournal[] $transactionJournals
* @property null|int $transaction_journals_count
* @property User $user
*
* @method static \Illuminate\Database\Eloquent\Builder|Bill newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Bill newQuery()
* @method static Builder|Bill onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|Bill query()
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereActive($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereAmountMax($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereAmountMin($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereAutomatch($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereDate($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereEndDate($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereExtensionDate($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereMatch($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereMatchEncrypted($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereNameEncrypted($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereOrder($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereRepeatFreq($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereSkip($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereTransactionCurrencyId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereUserId($value)
* @method static Builder|Bill withTrashed()
* @method static Builder|Bill withoutTrashed()
*
* @property int $user_group_id
*
* @method static \Illuminate\Database\Eloquent\Builder|Bill whereUserGroupId($value)
*
* @mixin Eloquent
* @mixin IdeHelperBill
*/
class Bill extends Model
{

View File

@@ -23,71 +23,20 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* FireflyIII\Models\Budget
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property null|Carbon $deleted_at
* @property int $user_id
* @property string $name
* @property bool $active
* @property bool $encrypted
* @property int $order
* @property Attachment[]|Collection $attachments
* @property null|int $attachments_count
* @property AutoBudget[]|Collection $autoBudgets
* @property null|int $auto_budgets_count
* @property BudgetLimit[]|Collection $budgetlimits
* @property null|int $budgetlimits_count
* @property Collection|TransactionJournal[] $transactionJournals
* @property null|int $transaction_journals_count
* @property Collection|Transaction[] $transactions
* @property null|int $transactions_count
* @property User $user
*
* @method static \Illuminate\Database\Eloquent\Builder|Budget newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Budget newQuery()
* @method static Builder|Budget onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|Budget query()
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereActive($value)
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereEncrypted($value)
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereOrder($value)
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereUserId($value)
* @method static Builder|Budget withTrashed()
* @method static Builder|Budget withoutTrashed()
*
* @property string $email
* @property int $user_group_id
*
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereUserGroupId($value)
*
* @property Collection|Note[] $notes
* @property null|int $notes_count
*
* @mixin Eloquent
* @mixin IdeHelperBudget
*/
class Budget extends Model
{

View File

@@ -23,50 +23,17 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Events\Model\BudgetLimit\Created;
use FireflyIII\Events\Model\BudgetLimit\Deleted;
use FireflyIII\Events\Model\BudgetLimit\Updated;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* FireflyIII\Models\BudgetLimit
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property int $budget_id
* @property int $transaction_currency_id
* @property Carbon $start_date
* @property null|Carbon $end_date
* @property string $amount
* @property string $spent
* @property null|string $period
* @property int|string $generated
* @property Budget $budget
* @property null|TransactionCurrency $transactionCurrency
*
* @method static Builder|BudgetLimit newModelQuery()
* @method static Builder|BudgetLimit newQuery()
* @method static Builder|BudgetLimit query()
* @method static Builder|BudgetLimit whereAmount($value)
* @method static Builder|BudgetLimit whereBudgetId($value)
* @method static Builder|BudgetLimit whereCreatedAt($value)
* @method static Builder|BudgetLimit whereEndDate($value)
* @method static Builder|BudgetLimit whereGenerated($value)
* @method static Builder|BudgetLimit whereId($value)
* @method static Builder|BudgetLimit wherePeriod($value)
* @method static Builder|BudgetLimit whereStartDate($value)
* @method static Builder|BudgetLimit whereTransactionCurrencyId($value)
* @method static Builder|BudgetLimit whereUpdatedAt($value)
*
* @mixin Eloquent
* @mixin IdeHelperBudgetLimit
*/
class BudgetLimit extends Model
{

View File

@@ -23,60 +23,18 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* FireflyIII\Models\Category
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property null|Carbon $deleted_at
* @property int $user_id
* @property string $name
* @property Carbon $lastActivity
* @property bool $encrypted
* @property Attachment[]|Collection $attachments
* @property null|int $attachments_count
* @property Collection|Note[] $notes
* @property null|int $notes_count
* @property Collection|TransactionJournal[] $transactionJournals
* @property null|int $transaction_journals_count
* @property Collection|Transaction[] $transactions
* @property null|int $transactions_count
* @property User $user
*
* @method static \Illuminate\Database\Eloquent\Builder|Category newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Category newQuery()
* @method static Builder|Category onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|Category query()
* @method static \Illuminate\Database\Eloquent\Builder|Category whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Category whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Category whereEncrypted($value)
* @method static \Illuminate\Database\Eloquent\Builder|Category whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Category whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|Category whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Category whereUserId($value)
* @method static Builder|Category withTrashed()
* @method static Builder|Category withoutTrashed()
*
* @property int $user_group_id
*
* @method static \Illuminate\Database\Eloquent\Builder|Category whereUserGroupId($value)
*
* @mixin Eloquent
* @mixin IdeHelperCategory
*/
class Category extends Model
{

View File

@@ -23,37 +23,12 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
/**
* FireflyIII\Models\Configuration
*
* @property int $id
* @property null|Carbon $created_at
* @property null|Carbon $updated_at
* @property null|Carbon $deleted_at
* @property string $name
* @property mixed $data
*
* @method static \Illuminate\Database\Eloquent\Builder|Configuration newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Configuration newQuery()
* @method static Builder|Configuration onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|Configuration query()
* @method static \Illuminate\Database\Eloquent\Builder|Configuration whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Configuration whereData($value)
* @method static \Illuminate\Database\Eloquent\Builder|Configuration whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Configuration whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Configuration whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|Configuration whereUpdatedAt($value)
* @method static Builder|Configuration withTrashed()
* @method static Builder|Configuration withoutTrashed()
*
* @mixin Eloquent
* @mixin IdeHelperConfiguration
*/
class Configuration extends Model
{

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