Compare commits

..

66 Commits

Author SHA1 Message Date
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
58 changed files with 2089 additions and 1126 deletions

View File

@@ -72,30 +72,38 @@
},
{
"name": "composer/pcre",
"version": "3.1.4",
"version": "3.2.0",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
"reference": "04229f163664973f68f38f6f73d917799168ef24"
"reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/04229f163664973f68f38f6f73d917799168ef24",
"reference": "04229f163664973f68f38f6f73d917799168ef24",
"url": "https://api.github.com/repos/composer/pcre/zipball/ea4ab6f9580a4fd221e0418f2c357cdd39102a90",
"reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0"
},
"conflict": {
"phpstan/phpstan": "<1.11.8"
},
"require-dev": {
"phpstan/phpstan": "^1.3",
"phpstan/phpstan": "^1.11.8",
"phpstan/phpstan-strict-rules": "^1.1",
"symfony/phpunit-bridge": "^5"
"phpunit/phpunit": "^8 || ^9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.x-dev"
},
"phpstan": {
"includes": [
"extension.neon"
]
}
},
"autoload": {
@@ -123,7 +131,7 @@
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/3.1.4"
"source": "https://github.com/composer/pcre/tree/3.2.0"
},
"funding": [
{
@@ -139,20 +147,20 @@
"type": "tidelift"
}
],
"time": "2024-05-27T13:40:54+00:00"
"time": "2024-07-25T09:36:02+00:00"
},
{
"name": "composer/semver",
"version": "3.4.0",
"version": "3.4.2",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
"reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"url": "https://api.github.com/repos/composer/semver/zipball/c51258e759afdb17f1fd1fe83bc12baaef6309d6",
"reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6",
"shasum": ""
},
"require": {
@@ -204,7 +212,7 @@
"support": {
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.4.0"
"source": "https://github.com/composer/semver/tree/3.4.2"
},
"funding": [
{
@@ -220,7 +228,7 @@
"type": "tidelift"
}
],
"time": "2023-08-31T09:50:34+00:00"
"time": "2024-07-12T11:35:52+00:00"
},
{
"name": "composer/xdebug-handler",
@@ -398,16 +406,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.59.3",
"version": "v3.60.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "30ba9ecc2b0e5205e578fe29973c15653d9bfd29"
"reference": "e595e4e070d17c5d42ed8c4206f630fcc5f401a4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/30ba9ecc2b0e5205e578fe29973c15653d9bfd29",
"reference": "30ba9ecc2b0e5205e578fe29973c15653d9bfd29",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/e595e4e070d17c5d42ed8c4206f630fcc5f401a4",
"reference": "e595e4e070d17c5d42ed8c4206f630fcc5f401a4",
"shasum": ""
},
"require": {
@@ -489,7 +497,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.59.3"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.60.0"
},
"funding": [
{
@@ -497,7 +505,7 @@
"type": "github"
}
],
"time": "2024-06-16T14:17:03+00:00"
"time": "2024-07-25T09:26:51+00:00"
},
{
"name": "psr/container",
@@ -1026,31 +1034,31 @@
},
{
"name": "react/socket",
"version": "v1.15.0",
"version": "v1.16.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/socket.git",
"reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038"
"reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/socket/zipball/216d3aec0b87f04a40ca04f481e6af01bdd1d038",
"reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038",
"url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1",
"reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1",
"shasum": ""
},
"require": {
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
"php": ">=5.3.0",
"react/dns": "^1.11",
"react/dns": "^1.13",
"react/event-loop": "^1.2",
"react/promise": "^3 || ^2.6 || ^1.2.1",
"react/stream": "^1.2"
"react/promise": "^3.2 || ^2.6 || ^1.2.1",
"react/stream": "^1.4"
},
"require-dev": {
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
"react/async": "^4 || ^3 || ^2",
"react/async": "^4.3 || ^3.3 || ^2",
"react/promise-stream": "^1.4",
"react/promise-timer": "^1.10"
"react/promise-timer": "^1.11"
},
"type": "library",
"autoload": {
@@ -1094,7 +1102,7 @@
],
"support": {
"issues": "https://github.com/reactphp/socket/issues",
"source": "https://github.com/reactphp/socket/tree/v1.15.0"
"source": "https://github.com/reactphp/socket/tree/v1.16.0"
},
"funding": [
{
@@ -1102,7 +1110,7 @@
"type": "open_collective"
}
],
"time": "2023-12-15T11:02:10+00:00"
"time": "2024-07-26T10:38:09+00:00"
},
{
"name": "react/stream",
@@ -1184,16 +1192,16 @@
},
{
"name": "sebastian/diff",
"version": "6.0.1",
"version": "6.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "ab83243ecc233de5655b76f577711de9f842e712"
"reference": "b4ccd857127db5d41a5b676f24b51371d76d8544"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ab83243ecc233de5655b76f577711de9f842e712",
"reference": "ab83243ecc233de5655b76f577711de9f842e712",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544",
"reference": "b4ccd857127db5d41a5b676f24b51371d76d8544",
"shasum": ""
},
"require": {
@@ -1239,7 +1247,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"security": "https://github.com/sebastianbergmann/diff/security/policy",
"source": "https://github.com/sebastianbergmann/diff/tree/6.0.1"
"source": "https://github.com/sebastianbergmann/diff/tree/6.0.2"
},
"funding": [
{
@@ -1247,20 +1255,20 @@
"type": "github"
}
],
"time": "2024-03-02T07:30:33+00:00"
"time": "2024-07-03T04:53:05+00:00"
},
{
"name": "symfony/console",
"version": "v7.1.2",
"version": "v7.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "0aa29ca177f432ab68533432db0de059f39c92ae"
"reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/0aa29ca177f432ab68533432db0de059f39c92ae",
"reference": "0aa29ca177f432ab68533432db0de059f39c92ae",
"url": "https://api.github.com/repos/symfony/console/zipball/cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9",
"reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9",
"shasum": ""
},
"require": {
@@ -1324,7 +1332,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.1.2"
"source": "https://github.com/symfony/console/tree/v7.1.3"
},
"funding": [
{
@@ -1340,7 +1348,7 @@
"type": "tidelift"
}
],
"time": "2024-06-28T10:03:55+00:00"
"time": "2024-07-26T12:41:01+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -1633,16 +1641,16 @@
},
{
"name": "symfony/finder",
"version": "v7.1.1",
"version": "v7.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "fbb0ba67688b780efbc886c1a0a0948dcf7205d6"
"reference": "717c6329886f32dc65e27461f80f2a465412fdca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/fbb0ba67688b780efbc886c1a0a0948dcf7205d6",
"reference": "fbb0ba67688b780efbc886c1a0a0948dcf7205d6",
"url": "https://api.github.com/repos/symfony/finder/zipball/717c6329886f32dc65e27461f80f2a465412fdca",
"reference": "717c6329886f32dc65e27461f80f2a465412fdca",
"shasum": ""
},
"require": {
@@ -1677,7 +1685,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v7.1.1"
"source": "https://github.com/symfony/finder/tree/v7.1.3"
},
"funding": [
{
@@ -1693,7 +1701,7 @@
"type": "tidelift"
}
],
"time": "2024-05-31T14:57:53+00:00"
"time": "2024-07-24T07:08:44+00:00"
},
{
"name": "symfony/options-resolver",
@@ -2238,16 +2246,16 @@
},
{
"name": "symfony/process",
"version": "v7.1.1",
"version": "v7.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "febf90124323a093c7ee06fdb30e765ca3c20028"
"reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/febf90124323a093c7ee06fdb30e765ca3c20028",
"reference": "febf90124323a093c7ee06fdb30e765ca3c20028",
"url": "https://api.github.com/repos/symfony/process/zipball/7f2f542c668ad6c313dc4a5e9c3321f733197eca",
"reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca",
"shasum": ""
},
"require": {
@@ -2279,7 +2287,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v7.1.1"
"source": "https://github.com/symfony/process/tree/v7.1.3"
},
"funding": [
{
@@ -2295,7 +2303,7 @@
"type": "tidelift"
}
],
"time": "2024-05-31T14:57:53+00:00"
"time": "2024-07-26T12:44:47+00:00"
},
{
"name": "symfony/service-contracts",
@@ -2444,16 +2452,16 @@
},
{
"name": "symfony/string",
"version": "v7.1.2",
"version": "v7.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8"
"reference": "ea272a882be7f20cad58d5d78c215001617b7f07"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/14221089ac66cf82e3cf3d1c1da65de305587ff8",
"reference": "14221089ac66cf82e3cf3d1c1da65de305587ff8",
"url": "https://api.github.com/repos/symfony/string/zipball/ea272a882be7f20cad58d5d78c215001617b7f07",
"reference": "ea272a882be7f20cad58d5d78c215001617b7f07",
"shasum": ""
},
"require": {
@@ -2511,7 +2519,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v7.1.2"
"source": "https://github.com/symfony/string/tree/v7.1.3"
},
"funding": [
{
@@ -2527,7 +2535,7 @@
"type": "tidelift"
}
],
"time": "2024-06-28T09:27:18+00:00"
"time": "2024-07-22T10:25:37+00:00"
}
],
"packages-dev": [],

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

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

View File

@@ -0,0 +1,110 @@
<?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)
{
$model = $schema
->repository()
->queryOne($account)
->withRequest($request)
->first()
;
// 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

@@ -44,55 +44,8 @@ class FixUnevenAmount extends 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->fixUnevenAmounts();
$this->matchCurrencies();
return 0;
}
@@ -149,4 +102,76 @@ class FixUnevenAmount extends Command
$message = sprintf('Corrected amount in transaction journal #%d', $param);
$this->friendlyInfo($message);
}
private function fixUnevenAmounts(): void
{
$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');
}
}
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.*'])
;
if (0 === $journals->count()) {
$this->friendlyPositive('Journal currency integrity is OK');
return;
}
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
Transaction::where('transaction_journal_id', $journal->id)->update(['transaction_currency_id' => $journal->transaction_currency_id]);
}
$this->friendlyPositive(sprintf('Fixed %d journal(s) with mismatched currencies.', $journals->count()));
}
}

View File

@@ -1,43 +0,0 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Api\V3\Controllers;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\JsonApi\V3\AccountBalances\AccountBalanceSchema;
use FireflyIII\Models\Account;
use Illuminate\Contracts\Support\Responsable;
use LaravelJsonApi\Core\Facades\JsonApi;
use LaravelJsonApi\Core\Responses\DataResponse;
use LaravelJsonApi\Laravel\Http\Controllers\Actions;
use LaravelJsonApi\Laravel\Http\Requests\AnonymousQuery;
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;
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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -21,7 +21,7 @@
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3\AccountBalances;
namespace FireflyIII\JsonApi\V2\AccountBalances;
use FireflyIII\Entities\AccountBalance;
use LaravelJsonApi\Contracts\Store\QueriesAll;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3\AccountBalances;
namespace FireflyIII\JsonApi\V2\AccountBalances;
use Illuminate\Http\Request;
use LaravelJsonApi\Core\Resources\JsonApiResource;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3\AccountBalances;
namespace FireflyIII\JsonApi\V2\AccountBalances;
use FireflyIII\Entities\AccountBalance;
use LaravelJsonApi\Core\Schema\Schema;

View File

@@ -21,7 +21,7 @@
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3\AccountBalances\Capabilities;
namespace FireflyIII\JsonApi\V2\AccountBalances\Capabilities;
use FireflyIII\Entities\AccountBalance;
use FireflyIII\Models\Account;

View File

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Models\Account;
use FireflyIII\Rules\IsAllowedGroupAction;
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__);
return [
'fields' => [
'nullable',
'array',
JsonApiRule::fieldSets(),
],
'user_group_id' => [
'nullable',
'integer',
new IsAllowedGroupAction(Account::class, request()->method()),
],
'filter' => [
'nullable',
'array',
JsonApiRule::filter(),
],
'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,98 @@
<?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\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
{
use HasCrudCapability;
use HasRelationsCapability;
use UsergroupAware;
/**
* SiteRepository constructor.
*/
public function __construct() {}
public function exists(string $resourceId): bool
{
Log::debug(__METHOD__);
return null !== Account::find((int) $resourceId);
}
public function find(string $resourceId): ?object
{
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
{
return Capabilities\CrudAccount::make();
}
protected function relations(): CrudRelations
{
return Capabilities\CrudAccountRelations::make();
}
}

View File

@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Models\Account;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Core\Resources\JsonApiResource;
/**
* @property Account $resource
*/
class AccountResource extends JsonApiResource
{
/**
* Get the resource id.
*/
public function id(): string
{
Log::debug(__METHOD__);
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,
'type' => $this->resource->account_type_string,
'account_role' => $this->resource->account_role,
'account_number' => '' === $this->resource->account_number ? null : $this->resource->account_number,
// currency
'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,
// liability things
'liability_direction' => $this->resource->liability_direction,
'interest' => $this->resource->interest,
'interest_period' => $this->resource->interest_period,
'current_debt' => $this->resource->current_debt,
'last_activity' => $this->resource->last_activity,
];
}
/**
* Get the resource's relationships.
*
* @param null|Request $request
*/
public function relationships($request): iterable
{
return [
$this->relation('user')->withData($this->resource->user),
];
}
}

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3\Accounts;
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Models\Account;
use Illuminate\Http\Request;
@@ -10,8 +10,13 @@ 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 AccountResource extends JsonApiResource
class AccountResourceOld extends JsonApiResource
{
/**
* Get the resource's attributes.
@@ -20,32 +25,23 @@ class AccountResource extends JsonApiResource
*/
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,
'iban' => '' === $this->resource->iban ? null : $this->resource->iban,
'active' => $this->resource->active,
'last_activity' => $this->resource->last_activity,
'type' => $this->resource->type,
'account_role' => $this->resource->account_role,
'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' => []
//
// currency
// 'currency_id' => $this->resource->currency_id,
// 'currency_code' => $this->resource->currency_code,
// 'currency_symbol' => $this->resource->currency_symbol,
// 'currency_decimal_places' => $this->resource->currency_decimal_places,
// 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,
@@ -65,11 +61,6 @@ class AccountResource extends JsonApiResource
// 'order' => $order,
// '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,
@@ -86,15 +77,9 @@ class AccountResource extends JsonApiResource
// 'balance_difference_start' => $diffStart,
// 'balance_difference_end' => $diffEnd,
//
// // more meta
// 'last_activity' => array_key_exists($id, $this->lastActivity) ? $this->lastActivity[$id]->toAtomString() : null,
//
// // liability stuff
// 'liability_type' => $liabilityType,
// 'liability_direction' => $liabilityDirection,
// 'interest' => $interest,
// 'interest_period' => $interestPeriod,
// 'current_debt' => $currentDebt,
//
// // object group
// 'object_group_id' => null !== $objectGroupId ? (string) $objectGroupId : null,
@@ -123,7 +108,8 @@ class AccountResource extends JsonApiResource
{
return [
$this->relation('user')->withData($this->resource->user),
$this->relation('account_balances')->withData($this->resource->balances),
$this->relation('currency')->withData($this->resource->transactionCurrency),
// $this->relation('account_balances')->withData($this->resource->balances),
];
}
}

View File

@@ -0,0 +1,88 @@
<?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;
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'),
Attribute::make('active'),
Attribute::make('order'),
Attribute::make('type'),
Attribute::make('account_role'),
Attribute::make('account_number'),
// currency
Attribute::make('currency_id'),
Attribute::make('currency_name'),
Attribute::make('currency_code'),
Attribute::make('currency_symbol'),
Attribute::make('currency_decimal_places'),
// liability things
Attribute::make('liability_direction'),
Attribute::make('interest'),
Attribute::make('interest_period'),
Attribute::make('current_debt'),
// dynamic data
Attribute::make('last_activity'),
HasOne::make('user')->readOnly(),
];
}
/**
* Get the resource filters.
*/
public function filters(): array
{
Log::debug(__METHOD__);
return [
Filter::make('id'),
];
}
public function repository(): AccountRepository
{
Log::debug(__METHOD__);
$this->setUserGroup($this->server->getUsergroup());
return AccountRepository::make()
->withServer($this->server)
->withSchema($this)
->withUserGroup($this->userGroup)
;
}
}

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3\Accounts;
namespace FireflyIII\JsonApi\V2\Accounts;
use FireflyIII\Models\Account;
use LaravelJsonApi\Eloquent\Contracts\Paginator;
@@ -17,7 +17,14 @@ use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
use LaravelJsonApi\Eloquent\Pagination\PagePagination;
use LaravelJsonApi\Eloquent\Schema;
class AccountSchema extends 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.
@@ -34,18 +41,19 @@ class AccountSchema extends Schema
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'),
HasMany::make('account_balances'),
// 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'),
];
}
/**
* Get the resource filters.
* Filters mentioned here can be used to filter the results.
* TODO write down exactly how this works.
*/
public function filters(): array
{

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

@@ -21,7 +21,7 @@
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3\Accounts\Capabilities;
namespace FireflyIII\JsonApi\V2\Accounts\Capabilities;
use FireflyIII\Support\JsonApi\Concerns\UsergroupAware;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
@@ -29,6 +29,7 @@ use FireflyIII\Support\JsonApi\ExpandsQuery;
use FireflyIII\Support\JsonApi\FiltersPagination;
use FireflyIII\Support\JsonApi\SortsCollection;
use FireflyIII\Support\JsonApi\ValidateSortParameters;
use Illuminate\Support\Facades\Log;
use LaravelJsonApi\Contracts\Store\HasPagination;
use LaravelJsonApi\NonEloquent\Capabilities\QueryAll;
use LaravelJsonApi\NonEloquent\Concerns\PaginatesEnumerables;
@@ -43,31 +44,45 @@ class AccountQuery extends QueryAll implements HasPagination
use ValidateSortParameters;
#[\Override]
/**
* This method returns all accounts, given a bunch of filters and sort fields, together with pagination.
*/
public function get(): iterable
{
Log::debug(__METHOD__);
// collect filters
$filters = $this->queryParameters->filter();
// collect sort options
$sort = $this->queryParameters->sortFields();
// collect pagination based on the page
$pagination = $this->filtersPagination($this->queryParameters->page());
$needsAll = $this->validateParams('account', $sort);
// 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', $sort);
// start the query
$query = $this->userGroup->accounts();
// add pagination to the query, limiting the results.
if (!$needsAll) {
$query = $this->addPagination($query, $pagination);
}
// add sort and filter parameters to the query.
$query = $this->addSortParams($query, $sort);
$query = $this->addFilterParams('account', $query, $filters);
// collect the result.
$collection = $query->get(['accounts.*']);
// enrich data
// enrich the collected data
$enrichment = new AccountEnrichment();
$collection = $enrichment->enrich($collection);
// add filters after the query
// TODO add filters after the query, if there are filters that cannot be applied to the database but only
// to the enriched results.
// add sort after the query
// sort the data after the query, and return it right away.
return $this->sortCollection($collection, $sort);
// var_dump($filters->value('name'));
// exit;
}
}

View File

@@ -1,6 +1,6 @@
<?php
/*
* AccountRepository.php
* CrudAccount.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
@@ -21,33 +21,22 @@
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3\Accounts;
namespace FireflyIII\JsonApi\V2\Accounts\Capabilities;
use FireflyIII\Models\Account;
use FireflyIII\Support\JsonApi\Concerns\UsergroupAware;
use LaravelJsonApi\Contracts\Store\QueriesAll;
use LaravelJsonApi\NonEloquent\AbstractRepository;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use LaravelJsonApi\NonEloquent\Capabilities\CrudResource;
class AccountRepository extends AbstractRepository implements QueriesAll
class CrudAccount extends CrudResource
{
use UsergroupAware;
/**
* SiteRepository constructor.
* Read the supplied site.
*/
public function __construct() {}
public function find(string $resourceId): ?object
public function read(Account $account): ?Account
{
return Account::find((int) $resourceId);
}
// enrich the collected data
$enrichment = new AccountEnrichment();
public function queryAll(): Capabilities\AccountQuery
{
return Capabilities\AccountQuery::make()
->withUserGroup($this->userGroup)
->withServer($this->server)
->withSchema($this->schema)
;
return $enrichment->enrichSingle($account);
}
}

View File

@@ -0,0 +1,28 @@
<?php
/*
* CrudAccountRelations.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 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

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3\Users;
namespace FireflyIII\JsonApi\V2\Users;
use FireflyIII\Models\User;
use Illuminate\Http\Request;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3\Users;
namespace FireflyIII\JsonApi\V2\Users;
use FireflyIII\User;
use LaravelJsonApi\Eloquent\Contracts\Paginator;

View File

@@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
namespace FireflyIII\JsonApi\V3;
use FireflyIII\JsonApi\V3\Accounts\AccountSchema;
use FireflyIII\JsonApi\V3\AccountBalances\AccountBalanceSchema;
use FireflyIII\JsonApi\V3\Users\UserSchema;
use LaravelJsonApi\Core\Server\Server as BaseServer;
class Server extends BaseServer
{
/**
* The base URI namespace for this server.
*/
protected string $baseUri = '/api/v3';
/**
* Bootstrap the server when it is handling an HTTP request.
*/
public function serving(): void
{
// no-op
}
/**
* Get the server's list of schemas.
*/
protected function allSchemas(): array
{
return [
AccountSchema::class,
UserSchema::class,
AccountBalanceSchema::class,
];
}
}

View File

@@ -28,6 +28,7 @@ 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;
@@ -50,6 +51,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property null|Carbon $deleted_at
* @property int $user_id
* @property int $account_type_id
* @property string $account_type_string
* @property string $name
* @property string $virtual_balance
* @property null|string $iban
@@ -74,6 +76,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property Collection|Transaction[] $transactions
* @property null|int $transactions_count
* @property User $user
* @property string $last_activity
*
* @method static EloquentBuilder|Account accountTypeIn($types)
* @method static EloquentBuilder|Account newModelQuery()
@@ -116,6 +119,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
*/
class Account extends Model
{
use Cachable;
use HasFactory;
use ReturnsIntegerIdTrait;
use ReturnsIntegerUserIdTrait;
@@ -144,7 +148,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();
@@ -246,7 +250,7 @@ class Account extends Model
public function setVirtualBalanceAttribute(mixed $value): void
{
$value = (string)$value;
$value = (string) $value;
if ('' === $value) {
$value = null;
}
@@ -266,7 +270,7 @@ class Account extends Model
protected function accountId(): Attribute
{
return Attribute::make(
get: static fn ($value) => (int)$value,
get: static fn ($value) => (int) $value,
);
}
@@ -276,21 +280,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,
);
}
@@ -300,7 +304,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

@@ -26,6 +26,7 @@ namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\Support\Models\ReturnsIntegerIdTrait;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Collection;
@@ -93,6 +94,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
*/
class Transaction extends Model
{
use Cachable;
use HasFactory;
use ReturnsIntegerIdTrait;
use SoftDeletes;

View File

@@ -554,6 +554,12 @@ class AccountRepository implements AccountRepositoryInterface
++$index;
}
}
// reset the rest to zero.
$all = [AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE];
$this->user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereNotIn('account_types.type', $all)
->update(['order' => 0])
;
}
public function searchAccount(string $query, array $types, int $limit): Collection

View File

@@ -408,10 +408,16 @@ class RecurringRepository implements RecurringRepositoryInterface
private function filterMaxDate(?Carbon $max, array $occurrences): array
{
if (null === $max) {
return $occurrences;
}
$filtered = [];
if (null === $max) {
foreach ($occurrences as $date) {
if ($date->gt(today())) {
$filtered[] = $date;
}
}
return $filtered;
}
foreach ($occurrences as $date) {
if ($date->lte($max) && $date->gt(today())) {
$filtered[] = $date;

View File

@@ -241,6 +241,12 @@ class AccountRepository implements AccountRepositoryInterface
++$index;
}
}
// reset the rest to zero.
$all = [AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE];
$this->user->accounts()->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereNotIn('account_types.type', $all)
->update(['order' => 0])
;
}
public function getAccountsByType(array $types, ?array $sort = [], ?array $filters = []): Collection

View File

@@ -0,0 +1,130 @@
<?php
/*
* IsAllowedGroupAction.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\Rules;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Support\Facades\Log;
class IsAllowedGroupAction implements ValidationRule
{
private string $className;
private string $methodName;
private array $acceptedRoles;
private UserGroupRepositoryInterface $repository;
public function __construct(string $className, string $methodName)
{
$this->className = $className;
$this->methodName = $methodName;
// you need these roles to do anything with any endpoint.
$this->acceptedRoles = [UserRoleEnum::OWNER, UserRoleEnum::FULL];
$this->repository = app(UserGroupRepositoryInterface::class);
}
/**
* @throws AuthorizationException
*/
#[\Override]
public function validate(string $attribute, mixed $value, \Closure $fail): void
{
if ('GET' === $this->methodName) {
// need at least "read only rights".
$this->acceptedRoles[] = UserRoleEnum::READ_ONLY;
}
if ('GET' !== $this->methodName) {
// either post, put or delete or something else.. you need more access rights.
switch ($this->className) {
default:
throw new AuthorizationException(sprintf('Cannot handle class "%s"', $this->className));
case Account::class:
$this->acceptedRoles[] = UserRoleEnum::MANAGE_TRANSACTIONS;
break;
}
}
$this->validateUserGroup((int)$value, $fail);
}
private function validateUserGroup(int $userGroupId, \Closure $fail): void
{
Log::debug(sprintf('validateUserGroup: %s', static::class));
if (!auth()->check()) {
Log::debug('validateUserGroup: user is not logged in, return NULL.');
$fail('validation.no_auth_user_group')->translate();
return;
}
/** @var User $user */
$user = auth()->user();
if (0 !== $userGroupId) {
Log::debug(sprintf('validateUserGroup: user group submitted, search for memberships in group #%d.', $userGroupId));
}
if (0 === $userGroupId) {
$userGroupId = $user->user_group_id;
Log::debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $userGroupId));
}
$this->repository->setUser($user);
$memberships = $this->repository->getMembershipsFromGroupId($userGroupId);
if (0 === $memberships->count()) {
Log::debug(sprintf('validateUserGroup: user has no access to group #%d.', $userGroupId));
$fail('validation.no_access_user_group')->translate();
return;
}
// need to get the group from the membership:
$userGroup = $this->repository->getById($userGroupId);
if (null === $userGroup) {
Log::debug(sprintf('validateUserGroup: group #%d does not exist.', $userGroupId));
$fail('validation.belongs_user_or_user_group')->translate();
return;
}
Log::debug(sprintf('validateUserGroup: validate access of user to group #%d ("%s").', $userGroupId, $userGroup->title));
Log::debug(sprintf('validateUserGroup: have %d roles to check.', count($this->acceptedRoles)), $this->acceptedRoles);
/** @var UserRoleEnum $role */
foreach ($this->acceptedRoles as $role) {
if ($user->hasRoleInGroupOrOwner($userGroup, $role)) {
Log::debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return.', $role->value, $userGroupId));
return;
}
Log::debug(sprintf('validateUserGroup: User does NOT have role "%s" in group #%d, continue searching.', $role->value, $userGroupId));
}
Log::debug('validateUserGroup: User does NOT have enough rights to access endpoint.');
$fail('validation.belongs_user_or_user_group')->translate();
}
}

View File

@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
/**
@@ -49,9 +50,10 @@ class ExchangeRateConverter
public function convert(TransactionCurrency $from, TransactionCurrency $to, Carbon $date, string $amount): string
{
if (false === config('cer.enabled')) {
Log::debug('ExchangeRateConverter: disabled, return amount as is.');
return $amount;
}
Log::debug('convert()');
$rate = $this->getCurrencyRate($from, $to, $date);
return bcmul($amount, $rate);
@@ -63,9 +65,10 @@ class ExchangeRateConverter
public function getCurrencyRate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): string
{
if (false === config('cer.enabled')) {
Log::debug('ExchangeRateConverter: disabled, return "1".');
return '1';
}
Log::debug('getCurrencyRate()');
$rate = $this->getRate($from, $to, $date);
return '0' === $rate ? '1' : $rate;
@@ -76,25 +79,36 @@ class ExchangeRateConverter
*/
private function getRate(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): string
{
Log::debug('getRate()');
if ($this->isPrepared && $this->noPreparedRates) {
$fallback = $this->fallback[$from->id][$to->id] ?? '0';
Log::debug(sprintf('Return fallback rate from #%d to #%d on %s: %s', $from->id, $to->id, $date->format('Y-m-d'), $fallback));
$key = $this->getCacheKey($from, $to, $date);
$res = Cache::get($key, null);
return $fallback;
// find in cache
if (null !== $res) {
Log::debug(sprintf('ExchangeRateConverter: Return cached rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
return $res;
}
// first attempt:
// find in database
$rate = $this->getFromDB($from->id, $to->id, $date->format('Y-m-d'));
if (null !== $rate) {
Cache::forever($key, $rate);
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
return $rate;
}
// no result. perhaps the other way around?
// find reverse in database
$rate = $this->getFromDB($to->id, $from->id, $date->format('Y-m-d'));
if (null !== $rate) {
return bcdiv('1', $rate);
$rate = bcdiv('1', $rate);
Cache::forever($key, $rate);
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
return $rate;
}
// if nothing in place, fall back on the rate for $from to EUR
// fallback scenario.
$first = $this->getEuroRate($from, $date);
$second = $this->getEuroRate($to, $date);
@@ -102,17 +116,19 @@ class ExchangeRateConverter
if (0 === bccomp('0', $first) || 0 === bccomp('0', $second)) {
Log::warning(sprintf('$first is "%s" and $second is "%s"', $first, $second));
return '0';
return '1';
}
$second = bcdiv('1', $second);
$rate = bcmul($first, $second);
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
Cache::forever($key, $rate);
return bcmul($first, $second);
return $rate;
}
private function getFromDB(int $from, int $to, string $date): ?string
{
Log::debug('getFromDB()');
if ($from === $to) {
return '1';
}
@@ -121,7 +137,7 @@ class ExchangeRateConverter
// perhaps the rate has been cached during this particular run
$preparedRate = $this->prepared[$date][$from][$to] ?? null;
if (null !== $preparedRate && 0 !== bccomp('0', $preparedRate)) {
Log::debug(sprintf('Found prepared rate from #%d to #%d on %s.', $from, $to, $date));
Log::debug(sprintf('ExchangeRateConverter: Found prepared rate from #%d to #%d on %s.', $from, $to, $date));
return $preparedRate;
}
@@ -133,7 +149,7 @@ class ExchangeRateConverter
if ('' === $rate) {
return null;
}
Log::debug(sprintf('Found cached rate from #%d to #%d on %s.', $from, $to, $date));
Log::debug(sprintf('ExchangeRateConverter: Found !cached! rate from #%d to #%d on %s.', $from, $to, $date));
return $rate;
}
@@ -148,19 +164,19 @@ class ExchangeRateConverter
->first()
;
++$this->queryCount;
$rate = (string)$result?->rate;
$rate = (string) $result?->rate;
if ('' === $rate) {
app('log')->debug(sprintf('Found no rate for #%d->#%d (%s) in the DB.', $from, $to, $date));
app('log')->debug(sprintf('ExchangeRateConverter: Found no rate for #%d->#%d (%s) in the DB.', $from, $to, $date));
return null;
}
if (0 === bccomp('0', $rate)) {
app('log')->debug(sprintf('Found rate for #%d->#%d (%s) in the DB, but it\'s zero.', $from, $to, $date));
app('log')->debug(sprintf('ExchangeRateConverter: Found rate for #%d->#%d (%s) in the DB, but it\'s zero.', $from, $to, $date));
return null;
}
app('log')->debug(sprintf('Found rate for #%d->#%d (%s) in the DB: %s.', $from, $to, $date, $rate));
app('log')->debug(sprintf('ExchangeRateConverter: Found rate for #%d->#%d (%s) in the DB: %s.', $from, $to, $date, $rate));
$cache->store($rate);
// if the rate has not been cached during this particular run, save it
@@ -184,7 +200,6 @@ class ExchangeRateConverter
*/
private function getEuroRate(TransactionCurrency $currency, Carbon $date): string
{
Log::debug('getEuroRate()');
$euroId = $this->getEuroId();
if ($euroId === $currency->id) {
return '1';
@@ -204,7 +219,7 @@ class ExchangeRateConverter
// grab backup values from config file:
$backup = config(sprintf('cer.rates.%s', $currency->code));
if (null !== $backup) {
return bcdiv('1', (string)$backup);
return bcdiv('1', (string) $backup);
// app('log')->debug(sprintf('Backup rate for %s to EUR is %s.', $currency->code, $backup));
// return $backup;
}
@@ -222,7 +237,7 @@ class ExchangeRateConverter
$cache = new CacheProperties();
$cache->addProperty('cer-euro-id');
if ($cache->has()) {
return (int)$cache->get();
return (int) $cache->get();
}
$euro = TransactionCurrency::whereCode('EUR')->first();
++$this->queryCount;
@@ -319,4 +334,9 @@ class ExchangeRateConverter
}
Log::debug(sprintf('ExchangeRateConverter ran %d queries.', $this->queryCount));
}
private function getCacheKey(TransactionCurrency $from, TransactionCurrency $to, Carbon $date): string
{
return sprintf('cer-%d-%d-%s', $from->id, $to->id, $date->format('Y-m-d'));
}
}

View File

@@ -0,0 +1,62 @@
<?php
/*
* UserGroupDetectable.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\Support\JsonApi\Concerns;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
trait UserGroupDetectable
{
/**
* Return the user group or NULL if none is set.
* Will throw exception if invalid.
* TODO Duplicate from API v2 code.
*/
public function detectUserGroup(): ?UserGroup
{
/** @var User $user */
$user = auth()->user();
app('log')->debug('Now in detectUserGroup()');
/** @var null|UserGroup $userGroup */
$userGroup = request()->route()?->parameter('userGroup');
if (null === $userGroup) {
app('log')->debug('Request class has no userGroup parameter, but perhaps there is a parameter.');
$userGroupId = (int)request()->get('user_group_id');
if (0 === $userGroupId) {
app('log')->debug(sprintf('Request class has no user_group_id parameter, grab default from user (group #%d).', $user->user_group_id));
$userGroupId = (int)$user->user_group_id;
}
$userGroup = UserGroup::find($userGroupId);
if (null === $userGroup) {
app('log')->error(sprintf('Request class has user_group_id (#%d), but group does not exist.', $userGroupId));
return null;
}
app('log')->debug('Request class has valid user_group_id.');
}
return $userGroup;
}
}

View File

@@ -29,35 +29,56 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Class AccountEnrichment
*
* This class "enriches" accounts and adds data from other tables and models to each account model.
*/
class AccountEnrichment implements EnrichmentInterface
{
private Collection $collection;
private array $currencies;
private AccountRepositoryInterface $repository;
private CurrencyRepositoryInterface $currencyRepository;
public function __construct()
{
$this->repository = app(AccountRepositoryInterface::class);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
}
#[\Override]
/**
* Do the actual enrichment.
*/
public function enrich(Collection $collection): Collection
{
Log::debug(sprintf('Now doing account enrichment for %d account(s)', $collection->count()));
// prep local fields
$this->collection = $collection;
$this->currencies = [];
// do everything here:
$this->getLastActivity();
// $this->getMetaBalances();
$this->collectAccountTypes();
$this->collectMetaData();
// $this->getMetaBalances();
$this->collection->transform(function (Account $account) {
$account->user_array = ['id' => 1, 'bla bla' => 'bla'];
$account->balances = collect([
['balance_id' => 1, 'balance' => 5],
['balance_id' => 2, 'balance' => 5],
['balance_id' => 3, 'balance' => 5],
]);
return $account;
});
// $this->collection->transform(function (Account $account) {
// $account->user_array = ['id' => 1, 'bla bla' => 'bla'];
// $account->balances = collect([
// ['balance_id' => 1, 'balance' => 5],
// ['balance_id' => 2, 'balance' => 5],
// ['balance_id' => 3, 'balance' => 5],
// ]);
//
// return $account;
// });
return $this->collection;
}
@@ -67,9 +88,7 @@ class AccountEnrichment implements EnrichmentInterface
*/
private function getLastActivity(): void
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$lastActivity = $accountRepository->getLastActivity($this->collection);
$lastActivity = $this->repository->getLastActivity($this->collection);
foreach ($lastActivity as $row) {
$this->collection->where('id', $row['account_id'])->first()->last_activity = Carbon::parse($row['date_max'], config('app.timezone'));
}
@@ -98,17 +117,15 @@ class AccountEnrichment implements EnrichmentInterface
*/
private function collectAccountTypes(): void
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$accountTypes = $accountRepository->getAccountTypes($this->collection);
$types = [];
$accountTypes = $this->repository->getAccountTypes($this->collection);
$types = [];
/** @var AccountType $row */
foreach ($accountTypes as $row) {
$types[$row->id] = $row->type;
}
$this->collection->transform(function (Account $account) use ($types) {
$account->type = $types[$account->id];
$account->account_type_string = $types[$account->id];
return $account;
});
@@ -116,17 +133,11 @@ class AccountEnrichment implements EnrichmentInterface
private function collectMetaData(): void
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$metaFields = $this->repository->getMetaValues($this->collection, ['currency_id', 'account_role', 'account_number', 'liability_direction', 'interest', 'interest_period', 'current_debt']);
$currencyIds = $metaFields->where('name', 'currency_id')->pluck('data')->toArray();
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$metaFields = $accountRepository->getMetaValues($this->collection, ['currency_id', 'account_role', 'account_number', 'liability_direction', 'interest', 'interest_period', 'current_debt']);
$currencyIds = $metaFields->where('name', 'currency_id')->pluck('data')->toArray();
$currencies = [];
foreach ($repository->getByIds($currencyIds) as $currency) {
$currencies = [];
foreach ($this->currencyRepository->getByIds($currencyIds) as $currency) {
$id = $currency->id;
$currencies[$id] = $currency;
}
@@ -137,6 +148,7 @@ class AccountEnrichment implements EnrichmentInterface
$account->{$entry->name} = $entry->data;
if ('currency_id' === $entry->name) {
$id = (int) $entry->data;
$account->currency_name = $currencies[$id]?->name;
$account->currency_code = $currencies[$id]?->code;
$account->currency_symbol = $currencies[$id]?->symbol;
$account->currency_decimal_places = $currencies[$id]?->decimal_places;
@@ -146,4 +158,14 @@ class AccountEnrichment implements EnrichmentInterface
return $account;
});
}
#[\Override]
public function enrichSingle(Model $model): Model
{
Log::debug(__METHOD__);
$collection = new Collection([$model]);
$collection = $this->enrich($collection);
return $collection->first();
}
}

View File

@@ -23,9 +23,12 @@ declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
interface EnrichmentInterface
{
public function enrich(Collection $collection): Collection;
public function enrichSingle(Model $model): Model;
}

View File

@@ -27,7 +27,7 @@ use LaravelJsonApi\Core\Query\SortFields;
trait ValidateSortParameters
{
public function validateParams(string $class, ?SortFields $params): bool
public function needsFullDataset(string $class, ?SortFields $params): bool
{
if (null === $params) {
return false;

View File

@@ -121,6 +121,10 @@ class AccountBalanceCalculator
$sumAmount = '' === $sumAmount ? '0' : $sumAmount;
$sumForeignAmount = '' === $sumForeignAmount ? '0' : $sumForeignAmount;
// at this point SQLite may return scientific notation because why not. Terrible.
$sumAmount = app('steam')->floatalize($sumAmount);
$sumForeignAmount = app('steam')->floatalize($sumForeignAmount);
// first create for normal currency:
$entry = $this->getAccountBalanceByAccount($account, $transactionCurrency);

View File

@@ -750,6 +750,8 @@ class Navigation
$function = $functionMap[$range];
$end->{$function}(); // @phpstan-ignore-line
Log::debug(sprintf('updateEndDate returns "%s"', $end->format('Y-m-d')));
return $end;
}
if ('6M' === $range) {
@@ -806,6 +808,7 @@ class Navigation
if (array_key_exists($range, $functionMap)) {
$function = $functionMap[$range];
$start->{$function}(); // @phpstan-ignore-line
Log::debug(sprintf('updateStartDate returns "%s"', $start->format('Y-m-d')));
return $start;
}

View File

@@ -73,6 +73,7 @@ trait ChecksLogin
/**
* Return the user group or NULL if none is set.
* Will throw exception if invalid.
* TODO duplicated in JSONAPI code.
*/
public function getUserGroup(): ?UserGroup
{

View File

@@ -836,6 +836,7 @@ class Steam
if (!str_contains($value, 'E')) {
return $value;
}
Log::debug(sprintf('Floatalizing %s', $value));
$number = substr($value, 0, (int)strpos($value, 'E'));
if (str_contains($number, '.')) {

View File

@@ -128,7 +128,8 @@ class RecurrenceTransformer extends AbstractTransformer
];
// get the (future) occurrences for this specific type of repetition:
$occurrences = $this->repository->getXOccurrencesSince($repetition, $fromDate, new Carbon(), 5);
$amount = 'daily' === $repetition->repetition_type ? 9 : 5;
$occurrences = $this->repository->getXOccurrencesSince($repetition, $fromDate, now(), $amount);
/** @var Carbon $carbon */
foreach ($occurrences as $carbon) {

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 6.1.19 - 2024-07-20
### Fixed
- [Issue 8844](https://github.com/firefly-iii/firefly-iii/issues/8844) (Split recurring transaction gets wrong (split) titles) reported by @dreautall
- [Issue 8981](https://github.com/firefly-iii/firefly-iii/issues/8981) (bcadd() error during Docker container startup) reported by @NoiTheCat
- [Issue 8986](https://github.com/firefly-iii/firefly-iii/issues/8986) (Search with "internal_reference_is" finds all transactions with full word of search string) reported by @baflo
- [Issue 9009](https://github.com/firefly-iii/firefly-iii/issues/9009) (Incorrect Amount Calculation in Reconciliation for Bank Account A) reported by @realzsan3
- [Issue 9021](https://github.com/firefly-iii/firefly-iii/issues/9021) (Incorrect "Expected Withdrawals" for Daily Recurring Transactions) reported by @xMarcii
- [Issue 9022](https://github.com/firefly-iii/firefly-iii/issues/9022) (Calendar Not Showing Green Fields for Recurring Transactions) reported by @xMarcii
- Improved currency exchange rate downloader
## 6.1.18 - 2024-06-19
### Fixed

View File

@@ -84,6 +84,7 @@
"bacon/bacon-qr-code": "2.*",
"diglactic/laravel-breadcrumbs": "^9",
"gdbots/query-parser": "^3.0",
"genealabs/laravel-model-caching": "^11.0",
"guzzlehttp/guzzle": "^7.8",
"jc5/google2fa-laravel": "^2.0",
"jc5/recovery": "^2",
@@ -107,8 +108,8 @@
"spatie/laravel-ignition": "^2",
"spatie/period": "^2.4",
"symfony/expression-language": "^7.0",
"symfony/http-client": "^7.0",
"symfony/mailgun-mailer": "^7.0"
"symfony/http-client": "^7.1",
"symfony/mailgun-mailer": "^7.1"
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.9",

661
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -225,7 +225,7 @@ return [
'show_copy' => false, // Show copy button next to the query,
'slow_threshold' => false, // Only track queries that last longer than this time in ms
'memory_usage' => false, // Show queries memory usage
'soft_limit' => 100, // After the soft limit, no parameters/backtrace are captured
'soft_limit' => 250, // After the soft limit, no parameters/backtrace are captured
'hard_limit' => 500, // After the hard limit, queries are ignored
],
'mail' => [

View File

@@ -114,10 +114,10 @@ return [
'telemetry' => false,
'webhooks' => true,
'handle_debts' => true,
'expression_engine' => false,
'expression_engine' => true,
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2024-07-01',
'version' => 'develop/2024-07-29',
'api_version' => '2.1.0',
'db_version' => 24,
@@ -503,13 +503,13 @@ return [
'remove_tag' => RemoveTag::class,
'remove_all_tags' => RemoveAllTags::class,
'set_description' => SetDescription::class,
'append_description' => AppendDescription::class,
'prepend_description' => PrependDescription::class,
// 'append_description' => AppendDescription::class,
// 'prepend_description' => PrependDescription::class,
'set_source_account' => SetSourceAccount::class,
'set_destination_account' => SetDestinationAccount::class,
'set_notes' => SetNotes::class,
'append_notes' => AppendNotes::class,
'prepend_notes' => PrependNotes::class,
// 'append_notes' => AppendNotes::class,
// 'prepend_notes' => PrependNotes::class,
'clear_notes' => ClearNotes::class,
'link_to_bill' => LinkToBill::class,
'convert_withdrawal' => ConvertToWithdrawal::class,
@@ -518,10 +518,10 @@ return [
'switch_accounts' => SwitchAccounts::class,
'update_piggy' => UpdatePiggybank::class,
'delete_transaction' => DeleteTransaction::class,
'append_descr_to_notes' => AppendDescriptionToNotes::class,
'append_notes_to_descr' => AppendNotesToDescription::class,
'move_descr_to_notes' => MoveDescriptionToNotes::class,
'move_notes_to_descr' => MoveNotesToDescription::class,
// 'append_descr_to_notes' => AppendDescriptionToNotes::class,
// 'append_notes_to_descr' => AppendNotesToDescription::class,
// 'move_descr_to_notes' => MoveDescriptionToNotes::class,
// 'move_notes_to_descr' => MoveNotesToDescription::class,
'set_source_to_cash' => SetSourceToCashAccount::class,
'set_destination_to_cash' => SetDestinationToCashAccount::class,
'set_amount' => SetAmount::class,

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
use FireflyIII\JsonApi\V3\Server;
use FireflyIII\JsonApi\V2\Server;
return [
/*
@@ -30,6 +30,6 @@ return [
| class name of the server class.
*/
'servers' => [
'v3' => Server::class,
'v2' => Server::class,
],
];

View File

@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
return [
'cache-prefix' => '',
'enabled' => env('MODEL_CACHE_ENABLED', true),
'use-database-keying' => env('MODEL_CACHE_USE_DATABASE_KEYING', true),
'store' => env('MODEL_CACHE_STORE'),
];

927
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@
},
"devDependencies": {
"@johmun/vue-tags-input": "^2",
"@vue/compiler-sfc": "^3.3.4",
"@vue/compiler-sfc": "^3.4.34",
"axios": "^1.3",
"bootstrap-sass": "^3",
"cross-env": "^7.0",

View File

@@ -9,17 +9,17 @@
},
"devDependencies": {
"axios": "^1.6.8",
"laravel-vite-plugin": "^1.0.2",
"laravel-vite-plugin": "^1.0.5",
"patch-package": "^8.0.0",
"sass": "^1.75.0",
"sass": "^1.77.8",
"vite": "^5",
"vite-plugin-manifest-sri": "^0.2.0"
},
"dependencies": {
"@ag-grid-community/client-side-row-model": "^31.0.3",
"@ag-grid-community/core": "^31.0.3",
"@ag-grid-community/infinite-row-model": "^31.0.3",
"@ag-grid-community/styles": "^31.0.3",
"@ag-grid-community/client-side-row-model": "^32.0.2",
"@ag-grid-community/core": "^32.0.2",
"@ag-grid-community/infinite-row-model": "^32.0.2",
"@ag-grid-community/styles": "^32.0.0",
"@fortawesome/fontawesome-free": "^6.4.0",
"@popperjs/core": "^2.11.8",
"admin-lte": "^4.0.0-alpha3",

View File

@@ -268,6 +268,7 @@ return [
'auto_budget_period_mandatory' => 'The auto budget period is a mandatory field.',
// no access to administration:
'no_auth_user_group' => 'You have to be logged in to access this administration.',
'no_access_user_group' => 'You do not have the correct access rights for this administration.',
'administration_owner_rename' => 'You can\'t rename your standard administration.',
];

View File

@@ -98,6 +98,7 @@
<!-- {{ trans('firefly.bill_expected_date', {date: entry.next_expected_match_diff }) }} -->
</td>
<td class="expected_in_period hidden-sm hidden-xs">
{% for date in entry.pay_dates %}
{{ formatDate(date, monthAndDayFormat) }}<br>
{% endfor %}
@@ -111,6 +112,7 @@
#}
{% if entry.paid_dates|length > 0 and entry.active %}
<td class="paid_in_period text-success">
{% for currentPaid in entry.paid_dates %}
<a href="{{ route('transactions.show',currentPaid.transaction_group_id) }}">
{{ formatDate(currentPaid.date, monthAndDayFormat) }}
@@ -120,7 +122,9 @@
</td>
<td class="expected_in_period hidden-sm hidden-xs">
{% if entry.next_expected_match %}
{{ formatDate(entry.next_expected_match, monthAndDayFormat) }}
{{ formatDate(entry.next_expected_match, monthAndDayFormat) }}
{% else %}
<span class="text-muted">{{ entry.next_expected_match_diff }}</span>
{% endif %}
</td>
{% endif %}

View File

@@ -22,14 +22,23 @@
declare(strict_types=1);
use FireflyIII\Http\Controllers\Api\V3\Controllers\AccountController;
use FireflyIII\Api\V2\Controllers\JsonApi\AccountController;
use LaravelJsonApi\Laravel\Facades\JsonApiRoute;
use LaravelJsonApi\Laravel\Http\Controllers\JsonApiController;
use LaravelJsonApi\Laravel\Routing\ActionRegistrar;
use LaravelJsonApi\Laravel\Routing\Relationships;
use LaravelJsonApi\Laravel\Routing\ResourceRegistrar;
// V2 auto complete controller(s)
/*
*
* ____ ____ ___ .______ ______ __ __ .___________. _______ _______.
* \ \ / / |__ \ | _ \ / __ \ | | | | | || ____| / |
* \ \/ / ) | | |_) | | | | | | | | | `---| |----`| |__ | (----`
* \ / / / | / | | | | | | | | | | | __| \ \
* \ / / /_ | |\ \----.| `--' | | `--' | | | | |____.----) |
* \__/ |____| | _| `._____| \______/ \______/ |__| |_______|_______/
*/
// AUTOCOMPLETE ROUTES
Route::group(
[
'namespace' => 'FireflyIII\Api\V2\Controllers\Autocomplete',
@@ -37,7 +46,6 @@ Route::group(
'as' => 'api.v2.autocomplete.',
],
static function (): void {
// Auto complete routes
Route::get('accounts', ['uses' => 'AccountController@accounts', 'as' => 'accounts']);
Route::get('categories', ['uses' => 'CategoryController@categories', 'as' => 'categories']);
Route::get('tags', ['uses' => 'TagController@tags', 'as' => 'tags']);
@@ -45,7 +53,7 @@ Route::group(
}
);
// V2 API routes for charts
// CHART ROUTES
Route::group(
[
'namespace' => 'FireflyIII\Api\V2\Controllers\Chart',
@@ -54,28 +62,12 @@ Route::group(
],
static function (): void {
Route::get('account/dashboard', ['uses' => 'AccountController@dashboard', 'as' => 'account.dashboard']);
// Route::get('budget/dashboard', ['uses' => 'BudgetController@dashboard', 'as' => 'budget.dashboard']);
// Route::get('category/dashboard', ['uses' => 'CategoryController@dashboard', 'as' => 'category.dashboard']);
Route::get('budget/dashboard', ['uses' => 'BudgetController@dashboard', 'as' => 'budget.dashboard']);
Route::get('category/dashboard', ['uses' => 'CategoryController@dashboard', 'as' => 'category.dashboard']);
Route::get('balance/balance', ['uses' => 'BalanceController@balance', 'as' => 'balance.balance']);
}
);
// JsonApiRoute::server('v3')
// ->prefix('v3')
// ->resources(function (ResourceRegistrar $server) {
// $server->resource('accounts', AccountController::class)->readOnly()->relationships(function (Relationships $relations) {
// $relations->hasOne('user')->readOnly();
// //$relations->hasMany('account_balances')->readOnly();
// })
// ->actions(function (ActionRegistrar $actions) {
// $actions->withId()->get('account-balances', 'readAccountBalances'); // non-eloquent pseudo relation
// });
// $server->resource('users', JsonApiController::class)->readOnly()->relationships(function (Relationships $relations) {
// $relations->hasMany('accounts')->readOnly();
// });
// $server->resource('account-balances', JsonApiController::class);
// });
// V2 API route for Summary boxes
// BASIC
Route::group(
@@ -121,19 +113,19 @@ Route::group(
}
);
// V2 API route for accounts.
Route::group(
[
'namespace' => 'FireflyIII\Api\V2\Controllers\Model\Account',
'prefix' => 'v2/accounts',
'as' => 'api.v2.accounts.',
],
static function (): void {
Route::get('', ['uses' => 'IndexController@index', 'as' => 'index']);
Route::get('{account}', ['uses' => 'ShowController@show', 'as' => 'show']);
Route::put('{account}', ['uses' => 'UpdateController@update', 'as' => 'update']);
}
);
// // V2 API route for accounts.
// Route::group(
// [
// 'namespace' => 'FireflyIII\Api\V2\Controllers\Model\Account',
// 'prefix' => 'v2/accounts',
// 'as' => 'api.v2.accounts.',
// ],
// static function (): void {
// Route::get('', ['uses' => 'IndexController@index', 'as' => 'index']);
// Route::get('{account}', ['uses' => 'ShowController@show', 'as' => 'show']);
// Route::put('{account}', ['uses' => 'UpdateController@update', 'as' => 'update']);
// }
// );
// V2 API route for subscriptions.
Route::group(
@@ -247,7 +239,30 @@ Route::group(
}
);
// down here is v1
// V2 JSON API ROUTES
JsonApiRoute::server('v2')->prefix('v2')
->resources(function (ResourceRegistrar $server): void {
// ACCOUNTS
$server->resource('accounts', AccountController::class)->readOnly()->relationships(function (Relationships $relations): void {
$relations->hasOne('user')->readOnly();
});
// $server->resource('accounts', AccountController::class)->readOnly();
// USERS
$server->resource('users', JsonApiController::class)->readOnly()->relationships(function (Relationships $relations): void {
$relations->hasMany('accounts')->readOnly();
});
})
;
/*
* ____ ____ __ .______ ______ __ __ .___________. _______ _______.
* \ \ / / /_ | | _ \ / __ \ | | | | | || ____| / |
* \ \/ / | | | |_) | | | | | | | | | `---| |----`| |__ | (----`
* \ / | | | / | | | | | | | | | | | __| \ \
* \ / | | | |\ \----.| `--' | | `--' | | | | |____.----) |
* \__/ |_| | _| `._____| \______/ \______/ |__| |_______|_______/
*/
// Autocomplete controllers
Route::group(
@@ -278,7 +293,7 @@ Route::group(
);
// CHART ROUTES.
// Accounts
// Chart accounts
Route::group(
[
'namespace' => 'FireflyIII\Api\V1\Controllers\Chart',