mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-31 10:47:00 +00:00 
			
		
		
		
	Compare commits
	
		
			47 Commits
		
	
	
		
			develop-20
			...
			develop-20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | b58d809063 | ||
|  | 9e34314dbc | ||
|  | e4aa218b5f | ||
|  | 31722477d4 | ||
|  | ec82105433 | ||
|  | 146e164f04 | ||
|  | 7d37c93988 | ||
|  | 73dffacd9a | ||
|  | d37304fa68 | ||
|  | 62f4da6063 | ||
|  | 760da08ab7 | ||
|  | e68c4d4408 | ||
|  | 46a200aa1f | ||
|  | c422039335 | ||
|  | 0579c8565d | ||
|  | 9f25880a59 | ||
|  | 05f1819f7d | ||
|  | fa2149f957 | ||
|  | c21a79e029 | ||
|  | 03e31ebb5e | ||
|  | 3c20e5f3af | ||
|  | 9a9dd9e075 | ||
|  | 7189986c03 | ||
|  | b407d8d315 | ||
|  | 41fa2a6208 | ||
|  | fe00c4c373 | ||
|  | 7248a76c63 | ||
|  | ee3c618797 | ||
|  | a1241ebedb | ||
|  | af78d998db | ||
|  | d96c235ffe | ||
|  | 79ca1b5f4e | ||
|  | 0f68735e1c | ||
|  | 82abee37de | ||
|  | 507040f1fd | ||
|  | 42dc8486e9 | ||
|  | 6c655634bc | ||
|  | f2166b97b8 | ||
|  | da88e02be0 | ||
|  | 0d56b7d251 | ||
|  | 0a089efcac | ||
|  | 89ab360391 | ||
|  | 2bd97d9a99 | ||
|  | 103b9056e4 | ||
|  | 5971d155ef | ||
|  | 9e373a9b0d | ||
|  | 4fb61646b4 | 
| @@ -29,7 +29,7 @@ $paths = [ | |||||||
|     $current . '/../../database', |     $current . '/../../database', | ||||||
|     $current . '/../../routes', |     $current . '/../../routes', | ||||||
|     $current . '/../../tests', |     $current . '/../../tests', | ||||||
|     $current . '/../../resources/lang', |     $current . '/../../resources/lang/en_US', | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| $finder = PhpCsFixer\Finder::create() | $finder = PhpCsFixer\Finder::create() | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								.ci/php-cs-fixer/composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										26
									
								
								.ci/php-cs-fixer/composer.lock
									
									
									
										generated
									
									
									
								
							| @@ -406,16 +406,16 @@ | |||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "friendsofphp/php-cs-fixer", |             "name": "friendsofphp/php-cs-fixer", | ||||||
|             "version": "v3.65.0", |             "version": "v3.66.0", | ||||||
|             "source": { |             "source": { | ||||||
|                 "type": "git", |                 "type": "git", | ||||||
|                 "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", |                 "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", | ||||||
|                 "reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f" |                 "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6" | ||||||
|             }, |             }, | ||||||
|             "dist": { |             "dist": { | ||||||
|                 "type": "zip", |                 "type": "zip", | ||||||
|                 "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/79d4f3e77b250a7d8043d76c6af8f0695e8a469f", |                 "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/5f5f2a142ff36b93c41885bca29cc5f861c013e6", | ||||||
|                 "reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f", |                 "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6", | ||||||
|                 "shasum": "" |                 "shasum": "" | ||||||
|             }, |             }, | ||||||
|             "require": { |             "require": { | ||||||
| @@ -441,7 +441,7 @@ | |||||||
|                 "symfony/polyfill-mbstring": "^1.28", |                 "symfony/polyfill-mbstring": "^1.28", | ||||||
|                 "symfony/polyfill-php80": "^1.28", |                 "symfony/polyfill-php80": "^1.28", | ||||||
|                 "symfony/polyfill-php81": "^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" |                 "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" | ||||||
|             }, |             }, | ||||||
|             "require-dev": { |             "require-dev": { | ||||||
| @@ -497,7 +497,7 @@ | |||||||
|             ], |             ], | ||||||
|             "support": { |             "support": { | ||||||
|                 "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", |                 "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", | ||||||
|                 "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.65.0" |                 "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.66.0" | ||||||
|             }, |             }, | ||||||
|             "funding": [ |             "funding": [ | ||||||
|                 { |                 { | ||||||
| @@ -505,7 +505,7 @@ | |||||||
|                     "type": "github" |                     "type": "github" | ||||||
|                 } |                 } | ||||||
|             ], |             ], | ||||||
|             "time": "2024-11-25T00:39:24+00:00" |             "time": "2024-12-29T13:46:23+00:00" | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "psr/container", |             "name": "psr/container", | ||||||
| @@ -2246,16 +2246,16 @@ | |||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "symfony/process", |             "name": "symfony/process", | ||||||
|             "version": "v7.2.0", |             "version": "v7.1.8", | ||||||
|             "source": { |             "source": { | ||||||
|                 "type": "git", |                 "type": "git", | ||||||
|                 "url": "https://github.com/symfony/process.git", |                 "url": "https://github.com/symfony/process.git", | ||||||
|                 "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e" |                 "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892" | ||||||
|             }, |             }, | ||||||
|             "dist": { |             "dist": { | ||||||
|                 "type": "zip", |                 "type": "zip", | ||||||
|                 "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", |                 "url": "https://api.github.com/repos/symfony/process/zipball/42783370fda6e538771f7c7a36e9fa2ee3a84892", | ||||||
|                 "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e", |                 "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892", | ||||||
|                 "shasum": "" |                 "shasum": "" | ||||||
|             }, |             }, | ||||||
|             "require": { |             "require": { | ||||||
| @@ -2287,7 +2287,7 @@ | |||||||
|             "description": "Executes commands in sub-processes", |             "description": "Executes commands in sub-processes", | ||||||
|             "homepage": "https://symfony.com", |             "homepage": "https://symfony.com", | ||||||
|             "support": { |             "support": { | ||||||
|                 "source": "https://github.com/symfony/process/tree/v7.2.0" |                 "source": "https://github.com/symfony/process/tree/v7.1.8" | ||||||
|             }, |             }, | ||||||
|             "funding": [ |             "funding": [ | ||||||
|                 { |                 { | ||||||
| @@ -2303,7 +2303,7 @@ | |||||||
|                     "type": "tidelift" |                     "type": "tidelift" | ||||||
|                 } |                 } | ||||||
|             ], |             ], | ||||||
|             "time": "2024-11-06T14:24:19+00:00" |             "time": "2024-11-06T14:23:19+00:00" | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|             "name": "symfony/service-contracts", |             "name": "symfony/service-contracts", | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -168,7 +168,7 @@ jobs: | |||||||
|  |  | ||||||
|           # if this is a develop build, slightly different variable names. |           # if this is a develop build, slightly different variable names. | ||||||
|           if [[ "develop" == "$version" ]]; then |           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') |             releaseName=$version-$(date +'%Y%m%d') | ||||||
|             originalName=$releaseName |             originalName=$releaseName | ||||||
|             zipName=FireflyIII-develop.zip |             zipName=FireflyIII-develop.zip | ||||||
| @@ -177,7 +177,7 @@ jobs: | |||||||
|  |  | ||||||
|           # if this is a branch build, also slightly different variable names. |           # if this is a branch build, also slightly different variable names. | ||||||
|           if [[ "$version" == branch* ]]; then |           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 |             # branch builds overrule develop | ||||||
|             releaseName=$version-$(date +'%Y%m%d') |             releaseName=$version-$(date +'%Y%m%d') | ||||||
|             originalName=$releaseName |             originalName=$releaseName | ||||||
| @@ -229,7 +229,7 @@ jobs: | |||||||
|           # describe the development release. |           # describe the development release. | ||||||
|           if [[ "develop" == "$version" ]]; then |           if [[ "develop" == "$version" ]]; then | ||||||
|             echo 'Develop release.' |             echo 'Develop release.' | ||||||
|             rm output.txt |             rm -f output.txt | ||||||
|             touch output.txt |             touch output.txt | ||||||
|             sudo chown -R runner:docker 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 |             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 |           # describe a branch release | ||||||
|           if [[ "$version" == branch* ]]; then |           if [[ "$version" == branch* ]]; then | ||||||
|             echo 'Branch release.' |             echo 'Branch release.' | ||||||
|             rm output.txt |             rm -f output.txt | ||||||
|             touch output.txt |             touch output.txt | ||||||
|             sudo chown -R runner:docker 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 |             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 |             echo ":warning: Please be careful with this branch pre-release, as it may not work as expected." >> output.txt | ||||||
|           fi |           fi | ||||||
|           # describe the main release |           # describe the main release | ||||||
|           if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]]; then |           if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]] && [[ "$version" != *alpha* ]] && [[ "$version" != *beta* ]]; then | ||||||
|             sudo chown -R runner:docker output.txt |  | ||||||
|             echo 'Main release.' |             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 '' >> output.txt | ||||||
|             echo '### Instructions' >> output.txt |             echo '### Instructions' >> output.txt | ||||||
|             echo '' >> output.txt |             echo '' >> output.txt | ||||||
| @@ -336,12 +372,12 @@ jobs: | |||||||
|             gh release upload $releaseName HEAD.txt |             gh release upload $releaseName HEAD.txt | ||||||
|  |  | ||||||
|             # remove all temporary files |             # remove all temporary files | ||||||
|             rm output.txt |             rm -f output.txt | ||||||
|             rm HEAD.txt |             rm -f HEAD.txt | ||||||
|             rm $zipName |             rm -f $zipName | ||||||
|             rm $zipName.sha256 |             rm -f $zipName.sha256 | ||||||
|             rm $tarName |             rm -f $tarName | ||||||
|             rm $tarName.sha256 |             rm -f $tarName.sha256 | ||||||
|  |  | ||||||
|             # merge main back into develop |             # merge main back into develop | ||||||
|             git checkout develop |             git checkout develop | ||||||
|   | |||||||
| @@ -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. | 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 | ## 2024 | ||||||
|  | - TasneemTantawy | ||||||
| - Antônio Franco | - Antônio Franco | ||||||
| - yparitcher | - yparitcher | ||||||
| - Jhon Pedroza | - Jhon Pedroza | ||||||
|   | |||||||
| @@ -26,9 +26,9 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete; | |||||||
| 
 | 
 | ||||||
| use FireflyIII\Api\V1\Controllers\Controller; | use FireflyIII\Api\V1\Controllers\Controller; | ||||||
| use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest; | use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest; | ||||||
|  | use FireflyIII\Enums\AccountTypeEnum; | ||||||
| use FireflyIII\Exceptions\FireflyException; | use FireflyIII\Exceptions\FireflyException; | ||||||
| use FireflyIII\Models\Account; | use FireflyIII\Models\Account; | ||||||
| use FireflyIII\Models\AccountType; |  | ||||||
| use FireflyIII\Repositories\Account\AccountRepositoryInterface; | use FireflyIII\Repositories\Account\AccountRepositoryInterface; | ||||||
| use FireflyIII\Support\Facades\Steam; | use FireflyIII\Support\Facades\Steam; | ||||||
| use FireflyIII\Support\Http\Api\AccountFilter; | use FireflyIII\Support\Http\Api\AccountFilter; | ||||||
| @@ -62,7 +62,7 @@ class AccountController extends Controller | |||||||
|                 return $next($request); |                 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 |     public function accounts(AutocompleteRequest $request): JsonResponse | ||||||
|     { |     { | ||||||
|         $data            = $request->getData(); |         $data   = $request->getData(); | ||||||
|         $types           = $data['types']; |         $types  = $data['types']; | ||||||
|         $query           = $data['query']; |         $query  = $data['query']; | ||||||
|         $date            = $data['date'] ?? today(config('app.timezone')); |         $date   = $data['date'] ?? today(config('app.timezone')); | ||||||
|         $return          = []; |         $return = []; | ||||||
|         $result          = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit')); |         $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(); |  | ||||||
| 
 | 
 | ||||||
|         /** @var Account $account */ |         /** @var Account $account */ | ||||||
|         foreach ($result as $account) { |         foreach ($result as $account) { | ||||||
|             $nameWithBalance = $account->name; |             $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)) { |             if (in_array($account->accountType->type, $this->balanceTypes, true)) { | ||||||
|                 $balance         = Steam::finalAccountBalance($account, $date); |                 $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( |                 $nameWithBalance = sprintf( | ||||||
|                     '%s (%s)', |                     '%s (%s)', | ||||||
|                     $account->name, |                     $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'                    => $account->name, | ||||||
|                 'name_with_balance'       => $nameWithBalance, |                 'name_with_balance'       => $nameWithBalance, | ||||||
|                 'type'                    => $account->accountType->type, |                 'type'                    => $account->accountType->type, | ||||||
|                 'currency_id'             => (string) $currency->id, |                 'currency_id'             => (string) $useCurrency->id, | ||||||
|                 'currency_name'           => $currency->name, |                 'currency_name'           => $useCurrency->name, | ||||||
|                 'currency_code'           => $currency->code, |                 'currency_code'           => $useCurrency->code, | ||||||
|                 'currency_symbol'         => $currency->symbol, |                 'currency_symbol'         => $useCurrency->symbol, | ||||||
|                 'currency_decimal_places' => $currency->decimal_places, |                 'currency_decimal_places' => $useCurrency->decimal_places, | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @@ -115,7 +115,7 @@ class AccountController extends Controller | |||||||
|         usort( |         usort( | ||||||
|             $return, |             $return, | ||||||
|             static function (array $left, array $right) { |             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); |                 $posA  = (int) array_search($left['type'], $order, true); | ||||||
|                 $posB  = (int) array_search($right['type'], $order, true); |                 $posB  = (int) array_search($right['type'], $order, true); | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -27,9 +27,9 @@ namespace FireflyIII\Api\V1\Controllers\Chart; | |||||||
| use Carbon\Carbon; | use Carbon\Carbon; | ||||||
| use FireflyIII\Api\V1\Controllers\Controller; | use FireflyIII\Api\V1\Controllers\Controller; | ||||||
| use FireflyIII\Api\V1\Requests\Data\DateRequest; | use FireflyIII\Api\V1\Requests\Data\DateRequest; | ||||||
|  | use FireflyIII\Enums\AccountTypeEnum; | ||||||
| use FireflyIII\Exceptions\FireflyException; | use FireflyIII\Exceptions\FireflyException; | ||||||
| use FireflyIII\Models\Account; | use FireflyIII\Models\Account; | ||||||
| use FireflyIII\Models\AccountType; |  | ||||||
| use FireflyIII\Models\Preference; | use FireflyIII\Models\Preference; | ||||||
| use FireflyIII\Repositories\Account\AccountRepositoryInterface; | use FireflyIII\Repositories\Account\AccountRepositoryInterface; | ||||||
| use FireflyIII\Support\Http\Api\ApiSupport; | use FireflyIII\Support\Http\Api\ApiSupport; | ||||||
| @@ -81,11 +81,10 @@ class AccountController extends Controller | |||||||
|         $end        = $dates['end']; |         $end        = $dates['end']; | ||||||
| 
 | 
 | ||||||
|         // user's preferences
 |         // 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 */ |         /** @var Preference $frontpage */ | ||||||
|         $frontpage  = app('preferences')->get('frontpageAccounts', $defaultSet); |         $frontpage  = app('preferences')->get('frontpageAccounts', $defaultSet); | ||||||
|         $default    = app('amount')->getDefaultCurrency(); |  | ||||||
| 
 | 
 | ||||||
|         if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) { |         if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) { | ||||||
|             $frontpage->data = $defaultSet; |             $frontpage->data = $defaultSet; | ||||||
| @@ -98,10 +97,8 @@ class AccountController extends Controller | |||||||
| 
 | 
 | ||||||
|         /** @var Account $account */ |         /** @var Account $account */ | ||||||
|         foreach ($accounts as $account) { |         foreach ($accounts as $account) { | ||||||
|             $currency     = $this->repository->getAccountCurrency($account); |             $currency     = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency; | ||||||
|             if (null === $currency) { |             $field        = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance'; | ||||||
|                 $currency = $default; |  | ||||||
|             } |  | ||||||
|             $currentSet   = [ |             $currentSet   = [ | ||||||
|                 'label'                   => $account->name, |                 'label'                   => $account->name, | ||||||
|                 'currency_id'             => (string) $currency->id, |                 '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.
 |             // TODO this code is also present in the V2 chart account controller so this method is due to be deprecated.
 | ||||||
|             $currentStart = clone $start; |             $currentStart = clone $start; | ||||||
|             $range        = app('steam')->finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative); |             $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][$field]; | ||||||
|             $previous     = array_values($range)[0]; |  | ||||||
|             while ($currentStart <= $end) { |             while ($currentStart <= $end) { | ||||||
|                 $format                        = $currentStart->format('Y-m-d'); |                 $format                        = $currentStart->format('Y-m-d'); | ||||||
|                 $label                         = $currentStart->toAtomString(); |                 $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; |                 $previous                      = $balance; | ||||||
|                 $currentStart->addDay(); |                 $currentStart->addDay(); | ||||||
|                 $currentSet['entries'][$label] = $balance; |                 $currentSet['entries'][$label] = $balance; | ||||||
|   | |||||||
| @@ -28,6 +28,9 @@ use Carbon\Carbon; | |||||||
| use Carbon\Exceptions\InvalidDateException; | use Carbon\Exceptions\InvalidDateException; | ||||||
| use Carbon\Exceptions\InvalidFormatException; | use Carbon\Exceptions\InvalidFormatException; | ||||||
| use FireflyIII\Models\Preference; | use FireflyIII\Models\Preference; | ||||||
|  | use FireflyIII\Models\TransactionCurrency; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
|  | use FireflyIII\Support\Facades\Steam; | ||||||
| use FireflyIII\User; | use FireflyIII\User; | ||||||
| use Illuminate\Foundation\Auth\Access\AuthorizesRequests; | use Illuminate\Foundation\Auth\Access\AuthorizesRequests; | ||||||
| use Illuminate\Foundation\Bus\DispatchesJobs; | use Illuminate\Foundation\Bus\DispatchesJobs; | ||||||
| @@ -56,6 +59,7 @@ abstract class Controller extends BaseController | |||||||
|     protected array        $allowedSort; |     protected array        $allowedSort; | ||||||
|     protected ParameterBag $parameters; |     protected ParameterBag $parameters; | ||||||
|     protected bool        $convertToNative = false; |     protected bool        $convertToNative = false; | ||||||
|  |     protected TransactionCurrency $defaultCurrency; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Controller constructor. |      * Controller constructor. | ||||||
| @@ -68,8 +72,9 @@ abstract class Controller extends BaseController | |||||||
|             function ($request, $next) { |             function ($request, $next) { | ||||||
|                 $this->parameters = $this->getParameters(); |                 $this->parameters = $this->getParameters(); | ||||||
|                 if (auth()->check()) { |                 if (auth()->check()) { | ||||||
|                     $language              = app('steam')->getLanguage(); |                     $language              = Steam::getLanguage(); | ||||||
|                     $this->convertToNative = app('preferences')->get('convert_to_native', false)->data; |                     $this->convertToNative = Amount::convertToNative(); | ||||||
|  |                     $this->defaultCurrency = Amount::getDefaultCurrency(); | ||||||
|                     app()->setLocale($language); |                     app()->setLocale($language); | ||||||
| 
 | 
 | ||||||
|                 } |                 } | ||||||
|   | |||||||
| @@ -26,10 +26,10 @@ namespace FireflyIII\Api\V1\Controllers\Data; | |||||||
| 
 | 
 | ||||||
| use FireflyIII\Api\V1\Controllers\Controller; | use FireflyIII\Api\V1\Controllers\Controller; | ||||||
| use FireflyIII\Api\V1\Requests\Data\DestroyRequest; | use FireflyIII\Api\V1\Requests\Data\DestroyRequest; | ||||||
|  | use FireflyIII\Enums\AccountTypeEnum; | ||||||
| use FireflyIII\Enums\TransactionTypeEnum; | use FireflyIII\Enums\TransactionTypeEnum; | ||||||
| use FireflyIII\Exceptions\FireflyException; | use FireflyIII\Exceptions\FireflyException; | ||||||
| use FireflyIII\Models\Account; | use FireflyIII\Models\Account; | ||||||
| use FireflyIII\Models\AccountType; |  | ||||||
| use FireflyIII\Models\TransactionJournal; | use FireflyIII\Models\TransactionJournal; | ||||||
| use FireflyIII\Repositories\Account\AccountRepositoryInterface; | use FireflyIII\Repositories\Account\AccountRepositoryInterface; | ||||||
| use FireflyIII\Repositories\Bill\BillRepositoryInterface; | use FireflyIII\Repositories\Bill\BillRepositoryInterface; | ||||||
| @@ -66,9 +66,9 @@ class DestroyController extends Controller | |||||||
|         $objects         = $request->getObjects(); |         $objects         = $request->getObjects(); | ||||||
|         $this->unused    = $request->boolean('unused', false); |         $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]; |         $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             = [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]; |         $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     = [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD]; |         $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]; |         $transactions    = [TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::TRANSFER->value, TransactionTypeEnum::RECONCILIATION->value]; | ||||||
| 
 | 
 | ||||||
|         match ($objects) { |         match ($objects) { | ||||||
| @@ -82,9 +82,9 @@ class DestroyController extends Controller | |||||||
|             'object_groups'          => $this->destroyObjectGroups(), |             'object_groups'          => $this->destroyObjectGroups(), | ||||||
|             'not_assets_liabilities' => $this->destroyAccounts($allExceptAssets), |             'not_assets_liabilities' => $this->destroyAccounts($allExceptAssets), | ||||||
|             'accounts'               => $this->destroyAccounts($all), |             'accounts'               => $this->destroyAccounts($all), | ||||||
|             'asset_accounts'         => $this->destroyAccounts([AccountType::ASSET, AccountType::DEFAULT]), |             'asset_accounts'         => $this->destroyAccounts([AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]), | ||||||
|             'expense_accounts'       => $this->destroyAccounts([AccountType::BENEFICIARY, AccountType::EXPENSE]), |             'expense_accounts'       => $this->destroyAccounts([AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::EXPENSE->value]), | ||||||
|             'revenue_accounts'       => $this->destroyAccounts([AccountType::REVENUE]), |             'revenue_accounts'       => $this->destroyAccounts([AccountTypeEnum::REVENUE->value]), | ||||||
|             'liabilities'            => $this->destroyAccounts($liabilities), |             'liabilities'            => $this->destroyAccounts($liabilities), | ||||||
|             'transactions'           => $this->destroyTransactions($transactions), |             'transactions'           => $this->destroyTransactions($transactions), | ||||||
|             'withdrawals'            => $this->destroyTransactions([TransactionTypeEnum::WITHDRAWAL->value]), |             'withdrawals'            => $this->destroyTransactions([TransactionTypeEnum::WITHDRAWAL->value]), | ||||||
|   | |||||||
| @@ -29,7 +29,9 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest; | |||||||
| use FireflyIII\Enums\TransactionTypeEnum; | use FireflyIII\Enums\TransactionTypeEnum; | ||||||
| use FireflyIII\Helpers\Collector\GroupCollectorInterface; | use FireflyIII\Helpers\Collector\GroupCollectorInterface; | ||||||
| use FireflyIII\Repositories\Bill\BillRepositoryInterface; | use FireflyIII\Repositories\Bill\BillRepositoryInterface; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
|  | use Illuminate\Support\Facades\Log; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Class BillController |  * Class BillController | ||||||
| @@ -63,11 +65,13 @@ class BillController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function bill(GenericRequest $request): JsonResponse |     public function bill(GenericRequest $request): JsonResponse | ||||||
|     { |     { | ||||||
|         $accounts   = $request->getAssetAccounts(); |         $accounts        = $request->getAssetAccounts(); | ||||||
|         $bills      = $request->getBills(); |         $bills           = $request->getBills(); | ||||||
|         $start      = $request->getStart(); |         $start           = $request->getStart(); | ||||||
|         $end        = $request->getEnd(); |         $end             = $request->getEnd(); | ||||||
|         $response   = []; |         $convertToNative = Amount::convertToNative(); | ||||||
|  |         $default         = Amount::getDefaultCurrency(); | ||||||
|  |         $response        = []; | ||||||
| 
 | 
 | ||||||
|         // get all bills:
 |         // get all bills:
 | ||||||
|         if (0 === $bills->count()) { |         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.
 |         // 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->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts); | ||||||
|         $collector->setBills($bills); |         $collector->setBills($bills); | ||||||
| 
 | 
 | ||||||
|         $genericSet = $collector->getExtractedJournals(); |         $genericSet      = $collector->getExtractedJournals(); | ||||||
|         foreach ($genericSet as $journal) { |         foreach ($genericSet as $journal) { | ||||||
|             $billId            = (int) $journal['bill_id']; |             $billId       = (int) $journal['bill_id']; | ||||||
|             $currencyId        = (int) $journal['currency_id']; |             $currencyId   = (int) $journal['currency_id']; | ||||||
|             $foreignCurrencyId = (int) $journal['foreign_currency_id']; |             $currencyCode = $journal['currency_code']; | ||||||
|             $key               = sprintf('%d-%d', $billId, $currencyId); |             $field        = 'amount'; | ||||||
|             $foreignKey        = sprintf('%d-%d', $billId, $foreignCurrencyId); | 
 | ||||||
|  |             // 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) { |             if (0 !== $currencyId) { | ||||||
|                 $response[$key] ??= [ |                 $response[$key] ??= [ | ||||||
| @@ -94,21 +111,11 @@ class BillController extends Controller | |||||||
|                     'difference'       => '0', |                     'difference'       => '0', | ||||||
|                     'difference_float' => 0, |                     'difference_float' => 0, | ||||||
|                     'currency_id'      => (string) $currencyId, |                     '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
 |                 $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)); |         return response()->json(array_values($response)); | ||||||
| @@ -122,42 +129,47 @@ class BillController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function noBill(GenericRequest $request): JsonResponse |     public function noBill(GenericRequest $request): JsonResponse | ||||||
|     { |     { | ||||||
|         $accounts   = $request->getAssetAccounts(); |         $accounts        = $request->getAssetAccounts(); | ||||||
|         $start      = $request->getStart(); |         $start           = $request->getStart(); | ||||||
|         $end        = $request->getEnd(); |         $end             = $request->getEnd(); | ||||||
|         $response   = []; |         $convertToNative = Amount::convertToNative(); | ||||||
|  |         $default         = Amount::getDefaultCurrency(); | ||||||
|  |         $response        = []; | ||||||
| 
 | 
 | ||||||
|         // collect all expenses in this period (regardless of type) by the given bills and accounts.
 |         // 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->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts); | ||||||
|         $collector->withoutBill(); |         $collector->withoutBill(); | ||||||
| 
 | 
 | ||||||
|         $genericSet = $collector->getExtractedJournals(); |         $genericSet      = $collector->getExtractedJournals(); | ||||||
| 
 | 
 | ||||||
|         foreach ($genericSet as $journal) { |         foreach ($genericSet as $journal) { | ||||||
|             $currencyId        = (int) $journal['currency_id']; |             $currencyId   = (int) $journal['currency_id']; | ||||||
|             $foreignCurrencyId = (int) $journal['foreign_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) { |             if (0 !== $currencyId) { | ||||||
|                 $response[$currencyId] ??= [ |                 $response[$currencyId] ??= [ | ||||||
|                     'difference'       => '0', |                     'difference'       => '0', | ||||||
|                     'difference_float' => 0, |                     'difference_float' => 0, | ||||||
|                     'currency_id'      => (string) $currencyId, |                     '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
 |                 $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)); |         return response()->json(array_values($response)); | ||||||
|   | |||||||
| @@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller; | |||||||
| use FireflyIII\Api\V1\Requests\Insight\GenericRequest; | use FireflyIII\Api\V1\Requests\Insight\GenericRequest; | ||||||
| use FireflyIII\Enums\TransactionTypeEnum; | use FireflyIII\Enums\TransactionTypeEnum; | ||||||
| use FireflyIII\Helpers\Collector\GroupCollectorInterface; | use FireflyIII\Helpers\Collector\GroupCollectorInterface; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
|  | use Illuminate\Support\Facades\Log; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Class PeriodController |  * Class PeriodController | ||||||
| @@ -41,39 +43,49 @@ class PeriodController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function total(GenericRequest $request): JsonResponse |     public function total(GenericRequest $request): JsonResponse | ||||||
|     { |     { | ||||||
|         $accounts   = $request->getAssetAccounts(); |         $accounts        = $request->getAssetAccounts(); | ||||||
|         $start      = $request->getStart(); |         $start           = $request->getStart(); | ||||||
|         $end        = $request->getEnd(); |         $end             = $request->getEnd(); | ||||||
|         $response   = []; |         $response        = []; | ||||||
|  |         $convertToNative = Amount::convertToNative(); | ||||||
|  |         $default         = Amount::getDefaultCurrency(); | ||||||
| 
 | 
 | ||||||
|         // collect all expenses in this period (regardless of type)
 |         // 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); |         $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts); | ||||||
|         $genericSet = $collector->getExtractedJournals(); |         $genericSet      = $collector->getExtractedJournals(); | ||||||
|         foreach ($genericSet as $journal) { |         foreach ($genericSet as $journal) { | ||||||
|             $currencyId        = (int) $journal['currency_id']; |             // same code as many other sumExpense methods. I think this needs some kind of generic method.
 | ||||||
|             $foreignCurrencyId = (int) $journal['foreign_currency_id']; |             $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] ??= [ |             $response[$currencyId] ??= [ | ||||||
|                     'difference'       => '0', |                 'difference'       => '0', | ||||||
|                     'difference_float' => 0, |                 'difference_float' => 0, | ||||||
|                     'currency_id'      => (string) $currencyId, |                 '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'], $amount); | ||||||
|                 $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // intentional float
 |             $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)); |         return response()->json(array_values($response)); | ||||||
|   | |||||||
| @@ -29,7 +29,9 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest; | |||||||
| use FireflyIII\Enums\TransactionTypeEnum; | use FireflyIII\Enums\TransactionTypeEnum; | ||||||
| use FireflyIII\Helpers\Collector\GroupCollectorInterface; | use FireflyIII\Helpers\Collector\GroupCollectorInterface; | ||||||
| use FireflyIII\Repositories\Tag\TagRepositoryInterface; | use FireflyIII\Repositories\Tag\TagRepositoryInterface; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
|  | use Illuminate\Support\Facades\Log; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Class TagController |  * Class TagController | ||||||
| @@ -62,42 +64,51 @@ class TagController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function noTag(GenericRequest $request): JsonResponse |     public function noTag(GenericRequest $request): JsonResponse | ||||||
|     { |     { | ||||||
|         $accounts   = $request->getAssetAccounts(); |         $accounts        = $request->getAssetAccounts(); | ||||||
|         $start      = $request->getStart(); |         $start           = $request->getStart(); | ||||||
|         $end        = $request->getEnd(); |         $end             = $request->getEnd(); | ||||||
|         $response   = []; |         $response        = []; | ||||||
|  |         $convertToNative = Amount::convertToNative(); | ||||||
|  |         $default         = Amount::getDefaultCurrency(); | ||||||
| 
 | 
 | ||||||
|         // collect all expenses in this period (regardless of type) by the given bills and accounts.
 |         // 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->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts); | ||||||
|         $collector->withoutTags(); |         $collector->withoutTags(); | ||||||
| 
 | 
 | ||||||
|         $genericSet = $collector->getExtractedJournals(); |         $genericSet      = $collector->getExtractedJournals(); | ||||||
| 
 | 
 | ||||||
|         foreach ($genericSet as $journal) { |         foreach ($genericSet as $journal) { | ||||||
|             $currencyId        = (int) $journal['currency_id']; |             // same code as many other sumExpense methods. I think this needs some kind of generic method.
 | ||||||
|             $foreignCurrencyId = (int) $journal['foreign_currency_id']; |             $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] ??= [ | ||||||
|                 $response[$currencyId] ??= [ |                 'difference'       => '0', | ||||||
|                     'difference'       => '0', |                 'difference_float' => 0, | ||||||
|                     'difference_float' => 0, |                 'currency_id'      => (string) $currencyId, | ||||||
|                     'currency_id'      => (string) $currencyId, |                 'currency_code'    => $currencyCode, | ||||||
|                     'currency_code'    => $journal['currency_code'], |             ]; | ||||||
|                 ]; |             $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], $amount); | ||||||
|                 $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], $journal['amount']); |             $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
 | ||||||
|                 $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.
 |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return response()->json(array_values($response)); |         return response()->json(array_values($response)); | ||||||
|   | |||||||
| @@ -73,6 +73,7 @@ class AccountController extends Controller | |||||||
|         $start         = $request->getStart(); |         $start         = $request->getStart(); | ||||||
|         $end           = $request->getEnd(); |         $end           = $request->getEnd(); | ||||||
|         $assetAccounts = $request->getAssetAccounts(); |         $assetAccounts = $request->getAssetAccounts(); | ||||||
|  | 
 | ||||||
|         $income        = $this->opsRepository->sumIncomeByDestination($start, $end, $assetAccounts); |         $income        = $this->opsRepository->sumIncomeByDestination($start, $end, $assetAccounts); | ||||||
|         $result        = []; |         $result        = []; | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller; | |||||||
| use FireflyIII\Api\V1\Requests\Insight\GenericRequest; | use FireflyIII\Api\V1\Requests\Insight\GenericRequest; | ||||||
| use FireflyIII\Enums\TransactionTypeEnum; | use FireflyIII\Enums\TransactionTypeEnum; | ||||||
| use FireflyIII\Helpers\Collector\GroupCollectorInterface; | use FireflyIII\Helpers\Collector\GroupCollectorInterface; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @@ -41,42 +42,41 @@ class PeriodController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function total(GenericRequest $request): JsonResponse |     public function total(GenericRequest $request): JsonResponse | ||||||
|     { |     { | ||||||
|         $accounts   = $request->getAssetAccounts(); |         $accounts        = $request->getAssetAccounts(); | ||||||
|         $start      = $request->getStart(); |         $start           = $request->getStart(); | ||||||
|         $end        = $request->getEnd(); |         $end             = $request->getEnd(); | ||||||
|         $response   = []; |         $response        = []; | ||||||
|  |         $convertToNative = Amount::convertToNative(); | ||||||
|  |         $default         = Amount::getDefaultCurrency(); | ||||||
| 
 | 
 | ||||||
|         // collect all expenses in this period (regardless of type)
 |         // 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); |         $collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts); | ||||||
|         $genericSet = $collector->getExtractedJournals(); |         $genericSet      = $collector->getExtractedJournals(); | ||||||
|         foreach ($genericSet as $journal) { |         foreach ($genericSet as $journal) { | ||||||
|             $currencyId        = (int) $journal['currency_id']; |             // currency
 | ||||||
|             $foreignCurrencyId = (int) $journal['foreign_currency_id']; |             $currencyId                                = $journal['currency_id']; | ||||||
|  |             $currencyCode                              = $journal['currency_code']; | ||||||
|  |             $field                                     = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount'; | ||||||
| 
 | 
 | ||||||
|             if (0 !== $currencyId) { |             // perhaps use default currency instead?
 | ||||||
|                 $response[$currencyId] ??= [ |             if ($convertToNative && $journal['currency_id'] !== $default->id) { | ||||||
|                     'difference'       => '0', |                 $currencyId   = $default->id; | ||||||
|                     'difference_float' => 0, |                 $currencyCode = $default->code; | ||||||
|                     '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.
 |  | ||||||
|             } |             } | ||||||
|             if (0 !== $foreignCurrencyId) { |             // use foreign amount when the foreign currency IS the default currency.
 | ||||||
|                 $response[$foreignCurrencyId] ??= [ |             if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) { | ||||||
|                     'difference'       => '0', |                 $field = 'foreign_amount'; | ||||||
|                     '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.
 |  | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             $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)); |         return response()->json(array_values($response)); | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest; | |||||||
| use FireflyIII\Enums\TransactionTypeEnum; | use FireflyIII\Enums\TransactionTypeEnum; | ||||||
| use FireflyIII\Helpers\Collector\GroupCollectorInterface; | use FireflyIII\Helpers\Collector\GroupCollectorInterface; | ||||||
| use FireflyIII\Repositories\Tag\TagRepositoryInterface; | use FireflyIII\Repositories\Tag\TagRepositoryInterface; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @@ -63,45 +64,45 @@ class TagController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function noTag(GenericRequest $request): JsonResponse |     public function noTag(GenericRequest $request): JsonResponse | ||||||
|     { |     { | ||||||
|         $accounts   = $request->getAssetAccounts(); |         $accounts        = $request->getAssetAccounts(); | ||||||
|         $start      = $request->getStart(); |         $start           = $request->getStart(); | ||||||
|         $end        = $request->getEnd(); |         $end             = $request->getEnd(); | ||||||
|         $response   = []; |         $response        = []; | ||||||
|  |         $convertToNative = Amount::convertToNative(); | ||||||
|  |         $default         = Amount::getDefaultCurrency(); | ||||||
| 
 | 
 | ||||||
|         // collect all expenses in this period (regardless of type) by the given bills and accounts.
 |         // 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->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts); | ||||||
|         $collector->withoutTags(); |         $collector->withoutTags(); | ||||||
| 
 | 
 | ||||||
|         $genericSet = $collector->getExtractedJournals(); |         $genericSet      = $collector->getExtractedJournals(); | ||||||
| 
 | 
 | ||||||
|         foreach ($genericSet as $journal) { |         foreach ($genericSet as $journal) { | ||||||
|             $currencyId        = (int) $journal['currency_id']; |             // currency
 | ||||||
|             $foreignCurrencyId = (int) $journal['foreign_currency_id']; |             $currencyId                                = $journal['currency_id']; | ||||||
|  |             $currencyCode                              = $journal['currency_code']; | ||||||
|  |             $field                                     = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount'; | ||||||
| 
 | 
 | ||||||
|             if (0 !== $currencyId) { |             // perhaps use default currency instead?
 | ||||||
|                 $response[$currencyId] ??= [ |             if ($convertToNative && $journal['currency_id'] !== $default->id) { | ||||||
|                     'difference'       => '0', |                 $currencyId   = $default->id; | ||||||
|                     'difference_float' => 0, |                 $currencyCode = $default->code; | ||||||
|                     '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']; |  | ||||||
|             } |             } | ||||||
|             if (0 !== $foreignCurrencyId) { |             // use foreign amount when the foreign currency IS the default currency.
 | ||||||
|                 $response[$foreignCurrencyId] ??= [ |             if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) { | ||||||
|                     'difference'       => '0', |                 $field = 'foreign_amount'; | ||||||
|                     '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']; |  | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             $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)); |         return response()->json(array_values($response)); | ||||||
|   | |||||||
| @@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller; | |||||||
| use FireflyIII\Api\V1\Requests\Insight\GenericRequest; | use FireflyIII\Api\V1\Requests\Insight\GenericRequest; | ||||||
| use FireflyIII\Helpers\Collector\GroupCollectorInterface; | use FireflyIII\Helpers\Collector\GroupCollectorInterface; | ||||||
| use FireflyIII\Models\TransactionType; | use FireflyIII\Models\TransactionType; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @@ -41,42 +42,42 @@ class PeriodController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function total(GenericRequest $request): JsonResponse |     public function total(GenericRequest $request): JsonResponse | ||||||
|     { |     { | ||||||
|         $accounts   = $request->getAssetAccounts(); |         $accounts        = $request->getAssetAccounts(); | ||||||
|         $start      = $request->getStart(); |         $start           = $request->getStart(); | ||||||
|         $end        = $request->getEnd(); |         $end             = $request->getEnd(); | ||||||
|         $response   = []; |         $response        = []; | ||||||
|  |         $convertToNative = Amount::convertToNative(); | ||||||
|  |         $default         = Amount::getDefaultCurrency(); | ||||||
| 
 | 
 | ||||||
|         // collect all expenses in this period (regardless of type)
 |         // 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); |         $collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts); | ||||||
|         $genericSet = $collector->getExtractedJournals(); |         $genericSet      = $collector->getExtractedJournals(); | ||||||
|         foreach ($genericSet as $journal) { |         foreach ($genericSet as $journal) { | ||||||
|             $currencyId        = (int) $journal['currency_id']; |             // currency
 | ||||||
|             $foreignCurrencyId = (int) $journal['foreign_currency_id']; |             $currencyId                                = $journal['currency_id']; | ||||||
|  |             $currencyCode                              = $journal['currency_code']; | ||||||
|  |             $field                                     = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount'; | ||||||
| 
 | 
 | ||||||
|             if (0 !== $currencyId) { |             // perhaps use default currency instead?
 | ||||||
|                 $response[$currencyId] ??= [ |             if ($convertToNative && $journal['currency_id'] !== $default->id) { | ||||||
|                     'difference'       => '0', |                 $currencyId   = $default->id; | ||||||
|                     'difference_float' => 0, |                 $currencyCode = $default->code; | ||||||
|                     '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']; |  | ||||||
|             } |             } | ||||||
|             if (0 !== $foreignCurrencyId) { |             // use foreign amount when the foreign currency IS the default currency.
 | ||||||
|                 $response[$foreignCurrencyId] ??= [ |             if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) { | ||||||
|                     'difference'       => '0', |                 $field = 'foreign_amount'; | ||||||
|                     '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']; |  | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             $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)); |         return response()->json(array_values($response)); | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest; | |||||||
| use FireflyIII\Helpers\Collector\GroupCollectorInterface; | use FireflyIII\Helpers\Collector\GroupCollectorInterface; | ||||||
| use FireflyIII\Models\TransactionType; | use FireflyIII\Models\TransactionType; | ||||||
| use FireflyIII\Repositories\Tag\TagRepositoryInterface; | use FireflyIII\Repositories\Tag\TagRepositoryInterface; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @@ -61,45 +62,46 @@ class TagController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function noTag(GenericRequest $request): JsonResponse |     public function noTag(GenericRequest $request): JsonResponse | ||||||
|     { |     { | ||||||
|         $accounts   = $request->getAssetAccounts(); |         $accounts        = $request->getAssetAccounts(); | ||||||
|         $start      = $request->getStart(); |         $start           = $request->getStart(); | ||||||
|         $end        = $request->getEnd(); |         $end             = $request->getEnd(); | ||||||
|         $response   = []; |         $response        = []; | ||||||
|  |         $convertToNative = Amount::convertToNative(); | ||||||
|  |         $default         = Amount::getDefaultCurrency(); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|         // collect all expenses in this period (regardless of type) by the given bills and accounts.
 |         // 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->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts); | ||||||
|         $collector->withoutTags(); |         $collector->withoutTags(); | ||||||
| 
 | 
 | ||||||
|         $genericSet = $collector->getExtractedJournals(); |         $genericSet      = $collector->getExtractedJournals(); | ||||||
| 
 | 
 | ||||||
|         foreach ($genericSet as $journal) { |         foreach ($genericSet as $journal) { | ||||||
|             $currencyId        = (int) $journal['currency_id']; |             // currency
 | ||||||
|             $foreignCurrencyId = (int) $journal['foreign_currency_id']; |             $currencyId                                = $journal['currency_id']; | ||||||
|  |             $currencyCode                              = $journal['currency_code']; | ||||||
|  |             $field                                     = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount'; | ||||||
| 
 | 
 | ||||||
|             if (0 !== $currencyId) { |             // perhaps use default currency instead?
 | ||||||
|                 $response[$currencyId] ??= [ |             if ($convertToNative && $journal['currency_id'] !== $default->id) { | ||||||
|                     'difference'       => '0', |                 $currencyId   = $default->id; | ||||||
|                     'difference_float' => 0, |                 $currencyCode = $default->code; | ||||||
|                     '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']; |  | ||||||
|             } |             } | ||||||
|             if (0 !== $foreignCurrencyId) { |             // use foreign amount when the foreign currency IS the default currency.
 | ||||||
|                 $response[$foreignCurrencyId] ??= [ |             if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) { | ||||||
|                     'difference'       => '0', |                 $field = 'foreign_amount'; | ||||||
|                     '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']; |  | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             $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)); |         return response()->json(array_values($response)); | ||||||
|   | |||||||
| @@ -105,19 +105,18 @@ class ShowController extends Controller | |||||||
|     public function show(TransactionCurrency $currency): JsonResponse |     public function show(TransactionCurrency $currency): JsonResponse | ||||||
|     { |     { | ||||||
|         /** @var User $user */ |         /** @var User $user */ | ||||||
|         $user            = auth()->user(); |         $user        = auth()->user(); | ||||||
|         $manager         = $this->getManager(); |         $manager     = $this->getManager(); | ||||||
|         $defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup); |         $this->parameters->set('defaultCurrency', $this->defaultCurrency); | ||||||
|         $this->parameters->set('defaultCurrency', $defaultCurrency); |  | ||||||
| 
 | 
 | ||||||
|         // update fields with user info.
 |         // update fields with user info.
 | ||||||
|         $currency->refreshForUser($user); |         $currency->refreshForUser($user); | ||||||
| 
 | 
 | ||||||
|         /** @var CurrencyTransformer $transformer */ |         /** @var CurrencyTransformer $transformer */ | ||||||
|         $transformer     = app(CurrencyTransformer::class); |         $transformer = app(CurrencyTransformer::class); | ||||||
|         $transformer->setParameters($this->parameters); |         $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); |         return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); | ||||||
|     } |     } | ||||||
| @@ -135,7 +134,7 @@ class ShowController extends Controller | |||||||
|         /** @var User $user */ |         /** @var User $user */ | ||||||
|         $user        = auth()->user(); |         $user        = auth()->user(); | ||||||
|         $manager     = $this->getManager(); |         $manager     = $this->getManager(); | ||||||
|         $currency    = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup); |         $currency    = $this->defaultCurrency; | ||||||
| 
 | 
 | ||||||
|         // update fields with user info.
 |         // update fields with user info.
 | ||||||
|         $currency->refreshForUser($user); |         $currency->refreshForUser($user); | ||||||
|   | |||||||
| @@ -103,10 +103,10 @@ class BasicController extends Controller | |||||||
|         $billData     = $this->getBillInformation($start, $end); |         $billData     = $this->getBillInformation($start, $end); | ||||||
|         $spentData    = $this->getLeftToSpendInfo($start, $end); |         $spentData    = $this->getLeftToSpendInfo($start, $end); | ||||||
|         $netWorthData = $this->getNetWorthInfo($start, $end); |         $netWorthData = $this->getNetWorthInfo($start, $end); | ||||||
|         //        $balanceData  = [];
 |         //                $balanceData  = [];
 | ||||||
|         //        $billData     = [];
 |         //                $billData     = [];
 | ||||||
|         //        $spentData    = [];
 |         //                $spentData    = [];
 | ||||||
|         //        $netWorthData = [];
 |         //                $netWorthData = [];
 | ||||||
|         $total        = array_merge($balanceData, $billData, $spentData, $netWorthData); |         $total        = array_merge($balanceData, $billData, $spentData, $netWorthData); | ||||||
| 
 | 
 | ||||||
|         // give new keys
 |         // give new keys
 | ||||||
| @@ -123,8 +123,8 @@ class BasicController extends Controller | |||||||
|     private function getBalanceInformation(Carbon $start, Carbon $end): array |     private function getBalanceInformation(Carbon $start, Carbon $end): array | ||||||
|     { |     { | ||||||
|         // some config settings
 |         // some config settings
 | ||||||
|         $convertToNative = app('preferences')->get('convert_to_native', false)->data; |         $convertToNative = Amount::convertToNative(); | ||||||
|         $default         = app('amount')->getDefaultCurrency(); |         $default         = Amount::getDefaultCurrency(); | ||||||
|         // prep some arrays:
 |         // prep some arrays:
 | ||||||
|         $incomes         = []; |         $incomes         = []; | ||||||
|         $expenses        = []; |         $expenses        = []; | ||||||
| @@ -276,13 +276,13 @@ class BasicController extends Controller | |||||||
|      */ |      */ | ||||||
|     private function getLeftToSpendInfo(Carbon $start, Carbon $end): array |     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    = []; |         $return    = []; | ||||||
|         $today     = today(config('app.timezone')); |         $today     = today(config('app.timezone')); | ||||||
|         $available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end); |         $available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end); | ||||||
|         $budgets   = $this->budgetRepository->getActiveBudgets(); |         $budgets   = $this->budgetRepository->getActiveBudgets(); | ||||||
|         $spent     = $this->opsRepository->sumExpenses($start, $end, null, $budgets); |         $spent     = $this->opsRepository->sumExpenses($start, $end, null, $budgets); | ||||||
|         $days      = (int) $today->diffInDays($end, true) + 1; |         $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) { |         foreach ($spent as $row) { | ||||||
|             // either an amount was budgeted or 0 is available.
 |             // either an amount was budgeted or 0 is available.
 | ||||||
|   | |||||||
| @@ -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);
 |  | ||||||
|     //    }
 |  | ||||||
| } |  | ||||||
| @@ -25,7 +25,6 @@ declare(strict_types=1); | |||||||
| namespace FireflyIII\Api\V2\Request\Chart; | namespace FireflyIII\Api\V2\Request\Chart; | ||||||
| 
 | 
 | ||||||
| use FireflyIII\Enums\UserRoleEnum; | use FireflyIII\Enums\UserRoleEnum; | ||||||
| use FireflyIII\Support\Http\Api\ParsesQueryFilters; |  | ||||||
| use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait; | use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait; | ||||||
| use FireflyIII\Support\Request\ChecksLogin; | use FireflyIII\Support\Request\ChecksLogin; | ||||||
| use FireflyIII\Support\Request\ConvertsDataTypes; | use FireflyIII\Support\Request\ConvertsDataTypes; | ||||||
| @@ -40,7 +39,6 @@ class ChartRequest extends FormRequest | |||||||
| { | { | ||||||
|     use ChecksLogin; |     use ChecksLogin; | ||||||
|     use ConvertsDataTypes; |     use ConvertsDataTypes; | ||||||
|     use ParsesQueryFilters; |  | ||||||
|     use ValidatesUserGroupTrait; |     use ValidatesUserGroupTrait; | ||||||
| 
 | 
 | ||||||
|     protected array $acceptedRoles = [UserRoleEnum::READ_ONLY]; |     protected array $acceptedRoles = [UserRoleEnum::READ_ONLY]; | ||||||
|   | |||||||
| @@ -74,7 +74,7 @@ class CorrectsDatabase extends Command | |||||||
|             'correction:recalculates-liabilities', |             'correction:recalculates-liabilities', | ||||||
|             'correction:preferences', |             'correction:preferences', | ||||||
|             // 'correction:transaction-types', // resource heavy, disabled.
 |             // 'correction:transaction-types', // resource heavy, disabled.
 | ||||||
|             // 'correction:recalculate-native-amounts', // not necessary, disabled.
 |             'correction:recalculate-native-amounts', // not necessary, disabled.
 | ||||||
|             'firefly-iii:report-integrity', |             'firefly-iii:report-integrity', | ||||||
|         ]; |         ]; | ||||||
|         foreach ($commands as $command) { |         foreach ($commands as $command) { | ||||||
|   | |||||||
| @@ -59,6 +59,11 @@ class CorrectsNativeAmounts extends Command | |||||||
|      */ |      */ | ||||||
|     public function handle(): int |     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.'); |         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!'); |         $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) { |             foreach ($piggyBank->accounts as $account) { | ||||||
|                 $account->pivot->native_current_amount = null; |                 $account->pivot->native_current_amount = null; | ||||||
|                 if (0 !== bccomp($account->pivot->current_amount, '0')) { |                 if (0 !== bccomp((string) $account->pivot->current_amount, '0')) { | ||||||
|                     $account->pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $currency, today(), $account->pivot->current_amount); |                     $account->pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $currency, today(), (string) $account->pivot->current_amount); | ||||||
|                 } |                 } | ||||||
|                 $account->pivot->save(); |                 $account->pivot->save(); | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -45,7 +45,6 @@ class ReportsIntegrity extends Command | |||||||
|             return 1; |             return 1; | ||||||
|         } |         } | ||||||
|         $commands = [ |         $commands = [ | ||||||
|             // 'firefly-iii:add-timezones-to-dates',
 |  | ||||||
|             'integrity:empty-objects', |             'integrity:empty-objects', | ||||||
|             'integrity:total-sums', |             'integrity:total-sums', | ||||||
|         ]; |         ]; | ||||||
|   | |||||||
| @@ -76,9 +76,6 @@ class AddsTransactionIdentifiers extends Command | |||||||
|             $this->updateJournalIdentifiers($journal); |             $this->updateJournalIdentifiers($journal); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (0 === $this->count) { |  | ||||||
|             $this->friendlyPositive('All split journal transaction identifiers are OK.'); |  | ||||||
|         } |  | ||||||
|         if (0 !== $this->count) { |         if (0 !== $this->count) { | ||||||
|             $this->friendlyInfo(sprintf('Fixed %d split journal transaction identifier(s).', $this->count)); |             $this->friendlyInfo(sprintf('Fixed %d split journal transaction identifier(s).', $this->count)); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -70,7 +70,6 @@ class RemovesDatabaseDecryption extends Command | |||||||
|     private function decryptTable(string $table, array $fields): void |     private function decryptTable(string $table, array $fields): void | ||||||
|     { |     { | ||||||
|         if ($this->isDecrypted($table)) { |         if ($this->isDecrypted($table)) { | ||||||
|             $this->friendlyInfo(sprintf('No decryption required for table "%s".', $table)); |  | ||||||
| 
 | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -62,9 +62,6 @@ class UpgradesAccountCurrencies extends Command | |||||||
|         } |         } | ||||||
|         $this->updateAccountCurrencies(); |         $this->updateAccountCurrencies(); | ||||||
| 
 | 
 | ||||||
|         if (0 === $this->count) { |  | ||||||
|             $this->friendlyPositive('All account currencies are OK.'); |  | ||||||
|         } |  | ||||||
|         if (0 !== $this->count) { |         if (0 !== $this->count) { | ||||||
|             $this->friendlyInfo(sprintf('Corrected %d account(s).', $this->count)); |             $this->friendlyInfo(sprintf('Corrected %d account(s).', $this->count)); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -73,9 +73,6 @@ class UpgradesAccountMetaData extends Command | |||||||
| 
 | 
 | ||||||
|         $this->markAsExecuted(); |         $this->markAsExecuted(); | ||||||
| 
 | 
 | ||||||
|         if (0 === $count) { |  | ||||||
|             $this->friendlyPositive('All account meta is OK.'); |  | ||||||
|         } |  | ||||||
|         if (0 !== $count) { |         if (0 !== $count) { | ||||||
|             $this->friendlyInfo(sprintf('Renamed %d account meta entries (entry).', $count)); |             $this->friendlyInfo(sprintf('Renamed %d account meta entries (entry).', $count)); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -79,9 +79,6 @@ class UpgradesAttachments extends Command | |||||||
|                 ++$count; |                 ++$count; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (0 === $count) { |  | ||||||
|             $this->friendlyPositive('All attachments are OK.'); |  | ||||||
|         } |  | ||||||
|         if (0 !== $count) { |         if (0 !== $count) { | ||||||
|             $this->friendlyInfo(sprintf('Updated %d attachment(s).', $count)); |             $this->friendlyInfo(sprintf('Updated %d attachment(s).', $count)); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -73,9 +73,6 @@ class UpgradesBillsToRules extends Command | |||||||
|             $this->migrateUser($user); |             $this->migrateUser($user); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (0 === $this->count) { |  | ||||||
|             $this->friendlyPositive('All bills are OK.'); |  | ||||||
|         } |  | ||||||
|         if (0 !== $this->count) { |         if (0 !== $this->count) { | ||||||
|             $this->friendlyInfo(sprintf('Verified and fixed %d bill(s).', $this->count)); |             $this->friendlyInfo(sprintf('Verified and fixed %d bill(s).', $this->count)); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -77,9 +77,6 @@ class UpgradesBudgetLimits extends Command | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (0 === $count) { |  | ||||||
|             $this->friendlyPositive('All budget limits are OK.'); |  | ||||||
|         } |  | ||||||
|         $this->markAsExecuted(); |         $this->markAsExecuted(); | ||||||
| 
 | 
 | ||||||
|         return 0; |         return 0; | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ class UpgradesCreditCardLiabilities extends Command | |||||||
|         $ccType   = AccountType::where('type', AccountType::CREDITCARD)->first(); |         $ccType   = AccountType::where('type', AccountType::CREDITCARD)->first(); | ||||||
|         $debtType = AccountType::where('type', AccountType::DEBT)->first(); |         $debtType = AccountType::where('type', AccountType::DEBT)->first(); | ||||||
|         if (null === $ccType || null === $debtType) { |         if (null === $ccType || null === $debtType) { | ||||||
|             $this->friendlyPositive('No incorrectly stored credit card liabilities.'); |  | ||||||
|             $this->markAsExecuted(); |             $this->markAsExecuted(); | ||||||
| 
 | 
 | ||||||
|             return 0; |             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' |                 '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(); |         $this->markAsExecuted(); | ||||||
| 
 | 
 | ||||||
|         return 0; |         return 0; | ||||||
|   | |||||||
| @@ -57,7 +57,6 @@ class UpgradesDatabase extends Command | |||||||
|             'upgrade:480-account-meta', |             'upgrade:480-account-meta', | ||||||
|             'upgrade:481-recurrence-meta', |             'upgrade:481-recurrence-meta', | ||||||
|             'upgrade:500-tag-locations', |             'upgrade:500-tag-locations', | ||||||
|             'upgrade:550-recurrence-type', |  | ||||||
|             'upgrade:560-liabilities', |             'upgrade:560-liabilities', | ||||||
|             'upgrade:600-liabilities', |             'upgrade:600-liabilities', | ||||||
|             'upgrade:550-budget-limit-periods', |             'upgrade:550-budget-limit-periods', | ||||||
|   | |||||||
| @@ -68,7 +68,7 @@ class UpgradesJournalMetaData extends Command | |||||||
| 
 | 
 | ||||||
|     private function isMigrated(): bool |     private function isMigrated(): bool | ||||||
|     { |     { | ||||||
|         $configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false); |         $configVar = app('fireflyconfig')->get(UpgradesToGroups::CONFIG_NAME, false); | ||||||
| 
 | 
 | ||||||
|         return (bool) $configVar->data; |         return (bool) $configVar->data; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -72,9 +72,6 @@ class UpgradesJournalNotes extends Command | |||||||
|             ++$count; |             ++$count; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (0 === $count) { |  | ||||||
|             $this->friendlyPositive('No notes to migrate.'); |  | ||||||
|         } |  | ||||||
|         if (0 !== $count) { |         if (0 !== $count) { | ||||||
|             $this->friendlyInfo(sprintf('Migrated %d note(s).', $count)); |             $this->friendlyInfo(sprintf('Migrated %d note(s).', $count)); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -52,9 +52,6 @@ class UpgradesRecurrenceMetaData extends Command | |||||||
|         } |         } | ||||||
|         $count = $this->migrateMetaData(); |         $count = $this->migrateMetaData(); | ||||||
| 
 | 
 | ||||||
|         if (0 === $count) { |  | ||||||
|             $this->friendlyPositive('No recurrence meta data migrated.'); |  | ||||||
|         } |  | ||||||
|         if ($count > 0) { |         if ($count > 0) { | ||||||
|             $this->friendlyInfo(sprintf('Migrated %d meta data entries', $count)); |             $this->friendlyInfo(sprintf('Migrated %d meta data entries', $count)); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -72,9 +72,6 @@ class UpgradesToGroups extends Command | |||||||
|         if (0 !== $this->count) { |         if (0 !== $this->count) { | ||||||
|             $this->friendlyInfo(sprintf('Migrated %d transaction journal(s).', $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(); |         $this->markAsMigrated(); | ||||||
| 
 | 
 | ||||||
|         return 0; |         return 0; | ||||||
| @@ -363,9 +360,6 @@ class UpgradesToGroups extends Command | |||||||
|                 $this->giveGroup($array); |                 $this->giveGroup($array); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (0 === $total) { |  | ||||||
|             $this->friendlyPositive('No need to convert transaction journals.'); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function giveGroup(array $array): void |     private function giveGroup(array $array): void | ||||||
|   | |||||||
| @@ -68,15 +68,10 @@ class UpgradesTransferCurrencies extends Command | |||||||
| 
 | 
 | ||||||
|         $this->startUpdateRoutine(); |         $this->startUpdateRoutine(); | ||||||
|         $this->markAsExecuted(); |         $this->markAsExecuted(); | ||||||
| 
 |         if ($this->count > 0) { | ||||||
|         if (0 === $this->count) { |             $this->friendlyInfo(sprintf('Verified currency information of %d transfer(s).', $this->count)); | ||||||
|             $this->friendlyPositive('All transfers have correct currency information.'); |  | ||||||
| 
 |  | ||||||
|             return 0; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $this->friendlyInfo(sprintf('Verified currency information of %d transfer(s).', $this->count)); |  | ||||||
| 
 |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -36,8 +36,6 @@ use Illuminate\Session\TokenMismatchException; | |||||||
| use Illuminate\Support\Arr; | use Illuminate\Support\Arr; | ||||||
| use Illuminate\Validation\ValidationException as LaravelValidationException; | use Illuminate\Validation\ValidationException as LaravelValidationException; | ||||||
| use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException; | use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException; | ||||||
| use LaravelJsonApi\Core\Exceptions\JsonApiException; |  | ||||||
| use LaravelJsonApi\Exceptions\ExceptionParser; |  | ||||||
| use League\OAuth2\Server\Exception\OAuthServerException; | use League\OAuth2\Server\Exception\OAuthServerException; | ||||||
| use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; | use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; | ||||||
| use Symfony\Component\HttpFoundation\Response; | use Symfony\Component\HttpFoundation\Response; | ||||||
| @@ -65,18 +63,12 @@ class Handler extends ExceptionHandler | |||||||
|             HttpException::class, |             HttpException::class, | ||||||
|             SuspiciousOperationException::class, |             SuspiciousOperationException::class, | ||||||
|             BadHttpHeaderException::class, |             BadHttpHeaderException::class, | ||||||
|             JsonApiException::class, |  | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Register the exception handling callbacks for the application. |      * Register the exception handling callbacks for the application. | ||||||
|      */ |      */ | ||||||
|     public function register(): void |     public function register(): void {} | ||||||
|     { |  | ||||||
|         $this->renderable( |  | ||||||
|             ExceptionParser::make()->renderable() |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Render an exception into an HTTP response. It's complex but lucky for us, we never use it because |      * Render an exception into an HTTP response. It's complex but lucky for us, we never use it because | ||||||
|   | |||||||
| @@ -43,11 +43,11 @@ class PiggyBankFactory | |||||||
| 
 | 
 | ||||||
|     public User                          $user { |     public User                          $user { | ||||||
|         set(User $value) { |         set(User $value) { | ||||||
|             $this->user = $value; |         $this->user = $value; | ||||||
|             $this->currencyRepository->setUser($value); |         $this->currencyRepository->setUser($value); | ||||||
|             $this->accountRepository->setUser($value); |         $this->accountRepository->setUser($value); | ||||||
|             $this->piggyBankRepository->setUser($value); |         $this->piggyBankRepository->setUser($value); | ||||||
|         } |     } | ||||||
|     } |     } | ||||||
|     private AccountRepositoryInterface   $accountRepository; |     private AccountRepositoryInterface   $accountRepository; | ||||||
|     private CurrencyRepositoryInterface  $currencyRepository; |     private CurrencyRepositoryInterface  $currencyRepository; | ||||||
| @@ -62,15 +62,11 @@ class PiggyBankFactory | |||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Store a piggy bank or come back with an exception. |      * Store a piggy bank or come back with an exception. | ||||||
|      * |  | ||||||
|      * @param array $data |  | ||||||
|      * |  | ||||||
|      * @return PiggyBank |  | ||||||
|      */ |      */ | ||||||
|     public function store(array $data): PiggyBank |     public function store(array $data): PiggyBank | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|         $piggyBankData = $data; |         $piggyBankData                            = $data; | ||||||
| 
 | 
 | ||||||
|         // unset some fields
 |         // unset some fields
 | ||||||
|         unset($piggyBankData['object_group_title'], $piggyBankData['transaction_currency_code'], $piggyBankData['transaction_currency_id'], $piggyBankData['accounts'], $piggyBankData['object_group_id'], $piggyBankData['notes']); |         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); |             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->linkToAccountIds($piggyBank, $data['accounts']); | ||||||
|         $this->piggyBankRepository->updateNote($piggyBank, $data['notes']); |         $this->piggyBankRepository->updateNote($piggyBank, $data['notes']); | ||||||
| 
 | 
 | ||||||
|         $objectGroupTitle = $data['object_group_title'] ?? ''; |         $objectGroupTitle                         = $data['object_group_title'] ?? ''; | ||||||
|         if ('' !== $objectGroupTitle) { |         if ('' !== $objectGroupTitle) { | ||||||
|             $objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle); |             $objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle); | ||||||
|             if (null !== $objectGroup) { |             if (null !== $objectGroup) { | ||||||
| @@ -106,7 +102,7 @@ class PiggyBankFactory | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         // try also with ID
 |         // try also with ID
 | ||||||
|         $objectGroupId = (int) ($data['object_group_id'] ?? 0); |         $objectGroupId                            = (int) ($data['object_group_id'] ?? 0); | ||||||
|         if (0 !== $objectGroupId) { |         if (0 !== $objectGroupId) { | ||||||
|             $objectGroup = $this->findObjectGroupById($objectGroupId); |             $objectGroup = $this->findObjectGroupById($objectGroupId); | ||||||
|             if (null !== $objectGroup) { |             if (null !== $objectGroup) { | ||||||
| @@ -114,9 +110,10 @@ class PiggyBankFactory | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         Log::debug('Touch piggy bank'); |         Log::debug('Touch piggy bank'); | ||||||
|         $piggyBank->encrypted = false; |         $piggyBank->encrypted                     = false; | ||||||
|         $piggyBank->save(); |         $piggyBank->save(); | ||||||
|         $piggyBank->touch(); |         $piggyBank->touch(); | ||||||
|  | 
 | ||||||
|         return $piggyBank; |         return $piggyBank; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -132,6 +129,7 @@ class PiggyBankFactory | |||||||
|             $currency = $this->currencyRepository->find((int) ($data['transaction_currency_id'] ?? 0)); |             $currency = $this->currencyRepository->find((int) ($data['transaction_currency_id'] ?? 0)); | ||||||
|         } |         } | ||||||
|         $currency ??= $defaultCurrency; |         $currency ??= $defaultCurrency; | ||||||
|  | 
 | ||||||
|         return $currency; |         return $currency; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -144,12 +142,12 @@ class PiggyBankFactory | |||||||
|         } |         } | ||||||
|         // first find by ID:
 |         // first find by ID:
 | ||||||
|         if ($piggyBankId > 0) { |         if ($piggyBankId > 0) { | ||||||
|             $piggyBank = PiggyBank |             $piggyBank = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') | ||||||
|                 ::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') |  | ||||||
|                 ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') |                 ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') | ||||||
|                 ->where('accounts.user_id', $this->user->id) |                 ->where('accounts.user_id', $this->user->id) | ||||||
|                 ->where('piggy_banks.id', $piggyBankId) |                 ->where('piggy_banks.id', $piggyBankId) | ||||||
|                 ->first(['piggy_banks.*']); |                 ->first(['piggy_banks.*']) | ||||||
|  |             ; | ||||||
|             if (null !== $piggyBank) { |             if (null !== $piggyBank) { | ||||||
|                 return $piggyBank; |                 return $piggyBank; | ||||||
|             } |             } | ||||||
| @@ -169,23 +167,24 @@ class PiggyBankFactory | |||||||
| 
 | 
 | ||||||
|     public function findByName(string $name): ?PiggyBank |     public function findByName(string $name): ?PiggyBank | ||||||
|     { |     { | ||||||
|         return PiggyBank |         return PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') | ||||||
|             ::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') |  | ||||||
|             ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') |             ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') | ||||||
|             ->where('accounts.user_id', $this->user->id) |             ->where('accounts.user_id', $this->user->id) | ||||||
|             ->where('piggy_banks.name', $name) |             ->where('piggy_banks.name', $name) | ||||||
|             ->first(['piggy_banks.*']); |             ->first(['piggy_banks.*']) | ||||||
|  |         ; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function setOrder(PiggyBank $piggyBank, array $data): PiggyBank |     private function setOrder(PiggyBank $piggyBank, array $data): PiggyBank | ||||||
|     { |     { | ||||||
|         $this->resetOrder(); |         $this->resetOrder(); | ||||||
|         $order = $this->getMaxOrder() + 1; |         $order            = $this->getMaxOrder() + 1; | ||||||
|         if (array_key_exists('order', $data)) { |         if (array_key_exists('order', $data)) { | ||||||
|             $order = $data['order']; |             $order = $data['order']; | ||||||
|         } |         } | ||||||
|         $piggyBank->order = $order; |         $piggyBank->order = $order; | ||||||
|         $piggyBank->saveQuietly(); |         $piggyBank->saveQuietly(); | ||||||
|  | 
 | ||||||
|         return $piggyBank; |         return $piggyBank; | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| @@ -193,8 +192,7 @@ class PiggyBankFactory | |||||||
|     public function resetOrder(): void |     public function resetOrder(): void | ||||||
|     { |     { | ||||||
|         // TODO duplicate code
 |         // TODO duplicate code
 | ||||||
|         $set     = PiggyBank |         $set     = PiggyBank::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') | ||||||
|             ::leftJoin('account_piggy_bank', 'account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') |  | ||||||
|             ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') |             ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') | ||||||
|             ->where('accounts.user_id', $this->user->id) |             ->where('accounts.user_id', $this->user->id) | ||||||
|             ->with( |             ->with( | ||||||
| @@ -202,7 +200,8 @@ class PiggyBankFactory | |||||||
|                     'objectGroups', |                     'objectGroups', | ||||||
|                 ] |                 ] | ||||||
|             ) |             ) | ||||||
|             ->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']); |             ->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']) | ||||||
|  |         ; | ||||||
|         $current = 1; |         $current = 1; | ||||||
|         foreach ($set as $piggyBank) { |         foreach ($set as $piggyBank) { | ||||||
|             if ($piggyBank->order !== $current) { |             if ($piggyBank->order !== $current) { | ||||||
| @@ -214,7 +213,6 @@ class PiggyBankFactory | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     private function getMaxOrder(): int |     private function getMaxOrder(): int | ||||||
|     { |     { | ||||||
|         return (int) $this->piggyBankRepository->getPiggyBanks()->max('order'); |         return (int) $this->piggyBankRepository->getPiggyBanks()->max('order'); | ||||||
|   | |||||||
| @@ -32,6 +32,7 @@ use FireflyIII\Models\Budget; | |||||||
| use FireflyIII\Models\BudgetLimit; | use FireflyIII\Models\BudgetLimit; | ||||||
| use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface; | use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface; | ||||||
| use FireflyIII\User; | use FireflyIII\User; | ||||||
|  | use Illuminate\Support\Facades\Log; | ||||||
| use Psr\Container\ContainerExceptionInterface; | use Psr\Container\ContainerExceptionInterface; | ||||||
| use Psr\Container\NotFoundExceptionInterface; | use Psr\Container\NotFoundExceptionInterface; | ||||||
| use Spatie\Period\Boundaries; | use Spatie\Period\Boundaries; | ||||||
| @@ -45,20 +46,20 @@ class BudgetLimitHandler | |||||||
| { | { | ||||||
|     public function created(Created $event): void |     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); |         $this->updateAvailableBudget($event->budgetLimit); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function updateAvailableBudget(BudgetLimit $budgetLimit): void |     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); |         $budget      = Budget::find($budgetLimit->budget_id); | ||||||
|         if (null === $budget) { |         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); |             $budget = Budget::withTrashed()->find($budgetLimit->budget_id); | ||||||
|         } |         } | ||||||
|         if (null === $budget) { |         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(); |             $budgetLimit->forceDelete(); | ||||||
| 
 | 
 | ||||||
|             return; |             return; | ||||||
| @@ -69,7 +70,7 @@ class BudgetLimitHandler | |||||||
| 
 | 
 | ||||||
|         // sanity check. It happens when the budget has been deleted so the original user is unknown.
 |         // sanity check. It happens when the budget has been deleted so the original user is unknown.
 | ||||||
|         if (null === $user) { |         if (null === $user) { | ||||||
|             app('log')->warning('User is null, cannot continue.'); |             Log::warning('User is null, cannot continue.'); | ||||||
|             $budgetLimit->forceDelete(); |             $budgetLimit->forceDelete(); | ||||||
| 
 | 
 | ||||||
|             return; |             return; | ||||||
| @@ -82,7 +83,7 @@ class BudgetLimitHandler | |||||||
|         try { |         try { | ||||||
|             $viewRange = app('preferences')->getForUser($user, 'viewRange', '1M')->data; |             $viewRange = app('preferences')->getForUser($user, 'viewRange', '1M')->data; | ||||||
|         } catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) { |         } catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) { | ||||||
|             app('log')->error($e->getMessage()); |             Log::error($e->getMessage()); | ||||||
|             $viewRange = '1M'; |             $viewRange = '1M'; | ||||||
|         } |         } | ||||||
|         // safety catch
 |         // safety catch
 | ||||||
| @@ -97,7 +98,7 @@ class BudgetLimitHandler | |||||||
| 
 | 
 | ||||||
|         // limit period in total is:
 |         // limit period in total is:
 | ||||||
|         $limitPeriod = Period::make($start, $end, precision: Precision::DAY(), boundaries: Boundaries::EXCLUDE_NONE()); |         $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!
 |         // from the start until the end of the budget limit, need to loop!
 | ||||||
|         $current     = clone $start; |         $current     = clone $start; | ||||||
| @@ -106,16 +107,14 @@ class BudgetLimitHandler | |||||||
| 
 | 
 | ||||||
|             // create or find AB for this particular period, and set the amount accordingly.
 |             // create or find AB for this particular period, and set the amount accordingly.
 | ||||||
|             /** @var null|AvailableBudget $availableBudget */ |             /** @var null|AvailableBudget $availableBudget */ | ||||||
|             $availableBudget = $user->availableBudgets()->where('start_date', $current->format('Y-m-d'))->where( |             $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(); | ||||||
|                 'end_date', |  | ||||||
|                 $currentEnd->format('Y-m-d') |  | ||||||
|             )->where('transaction_currency_id', $budgetLimit->transaction_currency_id)->first(); |  | ||||||
| 
 | 
 | ||||||
|             if (null !== $availableBudget) { |             if (null !== $availableBudget) { | ||||||
|                 app('log')->debug('Found 1 AB, will update.'); |                 Log::debug('Found 1 AB, will update.'); | ||||||
|                 $this->calculateAmount($availableBudget); |                 $this->calculateAmount($availableBudget); | ||||||
|             } |             } | ||||||
|             if (null === $availableBudget) { |             if (null === $availableBudget) { | ||||||
|  |                 Log::debug('No AB found, will create.'); | ||||||
|                 // if not exists:
 |                 // if not exists:
 | ||||||
|                 $currentPeriod = Period::make($current, $currentEnd, precision: Precision::DAY(), boundaries: Boundaries::EXCLUDE_NONE()); |                 $currentPeriod = Period::make($current, $currentEnd, precision: Precision::DAY(), boundaries: Boundaries::EXCLUDE_NONE()); | ||||||
|                 $daily         = $this->getDailyAmount($budgetLimit); |                 $daily         = $this->getDailyAmount($budgetLimit); | ||||||
| @@ -126,10 +125,10 @@ class BudgetLimitHandler | |||||||
|                     $amount = 0 === $budgetLimit->id ? '0' : $budgetLimit->amount; |                     $amount = 0 === $budgetLimit->id ? '0' : $budgetLimit->amount; | ||||||
|                 } |                 } | ||||||
|                 if (0 === bccomp($amount, '0')) { |                 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')) { |                 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( |                     $availableBudget = new AvailableBudget( | ||||||
|                         [ |                         [ | ||||||
|                             'user_id'                 => $user->id, |                             'user_id'                 => $user->id, | ||||||
| @@ -143,7 +142,8 @@ class BudgetLimitHandler | |||||||
|                         ] |                         ] | ||||||
|                     ); |                     ); | ||||||
|                     $availableBudget->save(); |                     $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); |         $repository->setUser($availableBudget->user); | ||||||
|         $newAmount               = '0'; |         $newAmount               = '0'; | ||||||
|         $abPeriod                = Period::make($availableBudget->start_date, $availableBudget->end_date, Precision::DAY()); |         $abPeriod                = Period::make($availableBudget->start_date, $availableBudget->end_date, Precision::DAY()); | ||||||
|         app('log')->debug( |         Log::debug( | ||||||
|             sprintf( |             sprintf( | ||||||
|                 'Now at AB #%d, ("%s" to "%s")', |                 'Now at AB #%d, ("%s" to "%s")', | ||||||
|                 $availableBudget->id, |                 $availableBudget->id, | ||||||
| @@ -168,11 +168,11 @@ class BudgetLimitHandler | |||||||
|         ); |         ); | ||||||
|         // have to recalculate everything just in case.
 |         // have to recalculate everything just in case.
 | ||||||
|         $set                     = $repository->getAllBudgetLimitsByCurrency($availableBudget->transactionCurrency, $availableBudget->start_date, $availableBudget->end_date); |         $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 */ |         /** @var BudgetLimit $budgetLimit */ | ||||||
|         foreach ($set as $budgetLimit) { |         foreach ($set as $budgetLimit) { | ||||||
|             app('log')->debug( |             Log::debug( | ||||||
|                 sprintf( |                 sprintf( | ||||||
|                     'Found interesting budget limit #%d ("%s" to "%s")', |                     'Found interesting budget limit #%d ("%s" to "%s")', | ||||||
|                     $budgetLimit->id, |                     $budgetLimit->id, | ||||||
| @@ -189,16 +189,16 @@ class BudgetLimitHandler | |||||||
|             ); |             ); | ||||||
|             // if both equal each other, amount from this BL must be added to the AB
 |             // if both equal each other, amount from this BL must be added to the AB
 | ||||||
|             if ($limitPeriod->equals($abPeriod)) { |             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); |                 $newAmount = bcadd($newAmount, $budgetLimit->amount); | ||||||
|             } |             } | ||||||
|             // if budget limit period is inside AB period, it can be added in full.
 |             // if budget limit period is inside AB period, it can be added in full.
 | ||||||
|             if (!$limitPeriod->equals($abPeriod) && $abPeriod->contains($limitPeriod)) { |             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); |                 $newAmount = bcadd($newAmount, $budgetLimit->amount); | ||||||
|             } |             } | ||||||
|             if (!$limitPeriod->equals($abPeriod) && !$abPeriod->contains($limitPeriod) && $abPeriod->overlapsWith($limitPeriod)) { |             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); |                 $overlap = $abPeriod->overlap($limitPeriod); | ||||||
|                 if (null !== $overlap) { |                 if (null !== $overlap) { | ||||||
|                     $length    = $overlap->length(); |                     $length    = $overlap->length(); | ||||||
| @@ -208,12 +208,12 @@ class BudgetLimitHandler | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (0 === bccomp('0', $newAmount)) { |         if (0 === bccomp('0', $newAmount)) { | ||||||
|             app('log')->debug('New amount is zero, deleting AB.'); |             Log::debug('New amount is zero, deleting AB.'); | ||||||
|             $availableBudget->delete(); |             $availableBudget->delete(); | ||||||
| 
 | 
 | ||||||
|             return; |             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->amount = app('steam')->bcround($newAmount, $availableBudget->transactionCurrency->decimal_places); | ||||||
|         $availableBudget->save(); |         $availableBudget->save(); | ||||||
|     } |     } | ||||||
| @@ -231,7 +231,7 @@ class BudgetLimitHandler | |||||||
|         ); |         ); | ||||||
|         $days        = $limitPeriod->length(); |         $days        = $limitPeriod->length(); | ||||||
|         $amount      = bcdiv($budgetLimit->amount, (string) $days, 12); |         $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) |             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 |     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     = $event->budgetLimit; | ||||||
|         $budgetLimit->id = 0; |         $budgetLimit->id = 0; | ||||||
|         $this->updateAvailableBudget($event->budgetLimit); |         $this->updateAvailableBudget($event->budgetLimit); | ||||||
| @@ -248,7 +248,7 @@ class BudgetLimitHandler | |||||||
| 
 | 
 | ||||||
|     public function updated(Updated $event): void |     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); |         $this->updateAvailableBudget($event->budgetLimit); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -30,7 +30,9 @@ use FireflyIII\Models\PiggyBank; | |||||||
| use FireflyIII\Models\UserGroup; | use FireflyIII\Models\UserGroup; | ||||||
| use FireflyIII\Repositories\UserGroups\Budget\BudgetRepositoryInterface; | use FireflyIII\Repositories\UserGroups\Budget\BudgetRepositoryInterface; | ||||||
| use FireflyIII\Repositories\UserGroups\PiggyBank\PiggyBankRepositoryInterface; | use FireflyIII\Repositories\UserGroups\PiggyBank\PiggyBankRepositoryInterface; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use Illuminate\Database\Query\Builder; | use Illuminate\Database\Query\Builder; | ||||||
|  | use Illuminate\Support\Facades\Artisan; | ||||||
| use Illuminate\Support\Facades\DB; | use Illuminate\Support\Facades\DB; | ||||||
| use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||||
| 
 | 
 | ||||||
| @@ -57,6 +59,10 @@ class PreferencesEventHandler | |||||||
|         $this->resetPiggyBanks($event->userGroup); |         $this->resetPiggyBanks($event->userGroup); | ||||||
|         $this->resetBudgets($event->userGroup); |         $this->resetBudgets($event->userGroup); | ||||||
|         $this->resetTransactions($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 |     private function resetPiggyBanks(UserGroup $userGroup): void | ||||||
| @@ -130,6 +136,6 @@ class PreferencesEventHandler | |||||||
|             }) |             }) | ||||||
|             ->update(['native_amount' => null, 'native_foreign_amount' => null]) |             ->update(['native_amount' => null, 'native_foreign_amount' => null]) | ||||||
|         ; |         ; | ||||||
|         Log::debug(sprintf('Updated %d transactions.', $success)); |         Log::debug(sprintf('Reset %d transactions.', $success)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ namespace FireflyIII\Handlers\Observer; | |||||||
| use FireflyIII\Models\Account; | use FireflyIII\Models\Account; | ||||||
| use FireflyIII\Models\PiggyBank; | use FireflyIII\Models\PiggyBank; | ||||||
| use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface; | use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Http\Api\ExchangeRateConverter; | use FireflyIII\Support\Http\Api\ExchangeRateConverter; | ||||||
| use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||||
| 
 | 
 | ||||||
| @@ -43,6 +44,9 @@ class AccountObserver | |||||||
| 
 | 
 | ||||||
|     private function updateNativeAmount(Account $account): void |     private function updateNativeAmount(Account $account): void | ||||||
|     { |     { | ||||||
|  |         if (!Amount::convertToNative($account->user)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|         $userCurrency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup); |         $userCurrency = app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup); | ||||||
|         $repository   = app(AccountRepositoryInterface::class); |         $repository   = app(AccountRepositoryInterface::class); | ||||||
|         $currency     = $repository->getAccountCurrency($account); |         $currency     = $repository->getAccountCurrency($account); | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ declare(strict_types=1); | |||||||
| namespace FireflyIII\Handlers\Observer; | namespace FireflyIII\Handlers\Observer; | ||||||
| 
 | 
 | ||||||
| use FireflyIII\Models\AutoBudget; | use FireflyIII\Models\AutoBudget; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Http\Api\ExchangeRateConverter; | use FireflyIII\Support\Http\Api\ExchangeRateConverter; | ||||||
| use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||||
| 
 | 
 | ||||||
| @@ -44,6 +45,9 @@ class AutoBudgetObserver | |||||||
| 
 | 
 | ||||||
|     private function updateNativeAmount(AutoBudget $autoBudget): void |     private function updateNativeAmount(AutoBudget $autoBudget): void | ||||||
|     { |     { | ||||||
|  |         if (!Amount::convertToNative($autoBudget->budget->user)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|         $userCurrency              = app('amount')->getDefaultCurrencyByUserGroup($autoBudget->budget->user->userGroup); |         $userCurrency              = app('amount')->getDefaultCurrencyByUserGroup($autoBudget->budget->user->userGroup); | ||||||
|         $autoBudget->native_amount = null; |         $autoBudget->native_amount = null; | ||||||
|         if ($autoBudget->transactionCurrency->id !== $userCurrency->id) { |         if ($autoBudget->transactionCurrency->id !== $userCurrency->id) { | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ declare(strict_types=1); | |||||||
| namespace FireflyIII\Handlers\Observer; | namespace FireflyIII\Handlers\Observer; | ||||||
| 
 | 
 | ||||||
| use FireflyIII\Models\AvailableBudget; | use FireflyIII\Models\AvailableBudget; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Http\Api\ExchangeRateConverter; | use FireflyIII\Support\Http\Api\ExchangeRateConverter; | ||||||
| use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||||
| 
 | 
 | ||||||
| @@ -32,18 +33,23 @@ class AvailableBudgetObserver | |||||||
| { | { | ||||||
|     public function created(AvailableBudget $availableBudget): void |     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); |         $this->updateNativeAmount($availableBudget); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function updated(AvailableBudget $availableBudget): void |     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); |         $this->updateNativeAmount($availableBudget); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function updateNativeAmount(AvailableBudget $availableBudget): void |     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); |         $userCurrency                   = app('amount')->getDefaultCurrencyByUserGroup($availableBudget->user->userGroup); | ||||||
|         $availableBudget->native_amount = null; |         $availableBudget->native_amount = null; | ||||||
|         if ($availableBudget->transactionCurrency->id !== $userCurrency->id) { |         if ($availableBudget->transactionCurrency->id !== $userCurrency->id) { | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ declare(strict_types=1); | |||||||
| namespace FireflyIII\Handlers\Observer; | namespace FireflyIII\Handlers\Observer; | ||||||
| 
 | 
 | ||||||
| use FireflyIII\Models\Bill; | use FireflyIII\Models\Bill; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Http\Api\ExchangeRateConverter; | use FireflyIII\Support\Http\Api\ExchangeRateConverter; | ||||||
| use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||||
| 
 | 
 | ||||||
| @@ -55,6 +56,9 @@ class BillObserver | |||||||
| 
 | 
 | ||||||
|     private function updateNativeAmount(Bill $bill): void |     private function updateNativeAmount(Bill $bill): void | ||||||
|     { |     { | ||||||
|  |         if (!Amount::convertToNative($bill->user)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|         $userCurrency            = app('amount')->getDefaultCurrencyByUserGroup($bill->user->userGroup); |         $userCurrency            = app('amount')->getDefaultCurrencyByUserGroup($bill->user->userGroup); | ||||||
|         $bill->native_amount_min = null; |         $bill->native_amount_min = null; | ||||||
|         $bill->native_amount_max = null; |         $bill->native_amount_max = null; | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ declare(strict_types=1); | |||||||
| namespace FireflyIII\Handlers\Observer; | namespace FireflyIII\Handlers\Observer; | ||||||
| 
 | 
 | ||||||
| use FireflyIII\Models\BudgetLimit; | use FireflyIII\Models\BudgetLimit; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Http\Api\ExchangeRateConverter; | use FireflyIII\Support\Http\Api\ExchangeRateConverter; | ||||||
| use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||||
| 
 | 
 | ||||||
| @@ -44,6 +45,11 @@ class BudgetLimitObserver | |||||||
| 
 | 
 | ||||||
|     private function updateNativeAmount(BudgetLimit $budgetLimit): void |     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); |         $userCurrency               = app('amount')->getDefaultCurrencyByUserGroup($budgetLimit->budget->user->userGroup); | ||||||
|         $budgetLimit->native_amount = null; |         $budgetLimit->native_amount = null; | ||||||
|         if ($budgetLimit->transactionCurrency->id !== $userCurrency->id) { |         if ($budgetLimit->transactionCurrency->id !== $userCurrency->id) { | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ declare(strict_types=1); | |||||||
| namespace FireflyIII\Handlers\Observer; | namespace FireflyIII\Handlers\Observer; | ||||||
| 
 | 
 | ||||||
| use FireflyIII\Models\PiggyBankEvent; | use FireflyIII\Models\PiggyBankEvent; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Http\Api\ExchangeRateConverter; | use FireflyIII\Support\Http\Api\ExchangeRateConverter; | ||||||
| use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||||
| 
 | 
 | ||||||
| @@ -44,6 +45,9 @@ class PiggyBankEventObserver | |||||||
| 
 | 
 | ||||||
|     private function updateNativeAmount(PiggyBankEvent $event): void |     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); |         $userCurrency         = app('amount')->getDefaultCurrencyByUserGroup($event->piggyBank->accounts()->first()->user->userGroup); | ||||||
|         $event->native_amount = null; |         $event->native_amount = null; | ||||||
|         if ($event->piggyBank->transactionCurrency->id !== $userCurrency->id) { |         if ($event->piggyBank->transactionCurrency->id !== $userCurrency->id) { | ||||||
|   | |||||||
| @@ -78,6 +78,7 @@ class PiggyBankObserver | |||||||
|         if ($piggyBank->transactionCurrency->id !== $userCurrency->id) { |         if ($piggyBank->transactionCurrency->id !== $userCurrency->id) { | ||||||
|             $converter                       = new ExchangeRateConverter(); |             $converter                       = new ExchangeRateConverter(); | ||||||
|             $converter->setIgnoreSettings(true); |             $converter->setIgnoreSettings(true); | ||||||
|  |             $converter->setUserGroup($group); | ||||||
|             $piggyBank->native_target_amount = $converter->convert($piggyBank->transactionCurrency, $userCurrency, today(), $piggyBank->target_amount); |             $piggyBank->native_target_amount = $converter->convert($piggyBank->transactionCurrency, $userCurrency, today(), $piggyBank->target_amount); | ||||||
|         } |         } | ||||||
|         $piggyBank->saveQuietly(); |         $piggyBank->saveQuietly(); | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ declare(strict_types=1); | |||||||
| namespace FireflyIII\Handlers\Observer; | namespace FireflyIII\Handlers\Observer; | ||||||
| 
 | 
 | ||||||
| use FireflyIII\Models\Transaction; | use FireflyIII\Models\Transaction; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Http\Api\ExchangeRateConverter; | use FireflyIII\Support\Http\Api\ExchangeRateConverter; | ||||||
| use FireflyIII\Support\Models\AccountBalanceCalculator; | use FireflyIII\Support\Models\AccountBalanceCalculator; | ||||||
| use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||||
| @@ -55,7 +56,7 @@ class TransactionObserver | |||||||
| 
 | 
 | ||||||
|     public function updated(Transaction $transaction): void |     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 (config('firefly.feature_flags.running_balance_column') && self::$recalculate) { | ||||||
|             if (1 === bccomp($transaction->amount, '0')) { |             if (1 === bccomp($transaction->amount, '0')) { | ||||||
|                 Log::debug('Trigger recalculateForJournal'); |                 Log::debug('Trigger recalculateForJournal'); | ||||||
| @@ -67,6 +68,9 @@ class TransactionObserver | |||||||
| 
 | 
 | ||||||
|     private function updateNativeAmount(Transaction $transaction): void |     private function updateNativeAmount(Transaction $transaction): void | ||||||
|     { |     { | ||||||
|  |         if (!Amount::convertToNative($transaction->transactionJournal->user)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|         $userCurrency                       = app('amount')->getDefaultCurrencyByUserGroup($transaction->transactionJournal->user->userGroup); |         $userCurrency                       = app('amount')->getDefaultCurrencyByUserGroup($transaction->transactionJournal->user->userGroup); | ||||||
|         $transaction->native_amount         = null; |         $transaction->native_amount         = null; | ||||||
|         $transaction->native_foreign_amount = null; |         $transaction->native_foreign_amount = null; | ||||||
|   | |||||||
| @@ -66,7 +66,7 @@ class NetWorth implements NetWorthInterface | |||||||
|     public function byAccounts(Collection $accounts, Carbon $date): array |     public function byAccounts(Collection $accounts, Carbon $date): array | ||||||
|     { |     { | ||||||
|         // start in the past, end in the future? use $date
 |         // 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()); |         $ids             = implode(',', $accounts->pluck('id')->toArray()); | ||||||
|         $cache           = new CacheProperties(); |         $cache           = new CacheProperties(); | ||||||
|         $cache->addProperty($date); |         $cache->addProperty($date); | ||||||
|   | |||||||
| @@ -76,7 +76,6 @@ class CreateController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function create(Request $request, string $objectType) |     public function create(Request $request, string $objectType) | ||||||
|     { |     { | ||||||
|         $defaultCurrency     = app('amount')->getDefaultCurrency(); |  | ||||||
|         $subTitleIcon        = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType)); |         $subTitleIcon        = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType)); | ||||||
|         $subTitle            = (string) trans(sprintf('firefly.make_new_%s_account', $objectType)); |         $subTitle            = (string) trans(sprintf('firefly.make_new_%s_account', $objectType)); | ||||||
|         $roles               = $this->getRoles(); |         $roles               = $this->getRoles(); | ||||||
| @@ -106,7 +105,7 @@ class CreateController extends Controller | |||||||
|         $request->session()->flash( |         $request->session()->flash( | ||||||
|             'preFilled', |             'preFilled', | ||||||
|             [ |             [ | ||||||
|                 'currency_id'       => $defaultCurrency->id, |                 'currency_id'       => $this->defaultCurrency->id, | ||||||
|                 'include_net_worth' => $hasOldInput ? (bool) $request->old('include_net_worth') : true, |                 'include_net_worth' => $hasOldInput ? (bool) $request->old('include_net_worth') : true, | ||||||
|             ] |             ] | ||||||
|         ); |         ); | ||||||
|   | |||||||
| @@ -90,6 +90,7 @@ class EditController extends Controller | |||||||
|         $latitude             = null !== $location ? $location->latitude : config('firefly.default_location.latitude'); |         $latitude             = null !== $location ? $location->latitude : config('firefly.default_location.latitude'); | ||||||
|         $longitude            = null !== $location ? $location->longitude : config('firefly.default_location.longitude'); |         $longitude            = null !== $location ? $location->longitude : config('firefly.default_location.longitude'); | ||||||
|         $zoomLevel            = null !== $location ? $location->zoom_level : config('firefly.default_location.zoom_level'); |         $zoomLevel            = null !== $location ? $location->zoom_level : config('firefly.default_location.zoom_level'); | ||||||
|  |         $canEditCurrency      = 0 === $account->piggyBanks()->count(); | ||||||
|         $hasLocation          = null !== $location; |         $hasLocation          = null !== $location; | ||||||
|         $locations            = [ |         $locations            = [ | ||||||
|             'location' => [ |             'location' => [ | ||||||
| @@ -123,7 +124,7 @@ class EditController extends Controller | |||||||
|             $openingBalanceAmount = ''; |             $openingBalanceAmount = ''; | ||||||
|         } |         } | ||||||
|         $openingBalanceDate   = $repository->getOpeningBalanceDate($account); |         $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?
 |         // include this account in net-worth charts?
 | ||||||
|         $includeNetWorth      = $repository->getMetaValue($account, 'include_net_worth'); |         $includeNetWorth      = $repository->getMetaValue($account, 'include_net_worth'); | ||||||
| @@ -162,7 +163,7 @@ class EditController extends Controller | |||||||
| 
 | 
 | ||||||
|         $request->session()->flash('preFilled', $preFilled); |         $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')); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -86,7 +86,7 @@ class ReconcileController extends Controller | |||||||
| 
 | 
 | ||||||
|             return redirect(route('accounts.index', [config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type))])); |             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:
 |         // no start or end:
 | ||||||
|         $range           = app('navigation')->getViewRange(false); |         $range           = app('navigation')->getViewRange(false); | ||||||
| @@ -197,7 +197,7 @@ class ReconcileController extends Controller | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $reconciliation = $this->accountRepos->getReconciliation($account); |         $reconciliation = $this->accountRepos->getReconciliation($account); | ||||||
|         $currency       = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency(); |         $currency       = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency; | ||||||
|         $source         = $reconciliation; |         $source         = $reconciliation; | ||||||
|         $destination    = $account; |         $destination    = $account; | ||||||
|         if (1 === bccomp($difference, '0')) { |         if (1 === bccomp($difference, '0')) { | ||||||
|   | |||||||
| @@ -30,7 +30,6 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface; | |||||||
| use FireflyIII\Http\Controllers\Controller; | use FireflyIII\Http\Controllers\Controller; | ||||||
| use FireflyIII\Models\Account; | use FireflyIII\Models\Account; | ||||||
| use FireflyIII\Repositories\Account\AccountRepositoryInterface; | use FireflyIII\Repositories\Account\AccountRepositoryInterface; | ||||||
| use FireflyIII\Support\Facades\Amount; |  | ||||||
| use FireflyIII\Support\Facades\Steam; | use FireflyIII\Support\Facades\Steam; | ||||||
| use FireflyIII\Support\Http\Controllers\PeriodOverview; | use FireflyIII\Support\Http\Controllers\PeriodOverview; | ||||||
| use Illuminate\Contracts\View\Factory; | use Illuminate\Contracts\View\Factory; | ||||||
| @@ -101,7 +100,7 @@ class ShowController extends Controller | |||||||
|         $page             = (int) $request->get('page'); |         $page             = (int) $request->get('page'); | ||||||
|         $pageSize         = (int) app('preferences')->get('listPageSize', 50)->data; |         $pageSize         = (int) app('preferences')->get('listPageSize', 50)->data; | ||||||
|         $accountCurrency  = $this->repository->getAccountCurrency($account); |         $accountCurrency  = $this->repository->getAccountCurrency($account); | ||||||
|         $currency         = $accountCurrency ?? Amount::getDefaultCurrency(); |         $currency         = $accountCurrency ?? $this->defaultCurrency; | ||||||
|         $fStart           = $start->isoFormat($this->monthAndDayFormat); |         $fStart           = $start->isoFormat($this->monthAndDayFormat); | ||||||
|         $fEnd             = $end->isoFormat($this->monthAndDayFormat); |         $fEnd             = $end->isoFormat($this->monthAndDayFormat); | ||||||
|         $subTitle         = (string) trans('firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $fStart, 'end' => $fEnd]); |         $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); |         $subTitleIcon    = config('firefly.subIconsByIdentifier.'.$account->accountType->type); | ||||||
|         $page            = (int) $request->get('page'); |         $page            = (int) $request->get('page'); | ||||||
|         $pageSize        = (int) app('preferences')->get('listPageSize', 50)->data; |         $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]); |         $subTitle        = (string) trans('firefly.all_journals_for_account', ['name' => $account->name]); | ||||||
|         $periods         = new Collection(); |         $periods         = new Collection(); | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -77,7 +77,7 @@ class CreateController extends Controller | |||||||
|             $periods[$current] = (string) trans('firefly.repeat_freq_'.$current); |             $periods[$current] = (string) trans('firefly.repeat_freq_'.$current); | ||||||
|         } |         } | ||||||
|         $subTitle        = (string) trans('firefly.create_new_bill'); |         $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").
 |         // put previous url in session if not redirect from store (not "create another").
 | ||||||
|         if (true !== session('bills.create.fromStore')) { |         if (true !== session('bills.create.fromStore')) { | ||||||
|   | |||||||
| @@ -85,11 +85,10 @@ class EditController extends Controller | |||||||
|             $this->rememberPreviousUrl('bills.edit.url'); |             $this->rememberPreviousUrl('bills.edit.url'); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $currency         = app('amount')->getDefaultCurrency(); |         $bill->amount_min = app('steam')->bcround($bill->amount_min, $bill->transactionCurrency->decimal_places); | ||||||
|         $bill->amount_min = app('steam')->bcround($bill->amount_min, $currency->decimal_places); |         $bill->amount_max = app('steam')->bcround($bill->amount_max, $bill->transactionCurrency->decimal_places); | ||||||
|         $bill->amount_max = app('steam')->bcround($bill->amount_max, $currency->decimal_places); |  | ||||||
|         $rules            = $this->repository->getRulesForBill($bill); |         $rules            = $this->repository->getRulesForBill($bill); | ||||||
|         $defaultCurrency  = app('amount')->getDefaultCurrency(); |         $defaultCurrency  = $this->defaultCurrency; | ||||||
| 
 | 
 | ||||||
|         // code to handle active-checkboxes
 |         // code to handle active-checkboxes
 | ||||||
|         $hasOldInput      = null !== $request->old('_token'); |         $hasOldInput      = null !== $request->old('_token'); | ||||||
|   | |||||||
| @@ -86,11 +86,10 @@ class CreateController extends Controller | |||||||
|             'half_year' => (string) trans('firefly.auto_budget_period_half_year'), |             'half_year' => (string) trans('firefly.auto_budget_period_half_year'), | ||||||
|             'yearly'    => (string) trans('firefly.auto_budget_period_yearly'), |             'yearly'    => (string) trans('firefly.auto_budget_period_yearly'), | ||||||
|         ]; |         ]; | ||||||
|         $currency          = app('amount')->getDefaultCurrency(); |  | ||||||
| 
 | 
 | ||||||
|         $preFilled         = [ |         $preFilled         = [ | ||||||
|             'auto_budget_period'      => $hasOldInput ? (bool) $request->old('auto_budget_period') : 'monthly', |             '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); |         $request->session()->flash('preFilled', $preFilled); | ||||||
|   | |||||||
| @@ -91,10 +91,9 @@ class EditController extends Controller | |||||||
| 
 | 
 | ||||||
|         // code to handle active-checkboxes
 |         // code to handle active-checkboxes
 | ||||||
|         $hasOldInput       = null !== $request->old('_token'); |         $hasOldInput       = null !== $request->old('_token'); | ||||||
|         $currency          = app('amount')->getDefaultCurrency(); |  | ||||||
|         $preFilled         = [ |         $preFilled         = [ | ||||||
|             'active'                  => $hasOldInput ? (bool) $request->old('active') : $budget->active, |             '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) { |         if (null !== $autoBudget) { | ||||||
|             $amount                          = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount; |             $amount                          = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount; | ||||||
|   | |||||||
| @@ -42,6 +42,7 @@ use Illuminate\Contracts\View\Factory; | |||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use Illuminate\Support\Collection; | use Illuminate\Support\Collection; | ||||||
|  | use Illuminate\Support\Facades\Log; | ||||||
| use Illuminate\View\View; | use Illuminate\View\View; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @@ -106,7 +107,6 @@ class IndexController extends Controller | |||||||
|             $end   ??= session('end', today(config('app.timezone'))->endOfMonth()); |             $end   ??= session('end', today(config('app.timezone'))->endOfMonth()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $defaultCurrency  = app('amount')->getDefaultCurrency(); |  | ||||||
|         $currencies       = $this->currencyRepository->get(); |         $currencies       = $this->currencyRepository->get(); | ||||||
|         $budgeted         = '0'; |         $budgeted         = '0'; | ||||||
|         $spent            = '0'; |         $spent            = '0'; | ||||||
| @@ -119,14 +119,14 @@ class IndexController extends Controller | |||||||
|         // get all available budgets:
 |         // get all available budgets:
 | ||||||
|         $availableBudgets = $this->getAllAvailableBudgets($start, $end); |         $availableBudgets = $this->getAllAvailableBudgets($start, $end); | ||||||
|         // get all active budgets:
 |         // get all active budgets:
 | ||||||
|         $budgets          = $this->getAllBudgets($start, $end, $currencies, $defaultCurrency); |         $budgets          = $this->getAllBudgets($start, $end, $currencies, $this->defaultCurrency); | ||||||
|         $sums             = $this->getSums($budgets); |         $sums             = $this->getSums($budgets); | ||||||
| 
 | 
 | ||||||
|         // get budgeted for default currency:
 |         // get budgeted for default currency:
 | ||||||
|         if (0 === count($availableBudgets)) { |         if (0 === count($availableBudgets)) { | ||||||
|             $budgeted = $this->blRepository->budgeted($start, $end, $defaultCurrency); |             $budgeted = $this->blRepository->budgeted($start, $end, $this->defaultCurrency); | ||||||
|             $spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $defaultCurrency); |             $spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $this->defaultCurrency); | ||||||
|             $spent    = $spentArr[$defaultCurrency->id]['sum'] ?? '0'; |             $spent    = $spentArr[$this->defaultCurrency->id]['sum'] ?? '0'; | ||||||
|             unset($spentArr); |             unset($spentArr); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @@ -136,6 +136,7 @@ class IndexController extends Controller | |||||||
| 
 | 
 | ||||||
|         // get all inactive budgets, and simply list them:
 |         // get all inactive budgets, and simply list them:
 | ||||||
|         $inactive         = $this->repository->getInactiveBudgets(); |         $inactive         = $this->repository->getInactiveBudgets(); | ||||||
|  |         $defaultCurrency  = $this->defaultCurrency; | ||||||
| 
 | 
 | ||||||
|         return view( |         return view( | ||||||
|             'budgets.index', |             'budgets.index', | ||||||
| @@ -162,6 +163,7 @@ class IndexController extends Controller | |||||||
| 
 | 
 | ||||||
|     private function getAllAvailableBudgets(Carbon $start, Carbon $end): array |     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(); |         $converter        = new ExchangeRateConverter(); | ||||||
|         // get all available budgets.
 |         // get all available budgets.
 | ||||||
|         $ab               = $this->abRepository->get($start, $end); |         $ab               = $this->abRepository->get($start, $end); | ||||||
|   | |||||||
| @@ -103,7 +103,6 @@ class AccountController extends Controller | |||||||
|         $currencies    = []; |         $currencies    = []; | ||||||
|         $chartData     = []; |         $chartData     = []; | ||||||
|         $tempData      = []; |         $tempData      = []; | ||||||
|         $default       = Amount::getDefaultCurrency(); |  | ||||||
| 
 | 
 | ||||||
|         // grab all accounts and names
 |         // grab all accounts and names
 | ||||||
|         $accounts      = $this->accountRepository->getAccountsByType([AccountTypeEnum::EXPENSE->value]); |         $accounts      = $this->accountRepository->getAccountsByType([AccountTypeEnum::EXPENSE->value]); | ||||||
| @@ -138,13 +137,13 @@ class AccountController extends Controller | |||||||
| 
 | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance)); |                 // Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
 | ||||||
|                 $searchCode   = $this->convertToNative ? $default->code : $key; |                 $searchCode   = $this->convertToNative ? $this->defaultCurrency->code : $key; | ||||||
|                 Log::debug(sprintf('Search code is %s', $searchCode)); |                 // Log::debug(sprintf('Search code is %s', $searchCode));
 | ||||||
|                 // see if there is an accompanying start amount.
 |                 // see if there is an accompanying start amount.
 | ||||||
|                 // grab the difference and find the currency.
 |                 // grab the difference and find the currency.
 | ||||||
|                 $startBalance = ($startBalances[$account->id][$key] ?? '0'); |                 $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); |                 $diff         = bcsub($endBalance, $startBalance); | ||||||
|                 $currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode); |                 $currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode); | ||||||
|                 if (0 !== bccomp($diff, '0')) { |                 if (0 !== bccomp($diff, '0')) { | ||||||
| @@ -562,7 +561,6 @@ class AccountController extends Controller | |||||||
|         $currencies    = []; |         $currencies    = []; | ||||||
|         $chartData     = []; |         $chartData     = []; | ||||||
|         $tempData      = []; |         $tempData      = []; | ||||||
|         $default       = Amount::getDefaultCurrency(); |  | ||||||
| 
 | 
 | ||||||
|         // grab all accounts and names
 |         // grab all accounts and names
 | ||||||
|         $accounts      = $this->accountRepository->getAccountsByType([AccountTypeEnum::REVENUE->value]); |         $accounts      = $this->accountRepository->getAccountsByType([AccountTypeEnum::REVENUE->value]); | ||||||
| @@ -598,13 +596,13 @@ class AccountController extends Controller | |||||||
| 
 | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance)); |                 // Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
 | ||||||
|                 $searchCode   = $this->convertToNative ? $default->code : $key; |                 $searchCode   = $this->convertToNative ? $this->defaultCurrency->code : $key; | ||||||
|                 Log::debug(sprintf('Search code is %s', $searchCode)); |                 // Log::debug(sprintf('Search code is %s', $searchCode));
 | ||||||
|                 // see if there is an accompanying start amount.
 |                 // see if there is an accompanying start amount.
 | ||||||
|                 // grab the difference and find the currency.
 |                 // grab the difference and find the currency.
 | ||||||
|                 $startBalance = ($startBalances[$account->id][$key] ?? '0'); |                 $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); |                 $diff         = bcsub($endBalance, $startBalance); | ||||||
|                 $currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode); |                 $currencies[$searchCode] ??= $this->currencyRepository->findByCode($searchCode); | ||||||
|                 if (0 !== bccomp($diff, '0')) { |                 if (0 !== bccomp($diff, '0')) { | ||||||
|   | |||||||
| @@ -234,8 +234,12 @@ class BudgetController extends Controller | |||||||
|             $key                    = sprintf('%d-%d', $journal['source_account_id'], $journal['currency_id']); |             $key                    = sprintf('%d-%d', $journal['source_account_id'], $journal['currency_id']); | ||||||
|             $amount                 = $journal['amount']; |             $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 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) { |             if ($this->convertToNative && $journal['currency_id'] !== $this->defaultCurrency->id) { | ||||||
|                 $key    = sprintf('%d-%d', $journal['source_account_id'], $this->defaultCurrency->id); |                 $key    = sprintf('%d-%d', $journal['source_account_id'], $this->defaultCurrency->id); | ||||||
|                 $symbol = $this->defaultCurrency->symbol; |                 $symbol = $this->defaultCurrency->symbol; | ||||||
|                 $code   = $this->defaultCurrency->code; |                 $code   = $this->defaultCurrency->code; | ||||||
| @@ -243,11 +247,7 @@ class BudgetController extends Controller | |||||||
|                 $amount = $journal['native_amount']; |                 $amount = $journal['native_amount']; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if ($this->convertToNative && $journal['currency_id'] !== $this->defaultCurrency->id && $journal['foreign_currency_id'] === $this->defaultCurrency->id) { |             if ($journal['foreign_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['foreign_amount']; |                 $amount = $journal['foreign_amount']; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @@ -465,7 +465,7 @@ class BudgetController extends Controller | |||||||
|         $chartGenerator->setStart($start); |         $chartGenerator->setStart($start); | ||||||
|         $chartGenerator->setEnd($end); |         $chartGenerator->setEnd($end); | ||||||
|         $chartGenerator->convertToNative = $this->convertToNative; |         $chartGenerator->convertToNative = $this->convertToNative; | ||||||
|         $chartGenerator->default         = Amount::getDefaultCurrency(); |         $chartGenerator->default         = $this->defaultCurrency; | ||||||
| 
 | 
 | ||||||
|         $chartData                       = $chartGenerator->generate(); |         $chartData                       = $chartGenerator->generate(); | ||||||
|         $data                            = $this->generator->multiSet($chartData); |         $data                            = $this->generator->multiSet($chartData); | ||||||
|   | |||||||
| @@ -197,11 +197,11 @@ class CategoryController extends Controller | |||||||
| 
 | 
 | ||||||
|             $chartData[$inKey] |             $chartData[$inKey] | ||||||
|                           = [ |                           = [ | ||||||
|                     'label'           => sprintf('%s (%s)', (string) trans('firefly.earned'), $currencyInfo['currency_name']), |                               'label'           => sprintf('%s (%s)', (string) trans('firefly.earned'), $currencyInfo['currency_name']), | ||||||
|                     'entries'         => [], |                               'entries'         => [], | ||||||
|                     'type'            => 'bar', |                               'type'            => 'bar', | ||||||
|                     'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
 |                               'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
 | ||||||
|                 ]; |                           ]; | ||||||
|             // loop empty periods:
 |             // loop empty periods:
 | ||||||
|             foreach (array_keys($periods) as $period) { |             foreach (array_keys($periods) as $period) { | ||||||
|                 $label                                 = $periods[$period]; |                 $label                                 = $periods[$period]; | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ declare(strict_types=1); | |||||||
| namespace FireflyIII\Http\Controllers; | namespace FireflyIII\Http\Controllers; | ||||||
| 
 | 
 | ||||||
| use FireflyIII\Models\TransactionCurrency; | use FireflyIII\Models\TransactionCurrency; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Facades\Steam; | use FireflyIII\Support\Facades\Steam; | ||||||
| use FireflyIII\Support\Http\Controllers\RequestInformation; | use FireflyIII\Support\Http\Controllers\RequestInformation; | ||||||
| use FireflyIII\Support\Http\Controllers\UserNavigation; | use FireflyIII\Support\Http\Controllers\UserNavigation; | ||||||
| @@ -117,11 +118,11 @@ abstract class Controller extends BaseController | |||||||
|                 $this->defaultCurrency   =null; |                 $this->defaultCurrency   =null; | ||||||
|                 // get shown-intro-preference:
 |                 // get shown-intro-preference:
 | ||||||
|                 if (auth()->check()) { |                 if (auth()->check()) { | ||||||
|                     $this->defaultCurrency   = app('amount')->getDefaultCurrency(); |                     $this->defaultCurrency   = Amount::getDefaultCurrency(); | ||||||
|                     $language  = Steam::getLanguage(); |                     $language  = Steam::getLanguage(); | ||||||
|                     $locale    = Steam::getLocale(); |                     $locale    = Steam::getLocale(); | ||||||
|                     $darkMode  = app('preferences')->get('darkMode', 'browser')->data; |                     $darkMode  = app('preferences')->get('darkMode', 'browser')->data; | ||||||
|                     $this->convertToNative =app('preferences')->get('convert_to_native', false)->data; |                     $this->convertToNative =Amount::convertToNative(); | ||||||
|                     $page      = $this->getPageName(); |                     $page      = $this->getPageName(); | ||||||
|                     $shownDemo = $this->hasSeenDemo(); |                     $shownDemo = $this->hasSeenDemo(); | ||||||
|                     View::share('language', $language); |                     View::share('language', $language); | ||||||
|   | |||||||
| @@ -160,8 +160,8 @@ class DebugController extends Controller | |||||||
|         Artisan::call('view:clear'); |         Artisan::call('view:clear'); | ||||||
| 
 | 
 | ||||||
|         // also do some recalculations.
 |         // also do some recalculations.
 | ||||||
|         Artisan::call('firefly-iii:trigger-credit-recalculation'); |         Artisan::call('correction:recalculates-liabilities'); | ||||||
|         AccountBalanceCalculator::recalculateAll(true); |         AccountBalanceCalculator::recalculateAll(false); | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             Artisan::call('twig:clean'); |             Artisan::call('twig:clean'); | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ namespace FireflyIII\Http\Controllers\ExchangeRates; | |||||||
| use FireflyIII\Http\Controllers\Controller; | use FireflyIII\Http\Controllers\Controller; | ||||||
| use FireflyIII\Models\TransactionCurrency; | use FireflyIII\Models\TransactionCurrency; | ||||||
| use Illuminate\View\View; | use Illuminate\View\View; | ||||||
|  | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; | ||||||
| 
 | 
 | ||||||
| class IndexController extends Controller | class IndexController extends Controller | ||||||
| { | { | ||||||
| @@ -46,6 +47,9 @@ class IndexController extends Controller | |||||||
|                 return $next($request); |                 return $next($request); | ||||||
|             } |             } | ||||||
|         ); |         ); | ||||||
|  |         if (!config('cer.enabled')) { | ||||||
|  |             throw new NotFoundHttpException(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function index(): View |     public function index(): View | ||||||
|   | |||||||
| @@ -78,8 +78,7 @@ class BoxController extends Controller | |||||||
|         $incomes   = []; |         $incomes   = []; | ||||||
|         $expenses  = []; |         $expenses  = []; | ||||||
|         $sums      = []; |         $sums      = []; | ||||||
|         $currency  = app('amount')->getDefaultCurrency(); |         $currency  = $this->defaultCurrency; | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
|         // collect income of user:
 |         // collect income of user:
 | ||||||
|         /** @var GroupCollectorInterface $collector */ |         /** @var GroupCollectorInterface $collector */ | ||||||
| @@ -91,7 +90,7 @@ class BoxController extends Controller | |||||||
| 
 | 
 | ||||||
|         /** @var array $journal */ |         /** @var array $journal */ | ||||||
|         foreach ($set as $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); |             $amount               = Amount::getAmountFromJournal($journal); | ||||||
|             $incomes[$currencyId] ??= '0'; |             $incomes[$currencyId] ??= '0'; | ||||||
|             $incomes[$currencyId] = bcadd($incomes[$currencyId], app('steam')->positive($amount)); |             $incomes[$currencyId] = bcadd($incomes[$currencyId], app('steam')->positive($amount)); | ||||||
| @@ -109,7 +108,7 @@ class BoxController extends Controller | |||||||
| 
 | 
 | ||||||
|         /** @var array $journal */ |         /** @var array $journal */ | ||||||
|         foreach ($set as $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); |             $amount                = Amount::getAmountFromJournal($journal); | ||||||
|             $expenses[$currencyId] ??= '0'; |             $expenses[$currencyId] ??= '0'; | ||||||
|             $expenses[$currencyId] = bcadd($expenses[$currencyId], $amount); |             $expenses[$currencyId] = bcadd($expenses[$currencyId], $amount); | ||||||
| @@ -126,10 +125,10 @@ class BoxController extends Controller | |||||||
|             $expenses[$currencyId] = app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false); |             $expenses[$currencyId] = app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false); | ||||||
|         } |         } | ||||||
|         if (0 === count($sums)) { |         if (0 === count($sums)) { | ||||||
|             $currency                = app('amount')->getDefaultCurrency(); |             $currency                             = $this->defaultCurrency; | ||||||
|             $sums[$currency->id]     = app('amount')->formatAnything($currency, '0', false); |             $sums[$this->defaultCurrency->id]     = app('amount')->formatAnything($this->defaultCurrency, '0', false); | ||||||
|             $incomes[$currency->id]  = app('amount')->formatAnything($currency, '0', false); |             $incomes[$this->defaultCurrency->id]  = app('amount')->formatAnything($this->defaultCurrency, '0', false); | ||||||
|             $expenses[$currency->id] = app('amount')->formatAnything($currency, '0', false); |             $expenses[$this->defaultCurrency->id] = app('amount')->formatAnything($this->defaultCurrency, '0', false); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $response  = [ |         $response  = [ | ||||||
|   | |||||||
| @@ -73,7 +73,7 @@ class ReconcileController extends Controller | |||||||
|     { |     { | ||||||
|         $startBalance    = $request->get('startBalance'); |         $startBalance    = $request->get('startBalance'); | ||||||
|         $endBalance      = $request->get('endBalance'); |         $endBalance      = $request->get('endBalance'); | ||||||
|         $accountCurrency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency(); |         $accountCurrency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency; | ||||||
|         $amount          = '0'; |         $amount          = '0'; | ||||||
|         $clearedAmount   = '0'; |         $clearedAmount   = '0'; | ||||||
| 
 | 
 | ||||||
| @@ -193,7 +193,7 @@ class ReconcileController extends Controller | |||||||
|         $startDate->subDay(); |         $startDate->subDay(); | ||||||
|         $end->endOfDay(); |         $end->endOfDay(); | ||||||
| 
 | 
 | ||||||
|         $currency       = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency(); |         $currency       = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency; | ||||||
|         $startBalance   = Steam::finalAccountBalance($account, $startDate)['balance']; |         $startBalance   = Steam::finalAccountBalance($account, $startDate)['balance']; | ||||||
|         $endBalance     = Steam::finalAccountBalance($account, $end)['balance']; |         $endBalance     = Steam::finalAccountBalance($account, $end)['balance']; | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ declare(strict_types=1); | |||||||
| 
 | 
 | ||||||
| namespace FireflyIII\Http\Controllers; | namespace FireflyIII\Http\Controllers; | ||||||
| 
 | 
 | ||||||
|  | use FireflyIII\Events\Preferences\UserGroupChangedDefaultCurrency; | ||||||
| use FireflyIII\Events\Test\UserTestNotificationChannel; | use FireflyIII\Events\Test\UserTestNotificationChannel; | ||||||
| use FireflyIII\Exceptions\FireflyException; | use FireflyIII\Exceptions\FireflyException; | ||||||
| use FireflyIII\Http\Requests\PreferencesRequest; | use FireflyIII\Http\Requests\PreferencesRequest; | ||||||
| @@ -35,6 +36,7 @@ use Illuminate\Contracts\View\Factory; | |||||||
| use Illuminate\Http\RedirectResponse; | use Illuminate\Http\RedirectResponse; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use Illuminate\Routing\Redirector; | use Illuminate\Routing\Redirector; | ||||||
|  | use Illuminate\Support\Facades\Log; | ||||||
| use Illuminate\View\View; | use Illuminate\View\View; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @@ -258,6 +260,11 @@ class PreferencesController extends Controller | |||||||
| 
 | 
 | ||||||
|         // convert native
 |         // convert native
 | ||||||
|         $convertToNative   = 1 === (int) $request->get('convertToNative'); |         $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); |         app('preferences')->set('convert_to_native', $convertToNative); | ||||||
| 
 | 
 | ||||||
|         // custom fiscal year
 |         // custom fiscal year
 | ||||||
|   | |||||||
| @@ -84,7 +84,7 @@ class CreateController extends Controller | |||||||
|     { |     { | ||||||
|         $budgets           = app('expandedform')->makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets()); |         $budgets           = app('expandedform')->makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets()); | ||||||
|         $bills             = app('expandedform')->makeSelectListWithEmpty($this->billRepository->getActiveBills()); |         $bills             = app('expandedform')->makeSelectListWithEmpty($this->billRepository->getActiveBills()); | ||||||
|         $defaultCurrency   = app('amount')->getDefaultCurrency(); |         $defaultCurrency   = $this->defaultCurrency; | ||||||
|         $tomorrow          = today(config('app.timezone')); |         $tomorrow          = today(config('app.timezone')); | ||||||
|         $oldRepetitionType = $request->old('repetition_type'); |         $oldRepetitionType = $request->old('repetition_type'); | ||||||
|         $tomorrow->addDay(); |         $tomorrow->addDay(); | ||||||
| @@ -129,7 +129,7 @@ class CreateController extends Controller | |||||||
|     { |     { | ||||||
|         $budgets           = app('expandedform')->makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets()); |         $budgets           = app('expandedform')->makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets()); | ||||||
|         $bills             = app('expandedform')->makeSelectListWithEmpty($this->billRepository->getActiveBills()); |         $bills             = app('expandedform')->makeSelectListWithEmpty($this->billRepository->getActiveBills()); | ||||||
|         $defaultCurrency   = app('amount')->getDefaultCurrency(); |         $defaultCurrency   = $this->defaultCurrency; | ||||||
|         $tomorrow          = today(config('app.timezone')); |         $tomorrow          = today(config('app.timezone')); | ||||||
|         $oldRepetitionType = $request->old('repetition_type'); |         $oldRepetitionType = $request->old('repetition_type'); | ||||||
|         $tomorrow->addDay(); |         $tomorrow->addDay(); | ||||||
|   | |||||||
| @@ -62,8 +62,6 @@ class InstallController extends Controller | |||||||
|             'migrate'                            => ['--seed' => true, '--force' => true], |             'migrate'                            => ['--seed' => true, '--force' => true], | ||||||
|             'generate-keys'                      => [], // an exception :(
 |             'generate-keys'                      => [], // an exception :(
 | ||||||
|             'firefly-iii:upgrade-database'       => [], |             'firefly-iii:upgrade-database'       => [], | ||||||
|             'firefly-iii:correct-database'       => [], |  | ||||||
|             'firefly-iii:report-integrity'       => [], |  | ||||||
|             'firefly-iii:set-latest-version'     => ['--james-is-cool' => true], |             'firefly-iii:set-latest-version'     => ['--james-is-cool' => true], | ||||||
|             'firefly-iii:verify-security-alerts' => [], |             'firefly-iii:verify-security-alerts' => [], | ||||||
|         ]; |         ]; | ||||||
|   | |||||||
| @@ -216,15 +216,14 @@ class ConvertController extends Controller | |||||||
|     private function getLiabilities(): array |     private function getLiabilities(): array | ||||||
|     { |     { | ||||||
|         // make repositories
 |         // make repositories
 | ||||||
|         $accountList     = $this->accountRepository->getActiveAccountsByType([AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]); |         $accountList = $this->accountRepository->getActiveAccountsByType([AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]); | ||||||
|         $defaultCurrency = app('amount')->getDefaultCurrency(); |         $grouped     = []; | ||||||
|         $grouped         = []; |  | ||||||
| 
 | 
 | ||||||
|         // group accounts:
 |         // group accounts:
 | ||||||
|         /** @var Account $account */ |         /** @var Account $account */ | ||||||
|         foreach ($accountList as $account) { |         foreach ($accountList as $account) { | ||||||
|             $balance                     = Steam::finalAccountBalance($account, today()->endOfDay())['balance']; |             $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; |             $role                        = 'l_'.$account->accountType->type; | ||||||
|             $key                         = (string) trans('firefly.opt_group_'.$role); |             $key                         = (string) trans('firefly.opt_group_'.$role); | ||||||
|             $grouped[$key][$account->id] = $account->name.' ('.app('amount')->formatAnything($currency, $balance, false).')'; |             $grouped[$key][$account->id] = $account->name.' ('.app('amount')->formatAnything($currency, $balance, false).')'; | ||||||
| @@ -239,15 +238,14 @@ class ConvertController extends Controller | |||||||
|     private function getAssetAccounts(): array |     private function getAssetAccounts(): array | ||||||
|     { |     { | ||||||
|         // make repositories
 |         // make repositories
 | ||||||
|         $accountList     = $this->accountRepository->getActiveAccountsByType([AccountType::ASSET]); |         $accountList = $this->accountRepository->getActiveAccountsByType([AccountType::ASSET]); | ||||||
|         $defaultCurrency = app('amount')->getDefaultCurrency(); |         $grouped     = []; | ||||||
|         $grouped         = []; |  | ||||||
| 
 | 
 | ||||||
|         // group accounts:
 |         // group accounts:
 | ||||||
|         /** @var Account $account */ |         /** @var Account $account */ | ||||||
|         foreach ($accountList as $account) { |         foreach ($accountList as $account) { | ||||||
|             $balance                     = Steam::finalAccountBalance($account, today()->endOfDay())['balance']; |             $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'); |             $role                        = (string) $this->accountRepository->getMetaValue($account, 'account_role'); | ||||||
|             if ('' === $role) { |             if ('' === $role) { | ||||||
|                 $role = 'no_account_type'; |                 $role = 'no_account_type'; | ||||||
|   | |||||||
| @@ -114,7 +114,7 @@ class CreateController extends Controller | |||||||
|         $optionalFields             = app('preferences')->get('transaction_journal_optional_fields', [])->data; |         $optionalFields             = app('preferences')->get('transaction_journal_optional_fields', [])->data; | ||||||
|         $allowedOpposingTypes       = config('firefly.allowed_opposing_types'); |         $allowedOpposingTypes       = config('firefly.allowed_opposing_types'); | ||||||
|         $accountToTypes             = config('firefly.account_to_transaction'); |         $accountToTypes             = config('firefly.account_to_transaction'); | ||||||
|         $defaultCurrency            = app('amount')->getDefaultCurrency(); |         $defaultCurrency            = $this->defaultCurrency; | ||||||
|         $previousUrl                = $this->rememberPreviousUrl('transactions.create.url'); |         $previousUrl                = $this->rememberPreviousUrl('transactions.create.url'); | ||||||
|         $parts                      = parse_url($previousUrl); |         $parts                      = parse_url($previousUrl); | ||||||
|         $search                     = sprintf('?%s', $parts['query'] ?? ''); |         $search                     = sprintf('?%s', $parts['query'] ?? ''); | ||||||
|   | |||||||
| @@ -82,7 +82,7 @@ class EditController extends Controller | |||||||
|         $title                      = $transactionGroup->transactionJournals()->count() > 1 ? $transactionGroup->title : $transactionGroup->transactionJournals()->first()->description; |         $title                      = $transactionGroup->transactionJournals()->count() > 1 ? $transactionGroup->title : $transactionGroup->transactionJournals()->first()->description; | ||||||
|         $subTitle                   = (string) trans('firefly.edit_transaction_title', ['description' => $title]); |         $subTitle                   = (string) trans('firefly.edit_transaction_title', ['description' => $title]); | ||||||
|         $subTitleIcon               = 'fa-plus'; |         $subTitleIcon               = 'fa-plus'; | ||||||
|         $defaultCurrency            = app('amount')->getDefaultCurrency(); |         $defaultCurrency            = $this->defaultCurrency; | ||||||
|         $cash                       = $repository->getCashAccount(); |         $cash                       = $repository->getCashAccount(); | ||||||
|         $previousUrl                = $this->rememberPreviousUrl('transactions.edit.url'); |         $previousUrl                = $this->rememberPreviousUrl('transactions.edit.url'); | ||||||
|         $parts                      = parse_url($previousUrl); |         $parts                      = parse_url($previousUrl); | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ namespace FireflyIII\Http\Middleware; | |||||||
| 
 | 
 | ||||||
| use Carbon\Carbon; | use Carbon\Carbon; | ||||||
| use FireflyIII\Repositories\Journal\JournalRepositoryInterface; | use FireflyIII\Repositories\Journal\JournalRepositoryInterface; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Http\Controllers\RequestInformation; | use FireflyIII\Support\Http\Controllers\RequestInformation; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||||
| @@ -108,7 +109,7 @@ class Range | |||||||
|         setlocale(LC_TIME, $localeArray); |         setlocale(LC_TIME, $localeArray); | ||||||
|         $moneyResult       = setlocale(LC_MONETARY, $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) { |         if (false === $moneyResult) { | ||||||
|             app('log')->error('Could not set locale. The following array doesnt work: ', $localeArray); |             app('log')->error('Could not set locale. The following array doesnt work: ', $localeArray); | ||||||
|             app('view')->share('invalidMonetaryLocale', true); |             app('view')->share('invalidMonetaryLocale', true); | ||||||
| @@ -117,7 +118,7 @@ class Range | |||||||
|         // save some formats:
 |         // save some formats:
 | ||||||
|         $monthAndDayFormat = (string) trans('config.month_and_day_js', [], $locale); |         $monthAndDayFormat = (string) trans('config.month_and_day_js', [], $locale); | ||||||
|         $dateTimeFormat    = (string) trans('config.date_time_js', [], $locale); |         $dateTimeFormat    = (string) trans('config.date_time_js', [], $locale); | ||||||
|         $defaultCurrency   = app('amount')->getDefaultCurrency(); |         $defaultCurrency   = Amount::getDefaultCurrency(); | ||||||
| 
 | 
 | ||||||
|         // also format for moment JS:
 |         // also format for moment JS:
 | ||||||
|         $madMomentJS       = (string) trans('config.month_and_day_moment_js', [], $locale); |         $madMomentJS       = (string) trans('config.month_and_day_moment_js', [], $locale); | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ namespace FireflyIII\Http\Requests; | |||||||
| use FireflyIII\Models\TransactionCurrency; | use FireflyIII\Models\TransactionCurrency; | ||||||
| use FireflyIII\Repositories\Account\AccountRepositoryInterface; | use FireflyIII\Repositories\Account\AccountRepositoryInterface; | ||||||
| use FireflyIII\Rules\IsValidPositiveAmount; | use FireflyIII\Rules\IsValidPositiveAmount; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Request\ChecksLogin; | use FireflyIII\Support\Request\ChecksLogin; | ||||||
| use FireflyIII\Support\Request\ConvertsDataTypes; | use FireflyIII\Support\Request\ConvertsDataTypes; | ||||||
| use Illuminate\Foundation\Http\FormRequest; | use Illuminate\Foundation\Http\FormRequest; | ||||||
| @@ -125,7 +126,7 @@ class PiggyBankStoreRequest extends FormRequest | |||||||
|         $currencyId = (int) ($data['transaction_currency_id'] ?? 0); |         $currencyId = (int) ($data['transaction_currency_id'] ?? 0); | ||||||
|         $currency   = TransactionCurrency::find($currencyId); |         $currency   = TransactionCurrency::find($currencyId); | ||||||
|         if (null === $currency) { |         if (null === $currency) { | ||||||
|             return app('amount')->getDefaultCurrency(); |             return Amount::getDefaultCurrency(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $currency; |         return $currency; | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ use FireflyIII\Models\PiggyBank; | |||||||
| use FireflyIII\Models\TransactionCurrency; | use FireflyIII\Models\TransactionCurrency; | ||||||
| use FireflyIII\Repositories\Account\AccountRepositoryInterface; | use FireflyIII\Repositories\Account\AccountRepositoryInterface; | ||||||
| use FireflyIII\Rules\IsValidPositiveAmount; | use FireflyIII\Rules\IsValidPositiveAmount; | ||||||
|  | use FireflyIII\Support\Facades\Amount; | ||||||
| use FireflyIII\Support\Request\ChecksLogin; | use FireflyIII\Support\Request\ChecksLogin; | ||||||
| use FireflyIII\Support\Request\ConvertsDataTypes; | use FireflyIII\Support\Request\ConvertsDataTypes; | ||||||
| use Illuminate\Foundation\Http\FormRequest; | use Illuminate\Foundation\Http\FormRequest; | ||||||
| @@ -128,7 +129,7 @@ class PiggyBankUpdateRequest extends FormRequest | |||||||
|         $currencyId = (int) ($data['transaction_currency_id'] ?? 0); |         $currencyId = (int) ($data['transaction_currency_id'] ?? 0); | ||||||
|         $currency   = TransactionCurrency::find($currencyId); |         $currency   = TransactionCurrency::find($currencyId); | ||||||
|         if (null === $currency) { |         if (null === $currency) { | ||||||
|             return app('amount')->getDefaultCurrency(); |             return Amount::getDefaultCurrency(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $currency; |         return $currency; | ||||||
|   | |||||||
| @@ -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]); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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) |  | ||||||
|         ; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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()), |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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) |  | ||||||
|         ; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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(), |  | ||||||
|             ], |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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',
 |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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), |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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),
 |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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) |  | ||||||
|         ; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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(), |  | ||||||
|             ], |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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.
 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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 {} |  | ||||||
| @@ -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,
 |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -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
 |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,55 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| declare(strict_types=1); |  | ||||||
| 
 |  | ||||||
| namespace FireflyIII\JsonApi\V2\Users; |  | ||||||
| 
 |  | ||||||
| use FireflyIII\User; |  | ||||||
| use LaravelJsonApi\Eloquent\Contracts\Paginator; |  | ||||||
| use LaravelJsonApi\Eloquent\Fields\DateTime; |  | ||||||
| use LaravelJsonApi\Eloquent\Fields\ID; |  | ||||||
| use LaravelJsonApi\Eloquent\Fields\Relations\HasMany; |  | ||||||
| use LaravelJsonApi\Eloquent\Fields\Str; |  | ||||||
| use LaravelJsonApi\Eloquent\Filters\WhereIdIn; |  | ||||||
| use LaravelJsonApi\Eloquent\Pagination\PagePagination; |  | ||||||
| use LaravelJsonApi\Eloquent\Schema; |  | ||||||
| 
 |  | ||||||
| class UserSchema extends Schema |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * The model the schema corresponds to. |  | ||||||
|      */ |  | ||||||
|     public static string $model = User::class; |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Get the resource fields. |  | ||||||
|      */ |  | ||||||
|     public function fields(): array |  | ||||||
|     { |  | ||||||
|         return [ |  | ||||||
|             ID::make(), |  | ||||||
|             DateTime::make('created_at')->sortable()->readOnly(), |  | ||||||
|             DateTime::make('updated_at')->sortable()->readOnly(), |  | ||||||
|             Str::make('email'), |  | ||||||
|             HasMany::make('accounts'), |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Get the resource filters. |  | ||||||
|      */ |  | ||||||
|     public function filters(): array |  | ||||||
|     { |  | ||||||
|         return [ |  | ||||||
|             WhereIdIn::make($this), |  | ||||||
|         ]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Get the resource paginator. |  | ||||||
|      */ |  | ||||||
|     public function pagination(): ?Paginator |  | ||||||
|     { |  | ||||||
|         return PagePagination::make(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -26,7 +26,6 @@ namespace FireflyIII\Models; | |||||||
| use FireflyIII\Support\Models\ReturnsIntegerIdTrait; | use FireflyIII\Support\Models\ReturnsIntegerIdTrait; | ||||||
| use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait; | use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait; | ||||||
| use FireflyIII\User; | use FireflyIII\User; | ||||||
| use GeneaLabs\LaravelModelCaching\Traits\Cachable; |  | ||||||
| use Illuminate\Database\Eloquent\Builder as EloquentBuilder; | use Illuminate\Database\Eloquent\Builder as EloquentBuilder; | ||||||
| use Illuminate\Database\Eloquent\Casts\Attribute; | use Illuminate\Database\Eloquent\Casts\Attribute; | ||||||
| use Illuminate\Database\Eloquent\Factories\HasFactory; | use Illuminate\Database\Eloquent\Factories\HasFactory; | ||||||
| @@ -44,7 +43,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; | |||||||
|  */ |  */ | ||||||
| class Account extends Model | class Account extends Model | ||||||
| { | { | ||||||
|     use Cachable; |  | ||||||
|     use HasFactory; |     use HasFactory; | ||||||
|     use ReturnsIntegerIdTrait; |     use ReturnsIntegerIdTrait; | ||||||
|     use ReturnsIntegerUserIdTrait; |     use ReturnsIntegerUserIdTrait; | ||||||
| @@ -52,13 +50,14 @@ class Account extends Model | |||||||
| 
 | 
 | ||||||
|     protected $casts |     protected $casts | ||||||
|                                      = [ |                                      = [ | ||||||
|             'created_at'      => 'datetime', |             'created_at'             => 'datetime', | ||||||
|             'updated_at'      => 'datetime', |             'updated_at'             => 'datetime', | ||||||
|             'user_id'         => 'integer', |             'user_id'                => 'integer', | ||||||
|             'deleted_at'      => 'datetime', |             'deleted_at'             => 'datetime', | ||||||
|             'active'          => 'boolean', |             'active'                 => 'boolean', | ||||||
|             'encrypted'       => 'boolean', |             'encrypted'              => 'boolean', | ||||||
|             'virtual_balance' => 'string', |             'virtual_balance'        => 'string', | ||||||
|  |             'native_virtual_balance' => 'string', | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|     protected $fillable              = ['user_id', 'user_group_id', 'account_type_id', 'name', 'active', 'virtual_balance', 'iban', 'native_virtual_balance']; |     protected $fillable              = ['user_id', 'user_group_id', 'account_type_id', 'name', 'active', 'virtual_balance', 'iban', 'native_virtual_balance']; | ||||||
|   | |||||||
| @@ -38,19 +38,20 @@ class AutoBudget extends Model | |||||||
|     use ReturnsIntegerIdTrait; |     use ReturnsIntegerIdTrait; | ||||||
|     use SoftDeletes; |     use SoftDeletes; | ||||||
| 
 | 
 | ||||||
|     #[\Deprecated]
 |     #[\Deprecated] /** @deprecated  */
 | ||||||
|     public const int AUTO_BUDGET_ADJUSTED = 3; |     public const int AUTO_BUDGET_ADJUSTED = 3; | ||||||
| 
 | 
 | ||||||
|     #[\Deprecated]
 |     #[\Deprecated] /** @deprecated  */
 | ||||||
|     public const int AUTO_BUDGET_RESET    = 1; |     public const int AUTO_BUDGET_RESET    = 1; | ||||||
| 
 | 
 | ||||||
|     #[\Deprecated]
 |     #[\Deprecated] /** @deprecated  */
 | ||||||
|     public const int AUTO_BUDGET_ROLLOVER = 2; |     public const int AUTO_BUDGET_ROLLOVER = 2; | ||||||
|     protected $casts |     protected $casts | ||||||
|                                           = [ |                                           = [ | ||||||
|             'amount' => 'string', |             'amount'        => 'string', | ||||||
|  |             'native_amount' => 'string', | ||||||
|         ]; |         ]; | ||||||
|     protected $fillable                   = ['budget_id', 'amount', 'period']; |     protected $fillable                   = ['budget_id', 'amount', 'period', 'native_amount']; | ||||||
| 
 | 
 | ||||||
|     public function budget(): BelongsTo |     public function budget(): BelongsTo | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ declare(strict_types=1); | |||||||
| 
 | 
 | ||||||
| namespace FireflyIII\Models; | namespace FireflyIII\Models; | ||||||
| 
 | 
 | ||||||
|  | use Carbon\Carbon; | ||||||
| use FireflyIII\Support\Models\ReturnsIntegerIdTrait; | use FireflyIII\Support\Models\ReturnsIntegerIdTrait; | ||||||
| use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait; | use FireflyIII\Support\Models\ReturnsIntegerUserIdTrait; | ||||||
| use FireflyIII\User; | use FireflyIII\User; | ||||||
| @@ -50,9 +51,10 @@ class AvailableBudget extends Model | |||||||
|             'end_date'                => 'date', |             'end_date'                => 'date', | ||||||
|             'transaction_currency_id' => 'int', |             'transaction_currency_id' => 'int', | ||||||
|             'amount'                  => 'string', |             'amount'                  => 'string', | ||||||
|  |             'native_amount'           => 'string', | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|     protected $fillable = ['user_id', 'user_group_id', 'transaction_currency_id', 'amount', 'start_date', 'end_date', 'start_date_tz', 'end_date_tz']; |     protected $fillable = ['user_id', 'user_group_id', 'transaction_currency_id', 'amount', 'start_date', 'end_date', 'start_date_tz', 'end_date_tz', 'native_amount']; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Route binder. Converts the key in the URL to the specified object (or throw 404). |      * Route binder. Converts the key in the URL to the specified object (or throw 404). | ||||||
| @@ -100,4 +102,20 @@ class AvailableBudget extends Model | |||||||
|             get: static fn ($value) => (int) $value, |             get: static fn ($value) => (int) $value, | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     protected function startDate(): Attribute | ||||||
|  |     { | ||||||
|  |         return Attribute::make( | ||||||
|  |             get: fn (string $value) => Carbon::parse($value), | ||||||
|  |             set: fn (Carbon $value) => $value->format('Y-m-d'), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected function endDate(): Attribute | ||||||
|  |     { | ||||||
|  |         return Attribute::make( | ||||||
|  |             get: fn (string $value) => Carbon::parse($value), | ||||||
|  |             set: fn (Carbon $value) => $value->format('Y-m-d'), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user