mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-31 10:47:00 +00:00 
			
		
		
		
	Compare commits
	
		
			168 Commits
		
	
	
		
			develop-20
			...
			develop-20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c525c70ec0 | ||
|  | 1f7d6e218b | ||
|  | a69b6d9ce2 | ||
|  | 28b2ddde18 | ||
|  | a16cc73c77 | ||
|  | 46395e350a | ||
|  | f62e49090c | ||
|  | af3b40a314 | ||
|  | c3cea0fa9e | ||
|  | 6cbdb2ce70 | ||
|  | b78460100d | ||
|  | bf6e1cb0e1 | ||
|  | 6a53f5031c | ||
|  | ae15ec01e8 | ||
|  | fe3c7c47c4 | ||
|  | 68b934010c | ||
|  | 22852bd238 | ||
|  | 5b3b1804f3 | ||
|  | f2588eb343 | ||
|  | 64a643ceec | ||
|  | 1add505644 | ||
|  | 9663eb6a19 | ||
|  | f30a24a02f | ||
|  | 68655d60a6 | ||
|  | 63b0efcd81 | ||
|  | 93284682c8 | ||
|  | 3bafcb6ad2 | ||
|  | 942d027556 | ||
|  | a60882d5f5 | ||
|  | 680f554981 | ||
|  | 20e4dc07ce | ||
|  | 184d8eb027 | ||
|  | 59725b088a | ||
|  | 32fca4a9f5 | ||
|  | 7dccf6ec48 | ||
|  | 917665feac | ||
|  | 06c50b68c2 | ||
|  | 7035c399d8 | ||
|  | 7c0ac5805c | ||
|  | 3424741583 | ||
|  | baf0297994 | ||
|  | 31d06752fa | ||
|  | 8a27154798 | ||
|  | 6d87e38ec0 | ||
|  | ccdc30a6fb | ||
|  | 90005538d3 | ||
|  | f4e0428ebc | ||
|  | bd1326eca9 | ||
|  | bdfa834251 | ||
|  | 4a9aeb4e44 | ||
|  | 3886c0fbde | ||
|  | d998eff56e | ||
|  | d73df9bf0a | ||
|  | 754f2f3a34 | ||
|  | 43fd7c928a | ||
|  | 05768c2e73 | ||
|  | 3feb2c9955 | ||
|  | 7d9f3ac473 | ||
|  | 8a5755c8f1 | ||
|  | a75a760019 | ||
|  | 78d1a130d2 | ||
|  | 79fd43f32b | ||
|  | 7a7bd65a27 | ||
|  | 01a9ecccac | ||
|  | c1b3c71090 | ||
|  | 323d04fe6c | ||
|  | 80c2f1ea3f | ||
|  | 784494871d | ||
|  | 8e93af5cc7 | ||
|  | ebfdeeedaa | ||
|  | 1d02ed6a56 | ||
|  | cca53cb0e8 | ||
|  | ab33aee4b1 | ||
|  | 41d4fab071 | ||
|  | f0a1913dc6 | ||
|  | b956b463c2 | ||
|  | 43603c4990 | ||
|  | 196e738f60 | ||
|  | 59e2ea357a | ||
|  | 5e9d942069 | ||
|  | 53d5bedd85 | ||
|  | 49c68af07b | ||
|  | c84c8e1aef | ||
|  | a8d43d7174 | ||
|  | 1087278890 | ||
|  | ae5912ab52 | ||
|  | 035bd96ae5 | ||
|  | 7283c616a0 | ||
|  | 5706666bb6 | ||
|  | 4607466fb6 | ||
|  | 34bcfcfe9b | ||
|  | 05986cb6a6 | ||
|  | 0c4ee9f043 | ||
|  | ff222795cf | ||
|  | e0c76695ee | ||
|  | ae126e8322 | ||
|  | 8f9c35fbe8 | ||
|  | 84efd6e2ee | ||
|  | b1fbe4e909 | ||
|  | 8576877072 | ||
|  | c298aced01 | ||
|  | ac61a78d8d | ||
|  | fce90a94c4 | ||
|  | 023a4f178d | ||
|  | ef254995ad | ||
|  | faeb74634b | ||
|  | b5baae373f | ||
|  | 63de711cda | ||
|  | bd28d116cb | ||
|  | 7efc2861bc | ||
|  | 5c689a2ca2 | ||
|  | d5d65df76f | ||
|  | df7d4f700c | ||
|  | efebe3cb41 | ||
|  | 2ba5b6ae49 | ||
|  | 31d93efab2 | ||
|  | 657b95485c | ||
|  | 3bfc12f93b | ||
|  | ccfd2f2ac3 | ||
|  | fb3fe0d87b | ||
|  | c80c6d52fe | ||
|  | 0fb3c0c7bf | ||
|  | 43c625bee2 | ||
|  | 967a5dd256 | ||
|  | 3c9d1bcaa1 | ||
|  | 8cd2de14a9 | ||
|  | 7728a35e04 | ||
|  | 49000da123 | ||
|  | 32a8f89875 | ||
|  | 49e5a81bd3 | ||
|  | a8efe86af0 | ||
|  | 4f07b089d2 | ||
|  | e786bf47c2 | ||
|  | be11778c53 | ||
|  | 3d7325424c | ||
|  | f4ffed99ef | ||
|  | 52dfe9a738 | ||
|  | a0bc8b2ba2 | ||
|  | 4ffca9e2ca | ||
|  | a6afec9afa | ||
|  | 5d859222f8 | ||
|  | 0e3ba14666 | ||
|  | 860767fe5a | ||
|  | 91b0ad625c | ||
|  | 67bab2561a | ||
|  | b7908ebcb4 | ||
|  | a20601ea85 | ||
|  | 14622329a8 | ||
|  | 5577be7b08 | ||
|  | e3bab9d7d8 | ||
|  | e0512bee3d | ||
|  | 20827a5fd1 | ||
|  | 8819dac1e1 | ||
|  | da0a07262c | ||
|  | 9c195dcc66 | ||
|  | 0b45506e52 | ||
|  | 51e58f8d88 | ||
|  | d0c658e79a | ||
|  | 35e0791a9f | ||
|  | 637ecc66d2 | ||
|  | 3a38175b2a | ||
|  | d78fd86d7a | ||
|  | 395332d6dd | ||
|  | c5cbceb81a | ||
|  | adbf785aba | ||
|  | 1fae39a49d | ||
|  | 659240a98b | ||
|  | e9644c9679 | 
| @@ -19,26 +19,25 @@ | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| use PhpCsFixer\Runner\Parallel\ParallelConfigFactory; | ||||
| 
 | ||||
| $current = __DIR__; | ||||
| 
 | ||||
| $paths = [ | ||||
|     $current . '/../../app', | ||||
|     $current . '/../../config', | ||||
|     $current . '/../../database', | ||||
|     $current . '/../../routes', | ||||
|     $current . '/../../tests', | ||||
|     $current . '/../../resources/lang/en_US', | ||||
| ]; | ||||
| 
 | ||||
| $finder = PhpCsFixer\Finder::create() | ||||
|                            ->in($paths); | ||||
| 
 | ||||
| 
 | ||||
| $config = new PhpCsFixer\Config(); | ||||
| $config->setParallelConfig(ParallelConfigFactory::detect()); | ||||
| $config = (new PhpCsFixer\Config()) | ||||
|         // ->setUnsupportedPhpVersionAllowed(true) // use this when PHP 8.5 comes out.
 | ||||
|         ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()) | ||||
|         ; | ||||
| return $config->setRules( | ||||
| 
 | ||||
|     [ | ||||
|         // rule sets
 | ||||
|         '@PHP83Migration'               => true, | ||||
| @@ -53,9 +52,6 @@ return $config->setRules( | ||||
|         'statement_indentation'         => true, | ||||
|         'void_return'                   => true, | ||||
| 
 | ||||
|         // about importing statements
 | ||||
|         'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true], | ||||
| 
 | ||||
|         // disabled rules
 | ||||
|         'native_function_invocation'    => false, // annoying
 | ||||
|         'php_unit_data_provider_name'   => false, // bloody annoying long test names
 | ||||
| @@ -64,9 +60,15 @@ return $config->setRules( | ||||
|         'comment_to_phpdoc'             => false, // breaks phpstan lines in combination with PHPStorm.
 | ||||
|         'type_declaration_spaces'       => false, | ||||
|         'cast_spaces'                   => false, | ||||
|         'phpdoc_to_comment'             => false, // do not overrule single line comment style, breaks phpstan.
 | ||||
| 
 | ||||
|         // enabled rules
 | ||||
|         'global_namespace_import' => true, // matches with rector.
 | ||||
| 
 | ||||
|         // complex rules
 | ||||
|         'phpdoc_to_comment' => ['ignored_tags' => ['var']], | ||||
|         'php_unit_test_case_static_method_calls' => [ | ||||
|             'call_type' => 'this', | ||||
|         ], | ||||
|         'array_syntax'                  => ['syntax' => 'short'], | ||||
|         'binary_operator_spaces'        => [ | ||||
|             'default'   => 'at_least_single_space', | ||||
| @@ -76,5 +78,7 @@ return $config->setRules( | ||||
|                 '??=' => 'align_single_space_minimal_by_scope', | ||||
|             ], | ||||
|         ], | ||||
|     ]) | ||||
|     ] | ||||
| 
 | ||||
| ) | ||||
|               ->setFinder($finder); | ||||
|   | ||||
							
								
								
									
										65
									
								
								.ci/php-cs-fixer/composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										65
									
								
								.ci/php-cs-fixer/composer.lock
									
									
									
										generated
									
									
									
								
							| @@ -406,58 +406,59 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "friendsofphp/php-cs-fixer", | ||||
|             "version": "v3.75.0", | ||||
|             "version": "v3.84.0", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", | ||||
|                 "reference": "399a128ff2fdaf4281e4e79b755693286cdf325c" | ||||
|                 "reference": "38dad0767bf2a9b516b976852200ae722fe984ca" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/399a128ff2fdaf4281e4e79b755693286cdf325c", | ||||
|                 "reference": "399a128ff2fdaf4281e4e79b755693286cdf325c", | ||||
|                 "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/38dad0767bf2a9b516b976852200ae722fe984ca", | ||||
|                 "reference": "38dad0767bf2a9b516b976852200ae722fe984ca", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "clue/ndjson-react": "^1.0", | ||||
|                 "composer/semver": "^3.4", | ||||
|                 "composer/xdebug-handler": "^3.0.3", | ||||
|                 "composer/xdebug-handler": "^3.0.5", | ||||
|                 "ext-filter": "*", | ||||
|                 "ext-hash": "*", | ||||
|                 "ext-json": "*", | ||||
|                 "ext-tokenizer": "*", | ||||
|                 "fidry/cpu-core-counter": "^1.2", | ||||
|                 "php": "^7.4 || ^8.0", | ||||
|                 "react/child-process": "^0.6.5", | ||||
|                 "react/child-process": "^0.6.6", | ||||
|                 "react/event-loop": "^1.0", | ||||
|                 "react/promise": "^2.0 || ^3.0", | ||||
|                 "react/promise": "^2.11 || ^3.0", | ||||
|                 "react/socket": "^1.0", | ||||
|                 "react/stream": "^1.0", | ||||
|                 "sebastian/diff": "^4.0 || ^5.1 || ^6.0 || ^7.0", | ||||
|                 "symfony/console": "^5.4 || ^6.4 || ^7.0", | ||||
|                 "symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", | ||||
|                 "symfony/filesystem": "^5.4 || ^6.4 || ^7.0", | ||||
|                 "symfony/finder": "^5.4 || ^6.4 || ^7.0", | ||||
|                 "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0", | ||||
|                 "symfony/polyfill-mbstring": "^1.31", | ||||
|                 "symfony/polyfill-php80": "^1.31", | ||||
|                 "symfony/polyfill-php81": "^1.31", | ||||
|                 "symfony/process": "^5.4 || ^6.4 || ^7.2", | ||||
|                 "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" | ||||
|                 "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", | ||||
|                 "symfony/console": "^5.4.45 || ^6.4.13 || ^7.0", | ||||
|                 "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", | ||||
|                 "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", | ||||
|                 "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", | ||||
|                 "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", | ||||
|                 "symfony/polyfill-mbstring": "^1.32", | ||||
|                 "symfony/polyfill-php80": "^1.32", | ||||
|                 "symfony/polyfill-php81": "^1.32", | ||||
|                 "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", | ||||
|                 "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "facile-it/paraunit": "^1.3.1 || ^2.6", | ||||
|                 "infection/infection": "^0.29.14", | ||||
|                 "justinrainbow/json-schema": "^5.3 || ^6.2", | ||||
|                 "keradus/cli-executor": "^2.1", | ||||
|                 "justinrainbow/json-schema": "^5.3 || ^6.4", | ||||
|                 "keradus/cli-executor": "^2.2", | ||||
|                 "mikey179/vfsstream": "^1.6.12", | ||||
|                 "php-coveralls/php-coveralls": "^2.7", | ||||
|                 "php-coveralls/php-coveralls": "^2.8", | ||||
|                 "php-cs-fixer/accessible-object": "^1.1", | ||||
|                 "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", | ||||
|                 "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", | ||||
|                 "phpunit/phpunit": "^9.6.22 || ^10.5.45 || ^11.5.12", | ||||
|                 "symfony/var-dumper": "^5.4.48 || ^6.4.18 || ^7.2.3", | ||||
|                 "symfony/yaml": "^5.4.45 || ^6.4.18 || ^7.2.3" | ||||
|                 "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", | ||||
|                 "symfony/polyfill-php84": "^1.32", | ||||
|                 "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", | ||||
|                 "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" | ||||
|             }, | ||||
|             "suggest": { | ||||
|                 "ext-dom": "For handling output formats in XML", | ||||
| @@ -498,7 +499,7 @@ | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", | ||||
|                 "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.75.0" | ||||
|                 "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.84.0" | ||||
|             }, | ||||
|             "funding": [ | ||||
|                 { | ||||
| @@ -506,7 +507,7 @@ | ||||
|                     "type": "github" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2025-03-31T18:40:42+00:00" | ||||
|             "time": "2025-07-15T18:21:57+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "psr/container", | ||||
| @@ -1256,16 +1257,16 @@ | ||||
|         }, | ||||
|         { | ||||
|             "name": "symfony/console", | ||||
|             "version": "v7.3.0", | ||||
|             "version": "v7.3.1", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/symfony/console.git", | ||||
|                 "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44" | ||||
|                 "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44", | ||||
|                 "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44", | ||||
|                 "url": "https://api.github.com/repos/symfony/console/zipball/9e27aecde8f506ba0fd1d9989620c04a87697101", | ||||
|                 "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
| @@ -1330,7 +1331,7 @@ | ||||
|                 "terminal" | ||||
|             ], | ||||
|             "support": { | ||||
|                 "source": "https://github.com/symfony/console/tree/v7.3.0" | ||||
|                 "source": "https://github.com/symfony/console/tree/v7.3.1" | ||||
|             }, | ||||
|             "funding": [ | ||||
|                 { | ||||
| @@ -1346,7 +1347,7 @@ | ||||
|                     "type": "tidelift" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2025-05-24T10:34:04+00:00" | ||||
|             "time": "2025-06-27T19:55:54+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "symfony/deprecation-contracts", | ||||
|   | ||||
| @@ -26,9 +26,10 @@ SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) | ||||
| cd $SCRIPT_DIR/php-cs-fixer | ||||
| composer update --quiet | ||||
| rm -f .php-cs-fixer.cache | ||||
| PHP_CS_FIXER_IGNORE_ENV=true ./vendor/bin/php-cs-fixer fix \ | ||||
| ./vendor/bin/php-cs-fixer fix \ | ||||
|     --config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php \ | ||||
|     --format=txt -v \ | ||||
|     --format=txt \ | ||||
|     -v \ | ||||
|     --allow-risky=yes | ||||
|  | ||||
| EXIT_CODE=$? | ||||
|   | ||||
| @@ -25,6 +25,7 @@ declare(strict_types=1); | ||||
| 
 | ||||
| use Rector\Config\RectorConfig; | ||||
| use Rector\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector; | ||||
| use Rector\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector; | ||||
| use Rector\Transform\Rector\String_\StringToClassConstantRector; | ||||
| use RectorLaravel\Set\LaravelLevelSetList; | ||||
| 
 | ||||
| @@ -32,6 +33,7 @@ use RectorLaravel\Set\LaravelLevelSetList; | ||||
| return RectorConfig::configure() | ||||
|     ->withSkip([ | ||||
|         ChangeOrIfContinueToMultiContinueRector::class, | ||||
|         AddParamBasedOnParentClassMethodRector::class, | ||||
|         StringToClassConstantRector::class => [ | ||||
|             __DIR__ . '/../app/Http/Controllers/Auth/LoginController.php', | ||||
|         ], | ||||
|   | ||||
| @@ -329,7 +329,7 @@ FIREFLY_III_LAYOUT=v1 | ||||
| # Which Query Parser implementation to use for the search engine and rules | ||||
| # 'new' is experimental, 'legacy' is the classic one | ||||
| # | ||||
| QUERY_PARSER_IMPLEMENTATION=legacy | ||||
| QUERY_PARSER_IMPLEMENTATION=new | ||||
|  | ||||
| # | ||||
| # Please make sure this URL matches the external URL of your Firefly III installation. | ||||
|   | ||||
							
								
								
									
										13
									
								
								.github/ISSUE_TEMPLATE/bug.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								.github/ISSUE_TEMPLATE/bug.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| name: Bug Report | ||||
| name: Bug report | ||||
| description: Report a bug in Firefly III (or associated tools) | ||||
| body: | ||||
|   - type: checkboxes | ||||
| @@ -12,7 +12,7 @@ body: | ||||
|   - type: checkboxes | ||||
|     attributes: | ||||
|       label: I've found a bug and checked that ... | ||||
|       description: Make sure that your request fulfills all of the following requirements. If one requirement cannot be satisfied, explain in detail why. | ||||
|       description: Make sure that your request fulfills all of the following requirements. If one requirement cannot be satisfied, please explain why. | ||||
|       options: | ||||
|         - label: ... [the documentation](https://docs.firefly-iii.org/) does not mention anything about my problem | ||||
|         - label: ... there are no open or closed issues that are related to my problem | ||||
| @@ -33,13 +33,6 @@ body: | ||||
|     validations: | ||||
|       required: true | ||||
|  | ||||
|   - type: textarea | ||||
|     attributes: | ||||
|       label: Expected behaviour | ||||
|       description: Please describe precisely what you'd expect to happen. Be specific. | ||||
|     validations: | ||||
|       required: false | ||||
|  | ||||
|   - type: textarea | ||||
|     attributes: | ||||
|       label: Steps to reproduce | ||||
| @@ -54,4 +47,4 @@ body: | ||||
|   - type: textarea | ||||
|     attributes: | ||||
|       label: Additional info | ||||
|       description: Please provide any additional information that seem useful. | ||||
|       description: Please provide any additional information that seems useful. | ||||
|   | ||||
							
								
								
									
										3
									
								
								.github/ISSUE_TEMPLATE/config.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/ISSUE_TEMPLATE/config.yml
									
									
									
									
										vendored
									
									
								
							| @@ -3,3 +3,6 @@ contact_links: | ||||
|   - name: Ask a question | ||||
|     url: https://github.com/firefly-iii/firefly-iii/discussions | ||||
|     about: Please ask and answer questions here. | ||||
|   - name: I need support!  | ||||
|     url: https://github.com/firefly-iii/firefly-iii/discussions | ||||
|     about: I think I broke something... | ||||
|   | ||||
							
								
								
									
										7
									
								
								.github/ISSUE_TEMPLATE/fr.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.github/ISSUE_TEMPLATE/fr.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| name: Feature Request | ||||
| name: Feature request | ||||
| description: Request a feature or enhancement in Firefly III (or associated tools) | ||||
| body: | ||||
|   - type: checkboxes | ||||
| @@ -31,11 +31,6 @@ body: | ||||
|     validations: | ||||
|       required: true | ||||
|  | ||||
|   - type: textarea | ||||
|     attributes: | ||||
|       label: What are alternatives? | ||||
|       description: Please describe what alternatives currently exist. | ||||
|  | ||||
|   - type: textarea | ||||
|     attributes: | ||||
|       label: Additional context | ||||
|   | ||||
							
								
								
									
										1
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							| @@ -66,7 +66,6 @@ jobs: | ||||
|               'label-actions.yml', | ||||
|               'lock.yml', | ||||
|               'release.yml', | ||||
|               'sonarcloud.yml', | ||||
|               'stale.yml' | ||||
|             ] | ||||
|  | ||||
|   | ||||
							
								
								
									
										28
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -259,6 +259,12 @@ jobs: | ||||
|             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 "" >> output.txt | ||||
|             echo ":warning: Please be careful with this pre-release, as it may not work as expected." >> output.txt | ||||
|  | ||||
|             # donations! | ||||
|             echo '' >> output.txt | ||||
|             echo '### Support Firefly III' >> output.txt | ||||
|             echo 'Did you know you can support the development of Firefly III? You can donate in many ways, like GitHub Sponsors or Patreon. For more information, please [follow this link](https://bit.ly/donate-to-Firefly-III) for more information.' >> output.txt | ||||
|             echo '' >> output.txt | ||||
|           fi | ||||
|           # describe a branch release | ||||
|           if [[ "$version" == branch* ]]; then | ||||
| @@ -279,16 +285,31 @@ jobs: | ||||
|           if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]] && [[ "$version" != *alpha* ]] && [[ "$version" != *beta* ]]; then | ||||
|             echo 'Describe the latest release' | ||||
|             sudo chown -R runner:docker output.txt | ||||
|  | ||||
|             # the changelog is in output.txt | ||||
|             mv output.txt output2.txt | ||||
|  | ||||
|             touch output.txt | ||||
|             echo '' >> output.txt | ||||
|             echo "Welcome to release $version of Firefly III. It contains the the latest fixes, translations and features. Docker users can find this release under the \`latest\` tag." >> output.txt | ||||
|             echo '' >> output.txt | ||||
|  | ||||
|             # add changelog to file. | ||||
|             cat output2.txt >> output.txt | ||||
|             echo '' >> output.txt | ||||
|             rm -f output2.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 | ||||
|  | ||||
|             # donations! | ||||
|             echo '' >> output.txt | ||||
|             echo '### Support Firefly III' >> output.txt | ||||
|             echo 'Did you know you can support the development of Firefly III? You can donate in many ways, like GitHub Sponsors or Patreon. For more information, please [follow this link](https://bit.ly/donate-to-Firefly-III) for more information.' >> output.txt | ||||
|             echo '' >> output.txt | ||||
|           fi | ||||
|  | ||||
|           # describe alpha release | ||||
| @@ -465,20 +486,27 @@ jobs: | ||||
|       - name: Upload artifacts | ||||
|         run: | | ||||
|           # add zip file to release. | ||||
|           echo "Upload $zipName to $releaseName" | ||||
|           gh release upload $releaseName $zipName | ||||
|           echo "Upload $tarName to $releaseName" | ||||
|           gh release upload $releaseName $tarName | ||||
|  | ||||
|           # add sha256 sum to release | ||||
|           echo "Upload $zipName.sha256 to $releaseName" | ||||
|           gh release upload $releaseName $zipName.sha256 | ||||
|           echo "Upload $tarName.sha256 to $releaseName" | ||||
|           gh release upload $releaseName $tarName.sha256 | ||||
|  | ||||
|           # add signatures to release | ||||
|           echo "Upload $zipName.asc to $releaseName" | ||||
|           gh release upload $releaseName $zipName.asc | ||||
|           echo "Upload $tarName.asc to $releaseName" | ||||
|           gh release upload $releaseName $tarName.asc | ||||
|  | ||||
|           # get current HEAD and add as file to the release | ||||
|           HEAD=$(git rev-parse HEAD) | ||||
|           echo $HEAD > HEAD.txt | ||||
|           echo "Upload HEAD.txt to $releaseName" | ||||
|           gh release upload $releaseName HEAD.txt | ||||
|  | ||||
|           # remove all temporary files | ||||
|   | ||||
							
								
								
									
										71
									
								
								.github/workflows/sonarcloud.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								.github/workflows/sonarcloud.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,71 +0,0 @@ | ||||
| name: 'Code - Run Sonarcloud' | ||||
| on: | ||||
|   pull_request: | ||||
|   workflow_dispatch: | ||||
|   push: | ||||
|     branches: | ||||
|       - main | ||||
| env: | ||||
|   DB_CONNECTION: sqlite | ||||
|   APP_KEY: TestTestTestTestTestTestTestTest | ||||
| jobs: | ||||
|   sonarcloud: | ||||
|     name: SonarCloud | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|       - name: Setup PHP with Xdebug | ||||
|         uses: shivammathur/setup-php@v2 | ||||
|         with: | ||||
|           php-version: '8.4' | ||||
|           coverage: xdebug | ||||
|           extensions: >- | ||||
|             bcmath | ||||
|             curl | ||||
|             fileinfo | ||||
|             iconv | ||||
|             intl | ||||
|             json | ||||
|             sqlite3 | ||||
|             mbstring | ||||
|             openssl | ||||
|             pdo | ||||
|             session | ||||
|             simplexml | ||||
|             sodium | ||||
|             tokenizer | ||||
|             xml | ||||
|             xmlwriter | ||||
|  | ||||
|       - name: Copy standard configuration | ||||
|         run: cp .env.testing .env | ||||
|  | ||||
|       - name: Install Composer dependencies | ||||
|         run: composer install --prefer-dist --no-interaction --no-progress --no-scripts | ||||
|  | ||||
|       - name: "Create database file" | ||||
|         run: | | ||||
|           touch storage/database/database.sqlite | ||||
|           wget -q https://github.com/firefly-iii/test-fixtures/raw/refs/heads/main/test-database.sqlite -O storage/database/database.sqlite | ||||
|  | ||||
|       - name: "Upgrades the database to the latest version" | ||||
|         run: | | ||||
|           php artisan firefly-iii:upgrade-database | ||||
|           chmod 600 storage/oauth-public.key | ||||
|           chmod 600 storage/oauth-private.key | ||||
|  | ||||
|       - name: "Integrity Database Report" | ||||
|         run: php artisan firefly-iii:report-integrity | ||||
|  | ||||
|       - name: "Run tests with coverage" | ||||
|         run: composer coverage | ||||
|  | ||||
|       - name: Fix code coverage paths | ||||
|         run: sed -i 's@'$GITHUB_WORKSPACE'@/github/workspace/@g' coverage.xml | ||||
|  | ||||
|       - name: SonarCloud Scan | ||||
|         uses: SonarSource/sonarqube-scan-action@v5.2.0 | ||||
|         env: | ||||
|           GITHUB_TOKEN: ${{ secrets.GH_ACTIONS_PERSONAL_ACCESS_TOKEN }} | ||||
|           SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | ||||
| @@ -24,6 +24,7 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Api\V1\Controllers\Autocomplete; | ||||
| 
 | ||||
| use Deprecated; | ||||
| use FireflyIII\Api\V1\Controllers\Controller; | ||||
| use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest; | ||||
| use FireflyIII\Models\TransactionCurrency; | ||||
| @@ -83,9 +84,8 @@ class CurrencyController extends Controller | ||||
|     /** | ||||
|      * Documentation for this endpoint is at: | ||||
|      * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getCurrenciesCodeAC
 | ||||
|      * | ||||
|      * @deprecated | ||||
|      */ | ||||
|     #[Deprecated]
 | ||||
|     public function currenciesWithCode(AutocompleteRequest $request): JsonResponse | ||||
|     { | ||||
|         $data       = $request->getData(); | ||||
|   | ||||
| @@ -24,22 +24,25 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Api\V1\Controllers\Chart; | ||||
| 
 | ||||
| use FireflyIII\Models\TransactionCurrency; | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Api\V1\Controllers\Controller; | ||||
| use FireflyIII\Api\V1\Requests\Chart\ChartRequest; | ||||
| use FireflyIII\Api\V1\Requests\Data\DateRequest; | ||||
| use FireflyIII\Enums\AccountTypeEnum; | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| use FireflyIII\Exceptions\ValidationException; | ||||
| use FireflyIII\Models\Account; | ||||
| use FireflyIII\Models\Preference; | ||||
| use FireflyIII\Models\TransactionCurrency; | ||||
| use FireflyIII\Repositories\Account\AccountRepositoryInterface; | ||||
| use FireflyIII\Support\Chart\ChartData; | ||||
| use FireflyIII\Support\Facades\Preferences; | ||||
| use FireflyIII\Support\Facades\Steam; | ||||
| use FireflyIII\Support\Http\Api\ApiSupport; | ||||
| use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| 
 | ||||
| /** | ||||
|  * Class AccountController | ||||
| @@ -84,10 +87,12 @@ class AccountController extends Controller | ||||
|         // move date to end of day
 | ||||
|         $queryParameters['start']->startOfDay(); | ||||
|         $queryParameters['end']->endOfDay(); | ||||
|         Log::debug(sprintf('dashboard(), convert to native: %s', var_export($this->convertToNative, true))); | ||||
| 
 | ||||
|         // loop each account, and collect info:
 | ||||
|         /** @var Account $account */ | ||||
|         foreach ($accounts as $account) { | ||||
|             Log::debug(sprintf('Account #%d ("%s")', $account->id, $account->name)); | ||||
|             $this->renderAccountData($queryParameters, $account); | ||||
|         } | ||||
| 
 | ||||
| @@ -99,15 +104,22 @@ class AccountController extends Controller | ||||
|      */ | ||||
|     private function renderAccountData(array $params, Account $account): void | ||||
|     { | ||||
|         $currency     = $this->repository->getAccountCurrency($account); | ||||
|         Log::debug(sprintf('Now in %s(array, #%d)', __METHOD__, $account->id)); | ||||
|         $currency       = $this->repository->getAccountCurrency($account); | ||||
|         $currentStart   = clone $params['start']; | ||||
|         $range          = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative); | ||||
| 
 | ||||
| 
 | ||||
|         $previous       = array_values($range)[0]['balance']; | ||||
|         $nativePrevious = null; | ||||
|         if (!$currency instanceof TransactionCurrency) { | ||||
|             $currency = $this->default; | ||||
|         } | ||||
|         $currentSet   = [ | ||||
|         $currentSet     = [ | ||||
|             'label'                   => $account->name, | ||||
| 
 | ||||
|             // the currency that belongs to the account.
 | ||||
|             'currency_id'             => (string) $currency->id, | ||||
|             'currency_id'             => (string)$currency->id, | ||||
|             'currency_code'           => $currency->code, | ||||
|             'currency_symbol'         => $currency->symbol, | ||||
|             'currency_decimal_places' => $currency->decimal_places, | ||||
| @@ -119,18 +131,33 @@ class AccountController extends Controller | ||||
|             'period'                  => '1D', | ||||
|             'entries'                 => [], | ||||
|         ]; | ||||
|         $currentStart = clone $params['start']; | ||||
|         $range        = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative); | ||||
|         if ($this->convertToNative) { | ||||
|             $currentSet['native_entries']                 = []; | ||||
|             $currentSet['native_currency_id']             = (string)$this->nativeCurrency->id; | ||||
|             $currentSet['native_currency_code']           = $this->nativeCurrency->code; | ||||
|             $currentSet['native_currency_symbol']         = $this->nativeCurrency->symbol; | ||||
|             $currentSet['native_currency_decimal_places'] = $this->nativeCurrency->decimal_places; | ||||
|             $nativePrevious                               = array_values($range)[0]['native_balance']; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         $previous     = array_values($range)[0]['balance']; | ||||
|         while ($currentStart <= $params['end']) { | ||||
|             $format                        = $currentStart->format('Y-m-d'); | ||||
|             $label                         = $currentStart->toAtomString(); | ||||
|             $balance                       = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous; | ||||
|             $previous                      = $balance; | ||||
|             $currentSet['entries'][$label] = $balance; | ||||
| 
 | ||||
| 
 | ||||
|             // do the same for the native balance, if relevant:
 | ||||
|             $nativeBalance                 = null; | ||||
|             if ($this->convertToNative) { | ||||
|                 $nativeBalance                        = array_key_exists($format, $range) ? $range[$format]['native_balance'] : $nativePrevious; | ||||
|                 $nativePrevious                       = $nativeBalance; | ||||
|                 $currentSet['native_entries'][$label] = $nativeBalance; | ||||
|             } | ||||
| 
 | ||||
|             $currentStart->addDay(); | ||||
|             $currentSet['entries'][$label] = $balance; | ||||
|         } | ||||
|         $this->chartData->add($currentSet); | ||||
|     } | ||||
| @@ -139,45 +166,39 @@ class AccountController extends Controller | ||||
|      * This endpoint is documented at: | ||||
|      * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/charts/getChartAccountOverview
 | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      * @throws ValidationException | ||||
|      */ | ||||
|     public function overview(DateRequest $request): JsonResponse | ||||
|     { | ||||
|         // parameters for chart:
 | ||||
|         $dates      = $request->getAll(); | ||||
|         $dates        = $request->getAll(); | ||||
| 
 | ||||
| 
 | ||||
|         /** @var Carbon $start */ | ||||
|         $start      = $dates['start']; | ||||
|         $start        = $dates['start']; | ||||
| 
 | ||||
|         /** @var Carbon $end */ | ||||
|         $end        = $dates['end']; | ||||
|         $end          = $dates['end']; | ||||
| 
 | ||||
|         // set dates to end of day + start of day:
 | ||||
|         $start->startOfDay(); | ||||
|         $end->endOfDay(); | ||||
| 
 | ||||
|         // user's preferences
 | ||||
|         $defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray(); | ||||
| 
 | ||||
|         /** @var Preference $frontpage */ | ||||
|         $frontpage  = app('preferences')->get('frontpageAccounts', $defaultSet); | ||||
| 
 | ||||
|         if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) { | ||||
|             $frontpage->data = $defaultSet; | ||||
|             $frontpage->save(); | ||||
|         } | ||||
| 
 | ||||
|         // get accounts:
 | ||||
|         $accounts   = $this->repository->getAccountsById($frontpage->data); | ||||
|         $chartData  = []; | ||||
|         $frontPageIds = $this->getFrontPageAccountIds(); | ||||
|         $accounts     = $this->repository->getAccountsById($frontPageIds); | ||||
|         $chartData    = []; | ||||
| 
 | ||||
|         /** @var Account $account */ | ||||
|         foreach ($accounts as $account) { | ||||
|             $currency     = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency; | ||||
|             $field        = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance'; | ||||
|             $currentSet   = [ | ||||
|             Log::debug(sprintf('Rendering chart data for account %s (%d)', $account->name, $account->id)); | ||||
|             $currency       = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency; | ||||
|             $currentStart   = clone $start; | ||||
|             $range          = Steam::finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative); | ||||
|             $previous       = array_values($range)[0]['balance']; | ||||
|             $nativePrevious = null; | ||||
|             $currentSet     = [ | ||||
|                 'label'                   => $account->name, | ||||
|                 'currency_id'             => (string) $currency->id, | ||||
|                 'currency_id'             => (string)$currency->id, | ||||
|                 'currency_code'           => $currency->code, | ||||
|                 'currency_symbol'         => $currency->symbol, | ||||
|                 'currency_decimal_places' => $currency->decimal_places, | ||||
| @@ -187,21 +208,57 @@ class AccountController extends Controller | ||||
|                 'yAxisID'                 => 0, // 0, 1, 2
 | ||||
|                 'entries'                 => [], | ||||
|             ]; | ||||
|             // TODO this code is also present in the V2 chart account controller so this method is due to be deprecated.
 | ||||
|             $currentStart = clone $start; | ||||
|             $range        = Steam::finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative); | ||||
|             $previous     = array_values($range)[0][$field]; | ||||
| 
 | ||||
|             // add "native_entries" if convertToNative is true:
 | ||||
|             if ($this->convertToNative) { | ||||
|                 $currentSet['native_entries']                 = []; | ||||
|                 $currentSet['native_currency_id']             = (string)$this->nativeCurrency->id; | ||||
|                 $currentSet['native_currency_code']           = $this->nativeCurrency->code; | ||||
|                 $currentSet['native_currency_symbol']         = $this->nativeCurrency->symbol; | ||||
|                 $currentSet['native_currency_decimal_places'] = $this->nativeCurrency->decimal_places; | ||||
|                 $nativePrevious                               = array_values($range)[0]['native_balance']; | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             // also get the native balance if convertToNative is true:
 | ||||
|             while ($currentStart <= $end) { | ||||
|                 $format                        = $currentStart->format('Y-m-d'); | ||||
|                 $label                         = $currentStart->toAtomString(); | ||||
|                 $balance                       = array_key_exists($format, $range) ? $range[$format][$field] : $previous; | ||||
| 
 | ||||
|                 // balance is based on "balance" from the $range variable.
 | ||||
|                 $balance                       = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous; | ||||
|                 $previous                      = $balance; | ||||
|                 $currentStart->addDay(); | ||||
|                 $currentSet['entries'][$label] = $balance; | ||||
| 
 | ||||
|                 // do the same for the native balance, if relevant:
 | ||||
|                 $nativeBalance                 = null; | ||||
|                 if ($this->convertToNative) { | ||||
|                     $nativeBalance                        = array_key_exists($format, $range) ? $range[$format]['native_balance'] : $nativePrevious; | ||||
|                     $nativePrevious                       = $nativeBalance; | ||||
|                     $currentSet['native_entries'][$label] = $nativeBalance; | ||||
|                 } | ||||
| 
 | ||||
|                 $currentStart->addDay(); | ||||
| 
 | ||||
|             } | ||||
|             $chartData[]  = $currentSet; | ||||
|             $chartData[]    = $currentSet; | ||||
|         } | ||||
| 
 | ||||
|         return response()->json($chartData); | ||||
|     } | ||||
| 
 | ||||
|     private function getFrontPageAccountIds(): array | ||||
|     { | ||||
|         $defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray(); | ||||
| 
 | ||||
|         /** @var Preference $frontpage */ | ||||
|         $frontpage  = Preferences::get('frontpageAccounts', $defaultSet); | ||||
| 
 | ||||
|         if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) { | ||||
|             $frontpage->data = $defaultSet; | ||||
|             $frontpage->save(); | ||||
|         } | ||||
| 
 | ||||
|         return $frontpage->data ?? $defaultSet; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -123,7 +123,7 @@ class BudgetController extends Controller | ||||
|         foreach ($rows as $row) { | ||||
|             $current  = [ | ||||
|                 'label'                   => $budget->name, | ||||
|                 'currency_id'             => (string) $row['currency_id'], | ||||
|                 'currency_id'             => (string)$row['currency_id'], | ||||
|                 'currency_code'           => $row['currency_code'], | ||||
|                 'currency_name'           => $row['currency_name'], | ||||
|                 'currency_decimal_places' => $row['currency_decimal_places'], | ||||
| @@ -131,6 +131,7 @@ class BudgetController extends Controller | ||||
|                 'start'                   => $row['start'], | ||||
|                 'end'                     => $row['end'], | ||||
|                 'entries'                 => [ | ||||
|                     'budgeted'  => $row['budgeted'], | ||||
|                     'spent'     => $row['spent'], | ||||
|                     'left'      => $row['left'], | ||||
|                     'overspent' => $row['overspent'], | ||||
| @@ -159,11 +160,9 @@ class BudgetController extends Controller | ||||
|      * Shared between the "noBudgetLimits" function and "processLimit". Will take a single set of expenses and return | ||||
|      * its info. | ||||
|      * | ||||
|      * @param array<int, array<int, string>> $array | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     private function processExpenses(int $budgetId, array $array, Carbon $start, Carbon $end): array | ||||
|     private function processExpenses(int $budgetId, array $spent, Carbon $start, Carbon $end): array | ||||
|     { | ||||
|         $return = []; | ||||
| 
 | ||||
| @@ -174,16 +173,17 @@ class BudgetController extends Controller | ||||
|          * @var int   $currencyId | ||||
|          * @var array $block | ||||
|          */ | ||||
|         foreach ($array as $currencyId => $block) { | ||||
|         foreach ($spent as $currencyId => $block) { | ||||
|             $this->currencies[$currencyId] ??= TransactionCurrency::find($currencyId); | ||||
|             $return[$currencyId]           ??= [ | ||||
|                 'currency_id'             => (string) $currencyId, | ||||
|                 'currency_id'             => (string)$currencyId, | ||||
|                 'currency_code'           => $block['currency_code'], | ||||
|                 'currency_name'           => $block['currency_name'], | ||||
|                 'currency_symbol'         => $block['currency_symbol'], | ||||
|                 'currency_decimal_places' => (int) $block['currency_decimal_places'], | ||||
|                 'currency_decimal_places' => (int)$block['currency_decimal_places'], | ||||
|                 'start'                   => $start->toAtomString(), | ||||
|                 'end'                     => $end->toAtomString(), | ||||
|                 'budgeted'                => '0', | ||||
|                 'spent'                   => '0', | ||||
|                 'left'                    => '0', | ||||
|                 'overspent'               => '0', | ||||
| @@ -193,7 +193,7 @@ class BudgetController extends Controller | ||||
|             // var_dump($return);
 | ||||
|             /** @var array $journal */ | ||||
|             foreach ($currentBudgetArray['transaction_journals'] as $journal) { | ||||
|                 $return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], (string) $journal['amount']); | ||||
|                 $return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], (string)$journal['amount']); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @@ -212,7 +212,7 @@ class BudgetController extends Controller | ||||
|      */ | ||||
|     private function budgetLimits(Budget $budget, Collection $limits): array | ||||
|     { | ||||
|         app('log')->debug(sprintf('Now in budgetLimits(#%d)', $budget->id)); | ||||
|         Log::debug(sprintf('Now in budgetLimits(#%d)', $budget->id)); | ||||
|         $data = []; | ||||
| 
 | ||||
|         /** @var BudgetLimit $limit */ | ||||
| @@ -233,25 +233,21 @@ class BudgetController extends Controller | ||||
|         $end->endOfDay(); | ||||
|         $spent           = $this->opsRepository->listExpenses($limit->start_date, $end, null, new Collection([$budget])); | ||||
|         $limitCurrencyId = $limit->transaction_currency_id; | ||||
|         $filtered        = []; | ||||
| 
 | ||||
|         /** @var array $entry */ | ||||
|         foreach ($spent as $currencyId => $entry) { | ||||
|             // only spent the entry where the entry's currency matches the budget limit's currency
 | ||||
|             // so $filtered will only have 1 or 0 entries
 | ||||
|             if ($entry['currency_id'] === $limitCurrencyId) { | ||||
|                 $filtered[$currencyId] = $entry; | ||||
|             } | ||||
|         } | ||||
|         // only spent the entry where the entry's currency matches the budget limit's currency
 | ||||
|         // so $filtered will only have 1 or 0 entries
 | ||||
|         $filtered        = array_filter($spent, fn ($entry) => $entry['currency_id'] === $limitCurrencyId); | ||||
|         $result          = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end); | ||||
|         if (1 === count($result)) { | ||||
|             $compare = bccomp($limit->amount, (string) app('steam')->positive($result[$limitCurrencyId]['spent'])); | ||||
|             $compare                              = bccomp($limit->amount, (string)app('steam')->positive($result[$limitCurrencyId]['spent'])); | ||||
|             $result[$limitCurrencyId]['budgeted'] = $limit->amount; | ||||
|             if (1 === $compare) { | ||||
|                 // convert this amount into the native currency:
 | ||||
|                 $result[$limitCurrencyId]['left'] = bcadd($limit->amount, (string) $result[$limitCurrencyId]['spent']); | ||||
|                 $result[$limitCurrencyId]['left'] = bcadd($limit->amount, (string)$result[$limitCurrencyId]['spent']); | ||||
|             } | ||||
|             if ($compare <= 0) { | ||||
|                 $result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, (string) $result[$limitCurrencyId]['spent'])); | ||||
|                 $result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, (string)$result[$limitCurrencyId]['spent'])); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|   | ||||
| @@ -127,7 +127,6 @@ abstract class Controller extends BaseController | ||||
|                 Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field)); | ||||
|                 Log::error($e->getMessage()); | ||||
|                 Log::error($e->getTraceAsString()); | ||||
|                 $value = null; | ||||
|             } | ||||
|             $obj  = null; | ||||
|             if (null !== $date) { | ||||
|   | ||||
| @@ -64,7 +64,7 @@ class DestroyController extends Controller | ||||
|     public function destroy(DestroyRequest $request): JsonResponse | ||||
|     { | ||||
|         $objects         = $request->getObjects(); | ||||
|         $this->unused    = $request->boolean('unused', false); | ||||
|         $this->unused    = $request->boolean('unused'); | ||||
| 
 | ||||
|         $allExceptAssets = [AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::CASH->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::RECONCILIATION->value, AccountTypeEnum::REVENUE->value]; | ||||
|         $all             = [AccountTypeEnum::ASSET->value, AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::CASH->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::RECONCILIATION->value]; | ||||
| @@ -176,14 +176,14 @@ class DestroyController extends Controller | ||||
|         foreach ($collection as $account) { | ||||
|             $count = $account->transactions()->count(); | ||||
|             if (true === $this->unused && 0 === $count) { | ||||
|                 app('log')->info(sprintf('Deleted unused account #%d "%s"', $account->id, $account->name)); | ||||
|                 Log::info(sprintf('Deleted unused account #%d "%s"', $account->id, $account->name)); | ||||
|                 Log::channel('audit')->info(sprintf('Deleted unused account #%d "%s"', $account->id, $account->name)); | ||||
|                 $service->destroy($account, null); | ||||
| 
 | ||||
|                 continue; | ||||
|             } | ||||
|             if (false === $this->unused) { | ||||
|                 app('log')->info(sprintf('Deleting account #%d "%s"', $account->id, $account->name)); | ||||
|                 Log::info(sprintf('Deleting account #%d "%s"', $account->id, $account->name)); | ||||
|                 Log::channel('audit')->warning(sprintf('Deleted account #%d "%s"', $account->id, $account->name)); | ||||
|                 $service->destroy($account, null); | ||||
|             } | ||||
|   | ||||
| @@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Data\Export\ExportRequest; | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| use FireflyIII\Support\Export\ExportDataGenerator; | ||||
| use Illuminate\Http\Response as LaravelResponse; | ||||
| use Safe\Exceptions\DatetimeException; | ||||
| 
 | ||||
| use function Safe\date; | ||||
| 
 | ||||
| @@ -72,6 +73,7 @@ class ExportController extends Controller | ||||
| 
 | ||||
|     /** | ||||
|      * @throws FireflyException | ||||
|      * @throws DatetimeException | ||||
|      */ | ||||
|     private function returnExport(string $key): LaravelResponse | ||||
|     { | ||||
|   | ||||
| @@ -32,6 +32,7 @@ use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment; | ||||
| use FireflyIII\Transformers\AccountTransformer; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| use League\Fractal\Resource\Item; | ||||
| 
 | ||||
| /** | ||||
| @@ -67,7 +68,7 @@ class UpdateController extends Controller | ||||
|      */ | ||||
|     public function update(UpdateRequest $request, Account $account): JsonResponse | ||||
|     { | ||||
|         app('log')->debug(sprintf('Now in %s', __METHOD__)); | ||||
|         Log::debug(sprintf('Now in %s', __METHOD__)); | ||||
|         $data         = $request->getUpdateData(); | ||||
|         $data['type'] = config('firefly.shortNamesByFullName.'.$account->accountType->type); | ||||
|         $account      = $this->repository->update($account, $data); | ||||
|   | ||||
| @@ -80,7 +80,7 @@ class StoreController extends Controller | ||||
| 
 | ||||
|             throw new NotFoundHttpException(); | ||||
|         } | ||||
|         app('log')->debug(sprintf('Now in %s', __METHOD__)); | ||||
|         Log::debug(sprintf('Now in %s', __METHOD__)); | ||||
|         $data        = $request->getAll(); | ||||
|         $attachment  = $this->repository->store($data); | ||||
|         $manager     = $this->getManager(); | ||||
| @@ -109,13 +109,13 @@ class StoreController extends Controller | ||||
|         $helper = app(AttachmentHelperInterface::class); | ||||
|         $body   = $request->getContent(); | ||||
|         if ('' === $body) { | ||||
|             app('log')->error('Body of attachment is empty.'); | ||||
|             Log::error('Body of attachment is empty.'); | ||||
| 
 | ||||
|             return response()->json([], 422); | ||||
|         } | ||||
|         $result = $helper->saveAttachmentFromApi($attachment, $body); | ||||
|         if (false === $result) { | ||||
|             app('log')->error('Could not save attachment from API.'); | ||||
|             Log::error('Could not save attachment from API.'); | ||||
| 
 | ||||
|             return response()->json([], 422); | ||||
|         } | ||||
|   | ||||
| @@ -69,7 +69,6 @@ class StoreController extends Controller | ||||
|         $data               = $request->getAll(); | ||||
|         $data['start_date'] = $data['start']; | ||||
|         $data['end_date']   = $data['end']; | ||||
|         $data['notes']      = $data['notes']; | ||||
|         $data['budget_id']  = $budget->id; | ||||
| 
 | ||||
|         $budgetLimit        = $this->blRepository->store($data); | ||||
|   | ||||
| @@ -34,6 +34,7 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface; | ||||
| use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepository; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| 
 | ||||
| /** | ||||
|  * Class DestroyController | ||||
| @@ -73,7 +74,7 @@ class DestroyController extends Controller | ||||
|      */ | ||||
|     public function destroy(TransactionGroup $transactionGroup): JsonResponse | ||||
|     { | ||||
|         app('log')->debug(sprintf('Now in %s', __METHOD__)); | ||||
|         Log::debug(sprintf('Now in %s', __METHOD__)); | ||||
|         // grab asset account(s) from group:
 | ||||
|         $accounts = []; | ||||
| 
 | ||||
| @@ -95,7 +96,7 @@ class DestroyController extends Controller | ||||
| 
 | ||||
|         /** @var Account $account */ | ||||
|         foreach ($accounts as $account) { | ||||
|             app('log')->debug(sprintf('Now going to trigger updated account event for account #%d', $account->id)); | ||||
|             Log::debug(sprintf('Now going to trigger updated account event for account #%d', $account->id)); | ||||
|             event(new UpdatedAccount($account)); | ||||
|         } | ||||
| 
 | ||||
|   | ||||
| @@ -147,6 +147,7 @@ class ShowController extends Controller | ||||
|         $enrichment->setUser($admin); | ||||
|         $selectedGroup = $enrichment->enrichSingle($selectedGroup); | ||||
| 
 | ||||
| 
 | ||||
|         /** @var TransactionGroupTransformer $transformer */ | ||||
|         $transformer   = app(TransactionGroupTransformer::class); | ||||
|         $transformer->setParameters($this->parameters); | ||||
|   | ||||
| @@ -84,7 +84,7 @@ class StoreController extends Controller | ||||
|      */ | ||||
|     public function store(StoreRequest $request): JsonResponse | ||||
|     { | ||||
|         app('log')->debug('Now in API StoreController::store()'); | ||||
|         Log::debug('Now in API StoreController::store()'); | ||||
|         $data               = $request->getAll(); | ||||
|         $data['user']       = auth()->user(); | ||||
|         $data['user_group'] = $this->userGroup; | ||||
| @@ -95,13 +95,13 @@ class StoreController extends Controller | ||||
|         try { | ||||
|             $transactionGroup = $this->groupRepository->store($data); | ||||
|         } catch (DuplicateTransactionException $e) { | ||||
|             app('log')->warning('Caught a duplicate transaction. Return error message.'); | ||||
|             Log::warning('Caught a duplicate transaction. Return error message.'); | ||||
|             $validator = Validator::make(['transactions' => [['description' => $e->getMessage()]]], ['transactions.0.description' => new IsDuplicateTransaction()]); | ||||
| 
 | ||||
|             throw new ValidationException($validator); | ||||
|         } catch (FireflyException $e) { | ||||
|             app('log')->warning('Caught an exception. Return error message.'); | ||||
|             app('log')->error($e->getMessage()); | ||||
|             Log::warning('Caught an exception. Return error message.'); | ||||
|             Log::error($e->getMessage()); | ||||
|             $message   = sprintf('Internal exception: %s', $e->getMessage()); | ||||
|             $validator = Validator::make(['transactions' => [['description' => $message]]], ['transactions.0.description' => new IsDuplicateTransaction()]); | ||||
| 
 | ||||
|   | ||||
| @@ -34,6 +34,7 @@ use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment; | ||||
| use FireflyIII\Transformers\TransactionGroupTransformer; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| use League\Fractal\Resource\Item; | ||||
| use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; | ||||
| 
 | ||||
| @@ -71,7 +72,7 @@ class UpdateController extends Controller | ||||
|      */ | ||||
|     public function update(UpdateRequest $request, TransactionGroup $transactionGroup): JsonResponse | ||||
|     { | ||||
|         app('log')->debug('Now in update routine for transaction group'); | ||||
|         Log::debug('Now in update routine for transaction group'); | ||||
|         $data              = $request->getAll(); | ||||
|         $oldHash           = $this->groupRepository->getCompareHash($transactionGroup); | ||||
|         $transactionGroup  = $this->groupRepository->update($transactionGroup, $data); | ||||
|   | ||||
| @@ -32,6 +32,7 @@ use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; | ||||
| use FireflyIII\Repositories\User\UserRepositoryInterface; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Validation\ValidationException; | ||||
| 
 | ||||
| /** | ||||
|  * Class DestroyController | ||||
| @@ -65,6 +66,7 @@ class DestroyController extends Controller | ||||
|      * Remove the specified resource from storage. | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      * @throws ValidationException | ||||
|      */ | ||||
|     public function destroy(TransactionCurrency $currency): JsonResponse | ||||
|     { | ||||
|   | ||||
| @@ -250,10 +250,8 @@ class ListController extends Controller | ||||
|         $collection     = $unfiltered->filter( | ||||
|             static function (Recurrence $recurrence) use ($currency) {  // @phpstan-ignore-line
 | ||||
|                 /** @var RecurrenceTransaction $transaction */ | ||||
|                 foreach ($recurrence->recurrenceTransactions as $transaction) { | ||||
|                     if ($transaction->transaction_currency_id === $currency->id || $transaction->foreign_currency_id === $currency->id) { | ||||
|                         return $recurrence; | ||||
|                     } | ||||
|                 if (array_any($recurrence->recurrenceTransactions, fn ($transaction) => $transaction->transaction_currency_id === $currency->id || $transaction->foreign_currency_id === $currency->id)) { | ||||
|                     return $recurrence; | ||||
|                 } | ||||
| 
 | ||||
|                 return null; | ||||
| @@ -297,10 +295,8 @@ class ListController extends Controller | ||||
|         $collection  = $unfiltered->filter( | ||||
|             static function (Rule $rule) use ($currency) { // @phpstan-ignore-line
 | ||||
|                 /** @var RuleTrigger $trigger */ | ||||
|                 foreach ($rule->ruleTriggers as $trigger) { | ||||
|                     if ('currency_is' === $trigger->trigger_type && $currency->name === $trigger->trigger_value) { | ||||
|                         return $rule; | ||||
|                     } | ||||
|                 if (array_any($rule->ruleTriggers, fn ($trigger) => 'currency_is' === $trigger->trigger_type && $currency->name === $trigger->trigger_value)) { | ||||
|                     return $rule; | ||||
|                 } | ||||
| 
 | ||||
|                 return null; | ||||
|   | ||||
| @@ -27,13 +27,13 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionLinkType; | ||||
| use Illuminate\Support\Facades\Validator; | ||||
| use FireflyIII\Api\V1\Controllers\Controller; | ||||
| use FireflyIII\Api\V1\Requests\Models\TransactionLinkType\StoreRequest; | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface; | ||||
| use FireflyIII\Repositories\User\UserRepositoryInterface; | ||||
| use FireflyIII\Support\Http\Api\TransactionFilter; | ||||
| use FireflyIII\Transformers\LinkTypeTransformer; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Validation\ValidationException; | ||||
| use League\Fractal\Resource\Item; | ||||
| 
 | ||||
| /** | ||||
| @@ -71,7 +71,7 @@ class StoreController extends Controller | ||||
|      * | ||||
|      * Store new object. | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      * @throws ValidationException | ||||
|      */ | ||||
|     public function store(StoreRequest $request): JsonResponse | ||||
|     { | ||||
|   | ||||
| @@ -35,6 +35,7 @@ use FireflyIII\Support\Http\Api\TransactionFilter; | ||||
| use FireflyIII\Transformers\LinkTypeTransformer; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Validation\ValidationException; | ||||
| use League\Fractal\Resource\Item; | ||||
| 
 | ||||
| /** | ||||
| @@ -73,6 +74,7 @@ class UpdateController extends Controller | ||||
|      * Update object. | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      * @throws ValidationException | ||||
|      */ | ||||
|     public function update(UpdateRequest $request, LinkType $linkType): JsonResponse | ||||
|     { | ||||
|   | ||||
| @@ -30,6 +30,7 @@ use FireflyIII\Models\UserGroup; | ||||
| use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface; | ||||
| use FireflyIII\Transformers\UserGroupTransformer; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| 
 | ||||
| class UpdateController extends Controller | ||||
| { | ||||
| @@ -54,7 +55,7 @@ class UpdateController extends Controller | ||||
| 
 | ||||
|     public function update(UpdateRequest $request, UserGroup $userGroup): JsonResponse | ||||
|     { | ||||
|         app('log')->debug(sprintf('Now in %s', __METHOD__)); | ||||
|         Log::debug(sprintf('Now in %s', __METHOD__)); | ||||
|         $data        = $request->getData(); | ||||
|         $userGroup   = $this->repository->update($userGroup, $data); | ||||
|         $userGroup->refresh(); | ||||
|   | ||||
| @@ -34,6 +34,7 @@ use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Http\Request; | ||||
| use Illuminate\Http\Response; | ||||
| use Illuminate\Pagination\LengthAwarePaginator; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| use League\Fractal\Pagination\IlluminatePaginatorAdapter; | ||||
| use League\Fractal\Resource\Collection as FractalCollection; | ||||
| 
 | ||||
| @@ -71,7 +72,7 @@ class AccountController extends Controller | ||||
|         if ('' === $query || !in_array($field, $this->validFields, true)) { | ||||
|             return response(null, 422); | ||||
|         } | ||||
|         app('log')->debug(sprintf('Now in account search("%s", "%s")', $field, $query)); | ||||
|         Log::debug(sprintf('Now in account search("%s", "%s")', $field, $query)); | ||||
|         $types       = $this->mapAccountTypes($type); | ||||
| 
 | ||||
|         /** @var AccountSearch $search */ | ||||
|   | ||||
| @@ -130,8 +130,6 @@ class BasicController extends Controller | ||||
|         $convertToNative = Amount::convertToNative(); | ||||
|         $default         = Amount::getNativeCurrency(); | ||||
|         // prep some arrays:
 | ||||
|         $incomes         = []; | ||||
|         $expenses        = []; | ||||
|         $sums            = []; | ||||
|         $return          = []; | ||||
|         $currencies      = [ | ||||
|   | ||||
| @@ -24,6 +24,8 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Api\V1\Controllers\System; | ||||
| 
 | ||||
| use FireflyIII\Support\Facades\FireflyConfig; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| use Illuminate\Support\Facades\Validator; | ||||
| use FireflyIII\Api\V1\Controllers\Controller; | ||||
| use FireflyIII\Api\V1\Requests\System\UpdateRequest; | ||||
| @@ -31,6 +33,7 @@ use FireflyIII\Exceptions\FireflyException; | ||||
| use FireflyIII\Repositories\User\UserRepositoryInterface; | ||||
| use FireflyIII\Support\Binder\EitherConfigKey; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Validation\ValidationException; | ||||
| 
 | ||||
| /** | ||||
|  * Class ConfigurationController | ||||
| @@ -65,8 +68,8 @@ class ConfigurationController extends Controller | ||||
|         try { | ||||
|             $dynamicData = $this->getDynamicConfiguration(); | ||||
|         } catch (FireflyException $e) { | ||||
|             app('log')->error($e->getMessage()); | ||||
|             app('log')->error($e->getTraceAsString()); | ||||
|             Log::error($e->getMessage()); | ||||
|             Log::error($e->getTraceAsString()); | ||||
| 
 | ||||
|             throw new FireflyException('200030: Could not load config variables.', 0, $e); | ||||
|         } | ||||
| @@ -92,13 +95,15 @@ class ConfigurationController extends Controller | ||||
| 
 | ||||
|     /** | ||||
|      * Get all config values. | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     private function getDynamicConfiguration(): array | ||||
|     { | ||||
|         $isDemoSite  = app('fireflyconfig')->get('is_demo_site'); | ||||
|         $updateCheck = app('fireflyconfig')->get('permission_update_check'); | ||||
|         $lastCheck   = app('fireflyconfig')->get('last_update_check'); | ||||
|         $singleUser  = app('fireflyconfig')->get('single_user_mode'); | ||||
|         $isDemoSite  = FireflyConfig::get('is_demo_site'); | ||||
|         $updateCheck = FireflyConfig::get('permission_update_check'); | ||||
|         $lastCheck   = FireflyConfig::get('last_update_check'); | ||||
|         $singleUser  = FireflyConfig::get('single_user_mode'); | ||||
| 
 | ||||
|         return [ | ||||
|             'is_demo_site'            => $isDemoSite?->data, | ||||
| @@ -153,6 +158,7 @@ class ConfigurationController extends Controller | ||||
|      * Update the configuration. | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      * @throws ValidationException | ||||
|      */ | ||||
|     public function update(UpdateRequest $request, string $name): JsonResponse | ||||
|     { | ||||
| @@ -164,7 +170,7 @@ class ConfigurationController extends Controller | ||||
|         $data      = $request->getAll(); | ||||
|         $shortName = str_replace('configuration.', '', $name); | ||||
| 
 | ||||
|         app('fireflyconfig')->set($shortName, $data['value']); | ||||
|         FireflyConfig::set($shortName, $data['value']); | ||||
| 
 | ||||
|         // get updated config:
 | ||||
|         $newConfig = $this->getDynamicConfiguration(); | ||||
|   | ||||
| @@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller; | ||||
| use FireflyIII\Api\V1\Requests\System\CronRequest; | ||||
| use FireflyIII\Support\Http\Controllers\CronRunner; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| 
 | ||||
| /** | ||||
|  * Class CronController | ||||
| @@ -44,8 +45,8 @@ class CronController extends Controller | ||||
|     { | ||||
|         $config                           = $request->getAll(); | ||||
| 
 | ||||
|         app('log')->debug(sprintf('Now in %s', __METHOD__)); | ||||
|         app('log')->debug(sprintf('Date is %s', $config['date']->toIsoString())); | ||||
|         Log::debug(sprintf('Now in %s', __METHOD__)); | ||||
|         Log::debug(sprintf('Date is %s', $config['date']->toIsoString())); | ||||
|         $return                           = []; | ||||
|         $return['recurring_transactions'] = $this->runRecurring($config['force'], $config['date']); | ||||
|         $return['auto_budgets']           = $this->runAutoBudget($config['force'], $config['date']); | ||||
|   | ||||
| @@ -33,6 +33,7 @@ use FireflyIII\Transformers\UserTransformer; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Pagination\LengthAwarePaginator; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| use League\Fractal\Pagination\IlluminatePaginatorAdapter; | ||||
| use League\Fractal\Resource\Collection as FractalCollection; | ||||
| use League\Fractal\Resource\Item; | ||||
| @@ -174,7 +175,7 @@ class UserController extends Controller | ||||
| 
 | ||||
|         // can only update 'blocked' when user is admin.
 | ||||
|         if (!$this->repository->hasRole(auth()->user(), 'owner')) { | ||||
|             app('log')->debug('Quietly drop fields "blocked" and "blocked_code" from request.'); | ||||
|             Log::debug('Quietly drop fields "blocked" and "blocked_code" from request.'); | ||||
|             unset($data['blocked'], $data['blocked_code']); | ||||
|         } | ||||
| 
 | ||||
|   | ||||
| @@ -138,7 +138,7 @@ class ShowController extends Controller | ||||
|             throw new NotFoundHttpException('Webhooks are not enabled.'); | ||||
|         } | ||||
| 
 | ||||
|         app('log')->debug(sprintf('Now in triggerTransaction(%d, %d)', $webhook->id, $group->id)); | ||||
|         Log::debug(sprintf('Now in triggerTransaction(%d, %d)', $webhook->id, $group->id)); | ||||
|         Log::channel('audit')->info(sprintf('User triggers webhook #%d on transaction group #%d.', $webhook->id, $group->id)); | ||||
| 
 | ||||
|         /** @var MessageGeneratorInterface $engine */ | ||||
| @@ -155,7 +155,7 @@ class ShowController extends Controller | ||||
|         $engine->generateMessages(); | ||||
| 
 | ||||
|         // trigger event to send them:
 | ||||
|         app('log')->debug('send event RequestedSendWebhookMessages'); | ||||
|         Log::debug('send event RequestedSendWebhookMessages'); | ||||
|         event(new RequestedSendWebhookMessages()); | ||||
| 
 | ||||
|         return response()->json([], 204); | ||||
|   | ||||
| @@ -76,6 +76,6 @@ class SubmitController extends Controller | ||||
|             SendWebhookMessage::dispatch($message)->afterResponse(); | ||||
|         } | ||||
| 
 | ||||
|         return response()->json([]); | ||||
|         return response()->json(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -58,7 +58,7 @@ class AutocompleteRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'date' => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'date' => 'date|after:1970-01-02|before:2038-01-17', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -60,8 +60,8 @@ class ChartRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start'       => 'required|date|after:1900-01-01|before:2099-12-31|before_or_equal:end', | ||||
|             'end'         => 'required|date|after:1900-01-01|before:2099-12-31|after_or_equal:start', | ||||
|             'start'       => 'required|date|after:1970-01-02|before:2038-01-17|before_or_equal:end', | ||||
|             'end'         => 'required|date|after:1970-01-02|before:2038-01-17|after_or_equal:start', | ||||
|             'preselected' => sprintf('nullable|in:%s', implode(',', config('firefly.preselected_accounts'))), | ||||
|             'period'      => sprintf('nullable|in:%s', implode(',', config('firefly.valid_view_ranges'))), | ||||
|             'accounts.*'  => 'exists:accounts,id', | ||||
|   | ||||
| @@ -54,8 +54,8 @@ class TransactionRequest extends FormRequest | ||||
|                 'query' => json_decode($this->get('query'), true, 8, JSON_THROW_ON_ERROR), | ||||
|             ]; | ||||
|         } catch (JsonException $e) { | ||||
|             // dont really care. the validation should catch invalid json.
 | ||||
|             app('log')->error($e->getMessage()); | ||||
|             // don't really care. the validation should catch invalid json.
 | ||||
|             Log::error($e->getMessage()); | ||||
|         } | ||||
| 
 | ||||
|         return $data; | ||||
|   | ||||
| @@ -65,9 +65,9 @@ class DateRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'date'  => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'start' => 'date|after:1900-01-01|before:2099-12-31|before:end|required_with:end', | ||||
|             'end'   => 'date|after:1900-01-01|before:2099-12-31|after:start|required_with:start', | ||||
|             'date'  => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'start' => 'date|after:1970-01-02|before:2038-01-17|before:end|required_with:end', | ||||
|             'end'   => 'date|after:1970-01-02|before:2038-01-17|after:start|required_with:start', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -55,8 +55,8 @@ class DateRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start' => 'required|date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'   => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01', | ||||
|             'start' => 'required|date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'   => 'required|date|after_or_equal:start|before:2038-01-17|after:1970-01-02', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -53,7 +53,7 @@ class SingleDateRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'date' => 'required|date|after:1900-01-01|before:2099-12-31', | ||||
|             'date' => 'required|date|after:1970-01-02|before:2038-01-17', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -66,8 +66,8 @@ class Request extends FormRequest | ||||
|             'currency_id'   => 'numeric|exists:transaction_currencies,id', | ||||
|             'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', | ||||
|             'amount'        => ['nullable', new IsValidPositiveAmount()], | ||||
|             'start'         => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'           => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'start'         => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'           => 'date|after:1970-01-02|before:2038-01-17', | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|   | ||||
| @@ -47,7 +47,7 @@ class StoreRequest extends FormRequest | ||||
|      */ | ||||
|     public function getAll(): array | ||||
|     { | ||||
|         app('log')->debug('Raw fields in Bill StoreRequest', $this->all()); | ||||
|         Log::debug('Raw fields in Bill StoreRequest', $this->all()); | ||||
|         $fields = [ | ||||
|             'name'               => ['name', 'convertString'], | ||||
|             'amount_min'         => ['amount_min', 'convertString'], | ||||
| @@ -80,9 +80,9 @@ class StoreRequest extends FormRequest | ||||
|             'amount_max'     => ['required', new IsValidPositiveAmount()], | ||||
|             'currency_id'    => 'numeric|exists:transaction_currencies,id', | ||||
|             'currency_code'  => 'min:3|max:51|exists:transaction_currencies,code', | ||||
|             'date'           => 'date|required|after:1900-01-01|before:2099-12-31', | ||||
|             'end_date'       => 'nullable|date|after:date|after:1900-01-01|before:2099-12-31', | ||||
|             'extension_date' => 'nullable|date|after:date|after:1900-01-01|before:2099-12-31', | ||||
|             'date'           => 'date|required|after:1970-01-02|before:2038-01-17', | ||||
|             'end_date'       => 'nullable|date|after:date|after:1970-01-02|before:2038-01-17', | ||||
|             'extension_date' => 'nullable|date|after:date|after:1970-01-02|before:2038-01-17', | ||||
|             'repeat_freq'    => 'in:weekly,monthly,quarterly,half-year,yearly|required', | ||||
|             'skip'           => 'min:0|max:31|numeric', | ||||
|             'active'         => [new IsBoolean()], | ||||
| @@ -128,7 +128,6 @@ class StoreRequest extends FormRequest | ||||
|             $failed = $validator->fails(); | ||||
|         } catch (TypeError $e) { | ||||
|             Log::error($e->getMessage()); | ||||
|             $failed = false; | ||||
|         } | ||||
|         if ($failed) { | ||||
|             Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray()); | ||||
|   | ||||
| @@ -81,9 +81,9 @@ class UpdateRequest extends FormRequest | ||||
|             'amount_max'     => ['nullable', new IsValidPositiveAmount()], | ||||
|             'currency_id'    => 'numeric|exists:transaction_currencies,id', | ||||
|             'currency_code'  => 'min:3|max:51|exists:transaction_currencies,code', | ||||
|             'date'           => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'end_date'       => 'date|after:date|after:1900-01-01|before:2099-12-31', | ||||
|             'extension_date' => 'date|after:date|after:1900-01-01|before:2099-12-31', | ||||
|             'date'           => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'end_date'       => 'date|after:date|after:1970-01-02|before:2038-01-17', | ||||
|             'extension_date' => 'date|after:date|after:1970-01-02|before:2038-01-17', | ||||
|             'repeat_freq'    => 'in:weekly,monthly,quarterly,half-year,yearly', | ||||
|             'skip'           => 'min:0|max:31|numeric', | ||||
|             'active'         => [new IsBoolean()], | ||||
|   | ||||
| @@ -67,8 +67,8 @@ class UpdateRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start'         => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'           => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'start'         => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'           => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'amount'        => ['nullable', new IsValidPositiveAmount()], | ||||
|             'currency_id'   => 'numeric|exists:transaction_currencies,id', | ||||
|             'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', | ||||
|   | ||||
| @@ -45,7 +45,7 @@ class DestroyRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'date' => 'required|date|after:1900-01-01|before:2099-12-31', | ||||
|             'date' => 'required|date|after:1970-01-02|before:2038-01-17', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -61,7 +61,7 @@ class StoreRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'date' => 'required|date|after:1900-01-01|before:2099-12-31', | ||||
|             'date' => 'required|date|after:1970-01-02|before:2038-01-17', | ||||
|             'rate' => 'required|numeric|gt:0', | ||||
|             'from' => 'required|exists:transaction_currencies,code', | ||||
|             'to'   => 'required|exists:transaction_currencies,code', | ||||
|   | ||||
| @@ -50,7 +50,7 @@ class UpdateRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'date' => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'date' => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'rate' => 'required|numeric|gt:0', | ||||
|         ]; | ||||
|     } | ||||
|   | ||||
| @@ -76,7 +76,7 @@ class StoreRequest extends FormRequest | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the transaction data as it is found in the submitted data. It's a complex method according to code | ||||
|      * standards but it just has a lot of ??-statements because of the fields that may or may not exist. | ||||
|      * standards, but it just has a lot of ??-statements because of the fields that may or may not exist. | ||||
|      */ | ||||
|     private function getTransactionData(): array | ||||
|     { | ||||
|   | ||||
| @@ -122,7 +122,7 @@ class UpdateRequest extends FormRequest | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the transaction data as it is found in the submitted data. It's a complex method according to code | ||||
|      * standards but it just has a lot of ??-statements because of the fields that may or may not exist. | ||||
|      * standards, but it just has a lot of ??-statements because of the fields that may or may not exist. | ||||
|      */ | ||||
|     private function getTransactionData(): array | ||||
|     { | ||||
| @@ -154,7 +154,7 @@ class UpdateRequest extends FormRequest | ||||
|         return [ | ||||
|             'title'                                => sprintf('min:1|max:255|uniqueObjectForUser:recurrences,title,%d', $recurrence->id), | ||||
|             'description'                          => 'min:1|max:32768', | ||||
|             'first_date'                           => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'first_date'                           => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'apply_rules'                          => [new IsBoolean()], | ||||
|             'active'                               => [new IsBoolean()], | ||||
|             'repeat_until'                         => 'nullable|date', | ||||
|   | ||||
| @@ -71,8 +71,8 @@ class TestRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start'      => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'        => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31', | ||||
|             'start'      => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'        => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17', | ||||
|             'accounts'   => '', | ||||
|             'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts', | ||||
|         ]; | ||||
|   | ||||
| @@ -65,8 +65,8 @@ class TriggerRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start'      => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'        => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31', | ||||
|             'start'      => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'        => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17', | ||||
|             'accounts'   => '', | ||||
|             'accounts.*' => 'exists:accounts,id|belongsToUser:accounts', | ||||
|         ]; | ||||
|   | ||||
| @@ -65,8 +65,8 @@ class TestRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start'      => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'        => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31', | ||||
|             'start'      => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'        => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17', | ||||
|             'accounts'   => '', | ||||
|             'accounts.*' => 'exists:accounts,id|belongsToUser:accounts', | ||||
|         ]; | ||||
|   | ||||
| @@ -69,8 +69,8 @@ class TriggerRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start' => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'   => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31', | ||||
|             'start' => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'   => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -62,7 +62,7 @@ class StoreRequest extends FormRequest | ||||
|         $rules = [ | ||||
|             'tag'         => 'required|min:1|uniqueObjectForUser:tags,tag|max:1024', | ||||
|             'description' => 'min:1|nullable|max:32768', | ||||
|             'date'        => 'date|nullable|after:1900-01-01|before:2099-12-31', | ||||
|             'date'        => 'date|nullable|after:1970-01-02|before:2038-01-17', | ||||
|         ]; | ||||
| 
 | ||||
|         return Location::requestRules($rules); | ||||
|   | ||||
| @@ -66,7 +66,7 @@ class UpdateRequest extends FormRequest | ||||
|         $rules = [ | ||||
|             'tag'         => 'min:1|max:1024|uniqueObjectForUser:tags,tag,'.$tag->id, | ||||
|             'description' => 'min:1|nullable|max:32768', | ||||
|             'date'        => 'date|nullable|after:1900-01-01|before:2099-12-31', | ||||
|             'date'        => 'date|nullable|after:1970-01-02|before:2038-01-17', | ||||
|         ]; | ||||
| 
 | ||||
|         return Location::requestRules($rules); | ||||
|   | ||||
| @@ -58,7 +58,7 @@ class StoreRequest extends FormRequest | ||||
|      */ | ||||
|     public function getAll(): array | ||||
|     { | ||||
|         app('log')->debug('get all data in TransactionStoreRequest'); | ||||
|         Log::debug('get all data in TransactionStoreRequest'); | ||||
| 
 | ||||
|         return [ | ||||
|             'group_title'             => $this->convertString('group_title'), | ||||
| @@ -175,7 +175,7 @@ class StoreRequest extends FormRequest | ||||
|      */ | ||||
|     public function rules(): array | ||||
|     { | ||||
|         app('log')->debug('Collect rules of TransactionStoreRequest'); | ||||
|         Log::debug('Collect rules of TransactionStoreRequest'); | ||||
|         $validProtocols = config('firefly.valid_url_protocols'); | ||||
|         $locationRules  = Location::requestRules([]); | ||||
| 
 | ||||
| @@ -276,9 +276,9 @@ class StoreRequest extends FormRequest | ||||
|                 $this->validateTransactionArray($validator); | ||||
| 
 | ||||
|                 // must submit at least one transaction.
 | ||||
|                 app('log')->debug('Now going to validateOneTransaction'); | ||||
|                 Log::debug('Now going to validateOneTransaction'); | ||||
|                 $this->validateOneTransaction($validator); | ||||
|                 app('log')->debug('Now done with validateOneTransaction'); | ||||
|                 Log::debug('Now done with validateOneTransaction'); | ||||
| 
 | ||||
|                 // all journals must have a description
 | ||||
|                 $this->validateDescriptions($validator); | ||||
|   | ||||
| @@ -183,7 +183,7 @@ class UpdateRequest extends FormRequest | ||||
|         foreach ($this->dateFields as $fieldName) { | ||||
|             app('log')->debug(sprintf('Now at date field %s', $fieldName)); | ||||
|             if (array_key_exists($fieldName, $transaction)) { | ||||
|                 app('log')->debug(sprintf('New value: "%s"', (string) $transaction[$fieldName])); | ||||
|                 Log::debug(sprintf('New value: "%s"', $transaction[$fieldName])); | ||||
|                 $current[$fieldName] = $this->dateFromValue((string) $transaction[$fieldName]); | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -24,7 +24,6 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Api\V1\Requests\Models\UserGroup; | ||||
| 
 | ||||
| use FireflyIII\Models\UserGroup; | ||||
| use FireflyIII\Support\Request\ChecksLogin; | ||||
| use FireflyIII\Support\Request\ConvertsDataTypes; | ||||
| use Illuminate\Foundation\Http\FormRequest; | ||||
| @@ -53,9 +52,6 @@ class UpdateRequest extends FormRequest | ||||
|      */ | ||||
|     public function rules(): array | ||||
|     { | ||||
|         /** @var UserGroup $userGroup */ | ||||
|         $userGroup = $this->route()->parameter('userGroup'); | ||||
| 
 | ||||
|         return [ | ||||
|             'title'                => ['required', 'min:1', 'max:255'], | ||||
|             'native_currency_id'   => 'exists:transaction_currencies,id', | ||||
|   | ||||
| @@ -73,7 +73,7 @@ class CronRequest extends FormRequest | ||||
|     { | ||||
|         return [ | ||||
|             'force' => 'in:true,false', | ||||
|             'date'  => 'nullable|date|after:1900-01-01|before:2099-12-31', | ||||
|             'date'  => 'nullable|date|after:1970-01-02|before:2038-01-17', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -39,7 +39,6 @@ use League\Fractal\Resource\Collection as FractalCollection; | ||||
| use League\Fractal\Resource\Item; | ||||
| use League\Fractal\Serializer\JsonApiSerializer; | ||||
| use Psr\Container\ContainerExceptionInterface; | ||||
| use Psr\Container\NotFoundExceptionInterface; | ||||
| use Symfony\Component\HttpFoundation\Exception\BadRequestException; | ||||
| use Symfony\Component\HttpFoundation\ParameterBag; | ||||
| 
 | ||||
| @@ -82,7 +81,7 @@ class Controller extends BaseController | ||||
| 
 | ||||
|         try { | ||||
|             $page = (int) request()->get('page'); | ||||
|         } catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) { | ||||
|         } catch (ContainerExceptionInterface) { | ||||
|             $page = 1; | ||||
|         } | ||||
| 
 | ||||
| @@ -117,7 +116,7 @@ class Controller extends BaseController | ||||
|                     app('log')->warning(sprintf('Ignored invalid date "%s" in API v2 controller parameter check: %s', substr((string) $date, 0, 20), $e->getMessage())); | ||||
|                 } | ||||
|                 // out of range? set to null.
 | ||||
|                 if ($obj instanceof Carbon && ($obj->year <= 1900 || $obj->year > 2099)) { | ||||
|                 if ($obj instanceof Carbon && ($obj->year <= 1970 || $obj->year > 2038)) { | ||||
|                     app('log')->warning(sprintf('Refuse to use date "%s" in API v2 controller parameter check: %s', $field, $obj->toAtomString())); | ||||
|                     $obj = null; | ||||
|                 } | ||||
|   | ||||
| @@ -53,7 +53,7 @@ class ListController extends Controller | ||||
|      */ | ||||
|     public function index(): JsonResponse | ||||
|     { | ||||
|         return response()->json([]); | ||||
|         return response()->json(); | ||||
|         //        throw new FireflyException('Needs refactoring, move to IndexController.');
 | ||||
|         //        $pageSize   = $this->parameters->get('limit');
 | ||||
|         //        $dates      = $request->getAll();
 | ||||
|   | ||||
| @@ -65,29 +65,28 @@ class UpdateController extends Controller | ||||
|     public function update(UpdateRequest $request, TransactionGroup $transactionGroup): JsonResponse | ||||
|     { | ||||
|         app('log')->debug('Now in update routine for transaction group [v2]!'); | ||||
|         $data              = $request->getAll(); | ||||
|         $transactionGroup  = $this->groupRepository->update($transactionGroup, $data); | ||||
|         $applyRules        = $data['apply_rules'] ?? true; | ||||
|         $fireWebhooks      = $data['fire_webhooks'] ?? true; | ||||
|         $runRecalculations = true; | ||||
|         $data             = $request->getAll(); | ||||
|         $transactionGroup = $this->groupRepository->update($transactionGroup, $data); | ||||
|         $applyRules       = $data['apply_rules'] ?? true; | ||||
|         $fireWebhooks     = $data['fire_webhooks'] ?? true; | ||||
| 
 | ||||
|         event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks, $runRecalculations)); | ||||
|         event(new UpdatedTransactionGroup($transactionGroup, $applyRules, $fireWebhooks, true)); | ||||
|         app('preferences')->mark(); | ||||
| 
 | ||||
|         /** @var User $admin */ | ||||
|         $admin             = auth()->user(); | ||||
|         $admin            = auth()->user(); | ||||
| 
 | ||||
|         // use new group collector:
 | ||||
|         /** @var GroupCollectorInterface $collector */ | ||||
|         $collector         = app(GroupCollectorInterface::class); | ||||
|         $collector        = app(GroupCollectorInterface::class); | ||||
|         $collector->setUser($admin)->setTransactionGroup($transactionGroup); | ||||
| 
 | ||||
|         $selectedGroup     = $collector->getGroups()->first(); | ||||
|         $selectedGroup    = $collector->getGroups()->first(); | ||||
|         if (null === $selectedGroup) { | ||||
|             throw new FireflyException('200032: Cannot find transaction. Possibly, a rule deleted this transaction after its creation.'); | ||||
|         } | ||||
| 
 | ||||
|         $transformer       = new TransactionGroupTransformer(); | ||||
|         $transformer      = new TransactionGroupTransformer(); | ||||
|         $transformer->setParameters($this->parameters); | ||||
| 
 | ||||
|         return response()->api($this->jsonApiObject('transactions', $selectedGroup, $transformer))->header('Content-Type', self::CONTENT_TYPE); | ||||
|   | ||||
| @@ -31,6 +31,7 @@ use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; | ||||
| use FireflyIII\Transformers\CurrencyTransformer; | ||||
| use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Pagination\LengthAwarePaginator; | ||||
| use Illuminate\Support\Collection; | ||||
| 
 | ||||
| class IndexController extends Controller | ||||
| { | ||||
| @@ -56,6 +57,7 @@ class IndexController extends Controller | ||||
|     public function index(IndexRequest $request): JsonResponse | ||||
|     { | ||||
|         $settings    = $request->getAll(); | ||||
|         $currencies  = new Collection(); | ||||
|         if (true === $settings['enabled']) { | ||||
|             $currencies = $this->repository->get(); | ||||
|         } | ||||
|   | ||||
| @@ -86,7 +86,7 @@ class AutocompleteRequest extends FormRequest | ||||
|         $valid = array_keys($this->types); | ||||
| 
 | ||||
|         return [ | ||||
|             'date'              => 'nullable|date|after:1900-01-01|before:2100-01-01', | ||||
|             'date'              => 'nullable|date|after:1970-01-02|before:2038-01-17', | ||||
|             'query'             => 'nullable|string', | ||||
|             'size'              => 'nullable|integer|min:1|max:100', | ||||
|             'page'              => 'nullable|integer|min:1', | ||||
|   | ||||
| @@ -60,8 +60,8 @@ class BalanceChartRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start'      => 'required|date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'        => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01', | ||||
|             'start'      => 'required|date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'        => 'required|date|after_or_equal:start|before:2038-01-17|after:1970-01-02', | ||||
|             'accounts.*' => 'required|exists:accounts,id', | ||||
|             'period'     => sprintf('required|in:%s', implode(',', config('firefly.valid_view_ranges'))), | ||||
|         ]; | ||||
|   | ||||
| @@ -61,8 +61,8 @@ class ChartRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start'       => 'required|date|after:1900-01-01|before:2099-12-31|before_or_equal:end', | ||||
|             'end'         => 'required|date|after:1900-01-01|before:2099-12-31|after_or_equal:start', | ||||
|             'start'       => 'required|date|after:1970-01-02|before:2038-01-17|before_or_equal:end', | ||||
|             'end'         => 'required|date|after:1970-01-02|before:2038-01-17|after_or_equal:start', | ||||
|             'preselected' => sprintf('nullable|in:%s', implode(',', config('firefly.preselected_accounts'))), | ||||
|             'period'      => sprintf('nullable|in:%s', implode(',', config('firefly.valid_view_ranges'))), | ||||
|             'accounts.*'  => 'exists:accounts,id', | ||||
|   | ||||
| @@ -60,8 +60,8 @@ class DashboardChartRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start'       => 'required|date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'         => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01', | ||||
|             'start'       => 'required|date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'         => 'required|date|after_or_equal:start|before:2038-01-17|after:1970-01-02', | ||||
|             'preselected' => sprintf('in:%s', implode(',', config('firefly.preselected_accounts'))), | ||||
|             'accounts.*'  => 'exists:accounts,id', | ||||
|         ]; | ||||
|   | ||||
| @@ -55,8 +55,8 @@ class DateRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start' => 'required|date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'   => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01', | ||||
|             'start' => 'required|date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'   => 'required|date|after_or_equal:start|before:2038-01-17|after:1970-01-02', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -53,7 +53,7 @@ class SingleDateRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'date' => 'required|date|after:1900-01-01|before:2099-12-31', | ||||
|             'date' => 'required|date|after:1970-01-02|before:2038-01-17', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -63,9 +63,9 @@ class IndexRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'date'  => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'start' => 'date|after:1900-01-01|before:2099-12-31|before:end|required_with:end', | ||||
|             'end'   => 'date|after:1900-01-01|before:2099-12-31|after:start|required_with:start', | ||||
|             'date'  => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'start' => 'date|after:1970-01-02|before:2038-01-17|before:end|required_with:end', | ||||
|             'end'   => 'date|after:1970-01-02|before:2038-01-17|after:start|required_with:start', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -109,8 +109,8 @@ class InfiniteListRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start'     => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'       => 'date|after:start|after:1900-01-01|before:2099-12-31', | ||||
|             'start'     => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'       => 'date|after:start|after:1970-01-02|before:2038-01-17', | ||||
|             'start_row' => 'integer|min:0|max:4294967296', | ||||
|             'end_row'   => 'integer|min:0|max:4294967296|gt:start_row', | ||||
|         ]; | ||||
|   | ||||
| @@ -84,8 +84,8 @@ class ListRequest extends FormRequest | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'start' => 'date|after:1900-01-01|before:2099-12-31', | ||||
|             'end'   => 'date|after:start|after:1900-01-01|before:2099-12-31', | ||||
|             'start' => 'date|after:1970-01-02|before:2038-01-17', | ||||
|             'end'   => 'date|after:start|after:1970-01-02|before:2038-01-17', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -68,7 +68,7 @@ class UpdateRequest extends Request | ||||
|     #[Override]
 | ||||
|     public function getAll(): array | ||||
|     { | ||||
|         app('log')->debug(sprintf('Now in %s', __METHOD__)); | ||||
|         Log::debug(sprintf('Now in %s', __METHOD__)); | ||||
|         $this->integerFields  = ['order', 'currency_id', 'foreign_currency_id', 'transaction_journal_id', 'source_id', 'destination_id', 'budget_id', 'category_id', 'bill_id', 'recurrence_id']; | ||||
|         $this->dateFields     = ['date', 'interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date']; | ||||
|         $this->textareaFields = ['notes']; | ||||
| @@ -101,7 +101,7 @@ class UpdateRequest extends Request | ||||
|      */ | ||||
|     private function getTransactionData(): array | ||||
|     { | ||||
|         app('log')->debug(sprintf('Now in %s', __METHOD__)); | ||||
|         Log::debug(sprintf('Now in %s', __METHOD__)); | ||||
|         $return       = []; | ||||
| 
 | ||||
|         /** @var null|array $transactions */ | ||||
| @@ -185,9 +185,9 @@ class UpdateRequest extends Request | ||||
|     private function getDateData(array $current, array $transaction): array | ||||
|     { | ||||
|         foreach ($this->dateFields as $fieldName) { | ||||
|             app('log')->debug(sprintf('Now at date field %s', $fieldName)); | ||||
|             Log::debug(sprintf('Now at date field %s', $fieldName)); | ||||
|             if (array_key_exists($fieldName, $transaction)) { | ||||
|                 app('log')->debug(sprintf('New value: "%s"', (string) $transaction[$fieldName])); | ||||
|                 Log::debug(sprintf('New value: "%s"', $transaction[$fieldName])); | ||||
|                 $current[$fieldName] = $this->dateFromValue((string) $transaction[$fieldName]); | ||||
|             } | ||||
|         } | ||||
| @@ -252,7 +252,7 @@ class UpdateRequest extends Request | ||||
|     #[Override]
 | ||||
|     public function rules(): array | ||||
|     { | ||||
|         app('log')->debug(sprintf('Now in %s', __METHOD__)); | ||||
|         Log::debug(sprintf('Now in %s', __METHOD__)); | ||||
|         $validProtocols = config('firefly.valid_url_protocols'); | ||||
| 
 | ||||
|         return [ | ||||
| @@ -336,7 +336,7 @@ class UpdateRequest extends Request | ||||
|     #[Override]
 | ||||
|     public function withValidator(Validator $validator): void | ||||
|     { | ||||
|         app('log')->debug('Now in withValidator'); | ||||
|         Log::debug('Now in withValidator'); | ||||
| 
 | ||||
|         /** @var TransactionGroup $transactionGroup */ | ||||
|         $transactionGroup = $this->route()->parameter('userGroupTransaction'); | ||||
|   | ||||
| @@ -30,6 +30,7 @@ use FireflyIII\Enums\TransactionTypeEnum; | ||||
| use FireflyIII\Models\Transaction; | ||||
| use FireflyIII\Models\TransactionJournal; | ||||
| use FireflyIII\Repositories\Account\AccountRepositoryInterface; | ||||
| use FireflyIII\Support\Facades\Steam; | ||||
| use FireflyIII\Support\Models\AccountBalanceCalculator; | ||||
| use Illuminate\Console\Command; | ||||
| use Illuminate\Support\Facades\DB; | ||||
| @@ -140,6 +141,7 @@ class CorrectsUnevenAmount extends Command | ||||
|         /** @var stdClass $entry */ | ||||
|         foreach ($journals as $entry) { | ||||
|             $sum = (string) $entry->the_sum; | ||||
|             $sum = Steam::floatalize($sum); | ||||
|             if (!is_numeric($sum) | ||||
|                 || '' === $sum // @phpstan-ignore-line
 | ||||
|                 || str_contains($sum, 'e') | ||||
|   | ||||
| @@ -26,6 +26,7 @@ namespace FireflyIII\Console\Commands\Integrity; | ||||
| 
 | ||||
| use FireflyIII\Console\Commands\ShowsFriendlyMessages; | ||||
| use FireflyIII\Repositories\User\UserRepositoryInterface; | ||||
| use FireflyIII\Support\Facades\Steam; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Console\Command; | ||||
| 
 | ||||
| @@ -60,6 +61,8 @@ class ReportsSums extends Command | ||||
|             $foreign = (string) $user->transactions()->selectRaw('SUM(foreign_amount) as total')->value('total'); | ||||
|             $sum     = '' === $sum ? '0' : $sum; | ||||
|             $foreign = '' === $foreign ? '0' : $foreign; | ||||
|             $sum     = Steam::floatalize($sum); | ||||
|             $foreign = Steam::floatalize($foreign); | ||||
|             $total   = bcadd($sum, $foreign); | ||||
| 
 | ||||
|             if (0 !== bccomp($total, '0')) { | ||||
|   | ||||
| @@ -87,6 +87,12 @@ class UpgradesMultiPiggyBanks extends Command | ||||
| 
 | ||||
|     private function upgradePiggyBank(PiggyBank $piggyBank): void | ||||
|     { | ||||
|         if (null === $piggyBank->account) { | ||||
|             // #10432 account has been deleted, delete piggy bank.
 | ||||
|             $piggyBank->delete(); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
|         $this->repository->setUser($piggyBank->account->user); | ||||
|         $this->accountRepository->setUser($piggyBank->account->user); | ||||
|         $repetition                         = $this->repository->getRepetition($piggyBank, true); | ||||
|   | ||||
							
								
								
									
										16
									
								
								app/Events/Model/PiggyBank/ChangedName.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/Events/Model/PiggyBank/ChangedName.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| <?php | ||||
| 
 | ||||
| declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Events\Model\PiggyBank; | ||||
| 
 | ||||
| use FireflyIII\Events\Event; | ||||
| use FireflyIII\Models\PiggyBank; | ||||
| use Illuminate\Queue\SerializesModels; | ||||
| 
 | ||||
| class ChangedName extends Event | ||||
| { | ||||
|     use SerializesModels; | ||||
| 
 | ||||
|     public function __construct(public PiggyBank $piggyBank, public string $oldName, public string $newName) {} | ||||
| } | ||||
| @@ -58,11 +58,13 @@ use function Safe\parse_url; | ||||
|  */ | ||||
| class Handler extends ExceptionHandler | ||||
| { | ||||
|     public static ?Throwable $lastError = null; | ||||
| 
 | ||||
|     /** | ||||
|      * @var array<int, class-string<Throwable>> | ||||
|      */ | ||||
|     protected $dontReport | ||||
|         = [ | ||||
|                                         = [ | ||||
|             AuthenticationException::class, | ||||
|             LaravelValidationException::class, | ||||
|             NotFoundHttpException::class, | ||||
| @@ -123,7 +125,7 @@ class Handler extends ExceptionHandler | ||||
|             // somehow Laravel handler does not catch this:
 | ||||
|             app('log')->debug('Return JSON unauthenticated error.'); | ||||
| 
 | ||||
|             return response()->json(['message' => 'Unauthenticated', 'exception' => 'AuthenticationException'], 401); | ||||
|             return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthenticationException'], 401); | ||||
|         } | ||||
| 
 | ||||
|         if ($e instanceof OAuthServerException && $expectsJson) { | ||||
| @@ -215,13 +217,14 @@ class Handler extends ExceptionHandler | ||||
|     #[Override]
 | ||||
|     public function report(Throwable $e): void | ||||
|     { | ||||
|         $doMailError = (bool) config('firefly.send_error_message'); | ||||
|         self::$lastError = $e; | ||||
|         $doMailError     = (bool) config('firefly.send_error_message'); | ||||
|         if ($this->shouldntReportLocal($e) || !$doMailError) { | ||||
|             parent::report($e); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
|         $userData    = [ | ||||
|         $userData        = [ | ||||
|             'id'    => 0, | ||||
|             'email' => 'unknown@example.com', | ||||
|         ]; | ||||
| @@ -230,9 +233,9 @@ class Handler extends ExceptionHandler | ||||
|             $userData['email'] = auth()->user()->email; | ||||
|         } | ||||
| 
 | ||||
|         $headers     = request()->headers->all(); | ||||
|         $headers         = request()->headers->all(); | ||||
| 
 | ||||
|         $data        = [ | ||||
|         $data            = [ | ||||
|             'class'        => $e::class, | ||||
|             'errorMessage' => $e->getMessage(), | ||||
|             'time'         => Carbon::now()->format('r'), | ||||
| @@ -250,8 +253,8 @@ class Handler extends ExceptionHandler | ||||
|         ]; | ||||
| 
 | ||||
|         // create job that will mail.
 | ||||
|         $ipAddress   = request()->ip() ?? '0.0.0.0'; | ||||
|         $job         = new MailError($userData, (string) config('firefly.site_owner'), $ipAddress, $data); | ||||
|         $ipAddress       = request()->ip() ?? '0.0.0.0'; | ||||
|         $job             = new MailError($userData, (string) config('firefly.site_owner'), $ipAddress, $data); | ||||
|         dispatch($job); | ||||
| 
 | ||||
|         parent::report($e); | ||||
|   | ||||
| @@ -46,9 +46,9 @@ class PiggyBankFactory | ||||
| { | ||||
|     use CreatesObjectGroups; | ||||
| 
 | ||||
|     public User                          $user; | ||||
|     private AccountRepositoryInterface   $accountRepository; | ||||
|     private CurrencyRepositoryInterface  $currencyRepository; | ||||
|     public User $user; | ||||
|     private AccountRepositoryInterface $accountRepository; | ||||
|     private CurrencyRepositoryInterface $currencyRepository; | ||||
|     private PiggyBankRepositoryInterface $piggyBankRepository; | ||||
| 
 | ||||
|     public function __construct() | ||||
| @@ -78,7 +78,7 @@ class PiggyBankFactory | ||||
|         unset($piggyBankData['object_group_title'], $piggyBankData['transaction_currency_code'], $piggyBankData['transaction_currency_id'], $piggyBankData['accounts'], $piggyBankData['object_group_id'], $piggyBankData['notes']); | ||||
| 
 | ||||
|         // validate amount:
 | ||||
|         if (array_key_exists('target_amount', $piggyBankData) && '' === (string) $piggyBankData['target_amount']) { | ||||
|         if (array_key_exists('target_amount', $piggyBankData) && '' === (string)$piggyBankData['target_amount']) { | ||||
|             $piggyBankData['target_amount'] = '0'; | ||||
|         } | ||||
| 
 | ||||
| @@ -108,7 +108,7 @@ class PiggyBankFactory | ||||
|             } | ||||
|         } | ||||
|         // try also with ID
 | ||||
|         $objectGroupId                            = (int) ($data['object_group_id'] ?? 0); | ||||
|         $objectGroupId                            = (int)($data['object_group_id'] ?? 0); | ||||
|         if (0 !== $objectGroupId) { | ||||
|             $objectGroup = $this->findObjectGroupById($objectGroupId); | ||||
|             if ($objectGroup instanceof ObjectGroup) { | ||||
| @@ -129,10 +129,10 @@ class PiggyBankFactory | ||||
|         $defaultCurrency = app('amount')->getNativeCurrency(); | ||||
|         $currency        = null; | ||||
|         if (array_key_exists('transaction_currency_code', $data)) { | ||||
|             $currency = $this->currencyRepository->findByCode((string) ($data['transaction_currency_code'] ?? '')); | ||||
|             $currency = $this->currencyRepository->findByCode((string)($data['transaction_currency_code'] ?? '')); | ||||
|         } | ||||
|         if (array_key_exists('transaction_currency_id', $data)) { | ||||
|             $currency = $this->currencyRepository->find((int) ($data['transaction_currency_id'] ?? 0)); | ||||
|             $currency = $this->currencyRepository->find((int)($data['transaction_currency_id'] ?? 0)); | ||||
|         } | ||||
|         $currency ??= $defaultCurrency; | ||||
| 
 | ||||
| @@ -141,8 +141,8 @@ class PiggyBankFactory | ||||
| 
 | ||||
|     public function find(?int $piggyBankId, ?string $piggyBankName): ?PiggyBank | ||||
|     { | ||||
|         $piggyBankId   = (int) $piggyBankId; | ||||
|         $piggyBankName = (string) $piggyBankName; | ||||
|         $piggyBankId   = (int)$piggyBankId; | ||||
|         $piggyBankName = (string)$piggyBankName; | ||||
|         if ('' === $piggyBankName && 0 === $piggyBankId) { | ||||
|             return null; | ||||
|         } | ||||
| @@ -221,7 +221,7 @@ class PiggyBankFactory | ||||
| 
 | ||||
|     private function getMaxOrder(): int | ||||
|     { | ||||
|         return (int) $this->piggyBankRepository->getPiggyBanks()->max('order'); | ||||
|         return (int)$this->piggyBankRepository->getPiggyBanks()->max('order'); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| @@ -230,12 +230,13 @@ class PiggyBankFactory | ||||
|         Log::debug(sprintf('Linking piggy bank #%d to %d accounts.', $piggyBank->id, count($accounts)), $accounts); | ||||
|         // collect current current_amount so the sync does not remove them.
 | ||||
|         // TODO this is a tedious check. Feels like a hack.
 | ||||
|         $toBeLinked = []; | ||||
|         $toBeLinked     = []; | ||||
|         $oldSavedAmount = $this->piggyBankRepository->getCurrentAmount($piggyBank); | ||||
|         foreach ($piggyBank->accounts as $account) { | ||||
|             Log::debug(sprintf('Checking account #%d', $account->id)); | ||||
|             foreach ($accounts as $info) { | ||||
|                 Log::debug(sprintf('  Checking other account #%d', $info['account_id'])); | ||||
|                 if ((int) $account->id === (int) $info['account_id']) { | ||||
|                 if ((int)$account->id === (int)$info['account_id']) { | ||||
|                     $toBeLinked[$account->id] = ['current_amount' => $account->pivot->current_amount ?? '0']; | ||||
|                     Log::debug(sprintf('Prefilled for account #%d with amount %s', $account->id, $account->pivot->current_amount ?? '0')); | ||||
|                 } | ||||
| @@ -244,9 +245,9 @@ class PiggyBankFactory | ||||
| 
 | ||||
|         /** @var array $info */ | ||||
|         foreach ($accounts as $info) { | ||||
|             $account = $this->accountRepository->find((int) ($info['account_id'] ?? 0)); | ||||
|             $account = $this->accountRepository->find((int)($info['account_id'] ?? 0)); | ||||
|             if (!$account instanceof Account) { | ||||
|                 Log::debug(sprintf('Account #%d not found, skipping.', (int) ($info['account_id'] ?? 0))); | ||||
|                 Log::debug(sprintf('Account #%d not found, skipping.', (int)($info['account_id'] ?? 0))); | ||||
| 
 | ||||
|                 continue; | ||||
|             } | ||||
| @@ -290,7 +291,16 @@ class PiggyBankFactory | ||||
|         } | ||||
|         Log::debug(sprintf('Link information: %s', json_encode($toBeLinked))); | ||||
|         if (0 !== count($toBeLinked)) { | ||||
|             Log::debug('Syncing accounts to piggy bank.'); | ||||
|             $piggyBank->accounts()->sync($toBeLinked); | ||||
|             $piggyBank->refresh(); | ||||
|             $newSavedAmount = $this->piggyBankRepository->getCurrentAmount($piggyBank); | ||||
|             Log::debug(sprintf('Old saved amount: %s, new saved amount is %s', $oldSavedAmount, $newSavedAmount)); | ||||
|             if (0 !== bccomp($oldSavedAmount, $newSavedAmount)) { | ||||
|                 Log::debug('Amount changed, will create event for it.'); | ||||
|                 // create event for difference.
 | ||||
|                 event(new ChangedAmount($piggyBank, bcsub($newSavedAmount, $oldSavedAmount), null, null)); | ||||
|             } | ||||
|         } | ||||
|         if (0 === count($toBeLinked)) { | ||||
|             Log::warning('No accounts to link to piggy bank, will not change whatever is there now.'); | ||||
|   | ||||
| @@ -75,15 +75,15 @@ class TagFactory | ||||
|         $latitude  = 0.0 === (float) $data['latitude'] ? null : (float) $data['latitude'];   // intentional float
 | ||||
|         $longitude = 0.0 === (float) $data['longitude'] ? null : (float) $data['longitude']; // intentional float
 | ||||
|         $array     = [ | ||||
|             'user_id'       => $this->user->id, | ||||
|             'user_group_id' => $this->userGroup->id, | ||||
|             'tag'           => trim((string) $data['tag']), | ||||
|             'tagMode'       => 'nothing', | ||||
|             'date'          => $data['date'], | ||||
|             'description'   => $data['description'], | ||||
|             'latitude'      => null, | ||||
|             'longitude'     => null, | ||||
|             'zoomLevel'     => null, | ||||
|             'user_id'        => $this->user->id, | ||||
|             'user_group_id'  => $this->userGroup->id, | ||||
|             'tag'            => trim((string) $data['tag']), | ||||
|             'tag_mode'       => 'nothing', | ||||
|             'date'           => $data['date'], | ||||
|             'description'    => $data['description'], | ||||
|             'latitude'       => null, | ||||
|             'longitude'      => null, | ||||
|             'zoomLevel'      => null, | ||||
|         ]; | ||||
| 
 | ||||
|         /** @var null|Tag $tag */ | ||||
|   | ||||
| @@ -32,11 +32,14 @@ use FireflyIII\Models\TransactionGroup; | ||||
| use FireflyIII\Models\TransactionJournal; | ||||
| use FireflyIII\Models\Webhook; | ||||
| use FireflyIII\Models\WebhookMessage; | ||||
| use FireflyIII\Support\Facades\Amount; | ||||
| use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment; | ||||
| use FireflyIII\Transformers\AccountTransformer; | ||||
| use FireflyIII\Transformers\TransactionGroupTransformer; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Database\Eloquent\Model; | ||||
| use Illuminate\Support\Collection; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| use Ramsey\Uuid\Uuid; | ||||
| use Symfony\Component\HttpFoundation\ParameterBag; | ||||
| 
 | ||||
| @@ -59,14 +62,14 @@ class StandardMessageGenerator implements MessageGeneratorInterface | ||||
| 
 | ||||
|     public function generateMessages(): void | ||||
|     { | ||||
|         app('log')->debug(__METHOD__); | ||||
|         Log::debug(__METHOD__); | ||||
|         // get the webhooks:
 | ||||
|         if (0 === $this->webhooks->count()) { | ||||
|             $this->webhooks = $this->getWebhooks(); | ||||
|         } | ||||
| 
 | ||||
|         // do some debugging
 | ||||
|         app('log')->debug( | ||||
|         Log::debug( | ||||
|             sprintf('StandardMessageGenerator will generate messages for %d object(s) and %d webhook(s).', $this->objects->count(), $this->webhooks->count()) | ||||
|         ); | ||||
|         $this->run(); | ||||
| @@ -79,13 +82,13 @@ class StandardMessageGenerator implements MessageGeneratorInterface | ||||
| 
 | ||||
|     private function run(): void | ||||
|     { | ||||
|         app('log')->debug('Now in StandardMessageGenerator::run'); | ||||
|         Log::debug('Now in StandardMessageGenerator::run'); | ||||
| 
 | ||||
|         /** @var Webhook $webhook */ | ||||
|         foreach ($this->webhooks as $webhook) { | ||||
|             $this->runWebhook($webhook); | ||||
|         } | ||||
|         app('log')->debug('Done with StandardMessageGenerator::run'); | ||||
|         Log::debug('Done with StandardMessageGenerator::run'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @@ -93,7 +96,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface | ||||
|      */ | ||||
|     private function runWebhook(Webhook $webhook): void | ||||
|     { | ||||
|         app('log')->debug(sprintf('Now in runWebhook(#%d)', $webhook->id)); | ||||
|         Log::debug(sprintf('Now in runWebhook(#%d)', $webhook->id)); | ||||
| 
 | ||||
|         /** @var Model $object */ | ||||
|         foreach ($this->objects as $object) { | ||||
| @@ -108,7 +111,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface | ||||
|     { | ||||
|         $class        = $model::class; | ||||
|         // Line is ignored because all of Firefly III's Models have an id property.
 | ||||
|         app('log')->debug(sprintf('Now in generateMessage(#%d, %s#%d)', $webhook->id, $class, $model->id)); | ||||
|         Log::debug(sprintf('Now in generateMessage(#%d, %s#%d)', $webhook->id, $class, $model->id)); | ||||
| 
 | ||||
|         $uuid         = Uuid::uuid4(); | ||||
|         $basicMessage = [ | ||||
| @@ -125,7 +128,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface | ||||
|         switch ($class) { | ||||
|             default: | ||||
|                 // Line is ignored because all of Firefly III's Models have an id property.
 | ||||
|                 app('log')->error( | ||||
|                 Log::error( | ||||
|                     sprintf('Webhook #%d was given %s#%d to deal with but can\'t extract user ID from it.', $webhook->id, $class, $model->id) | ||||
|                 ); | ||||
| 
 | ||||
| @@ -141,7 +144,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface | ||||
|         // then depends on the response what to put in the message:
 | ||||
|         switch ($webhook->response) { | ||||
|             default: | ||||
|                 app('log')->error( | ||||
|                 Log::error( | ||||
|                     sprintf('The response code for webhook #%d is "%d" and the message generator cant handle it. Soft fail.', $webhook->id, $webhook->response) | ||||
|                 ); | ||||
| 
 | ||||
| @@ -159,10 +162,10 @@ class StandardMessageGenerator implements MessageGeneratorInterface | ||||
|                 try { | ||||
|                     $basicMessage['content'] = $transformer->transformObject($model); | ||||
|                 } catch (FireflyException $e) { | ||||
|                     app('log')->error( | ||||
|                     Log::error( | ||||
|                         sprintf('The transformer could not include the requested transaction group for webhook #%d: %s', $webhook->id, $e->getMessage()) | ||||
|                     ); | ||||
|                     app('log')->error($e->getTraceAsString()); | ||||
|                     Log::error($e->getTraceAsString()); | ||||
| 
 | ||||
|                     return; | ||||
|                 } | ||||
| @@ -172,6 +175,10 @@ class StandardMessageGenerator implements MessageGeneratorInterface | ||||
|             case WebhookResponse::ACCOUNTS->value: | ||||
|                 /** @var TransactionGroup $model */ | ||||
|                 $accounts                = $this->collectAccounts($model); | ||||
|                 $enrichment              = new AccountEnrichment(); | ||||
|                 $enrichment->setUser($model->user); | ||||
|                 $enrichment->setNative(Amount::getNativeCurrencyByUserGroup($model->userGroup)); | ||||
|                 $accounts                = $enrichment->enrich($accounts); | ||||
|                 foreach ($accounts as $account) { | ||||
|                     $transformer               = new AccountTransformer(); | ||||
|                     $transformer->setParameters(new ParameterBag()); | ||||
| @@ -210,7 +217,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface | ||||
|         $webhookMessage->uuid    = $message['uuid']; | ||||
|         $webhookMessage->message = $message; | ||||
|         $webhookMessage->save(); | ||||
|         app('log')->debug(sprintf('Stored new webhook message #%d', $webhookMessage->id)); | ||||
|         Log::debug(sprintf('Stored new webhook message #%d', $webhookMessage->id)); | ||||
|     } | ||||
| 
 | ||||
|     public function setObjects(Collection $objects): void | ||||
|   | ||||
| @@ -24,6 +24,10 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Handlers\Events\Model; | ||||
| 
 | ||||
| use FireflyIII\Events\Model\PiggyBank\ChangedName; | ||||
| use FireflyIII\Models\Account; | ||||
| use FireflyIII\Models\Rule; | ||||
| use FireflyIII\Models\RuleAction; | ||||
| use FireflyIII\Models\TransactionGroup; | ||||
| use FireflyIII\Events\Model\PiggyBank\ChangedAmount; | ||||
| use FireflyIII\Models\PiggyBankEvent; | ||||
| @@ -33,6 +37,24 @@ use FireflyIII\Models\PiggyBankEvent; | ||||
|  */ | ||||
| class PiggyBankEventHandler | ||||
| { | ||||
|     public function changedPiggyBankName(ChangedName $event): void | ||||
|     { | ||||
|         // loop all accounts, collect all user's rules.
 | ||||
|         /** @var Account $account */ | ||||
|         foreach ($event->piggyBank->accounts as $account) { | ||||
|             /** @var Rule $rule */ | ||||
|             foreach ($account->user->rules as $rule) { | ||||
|                 /** @var RuleAction $ruleAction */ | ||||
|                 foreach ($rule->ruleActions()->where('action_type', 'update_piggy')->get() as $ruleAction) { | ||||
|                     if ($event->oldName === $ruleAction->action_value) { | ||||
|                         $ruleAction->action_value = $event->newName; | ||||
|                         $ruleAction->save(); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public function changePiggyAmount(ChangedAmount $event): void | ||||
|     { | ||||
|         // find journal if group is present.
 | ||||
|   | ||||
| @@ -49,7 +49,7 @@ class UpdatedGroupEventHandler | ||||
|         $this->processRules($event); | ||||
|         $this->recalculateCredit($event); | ||||
|         $this->triggerWebhooks($event); | ||||
|         if ($event->amountChanged) { | ||||
|         if ($event->runRecalculations) { | ||||
|             $this->updateRunningBalance($event); | ||||
|         } | ||||
| 
 | ||||
|   | ||||
| @@ -23,6 +23,7 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Handlers\Events; | ||||
| 
 | ||||
| use Deprecated; | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Events\RequestedVersionCheckStatus; | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| @@ -42,9 +43,8 @@ class VersionCheckEventHandler | ||||
|      * Checks with GitHub to see if there is a new version. | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      * | ||||
|      * @deprecated ? | ||||
|      */ | ||||
|     #[Deprecated(message: '?')]
 | ||||
|     public function checkForUpdates(RequestedVersionCheckStatus $event): void | ||||
|     { | ||||
|         Log::debug('Now in checkForUpdates()'); | ||||
|   | ||||
| @@ -26,6 +26,7 @@ namespace FireflyIII\Handlers\Events; | ||||
| 
 | ||||
| use FireflyIII\Jobs\SendWebhookMessage; | ||||
| use FireflyIII\Models\WebhookMessage; | ||||
| use Illuminate\Support\Facades\Log; | ||||
| 
 | ||||
| /** | ||||
|  * Class WebhookEventHandler | ||||
| @@ -37,7 +38,13 @@ class WebhookEventHandler | ||||
|      */ | ||||
|     public function sendWebhookMessages(): void | ||||
|     { | ||||
|         app('log')->debug(sprintf('Now in %s', __METHOD__)); | ||||
|         Log::debug(sprintf('Now in %s', __METHOD__)); | ||||
|         if (false === config('firefly.feature_flags.webhooks') || false === config('firefly.allow_webhooks')) { | ||||
|             Log::info('Webhook event handler is disabled, do not run sendWebhookMessages().'); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // kick off the job!
 | ||||
|         $messages = WebhookMessage::where('webhook_messages.sent', false) | ||||
|             ->get(['webhook_messages.*']) | ||||
| @@ -45,14 +52,14 @@ class WebhookEventHandler | ||||
|                 static fn (WebhookMessage $message) => $message->webhookAttempts()->count() <= 2 | ||||
|             )->splice(0, 5) | ||||
|         ; | ||||
|         app('log')->debug(sprintf('Found %d webhook message(s) ready to be send.', $messages->count())); | ||||
|         Log::debug(sprintf('Found %d webhook message(s) ready to be send.', $messages->count())); | ||||
|         foreach ($messages as $message) { | ||||
|             if (false === $message->sent) { | ||||
|                 app('log')->debug(sprintf('Send message #%d', $message->id)); | ||||
|                 Log::debug(sprintf('Send message #%d', $message->id)); | ||||
|                 SendWebhookMessage::dispatch($message)->afterResponse(); | ||||
|             } | ||||
|             if (false !== $message->sent) { | ||||
|                 app('log')->debug(sprintf('Skip message #%d', $message->id)); | ||||
|                 Log::debug(sprintf('Skip message #%d', $message->id)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -434,6 +434,7 @@ class GroupCollector implements GroupCollectorInterface | ||||
| 
 | ||||
|     public function findNothing(): GroupCollectorInterface | ||||
|     { | ||||
|         Log::warning('The search engine was instructed to FIND NOTHING. This may be a bug.'); | ||||
|         $this->query->where('transaction_groups.id', -1); | ||||
| 
 | ||||
|         return $this; | ||||
| @@ -557,7 +558,6 @@ class GroupCollector implements GroupCollectorInterface | ||||
|                 $groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedJournal($augumentedJournal); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         $groups = $this->parseSums($groups); | ||||
| 
 | ||||
|         return new Collection($groups); | ||||
| @@ -1094,6 +1094,10 @@ class GroupCollector implements GroupCollectorInterface | ||||
|             ->whereNull('transaction_groups.deleted_at') | ||||
|             ->whereNull('transaction_journals.deleted_at') | ||||
|             ->whereNull('source.deleted_at') | ||||
| 
 | ||||
|             // #10507 ignore opening balance.
 | ||||
|             ->where('transaction_types.type', '!=', TransactionTypeEnum::OPENING_BALANCE->value) | ||||
| 
 | ||||
|             ->whereNotNull('transaction_groups.id') | ||||
|             ->whereNull('destination.deleted_at') | ||||
|             ->orderBy('transaction_journals.date', 'DESC') | ||||
|   | ||||
| @@ -24,6 +24,7 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Helpers\Report; | ||||
| 
 | ||||
| use Deprecated; | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Enums\AccountTypeEnum; | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| @@ -81,7 +82,7 @@ class NetWorth implements NetWorthInterface | ||||
| 
 | ||||
|         /** @var Account $account */ | ||||
|         foreach ($accounts as $account) { | ||||
|             Log::debug(sprintf('Now at account #%d ("%s")', $account->id, $account->name)); | ||||
|             //            Log::debug(sprintf('Now at account #%d ("%s")', $account->id, $account->name));
 | ||||
|             $currency                           = $this->accountRepository->getAccountCurrency($account) ?? $default; | ||||
|             $useNative                          = $convertToNative && $default->id !== $currency->id; | ||||
|             $currency                           = $useNative ? $default : $currency; | ||||
| @@ -92,12 +93,12 @@ class NetWorth implements NetWorthInterface | ||||
|                 $balance       = $balances[$account->id]['balance'] ?? '0'; | ||||
|                 $nativeBalance = $balances[$account->id]['native_balance'] ?? '0'; | ||||
|             } | ||||
|             Log::debug(sprintf('Balance is %s, native balance is %s', $balance, $nativeBalance)); | ||||
|             //            Log::debug(sprintf('Balance is %s, native balance is %s', $balance, $nativeBalance));
 | ||||
|             // always subtract virtual balance again.
 | ||||
|             $balance                            = '' !== (string) $account->virtual_balance ? bcsub($balance, (string) $account->virtual_balance) : $balance; | ||||
|             $nativeBalance                      = '' !== (string) $account->native_virtual_balance ? bcsub($nativeBalance, (string) $account->native_virtual_balance) : $nativeBalance; | ||||
|             $amountToUse                        = $useNative ? $nativeBalance : $balance; | ||||
|             Log::debug(sprintf('Will use %s %s', $currencyCode, $amountToUse)); | ||||
|             //            Log::debug(sprintf('Will use %s %s', $currencyCode, $amountToUse));
 | ||||
| 
 | ||||
|             $netWorth[$currencyCode] ??= [ | ||||
|                 'balance'                 => '0', | ||||
| @@ -134,9 +135,7 @@ class NetWorth implements NetWorthInterface | ||||
|         $this->currencyRepos->setUserGroup($this->userGroup); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @deprecated | ||||
|      */ | ||||
|     #[Deprecated]
 | ||||
|     public function sumNetWorthByCurrency(Carbon $date): array | ||||
|     { | ||||
|         /** | ||||
|   | ||||
| @@ -24,6 +24,7 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Helpers\Report; | ||||
| 
 | ||||
| use Deprecated; | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Models\UserGroup; | ||||
| use FireflyIII\User; | ||||
| @@ -53,8 +54,7 @@ interface NetWorthInterface | ||||
|      * TODO move to repository | ||||
|      * | ||||
|      * Same as above but cleaner function with less dependencies. | ||||
|      * | ||||
|      * @deprecated | ||||
|      */ | ||||
|     #[Deprecated]
 | ||||
|     public function sumNetWorthByCurrency(Carbon $date): array; | ||||
| } | ||||
|   | ||||
| @@ -88,7 +88,9 @@ class IndexController extends Controller | ||||
| 
 | ||||
|         /** @var Carbon $end */ | ||||
|         $end           = clone session('end', today(config('app.timezone'))->endOfMonth()); | ||||
|         $start->subDay(); | ||||
| 
 | ||||
|         // #10618 go to the end of the previous day.
 | ||||
|         $start->subSecond(); | ||||
| 
 | ||||
|         $ids           = $accounts->pluck('id')->toArray(); | ||||
|         Log::debug(sprintf('inactive start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s'))); | ||||
| @@ -164,8 +166,8 @@ class IndexController extends Controller | ||||
|         /** @var Carbon $end */ | ||||
|         $end           = clone session('end', today(config('app.timezone'))->endOfMonth()); | ||||
| 
 | ||||
|         // 2025-05-11 removed this so start is exactly the start of the month.
 | ||||
|         // $start->subDay();
 | ||||
|         // #10618 go to the end of the previous day.
 | ||||
|         $start->subSecond(); | ||||
| 
 | ||||
|         $ids           = $accounts->pluck('id')->toArray(); | ||||
|         Log::debug(sprintf('index start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s'))); | ||||
|   | ||||
| @@ -61,12 +61,12 @@ class ForgotPasswordController extends Controller | ||||
|      * | ||||
|      * @return Factory|RedirectResponse|View | ||||
|      */ | ||||
|     public function sendResetLinkEmail(Request $request, ?UserRepositoryInterface $repository = null) | ||||
|     public function sendResetLinkEmail(Request $request, UserRepositoryInterface $repository) | ||||
|     { | ||||
|         app('log')->info('Start of sendResetLinkEmail()'); | ||||
|         if ('web' !== config('firefly.authentication_guard')) { | ||||
|         Log::info('Start of sendResetLinkEmail()'); | ||||
|         if ('web'   !== config('firefly.authentication_guard')) { | ||||
|             $message = sprintf('Cannot reset password when authenticating over "%s".', config('firefly.authentication_guard')); | ||||
|             app('log')->error($message); | ||||
|             Log::error($message); | ||||
| 
 | ||||
|             return view('error', compact('message')); | ||||
|         } | ||||
| @@ -89,7 +89,7 @@ class ForgotPasswordController extends Controller | ||||
|         // need to show to the user. Finally, we'll send out a proper response.
 | ||||
|         $result   = $this->broker()->sendResetLink($request->only('email')); | ||||
|         if ('passwords.throttled' === $result) { | ||||
|             app('log')->error(sprintf('Cowardly refuse to send a password reset message to user #%d because the reset button has been throttled.', $user->id)); | ||||
|             Log::error(sprintf('Cowardly refuse to send a password reset message to user #%d because the reset button has been throttled.', $user->id)); | ||||
|         } | ||||
| 
 | ||||
|         // always send the same response to the user:
 | ||||
|   | ||||
| @@ -223,7 +223,7 @@ class LoginController extends Controller | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public function showLoginForm(?Request $request = null) | ||||
|     public function showLoginForm(Request $request) | ||||
|     { | ||||
|         Log::channel('audit')->info('Show login form (1.1).'); | ||||
| 
 | ||||
|   | ||||
| @@ -91,7 +91,7 @@ class IndexController extends Controller | ||||
|     public function index(?Carbon $start = null, ?Carbon $end = null) | ||||
|     { | ||||
|         $this->abRepository->cleanup(); | ||||
|         app('log')->debug(sprintf('Start of IndexController::index("%s", "%s")', $start?->format('Y-m-d'), $end?->format('Y-m-d'))); | ||||
|         Log::debug(sprintf('Start of IndexController::index("%s", "%s")', $start?->format('Y-m-d'), $end?->format('Y-m-d'))); | ||||
| 
 | ||||
|         // collect some basic vars:
 | ||||
|         $range            = app('navigation')->getViewRange(true); | ||||
| @@ -199,12 +199,12 @@ class IndexController extends Controller | ||||
|         // get all budgets, and paginate them into $budgets.
 | ||||
|         $collection = $this->repository->getActiveBudgets(); | ||||
|         $budgets    = []; | ||||
|         app('log')->debug(sprintf('7) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); | ||||
|         Log::debug(sprintf('(getAllBudgets) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); | ||||
| 
 | ||||
|         // complement budget with budget limits in range, and expenses in currency X in range.
 | ||||
|         /** @var Budget $current */ | ||||
|         foreach ($collection as $current) { | ||||
|             app('log')->debug(sprintf('Working on budget #%d ("%s")', $current->id, $current->name)); | ||||
|             Log::debug(sprintf('Working on budget #%d ("%s")', $current->id, $current->name)); | ||||
|             $array                = $current->toArray(); | ||||
|             $array['spent']       = []; | ||||
|             $array['spent_total'] = []; | ||||
| @@ -215,7 +215,7 @@ class IndexController extends Controller | ||||
| 
 | ||||
|             /** @var BudgetLimit $limit */ | ||||
|             foreach ($budgetLimits as $limit) { | ||||
|                 app('log')->debug(sprintf('Working on budget limit #%d', $limit->id)); | ||||
|                 Log::debug(sprintf('Working on budget limit #%d', $limit->id)); | ||||
|                 $currency            = $limit->transactionCurrency ?? $defaultCurrency; | ||||
|                 $amount              = app('steam')->bcround($limit->amount, $currency->decimal_places); | ||||
|                 $array['budgeted'][] = [ | ||||
| @@ -225,14 +225,17 @@ class IndexController extends Controller | ||||
|                     'start_date'              => $limit->start_date->isoFormat($this->monthAndDayFormat), | ||||
|                     'end_date'                => $limit->end_date->isoFormat($this->monthAndDayFormat), | ||||
|                     'in_range'                => $limit->start_date->isSameDay($start) && $limit->end_date->isSameDay($end), | ||||
|                     'total_days'              => $limit->start_date->diffInDays($limit->end_date) + 1, | ||||
|                     'currency_id'             => $currency->id, | ||||
|                     'currency_symbol'         => $currency->symbol, | ||||
|                     'currency_name'           => $currency->name, | ||||
|                     'currency_decimal_places' => $currency->decimal_places, | ||||
|                 ]; | ||||
|                 app('log')->debug(sprintf('The amount budgeted for budget limit #%d is %s %s', $limit->id, $currency->code, $amount)); | ||||
|                 Log::debug(sprintf('The amount budgeted for budget limit #%d is %s %s', $limit->id, $currency->code, $amount)); | ||||
|             } | ||||
| 
 | ||||
|             // #10463
 | ||||
| 
 | ||||
|             /** @var TransactionCurrency $currency */ | ||||
|             foreach ($currencies as $currency) { | ||||
|                 $spentArr = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$current]), $currency, false); | ||||
| @@ -259,6 +262,8 @@ class IndexController extends Controller | ||||
| 
 | ||||
|         /** @var array $budget */ | ||||
|         foreach ($budgets as $budget) { | ||||
|             Log::debug(sprintf('Now working on budget #%d ("%s")', $budget['id'], $budget['name'])); | ||||
| 
 | ||||
|             /** @var array $spent */ | ||||
|             foreach ($budget['spent'] as $spent) { | ||||
|                 $currencyId                           = $spent['currency_id']; | ||||
|   | ||||
| @@ -23,8 +23,6 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Http\Controllers; | ||||
| 
 | ||||
| use function Safe\realpath; | ||||
| use function Safe\ini_get; | ||||
| use FireflyIII\Models\TransactionCurrency; | ||||
| use FireflyIII\Support\Facades\Amount; | ||||
| use FireflyIII\Support\Facades\Steam; | ||||
| @@ -38,6 +36,9 @@ use Illuminate\Support\Facades\Config; | ||||
| use Illuminate\Support\Facades\View; | ||||
| use Illuminate\Support\Facades\Route; | ||||
| 
 | ||||
| use function Safe\realpath; | ||||
| use function Safe\ini_get; | ||||
| 
 | ||||
| /** | ||||
|  * Class Controller. | ||||
|  * | ||||
| @@ -78,12 +79,12 @@ abstract class Controller extends BaseController | ||||
|         View::share('featuringWebhooks', true === config('firefly.feature_flags.webhooks') && true === config('firefly.allow_webhooks')); | ||||
| 
 | ||||
|         // share custom auth guard info.
 | ||||
|         $authGuard = config('firefly.authentication_guard'); | ||||
|         $logoutUrl = config('firefly.custom_logout_url'); | ||||
|         $authGuard        = config('firefly.authentication_guard'); | ||||
|         $logoutUrl        = config('firefly.custom_logout_url'); | ||||
| 
 | ||||
|         // overrule v2 layout back to v1.
 | ||||
|         if ('true' === request()->get('force_default_layout') && 'v2' === config('view.layout')) { | ||||
|             //config('view.layout','v1');
 | ||||
|             // config('view.layout','v1');
 | ||||
|             Config::set('view.layout', 'v1'); | ||||
|             View::getFinder()->setPaths([realpath(base_path('resources/views'))]); // @phpstan-ignore-line
 | ||||
|         } | ||||
| @@ -92,15 +93,15 @@ abstract class Controller extends BaseController | ||||
|         View::share('logoutUrl', $logoutUrl); | ||||
| 
 | ||||
|         // upload size
 | ||||
|         $maxFileSize = Steam::phpBytes((string) ini_get('upload_max_filesize')); | ||||
|         $maxPostSize = Steam::phpBytes((string) ini_get('post_max_size')); | ||||
|         $uploadSize  = min($maxFileSize, $maxPostSize); | ||||
|         $maxFileSize      = Steam::phpBytes((string) ini_get('upload_max_filesize')); | ||||
|         $maxPostSize      = Steam::phpBytes((string) ini_get('post_max_size')); | ||||
|         $uploadSize       = min($maxFileSize, $maxPostSize); | ||||
|         View::share('uploadSize', $uploadSize); | ||||
| 
 | ||||
|         // share is alpha, is beta
 | ||||
|         $isAlpha   = false; | ||||
|         $isBeta    = false; | ||||
|         $isDevelop = false; | ||||
|         $isAlpha          = false; | ||||
|         $isBeta           = false; | ||||
|         $isDevelop        = false; | ||||
|         if (str_contains((string) config('firefly.version'), 'alpha')) { | ||||
|             $isAlpha = true; | ||||
|         } | ||||
| @@ -118,7 +119,7 @@ abstract class Controller extends BaseController | ||||
| 
 | ||||
|         $this->middleware( | ||||
|             function ($request, $next): mixed { | ||||
|                 $locale = Steam::getLocale(); | ||||
|                 $locale                  = Steam::getLocale(); | ||||
|                 // translations for specific strings:
 | ||||
|                 $this->monthFormat       = (string) trans('config.month_js', [], $locale); | ||||
|                 $this->monthAndDayFormat = (string) trans('config.month_and_day_js', [], $locale); | ||||
|   | ||||
| @@ -23,6 +23,7 @@ declare(strict_types=1); | ||||
| 
 | ||||
| namespace FireflyIII\Http\Controllers\Json; | ||||
| 
 | ||||
| use Deprecated; | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Enums\AccountTypeEnum; | ||||
| use FireflyIII\Enums\TransactionTypeEnum; | ||||
| @@ -46,9 +47,8 @@ class BoxController extends Controller | ||||
| 
 | ||||
|     /** | ||||
|      * Deprecated method, no longer in use. | ||||
|      * | ||||
|      * @deprecated | ||||
|      */ | ||||
|     #[Deprecated]
 | ||||
|     public function available(): JsonResponse | ||||
|     { | ||||
|         return response()->json([]); | ||||
|   | ||||
| @@ -107,7 +107,7 @@ class RecurrenceController extends Controller | ||||
|             $repetitionMoment = str_ireplace('ndom,', '', $request->get('type')); | ||||
|         } | ||||
|         if ('yearly' === $repetitionType) { | ||||
|             $repetitionMoment = explode(',', (string) $request->get('type'))[1] ?? '2018-01-01'; | ||||
|             $repetitionMoment = explode(',', (string) $request->get('type'))[1] ?? '2025-01-01'; | ||||
|         } | ||||
|         $actualStart->startOfDay(); | ||||
|         $repetition                    = new RecurrenceRepetition(); | ||||
|   | ||||
| @@ -75,13 +75,22 @@ class AmountController extends Controller | ||||
|         $totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank); | ||||
|         foreach ($piggyBank->accounts as $account) { | ||||
|             $leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date); | ||||
|             $savedSoFar    = $this->piggyRepos->getCurrentAmount($piggyBank, $account); | ||||
|             $leftToSave    = bcsub($piggyBank->target_amount, $savedSoFar); | ||||
|             $leftToSave    = bcsub($piggyBank->target_amount, $totalSaved); | ||||
|             $maxAmount     = 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave); | ||||
| 
 | ||||
|             Log::debug(sprintf( | ||||
|                 'Account "%s", left on account "%s", saved so far "%s", left to save "%s", max amount "%s".', | ||||
|                 $account->name, | ||||
|                 $leftOnAccount, | ||||
|                 $totalSaved, | ||||
|                 $leftToSave, | ||||
|                 $maxAmount, | ||||
|             )); | ||||
| 
 | ||||
|             $accounts[]    = [ | ||||
|                 'account'         => $account, | ||||
|                 'left_on_account' => $leftOnAccount, | ||||
|                 'saved_so_far'    => $savedSoFar, | ||||
|                 'total_saved'     => $totalSaved, | ||||
|                 'left_to_save'    => $leftToSave, | ||||
|                 'max_amount'      => $maxAmount, | ||||
|             ]; | ||||
| @@ -100,18 +109,18 @@ class AmountController extends Controller | ||||
|     public function addMobile(PiggyBank $piggyBank) | ||||
|     { | ||||
|         /** @var Carbon $date */ | ||||
|         $date     = session('end', today(config('app.timezone'))); | ||||
|         $accounts = []; | ||||
|         $total    = '0'; | ||||
|         $date       = session('end', today(config('app.timezone'))); | ||||
|         $accounts   = []; | ||||
|         $total      = '0'; | ||||
|         $totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank); | ||||
|         foreach ($piggyBank->accounts as $account) { | ||||
|             $leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date); | ||||
|             $savedSoFar    = $this->piggyRepos->getCurrentAmount($piggyBank, $account); | ||||
|             $leftToSave    = bcsub($piggyBank->target_amount, $savedSoFar); | ||||
|             $leftToSave    = bcsub($piggyBank->target_amount, $totalSaved); | ||||
|             $maxAmount     = 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave); | ||||
|             $accounts[]    = [ | ||||
|                 'account'         => $account, | ||||
|                 'left_on_account' => $leftOnAccount, | ||||
|                 'saved_so_far'    => $savedSoFar, | ||||
|                 'total_saved'     => $totalSaved, | ||||
|                 'left_to_save'    => $leftToSave, | ||||
|                 'max_amount'      => $maxAmount, | ||||
|             ]; | ||||
|   | ||||
| @@ -63,6 +63,14 @@ class EditController extends Controller | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function resetHistory(PiggyBank $piggyBank): RedirectResponse | ||||
|     { | ||||
|         $this->piggyRepos->resetHistory($piggyBank); | ||||
|         session()->flash('success', (string) trans('firefly.piggy_history_reset')); | ||||
| 
 | ||||
|         return redirect(route('piggy-banks.show', [$piggyBank->id])); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Edit a piggy bank. | ||||
|      * | ||||
|   | ||||
| @@ -34,6 +34,7 @@ use FireflyIII\TransactionRules\Engine\RuleEngineInterface; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Contracts\View\Factory; | ||||
| use Illuminate\Http\RedirectResponse; | ||||
| use Illuminate\Support\Collection; | ||||
| use Illuminate\View\View; | ||||
| 
 | ||||
| /** | ||||
| @@ -75,7 +76,6 @@ class ExecutionController extends Controller | ||||
|         $accounts      = implode(',', $request->get('accounts')); | ||||
|         $startDate     = new Carbon($request->get('start')); | ||||
|         $endDate       = new Carbon($request->get('end')); | ||||
|         $rules         = $this->ruleGroupRepository->getActiveRules($ruleGroup); | ||||
|         // create new rule engine:
 | ||||
|         $newRuleEngine = app(RuleEngineInterface::class); | ||||
|         $newRuleEngine->setUser($user); | ||||
| @@ -86,7 +86,9 @@ class ExecutionController extends Controller | ||||
|         $newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]); | ||||
| 
 | ||||
|         // set rules:
 | ||||
|         $newRuleEngine->setRules($rules); | ||||
|         // #10427, file rule group and not the set of rules.
 | ||||
|         $collection    = new Collection([$ruleGroup]); | ||||
|         $newRuleEngine->setRuleGroups($collection); | ||||
|         $newRuleEngine->fire(); | ||||
| 
 | ||||
|         // Tell the user that the job is queued
 | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user