Compare commits

...

68 Commits

Author SHA1 Message Date
github-actions
a9ea32772f Auto commit for release 'develop' on 2025-01-01 2025-01-01 16:38:58 +01:00
James Cole
6fde693e7a Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/Support/Steam.php
2024-12-31 08:19:47 +01:00
James Cole
2e46d9ba33 Clean up some logs. 2024-12-31 08:18:40 +01:00
James Cole
e36f8deb08 Clean up some logs. 2024-12-31 08:18:21 +01:00
James Cole
1631b422f1 Clean up logs, add cache. 2024-12-31 08:17:35 +01:00
github-actions
b58d809063 Auto commit for release 'develop' on 2024-12-31 2024-12-31 08:09:51 +01:00
James Cole
9e34314dbc Fix various issues with new features, nullpointers and missing checks. 2024-12-31 08:05:25 +01:00
github-actions
e4aa218b5f Auto commit for release 'v6.2.0-alpha.1' on 2024-12-30 2024-12-30 17:09:40 +01:00
github-actions
31722477d4 Merge branch 'develop' 2024-12-30 16:07:29 +00:00
github-actions
ec82105433 Auto commit for release 'develop' on 2024-12-30 2024-12-30 15:35:26 +01:00
James Cole
146e164f04 Back to 8. 2024-12-30 15:31:27 +01:00
James Cole
7d37c93988 Expand workflow. 2024-12-30 15:25:39 +01:00
James Cole
73dffacd9a Expand to support alpha and beta versions. 2024-12-30 12:23:50 +01:00
James Cole
d37304fa68 Fix available budgets. 2024-12-30 12:22:39 +01:00
James Cole
62f4da6063 Update available budgets code. 2024-12-30 10:51:34 +01:00
James Cole
760da08ab7 Update exchange rates. 2024-12-30 07:36:22 +01:00
James Cole
e68c4d4408 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2024-12-30 07:36:12 +01:00
James Cole
46a200aa1f Fix broken variable. 2024-12-30 07:30:23 +01:00
James Cole
c422039335 Merge pull request #9589 from tasnim0tantawi/autocomplete-test
Autocomplete test - CurrencyControllerTest & ObjectGroupControllerTest
2024-12-30 07:18:05 +01:00
github-actions
0579c8565d Auto commit for release 'develop' on 2024-12-30 2024-12-30 04:12:18 +01:00
James Cole
9f25880a59 Clean up several endpoints with complex code. 2024-12-29 18:32:02 +01:00
James Cole
05f1819f7d Fix API convert to native. Still needs refactoring. 2024-12-29 14:24:20 +01:00
James Cole
fa2149f957 Update API to convert to native. 2024-12-29 13:47:48 +01:00
James Cole
c21a79e029 Better, but not perfect, currency switch. 2024-12-29 08:16:27 +01:00
James Cole
03e31ebb5e Clean up endpoint. 2024-12-29 06:36:49 +01:00
James Cole
3c20e5f3af Make sure integers are converted to strings because sqlite sucks. 2024-12-29 06:32:50 +01:00
James Cole
9a9dd9e075 Double fix. Not sure yet what causes this. 2024-12-29 06:17:29 +01:00
James Cole
7189986c03 Remove some debug logging. 2024-12-29 06:15:42 +01:00
James Cole
b407d8d315 Add usergroup, clean up some code. 2024-12-29 06:14:40 +01:00
James Cole
41fa2a6208 Include user group in test set. 2024-12-29 06:10:54 +01:00
James Cole
fe00c4c373 Fix unauthenticated get default currency. 2024-12-29 06:08:35 +01:00
James Cole
7248a76c63 Fix chart, expand changelog. 2024-12-29 05:58:12 +01:00
James Cole
ee3c618797 Fix https://github.com/firefly-iii/firefly-iii/issues/9586 2024-12-29 05:55:49 +01:00
James Cole
a1241ebedb Various multi-currency things in the autocomplete API. 2024-12-28 18:38:19 +01:00
James Cole
af78d998db Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2024-12-28 14:09:42 +01:00
James Cole
d96c235ffe Fix path 2024-12-28 14:09:22 +01:00
James Cole
79ca1b5f4e Change some CS fixer settings. 2024-12-28 14:08:34 +01:00
github-actions
0f68735e1c Auto commit for release 'develop' on 2024-12-28 2024-12-28 13:59:31 +01:00
James Cole
82abee37de Fix a string of text. 2024-12-28 13:45:45 +01:00
James Cole
507040f1fd Update various code for sqlite compatibility. 2024-12-28 13:36:25 +01:00
James Cole
42dc8486e9 Fix string. 2024-12-28 11:16:55 +01:00
github-actions
6c655634bc Auto commit for release 'develop' on 2024-12-28 2024-12-28 10:58:01 +01:00
James Cole
f2166b97b8 Various fixes for sqlite databases 2024-12-28 10:52:46 +01:00
James Cole
da88e02be0 Catch exception. 2024-12-28 07:47:32 +01:00
James Cole
0d56b7d251 Ignore error. Must test more with sqlite. 2024-12-28 07:39:39 +01:00
James Cole
0a089efcac Clean up commands. 2024-12-28 07:35:20 +01:00
James Cole
89ab360391 Remove reference to cacheable models 2024-12-28 07:10:33 +01:00
James Cole
2bd97d9a99 Remove references to laravel json api 2024-12-28 07:09:25 +01:00
James Cole
103b9056e4 Expand changelog, remove unused packages. 2024-12-28 06:55:17 +01:00
github-actions
23c4352c18 Auto commit for release 'develop' on 2024-12-27 2024-12-27 22:03:16 +01:00
James Cole
2dddaa36d5 Actions will default to php 8.4 2024-12-27 19:51:20 +01:00
James Cole
8ab7cf2388 Merge branch 'v6.2' into develop
# Conflicts:
#	composer.lock
#	config/firefly.php
#	package-lock.json
2024-12-27 19:50:05 +01:00
James Cole
f191086adb Enable cache again. 2024-12-27 19:47:35 +01:00
James Cole
68b446db18 Final changes. 2024-12-27 19:46:40 +01:00
James Cole
3d49d81856 Expand some multi currency things. 2024-12-27 16:36:01 +01:00
James Cole
96493425d1 Convert more of the budget view to native currency. 2024-12-27 13:42:48 +01:00
James Cole
419975285c Fix nullpointer 2024-12-27 13:02:23 +01:00
TasneemTantawy
5971d155ef fixed create authenticated user 2024-12-23 09:37:06 +03:00
James Cole
cea52c0ac7 Merge pull request #9571 from firefly-iii/dependabot/composer/develop/phpunit/phpunit-10.5.40
Bump phpunit/phpunit from 10.5.39 to 10.5.40
2024-12-23 07:02:55 +01:00
James Cole
1b33ff9c25 Merge pull request #9573 from firefly-iii/dependabot/npm_and_yarn/develop/i18next-24.2.0
Bump i18next from 24.1.2 to 24.2.0
2024-12-23 07:02:41 +01:00
James Cole
594ba205bb Merge pull request #9574 from firefly-iii/dependabot/npm_and_yarn/develop/vite-6.0.5
Bump vite from 6.0.3 to 6.0.5
2024-12-23 07:01:29 +01:00
dependabot[bot]
495f5c71c3 Bump vite from 6.0.3 to 6.0.5
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.0.3 to 6.0.5.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.0.5/packages/vite)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-23 03:12:47 +00:00
dependabot[bot]
7e80f607b7 Bump i18next from 24.1.2 to 24.2.0
Bumps [i18next](https://github.com/i18next/i18next) from 24.1.2 to 24.2.0.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v24.1.2...v24.2.0)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-23 03:12:31 +00:00
github-actions
d93732e451 Auto commit for release 'develop' on 2024-12-23 2024-12-23 04:12:14 +01:00
dependabot[bot]
1b57bc7889 Bump phpunit/phpunit from 10.5.39 to 10.5.40
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.5.39 to 10.5.40.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.5.40/ChangeLog-10.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/10.5.39...10.5.40)

---
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-12-23 03:01:52 +00:00
TasneemTantawy
9e373a9b0d object group controller test 2024-12-22 16:29:56 +03:00
TasneemTantawy
4fb61646b4 currency controller test 2024-12-22 15:54:18 +03:00
github-actions
e2f1fc307f Auto commit for release 'develop' on 2024-12-18 2024-12-18 16:52:40 +01:00
193 changed files with 1820 additions and 3574 deletions

View File

@@ -29,7 +29,7 @@ $paths = [
$current . '/../../database',
$current . '/../../routes',
$current . '/../../tests',
$current . '/../../resources/lang',
$current . '/../../resources/lang/en_US',
];
$finder = PhpCsFixer\Finder::create()

View File

@@ -406,16 +406,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.65.0",
"version": "v3.66.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f"
"reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/79d4f3e77b250a7d8043d76c6af8f0695e8a469f",
"reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/5f5f2a142ff36b93c41885bca29cc5f861c013e6",
"reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6",
"shasum": ""
},
"require": {
@@ -441,7 +441,7 @@
"symfony/polyfill-mbstring": "^1.28",
"symfony/polyfill-php80": "^1.28",
"symfony/polyfill-php81": "^1.28",
"symfony/process": "^5.4 || ^6.0 || ^7.0",
"symfony/process": "^5.4 || ^6.0 || ^7.0 <7.2",
"symfony/stopwatch": "^5.4 || ^6.0 || ^7.0"
},
"require-dev": {
@@ -497,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.65.0"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.66.0"
},
"funding": [
{
@@ -505,7 +505,7 @@
"type": "github"
}
],
"time": "2024-11-25T00:39:24+00:00"
"time": "2024-12-29T13:46:23+00:00"
},
{
"name": "psr/container",
@@ -1369,12 +1369,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -1517,12 +1517,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -1641,16 +1641,16 @@
},
{
"name": "symfony/finder",
"version": "v7.2.0",
"version": "v7.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49"
"reference": "87a71856f2f56e4100373e92529eed3171695cfb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/6de263e5868b9a137602dd1e33e4d48bfae99c49",
"reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49",
"url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb",
"reference": "87a71856f2f56e4100373e92529eed3171695cfb",
"shasum": ""
},
"require": {
@@ -1685,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.2.0"
"source": "https://github.com/symfony/finder/tree/v7.2.2"
},
"funding": [
{
@@ -1701,7 +1701,7 @@
"type": "tidelift"
}
],
"time": "2024-10-23T06:56:12+00:00"
"time": "2024-12-30T19:00:17+00:00"
},
{
"name": "symfony/options-resolver",
@@ -2246,16 +2246,16 @@
},
{
"name": "symfony/process",
"version": "v7.2.0",
"version": "v7.1.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e"
"reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e",
"reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e",
"url": "https://api.github.com/repos/symfony/process/zipball/42783370fda6e538771f7c7a36e9fa2ee3a84892",
"reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892",
"shasum": ""
},
"require": {
@@ -2287,7 +2287,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v7.2.0"
"source": "https://github.com/symfony/process/tree/v7.1.8"
},
"funding": [
{
@@ -2303,7 +2303,7 @@
"type": "tidelift"
}
],
"time": "2024-11-06T14:24:19+00:00"
"time": "2024-11-06T14:23:19+00:00"
},
{
"name": "symfony/service-contracts",
@@ -2329,12 +2329,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -2390,16 +2390,16 @@
},
{
"name": "symfony/stopwatch",
"version": "v7.2.0",
"version": "v7.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/stopwatch.git",
"reference": "696f418b0d722a4225e1c3d95489d262971ca924"
"reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/696f418b0d722a4225e1c3d95489d262971ca924",
"reference": "696f418b0d722a4225e1c3d95489d262971ca924",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/e46690d5b9d7164a6d061cab1e8d46141b9f49df",
"reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df",
"shasum": ""
},
"require": {
@@ -2432,7 +2432,7 @@
"description": "Provides a way to profile code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/stopwatch/tree/v7.2.0"
"source": "https://github.com/symfony/stopwatch/tree/v7.2.2"
},
"funding": [
{
@@ -2448,7 +2448,7 @@
"type": "tidelift"
}
],
"time": "2024-09-25T14:21:43+00:00"
"time": "2024-12-18T14:28:33+00:00"
},
{
"name": "symfony/string",

View File

@@ -10,7 +10,7 @@ on:
phpversion:
description: 'PHP version'
required: true
default: '8.3'
default: '8.4'
schedule:
- cron: '0 3 * * MON'
@@ -168,7 +168,7 @@ jobs:
# if this is a develop build, slightly different variable names.
if [[ "develop" == "$version" ]]; then
[[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
#[[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
releaseName=$version-$(date +'%Y%m%d')
originalName=$releaseName
zipName=FireflyIII-develop.zip
@@ -177,7 +177,7 @@ jobs:
# if this is a branch build, also slightly different variable names.
if [[ "$version" == branch* ]]; then
[[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
#[[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
# branch builds overrule develop
releaseName=$version-$(date +'%Y%m%d')
originalName=$releaseName
@@ -229,7 +229,7 @@ jobs:
# describe the development release.
if [[ "develop" == "$version" ]]; then
echo 'Develop release.'
rm output.txt
rm -f output.txt
touch output.txt
sudo chown -R runner:docker output.txt
echo "Weekly development release of Firefly III with the latest fixes, translations and features. Docker users can find this release under the \`develop\` tag." >> output.txt
@@ -244,7 +244,7 @@ jobs:
# describe a branch release
if [[ "$version" == branch* ]]; then
echo 'Branch release.'
rm output.txt
rm -f output.txt
touch output.txt
sudo chown -R runner:docker output.txt
echo "Irregular BRANCH release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
@@ -257,9 +257,45 @@ jobs:
echo ":warning: Please be careful with this branch pre-release, as it may not work as expected." >> output.txt
fi
# describe the main release
if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]]; then
sudo chown -R runner:docker output.txt
if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]] && [[ "$version" != *alpha* ]] && [[ "$version" != *beta* ]]; then
echo 'Main release.'
sudo chown -R runner:docker output.txt
echo '' >> output.txt
echo '### Instructions' >> output.txt
echo '' >> output.txt
echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
fi
# describe alpha release
if [[ "$version" == *alpha* ]]; then
echo 'ALPHA release.'
rm -f output.txt
touch output.txt
sudo chown -R runner:docker output.txt
echo "Very early ALPHA release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
echo '' >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo '' >> output.txt
echo '### Instructions' >> output.txt
echo '' >> output.txt
echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
fi
# describe beta release
if [[ "$version" == *beta* ]]; then
echo 'BETA release.'
rm -f output.txt
touch output.txt
sudo chown -R runner:docker output.txt
echo "Very early BETA release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
echo '' >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo '' >> output.txt
echo '### Instructions' >> output.txt
echo '' >> output.txt
@@ -336,12 +372,12 @@ jobs:
gh release upload $releaseName HEAD.txt
# remove all temporary files
rm output.txt
rm HEAD.txt
rm $zipName
rm $zipName.sha256
rm $tarName
rm $tarName.sha256
rm -f output.txt
rm -f HEAD.txt
rm -f $zipName
rm -f $zipName.sha256
rm -f $tarName
rm -f $tarName.sha256
# merge main back into develop
git checkout develop

View File

@@ -19,7 +19,7 @@ jobs:
- name: Setup PHP with Xdebug
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
php-version: '8.4'
coverage: xdebug
extensions: >-
bcmath

View File

@@ -4,6 +4,7 @@ Over time, many people have contributed to Firefly III. Their efforts are not al
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
## 2024
- TasneemTantawy
- Antônio Franco
- yparitcher
- Jhon Pedroza

View File

@@ -26,9 +26,9 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\AccountFilter;
@@ -62,7 +62,7 @@ class AccountController extends Controller
return $next($request);
}
);
$this->balanceTypes = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
$this->balanceTypes = [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value];
}
/**
@@ -74,27 +74,27 @@ class AccountController extends Controller
*/
public function accounts(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$types = $data['types'];
$query = $data['query'];
$date = $data['date'] ?? today(config('app.timezone'));
$return = [];
$result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
// TODO this code is duplicated in the V2 Autocomplete controller, which means this code is due to be deprecated.
$defaultCurrency = app('amount')->getDefaultCurrency();
$data = $request->getData();
$types = $data['types'];
$query = $data['query'];
$date = $data['date'] ?? today(config('app.timezone'));
$return = [];
$result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
/** @var Account $account */
foreach ($result as $account) {
$nameWithBalance = $account->name;
$currency = $this->repository->getAccountCurrency($account) ?? $defaultCurrency;
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
$useCurrency = $currency;
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
$balance = Steam::finalAccountBalance($account, $date);
$key = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
$useCurrency = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? $this->defaultCurrency : $currency;
$amount = $balance[$key] ?? '0';
$nameWithBalance = sprintf(
'%s (%s)',
$account->name,
app('amount')->formatAnything($currency, $balance['balance'], false)
app('amount')->formatAnything($useCurrency, $amount, false)
);
}
@@ -103,11 +103,11 @@ class AccountController extends Controller
'name' => $account->name,
'name_with_balance' => $nameWithBalance,
'type' => $account->accountType->type,
'currency_id' => (string) $currency->id,
'currency_name' => $currency->name,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'currency_id' => (string) $useCurrency->id,
'currency_name' => $useCurrency->name,
'currency_code' => $useCurrency->code,
'currency_symbol' => $useCurrency->symbol,
'currency_decimal_places' => $useCurrency->decimal_places,
];
}
@@ -115,7 +115,7 @@ class AccountController extends Controller
usort(
$return,
static function (array $left, array $right) {
$order = [AccountType::ASSET, AccountType::REVENUE, AccountType::EXPENSE];
$order = [AccountTypeEnum::ASSET->value, AccountTypeEnum::REVENUE->value, AccountTypeEnum::EXPENSE->value];
$posA = (int) array_search($left['type'], $order, true);
$posB = (int) array_search($right['type'], $order, true);

View File

@@ -27,9 +27,9 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Http\Api\ApiSupport;
@@ -81,11 +81,10 @@ class AccountController extends Controller
$end = $dates['end'];
// user's preferences
$defaultSet = $this->repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray();
$defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
/** @var Preference $frontpage */
$frontpage = app('preferences')->get('frontpageAccounts', $defaultSet);
$default = app('amount')->getDefaultCurrency();
if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) {
$frontpage->data = $defaultSet;
@@ -98,10 +97,8 @@ class AccountController extends Controller
/** @var Account $account */
foreach ($accounts as $account) {
$currency = $this->repository->getAccountCurrency($account);
if (null === $currency) {
$currency = $default;
}
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
$field = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
$currentSet = [
'label' => $account->name,
'currency_id' => (string) $currency->id,
@@ -117,12 +114,11 @@ class AccountController extends Controller
// TODO this code is also present in the V2 chart account controller so this method is due to be deprecated.
$currentStart = clone $start;
$range = app('steam')->finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
// 2022-10-11 this method no longer converts to float.
$previous = array_values($range)[0];
$previous = array_values($range)[0][$field];
while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous;
$balance = array_key_exists($format, $range) ? $range[$format][$field] : $previous;
$previous = $balance;
$currentStart->addDay();
$currentSet['entries'][$label] = $balance;

View File

@@ -28,6 +28,9 @@ use Carbon\Carbon;
use Carbon\Exceptions\InvalidDateException;
use Carbon\Exceptions\InvalidFormatException;
use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
@@ -56,6 +59,7 @@ abstract class Controller extends BaseController
protected array $allowedSort;
protected ParameterBag $parameters;
protected bool $convertToNative = false;
protected TransactionCurrency $defaultCurrency;
/**
* Controller constructor.
@@ -68,8 +72,9 @@ abstract class Controller extends BaseController
function ($request, $next) {
$this->parameters = $this->getParameters();
if (auth()->check()) {
$language = app('steam')->getLanguage();
$this->convertToNative = app('preferences')->get('convert_to_native', false)->data;
$language = Steam::getLanguage();
$this->convertToNative = Amount::convertToNative();
$this->defaultCurrency = Amount::getDefaultCurrency();
app()->setLocale($language);
}

View File

@@ -26,10 +26,10 @@ namespace FireflyIII\Api\V1\Controllers\Data;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DestroyRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
@@ -66,9 +66,9 @@ class DestroyController extends Controller
$objects = $request->getObjects();
$this->unused = $request->boolean('unused', false);
$allExceptAssets = [AccountType::BENEFICIARY, AccountType::CASH, AccountType::CREDITCARD, AccountType::DEFAULT, AccountType::EXPENSE, AccountType::IMPORT, AccountType::INITIAL_BALANCE, AccountType::LIABILITY_CREDIT, AccountType::RECONCILIATION, AccountType::REVENUE];
$all = [AccountType::ASSET, AccountType::BENEFICIARY, AccountType::CASH, AccountType::CREDITCARD, AccountType::DEBT, AccountType::DEFAULT, AccountType::EXPENSE, AccountType::IMPORT, AccountType::INITIAL_BALANCE, AccountType::LIABILITY_CREDIT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::RECONCILIATION];
$liabilities = [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD];
$allExceptAssets = [AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::CASH->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::RECONCILIATION->value, AccountTypeEnum::REVENUE->value];
$all = [AccountTypeEnum::ASSET->value, AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::CASH->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::RECONCILIATION->value];
$liabilities = [AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::CREDITCARD->value];
$transactions = [TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::TRANSFER->value, TransactionTypeEnum::RECONCILIATION->value];
match ($objects) {
@@ -82,9 +82,9 @@ class DestroyController extends Controller
'object_groups' => $this->destroyObjectGroups(),
'not_assets_liabilities' => $this->destroyAccounts($allExceptAssets),
'accounts' => $this->destroyAccounts($all),
'asset_accounts' => $this->destroyAccounts([AccountType::ASSET, AccountType::DEFAULT]),
'expense_accounts' => $this->destroyAccounts([AccountType::BENEFICIARY, AccountType::EXPENSE]),
'revenue_accounts' => $this->destroyAccounts([AccountType::REVENUE]),
'asset_accounts' => $this->destroyAccounts([AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]),
'expense_accounts' => $this->destroyAccounts([AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::EXPENSE->value]),
'revenue_accounts' => $this->destroyAccounts([AccountTypeEnum::REVENUE->value]),
'liabilities' => $this->destroyAccounts($liabilities),
'transactions' => $this->destroyTransactions($transactions),
'withdrawals' => $this->destroyTransactions([TransactionTypeEnum::WITHDRAWAL->value]),

View File

@@ -29,7 +29,9 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class BillController
@@ -63,11 +65,13 @@ class BillController extends Controller
*/
public function bill(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$bills = $request->getBills();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$accounts = $request->getAssetAccounts();
$bills = $request->getBills();
$start = $request->getStart();
$end = $request->getEnd();
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$response = [];
// get all bills:
if (0 === $bills->count()) {
@@ -75,17 +79,30 @@ class BillController extends Controller
}
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
$collector->setBills($bills);
$genericSet = $collector->getExtractedJournals();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$billId = (int) $journal['bill_id'];
$currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
$key = sprintf('%d-%d', $billId, $currencyId);
$foreignKey = sprintf('%d-%d', $billId, $foreignCurrencyId);
$billId = (int) $journal['bill_id'];
$currencyId = (int) $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$field = 'amount';
// use the native amount if the user wants to convert to native currency
if ($convertToNative && $currencyId !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
$field = 'native_amount';
}
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
Log::debug(sprintf('Journal #%d in bill #%d will use %s (%s %s)', $journal['transaction_group_id'], $billId, $field, $currencyCode, $journal[$field] ?? '0'));
$key = sprintf('%d-%d', $billId, $currencyId);
if (0 !== $currencyId) {
$response[$key] ??= [
@@ -94,21 +111,11 @@ class BillController extends Controller
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'],
'currency_code' => $currencyCode,
];
$response[$key]['difference'] = bcadd($response[$key]['difference'], $journal['amount']);
$response[$key]['difference'] = bcadd($response[$key]['difference'], (string) ($journal[$field] ?? '0'));
$response[$key]['difference_float'] = (float) $response[$key]['difference']; // intentional float
}
if (0 !== $foreignCurrencyId) {
$response[$foreignKey] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignKey]['difference'] = bcadd($response[$foreignKey]['difference'], $journal['foreign_amount']);
$response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // intentional float
}
}
return response()->json(array_values($response));
@@ -122,42 +129,47 @@ class BillController extends Controller
*/
public function noBill(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
$response = [];
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
$collector->withoutBill();
$genericSet = $collector->getExtractedJournals();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
$currencyId = (int) $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$field = 'amount';
// use the native amount if the user wants to convert to native currency
if ($convertToNative && $currencyId !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
$field = 'native_amount';
}
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
Log::debug(sprintf('Journal #%d will use %s (%s %s)', $journal['transaction_group_id'], $field, $currencyCode, $journal[$field] ?? '0'));
if (0 !== $currencyId) {
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'],
'currency_code' => $currencyCode,
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $journal['amount']);
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], (string) ($journal[$field] ?? '0'));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // intentional float
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
$response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference']; // intentional float
}
}
return response()->json(array_values($response));

View File

@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class PeriodController
@@ -41,39 +43,49 @@ class PeriodController extends Controller
*/
public function total(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
$genericSet = $collector->getExtractedJournals();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
// same code as many other sumExpense methods. I think this needs some kind of generic method.
$amount = '0';
$currencyId = (int) $journal['currency_id'];
$currencyCode = $journal['currency_code'];
if ($convertToNative) {
$amount = Amount::getAmountFromJournal($journal);
if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
if ($default->id !== (int) $journal['currency_id'] && $default->id === (int) $journal['foreign_currency_id']) {
$currencyId = $journal['foreign_currency_id'];
$currencyCode = $journal['foreign_currency_code'];
}
Log::debug(sprintf('[a] Add amount %s %s', $currencyCode, $amount));
}
if (!$convertToNative) {
// ignore the amount in foreign currency.
Log::debug(sprintf('[b] Add amount %s %s', $currencyCode, $journal['amount']));
$amount = $journal['amount'];
}
if (0 !== $currencyId) {
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $journal['amount']);
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // intentional float
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
$response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference']; // intentional float
}
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode,
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $amount);
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // intentional float
}
return response()->json(array_values($response));

View File

@@ -29,7 +29,9 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class TagController
@@ -62,42 +64,51 @@ class TagController extends Controller
*/
public function noTag(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
$collector->withoutTags();
$genericSet = $collector->getExtractedJournals();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
// same code as many other sumExpense methods. I think this needs some kind of generic method.
$amount = '0';
$currencyId = (int) $journal['currency_id'];
$currencyCode = $journal['currency_code'];
if ($convertToNative) {
$amount = Amount::getAmountFromJournal($journal);
if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
if ($default->id !== (int) $journal['currency_id'] && $default->id === (int) $journal['foreign_currency_id']) {
$currencyId = $journal['foreign_currency_id'];
$currencyCode = $journal['foreign_currency_code'];
}
Log::debug(sprintf('[a] Add amount %s %s', $currencyCode, $amount));
}
if (!$convertToNative) {
// ignore the amount in foreign currency.
Log::debug(sprintf('[b] Add amount %s %s', $currencyCode, $journal['amount']));
$amount = $journal['amount'];
}
if (0 !== $currencyId) {
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $journal['amount']);
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
$response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference']; // float but on purpose.
}
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode,
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], $amount);
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
}
return response()->json(array_values($response));

View File

@@ -73,6 +73,7 @@ class AccountController extends Controller
$start = $request->getStart();
$end = $request->getEnd();
$assetAccounts = $request->getAssetAccounts();
$income = $this->opsRepository->sumIncomeByDestination($start, $end, $assetAccounts);
$result = [];

View File

@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse;
/**
@@ -41,42 +42,41 @@ class PeriodController extends Controller
*/
public function total(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts);
$genericSet = $collector->getExtractedJournals();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
// currency
$currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
if (0 !== $currencyId) {
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
// perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'],
app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference']; // float but on purpose.
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode,
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
}
return response()->json(array_values($response));

View File

@@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse;
/**
@@ -63,45 +64,45 @@ class TagController extends Controller
*/
public function noTag(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->withoutTags();
$genericSet = $collector->getExtractedJournals();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
// currency
$currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
if (0 !== $currencyId) {
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
// perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'],
app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference'];
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode,
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
}
return response()->json(array_values($response));

View File

@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse;
/**
@@ -41,42 +42,42 @@ class PeriodController extends Controller
*/
public function total(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type)
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
$genericSet = $collector->getExtractedJournals();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
// currency
$currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
if (0 !== $currencyId) {
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
// perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'],
app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference'];
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode,
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
}
return response()->json(array_values($response));

View File

@@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse;
/**
@@ -61,45 +62,46 @@ class TagController extends Controller
*/
public function noTag(GenericRequest $request): JsonResponse
{
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$accounts = $request->getAssetAccounts();
$start = $request->getStart();
$end = $request->getEnd();
$response = [];
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// collect all expenses in this period (regardless of type) by the given bills and accounts.
$collector = app(GroupCollectorInterface::class);
$collector = app(GroupCollectorInterface::class);
$collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
$collector->withoutTags();
$genericSet = $collector->getExtractedJournals();
$genericSet = $collector->getExtractedJournals();
foreach ($genericSet as $journal) {
$currencyId = (int) $journal['currency_id'];
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
// currency
$currencyId = $journal['currency_id'];
$currencyCode = $journal['currency_code'];
$field = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
if (0 !== $currencyId) {
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'],
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
// perhaps use default currency instead?
if ($convertToNative && $journal['currency_id'] !== $default->id) {
$currencyId = $default->id;
$currencyCode = $default->code;
}
if (0 !== $foreignCurrencyId) {
$response[$foreignCurrencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'],
];
$response[$foreignCurrencyId]['difference'] = bcadd(
$response[$foreignCurrencyId]['difference'],
app('steam')->positive($journal['foreign_amount'])
);
$response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference'];
// use foreign amount when the foreign currency IS the default currency.
if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
$field = 'foreign_amount';
}
$response[$currencyId] ??= [
'difference' => '0',
'difference_float' => 0,
'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode,
];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
}
return response()->json(array_values($response));

View File

@@ -105,19 +105,18 @@ class ShowController extends Controller
public function show(TransactionCurrency $currency): JsonResponse
{
/** @var User $user */
$user = auth()->user();
$manager = $this->getManager();
$defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$this->parameters->set('defaultCurrency', $defaultCurrency);
$user = auth()->user();
$manager = $this->getManager();
$this->parameters->set('defaultCurrency', $this->defaultCurrency);
// update fields with user info.
$currency->refreshForUser($user);
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');
$resource = new Item($currency, $transformer, 'currencies');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
@@ -135,7 +134,7 @@ class ShowController extends Controller
/** @var User $user */
$user = auth()->user();
$manager = $this->getManager();
$currency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$currency = $this->defaultCurrency;
// update fields with user info.
$currency->refreshForUser($user);

View File

@@ -103,10 +103,10 @@ class BasicController extends Controller
$billData = $this->getBillInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($start, $end);
// $balanceData = [];
// $billData = [];
// $spentData = [];
// $netWorthData = [];
// $balanceData = [];
// $billData = [];
// $spentData = [];
// $netWorthData = [];
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
// give new keys
@@ -123,8 +123,8 @@ class BasicController extends Controller
private function getBalanceInformation(Carbon $start, Carbon $end): array
{
// some config settings
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
$default = app('amount')->getDefaultCurrency();
$convertToNative = Amount::convertToNative();
$default = Amount::getDefaultCurrency();
// prep some arrays:
$incomes = [];
$expenses = [];
@@ -276,13 +276,13 @@ class BasicController extends Controller
*/
private function getLeftToSpendInfo(Carbon $start, Carbon $end): array
{
Log::debug(sprintf('Now in getLeftToSpendInfo("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$return = [];
$today = today(config('app.timezone'));
$available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
$budgets = $this->budgetRepository->getActiveBudgets();
$spent = $this->opsRepository->sumExpenses($start, $end, null, $budgets);
$days = (int) $today->diffInDays($end, true) + 1;
Log::debug(sprintf('Now in getLeftToSpendInfo("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
foreach ($spent as $row) {
// either an amount was budgeted or 0 is available.

View File

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

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Request\Chart;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Support\Http\Api\ParsesQueryFilters;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
@@ -40,7 +39,6 @@ class ChartRequest extends FormRequest
{
use ChecksLogin;
use ConvertsDataTypes;
use ParsesQueryFilters;
use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];

View File

@@ -74,7 +74,7 @@ class CorrectsDatabase extends Command
'correction:recalculates-liabilities',
'correction:preferences',
// 'correction:transaction-types', // resource heavy, disabled.
// 'correction:recalculate-native-amounts', // not necessary, disabled.
'correction:recalculate-native-amounts', // not necessary, disabled.
'firefly-iii:report-integrity',
];
foreach ($commands as $command) {

View File

@@ -59,6 +59,11 @@ class CorrectsNativeAmounts extends Command
*/
public function handle(): int
{
if (!config('cer.enabled')) {
$this->friendlyInfo('This command will not run because currency exchange rates are disabled.');
return 0;
}
Log::debug('Will update all native amounts. This may take some time.');
$this->friendlyWarning('Recalculating native amounts for all objects. This may take some time!');
@@ -124,8 +129,8 @@ class CorrectsNativeAmounts extends Command
foreach ($piggyBank->accounts as $account) {
$account->pivot->native_current_amount = null;
if (0 !== bccomp($account->pivot->current_amount, '0')) {
$account->pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $currency, today(), $account->pivot->current_amount);
if (0 !== bccomp((string) $account->pivot->current_amount, '0')) {
$account->pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $currency, today(), (string) $account->pivot->current_amount);
}
$account->pivot->save();
}

View File

@@ -45,7 +45,6 @@ class ReportsIntegrity extends Command
return 1;
}
$commands = [
// 'firefly-iii:add-timezones-to-dates',
'integrity:empty-objects',
'integrity:total-sums',
];

View File

@@ -76,9 +76,6 @@ class AddsTransactionIdentifiers extends Command
$this->updateJournalIdentifiers($journal);
}
if (0 === $this->count) {
$this->friendlyPositive('All split journal transaction identifiers are OK.');
}
if (0 !== $this->count) {
$this->friendlyInfo(sprintf('Fixed %d split journal transaction identifier(s).', $this->count));
}

View File

@@ -70,7 +70,6 @@ class RemovesDatabaseDecryption extends Command
private function decryptTable(string $table, array $fields): void
{
if ($this->isDecrypted($table)) {
$this->friendlyInfo(sprintf('No decryption required for table "%s".', $table));
return;
}

View File

@@ -62,9 +62,6 @@ class UpgradesAccountCurrencies extends Command
}
$this->updateAccountCurrencies();
if (0 === $this->count) {
$this->friendlyPositive('All account currencies are OK.');
}
if (0 !== $this->count) {
$this->friendlyInfo(sprintf('Corrected %d account(s).', $this->count));
}

View File

@@ -73,9 +73,6 @@ class UpgradesAccountMetaData extends Command
$this->markAsExecuted();
if (0 === $count) {
$this->friendlyPositive('All account meta is OK.');
}
if (0 !== $count) {
$this->friendlyInfo(sprintf('Renamed %d account meta entries (entry).', $count));
}

View File

@@ -79,9 +79,6 @@ class UpgradesAttachments extends Command
++$count;
}
}
if (0 === $count) {
$this->friendlyPositive('All attachments are OK.');
}
if (0 !== $count) {
$this->friendlyInfo(sprintf('Updated %d attachment(s).', $count));
}

View File

@@ -73,9 +73,6 @@ class UpgradesBillsToRules extends Command
$this->migrateUser($user);
}
if (0 === $this->count) {
$this->friendlyPositive('All bills are OK.');
}
if (0 !== $this->count) {
$this->friendlyInfo(sprintf('Verified and fixed %d bill(s).', $this->count));
}

View File

@@ -77,9 +77,6 @@ class UpgradesBudgetLimits extends Command
}
}
}
if (0 === $count) {
$this->friendlyPositive('All budget limits are OK.');
}
$this->markAsExecuted();
return 0;

View File

@@ -55,7 +55,6 @@ class UpgradesCreditCardLiabilities extends Command
$ccType = AccountType::where('type', AccountType::CREDITCARD)->first();
$debtType = AccountType::where('type', AccountType::DEBT)->first();
if (null === $ccType || null === $debtType) {
$this->friendlyPositive('No incorrectly stored credit card liabilities.');
$this->markAsExecuted();
return 0;
@@ -73,9 +72,6 @@ class UpgradesCreditCardLiabilities extends Command
'Credit card liability types are no longer supported and have been converted to generic debts. See: https://bit.ly/FF3-credit-cards'
);
}
if (0 === $accounts->count()) {
$this->friendlyPositive('No incorrectly stored credit card liabilities.');
}
$this->markAsExecuted();
return 0;

View File

@@ -57,7 +57,6 @@ class UpgradesDatabase extends Command
'upgrade:480-account-meta',
'upgrade:481-recurrence-meta',
'upgrade:500-tag-locations',
'upgrade:550-recurrence-type',
'upgrade:560-liabilities',
'upgrade:600-liabilities',
'upgrade:550-budget-limit-periods',

View File

@@ -68,7 +68,7 @@ class UpgradesJournalMetaData extends Command
private function isMigrated(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
$configVar = app('fireflyconfig')->get(UpgradesToGroups::CONFIG_NAME, false);
return (bool) $configVar->data;
}

View File

@@ -72,9 +72,6 @@ class UpgradesJournalNotes extends Command
++$count;
}
if (0 === $count) {
$this->friendlyPositive('No notes to migrate.');
}
if (0 !== $count) {
$this->friendlyInfo(sprintf('Migrated %d note(s).', $count));
}

View File

@@ -52,9 +52,6 @@ class UpgradesRecurrenceMetaData extends Command
}
$count = $this->migrateMetaData();
if (0 === $count) {
$this->friendlyPositive('No recurrence meta data migrated.');
}
if ($count > 0) {
$this->friendlyInfo(sprintf('Migrated %d meta data entries', $count));
}

View File

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

View File

@@ -72,9 +72,6 @@ class UpgradesToGroups extends Command
if (0 !== $this->count) {
$this->friendlyInfo(sprintf('Migrated %d transaction journal(s).', $this->count));
}
if (0 === $this->count) {
$this->friendlyPositive('No journals to migrate to groups.');
}
$this->markAsMigrated();
return 0;
@@ -363,9 +360,6 @@ class UpgradesToGroups extends Command
$this->giveGroup($array);
}
}
if (0 === $total) {
$this->friendlyPositive('No need to convert transaction journals.');
}
}
private function giveGroup(array $array): void

View File

@@ -68,15 +68,10 @@ class UpgradesTransferCurrencies extends Command
$this->startUpdateRoutine();
$this->markAsExecuted();
if (0 === $this->count) {
$this->friendlyPositive('All transfers have correct currency information.');
return 0;
if ($this->count > 0) {
$this->friendlyInfo(sprintf('Verified currency information of %d transfer(s).', $this->count));
}
$this->friendlyInfo(sprintf('Verified currency information of %d transfer(s).', $this->count));
return 0;
}

View File

@@ -36,8 +36,6 @@ use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException as LaravelValidationException;
use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException;
use LaravelJsonApi\Core\Exceptions\JsonApiException;
use LaravelJsonApi\Exceptions\ExceptionParser;
use League\OAuth2\Server\Exception\OAuthServerException;
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
use Symfony\Component\HttpFoundation\Response;
@@ -65,18 +63,12 @@ class Handler extends ExceptionHandler
HttpException::class,
SuspiciousOperationException::class,
BadHttpHeaderException::class,
JsonApiException::class,
];
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->renderable(
ExceptionParser::make()->renderable()
);
}
public function register(): void {}
/**
* Render an exception into an HTTP response. It's complex but lucky for us, we never use it because

View File

@@ -43,11 +43,11 @@ class PiggyBankFactory
public User $user {
set(User $value) {
$this->user = $value;
$this->currencyRepository->setUser($value);
$this->accountRepository->setUser($value);
$this->piggyBankRepository->setUser($value);
}
$this->user = $value;
$this->currencyRepository->setUser($value);
$this->accountRepository->setUser($value);
$this->piggyBankRepository->setUser($value);
}
}
private AccountRepositoryInterface $accountRepository;
private CurrencyRepositoryInterface $currencyRepository;
@@ -62,15 +62,11 @@ class PiggyBankFactory
/**
* Store a piggy bank or come back with an exception.
*
* @param array $data
*
* @return PiggyBank
*/
public function store(array $data): PiggyBank
{
$piggyBankData = $data;
$piggyBankData = $data;
// unset some fields
unset($piggyBankData['object_group_title'], $piggyBankData['transaction_currency_code'], $piggyBankData['transaction_currency_id'], $piggyBankData['accounts'], $piggyBankData['object_group_id'], $piggyBankData['notes']);
@@ -94,11 +90,11 @@ class PiggyBankFactory
throw new FireflyException('400005: Could not store new piggy bank.', 0, $e);
}
$piggyBank = $this->setOrder($piggyBank, $data);
$piggyBank = $this->setOrder($piggyBank, $data);
$this->linkToAccountIds($piggyBank, $data['accounts']);
$this->piggyBankRepository->updateNote($piggyBank, $data['notes']);
$objectGroupTitle = $data['object_group_title'] ?? '';
$objectGroupTitle = $data['object_group_title'] ?? '';
if ('' !== $objectGroupTitle) {
$objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle);
if (null !== $objectGroup) {
@@ -106,7 +102,7 @@ class PiggyBankFactory
}
}
// try also with ID
$objectGroupId = (int) ($data['object_group_id'] ?? 0);
$objectGroupId = (int) ($data['object_group_id'] ?? 0);
if (0 !== $objectGroupId) {
$objectGroup = $this->findObjectGroupById($objectGroupId);
if (null !== $objectGroup) {
@@ -114,9 +110,10 @@ class PiggyBankFactory
}
}
Log::debug('Touch piggy bank');
$piggyBank->encrypted = false;
$piggyBank->encrypted = false;
$piggyBank->save();
$piggyBank->touch();
return $piggyBank;
}
@@ -132,6 +129,7 @@ class PiggyBankFactory
$currency = $this->currencyRepository->find((int) ($data['transaction_currency_id'] ?? 0));
}
$currency ??= $defaultCurrency;
return $currency;
}
@@ -144,12 +142,12 @@ class PiggyBankFactory
}
// first find by ID:
if ($piggyBankId > 0) {
$piggyBank = PiggyBank
::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
$piggyBank = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->where('piggy_banks.id', $piggyBankId)
->first(['piggy_banks.*']);
->first(['piggy_banks.*'])
;
if (null !== $piggyBank) {
return $piggyBank;
}
@@ -169,23 +167,24 @@ class PiggyBankFactory
public function findByName(string $name): ?PiggyBank
{
return PiggyBank
::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->where('piggy_banks.name', $name)
->first(['piggy_banks.*']);
->first(['piggy_banks.*'])
;
}
private function setOrder(PiggyBank $piggyBank, array $data): PiggyBank
{
$this->resetOrder();
$order = $this->getMaxOrder() + 1;
$order = $this->getMaxOrder() + 1;
if (array_key_exists('order', $data)) {
$order = $data['order'];
}
$piggyBank->order = $order;
$piggyBank->saveQuietly();
return $piggyBank;
}
@@ -193,8 +192,7 @@ class PiggyBankFactory
public function resetOrder(): void
{
// TODO duplicate code
$set = PiggyBank
::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
$set = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id')
->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id')
->where('accounts.user_id', $this->user->id)
->with(
@@ -202,7 +200,8 @@ class PiggyBankFactory
'objectGroups',
]
)
->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']);
->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*'])
;
$current = 1;
foreach ($set as $piggyBank) {
if ($piggyBank->order !== $current) {
@@ -214,7 +213,6 @@ class PiggyBankFactory
}
}
private function getMaxOrder(): int
{
return (int) $this->piggyBankRepository->getPiggyBanks()->max('order');
@@ -231,8 +229,8 @@ class PiggyBankFactory
foreach ($accounts as $info) {
if ($account->id === $info['account_id']) {
if (array_key_exists($account->id, $accounts)) {
$toBeLinked[$account->id] = ['current_amount' => $account->pivot->current_amount ?? '0'];
Log::debug(sprintf('Prefilled for account #%d with amount %s', $account->id, $account->pivot->current_amount ?? '0'));
$toBeLinked[$account->id] = ['current_amount' => $account->pivot?->current_amount ?? '0'];
Log::debug(sprintf('Prefilled for account #%d with amount %s', $account->id, $account->pivot?->current_amount ?? '0'));
}
}
}
@@ -247,7 +245,7 @@ class PiggyBankFactory
}
if (array_key_exists('current_amount', $info)) {
$toBeLinked[$account->id] = ['current_amount' => $info['current_amount']];
Log::debug(sprintf('Will link account #%d with amount %s', $account->id, $account->pivot->current_amount));
Log::debug(sprintf('Will link account #%d with amount %s', $account->id, $account->pivot?->current_amount ?? '0'));
}
if (!array_key_exists('current_amount', $info)) {
$toBeLinked[$account->id] ??= [];

View File

@@ -32,6 +32,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\User;
use Illuminate\Support\Facades\Log;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Spatie\Period\Boundaries;
@@ -45,20 +46,20 @@ class BudgetLimitHandler
{
public function created(Created $event): void
{
app('log')->debug(sprintf('BudgetLimitHandler::created(#%s)', $event->budgetLimit->id));
Log::debug(sprintf('BudgetLimitHandler::created(#%s)', $event->budgetLimit->id));
$this->updateAvailableBudget($event->budgetLimit);
}
private function updateAvailableBudget(BudgetLimit $budgetLimit): void
{
app('log')->debug(sprintf('Now in updateAvailableBudget(#%d)', $budgetLimit->id));
Log::debug(sprintf('Now in updateAvailableBudget(limit #%d)', $budgetLimit->id));
$budget = Budget::find($budgetLimit->budget_id);
if (null === $budget) {
app('log')->warning('Budget is null, probably deleted, find deleted version.');
Log::warning('Budget is null, probably deleted, find deleted version.');
$budget = Budget::withTrashed()->find($budgetLimit->budget_id);
}
if (null === $budget) {
app('log')->warning('Budget is still null, cannot continue, will delete budget limit.');
Log::warning('Budget is still null, cannot continue, will delete budget limit.');
$budgetLimit->forceDelete();
return;
@@ -69,7 +70,7 @@ class BudgetLimitHandler
// sanity check. It happens when the budget has been deleted so the original user is unknown.
if (null === $user) {
app('log')->warning('User is null, cannot continue.');
Log::warning('User is null, cannot continue.');
$budgetLimit->forceDelete();
return;
@@ -82,7 +83,7 @@ class BudgetLimitHandler
try {
$viewRange = app('preferences')->getForUser($user, 'viewRange', '1M')->data;
} catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) {
app('log')->error($e->getMessage());
Log::error($e->getMessage());
$viewRange = '1M';
}
// safety catch
@@ -97,7 +98,7 @@ class BudgetLimitHandler
// limit period in total is:
$limitPeriod = Period::make($start, $end, precision: Precision::DAY(), boundaries: Boundaries::EXCLUDE_NONE());
app('log')->debug(sprintf('Limit period is from %s to %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
Log::debug(sprintf('Limit period is from %s to %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
// from the start until the end of the budget limit, need to loop!
$current = clone $start;
@@ -106,16 +107,14 @@ class BudgetLimitHandler
// create or find AB for this particular period, and set the amount accordingly.
/** @var null|AvailableBudget $availableBudget */
$availableBudget = $user->availableBudgets()->where('start_date', $current->format('Y-m-d'))->where(
'end_date',
$currentEnd->format('Y-m-d')
)->where('transaction_currency_id', $budgetLimit->transaction_currency_id)->first();
$availableBudget = $user->availableBudgets()->where('start_date', $current->format('Y-m-d'))->where('end_date', $currentEnd->format('Y-m-d'))->where('transaction_currency_id', $budgetLimit->transaction_currency_id)->first();
if (null !== $availableBudget) {
app('log')->debug('Found 1 AB, will update.');
Log::debug('Found 1 AB, will update.');
$this->calculateAmount($availableBudget);
}
if (null === $availableBudget) {
Log::debug('No AB found, will create.');
// if not exists:
$currentPeriod = Period::make($current, $currentEnd, precision: Precision::DAY(), boundaries: Boundaries::EXCLUDE_NONE());
$daily = $this->getDailyAmount($budgetLimit);
@@ -126,10 +125,10 @@ class BudgetLimitHandler
$amount = 0 === $budgetLimit->id ? '0' : $budgetLimit->amount;
}
if (0 === bccomp($amount, '0')) {
app('log')->debug('Amount is zero, will not create AB.');
Log::debug('Amount is zero, will not create AB.');
}
if (0 !== bccomp($amount, '0')) {
app('log')->debug(sprintf('Will create AB for period %s to %s', $current->format('Y-m-d'), $currentEnd->format('Y-m-d')));
Log::debug(sprintf('Will create AB for period %s to %s', $current->format('Y-m-d'), $currentEnd->format('Y-m-d')));
$availableBudget = new AvailableBudget(
[
'user_id' => $user->id,
@@ -143,7 +142,8 @@ class BudgetLimitHandler
]
);
$availableBudget->save();
app('log')->debug(sprintf('ID of new AB is #%d', $availableBudget->id));
Log::debug(sprintf('ID of new AB is #%d', $availableBudget->id));
$this->calculateAmount($availableBudget);
}
}
@@ -158,7 +158,7 @@ class BudgetLimitHandler
$repository->setUser($availableBudget->user);
$newAmount = '0';
$abPeriod = Period::make($availableBudget->start_date, $availableBudget->end_date, Precision::DAY());
app('log')->debug(
Log::debug(
sprintf(
'Now at AB #%d, ("%s" to "%s")',
$availableBudget->id,
@@ -168,11 +168,11 @@ class BudgetLimitHandler
);
// have to recalculate everything just in case.
$set = $repository->getAllBudgetLimitsByCurrency($availableBudget->transactionCurrency, $availableBudget->start_date, $availableBudget->end_date);
app('log')->debug(sprintf('Found %d interesting budget limit(s).', $set->count()));
Log::debug(sprintf('Found %d interesting budget limit(s).', $set->count()));
/** @var BudgetLimit $budgetLimit */
foreach ($set as $budgetLimit) {
app('log')->debug(
Log::debug(
sprintf(
'Found interesting budget limit #%d ("%s" to "%s")',
$budgetLimit->id,
@@ -189,16 +189,16 @@ class BudgetLimitHandler
);
// if both equal each other, amount from this BL must be added to the AB
if ($limitPeriod->equals($abPeriod)) {
app('log')->debug('This budget limit is equal to the available budget period.');
Log::debug('This budget limit is equal to the available budget period.');
$newAmount = bcadd($newAmount, $budgetLimit->amount);
}
// if budget limit period is inside AB period, it can be added in full.
if (!$limitPeriod->equals($abPeriod) && $abPeriod->contains($limitPeriod)) {
app('log')->debug('This budget limit is smaller than the available budget period.');
Log::debug('This budget limit is smaller than the available budget period.');
$newAmount = bcadd($newAmount, $budgetLimit->amount);
}
if (!$limitPeriod->equals($abPeriod) && !$abPeriod->contains($limitPeriod) && $abPeriod->overlapsWith($limitPeriod)) {
app('log')->debug('This budget limit is something else entirely!');
Log::debug('This budget limit is something else entirely!');
$overlap = $abPeriod->overlap($limitPeriod);
if (null !== $overlap) {
$length = $overlap->length();
@@ -208,12 +208,12 @@ class BudgetLimitHandler
}
}
if (0 === bccomp('0', $newAmount)) {
app('log')->debug('New amount is zero, deleting AB.');
Log::debug('New amount is zero, deleting AB.');
$availableBudget->delete();
return;
}
app('log')->debug(sprintf('Concluded new amount for this AB must be %s', $newAmount));
Log::debug(sprintf('Concluded new amount for this AB must be %s', $newAmount));
$availableBudget->amount = app('steam')->bcround($newAmount, $availableBudget->transactionCurrency->decimal_places);
$availableBudget->save();
}
@@ -231,7 +231,7 @@ class BudgetLimitHandler
);
$days = $limitPeriod->length();
$amount = bcdiv($budgetLimit->amount, (string) $days, 12);
app('log')->debug(
Log::debug(
sprintf('Total amount for budget limit #%d is %s. Nr. of days is %d. Amount per day is %s', $budgetLimit->id, $budgetLimit->amount, $days, $amount)
);
@@ -240,7 +240,7 @@ class BudgetLimitHandler
public function deleted(Deleted $event): void
{
app('log')->debug(sprintf('BudgetLimitHandler::deleted(#%s)', $event->budgetLimit->id));
Log::debug(sprintf('BudgetLimitHandler::deleted(#%s)', $event->budgetLimit->id));
$budgetLimit = $event->budgetLimit;
$budgetLimit->id = 0;
$this->updateAvailableBudget($event->budgetLimit);
@@ -248,7 +248,7 @@ class BudgetLimitHandler
public function updated(Updated $event): void
{
app('log')->debug(sprintf('BudgetLimitHandler::updated(#%s)', $event->budgetLimit->id));
Log::debug(sprintf('BudgetLimitHandler::updated(#%s)', $event->budgetLimit->id));
$this->updateAvailableBudget($event->budgetLimit);
}
}

View File

@@ -30,7 +30,9 @@ use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroups\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\UserGroups\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
@@ -57,6 +59,10 @@ class PreferencesEventHandler
$this->resetPiggyBanks($event->userGroup);
$this->resetBudgets($event->userGroup);
$this->resetTransactions($event->userGroup);
// fire laravel command to recalculate them all.
if (Amount::convertToNative()) {
Artisan::call('correction:recalculate-native-amounts');
}
}
private function resetPiggyBanks(UserGroup $userGroup): void
@@ -130,6 +136,6 @@ class PreferencesEventHandler
})
->update(['native_amount' => null, 'native_foreign_amount' => null])
;
Log::debug(sprintf('Updated %d transactions.', $success));
Log::debug(sprintf('Reset %d transactions.', $success));
}
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\Log;
@@ -43,6 +44,9 @@ class AccountObserver
private function updateNativeAmount(Account $account): void
{
if (!Amount::convertToNative($account->user)) {
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup);
$repository = app(AccountRepositoryInterface::class);
$currency = $repository->getAccountCurrency($account);

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\AutoBudget;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\Log;
@@ -44,6 +45,9 @@ class AutoBudgetObserver
private function updateNativeAmount(AutoBudget $autoBudget): void
{
if (!Amount::convertToNative($autoBudget->budget->user)) {
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($autoBudget->budget->user->userGroup);
$autoBudget->native_amount = null;
if ($autoBudget->transactionCurrency->id !== $userCurrency->id) {

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\Log;
@@ -32,18 +33,23 @@ class AvailableBudgetObserver
{
public function created(AvailableBudget $availableBudget): void
{
Log::debug('Observe "created" of an available budget.');
// Log::debug('Observe "created" of an available budget.');
$this->updateNativeAmount($availableBudget);
}
public function updated(AvailableBudget $availableBudget): void
{
Log::debug('Observe "updated" of an available budget.');
// Log::debug('Observe "updated" of an available budget.');
$this->updateNativeAmount($availableBudget);
}
private function updateNativeAmount(AvailableBudget $availableBudget): void
{
if (!Amount::convertToNative($availableBudget->user)) {
// Log::debug('Do not update native available amount of the available budget.');
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($availableBudget->user->userGroup);
$availableBudget->native_amount = null;
if ($availableBudget->transactionCurrency->id !== $userCurrency->id) {

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Bill;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\Log;
@@ -55,6 +56,9 @@ class BillObserver
private function updateNativeAmount(Bill $bill): void
{
if (!Amount::convertToNative($bill->user)) {
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($bill->user->userGroup);
$bill->native_amount_min = null;
$bill->native_amount_max = null;

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\Log;
@@ -44,6 +45,11 @@ class BudgetLimitObserver
private function updateNativeAmount(BudgetLimit $budgetLimit): void
{
if (!Amount::convertToNative($budgetLimit->budget->user)) {
// Log::debug('Do not update native amount of the budget limit.');
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($budgetLimit->budget->user->userGroup);
$budgetLimit->native_amount = null;
if ($budgetLimit->transactionCurrency->id !== $userCurrency->id) {

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\Log;
@@ -44,6 +45,9 @@ class PiggyBankEventObserver
private function updateNativeAmount(PiggyBankEvent $event): void
{
if (!Amount::convertToNative($event->piggyBank->accounts()->first()->user)) {
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($event->piggyBank->accounts()->first()->user->userGroup);
$event->native_amount = null;
if ($event->piggyBank->transactionCurrency->id !== $userCurrency->id) {

View File

@@ -78,6 +78,7 @@ class PiggyBankObserver
if ($piggyBank->transactionCurrency->id !== $userCurrency->id) {
$converter = new ExchangeRateConverter();
$converter->setIgnoreSettings(true);
$converter->setUserGroup($group);
$piggyBank->native_target_amount = $converter->convert($piggyBank->transactionCurrency, $userCurrency, today(), $piggyBank->target_amount);
}
$piggyBank->saveQuietly();

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Transaction;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Models\AccountBalanceCalculator;
use Illuminate\Support\Facades\Log;
@@ -55,7 +56,7 @@ class TransactionObserver
public function updated(Transaction $transaction): void
{
Log::debug('Observe "updated" of a transaction.');
// Log::debug('Observe "updated" of a transaction.');
if (config('firefly.feature_flags.running_balance_column') && self::$recalculate) {
if (1 === bccomp($transaction->amount, '0')) {
Log::debug('Trigger recalculateForJournal');
@@ -67,6 +68,9 @@ class TransactionObserver
private function updateNativeAmount(Transaction $transaction): void
{
if (!Amount::convertToNative($transaction->transactionJournal->user)) {
return;
}
$userCurrency = app('amount')->getDefaultCurrencyByUserGroup($transaction->transactionJournal->user->userGroup);
$transaction->native_amount = null;
$transaction->native_foreign_amount = null;

View File

@@ -66,7 +66,7 @@ class NetWorth implements NetWorthInterface
public function byAccounts(Collection $accounts, Carbon $date): array
{
// start in the past, end in the future? use $date
$convertToNative = app('preferences')->get('convert_to_native', false)->data;
$convertToNative = Amount::convertToNative();
$ids = implode(',', $accounts->pluck('id')->toArray());
$cache = new CacheProperties();
$cache->addProperty($date);
@@ -74,7 +74,7 @@ class NetWorth implements NetWorthInterface
$cache->addProperty('net-worth-by-accounts');
$cache->addProperty($ids);
if ($cache->has()) {
// return $cache->get();
return $cache->get();
}
Log::debug(sprintf('Now in byAccounts("%s", "%s")', $ids, $date->format('Y-m-d H:i:s')));
$default = Amount::getDefaultCurrency();

View File

@@ -76,7 +76,6 @@ class CreateController extends Controller
*/
public function create(Request $request, string $objectType)
{
$defaultCurrency = app('amount')->getDefaultCurrency();
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
$subTitle = (string) trans(sprintf('firefly.make_new_%s_account', $objectType));
$roles = $this->getRoles();
@@ -106,7 +105,7 @@ class CreateController extends Controller
$request->session()->flash(
'preFilled',
[
'currency_id' => $defaultCurrency->id,
'currency_id' => $this->defaultCurrency->id,
'include_net_worth' => $hasOldInput ? (bool) $request->old('include_net_worth') : true,
]
);

View File

@@ -90,6 +90,7 @@ class EditController extends Controller
$latitude = null !== $location ? $location->latitude : config('firefly.default_location.latitude');
$longitude = null !== $location ? $location->longitude : config('firefly.default_location.longitude');
$zoomLevel = null !== $location ? $location->zoom_level : config('firefly.default_location.zoom_level');
$canEditCurrency = 0 === $account->piggyBanks()->count();
$hasLocation = null !== $location;
$locations = [
'location' => [
@@ -123,7 +124,7 @@ class EditController extends Controller
$openingBalanceAmount = '';
}
$openingBalanceDate = $repository->getOpeningBalanceDate($account);
$currency = $this->repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
// include this account in net-worth charts?
$includeNetWorth = $repository->getMetaValue($account, 'include_net_worth');
@@ -162,7 +163,7 @@ class EditController extends Controller
$request->session()->flash('preFilled', $preFilled);
return view('accounts.edit', compact('account', 'currency', 'showNetWorth', 'subTitle', 'subTitleIcon', 'locations', 'liabilityDirections', 'objectType', 'roles', 'preFilled', 'liabilityTypes', 'interestPeriods'));
return view('accounts.edit', compact('account', 'currency', 'canEditCurrency', 'showNetWorth', 'subTitle', 'subTitleIcon', 'locations', 'liabilityDirections', 'objectType', 'roles', 'preFilled', 'liabilityTypes', 'interestPeriods'));
}
/**

View File

@@ -86,7 +86,7 @@ class ReconcileController extends Controller
return redirect(route('accounts.index', [config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type))]));
}
$currency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
// no start or end:
$range = app('navigation')->getViewRange(false);
@@ -197,7 +197,7 @@ class ReconcileController extends Controller
}
$reconciliation = $this->accountRepos->getReconciliation($account);
$currency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
$source = $reconciliation;
$destination = $account;
if (1 === bccomp($difference, '0')) {

View File

@@ -30,7 +30,6 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\PeriodOverview;
use Illuminate\Contracts\View\Factory;
@@ -101,7 +100,7 @@ class ShowController extends Controller
$page = (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$accountCurrency = $this->repository->getAccountCurrency($account);
$currency = $accountCurrency ?? Amount::getDefaultCurrency();
$currency = $accountCurrency ?? $this->defaultCurrency;
$fStart = $start->isoFormat($this->monthAndDayFormat);
$fEnd = $end->isoFormat($this->monthAndDayFormat);
$subTitle = (string) trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]);
@@ -178,7 +177,7 @@ class ShowController extends Controller
$subTitleIcon = config('firefly.subIconsByIdentifier.'.$account->accountType->type);
$page = (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$currency = $this->repository->getAccountCurrency($account) ?? Amount::getDefaultCurrency();
$currency = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
$subTitle = (string) trans('firefly.all_journals_for_account', ['name' => $account->name]);
$periods = new Collection();

View File

@@ -77,7 +77,7 @@ class CreateController extends Controller
$periods[$current] = (string) trans('firefly.repeat_freq_'.$current);
}
$subTitle = (string) trans('firefly.create_new_bill');
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
// put previous url in session if not redirect from store (not "create another").
if (true !== session('bills.create.fromStore')) {

View File

@@ -85,11 +85,10 @@ class EditController extends Controller
$this->rememberPreviousUrl('bills.edit.url');
}
$currency = app('amount')->getDefaultCurrency();
$bill->amount_min = app('steam')->bcround($bill->amount_min, $currency->decimal_places);
$bill->amount_max = app('steam')->bcround($bill->amount_max, $currency->decimal_places);
$bill->amount_min = app('steam')->bcround($bill->amount_min, $bill->transactionCurrency->decimal_places);
$bill->amount_max = app('steam')->bcround($bill->amount_max, $bill->transactionCurrency->decimal_places);
$rules = $this->repository->getRulesForBill($bill);
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');

View File

@@ -86,11 +86,10 @@ class CreateController extends Controller
'half_year' => (string) trans('firefly.auto_budget_period_half_year'),
'yearly' => (string) trans('firefly.auto_budget_period_yearly'),
];
$currency = app('amount')->getDefaultCurrency();
$preFilled = [
'auto_budget_period' => $hasOldInput ? (bool) $request->old('auto_budget_period') : 'monthly',
'auto_budget_currency_id' => $hasOldInput ? (int) $request->old('auto_budget_currency_id') : $currency->id,
'auto_budget_currency_id' => $hasOldInput ? (int) $request->old('auto_budget_currency_id') : $this->defaultCurrency->id,
];
$request->session()->flash('preFilled', $preFilled);

View File

@@ -91,10 +91,9 @@ class EditController extends Controller
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');
$currency = app('amount')->getDefaultCurrency();
$preFilled = [
'active' => $hasOldInput ? (bool) $request->old('active') : $budget->active,
'auto_budget_currency_id' => $hasOldInput ? (int) $request->old('auto_budget_currency_id') : $currency->id,
'auto_budget_currency_id' => $hasOldInput ? (int) $request->old('auto_budget_currency_id') : $this->defaultCurrency->id,
];
if (null !== $autoBudget) {
$amount = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount;

View File

@@ -36,11 +36,13 @@ use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Http\Controllers\DateCalculation;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@@ -105,7 +107,6 @@ class IndexController extends Controller
$end ??= session('end', today(config('app.timezone'))->endOfMonth());
}
$defaultCurrency = app('amount')->getDefaultCurrency();
$currencies = $this->currencyRepository->get();
$budgeted = '0';
$spent = '0';
@@ -118,14 +119,14 @@ class IndexController extends Controller
// get all available budgets:
$availableBudgets = $this->getAllAvailableBudgets($start, $end);
// get all active budgets:
$budgets = $this->getAllBudgets($start, $end, $currencies, $defaultCurrency);
$budgets = $this->getAllBudgets($start, $end, $currencies, $this->defaultCurrency);
$sums = $this->getSums($budgets);
// get budgeted for default currency:
if (0 === count($availableBudgets)) {
$budgeted = $this->blRepository->budgeted($start, $end, $defaultCurrency);
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $defaultCurrency);
$spent = $spentArr[$defaultCurrency->id]['sum'] ?? '0';
$budgeted = $this->blRepository->budgeted($start, $end, $this->defaultCurrency);
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $this->defaultCurrency);
$spent = $spentArr[$this->defaultCurrency->id]['sum'] ?? '0';
unset($spentArr);
}
@@ -135,6 +136,7 @@ class IndexController extends Controller
// get all inactive budgets, and simply list them:
$inactive = $this->repository->getInactiveBudgets();
$defaultCurrency = $this->defaultCurrency;
return view(
'budgets.index',
@@ -161,6 +163,8 @@ class IndexController extends Controller
private function getAllAvailableBudgets(Carbon $start, Carbon $end): array
{
Log::debug(sprintf('Start of getAllAvailableBudgets("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$converter = new ExchangeRateConverter();
// get all available budgets.
$ab = $this->abRepository->get($start, $end);
$availableBudgets = [];
@@ -168,18 +172,22 @@ class IndexController extends Controller
// for each, complement with spent amount:
/** @var AvailableBudget $entry */
foreach ($ab as $entry) {
$array = $entry->toArray();
$array['start_date'] = $entry->start_date;
$array['end_date'] = $entry->end_date;
$array = $entry->toArray();
$array['start_date'] = $entry->start_date;
$array['end_date'] = $entry->end_date;
// spent in period:
$spentArr = $this->opsRepository->sumExpenses($entry->start_date, $entry->end_date, null, null, $entry->transactionCurrency);
$array['spent'] = $spentArr[$entry->transaction_currency_id]['sum'] ?? '0';
$spentArr = $this->opsRepository->sumExpenses($entry->start_date, $entry->end_date, null, null, $entry->transactionCurrency);
$array['spent'] = $spentArr[$entry->transaction_currency_id]['sum'] ?? '0';
$array['native_spent'] = $this->convertToNative && $entry->transaction_currency_id !== $this->defaultCurrency->id ? $converter->convert($entry->transactionCurrency, $this->defaultCurrency, $entry->start_date, $array['spent']) : null;
// budgeted in period:
$budgeted = $this->blRepository->budgeted($entry->start_date, $entry->end_date, $entry->transactionCurrency);
$array['budgeted'] = $budgeted;
$availableBudgets[] = $array;
$budgeted = $this->blRepository->budgeted($entry->start_date, $entry->end_date, $entry->transactionCurrency);
$array['budgeted'] = $budgeted;
$array['native_budgeted'] = $this->convertToNative && $entry->transaction_currency_id !== $this->defaultCurrency->id ? $converter->convert($entry->transactionCurrency, $this->defaultCurrency, $entry->start_date, $budgeted) : null;
// this time, because of complex sums, use the currency converter.
$availableBudgets[] = $array;
unset($spentArr);
}

View File

@@ -103,7 +103,6 @@ class AccountController extends Controller
$currencies = [];
$chartData = [];
$tempData = [];
$default = Amount::getDefaultCurrency();
// grab all accounts and names
$accounts = $this->accountRepository->getAccountsByType([AccountTypeEnum::EXPENSE->value]);
@@ -115,7 +114,7 @@ class AccountController extends Controller
// loop the accounts, then check for balance and currency info.
foreach ($accounts as $account) {
Log::debug(sprintf('Now in account #%d ("%s")', $account->id, $account->name));
// Log::debug(sprintf('[a] Now in account #%d ("%s")', $account->id, $account->name));
$expenses = $endBalances[$account->id] ?? false;
if (false === $expenses) {
Log::error(sprintf('Found no end balance for account #%d', $account->id));
@@ -138,13 +137,13 @@ class AccountController extends Controller
continue;
}
Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToNative ? $default->code : $key;
Log::debug(sprintf('Search code is %s', $searchCode));
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToNative ? $this->defaultCurrency->code : $key;
// Log::debug(sprintf('Search code is %s', $searchCode));
// see if there is an accompanying start amount.
// grab the difference and find the currency.
$startBalance = ($startBalances[$account->id][$key] ?? '0');
Log::debug(sprintf('Start balance is %s', $startBalance));
// Log::debug(sprintf('Start balance is %s', $startBalance));
$diff = bcsub($endBalance, $startBalance);
$currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode);
if (0 !== bccomp($diff, '0')) {
@@ -426,7 +425,7 @@ class AccountController extends Controller
$cache->addProperty($this->convertToNative);
$cache->addProperty($account->id);
if ($cache->has()) {
// return response()->json($cache->get());
return response()->json($cache->get());
}
// collect and filter balances for the entire period.
@@ -562,7 +561,6 @@ class AccountController extends Controller
$currencies = [];
$chartData = [];
$tempData = [];
$default = Amount::getDefaultCurrency();
// grab all accounts and names
$accounts = $this->accountRepository->getAccountsByType([AccountTypeEnum::REVENUE->value]);
@@ -575,7 +573,7 @@ class AccountController extends Controller
// loop the accounts, then check for balance and currency info.
foreach ($accounts as $account) {
Log::debug(sprintf('Now in account #%d ("%s")', $account->id, $account->name));
// Log::debug(sprintf('[b] Now in account #%d ("%s")', $account->id, $account->name));
$expenses = $endBalances[$account->id] ?? false;
if (false === $expenses) {
Log::error(sprintf('Found no end balance for account #%d', $account->id));
@@ -598,13 +596,13 @@ class AccountController extends Controller
continue;
}
Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToNative ? $default->code : $key;
Log::debug(sprintf('Search code is %s', $searchCode));
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToNative ? $this->defaultCurrency->code : $key;
// Log::debug(sprintf('Search code is %s', $searchCode));
// see if there is an accompanying start amount.
// grab the difference and find the currency.
$startBalance = ($startBalances[$account->id][$key] ?? '0');
Log::debug(sprintf('Start balance is %s', $startBalance));
// Log::debug(sprintf('Start balance is %s', $startBalance));
$diff = bcsub($endBalance, $startBalance);
$currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode);
if (0 !== bccomp($diff, '0')) {

View File

@@ -111,7 +111,7 @@ class BillController extends Controller
$cache->addProperty($bill->id);
$cache->addProperty($this->convertToNative);
if ($cache->has()) {
// return response()->json($cache->get());
return response()->json($cache->get());
}
$locale = app('steam')->getLocale();

View File

@@ -92,6 +92,7 @@ class BudgetController extends Controller
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($this->convertToNative);
$cache->addProperty('chart.budget.budget');
$cache->addProperty($budget->id);
@@ -108,7 +109,7 @@ class BudgetController extends Controller
while ($end >= $loopStart) {
/** @var Carbon $loopEnd */
$loopEnd = app('navigation')->endOfPeriod($loopStart, $step);
$spent = $this->opsRepository->sumExpenses($loopStart, $loopEnd, null, $collection);
$spent = $this->opsRepository->sumExpenses($loopStart, $loopEnd, null, $collection); // this method already converts to native.
$label = trim(app('navigation')->periodShow($loopStart, $step));
foreach ($spent as $row) {
@@ -157,6 +158,7 @@ class BudgetController extends Controller
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($this->convertToNative);
$cache->addProperty('chart.budget.budget.limit');
$cache->addProperty($budgetLimit->id);
$cache->addProperty($budget->id);
@@ -169,9 +171,15 @@ class BudgetController extends Controller
$amount = $budgetLimit->amount;
$budgetCollection = new Collection([$budget]);
$currency = $budgetLimit->transactionCurrency;
if ($this->convertToNative) {
$amount = $budgetLimit->native_amount;
$currency = $this->defaultCurrency;
}
while ($start <= $end) {
$current = clone $start;
$expenses = $this->opsRepository->sumExpenses($current, $current, null, $budgetCollection, $currency);
$expenses = $this->opsRepository->sumExpenses($current, $current, null, $budgetCollection, $budgetLimit->transactionCurrency);
$spent = $expenses[$currency->id]['sum'] ?? '0';
$amount = bcadd($amount, $spent);
$format = $start->isoFormat((string) trans('config.month_and_day_js', [], $locale));
@@ -181,8 +189,8 @@ class BudgetController extends Controller
}
$data = $this->generator->singleSet((string) trans('firefly.left'), $entries);
// add currency symbol from budget limit:
$data['datasets'][0]['currency_symbol'] = $budgetLimit->transactionCurrency->symbol;
$data['datasets'][0]['currency_code'] = $budgetLimit->transactionCurrency->code;
$data['datasets'][0]['currency_symbol'] = $currency->symbol;
$data['datasets'][0]['currency_code'] = $currency->code;
$cache->store($data);
return response()->json($data);
@@ -198,6 +206,7 @@ class BudgetController extends Controller
$budgetLimitId = null === $budgetLimit ? 0 : $budgetLimit->id;
$cache = new CacheProperties();
$cache->addProperty($budget->id);
$cache->addProperty($this->convertToNative);
$cache->addProperty($budgetLimitId);
$cache->addProperty('chart.budget.expense-asset');
$start = session('first', today(config('app.timezone'))->startOfYear());
@@ -222,14 +231,33 @@ class BudgetController extends Controller
// group by asset account ID:
foreach ($journals as $journal) {
$key = sprintf('%d-%d', (int) $journal['source_account_id'], $journal['currency_id']);
$key = sprintf('%d-%d', $journal['source_account_id'], $journal['currency_id']);
$amount = $journal['amount'];
$symbol = $journal['currency_symbol'];
$code = $journal['currency_code'];
$name = $journal['currency_name'];
// if convert to native, use the native things, unless it's the foreign amount which is in the native currency.
if ($this->convertToNative && $journal['currency_id'] !== $this->defaultCurrency->id) {
$key = sprintf('%d-%d', $journal['source_account_id'], $this->defaultCurrency->id);
$symbol = $this->defaultCurrency->symbol;
$code = $this->defaultCurrency->code;
$name = $this->defaultCurrency->name;
$amount = $journal['native_amount'];
}
if ($journal['foreign_currency_id'] === $this->defaultCurrency->id) {
$amount = $journal['foreign_amount'];
}
$result[$key] ??= [
'amount' => '0',
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $symbol,
'currency_code' => $code,
'currency_name' => $name,
];
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
$result[$key]['amount'] = bcadd($amount, $result[$key]['amount']);
}
$names = $this->getAccountNames(array_keys($result));
@@ -261,6 +289,7 @@ class BudgetController extends Controller
$budgetLimitId = null === $budgetLimit ? 0 : $budgetLimit->id;
$cache = new CacheProperties();
$cache->addProperty($budget->id);
$cache->addProperty($this->convertToNative);
$cache->addProperty($budgetLimitId);
$cache->addProperty('chart.budget.expense-category');
$start = session('first', today(config('app.timezone'))->startOfYear());
@@ -283,13 +312,36 @@ class BudgetController extends Controller
$chartData = [];
foreach ($journals as $journal) {
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
$symbol = $journal['currency_symbol'];
$code = $journal['currency_code'];
$name = $journal['currency_name'];
$amount = $journal['amount'];
// if convert to native, use the native things, unless it's the foreign amount which is in the native currency.
if ($this->convertToNative && $journal['currency_id'] !== $this->defaultCurrency->id && $journal['foreign_currency_id'] !== $this->defaultCurrency->id
) {
$key = sprintf('%d-%d', $journal['category_id'], $this->defaultCurrency->id);
$symbol = $this->defaultCurrency->symbol;
$code = $this->defaultCurrency->code;
$name = $this->defaultCurrency->name;
$amount = $journal['native_amount'];
}
if ($this->convertToNative && $journal['currency_id'] !== $this->defaultCurrency->id && $journal['foreign_currency_id'] === $this->defaultCurrency->id
) {
$key = sprintf('%d-%d', $journal['category_id'], $this->defaultCurrency->id);
$symbol = $this->defaultCurrency->symbol;
$code = $this->defaultCurrency->code;
$name = $this->defaultCurrency->name;
$amount = $journal['foreign_amount'];
}
$result[$key] ??= [
'amount' => '0',
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $symbol,
'currency_code' => $code,
'currency_name' => $name,
];
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
$result[$key]['amount'] = bcadd($amount, $result[$key]['amount']);
}
$names = $this->getCategoryNames(array_keys($result));
@@ -320,6 +372,7 @@ class BudgetController extends Controller
$cache = new CacheProperties();
$cache->addProperty($budget->id);
$cache->addProperty($budgetLimitId);
$cache->addProperty($this->convertToNative);
$cache->addProperty('chart.budget.expense-expense');
$start = session('first', today(config('app.timezone'))->startOfYear());
$end = today();
@@ -343,13 +396,32 @@ class BudgetController extends Controller
/** @var array $journal */
foreach ($journals as $journal) {
$key = sprintf('%d-%d', $journal['destination_account_id'], $journal['currency_id']);
$amount = $journal['amount'];
// if convert to native, use the native things, unless it's the foreign amount which is in the native currency.
if ($this->convertToNative && $journal['currency_id'] !== $this->defaultCurrency->id && $journal['foreign_currency_id'] !== $this->defaultCurrency->id) {
$key = sprintf('%d-%d', $journal['destination_account_id'], $this->defaultCurrency->id);
$symbol = $this->defaultCurrency->symbol;
$code = $this->defaultCurrency->code;
$name = $this->defaultCurrency->name;
$amount = $journal['native_amount'];
}
if ($this->convertToNative && $journal['currency_id'] !== $this->defaultCurrency->id && $journal['foreign_currency_id'] === $this->defaultCurrency->id) {
$key = sprintf('%d-%d', $journal['destination_account_id'], $this->defaultCurrency->id);
$symbol = $this->defaultCurrency->symbol;
$code = $this->defaultCurrency->code;
$name = $this->defaultCurrency->name;
$amount = $journal['foreign_amount'];
}
$result[$key] ??= [
'amount' => '0',
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $symbol,
'currency_code' => $code,
'currency_name' => $name,
];
$result[$key]['amount'] = bcadd($journal['amount'], $result[$key]['amount']);
$result[$key]['amount'] = bcadd($amount, $result[$key]['amount']);
}
$names = $this->getAccountNames(array_keys($result));
@@ -385,7 +457,7 @@ class BudgetController extends Controller
$cache->addProperty($this->convertToNative);
$cache->addProperty('chart.budget.frontpage');
if ($cache->has()) {
// return response()->json($cache->get());
return response()->json($cache->get());
}
Log::debug('Regenerate frontpage chart from scratch.');
$chartGenerator = app(FrontpageChartGenerator::class);
@@ -393,7 +465,7 @@ class BudgetController extends Controller
$chartGenerator->setStart($start);
$chartGenerator->setEnd($end);
$chartGenerator->convertToNative = $this->convertToNative;
$chartGenerator->default = Amount::getDefaultCurrency();
$chartGenerator->default = $this->defaultCurrency;
$chartData = $chartGenerator->generate();
$data = $this->generator->multiSet($chartData);

View File

@@ -70,24 +70,27 @@ class CategoryController extends Controller
public function all(Category $category): JsonResponse
{
// cache results:
$cache = new CacheProperties();
$cache = new CacheProperties();
$cache->addProperty('chart.category.all');
$cache->addProperty($category->id);
$cache->addProperty($this->convertToNative);
if ($cache->has()) {
return response()->json($cache->get());
}
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
$start = $repository->firstUseDate($category) ?? $this->getDate();
$range = app('navigation')->getViewRange(false);
$start = app('navigation')->startOfPeriod($start, $range);
$end = $this->getDate();
$repository = app(CategoryRepositoryInterface::class);
$start = $repository->firstUseDate($category) ?? $this->getDate();
$range = app('navigation')->getViewRange(false);
$start = app('navigation')->startOfPeriod($start, $range);
$end = $this->getDate();
/** @var WholePeriodChartGenerator $chartGenerator */
$chartGenerator = app(WholePeriodChartGenerator::class);
$chartData = $chartGenerator->generate($category, $start, $end);
$data = $this->generator->multiSet($chartData);
$chartGenerator = app(WholePeriodChartGenerator::class);
$chartGenerator->convertToNative = $this->convertToNative;
$chartData = $chartGenerator->generate($category, $start, $end);
$data = $this->generator->multiSet($chartData);
$cache->store($data);
return response()->json($data);
@@ -113,7 +116,7 @@ class CategoryController extends Controller
$cache->addProperty($this->convertToNative);
$cache->addProperty('chart.category.frontpage');
if ($cache->has()) {
// return response()->json($cache->get());
return response()->json($cache->get());
}
$frontpageGenerator = new FrontpageChartGenerator($start, $end);
@@ -136,6 +139,7 @@ class CategoryController extends Controller
$cache->addProperty('chart.category.period');
$cache->addProperty($accounts->pluck('id')->toArray());
$cache->addProperty($category);
$cache->addProperty($this->convertToNative);
if ($cache->has()) {
return response()->json($cache->get());
}

View File

@@ -145,7 +145,7 @@ class ReportController extends Controller
$cache->addProperty($accounts);
$cache->addProperty($end);
if ($cache->has()) {
// return response()->json($cache->get());
return response()->json($cache->get());
}
Log::debug('Going to do operations for accounts ', $accounts->pluck('id')->toArray());

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\RequestInformation;
use FireflyIII\Support\Http\Controllers\UserNavigation;
@@ -117,11 +118,11 @@ abstract class Controller extends BaseController
$this->defaultCurrency =null;
// get shown-intro-preference:
if (auth()->check()) {
$this->defaultCurrency = app('amount')->getDefaultCurrency();
$this->defaultCurrency = Amount::getDefaultCurrency();
$language = Steam::getLanguage();
$locale = Steam::getLocale();
$darkMode = app('preferences')->get('darkMode', 'browser')->data;
$this->convertToNative =app('preferences')->get('convert_to_native', false)->data;
$this->convertToNative =Amount::convertToNative();
$page = $this->getPageName();
$shownDemo = $this->hasSeenDemo();
View::share('language', $language);

View File

@@ -76,6 +76,10 @@ class DebugController extends Controller
|| str_starts_with($route->uri(), '_debugbar')
|| str_starts_with($route->uri(), '_ignition')
|| str_starts_with($route->uri(), 'oauth')
|| str_starts_with($route->uri(), 'chart')
|| str_starts_with($route->uri(), 'v1/jscript')
|| str_starts_with($route->uri(), 'v2/jscript')
|| str_starts_with($route->uri(), 'json')
|| str_starts_with($route->uri(), 'sanctum')
) {
continue;
@@ -156,8 +160,8 @@ class DebugController extends Controller
Artisan::call('view:clear');
// also do some recalculations.
Artisan::call('firefly-iii:trigger-credit-recalculation');
AccountBalanceCalculator::recalculateAll(true);
Artisan::call('correction:recalculates-liabilities');
AccountBalanceCalculator::recalculateAll(false);
try {
Artisan::call('twig:clean');

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Http\Controllers\ExchangeRates;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\TransactionCurrency;
use Illuminate\View\View;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class IndexController extends Controller
{
@@ -46,6 +47,9 @@ class IndexController extends Controller
return $next($request);
}
);
if (!config('cer.enabled')) {
throw new NotFoundHttpException();
}
}
public function index(): View

View File

@@ -49,14 +49,13 @@ class JavascriptController extends Controller
$accounts = $repository->getAccountsByType(
[AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD]
);
$default = app('amount')->getDefaultCurrency();
$data = ['accounts' => []];
/** @var Account $account */
foreach ($accounts as $account) {
$accountId = $account->id;
$currency = (int) $repository->getMetaValue($account, 'currency_id');
$currency = 0 === $currency ? $default->id : $currency;
$currency = 0 === $currency ? $this->defaultCurrency->id : $currency;
$entry = ['preferredCurrency' => $currency, 'name' => $account->name];
$data['accounts'][$accountId] = $entry;
}
@@ -96,9 +95,9 @@ class JavascriptController extends Controller
public function variables(Request $request, AccountRepositoryInterface $repository): Response
{
$account = $repository->find((int) $request->get('account'));
$currency = app('amount')->getDefaultCurrency();
$currency = $this->defaultCurrency;
if (null !== $account) {
$currency = $repository->getAccountCurrency($account) ?? $currency;
$currency = $repository->getAccountCurrency($account) ?? $this->defaultCurrency;
}
$locale = app('steam')->getLocale();
$accounting = app('amount')->getJsConfig();

View File

@@ -78,8 +78,7 @@ class BoxController extends Controller
$incomes = [];
$expenses = [];
$sums = [];
$currency = app('amount')->getDefaultCurrency();
$currency = $this->defaultCurrency;
// collect income of user:
/** @var GroupCollectorInterface $collector */
@@ -91,7 +90,7 @@ class BoxController extends Controller
/** @var array $journal */
foreach ($set as $journal) {
$currencyId = $this->convertToNative ? $currency->id : (int) $journal['currency_id'];
$currencyId = $this->convertToNative && $this->defaultCurrency->id !== (int) $journal['currency_id'] ? $this->defaultCurrency->id : (int) $journal['currency_id'];
$amount = Amount::getAmountFromJournal($journal);
$incomes[$currencyId] ??= '0';
$incomes[$currencyId] = bcadd($incomes[$currencyId], app('steam')->positive($amount));
@@ -109,7 +108,7 @@ class BoxController extends Controller
/** @var array $journal */
foreach ($set as $journal) {
$currencyId = $this->convertToNative ? $currency->id : (int) $journal['currency_id'];
$currencyId = $this->convertToNative ? $this->defaultCurrency->id : (int) $journal['currency_id'];
$amount = Amount::getAmountFromJournal($journal);
$expenses[$currencyId] ??= '0';
$expenses[$currencyId] = bcadd($expenses[$currencyId], $amount);
@@ -126,10 +125,10 @@ class BoxController extends Controller
$expenses[$currencyId] = app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false);
}
if (0 === count($sums)) {
$currency = app('amount')->getDefaultCurrency();
$sums[$currency->id] = app('amount')->formatAnything($currency, '0', false);
$incomes[$currency->id] = app('amount')->formatAnything($currency, '0', false);
$expenses[$currency->id] = app('amount')->formatAnything($currency, '0', false);
$currency = $this->defaultCurrency;
$sums[$this->defaultCurrency->id] = app('amount')->formatAnything($this->defaultCurrency, '0', false);
$incomes[$this->defaultCurrency->id] = app('amount')->formatAnything($this->defaultCurrency, '0', false);
$expenses[$this->defaultCurrency->id] = app('amount')->formatAnything($this->defaultCurrency, '0', false);
}
$response = [

View File

@@ -73,7 +73,7 @@ class ReconcileController extends Controller
{
$startBalance = $request->get('startBalance');
$endBalance = $request->get('endBalance');
$accountCurrency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$accountCurrency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
$amount = '0';
$clearedAmount = '0';
@@ -193,7 +193,7 @@ class ReconcileController extends Controller
$startDate->subDay();
$end->endOfDay();
$currency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
$startBalance = Steam::finalAccountBalance($account, $startDate)['balance'];
$endBalance = Steam::finalAccountBalance($account, $end)['balance'];

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use FireflyIII\Events\Preferences\UserGroupChangedDefaultCurrency;
use FireflyIII\Events\Test\UserTestNotificationChannel;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Requests\PreferencesRequest;
@@ -35,6 +36,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@@ -258,6 +260,11 @@ class PreferencesController extends Controller
// convert native
$convertToNative = 1 === (int) $request->get('convertToNative');
if ($convertToNative && !$this->convertToNative) {
// set to true!
Log::debug('User sets convertToNative to true.');
event(new UserGroupChangedDefaultCurrency(auth()->user()->userGroup));
}
app('preferences')->set('convert_to_native', $convertToNative);
// custom fiscal year

View File

@@ -84,7 +84,7 @@ class CreateController extends Controller
{
$budgets = app('expandedform')->makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets());
$bills = app('expandedform')->makeSelectListWithEmpty($this->billRepository->getActiveBills());
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
$tomorrow = today(config('app.timezone'));
$oldRepetitionType = $request->old('repetition_type');
$tomorrow->addDay();
@@ -129,7 +129,7 @@ class CreateController extends Controller
{
$budgets = app('expandedform')->makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets());
$bills = app('expandedform')->makeSelectListWithEmpty($this->billRepository->getActiveBills());
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
$tomorrow = today(config('app.timezone'));
$oldRepetitionType = $request->old('repetition_type');
$tomorrow->addDay();

View File

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

View File

@@ -216,15 +216,14 @@ class ConvertController extends Controller
private function getLiabilities(): array
{
// make repositories
$accountList = $this->accountRepository->getActiveAccountsByType([AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
$defaultCurrency = app('amount')->getDefaultCurrency();
$grouped = [];
$accountList = $this->accountRepository->getActiveAccountsByType([AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
$grouped = [];
// group accounts:
/** @var Account $account */
foreach ($accountList as $account) {
$balance = Steam::finalAccountBalance($account, today()->endOfDay())['balance'];
$currency = $this->accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->defaultCurrency;
$role = 'l_'.$account->accountType->type;
$key = (string) trans('firefly.opt_group_'.$role);
$grouped[$key][$account->id] = $account->name.' ('.app('amount')->formatAnything($currency, $balance, false).')';
@@ -239,15 +238,14 @@ class ConvertController extends Controller
private function getAssetAccounts(): array
{
// make repositories
$accountList = $this->accountRepository->getActiveAccountsByType([AccountType::ASSET]);
$defaultCurrency = app('amount')->getDefaultCurrency();
$grouped = [];
$accountList = $this->accountRepository->getActiveAccountsByType([AccountType::ASSET]);
$grouped = [];
// group accounts:
/** @var Account $account */
foreach ($accountList as $account) {
$balance = Steam::finalAccountBalance($account, today()->endOfDay())['balance'];
$currency = $this->accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->defaultCurrency;
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
if ('' === $role) {
$role = 'no_account_type';

View File

@@ -114,7 +114,7 @@ class CreateController extends Controller
$optionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data;
$allowedOpposingTypes = config('firefly.allowed_opposing_types');
$accountToTypes = config('firefly.account_to_transaction');
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = $this->defaultCurrency;
$previousUrl = $this->rememberPreviousUrl('transactions.create.url');
$parts = parse_url($previousUrl);
$search = sprintf('?%s', $parts['query'] ?? '');

View File

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

View File

@@ -25,6 +25,7 @@ namespace FireflyIII\Http\Middleware;
use Carbon\Carbon;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Controllers\RequestInformation;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
@@ -108,7 +109,7 @@ class Range
setlocale(LC_TIME, $localeArray);
$moneyResult = setlocale(LC_MONETARY, $localeArray);
// send error to view, if could not set money format
// send error to view, if it could not set money format
if (false === $moneyResult) {
app('log')->error('Could not set locale. The following array doesnt work: ', $localeArray);
app('view')->share('invalidMonetaryLocale', true);
@@ -117,7 +118,7 @@ class Range
// save some formats:
$monthAndDayFormat = (string) trans('config.month_and_day_js', [], $locale);
$dateTimeFormat = (string) trans('config.date_time_js', [], $locale);
$defaultCurrency = app('amount')->getDefaultCurrency();
$defaultCurrency = Amount::getDefaultCurrency();
// also format for moment JS:
$madMomentJS = (string) trans('config.month_and_day_moment_js', [], $locale);

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Http\Requests;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
@@ -125,7 +126,7 @@ class PiggyBankStoreRequest extends FormRequest
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
return app('amount')->getDefaultCurrency();
return Amount::getDefaultCurrency();
}
return $currency;

View File

@@ -27,6 +27,7 @@ use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\IsValidPositiveAmount;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
@@ -128,7 +129,7 @@ class PiggyBankUpdateRequest extends FormRequest
$currencyId = (int) ($data['transaction_currency_id'] ?? 0);
$currency = TransactionCurrency::find($currencyId);
if (null === $currency) {
return app('amount')->getDefaultCurrency();
return Amount::getDefaultCurrency();
}
return $currency;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@@ -1,45 +0,0 @@
<?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

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

View File

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

View File

@@ -1,29 +0,0 @@
<?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 {}

View File

@@ -1,53 +0,0 @@
<?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

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

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