mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-11-03 20:55:05 +00:00 
			
		
		
		
	Compare commits
	
		
			257 Commits
		
	
	
		
			develop-20
			...
			develop-20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f909f1d9ff | ||
| 
						 | 
					55018ca046 | ||
| 
						 | 
					19c746a865 | ||
| 
						 | 
					503d2aa786 | ||
| 
						 | 
					70d83ab501 | ||
| 
						 | 
					edab602bb7 | ||
| 
						 | 
					f9bcc4b1fa | ||
| 
						 | 
					f3fe86167c | ||
| 
						 | 
					2189fb46a2 | ||
| 
						 | 
					7ff4178c8b | ||
| 
						 | 
					fffd695ef8 | ||
| 
						 | 
					ee592de035 | ||
| 
						 | 
					7394e50ae2 | ||
| 
						 | 
					f42fcff04a | ||
| 
						 | 
					4eb3ce7c14 | ||
| 
						 | 
					a977c567ce | ||
| 
						 | 
					785bd7e905 | ||
| 
						 | 
					df19f699d4 | ||
| 
						 | 
					5e6e932e7e | ||
| 
						 | 
					5bc397f01a | ||
| 
						 | 
					42209e367f | ||
| 
						 | 
					d53b1670d3 | ||
| 
						 | 
					a6d450ba18 | ||
| 
						 | 
					e8c1a95128 | ||
| 
						 | 
					edb201f210 | ||
| 
						 | 
					fe57367a8c | ||
| 
						 | 
					134194a95b | ||
| 
						 | 
					41c0e6fe2d | ||
| 
						 | 
					c07914e733 | ||
| 
						 | 
					52e2302f4f | ||
| 
						 | 
					0a6b34b4f2 | ||
| 
						 | 
					1e06b4dd0b | ||
| 
						 | 
					5701f95e0b | ||
| 
						 | 
					60d3572d37 | ||
| 
						 | 
					ffa6e6a571 | ||
| 
						 | 
					d6453cd735 | ||
| 
						 | 
					fd79f9df44 | ||
| 
						 | 
					4587340293 | ||
| 
						 | 
					90bfdc7573 | ||
| 
						 | 
					eca12f661f | ||
| 
						 | 
					f85878b843 | ||
| 
						 | 
					6499b5eaab | ||
| 
						 | 
					7e4fece63d | ||
| 
						 | 
					512eddf8be | ||
| 
						 | 
					f0fa93a811 | ||
| 
						 | 
					3c8de21709 | ||
| 
						 | 
					81173e8340 | ||
| 
						 | 
					35a8fa5f02 | ||
| 
						 | 
					443036936d | ||
| 
						 | 
					ac88007593 | ||
| 
						 | 
					2297589dca | ||
| 
						 | 
					6ada5fa560 | ||
| 
						 | 
					8f6eefb5e7 | ||
| 
						 | 
					b36a50381b | ||
| 
						 | 
					51f84b3060 | ||
| 
						 | 
					72132a19b0 | ||
| 
						 | 
					065d165211 | ||
| 
						 | 
					cabedf39b2 | ||
| 
						 | 
					5d3806fcd4 | ||
| 
						 | 
					01695b3342 | ||
| 
						 | 
					71fb5fe077 | ||
| 
						 | 
					3bec106840 | ||
| 
						 | 
					fb01c36be1 | ||
| 
						 | 
					26d851e69e | ||
| 
						 | 
					28c18c046b | ||
| 
						 | 
					318cef7e3b | ||
| 
						 | 
					e8dc8f25be | ||
| 
						 | 
					10ccc30240 | ||
| 
						 | 
					5adc877d5e | ||
| 
						 | 
					30923afb2b | ||
| 
						 | 
					4eb6813b43 | ||
| 
						 | 
					7521a31619 | ||
| 
						 | 
					fc05beb452 | ||
| 
						 | 
					1103428a83 | ||
| 
						 | 
					d06d521bf0 | ||
| 
						 | 
					8f64f1c0eb | ||
| 
						 | 
					d11c232171 | ||
| 
						 | 
					93c73248de | ||
| 
						 | 
					5bed081ab9 | ||
| 
						 | 
					c5188c503e | ||
| 
						 | 
					98ffcac7b6 | ||
| 
						 | 
					df1e81d611 | ||
| 
						 | 
					9711170b08 | ||
| 
						 | 
					e43264bdce | ||
| 
						 | 
					e0643bed7a | ||
| 
						 | 
					7f0eb3b064 | ||
| 
						 | 
					f38e510526 | ||
| 
						 | 
					25f99b23b2 | ||
| 
						 | 
					44281fc8a0 | ||
| 
						 | 
					eed3902cb7 | ||
| 
						 | 
					94a3bb0443 | ||
| 
						 | 
					8dcc36880e | ||
| 
						 | 
					695bb31894 | ||
| 
						 | 
					f8ded66869 | ||
| 
						 | 
					8e4bdbc584 | ||
| 
						 | 
					f7b14b01bc | ||
| 
						 | 
					705b9bf0f2 | ||
| 
						 | 
					f0226dbc54 | ||
| 
						 | 
					1b1dfb0d7b | ||
| 
						 | 
					8ed5092a76 | ||
| 
						 | 
					d609821be6 | ||
| 
						 | 
					cd0201074c | ||
| 
						 | 
					1d8feec7bc | ||
| 
						 | 
					d941472c84 | ||
| 
						 | 
					674a118fac | ||
| 
						 | 
					1334d793f6 | ||
| 
						 | 
					60354c0202 | ||
| 
						 | 
					22081d3f0a | ||
| 
						 | 
					4b3f8fc78d | ||
| 
						 | 
					4bd1aab86d | ||
| 
						 | 
					60362cb60c | ||
| 
						 | 
					27f740bf98 | ||
| 
						 | 
					5e15747a5b | ||
| 
						 | 
					8a6eaad2bb | ||
| 
						 | 
					5ab52d9f66 | ||
| 
						 | 
					21a327bf08 | ||
| 
						 | 
					15dd175394 | ||
| 
						 | 
					3f35305beb | ||
| 
						 | 
					768d8b1515 | ||
| 
						 | 
					1c19428a12 | ||
| 
						 | 
					c204533195 | ||
| 
						 | 
					6d89485792 | ||
| 
						 | 
					949d818bad | ||
| 
						 | 
					a12e200a0a | ||
| 
						 | 
					b4039b1f13 | ||
| 
						 | 
					32921e15b1 | ||
| 
						 | 
					4f7cc7d53b | ||
| 
						 | 
					0986bfbc34 | ||
| 
						 | 
					663202bfc6 | ||
| 
						 | 
					6f63ddf5b0 | ||
| 
						 | 
					a9805b144a | ||
| 
						 | 
					e1b8b9b3ae | ||
| 
						 | 
					d57327fd11 | ||
| 
						 | 
					15ac69bfad | ||
| 
						 | 
					a5bd28f8d4 | ||
| 
						 | 
					b2516ca1b4 | ||
| 
						 | 
					053b46ae63 | ||
| 
						 | 
					6e836aceec | ||
| 
						 | 
					0e8bcd2e79 | ||
| 
						 | 
					bd1f8b2497 | ||
| 
						 | 
					19dfcf7139 | ||
| 
						 | 
					ef7a3287bb | ||
| 
						 | 
					2900049498 | ||
| 
						 | 
					04d1e8fd59 | ||
| 
						 | 
					9d2f57e40a | ||
| 
						 | 
					ae366341cc | ||
| 
						 | 
					3766128cb8 | ||
| 
						 | 
					950c60d55c | ||
| 
						 | 
					4b2807de48 | ||
| 
						 | 
					649736cb31 | ||
| 
						 | 
					6a121a8a78 | ||
| 
						 | 
					f69b9ac9da | ||
| 
						 | 
					23d70a2fac | ||
| 
						 | 
					d178ff9de0 | ||
| 
						 | 
					3ecad3457f | ||
| 
						 | 
					fa6c621968 | ||
| 
						 | 
					df863b6cff | ||
| 
						 | 
					9316ff3e51 | ||
| 
						 | 
					bfd91f8ee6 | ||
| 
						 | 
					13e5d25cfe | ||
| 
						 | 
					b13030420b | ||
| 
						 | 
					44d1e8181c | ||
| 
						 | 
					63b34c1853 | ||
| 
						 | 
					facd0144cb | ||
| 
						 | 
					115e3435af | ||
| 
						 | 
					d44cd50768 | ||
| 
						 | 
					1afcaea4c6 | ||
| 
						 | 
					2bd1b37717 | ||
| 
						 | 
					2d37177316 | ||
| 
						 | 
					abb25e2015 | ||
| 
						 | 
					d08d075e30 | ||
| 
						 | 
					b4c67c02a7 | ||
| 
						 | 
					04fb6a953e | ||
| 
						 | 
					5dce0bec8e | ||
| 
						 | 
					481bb3fb0a | ||
| 
						 | 
					b6960dc299 | ||
| 
						 | 
					73104aae1f | ||
| 
						 | 
					10a284848b | ||
| 
						 | 
					fd6560bdd0 | ||
| 
						 | 
					0810f617c7 | ||
| 
						 | 
					c3ffd39450 | ||
| 
						 | 
					0f69e0d672 | ||
| 
						 | 
					1aa8ebe57f | ||
| 
						 | 
					23178614d5 | ||
| 
						 | 
					d2b6829574 | ||
| 
						 | 
					5602715c96 | ||
| 
						 | 
					54d0433dd4 | ||
| 
						 | 
					f4bc313d0b | ||
| 
						 | 
					5617de3a79 | ||
| 
						 | 
					2d62f0ff06 | ||
| 
						 | 
					1c79f6b1b6 | ||
| 
						 | 
					bf01153c6b | ||
| 
						 | 
					c43b37baef | ||
| 
						 | 
					d4942efd8e | ||
| 
						 | 
					ea9f635b1a | ||
| 
						 | 
					7eaa0e16b3 | ||
| 
						 | 
					1b97d8fd48 | ||
| 
						 | 
					89a29b9b10 | ||
| 
						 | 
					2baac1a6d7 | ||
| 
						 | 
					cd296aa9ac | ||
| 
						 | 
					959d168352 | ||
| 
						 | 
					6cd60951ba | ||
| 
						 | 
					3898c0c0ef | ||
| 
						 | 
					fe4d139817 | ||
| 
						 | 
					d95f3ca59f | ||
| 
						 | 
					7f6c03ce17 | ||
| 
						 | 
					394d0eabef | ||
| 
						 | 
					a8ae496fda | ||
| 
						 | 
					1787f4421b | ||
| 
						 | 
					36351a5dd9 | ||
| 
						 | 
					d009ce31ca | ||
| 
						 | 
					44eafeeae5 | ||
| 
						 | 
					21165eb3e0 | ||
| 
						 | 
					2ef3a33fbf | ||
| 
						 | 
					f74be0402f | ||
| 
						 | 
					a60cb366b2 | ||
| 
						 | 
					58e2ef187d | ||
| 
						 | 
					ae80fd8578 | ||
| 
						 | 
					c17f2efca6 | ||
| 
						 | 
					4a185639b9 | ||
| 
						 | 
					dae7e7d507 | ||
| 
						 | 
					e33e3cc40f | ||
| 
						 | 
					36ec1daf3a | ||
| 
						 | 
					50aff9cfb6 | ||
| 
						 | 
					058a0f9fb2 | ||
| 
						 | 
					0c955efa8b | ||
| 
						 | 
					a62916a63d | ||
| 
						 | 
					af7a4b5d3d | ||
| 
						 | 
					2ae3929dd6 | ||
| 
						 | 
					ebd30f4861 | ||
| 
						 | 
					afc9ea08f3 | ||
| 
						 | 
					78f9f7e2dd | ||
| 
						 | 
					c44b827922 | ||
| 
						 | 
					fb30f7ec8f | ||
| 
						 | 
					e878d5ce07 | ||
| 
						 | 
					f727a38b69 | ||
| 
						 | 
					c11a5384da | ||
| 
						 | 
					ed92cbd4b8 | ||
| 
						 | 
					a9ea32772f | ||
| 
						 | 
					92f5cca65b | ||
| 
						 | 
					57b064f590 | ||
| 
						 | 
					9729434926 | ||
| 
						 | 
					9d9dffee74 | ||
| 
						 | 
					b3f374f4ea | ||
| 
						 | 
					50e07d422f | ||
| 
						 | 
					631ed4956a | ||
| 
						 | 
					0eca1c8d03 | ||
| 
						 | 
					e38e4574ad | ||
| 
						 | 
					be2d3f3637 | ||
| 
						 | 
					0e3d779e24 | ||
| 
						 | 
					4d25336d87 | ||
| 
						 | 
					74f76a2835 | ||
| 
						 | 
					84560a6f44 | ||
| 
						 | 
					6fde693e7a | ||
| 
						 | 
					2e46d9ba33 | ||
| 
						 | 
					e36f8deb08 | ||
| 
						 | 
					1631b422f1 | 
@@ -61,6 +61,7 @@ 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.
 | 
			
		||||
 | 
			
		||||
        // complex rules
 | 
			
		||||
        'array_syntax'                  => ['syntax' => 'short'],
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										104
									
								
								.ci/php-cs-fixer/composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										104
									
								
								.ci/php-cs-fixer/composer.lock
									
									
									
										generated
									
									
									
								
							@@ -406,16 +406,16 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "friendsofphp/php-cs-fixer",
 | 
			
		||||
            "version": "v3.66.0",
 | 
			
		||||
            "version": "v3.68.5",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
 | 
			
		||||
                "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6"
 | 
			
		||||
                "reference": "7bedb718b633355272428c60736dc97fb96daf27"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/5f5f2a142ff36b93c41885bca29cc5f861c013e6",
 | 
			
		||||
                "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6",
 | 
			
		||||
                "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7bedb718b633355272428c60736dc97fb96daf27",
 | 
			
		||||
                "reference": "7bedb718b633355272428c60736dc97fb96daf27",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -432,17 +432,17 @@
 | 
			
		||||
                "react/promise": "^2.0 || ^3.0",
 | 
			
		||||
                "react/socket": "^1.0",
 | 
			
		||||
                "react/stream": "^1.0",
 | 
			
		||||
                "sebastian/diff": "^4.0 || ^5.0 || ^6.0",
 | 
			
		||||
                "symfony/console": "^5.4 || ^6.0 || ^7.0",
 | 
			
		||||
                "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0",
 | 
			
		||||
                "symfony/filesystem": "^5.4 || ^6.0 || ^7.0",
 | 
			
		||||
                "symfony/finder": "^5.4 || ^6.0 || ^7.0",
 | 
			
		||||
                "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0",
 | 
			
		||||
                "symfony/polyfill-mbstring": "^1.28",
 | 
			
		||||
                "symfony/polyfill-php80": "^1.28",
 | 
			
		||||
                "symfony/polyfill-php81": "^1.28",
 | 
			
		||||
                "symfony/process": "^5.4 || ^6.0 || ^7.0 <7.2",
 | 
			
		||||
                "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0"
 | 
			
		||||
                "sebastian/diff": "^4.0 || ^5.1 || ^6.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"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "facile-it/paraunit": "^1.3.1 || ^2.4",
 | 
			
		||||
@@ -454,9 +454,9 @@
 | 
			
		||||
                "php-cs-fixer/accessible-object": "^1.1",
 | 
			
		||||
                "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5",
 | 
			
		||||
                "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5",
 | 
			
		||||
                "phpunit/phpunit": "^9.6.21 || ^10.5.38 || ^11.4.3",
 | 
			
		||||
                "symfony/var-dumper": "^5.4.47 || ^6.4.15 || ^7.1.8",
 | 
			
		||||
                "symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.1.6"
 | 
			
		||||
                "phpunit/phpunit": "^9.6.22 || ^10.5.40 || ^11.5.2",
 | 
			
		||||
                "symfony/var-dumper": "^5.4.48 || ^6.4.15 || ^7.2.0",
 | 
			
		||||
                "symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.2.0"
 | 
			
		||||
            },
 | 
			
		||||
            "suggest": {
 | 
			
		||||
                "ext-dom": "For handling output formats in XML",
 | 
			
		||||
@@ -497,7 +497,7 @@
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
 | 
			
		||||
                "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.66.0"
 | 
			
		||||
                "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.5"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
@@ -505,7 +505,7 @@
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2024-12-29T13:46:23+00:00"
 | 
			
		||||
            "time": "2025-01-30T17:00:50+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "psr/container",
 | 
			
		||||
@@ -734,33 +734,33 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "react/child-process",
 | 
			
		||||
            "version": "v0.6.5",
 | 
			
		||||
            "version": "v0.6.6",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/reactphp/child-process.git",
 | 
			
		||||
                "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43"
 | 
			
		||||
                "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/reactphp/child-process/zipball/e71eb1aa55f057c7a4a0d08d06b0b0a484bead43",
 | 
			
		||||
                "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43",
 | 
			
		||||
                "url": "https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159",
 | 
			
		||||
                "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
 | 
			
		||||
                "php": ">=5.3.0",
 | 
			
		||||
                "react/event-loop": "^1.2",
 | 
			
		||||
                "react/stream": "^1.2"
 | 
			
		||||
                "react/stream": "^1.4"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
 | 
			
		||||
                "react/socket": "^1.8",
 | 
			
		||||
                "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
 | 
			
		||||
                "react/socket": "^1.16",
 | 
			
		||||
                "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "React\\ChildProcess\\": "src"
 | 
			
		||||
                    "React\\ChildProcess\\": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
@@ -797,19 +797,15 @@
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "issues": "https://github.com/reactphp/child-process/issues",
 | 
			
		||||
                "source": "https://github.com/reactphp/child-process/tree/v0.6.5"
 | 
			
		||||
                "source": "https://github.com/reactphp/child-process/tree/v0.6.6"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/WyriHaximus",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/clue",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                    "url": "https://opencollective.com/reactphp",
 | 
			
		||||
                    "type": "open_collective"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2022-09-16T13:41:56+00:00"
 | 
			
		||||
            "time": "2025-01-01T16:37:48+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "react/dns",
 | 
			
		||||
@@ -1641,16 +1637,16 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/finder",
 | 
			
		||||
            "version": "v7.2.0",
 | 
			
		||||
            "version": "v7.2.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/finder.git",
 | 
			
		||||
                "reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49"
 | 
			
		||||
                "reference": "87a71856f2f56e4100373e92529eed3171695cfb"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/finder/zipball/6de263e5868b9a137602dd1e33e4d48bfae99c49",
 | 
			
		||||
                "reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb",
 | 
			
		||||
                "reference": "87a71856f2f56e4100373e92529eed3171695cfb",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -1685,7 +1681,7 @@
 | 
			
		||||
            "description": "Finds files and directories via an intuitive fluent interface",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "support": {
 | 
			
		||||
                "source": "https://github.com/symfony/finder/tree/v7.2.0"
 | 
			
		||||
                "source": "https://github.com/symfony/finder/tree/v7.2.2"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
@@ -1701,7 +1697,7 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2024-10-23T06:56:12+00:00"
 | 
			
		||||
            "time": "2024-12-30T19:00:17+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/options-resolver",
 | 
			
		||||
@@ -2246,16 +2242,16 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/process",
 | 
			
		||||
            "version": "v7.1.8",
 | 
			
		||||
            "version": "v7.2.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/process.git",
 | 
			
		||||
                "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892"
 | 
			
		||||
                "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/process/zipball/42783370fda6e538771f7c7a36e9fa2ee3a84892",
 | 
			
		||||
                "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e",
 | 
			
		||||
                "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -2287,7 +2283,7 @@
 | 
			
		||||
            "description": "Executes commands in sub-processes",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "support": {
 | 
			
		||||
                "source": "https://github.com/symfony/process/tree/v7.1.8"
 | 
			
		||||
                "source": "https://github.com/symfony/process/tree/v7.2.0"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
@@ -2303,7 +2299,7 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2024-11-06T14:23:19+00:00"
 | 
			
		||||
            "time": "2024-11-06T14:24:19+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/service-contracts",
 | 
			
		||||
@@ -2390,16 +2386,16 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/stopwatch",
 | 
			
		||||
            "version": "v7.2.0",
 | 
			
		||||
            "version": "v7.2.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/stopwatch.git",
 | 
			
		||||
                "reference": "696f418b0d722a4225e1c3d95489d262971ca924"
 | 
			
		||||
                "reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/stopwatch/zipball/696f418b0d722a4225e1c3d95489d262971ca924",
 | 
			
		||||
                "reference": "696f418b0d722a4225e1c3d95489d262971ca924",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/stopwatch/zipball/e46690d5b9d7164a6d061cab1e8d46141b9f49df",
 | 
			
		||||
                "reference": "e46690d5b9d7164a6d061cab1e8d46141b9f49df",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -2432,7 +2428,7 @@
 | 
			
		||||
            "description": "Provides a way to profile code",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "support": {
 | 
			
		||||
                "source": "https://github.com/symfony/stopwatch/tree/v7.2.0"
 | 
			
		||||
                "source": "https://github.com/symfony/stopwatch/tree/v7.2.2"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
@@ -2448,7 +2444,7 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2024-09-25T14:21:43+00:00"
 | 
			
		||||
            "time": "2024-12-18T14:28:33+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/string",
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ composer update --quiet
 | 
			
		||||
rm -f .php-cs-fixer.cache
 | 
			
		||||
PHP_CS_FIXER_IGNORE_ENV=true ./vendor/bin/php-cs-fixer fix \
 | 
			
		||||
    --config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php \
 | 
			
		||||
    --format=txt \
 | 
			
		||||
    --format=txt -v \
 | 
			
		||||
    --allow-risky=yes
 | 
			
		||||
 | 
			
		||||
EXIT_CODE=$?
 | 
			
		||||
 
 | 
			
		||||
@@ -1,61 +1,36 @@
 | 
			
		||||
parameters:
 | 
			
		||||
  scanFiles:
 | 
			
		||||
    - ../_ide_helper_models.php
 | 
			
		||||
  universalObjectCratesClasses:
 | 
			
		||||
    - Illuminate\Database\Eloquent\Model
 | 
			
		||||
  # TODO: slowly remove these parameters and fix the issues found.
 | 
			
		||||
  reportUnmatchedIgnoredErrors: false
 | 
			
		||||
  ignoreErrors:
 | 
			
		||||
  # TODO: slowly remove these exceptions and fix the issues found.
 | 
			
		||||
    - '#Dynamic call to static method#' # all the Laravel ORM things depend on this.
 | 
			
		||||
    - '#Control structures using switch should not be used.#' # switch is fine in some cases.
 | 
			
		||||
    - '#with no value type specified in iterable type array#' # remove this rule when all other issues are solved.
 | 
			
		||||
    - '#has no value type specified in iterable type array#' # remove this rule when all other issues are solved.
 | 
			
		||||
    - '#is not allowed to extend#'
 | 
			
		||||
    - '#does not specify its types#'
 | 
			
		||||
    - '#switch is forbidden to use#'
 | 
			
		||||
    - '#is neither abstract nor final#'
 | 
			
		||||
    - '#on left side of \?\?\= always exists and is not nullable#'
 | 
			
		||||
    - '#has a nullable return type declaration#' # perhaps throw errors instead?
 | 
			
		||||
    - '#with a nullable type declaration#' # decide what action should be if param is null.
 | 
			
		||||
    - '#with null as default value#'
 | 
			
		||||
    -
 | 
			
		||||
        message: '#Constructor in [a-zA-Z0-9\\_]+ has parameter \$[a-zA-Z0-9\\_]+ with default value#'
 | 
			
		||||
        paths:
 | 
			
		||||
            - ../app/Exceptions/IntervalException.php
 | 
			
		||||
            - ../app/Support/Navigation.php
 | 
			
		||||
    -
 | 
			
		||||
        message: '#but containers should not be injected#'
 | 
			
		||||
        paths:
 | 
			
		||||
            - ../app/Support/Authentication/RemoteUserGuard.php
 | 
			
		||||
    -
 | 
			
		||||
        message: '#Function compact\(\) should not be used#' # too useful in template rendering.
 | 
			
		||||
        paths:
 | 
			
		||||
            - ../app/Generator/Report/Account/MonthReportGenerator.php
 | 
			
		||||
            - ../app/Generator/Report/Audit/MonthReportGenerator.php
 | 
			
		||||
            - ../app/Generator/Report/Budget/MonthReportGenerator.php
 | 
			
		||||
            - ../app/Generator/Report/Category/MonthReportGenerator.php
 | 
			
		||||
            - ../app/Generator/Report/Standard/MonthReportGenerator.php
 | 
			
		||||
            - ../app/Generator/Report/Standard/MultiYearReportGenerator.php
 | 
			
		||||
            - ../app/Generator/Report/Standard/YearReportGenerator.php
 | 
			
		||||
            - ../app/Generator/Report/Tag/MonthReportGenerator.php
 | 
			
		||||
            - ../app/Http/Controllers/Account/*.php
 | 
			
		||||
            - ../app/Http/Controllers/Admin/*.php
 | 
			
		||||
            - ../app/Http/Controllers/*.php
 | 
			
		||||
            - ../app/Support/ExpandedForm.php
 | 
			
		||||
            - ../app/Support/Form/AccountForm.php
 | 
			
		||||
            - ../app/Support/Form/CurrencyForm.php
 | 
			
		||||
            - ../app/Support/Form/FormSupport.php
 | 
			
		||||
    -
 | 
			
		||||
        message: '#Either catch a more specific exception#'
 | 
			
		||||
        paths:
 | 
			
		||||
            - ../app/Support/Form/FormSupport.php
 | 
			
		||||
    - ../_ide_helper
 | 
			
		||||
  paths:
 | 
			
		||||
    - ../app
 | 
			
		||||
    - ../database
 | 
			
		||||
    - ../routes
 | 
			
		||||
    - ../config
 | 
			
		||||
    - ../bootstrap/app.php
 | 
			
		||||
  universalObjectCratesClasses:
 | 
			
		||||
    - Illuminate\Database\Eloquent\Model
 | 
			
		||||
  # TODO: slowly remove these parameters and fix the issues found.
 | 
			
		||||
  reportUnmatchedIgnoredErrors: true
 | 
			
		||||
  ignoreErrors:
 | 
			
		||||
  # TODO: slowly remove these exceptions and fix the issues found.
 | 
			
		||||
    - '#Dynamic call to static method#' # all the Laravel ORM things depend on this.
 | 
			
		||||
    - identifier: varTag.nativeType
 | 
			
		||||
    - identifier: varTag.type
 | 
			
		||||
    -
 | 
			
		||||
        identifier: larastan.noEnvCallsOutsideOfConfig
 | 
			
		||||
        path: ../app/Console/Commands/System/CreatesDatabase.php
 | 
			
		||||
    - identifier: missingType.iterableValue # not interesting enough to fix.
 | 
			
		||||
    - identifier: missingType.generics # not interesting enough to fix.
 | 
			
		||||
    - "#Parameter \\#[1-2] \\$num[1-2] of function bc[a-z]+ expects numeric-string, [a-z\\-|&]+ given#"
 | 
			
		||||
    - '#expects view-string, string given#'
 | 
			
		||||
    - '#expects view-string\|null, string given#'
 | 
			
		||||
 | 
			
		||||
    # phpstan can't handle this so we ignore them.
 | 
			
		||||
    - '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::before#'
 | 
			
		||||
    - '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::after#'
 | 
			
		||||
    - '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::withTrashed#'
 | 
			
		||||
    - '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::accountTypeIn#'
 | 
			
		||||
    - '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\BelongsTo::withTrashed#'
 | 
			
		||||
 | 
			
		||||
  # The level 8 is the highest level. original was 5
 | 
			
		||||
  # 7 is more than enough, higher just leaves NULL things.
 | 
			
		||||
 
 | 
			
		||||
@@ -325,6 +325,12 @@ USE_RUNNING_BALANCE=false
 | 
			
		||||
#
 | 
			
		||||
FIREFLY_III_LAYOUT=v1
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Which Query Parser implementation to use for the search rngine and rules
 | 
			
		||||
# 'new' is experimental, 'legacy' is the classic one
 | 
			
		||||
#
 | 
			
		||||
QUERY_PARSER_IMPLEMENTATION=legacy
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Please make sure this URL matches the external URL of your Firefly III installation.
 | 
			
		||||
# It is used to validate specific requests and to generate URLs in emails.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								.github/label-actions.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								.github/label-actions.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,16 +1,29 @@
 | 
			
		||||
# Configuration for Label Actions - https://github.com/dessant/label-actions
 | 
			
		||||
 | 
			
		||||
# The `feature` label is added to issues
 | 
			
		||||
fixed:
 | 
			
		||||
  issues:
 | 
			
		||||
    # Post a comment, `{issue-author}` is an optional placeholder
 | 
			
		||||
    comment: |
 | 
			
		||||
      Hi there!
 | 
			
		||||
 | 
			
		||||
      This is an automatic reply. `Share and enjoy`
 | 
			
		||||
 | 
			
		||||
      This issue has been marked as fixed. Thanks for reporting! A new version will be released in due time. Unfortunately, [I cannot give an estimate](https://docs.firefly-iii.org/references/faq/firefly-iii/general/#when-will-you-release-version-the-next-version), but [the roadmap](https://roadmap.firefly-iii.org/) is available for your reading pleasure.
 | 
			
		||||
 | 
			
		||||
      There is no need to close the issue. It will be closed automatically.
 | 
			
		||||
 | 
			
		||||
      Thank you for your contributions.
 | 
			
		||||
feature:
 | 
			
		||||
  issues:
 | 
			
		||||
    # Post a comment, `{issue-author}` is an optional placeholder
 | 
			
		||||
    unlabel: feature
 | 
			
		||||
    comment: |
 | 
			
		||||
      Hi there! 
 | 
			
		||||
      Hi there!
 | 
			
		||||
 | 
			
		||||
      This is an automatic reply. `Share and enjoy`
 | 
			
		||||
 | 
			
		||||
      This issue has been marked as a feature request. The requested (new) feature will become a part of Firefly III or the data importer in due course.
 | 
			
		||||
      This issue has been marked as a feature request.
 | 
			
		||||
 | 
			
		||||
      If you come across this issue, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. You can subscribe to this issue to get updates.
 | 
			
		||||
 | 
			
		||||
@@ -20,13 +33,13 @@ epic:
 | 
			
		||||
  issues:
 | 
			
		||||
    # Post a comment, `{issue-author}` is an optional placeholder
 | 
			
		||||
    comment: |
 | 
			
		||||
      Hi there! 
 | 
			
		||||
      Hi there!
 | 
			
		||||
 | 
			
		||||
      This is an automatic reply. `Share and enjoy`
 | 
			
		||||
 | 
			
		||||
      This issue has been marked as an epic. In epics, large amounts of works are collected that will be part of a major new feature. If you have more ideas that could be a part of this epic, feel free to reply.
 | 
			
		||||
 | 
			
		||||
      *However*, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. 
 | 
			
		||||
      *However*, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted.
 | 
			
		||||
 | 
			
		||||
      If you are merely interested in this epic's progress, you can subscribe to this issue to get updates.
 | 
			
		||||
 | 
			
		||||
@@ -37,11 +50,11 @@ enhancement:
 | 
			
		||||
  issues:
 | 
			
		||||
    # Post a comment, `{issue-author}` is an optional placeholder
 | 
			
		||||
    comment: |
 | 
			
		||||
      Hi there! 
 | 
			
		||||
      Hi there!
 | 
			
		||||
 | 
			
		||||
      This is an automatic reply. `Share and enjoy`
 | 
			
		||||
 | 
			
		||||
      This issue has been marked as an enhancement. The requested enhancement to an existing feature will become a part of Firefly III or the data importer in due course.
 | 
			
		||||
      This issue has been marked as an enhancement.
 | 
			
		||||
 | 
			
		||||
      If you come across this issue, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. You can subscribe to this issue to get updates.
 | 
			
		||||
 | 
			
		||||
@@ -51,7 +64,7 @@ triage:
 | 
			
		||||
  issues:
 | 
			
		||||
    # Post a comment, `{issue-author}` is an optional placeholder
 | 
			
		||||
    comment: |
 | 
			
		||||
      Hi there! 
 | 
			
		||||
      Hi there!
 | 
			
		||||
 | 
			
		||||
      This is an automatic reply. `Share and enjoy`
 | 
			
		||||
 | 
			
		||||
@@ -62,7 +75,7 @@ triage:
 | 
			
		||||
needs-moar-debug:
 | 
			
		||||
  issues:
 | 
			
		||||
    comment: |
 | 
			
		||||
      Hi there! 
 | 
			
		||||
      Hi there!
 | 
			
		||||
 | 
			
		||||
      This is an automatic reply. `Share and enjoy`
 | 
			
		||||
 | 
			
		||||
@@ -80,7 +93,7 @@ needs-moar-debug:
 | 
			
		||||
needs-moar-logs:
 | 
			
		||||
  issues:
 | 
			
		||||
    comment: |
 | 
			
		||||
      Hi there! 
 | 
			
		||||
      Hi there!
 | 
			
		||||
 | 
			
		||||
      This is an automatic reply. `Share and enjoy`
 | 
			
		||||
 | 
			
		||||
@@ -96,7 +109,7 @@ needs-moar-logs:
 | 
			
		||||
v2-layout-issue:
 | 
			
		||||
  issues:
 | 
			
		||||
    comment: |
 | 
			
		||||
      Hi there! 
 | 
			
		||||
      Hi there!
 | 
			
		||||
 | 
			
		||||
      This is an automatic reply. `Share and enjoy`
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								.github/mergify.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								.github/mergify.yml
									
									
									
									
										vendored
									
									
								
							@@ -8,56 +8,3 @@ pull_request_rules:
 | 
			
		||||
      close:
 | 
			
		||||
        message: Please do not open PR's on the `main` branch, but on the `develop`
 | 
			
		||||
          branch only. Thank you!
 | 
			
		||||
  - name: No translations
 | 
			
		||||
    conditions:
 | 
			
		||||
      - -author~=^dependabot(|-preview)\[bot\]$
 | 
			
		||||
      - base=develop
 | 
			
		||||
      - or:
 | 
			
		||||
          - files~=^resources/lang/bg_BG
 | 
			
		||||
          - files~=^resources/lang/ca_ES
 | 
			
		||||
          - files~=^resources/lang/cs_CZ
 | 
			
		||||
          - files~=^resources/lang/da_DK
 | 
			
		||||
          - files~=^resources/lang/de_DE
 | 
			
		||||
          - files~=^resources/lang/el_GR
 | 
			
		||||
          - files~=^resources/lang/en_GB
 | 
			
		||||
          - files~=^resources/lang/es_ES
 | 
			
		||||
          - files~=^resources/lang/et_EE
 | 
			
		||||
          - files~=^resources/lang/fa_IR
 | 
			
		||||
          - files~=^resources/lang/fi_FI
 | 
			
		||||
          - files~=^resources/lang/fr_FR
 | 
			
		||||
          - files~=^resources/lang/he_IL
 | 
			
		||||
          - files~=^resources/lang/hu_HU
 | 
			
		||||
          - files~=^resources/lang/id_ID
 | 
			
		||||
          - files~=^resources/lang/is_IS
 | 
			
		||||
          - files~=^resources/lang/it_IT
 | 
			
		||||
          - files~=^resources/lang/ja_JP
 | 
			
		||||
          - files~=^resources/lang/ko_KR
 | 
			
		||||
          - files~=^resources/lang/lt_LT
 | 
			
		||||
          - files~=^resources/lang/nb_NO
 | 
			
		||||
          - files~=^resources/lang/nl_NL
 | 
			
		||||
          - files~=^resources/lang/pl_PL
 | 
			
		||||
          - files~=^resources/lang/pt_BR
 | 
			
		||||
          - files~=^resources/lang/pt_PT
 | 
			
		||||
          - files~=^resources/lang/ro_RO
 | 
			
		||||
          - files~=^resources/lang/ru_RU
 | 
			
		||||
          - files~=^resources/lang/si_LK
 | 
			
		||||
          - files~=^resources/lang/sk_SK
 | 
			
		||||
          - files~=^resources/lang/sl_SI
 | 
			
		||||
          - files~=^resources/lang/sr_CS
 | 
			
		||||
          - files~=^resources/lang/sv_SE
 | 
			
		||||
          - files~=^resources/lang/th_TH
 | 
			
		||||
          - files~=^resources/lang/tlh_AA
 | 
			
		||||
          - files~=^resources/lang/tr_TR
 | 
			
		||||
          - files~=^resources/lang/uk_UA
 | 
			
		||||
          - files~=^resources/lang/vi_VN
 | 
			
		||||
          - files~=^resources/lang/zh_CN
 | 
			
		||||
          - files~=^resources/lang/zh_TW
 | 
			
		||||
    actions:
 | 
			
		||||
      comment:
 | 
			
		||||
        message: >
 | 
			
		||||
          Please do not submit translated strings in your PR. If you need new
 | 
			
		||||
          sentences to be translated, add them to the `en_US` language strings.
 | 
			
		||||
          New or changed translations for other languages can be submitted at
 | 
			
		||||
          https://crowdin.com/project/firefly-iii
 | 
			
		||||
 | 
			
		||||
          Thank you!
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/closed-issues.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/closed-issues.yml
									
									
									
									
										vendored
									
									
								
							@@ -8,7 +8,7 @@ jobs:
 | 
			
		||||
  command_and_close:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: aws-actions/closed-issue-message@v1
 | 
			
		||||
      - uses: aws-actions/closed-issue-message@v2
 | 
			
		||||
        with:
 | 
			
		||||
          message: |
 | 
			
		||||
            Hi there! This is an automatic reply. `Share and enjoy`
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -58,15 +58,6 @@ jobs:
 | 
			
		||||
          GITHUB_TOKEN: ${{ github.token }}
 | 
			
		||||
          CROWDIN_PROJECT_NR: ${{ secrets.CROWDIN_PROJECT_NR }}
 | 
			
		||||
          CROWDIN_TOKEN: ${{ secrets.CROWDIN_TOKEN }}
 | 
			
		||||
      - name: Cleanup translations
 | 
			
		||||
        id: cleanup-transactions
 | 
			
		||||
        uses: JC5/firefly-iii-dev@main
 | 
			
		||||
        with:
 | 
			
		||||
          action: 'ff3:crowdin-warning'
 | 
			
		||||
          output: ''
 | 
			
		||||
        env:
 | 
			
		||||
          FIREFLY_III_ROOT: /github/workspace
 | 
			
		||||
          GH_TOKEN: ''
 | 
			
		||||
      - name: Cleanup changelog
 | 
			
		||||
        id: cleanup-changelog
 | 
			
		||||
        uses: JC5/firefly-iii-dev@main
 | 
			
		||||
@@ -314,6 +305,7 @@ jobs:
 | 
			
		||||
            git push origin $releaseName
 | 
			
		||||
            gh release create $releaseName -p --verify-tag \
 | 
			
		||||
              -t "Development release for $(date +'%Y-%m-%d')" \
 | 
			
		||||
              --latest=false \
 | 
			
		||||
              -F output.txt
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
@@ -327,6 +319,7 @@ jobs:
 | 
			
		||||
            git push origin $releaseName
 | 
			
		||||
            gh release create $releaseName -p --verify-tag \
 | 
			
		||||
              -t "Branch release for $(date +'%Y-%m-%d')" \
 | 
			
		||||
              --latest=false \
 | 
			
		||||
              -F output.txt
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
@@ -352,7 +345,18 @@ jobs:
 | 
			
		||||
            echo 'MAIN (real) release'
 | 
			
		||||
            git tag -a $releaseName -m "Here be changelog"
 | 
			
		||||
            git push origin $releaseName
 | 
			
		||||
            gh release create $releaseName -F output.txt -t "$releaseName" --verify-tag
 | 
			
		||||
 | 
			
		||||
            # do not tag as latest when alpha or beta.
 | 
			
		||||
            if [[ "$version" == *alpha* ]] || [[ "$version" == *beta* ]]; then
 | 
			
		||||
              echo 'Mark alpha or beta as NOT the latest.'
 | 
			
		||||
              gh release create $releaseName -F output.txt -t "$releaseName" --verify-tag --latest=false
 | 
			
		||||
            fi
 | 
			
		||||
 | 
			
		||||
            # tag as latest when NOT alpha or beta.
 | 
			
		||||
            if [[ "$version" != *alpha* ]] && [[ "$version" != *beta* ]]; then
 | 
			
		||||
              echo 'Mark prod as the latest.'
 | 
			
		||||
              gh release create $releaseName -F output.txt -t "$releaseName" --verify-tag
 | 
			
		||||
            fi
 | 
			
		||||
 | 
			
		||||
            # add archive files to release
 | 
			
		||||
            gh release upload $releaseName $zipName
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								.github/workflows/sonarcloud.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/sonarcloud.yml
									
									
									
									
										vendored
									
									
								
							@@ -8,7 +8,7 @@ on:
 | 
			
		||||
      - develop
 | 
			
		||||
env:
 | 
			
		||||
  DB_CONNECTION: sqlite
 | 
			
		||||
  APP_KEY: UfpBqqeXx7zpNodsC6yjYQcRfDdm4Bxh
 | 
			
		||||
  APP_KEY: TestTestTestTestTestTestTestTest
 | 
			
		||||
jobs:
 | 
			
		||||
  sonarcloud:
 | 
			
		||||
    name: SonarCloud
 | 
			
		||||
@@ -46,7 +46,9 @@ jobs:
 | 
			
		||||
        run: composer install --prefer-dist --no-interaction --no-progress --no-scripts
 | 
			
		||||
 | 
			
		||||
      - name: "Create database file"
 | 
			
		||||
        run: touch storage/database/database.sqlite
 | 
			
		||||
        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
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,11 @@
 | 
			
		||||
Over time, many people have contributed to Firefly III. Their efforts are not always visible, but always remembered and appreciated.
 | 
			
		||||
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
 | 
			
		||||
 | 
			
		||||
## 2025
 | 
			
		||||
- SoftBrix
 | 
			
		||||
 | 
			
		||||
## 2024
 | 
			
		||||
- Sobuno
 | 
			
		||||
- TasneemTantawy
 | 
			
		||||
- Antônio Franco
 | 
			
		||||
- yparitcher
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,8 @@ use Illuminate\Http\JsonResponse;
 | 
			
		||||
class AccountController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    use AccountFilter;
 | 
			
		||||
    // this array only exists to test if the constructor will use it properly.
 | 
			
		||||
    protected array $accepts = ['application/json', 'application/vnd.api+json'];
 | 
			
		||||
 | 
			
		||||
    /** @var array<int, string> */
 | 
			
		||||
    private array                      $balanceTypes;
 | 
			
		||||
@@ -81,15 +83,18 @@ class AccountController extends Controller
 | 
			
		||||
        $return = [];
 | 
			
		||||
        $result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
 | 
			
		||||
 | 
			
		||||
        // set date to end-of-day for account balance.
 | 
			
		||||
        $date->endOfDay();
 | 
			
		||||
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        foreach ($result as $account) {
 | 
			
		||||
            $nameWithBalance = $account->name;
 | 
			
		||||
            $currency        = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
 | 
			
		||||
            $currency        = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency;
 | 
			
		||||
            $useCurrency     = $currency;
 | 
			
		||||
            if (in_array($account->accountType->type, $this->balanceTypes, true)) {
 | 
			
		||||
                $balance         = Steam::finalAccountBalance($account, $date);
 | 
			
		||||
                $key             = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
 | 
			
		||||
                $useCurrency     = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? $this->defaultCurrency : $currency;
 | 
			
		||||
                $key             = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance';
 | 
			
		||||
                $useCurrency     = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? $this->nativeCurrency : $currency;
 | 
			
		||||
                $amount          = $balance[$key] ?? '0';
 | 
			
		||||
                $nameWithBalance = sprintf(
 | 
			
		||||
                    '%s (%s)',
 | 
			
		||||
@@ -99,15 +104,20 @@ class AccountController extends Controller
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $return[]        = [
 | 
			
		||||
                'id'                      => (string) $account->id,
 | 
			
		||||
                'name'                    => $account->name,
 | 
			
		||||
                'name_with_balance'       => $nameWithBalance,
 | 
			
		||||
                'type'                    => $account->accountType->type,
 | 
			
		||||
                'currency_id'             => (string) $useCurrency->id,
 | 
			
		||||
                'currency_name'           => $useCurrency->name,
 | 
			
		||||
                'currency_code'           => $useCurrency->code,
 | 
			
		||||
                'currency_symbol'         => $useCurrency->symbol,
 | 
			
		||||
                'currency_decimal_places' => $useCurrency->decimal_places,
 | 
			
		||||
                'id'                              => (string) $account->id,
 | 
			
		||||
                'name'                            => $account->name,
 | 
			
		||||
                'name_with_balance'               => $nameWithBalance,
 | 
			
		||||
                'type'                            => $account->accountType->type,
 | 
			
		||||
                'currency_id'                     => (string) $useCurrency->id,
 | 
			
		||||
                'currency_name'                   => $useCurrency->name,
 | 
			
		||||
                'currency_code'                   => $useCurrency->code,
 | 
			
		||||
                'currency_symbol'                 => $useCurrency->symbol,
 | 
			
		||||
                'currency_decimal_places'         => $useCurrency->decimal_places,
 | 
			
		||||
                'account_currency_id'             => (string) $currency->id,
 | 
			
		||||
                'account_currency_name'           => $currency->name,
 | 
			
		||||
                'account_currency_code'           => $currency->code,
 | 
			
		||||
                'account_currency_symbol'         => $currency->symbol,
 | 
			
		||||
                'account_currency_decimal_places' => $currency->decimal_places,
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -123,6 +133,6 @@ class AccountController extends Controller
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return response()->json($return);
 | 
			
		||||
        return response()->api($return);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -74,6 +74,6 @@ class BillController extends Controller
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return response()->json($filtered->toArray());
 | 
			
		||||
        return response()->api($filtered->toArray());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -73,6 +73,6 @@ class BudgetController extends Controller
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return response()->json($filtered);
 | 
			
		||||
        return response()->api($filtered->toArray());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -73,6 +73,6 @@ class CategoryController extends Controller
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return response()->json($filtered);
 | 
			
		||||
        return response()->api($filtered->toArray());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -77,7 +77,7 @@ class CurrencyController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($result);
 | 
			
		||||
        return response()->api($result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -103,6 +103,6 @@ class CurrencyController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($result);
 | 
			
		||||
        return response()->api($result);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -75,6 +75,6 @@ class ObjectGroupController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($return);
 | 
			
		||||
        return response()->api($return);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -87,7 +87,7 @@ class PiggyBankController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($response);
 | 
			
		||||
        return response()->api($response);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -124,6 +124,6 @@ class PiggyBankController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($response);
 | 
			
		||||
        return response()->api($response);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -73,6 +73,6 @@ class RecurrenceController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($response);
 | 
			
		||||
        return response()->api($response);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,6 @@ class RuleController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($response);
 | 
			
		||||
        return response()->api($response);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,6 @@ class RuleGroupController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($response);
 | 
			
		||||
        return response()->api($response);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -75,6 +75,6 @@ class TagController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($array);
 | 
			
		||||
        return response()->api($array);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -84,7 +84,7 @@ class TransactionController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($array);
 | 
			
		||||
        return response()->api($array);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -122,6 +122,6 @@ class TransactionController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($array);
 | 
			
		||||
        return response()->api($array);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,6 @@ class TransactionTypeController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($array);
 | 
			
		||||
        return response()->api($array);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\Preference;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Facades\Steam;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ApiSupport;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
@@ -80,6 +81,10 @@ class AccountController extends Controller
 | 
			
		||||
        /** @var Carbon $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();
 | 
			
		||||
 | 
			
		||||
@@ -97,8 +102,8 @@ class AccountController extends Controller
 | 
			
		||||
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        foreach ($accounts as $account) {
 | 
			
		||||
            $currency     = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
 | 
			
		||||
            $field        = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
 | 
			
		||||
            $currency     = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency;
 | 
			
		||||
            $field        = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance';
 | 
			
		||||
            $currentSet   = [
 | 
			
		||||
                'label'                   => $account->name,
 | 
			
		||||
                'currency_id'             => (string) $currency->id,
 | 
			
		||||
@@ -113,7 +118,7 @@ class AccountController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
            // TODO this code is also present in the V2 chart account controller so this method is due to be deprecated.
 | 
			
		||||
            $currentStart = clone $start;
 | 
			
		||||
            $range        = app('steam')->finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
 | 
			
		||||
            $range        = Steam::finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
 | 
			
		||||
            $previous     = array_values($range)[0][$field];
 | 
			
		||||
            while ($currentStart <= $end) {
 | 
			
		||||
                $format                        = $currentStart->format('Y-m-d');
 | 
			
		||||
 
 | 
			
		||||
@@ -25,18 +25,25 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers;
 | 
			
		||||
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use Carbon\Exceptions\InvalidDateException;
 | 
			
		||||
use Carbon\Exceptions\InvalidFormatException;
 | 
			
		||||
use FireflyIII\Exceptions\BadHttpHeaderException;
 | 
			
		||||
use FireflyIII\Models\Preference;
 | 
			
		||||
use FireflyIII\Models\TransactionCurrency;
 | 
			
		||||
use FireflyIII\Support\Facades\Amount;
 | 
			
		||||
use FireflyIII\Support\Facades\Steam;
 | 
			
		||||
use FireflyIII\Transformers\V2\AbstractTransformer;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
use Illuminate\Database\Eloquent\Model;
 | 
			
		||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
 | 
			
		||||
use Illuminate\Foundation\Bus\DispatchesJobs;
 | 
			
		||||
use Illuminate\Foundation\Validation\ValidatesRequests;
 | 
			
		||||
use Illuminate\Pagination\LengthAwarePaginator;
 | 
			
		||||
use Illuminate\Routing\Controller as BaseController;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
use League\Fractal\Manager;
 | 
			
		||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
 | 
			
		||||
use League\Fractal\Resource\Collection as FractalCollection;
 | 
			
		||||
use League\Fractal\Resource\Item;
 | 
			
		||||
use League\Fractal\Serializer\JsonApiSerializer;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
 | 
			
		||||
use Symfony\Component\HttpFoundation\ParameterBag;
 | 
			
		||||
@@ -44,8 +51,8 @@ use Symfony\Component\HttpFoundation\ParameterBag;
 | 
			
		||||
/**
 | 
			
		||||
 * Class Controller.
 | 
			
		||||
 *
 | 
			
		||||
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 | 
			
		||||
 * @SuppressWarnings(PHPMD.NumberOfChildren)
 | 
			
		||||
 * @SuppressWarnings("PHPMD.CouplingBetweenObjects")
 | 
			
		||||
 * @SuppressWarnings("PHPMD.NumberOfChildren")
 | 
			
		||||
 */
 | 
			
		||||
abstract class Controller extends BaseController
 | 
			
		||||
{
 | 
			
		||||
@@ -53,13 +60,15 @@ abstract class Controller extends BaseController
 | 
			
		||||
    use DispatchesJobs;
 | 
			
		||||
    use ValidatesRequests;
 | 
			
		||||
 | 
			
		||||
    protected const string CONTENT_TYPE    = 'application/vnd.api+json';
 | 
			
		||||
    protected const string CONTENT_TYPE      = 'application/vnd.api+json';
 | 
			
		||||
    protected const string JSON_CONTENT_TYPE = 'application/json';
 | 
			
		||||
 | 
			
		||||
    /** @var array<int, string> */
 | 
			
		||||
    protected array        $allowedSort;
 | 
			
		||||
    protected ParameterBag $parameters;
 | 
			
		||||
    protected bool        $convertToNative = false;
 | 
			
		||||
    protected TransactionCurrency $defaultCurrency;
 | 
			
		||||
    protected bool        $convertToNative   = false;
 | 
			
		||||
    protected array $accepts                 = ['application/json', 'application/vnd.api+json'];
 | 
			
		||||
    protected TransactionCurrency $nativeCurrency;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Controller constructor.
 | 
			
		||||
@@ -74,11 +83,17 @@ abstract class Controller extends BaseController
 | 
			
		||||
                if (auth()->check()) {
 | 
			
		||||
                    $language              = Steam::getLanguage();
 | 
			
		||||
                    $this->convertToNative = Amount::convertToNative();
 | 
			
		||||
                    $this->defaultCurrency = Amount::getDefaultCurrency();
 | 
			
		||||
                    $this->nativeCurrency  = Amount::getNativeCurrency();
 | 
			
		||||
                    app()->setLocale($language);
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                // filter down what this endpoint accepts.
 | 
			
		||||
                if (!$request->accepts($this->accepts)) {
 | 
			
		||||
                    throw new BadHttpHeaderException(sprintf('Sorry, Accept header "%s" is not something this endpoint can provide.', $request->header('Accept')));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                return $next($request);
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@@ -116,7 +131,7 @@ abstract class Controller extends BaseController
 | 
			
		||||
            if (null !== $date) {
 | 
			
		||||
                try {
 | 
			
		||||
                    $obj = Carbon::parse((string) $date);
 | 
			
		||||
                } catch (InvalidDateException|InvalidFormatException $e) {
 | 
			
		||||
                } catch (InvalidFormatException $e) {
 | 
			
		||||
                    // don't care
 | 
			
		||||
                    app('log')->warning(
 | 
			
		||||
                        sprintf(
 | 
			
		||||
@@ -142,7 +157,15 @@ abstract class Controller extends BaseController
 | 
			
		||||
                $value = null;
 | 
			
		||||
            }
 | 
			
		||||
            if (null !== $value) {
 | 
			
		||||
                $bag->set($integer, (int) $value);
 | 
			
		||||
                $value = (int) $value;
 | 
			
		||||
                if ($value < 1) {
 | 
			
		||||
                    $value = 1;
 | 
			
		||||
                }
 | 
			
		||||
                if ($value > 2 ** 16) {
 | 
			
		||||
                    $value = 2 ** 16;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $bag->set($integer, $value);
 | 
			
		||||
            }
 | 
			
		||||
            if (null === $value
 | 
			
		||||
                && 'limit' === $integer // @phpstan-ignore-line
 | 
			
		||||
@@ -224,4 +247,45 @@ abstract class Controller extends BaseController
 | 
			
		||||
 | 
			
		||||
        return $manager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final protected function jsonApiList(string $key, LengthAwarePaginator $paginator, AbstractTransformer $transformer): array
 | 
			
		||||
    {
 | 
			
		||||
        $manager  = new Manager();
 | 
			
		||||
        $baseUrl  = sprintf('%s/api/v1/', request()->getSchemeAndHttpHost());
 | 
			
		||||
 | 
			
		||||
        // TODO add stuff to path?
 | 
			
		||||
 | 
			
		||||
        $manager->setSerializer(new JsonApiSerializer($baseUrl));
 | 
			
		||||
 | 
			
		||||
        $objects  = $paginator->getCollection();
 | 
			
		||||
 | 
			
		||||
        // the transformer, at this point, needs to collect information that ALL items in the collection
 | 
			
		||||
        // require, like meta-data and stuff like that, and save it for later.
 | 
			
		||||
        $objects  = $transformer->collectMetaData($objects);
 | 
			
		||||
        $paginator->setCollection($objects);
 | 
			
		||||
 | 
			
		||||
        $resource = new FractalCollection($objects, $transformer, $key);
 | 
			
		||||
        $resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
 | 
			
		||||
 | 
			
		||||
        return $manager->createData($resource)->toArray();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a JSON API object and returns it.
 | 
			
		||||
     *
 | 
			
		||||
     * @param array<int, mixed>|Model $object
 | 
			
		||||
     */
 | 
			
		||||
    final protected function jsonApiObject(string $key, array|Model $object, AbstractTransformer $transformer): array
 | 
			
		||||
    {
 | 
			
		||||
        // create some objects:
 | 
			
		||||
        $manager  = new Manager();
 | 
			
		||||
        $baseUrl  = sprintf('%s/api/v1', request()->getSchemeAndHttpHost());
 | 
			
		||||
        $manager->setSerializer(new JsonApiSerializer($baseUrl));
 | 
			
		||||
 | 
			
		||||
        $transformer->collectMetaData(new Collection([$object]));
 | 
			
		||||
 | 
			
		||||
        $resource = new Item($object, $transformer, $key);
 | 
			
		||||
 | 
			
		||||
        return $manager->createData($resource)->toArray();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ class ExportController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @throws FireflyException
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function accounts(ExportRequest $request): LaravelResponse
 | 
			
		||||
    {
 | 
			
		||||
@@ -100,7 +100,7 @@ class ExportController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @throws FireflyException
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function bills(ExportRequest $request): LaravelResponse
 | 
			
		||||
    {
 | 
			
		||||
@@ -115,7 +115,7 @@ class ExportController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @throws FireflyException
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function budgets(ExportRequest $request): LaravelResponse
 | 
			
		||||
    {
 | 
			
		||||
@@ -130,7 +130,7 @@ class ExportController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @throws FireflyException
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function categories(ExportRequest $request): LaravelResponse
 | 
			
		||||
    {
 | 
			
		||||
@@ -145,7 +145,7 @@ class ExportController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @throws FireflyException
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function piggyBanks(ExportRequest $request): LaravelResponse
 | 
			
		||||
    {
 | 
			
		||||
@@ -160,7 +160,7 @@ class ExportController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @throws FireflyException
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function recurring(ExportRequest $request): LaravelResponse
 | 
			
		||||
    {
 | 
			
		||||
@@ -175,7 +175,7 @@ class ExportController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @throws FireflyException
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function rules(ExportRequest $request): LaravelResponse
 | 
			
		||||
    {
 | 
			
		||||
@@ -190,7 +190,7 @@ class ExportController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @throws FireflyException
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function tags(ExportRequest $request): LaravelResponse
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -70,7 +70,7 @@ class BillController extends Controller
 | 
			
		||||
        $start           = $request->getStart();
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $default         = Amount::getNativeCurrency();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
 | 
			
		||||
        // get all bills:
 | 
			
		||||
@@ -133,7 +133,7 @@ class BillController extends Controller
 | 
			
		||||
        $start           = $request->getStart();
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $default         = Amount::getNativeCurrency();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type) by the given bills and accounts.
 | 
			
		||||
 
 | 
			
		||||
@@ -48,7 +48,7 @@ class PeriodController extends Controller
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $default         = Amount::getNativeCurrency();
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type)
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ class TagController extends Controller
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $default         = Amount::getNativeCurrency();
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type) by the given bills and accounts.
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ class PeriodController extends Controller
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $default         = Amount::getNativeCurrency();
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type)
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ class TagController extends Controller
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $default         = Amount::getNativeCurrency();
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type) by the given bills and accounts.
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,8 @@ namespace FireflyIII\Api\V1\Controllers\Insight\Transfer;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
 | 
			
		||||
use FireflyIII\Models\TransactionType;
 | 
			
		||||
use FireflyIII\Support\Facades\Amount;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
 | 
			
		||||
@@ -47,11 +47,11 @@ class PeriodController extends Controller
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $default         = Amount::getNativeCurrency();
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type)
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::TRANSFER->value])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $genericSet      = $collector->getExtractedJournals();
 | 
			
		||||
        foreach ($genericSet as $journal) {
 | 
			
		||||
            // currency
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,8 @@ namespace FireflyIII\Api\V1\Controllers\Insight\Transfer;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
 | 
			
		||||
use FireflyIII\Models\TransactionType;
 | 
			
		||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Facades\Amount;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
@@ -67,12 +67,12 @@ class TagController extends Controller
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $default         = Amount::getNativeCurrency();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type) by the given bills and accounts.
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::TRANSFER->value])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $collector->withoutTags();
 | 
			
		||||
 | 
			
		||||
        $genericSet      = $collector->getExtractedJournals();
 | 
			
		||||
@@ -128,7 +128,7 @@ class TagController extends Controller
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type) by the given bills and accounts.
 | 
			
		||||
        $collector  = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::TRANSFER->value])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $collector->setTags($tags);
 | 
			
		||||
        $genericSet = $collector->getExtractedJournals();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers\Models\Budget;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
 | 
			
		||||
use FireflyIII\Models\Budget;
 | 
			
		||||
@@ -208,6 +209,8 @@ class ListController extends Controller
 | 
			
		||||
        $collector    = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector
 | 
			
		||||
            ->setUser($admin)
 | 
			
		||||
            // withdrawals only
 | 
			
		||||
            ->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
 | 
			
		||||
            // filter on budget.
 | 
			
		||||
            ->withoutBudget()
 | 
			
		||||
            // all info needed for the API:
 | 
			
		||||
 
 | 
			
		||||
@@ -100,7 +100,7 @@ class ShowController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * Display a listing of the budget limits for this budget.
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function indexAll(SameDateRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * DestroyController.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -22,10 +22,13 @@
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V2\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V2\Request\Model\ExchangeRate\DestroyRequest;
 | 
			
		||||
use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\DestroyRequest;
 | 
			
		||||
use FireflyIII\Enums\UserRoleEnum;
 | 
			
		||||
use FireflyIII\Exceptions\ValidationException;
 | 
			
		||||
use FireflyIII\Models\CurrencyExchangeRate;
 | 
			
		||||
use FireflyIII\Models\TransactionCurrency;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
 | 
			
		||||
@@ -36,6 +39,8 @@ class DestroyController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    use ValidatesUserGroupTrait;
 | 
			
		||||
 | 
			
		||||
    protected array $acceptedRoles   = [UserRoleEnum::OWNER];
 | 
			
		||||
 | 
			
		||||
    public const string RESOURCE_KEY = 'exchange-rates';
 | 
			
		||||
 | 
			
		||||
    private ExchangeRateRepositoryInterface $repository;
 | 
			
		||||
@@ -56,6 +61,9 @@ class DestroyController extends Controller
 | 
			
		||||
    public function destroy(DestroyRequest $request, TransactionCurrency $from, TransactionCurrency $to): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $date = $request->getDate();
 | 
			
		||||
        if (null === $date) {
 | 
			
		||||
            throw new ValidationException('Date is required');
 | 
			
		||||
        }
 | 
			
		||||
        $rate = $this->repository->getSpecificRateOnDate($from, $to, $date);
 | 
			
		||||
        if (null === $rate) {
 | 
			
		||||
            throw new NotFoundHttpException();
 | 
			
		||||
@@ -64,4 +72,11 @@ class DestroyController extends Controller
 | 
			
		||||
 | 
			
		||||
        return response()->json([], 204);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function destroySingle(CurrencyExchangeRate $exchangeRate): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $this->repository->deleteRate($exchangeRate);
 | 
			
		||||
 | 
			
		||||
        return response()->json([], 204);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ShowController.php
 | 
			
		||||
 * Copyright (c) 2023 james@firefly-iii.org
 | 
			
		||||
 * IndexController.php
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -17,16 +17,17 @@
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 * along with this program.  If not, see https://www.gnu.org/licenses/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V2\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
 | 
			
		||||
use FireflyIII\Transformers\V2\ExchangeRateTransformer;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
use Illuminate\Pagination\LengthAwarePaginator;
 | 
			
		||||
 | 
			
		||||
@@ -37,7 +38,7 @@ class IndexController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    use ValidatesUserGroupTrait;
 | 
			
		||||
 | 
			
		||||
    public const string RESOURCE_KEY = 'exchange-rates';
 | 
			
		||||
    public const string RESOURCE_KEY = 'currency_exchange_rates';
 | 
			
		||||
 | 
			
		||||
    private ExchangeRateRepositoryInterface $repository;
 | 
			
		||||
 | 
			
		||||
@@ -56,14 +57,11 @@ class IndexController extends Controller
 | 
			
		||||
 | 
			
		||||
    public function index(): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $piggies     = $this->repository->getAll();
 | 
			
		||||
        $entries     = $this->repository->getAll();
 | 
			
		||||
        $pageSize    = $this->parameters->get('limit');
 | 
			
		||||
        $count       = $piggies->count();
 | 
			
		||||
        $piggies     = $piggies->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
 | 
			
		||||
        $paginator   = new LengthAwarePaginator($piggies, $count, $pageSize, $this->parameters->get('page'));
 | 
			
		||||
 | 
			
		||||
        var_dump('here we are');
 | 
			
		||||
 | 
			
		||||
        $count       = $entries->count();
 | 
			
		||||
        $entries     = $entries->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
 | 
			
		||||
        $paginator   = new LengthAwarePaginator($entries, $count, $pageSize, $this->parameters->get('page'));
 | 
			
		||||
        $transformer = new ExchangeRateTransformer();
 | 
			
		||||
        $transformer->setParameters($this->parameters); // give params to transformer
 | 
			
		||||
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ShowController.php
 | 
			
		||||
 * Copyright (c) 2023 james@firefly-iii.org
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -17,14 +17,15 @@
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 * along with this program.  If not, see https://www.gnu.org/licenses/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V2\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Models\CurrencyExchangeRate;
 | 
			
		||||
use FireflyIII\Models\TransactionCurrency;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
 | 
			
		||||
@@ -73,4 +74,15 @@ class ShowController extends Controller
 | 
			
		||||
            ->header('Content-Type', self::CONTENT_TYPE)
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function showSingle(CurrencyExchangeRate $exchangeRate): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $transformer = new ExchangeRateTransformer();
 | 
			
		||||
        $transformer->setParameters($this->parameters);
 | 
			
		||||
 | 
			
		||||
        return response()
 | 
			
		||||
            ->api($this->jsonApiObject(self::RESOURCE_KEY, $exchangeRate, $transformer))
 | 
			
		||||
            ->header('Content-Type', self::CONTENT_TYPE)
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * DestroyController.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 * StoreController.php
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -22,10 +22,10 @@
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\StoreRequest;
 | 
			
		||||
use FireflyIII\Api\V2\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V2\Request\Model\ExchangeRate\StoreRequest;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
 | 
			
		||||
use FireflyIII\Transformers\V2\ExchangeRateTransformer;
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * DestroyController.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 * UpdateController.php
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -22,10 +22,10 @@
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\UpdateRequest;
 | 
			
		||||
use FireflyIII\Api\V2\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V2\Request\Model\ExchangeRate\UpdateRequest;
 | 
			
		||||
use FireflyIII\Models\CurrencyExchangeRate;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\ExchangeRate\ExchangeRateRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
 | 
			
		||||
@@ -37,7 +37,7 @@ class ExpressionController extends Controller
 | 
			
		||||
     * This endpoint is documented at:
 | 
			
		||||
     * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/rules/validateExpression
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function validateExpression(ValidateExpressionRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -88,21 +88,21 @@ class StoreController extends Controller
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $transactionGroup = $this->groupRepository->store($data);
 | 
			
		||||
        } catch (DuplicateTransactionException $e) { // @phpstan-ignore-line
 | 
			
		||||
        } catch (DuplicateTransactionException $e) {
 | 
			
		||||
            app('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); // @phpstan-ignore-line
 | 
			
		||||
        } catch (FireflyException $e) { // @phpstan-ignore-line
 | 
			
		||||
            throw new ValidationException($validator);
 | 
			
		||||
        } catch (FireflyException $e) {
 | 
			
		||||
            app('log')->warning('Caught an exception. Return error message.');
 | 
			
		||||
            app('log')->error($e->getMessage());
 | 
			
		||||
            $message   = sprintf('Internal exception: %s', $e->getMessage());
 | 
			
		||||
            $validator = \Validator::make(['transactions' => [['description' => $message]]], ['transactions.0.description' => new IsDuplicateTransaction()]);
 | 
			
		||||
 | 
			
		||||
            throw new ValidationException($validator); // @phpstan-ignore-line
 | 
			
		||||
            throw new ValidationException($validator);
 | 
			
		||||
        }
 | 
			
		||||
        app('preferences')->mark();
 | 
			
		||||
        $applyRules    = $data['apply_rules'] ?? true;
 | 
			
		||||
 
 | 
			
		||||
@@ -72,13 +72,6 @@ class UpdateController extends Controller
 | 
			
		||||
    {
 | 
			
		||||
        app('log')->debug('Now in update routine for transaction group');
 | 
			
		||||
        $data             = $request->getAll();
 | 
			
		||||
 | 
			
		||||
        // Fixes 8750.
 | 
			
		||||
        $transactions     = $data['transactions'] ?? [];
 | 
			
		||||
        foreach ($transactions as $index => $info) {
 | 
			
		||||
            unset($data['transactions'][$index]['type']);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $transactionGroup = $this->groupRepository->update($transactionGroup, $data);
 | 
			
		||||
        $manager          = $this->getManager();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -236,10 +236,10 @@ class ListController extends Controller
 | 
			
		||||
        // get list of budgets. Count it and split it.
 | 
			
		||||
        /** @var RecurringRepositoryInterface $recurringRepos */
 | 
			
		||||
        $recurringRepos = app(RecurringRepositoryInterface::class);
 | 
			
		||||
        $unfiltered     = $recurringRepos->getAll();
 | 
			
		||||
        $unfiltered     = $recurringRepos->get();
 | 
			
		||||
 | 
			
		||||
        // filter selection
 | 
			
		||||
        $collection     = $unfiltered->filter( // @phpstan-ignore-line
 | 
			
		||||
        $collection     = $unfiltered->filter(
 | 
			
		||||
            static function (Recurrence $recurrence) use ($currency) {  // @phpstan-ignore-line
 | 
			
		||||
                /** @var RecurrenceTransaction $transaction */
 | 
			
		||||
                foreach ($recurrence->recurrenceTransactions as $transaction) {
 | 
			
		||||
@@ -286,7 +286,7 @@ class ListController extends Controller
 | 
			
		||||
        $ruleRepos   = app(RuleRepositoryInterface::class);
 | 
			
		||||
        $unfiltered  = $ruleRepos->getAll();
 | 
			
		||||
 | 
			
		||||
        $collection  = $unfiltered->filter( // @phpstan-ignore-line
 | 
			
		||||
        $collection  = $unfiltered->filter(
 | 
			
		||||
            static function (Rule $rule) use ($currency) { // @phpstan-ignore-line
 | 
			
		||||
                /** @var RuleTrigger $trigger */
 | 
			
		||||
                foreach ($rule->ruleTriggers as $trigger) {
 | 
			
		||||
 
 | 
			
		||||
@@ -107,7 +107,7 @@ class ShowController extends Controller
 | 
			
		||||
        /** @var User $user */
 | 
			
		||||
        $user        = auth()->user();
 | 
			
		||||
        $manager     = $this->getManager();
 | 
			
		||||
        $this->parameters->set('defaultCurrency', $this->defaultCurrency);
 | 
			
		||||
        $this->parameters->set('nativeCurrency', $this->nativeCurrency);
 | 
			
		||||
 | 
			
		||||
        // update fields with user info.
 | 
			
		||||
        $currency->refreshForUser($user);
 | 
			
		||||
@@ -123,7 +123,7 @@ class ShowController extends Controller
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This endpoint is documented at:
 | 
			
		||||
     * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/getDefaultCurrency
 | 
			
		||||
     * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/getNativeCurrency
 | 
			
		||||
     *
 | 
			
		||||
     * Show a currency.
 | 
			
		||||
     *
 | 
			
		||||
@@ -134,7 +134,7 @@ class ShowController extends Controller
 | 
			
		||||
        /** @var User $user */
 | 
			
		||||
        $user        = auth()->user();
 | 
			
		||||
        $manager     = $this->getManager();
 | 
			
		||||
        $currency    = $this->defaultCurrency;
 | 
			
		||||
        $currency    = $this->nativeCurrency;
 | 
			
		||||
 | 
			
		||||
        // update fields with user info.
 | 
			
		||||
        $currency->refreshForUser($user);
 | 
			
		||||
 
 | 
			
		||||
@@ -100,7 +100,7 @@ class UpdateController extends Controller
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This endpoint is documented at:
 | 
			
		||||
     * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/defaultCurrency
 | 
			
		||||
     * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/nativeCurrency
 | 
			
		||||
     *
 | 
			
		||||
     * Make the currency a default currency.
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								app/Api/V1/Controllers/Models/UserGroup/IndexController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								app/Api/V1/Controllers/Models/UserGroup/IndexController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * IndexController.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see https://www.gnu.org/licenses/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers\Models\UserGroup;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Data\DateRequest;
 | 
			
		||||
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
 | 
			
		||||
use FireflyIII\Transformers\UserGroupTransformer;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
use Illuminate\Pagination\LengthAwarePaginator;
 | 
			
		||||
 | 
			
		||||
class IndexController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    public const string RESOURCE_KEY = 'user_groups';
 | 
			
		||||
 | 
			
		||||
    private UserGroupRepositoryInterface $repository;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * AccountController constructor.
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
        $this->middleware(
 | 
			
		||||
            function ($request, $next) {
 | 
			
		||||
                $this->repository = app(UserGroupRepositoryInterface::class);
 | 
			
		||||
 | 
			
		||||
                return $next($request);
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function index(DateRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $administrations = $this->repository->get();
 | 
			
		||||
        $pageSize        = $this->parameters->get('limit');
 | 
			
		||||
        $count           = $administrations->count();
 | 
			
		||||
        $administrations = $administrations->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
 | 
			
		||||
        $paginator       = new LengthAwarePaginator($administrations, $count, $pageSize, $this->parameters->get('page'));
 | 
			
		||||
        $transformer     = new UserGroupTransformer();
 | 
			
		||||
 | 
			
		||||
        $transformer->setParameters($this->parameters); // give params to transformer
 | 
			
		||||
 | 
			
		||||
        return response()
 | 
			
		||||
            ->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
 | 
			
		||||
            ->header('Content-Type', self::CONTENT_TYPE)
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								app/Api/V1/Controllers/Models/UserGroup/ShowController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								app/Api/V1/Controllers/Models/UserGroup/ShowController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ShowController.php
 | 
			
		||||
 * Copyright (c) 2021 james@firefly-iii.org
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers\Models\UserGroup;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Models\UserGroup;
 | 
			
		||||
use FireflyIII\Repositories\Webhook\WebhookRepositoryInterface;
 | 
			
		||||
use FireflyIII\Transformers\UserGroupTransformer;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ShowController
 | 
			
		||||
 */
 | 
			
		||||
class ShowController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    public const string RESOURCE_KEY = 'user_groups';
 | 
			
		||||
    private WebhookRepositoryInterface $repository;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
        $this->middleware(
 | 
			
		||||
            function ($request, $next) {
 | 
			
		||||
                $this->repository = app(WebhookRepositoryInterface::class);
 | 
			
		||||
                $this->repository->setUser(auth()->user());
 | 
			
		||||
 | 
			
		||||
                return $next($request);
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function show(UserGroup $userGroup): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $transformer = new UserGroupTransformer();
 | 
			
		||||
        $transformer->setParameters($this->parameters);
 | 
			
		||||
 | 
			
		||||
        return response()
 | 
			
		||||
            ->api($this->jsonApiObject(self::RESOURCE_KEY, $userGroup, $transformer))
 | 
			
		||||
            ->header('Content-Type', self::CONTENT_TYPE)
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										71
									
								
								app/Api/V1/Controllers/Models/UserGroup/UpdateController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								app/Api/V1/Controllers/Models/UserGroup/UpdateController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * UpdateController.php
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see https://www.gnu.org/licenses/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers\Models\UserGroup;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Models\UserGroup\UpdateRequest;
 | 
			
		||||
use FireflyIII\Models\UserGroup;
 | 
			
		||||
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
 | 
			
		||||
use FireflyIII\Transformers\UserGroupTransformer;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
 | 
			
		||||
class UpdateController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    public const string RESOURCE_KEY = 'user_groups';
 | 
			
		||||
 | 
			
		||||
    private UserGroupRepositoryInterface $repository;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * AccountController constructor.
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
        $this->middleware(
 | 
			
		||||
            function ($request, $next) {
 | 
			
		||||
                $this->repository = app(UserGroupRepositoryInterface::class);
 | 
			
		||||
 | 
			
		||||
                return $next($request);
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function update(UpdateRequest $request, UserGroup $userGroup): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        app('log')->debug(sprintf('Now in %s', __METHOD__));
 | 
			
		||||
        $data        = $request->getData();
 | 
			
		||||
        $userGroup   = $this->repository->update($userGroup, $data);
 | 
			
		||||
        $userGroup->refresh();
 | 
			
		||||
        app('preferences')->mark();
 | 
			
		||||
 | 
			
		||||
        $transformer = new UserGroupTransformer();
 | 
			
		||||
        $transformer->setParameters($this->parameters);
 | 
			
		||||
 | 
			
		||||
        return response()
 | 
			
		||||
            ->api($this->jsonApiObject(self::RESOURCE_KEY, $userGroup, $transformer))
 | 
			
		||||
            ->header('Content-Type', self::CONTENT_TYPE)
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -124,7 +124,7 @@ class BasicController extends Controller
 | 
			
		||||
    {
 | 
			
		||||
        // some config settings
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $default         = Amount::getNativeCurrency();
 | 
			
		||||
        // prep some arrays:
 | 
			
		||||
        $incomes         = [];
 | 
			
		||||
        $expenses        = [];
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ class AboutController extends Controller
 | 
			
		||||
                           'driver'      => $currentDriver,
 | 
			
		||||
                       ];
 | 
			
		||||
 | 
			
		||||
        return response()->api(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
 | 
			
		||||
        return response()->api(['data' => $data])->header('Content-Type', self::JSON_CONTENT_TYPE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -86,7 +86,7 @@ class ConfigurationController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json($return);
 | 
			
		||||
        return response()->api($return);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -142,7 +142,7 @@ class ConfigurationController extends Controller
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
 | 
			
		||||
        return response()->api(['data' => $data])->header('Content-Type', self::JSON_CONTENT_TYPE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -173,6 +173,6 @@ class ConfigurationController extends Controller
 | 
			
		||||
            'editable' => true,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
 | 
			
		||||
        return response()->api(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,8 +52,8 @@ class CronController extends Controller
 | 
			
		||||
        if (true === config('cer.download_enabled')) {
 | 
			
		||||
            $return['exchange_rates'] = $this->exchangeRatesCronJob($config['force'], $config['date']);
 | 
			
		||||
        }
 | 
			
		||||
        $return['bill_warnings']          = $this->billWarningCronJob($config['force'], $config['date']);
 | 
			
		||||
        $return['bill_notifications']     = $this->billWarningCronJob($config['force'], $config['date']);
 | 
			
		||||
 | 
			
		||||
        return response()->json($return);
 | 
			
		||||
        return response()->api($return);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,6 @@ use FireflyIII\Models\Preference;
 | 
			
		||||
use FireflyIII\Transformers\PreferenceTransformer;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
use Illuminate\Pagination\LengthAwarePaginator;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
 | 
			
		||||
use League\Fractal\Resource\Collection as FractalCollection;
 | 
			
		||||
use League\Fractal\Resource\Item;
 | 
			
		||||
@@ -86,7 +85,7 @@ class PreferencesController extends Controller
 | 
			
		||||
        $manager     = $this->getManager();
 | 
			
		||||
 | 
			
		||||
        if ('currencyPreference' === $preference->name) {
 | 
			
		||||
            throw new FireflyException('Please use api/v1/currencies/default instead.');
 | 
			
		||||
            throw new FireflyException('Please use api/v1/currencies/native instead.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /** @var PreferenceTransformer $transformer */
 | 
			
		||||
@@ -98,34 +97,6 @@ class PreferencesController extends Controller
 | 
			
		||||
        return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * TODO This endpoint is not documented.
 | 
			
		||||
     *
 | 
			
		||||
     * Return a single preference by name.
 | 
			
		||||
     *
 | 
			
		||||
     * @param Collection<int, Preference> $collection
 | 
			
		||||
     */
 | 
			
		||||
    public function showList(Collection $collection): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $manager     = $this->getManager();
 | 
			
		||||
        $count       = $collection->count();
 | 
			
		||||
        $pageSize    = $this->parameters->get('limit');
 | 
			
		||||
        $preferences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
 | 
			
		||||
 | 
			
		||||
        // make paginator:
 | 
			
		||||
        $paginator   = new LengthAwarePaginator($preferences, $count, $pageSize, $this->parameters->get('page'));
 | 
			
		||||
        $paginator->setPath(route('api.v1.preferences.show-list').$this->buildParams());
 | 
			
		||||
 | 
			
		||||
        /** @var PreferenceTransformer $transformer */
 | 
			
		||||
        $transformer = app(PreferenceTransformer::class);
 | 
			
		||||
        $transformer->setParameters($this->parameters);
 | 
			
		||||
 | 
			
		||||
        $resource    = new FractalCollection($preferences, $transformer, self::RESOURCE_KEY);
 | 
			
		||||
        $resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
 | 
			
		||||
 | 
			
		||||
        return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This endpoint is documented at:
 | 
			
		||||
     * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/preferences/storePreference
 | 
			
		||||
@@ -161,7 +132,7 @@ class PreferencesController extends Controller
 | 
			
		||||
    public function update(PreferenceUpdateRequest $request, Preference $preference): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        if ('currencyPreference' === $preference->name) {
 | 
			
		||||
            throw new FireflyException('Please use api/v1/currencies/default instead.');
 | 
			
		||||
            throw new FireflyException('Please use api/v1/currencies/native instead.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $manager     = $this->getManager();
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V1\Requests\Autocomplete;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Support\Request\ChecksLogin;
 | 
			
		||||
use FireflyIII\Support\Request\ConvertsDataTypes;
 | 
			
		||||
use Illuminate\Foundation\Http\FormRequest;
 | 
			
		||||
@@ -46,7 +46,7 @@ class AutocompleteRequest extends FormRequest
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // remove 'initial balance' from allowed types. its internal
 | 
			
		||||
        $array = array_diff($array, [AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION]);
 | 
			
		||||
        $array = array_diff($array, [AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::RECONCILIATION->value]);
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            'types' => $array,
 | 
			
		||||
@@ -58,6 +58,7 @@ class AutocompleteRequest extends FormRequest
 | 
			
		||||
    public function rules(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'date' => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V1\Requests\Data;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Exceptions\ValidationException;
 | 
			
		||||
use FireflyIII\Support\Request\ChecksLogin;
 | 
			
		||||
use FireflyIII\Support\Request\ConvertsDataTypes;
 | 
			
		||||
use Illuminate\Foundation\Http\FormRequest;
 | 
			
		||||
@@ -49,12 +49,13 @@ class DateRequest extends FormRequest
 | 
			
		||||
        $start->startOfDay();
 | 
			
		||||
        $end->endOfDay();
 | 
			
		||||
        if ($start->diffInYears($end, true) > 5) {
 | 
			
		||||
            throw new FireflyException('Date range out of range.');
 | 
			
		||||
            throw new ValidationException('Date range out of range.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            'start' => $start,
 | 
			
		||||
            'end'   => $end,
 | 
			
		||||
            'date'  => $this->getCarbonDate('date'),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -64,8 +65,9 @@ class DateRequest extends FormRequest
 | 
			
		||||
    public function rules(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'start' => 'required|date',
 | 
			
		||||
            'end'   => 'required|date|after:start',
 | 
			
		||||
            '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',
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V1\Requests\Data\Export;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Request\ChecksLogin;
 | 
			
		||||
use FireflyIII\Support\Request\ConvertsDataTypes;
 | 
			
		||||
@@ -55,7 +55,7 @@ class ExportRequest extends FormRequest
 | 
			
		||||
            $accountId = (int) $part;
 | 
			
		||||
            if (0 !== $accountId) {
 | 
			
		||||
                $account = $repository->find($accountId);
 | 
			
		||||
                if (null !== $account && AccountType::ASSET === $account->accountType->type) {
 | 
			
		||||
                if (null !== $account && AccountTypeEnum::ASSET->value === $account->accountType->type) {
 | 
			
		||||
                    $accounts->push($account);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -25,8 +25,8 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Api\V1\Requests\Insight;
 | 
			
		||||
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
 | 
			
		||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
 | 
			
		||||
@@ -70,7 +70,7 @@ class GenericRequest extends FormRequest
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        foreach ($this->accounts as $account) {
 | 
			
		||||
            $type = $account->accountType->type;
 | 
			
		||||
            if (in_array($type, [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], true)) {
 | 
			
		||||
            if (in_array($type, [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value], true)) {
 | 
			
		||||
                $return->push($account);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -191,7 +191,7 @@ class GenericRequest extends FormRequest
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        foreach ($this->accounts as $account) {
 | 
			
		||||
            $type = $account->accountType->type;
 | 
			
		||||
            if (AccountType::EXPENSE === $type) {
 | 
			
		||||
            if (AccountTypeEnum::EXPENSE->value === $type) {
 | 
			
		||||
                $return->push($account);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -207,7 +207,7 @@ class GenericRequest extends FormRequest
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        foreach ($this->accounts as $account) {
 | 
			
		||||
            $type = $account->accountType->type;
 | 
			
		||||
            if (AccountType::REVENUE === $type) {
 | 
			
		||||
            if (AccountTypeEnum::REVENUE->value === $type) {
 | 
			
		||||
                $return->push($account);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\Account;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\Location;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Rules\IsBoolean;
 | 
			
		||||
use FireflyIII\Rules\UniqueAccountNumber;
 | 
			
		||||
use FireflyIII\Rules\UniqueIban;
 | 
			
		||||
@@ -33,6 +34,8 @@ use FireflyIII\Support\Request\AppendsLocationData;
 | 
			
		||||
use FireflyIII\Support\Request\ChecksLogin;
 | 
			
		||||
use FireflyIII\Support\Request\ConvertsDataTypes;
 | 
			
		||||
use Illuminate\Foundation\Http\FormRequest;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
use Illuminate\Validation\Validator;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class UpdateRequest
 | 
			
		||||
@@ -112,4 +115,36 @@ class UpdateRequest extends FormRequest
 | 
			
		||||
 | 
			
		||||
        return Location::requestRules($rules);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Configure the validator instance with special rules for after the basic validation rules.
 | 
			
		||||
     */
 | 
			
		||||
    public function withValidator(Validator $validator): void
 | 
			
		||||
    {
 | 
			
		||||
        $validator->after(
 | 
			
		||||
            function (Validator $validator): void {
 | 
			
		||||
                // validate start before end only if both are there.
 | 
			
		||||
                $data       = $validator->getData();
 | 
			
		||||
 | 
			
		||||
                /** @var Account $account */
 | 
			
		||||
                $account    = $this->route()->parameter('account');
 | 
			
		||||
 | 
			
		||||
                /** @var AccountRepositoryInterface $repository */
 | 
			
		||||
                $repository = app(AccountRepositoryInterface::class);
 | 
			
		||||
                $currency   = $repository->getAccountCurrency($account);
 | 
			
		||||
 | 
			
		||||
                // how many piggies are attached?
 | 
			
		||||
                $piggyBanks = $account->piggyBanks()->count();
 | 
			
		||||
                if ($piggyBanks > 0 && array_key_exists('currency_code', $data) && $data['currency_code'] !== $currency->code) {
 | 
			
		||||
                    $validator->errors()->add('currency_code', (string) trans('validation.piggy_no_change_currency'));
 | 
			
		||||
                }
 | 
			
		||||
                if ($piggyBanks > 0 && array_key_exists('currency_id', $data) && (int) $data['currency_id'] !== $currency->id) {
 | 
			
		||||
                    $validator->errors()->add('currency_id', (string) trans('validation.piggy_no_change_currency'));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
        if ($validator->fails()) {
 | 
			
		||||
            Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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',
 | 
			
		||||
            'end'           => 'date',
 | 
			
		||||
            'start'         => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'end'           => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -78,9 +78,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',
 | 
			
		||||
            'end_date'       => 'nullable|date|after:date',
 | 
			
		||||
            'extension_date' => 'nullable|date|after:date',
 | 
			
		||||
            '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',
 | 
			
		||||
            'repeat_freq'    => 'in:weekly,monthly,quarterly,half-year,yearly|required',
 | 
			
		||||
            'skip'           => 'min:0|max:31|numeric',
 | 
			
		||||
            'active'         => [new IsBoolean()],
 | 
			
		||||
@@ -95,16 +95,40 @@ class StoreRequest extends FormRequest
 | 
			
		||||
    {
 | 
			
		||||
        $validator->after(
 | 
			
		||||
            static function (Validator $validator): void {
 | 
			
		||||
                $data = $validator->getData();
 | 
			
		||||
                $min  = (string) ($data['amount_min'] ?? '0');
 | 
			
		||||
                $max  = (string) ($data['amount_max'] ?? '0');
 | 
			
		||||
                $data   = $validator->getData();
 | 
			
		||||
                $min    = $data['amount_min'] ?? '0';
 | 
			
		||||
                $max    = $data['amount_max'] ?? '0';
 | 
			
		||||
 | 
			
		||||
                if (1 === bccomp($min, $max)) {
 | 
			
		||||
                if (is_array($min) || is_array($max)) {
 | 
			
		||||
                    $validator->errors()->add('amount_min', (string) trans('validation.generic_invalid'));
 | 
			
		||||
                    $validator->errors()->add('amount_max', (string) trans('validation.generic_invalid'));
 | 
			
		||||
                    $min = '0';
 | 
			
		||||
                    $max = '0';
 | 
			
		||||
                }
 | 
			
		||||
                $result = false;
 | 
			
		||||
 | 
			
		||||
                try {
 | 
			
		||||
                    $result = bccomp($min, $max);
 | 
			
		||||
                } catch (\ValueError $e) {
 | 
			
		||||
                    Log::error($e->getMessage());
 | 
			
		||||
                    $validator->errors()->add('amount_min', (string) trans('validation.generic_invalid'));
 | 
			
		||||
                    $validator->errors()->add('amount_max', (string) trans('validation.generic_invalid'));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (1 === $result) {
 | 
			
		||||
                    $validator->errors()->add('amount_min', (string) trans('validation.amount_min_over_max'));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
        if ($validator->fails()) {
 | 
			
		||||
        $failed = false;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $failed = $validator->fails();
 | 
			
		||||
        } catch (\TypeError $e) {
 | 
			
		||||
            Log::error($e->getMessage());
 | 
			
		||||
            $failed = false;
 | 
			
		||||
        }
 | 
			
		||||
        if ($failed) {
 | 
			
		||||
            Log::channel('audit')->error(sprintf('Validation errors in %s', __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',
 | 
			
		||||
            'end_date'       => 'date|after:date',
 | 
			
		||||
            'extension_date' => 'date|after:date',
 | 
			
		||||
            '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',
 | 
			
		||||
            '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',
 | 
			
		||||
            'end'           => 'date',
 | 
			
		||||
            'start'         => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'end'           => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'amount'        => ['nullable', new IsValidPositiveAmount()],
 | 
			
		||||
            'currency_id'   => 'numeric|exists:transaction_currencies,id',
 | 
			
		||||
            'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * DestroyRequest.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V2\Request\Model\ExchangeRate;
 | 
			
		||||
namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
 | 
			
		||||
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use FireflyIII\Support\Request\ChecksLogin;
 | 
			
		||||
@@ -34,7 +34,7 @@ class DestroyRequest extends FormRequest
 | 
			
		||||
    use ChecksLogin;
 | 
			
		||||
    use ConvertsDataTypes;
 | 
			
		||||
 | 
			
		||||
    public function getDate(): Carbon
 | 
			
		||||
    public function getDate(): ?Carbon
 | 
			
		||||
    {
 | 
			
		||||
        return $this->getCarbonDate('date');
 | 
			
		||||
    }
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * DestroyRequest.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 * StoreRequest.php
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V2\Request\Model\ExchangeRate;
 | 
			
		||||
namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
 | 
			
		||||
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use FireflyIII\Models\TransactionCurrency;
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * DestroyRequest.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 * UpdateRequest.php
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V2\Request\Model\ExchangeRate;
 | 
			
		||||
namespace FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate;
 | 
			
		||||
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use FireflyIII\Support\Request\ChecksLogin;
 | 
			
		||||
@@ -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',
 | 
			
		||||
            'first_date'                           => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            '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',
 | 
			
		||||
            'end'        => 'date|after_or_equal:start',
 | 
			
		||||
            'start'      => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'end'        => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'accounts'   => '',
 | 
			
		||||
            'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
 | 
			
		||||
        ];
 | 
			
		||||
 
 | 
			
		||||
@@ -65,8 +65,8 @@ class TriggerRequest extends FormRequest
 | 
			
		||||
    public function rules(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'start'      => 'date',
 | 
			
		||||
            'end'        => 'date|after_or_equal:start',
 | 
			
		||||
            'start'      => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'end'        => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'accounts'   => '',
 | 
			
		||||
            'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
 | 
			
		||||
        ];
 | 
			
		||||
 
 | 
			
		||||
@@ -65,8 +65,8 @@ class TestRequest extends FormRequest
 | 
			
		||||
    public function rules(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'start'      => 'date',
 | 
			
		||||
            'end'        => 'date|after_or_equal:start',
 | 
			
		||||
            'start'      => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'end'        => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'accounts'   => '',
 | 
			
		||||
            'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
 | 
			
		||||
        ];
 | 
			
		||||
 
 | 
			
		||||
@@ -69,8 +69,8 @@ class TriggerRequest extends FormRequest
 | 
			
		||||
    public function rules(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'start' => 'date',
 | 
			
		||||
            'end'   => 'date|after_or_equal:start',
 | 
			
		||||
            'start' => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'end'   => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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',
 | 
			
		||||
            'date'        => 'date|nullable|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return Location::requestRules($rules);
 | 
			
		||||
 
 | 
			
		||||
@@ -63,11 +63,10 @@ class UpdateRequest extends FormRequest
 | 
			
		||||
    {
 | 
			
		||||
        /** @var Tag $tag */
 | 
			
		||||
        $tag   = $this->route()->parameter('tagOrId');
 | 
			
		||||
        // TODO check if uniqueObjectForUser is obsolete
 | 
			
		||||
        $rules = [
 | 
			
		||||
            'tag'         => 'min:1|max:1024|uniqueObjectForUser:tags,tag,'.$tag->id,
 | 
			
		||||
            'description' => 'min:1|nullable|max:32768',
 | 
			
		||||
            'date'        => 'date|nullable',
 | 
			
		||||
            'date'        => 'date|nullable|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return Location::requestRules($rules);
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V1\Requests\Models\Transaction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Models\Location;
 | 
			
		||||
use FireflyIII\Rules\BelongsUser;
 | 
			
		||||
use FireflyIII\Rules\IsBoolean;
 | 
			
		||||
use FireflyIII\Rules\IsDateOrTime;
 | 
			
		||||
@@ -82,82 +83,87 @@ class StoreRequest extends FormRequest
 | 
			
		||||
        foreach ($this->get('transactions') as $transaction) {
 | 
			
		||||
            $object   = new NullArrayObject($transaction);
 | 
			
		||||
            $return[] = [
 | 
			
		||||
                'type'                  => $this->clearString($object['type']),
 | 
			
		||||
                'date'                  => $this->dateFromValue($object['date']),
 | 
			
		||||
                'order'                 => $this->integerFromValue((string) $object['order']),
 | 
			
		||||
                'type'                    => $this->clearString($object['type']),
 | 
			
		||||
                'date'                    => $this->dateFromValue($object['date']),
 | 
			
		||||
                'order'                   => $this->integerFromValue((string) $object['order']),
 | 
			
		||||
 | 
			
		||||
                'currency_id'           => $this->integerFromValue((string) $object['currency_id']),
 | 
			
		||||
                'currency_code'         => $this->clearString((string) $object['currency_code']),
 | 
			
		||||
                'currency_id'             => $this->integerFromValue((string) $object['currency_id']),
 | 
			
		||||
                'currency_code'           => $this->clearString((string) $object['currency_code']),
 | 
			
		||||
 | 
			
		||||
                // location
 | 
			
		||||
                'latitude'                => $this->floatFromValue((string) $object['latitude']),
 | 
			
		||||
                'longitude'               => $this->floatFromValue((string) $object['longitude']),
 | 
			
		||||
                'zoom_level'              => $this->integerFromValue((string) $object['zoom_level']),
 | 
			
		||||
 | 
			
		||||
                // foreign currency info:
 | 
			
		||||
                'foreign_currency_id'   => $this->integerFromValue((string) $object['foreign_currency_id']),
 | 
			
		||||
                'foreign_currency_code' => $this->clearString((string) $object['foreign_currency_code']),
 | 
			
		||||
                'foreign_currency_id'     => $this->integerFromValue((string) $object['foreign_currency_id']),
 | 
			
		||||
                'foreign_currency_code'   => $this->clearString((string) $object['foreign_currency_code']),
 | 
			
		||||
 | 
			
		||||
                // amount and foreign amount. Cannot be 0.
 | 
			
		||||
                'amount'                => $this->clearString((string) $object['amount']),
 | 
			
		||||
                'foreign_amount'        => $this->clearString((string) $object['foreign_amount']),
 | 
			
		||||
                'amount'                  => $this->clearString((string) $object['amount']),
 | 
			
		||||
                'foreign_amount'          => $this->clearString((string) $object['foreign_amount']),
 | 
			
		||||
 | 
			
		||||
                // description.
 | 
			
		||||
                'description'           => $this->clearString($object['description']),
 | 
			
		||||
                'description'             => $this->clearString($object['description']),
 | 
			
		||||
 | 
			
		||||
                // source of transaction. If everything is null, assume cash account.
 | 
			
		||||
                'source_id'             => $this->integerFromValue((string) $object['source_id']),
 | 
			
		||||
                'source_name'           => $this->clearString((string) $object['source_name']),
 | 
			
		||||
                'source_iban'           => $this->clearIban((string) $object['source_iban']),
 | 
			
		||||
                'source_number'         => $this->clearString((string) $object['source_number']),
 | 
			
		||||
                'source_bic'            => $this->clearString((string) $object['source_bic']),
 | 
			
		||||
                'source_id'               => $this->integerFromValue((string) $object['source_id']),
 | 
			
		||||
                'source_name'             => $this->clearString((string) $object['source_name']),
 | 
			
		||||
                'source_iban'             => $this->clearIban((string) $object['source_iban']),
 | 
			
		||||
                'source_number'           => $this->clearString((string) $object['source_number']),
 | 
			
		||||
                'source_bic'              => $this->clearString((string) $object['source_bic']),
 | 
			
		||||
 | 
			
		||||
                // destination of transaction. If everything is null, assume cash account.
 | 
			
		||||
                'destination_id'        => $this->integerFromValue((string) $object['destination_id']),
 | 
			
		||||
                'destination_name'      => $this->clearString((string) $object['destination_name']),
 | 
			
		||||
                'destination_iban'      => $this->clearIban((string) $object['destination_iban']),
 | 
			
		||||
                'destination_number'    => $this->clearString((string) $object['destination_number']),
 | 
			
		||||
                'destination_bic'       => $this->clearString((string) $object['destination_bic']),
 | 
			
		||||
                'destination_id'          => $this->integerFromValue((string) $object['destination_id']),
 | 
			
		||||
                'destination_name'        => $this->clearString((string) $object['destination_name']),
 | 
			
		||||
                'destination_iban'        => $this->clearIban((string) $object['destination_iban']),
 | 
			
		||||
                'destination_number'      => $this->clearString((string) $object['destination_number']),
 | 
			
		||||
                'destination_bic'         => $this->clearString((string) $object['destination_bic']),
 | 
			
		||||
 | 
			
		||||
                // budget info
 | 
			
		||||
                'budget_id'             => $this->integerFromValue((string) $object['budget_id']),
 | 
			
		||||
                'budget_name'           => $this->clearString((string) $object['budget_name']),
 | 
			
		||||
                'budget_id'               => $this->integerFromValue((string) $object['budget_id']),
 | 
			
		||||
                'budget_name'             => $this->clearString((string) $object['budget_name']),
 | 
			
		||||
 | 
			
		||||
                // category info
 | 
			
		||||
                'category_id'           => $this->integerFromValue((string) $object['category_id']),
 | 
			
		||||
                'category_name'         => $this->clearString((string) $object['category_name']),
 | 
			
		||||
                'category_id'             => $this->integerFromValue((string) $object['category_id']),
 | 
			
		||||
                'category_name'           => $this->clearString((string) $object['category_name']),
 | 
			
		||||
 | 
			
		||||
                // journal bill reference. Optional. Will only work for withdrawals
 | 
			
		||||
                'bill_id'               => $this->integerFromValue((string) $object['bill_id']),
 | 
			
		||||
                'bill_name'             => $this->clearString((string) $object['bill_name']),
 | 
			
		||||
                'bill_id'                 => $this->integerFromValue((string) $object['bill_id']),
 | 
			
		||||
                'bill_name'               => $this->clearString((string) $object['bill_name']),
 | 
			
		||||
 | 
			
		||||
                // piggy bank reference. Optional. Will only work for transfers
 | 
			
		||||
                'piggy_bank_id'         => $this->integerFromValue((string) $object['piggy_bank_id']),
 | 
			
		||||
                'piggy_bank_name'       => $this->clearString((string) $object['piggy_bank_name']),
 | 
			
		||||
                'piggy_bank_id'           => $this->integerFromValue((string) $object['piggy_bank_id']),
 | 
			
		||||
                'piggy_bank_name'         => $this->clearString((string) $object['piggy_bank_name']),
 | 
			
		||||
 | 
			
		||||
                // some other interesting properties
 | 
			
		||||
                'reconciled'            => $this->convertBoolean((string) $object['reconciled']),
 | 
			
		||||
                'notes'                 => $this->clearStringKeepNewlines((string) $object['notes']),
 | 
			
		||||
                'tags'                  => $this->arrayFromValue($object['tags']),
 | 
			
		||||
                'reconciled'              => $this->convertBoolean((string) $object['reconciled']),
 | 
			
		||||
                'notes'                   => $this->clearStringKeepNewlines((string) $object['notes']),
 | 
			
		||||
                'tags'                    => $this->arrayFromValue($object['tags']),
 | 
			
		||||
 | 
			
		||||
                // all custom fields:
 | 
			
		||||
                'internal_reference'    => $this->clearString((string) $object['internal_reference']),
 | 
			
		||||
                'external_id'           => $this->clearString((string) $object['external_id']),
 | 
			
		||||
                'original_source'       => sprintf('ff3-v%s', config('firefly.version')),
 | 
			
		||||
                'recurrence_id'         => $this->integerFromValue($object['recurrence_id']),
 | 
			
		||||
                'bunq_payment_id'       => $this->clearString((string) $object['bunq_payment_id']),
 | 
			
		||||
                'external_url'          => $this->clearString((string) $object['external_url']),
 | 
			
		||||
                'internal_reference'      => $this->clearString((string) $object['internal_reference']),
 | 
			
		||||
                'external_id'             => $this->clearString((string) $object['external_id']),
 | 
			
		||||
                'original_source'         => sprintf('ff3-v%s', config('firefly.version')),
 | 
			
		||||
                'recurrence_id'           => $this->integerFromValue($object['recurrence_id']),
 | 
			
		||||
                'bunq_payment_id'         => $this->clearString((string) $object['bunq_payment_id']),
 | 
			
		||||
                'external_url'            => $this->clearString((string) $object['external_url']),
 | 
			
		||||
 | 
			
		||||
                'sepa_cc'               => $this->clearString((string) $object['sepa_cc']),
 | 
			
		||||
                'sepa_ct_op'            => $this->clearString((string) $object['sepa_ct_op']),
 | 
			
		||||
                'sepa_ct_id'            => $this->clearString((string) $object['sepa_ct_id']),
 | 
			
		||||
                'sepa_db'               => $this->clearString((string) $object['sepa_db']),
 | 
			
		||||
                'sepa_country'          => $this->clearString((string) $object['sepa_country']),
 | 
			
		||||
                'sepa_ep'               => $this->clearString((string) $object['sepa_ep']),
 | 
			
		||||
                'sepa_ci'               => $this->clearString((string) $object['sepa_ci']),
 | 
			
		||||
                'sepa_batch_id'         => $this->clearString((string) $object['sepa_batch_id']),
 | 
			
		||||
                'sepa_cc'                 => $this->clearString((string) $object['sepa_cc']),
 | 
			
		||||
                'sepa_ct_op'              => $this->clearString((string) $object['sepa_ct_op']),
 | 
			
		||||
                'sepa_ct_id'              => $this->clearString((string) $object['sepa_ct_id']),
 | 
			
		||||
                'sepa_db'                 => $this->clearString((string) $object['sepa_db']),
 | 
			
		||||
                'sepa_country'            => $this->clearString((string) $object['sepa_country']),
 | 
			
		||||
                'sepa_ep'                 => $this->clearString((string) $object['sepa_ep']),
 | 
			
		||||
                'sepa_ci'                 => $this->clearString((string) $object['sepa_ci']),
 | 
			
		||||
                'sepa_batch_id'           => $this->clearString((string) $object['sepa_batch_id']),
 | 
			
		||||
                // custom date fields. Must be Carbon objects. Presence is optional.
 | 
			
		||||
                'interest_date'         => $this->dateFromValue($object['interest_date']),
 | 
			
		||||
                'book_date'             => $this->dateFromValue($object['book_date']),
 | 
			
		||||
                'process_date'          => $this->dateFromValue($object['process_date']),
 | 
			
		||||
                'due_date'              => $this->dateFromValue($object['due_date']),
 | 
			
		||||
                'payment_date'          => $this->dateFromValue($object['payment_date']),
 | 
			
		||||
                'invoice_date'          => $this->dateFromValue($object['invoice_date']),
 | 
			
		||||
                'interest_date'           => $this->dateFromValue($object['interest_date']),
 | 
			
		||||
                'book_date'               => $this->dateFromValue($object['book_date']),
 | 
			
		||||
                'process_date'            => $this->dateFromValue($object['process_date']),
 | 
			
		||||
                'due_date'                => $this->dateFromValue($object['due_date']),
 | 
			
		||||
                'payment_date'            => $this->dateFromValue($object['payment_date']),
 | 
			
		||||
                'invoice_date'            => $this->dateFromValue($object['invoice_date']),
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -171,6 +177,7 @@ class StoreRequest extends FormRequest
 | 
			
		||||
    {
 | 
			
		||||
        app('log')->debug('Collect rules of TransactionStoreRequest');
 | 
			
		||||
        $validProtocols = config('firefly.valid_url_protocols');
 | 
			
		||||
        $locationRules  = Location::requestRules([]);
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            // basic fields for group:
 | 
			
		||||
@@ -178,6 +185,11 @@ class StoreRequest extends FormRequest
 | 
			
		||||
            'error_if_duplicate_hash'              => [new IsBoolean()],
 | 
			
		||||
            'apply_rules'                          => [new IsBoolean()],
 | 
			
		||||
 | 
			
		||||
            // location rules
 | 
			
		||||
            'transactions.*.latitude'              => $locationRules['latitude'],
 | 
			
		||||
            'transactions.*.longitude'             => $locationRules['longitude'],
 | 
			
		||||
            'transactions.*.zoom_level'            => $locationRules['zoom_level'],
 | 
			
		||||
 | 
			
		||||
            // transaction rules (in array for splits):
 | 
			
		||||
            'transactions.*.type'                  => 'required|in:withdrawal,deposit,transfer,opening-balance,reconciliation',
 | 
			
		||||
            'transactions.*.date'                  => ['required', new IsDateOrTime()],
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										65
									
								
								app/Api/V1/Requests/Models/UserGroup/UpdateRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								app/Api/V1/Requests/Models/UserGroup/UpdateRequest.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * UpdateRequest.php
 | 
			
		||||
 * Copyright (c) 2021 james@firefly-iii.org
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V1\Requests\Models\UserGroup;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Models\UserGroup;
 | 
			
		||||
use FireflyIII\Support\Request\ChecksLogin;
 | 
			
		||||
use FireflyIII\Support\Request\ConvertsDataTypes;
 | 
			
		||||
use Illuminate\Foundation\Http\FormRequest;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class UpdateRequest
 | 
			
		||||
 */
 | 
			
		||||
class UpdateRequest extends FormRequest
 | 
			
		||||
{
 | 
			
		||||
    use ChecksLogin;
 | 
			
		||||
    use ConvertsDataTypes;
 | 
			
		||||
 | 
			
		||||
    public function getData(): array
 | 
			
		||||
    {
 | 
			
		||||
        $fields = [
 | 
			
		||||
            'title'                => ['title', 'convertString'],
 | 
			
		||||
            'native_currency_id'   => ['native_currency_id', 'convertInteger'],
 | 
			
		||||
            'native_currency_code' => ['native_currency_code', 'convertString'],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return $this->getAllData($fields);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Rules for this request.
 | 
			
		||||
     */
 | 
			
		||||
    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',
 | 
			
		||||
            'native_currency_code' => 'exists:transaction_currencies,code',
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -57,6 +57,10 @@ class CronRequest extends FormRequest
 | 
			
		||||
        if ($this->has('date')) {
 | 
			
		||||
            $data['date'] = $this->getCarbonDate('date');
 | 
			
		||||
        }
 | 
			
		||||
        // catch NULL.
 | 
			
		||||
        if (null === $data['date']) {
 | 
			
		||||
            $data['date'] = today(config('app.timezone'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $data;
 | 
			
		||||
    }
 | 
			
		||||
@@ -68,7 +72,7 @@ class CronRequest extends FormRequest
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'force' => 'in:true,false',
 | 
			
		||||
            'date'  => 'date',
 | 
			
		||||
            'date'  => 'nullable|date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ class AccountController extends Controller
 | 
			
		||||
                $userGroup        = $this->validateUserGroup($request);
 | 
			
		||||
                $this->repository = app(AccountRepositoryInterface::class);
 | 
			
		||||
                $this->repository->setUserGroup($userGroup);
 | 
			
		||||
                $this->default    = app('amount')->getDefaultCurrency();
 | 
			
		||||
                $this->default    = app('amount')->getNativeCurrency();
 | 
			
		||||
                $this->converter  = app(ExchangeRateConverter::class);
 | 
			
		||||
 | 
			
		||||
                return $next($request);
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\TransactionCurrency;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Chart\ChartData;
 | 
			
		||||
use FireflyIII\Support\Facades\Steam;
 | 
			
		||||
use FireflyIII\Support\Http\Api\CleansChartData;
 | 
			
		||||
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
 | 
			
		||||
@@ -57,7 +58,7 @@ class AccountController extends Controller
 | 
			
		||||
                $this->repository = app(AccountRepositoryInterface::class);
 | 
			
		||||
                $this->repository->setUserGroup($this->validateUserGroup($request));
 | 
			
		||||
                $this->chartData  = new ChartData();
 | 
			
		||||
                $this->default    = app('amount')->getDefaultCurrency();
 | 
			
		||||
                $this->default    = app('amount')->getNativeCurrency();
 | 
			
		||||
 | 
			
		||||
                return $next($request);
 | 
			
		||||
            }
 | 
			
		||||
@@ -118,7 +119,7 @@ class AccountController extends Controller
 | 
			
		||||
            'native_entries'                 => [],
 | 
			
		||||
        ];
 | 
			
		||||
        $currentStart   = clone $params['start'];
 | 
			
		||||
        $range          = app('steam')->finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
 | 
			
		||||
        $range          = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
 | 
			
		||||
 | 
			
		||||
        $previous       = array_values($range)[0]['balance'];
 | 
			
		||||
        $previousNative = array_values($range)[0]['native_balance'];
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,7 @@ class BalanceController extends Controller
 | 
			
		||||
                $this->repository->setUserGroup($userGroup);
 | 
			
		||||
                $this->collector->setUserGroup($userGroup);
 | 
			
		||||
                $this->chartData  = new ChartData();
 | 
			
		||||
                // $this->default    = app('amount')->getDefaultCurrency();
 | 
			
		||||
                // $this->default    = app('amount')->getNativeCurrency();
 | 
			
		||||
 | 
			
		||||
                return $next($request);
 | 
			
		||||
            }
 | 
			
		||||
@@ -87,7 +87,7 @@ class BalanceController extends Controller
 | 
			
		||||
 | 
			
		||||
        // prepare for currency conversion and data collection:
 | 
			
		||||
        /** @var TransactionCurrency $default */
 | 
			
		||||
        $default         = app('amount')->getDefaultCurrency();
 | 
			
		||||
        $default         = app('amount')->getNativeCurrency();
 | 
			
		||||
 | 
			
		||||
        // get journals for entire period:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,7 @@ class BudgetController extends Controller
 | 
			
		||||
                $this->repository    = app(BudgetRepositoryInterface::class);
 | 
			
		||||
                $this->blRepository  = app(BudgetLimitRepositoryInterface::class);
 | 
			
		||||
                $this->opsRepository = app(OperationsRepositoryInterface::class);
 | 
			
		||||
                $this->currency      = app('amount')->getDefaultCurrency();
 | 
			
		||||
                $this->currency      = app('amount')->getNativeCurrency();
 | 
			
		||||
                $userGroup           = $this->validateUserGroup($request);
 | 
			
		||||
                $this->repository->setUserGroup($userGroup);
 | 
			
		||||
                $this->opsRepository->setUserGroup($userGroup);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,10 +27,10 @@ namespace FireflyIII\Api\V2\Controllers\Chart;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use FireflyIII\Api\V2\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V2\Request\Generic\DateRequest;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Http\Api\CleansChartData;
 | 
			
		||||
@@ -70,7 +70,7 @@ class CategoryController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @throws FireflyException
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function dashboard(DateRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
@@ -81,8 +81,8 @@ class CategoryController extends Controller
 | 
			
		||||
 | 
			
		||||
        /** @var Carbon $end */
 | 
			
		||||
        $end        = $this->parameters->get('end');
 | 
			
		||||
        $accounts   = $this->accountRepos->getAccountsByType([AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::ASSET, AccountType::DEFAULT]);
 | 
			
		||||
        $default    = app('amount')->getDefaultCurrency();
 | 
			
		||||
        $accounts   = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]);
 | 
			
		||||
        $default    = app('amount')->getNativeCurrency();
 | 
			
		||||
        $converter  = new ExchangeRateConverter();
 | 
			
		||||
        $currencies = [];
 | 
			
		||||
        $return     = [];
 | 
			
		||||
 
 | 
			
		||||
@@ -47,8 +47,8 @@ use Symfony\Component\HttpFoundation\ParameterBag;
 | 
			
		||||
/**
 | 
			
		||||
 * Class Controller
 | 
			
		||||
 *
 | 
			
		||||
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 | 
			
		||||
 * @SuppressWarnings(PHPMD.NumberOfChildren)
 | 
			
		||||
 * @SuppressWarnings("PHPMD.CouplingBetweenObjects")
 | 
			
		||||
 * @SuppressWarnings("PHPMD.NumberOfChildren")
 | 
			
		||||
 */
 | 
			
		||||
class Controller extends BaseController
 | 
			
		||||
{
 | 
			
		||||
@@ -74,7 +74,7 @@ class Controller extends BaseController
 | 
			
		||||
     * TODO duplicate from V1 controller
 | 
			
		||||
     * Method to grab all parameters from the URL.
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.NPathComplexity)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.NPathComplexity")
 | 
			
		||||
     */
 | 
			
		||||
    private function getParameters(): ParameterBag
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ class SumController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * TODO see autocomplete/accountcontroller for list.
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function paid(DateRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
@@ -74,7 +74,7 @@ class SumController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * TODO see autocomplete/accountcontroller for list.
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function unpaid(DateRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -80,21 +80,21 @@ class StoreController extends Controller
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $transactionGroup = $this->groupRepository->store($data);
 | 
			
		||||
        } catch (DuplicateTransactionException $e) { // @phpstan-ignore-line
 | 
			
		||||
        } catch (DuplicateTransactionException $e) {
 | 
			
		||||
            app('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); // @phpstan-ignore-line
 | 
			
		||||
        } catch (FireflyException $e) { // @phpstan-ignore-line
 | 
			
		||||
            throw new ValidationException($validator);
 | 
			
		||||
        } catch (FireflyException $e) {
 | 
			
		||||
            app('log')->warning('Caught an exception. Return error message.');
 | 
			
		||||
            app('log')->error($e->getMessage());
 | 
			
		||||
            $message   = sprintf('Internal exception: %s', $e->getMessage());
 | 
			
		||||
            $validator = Validator::make(['transactions' => [['description' => $message]]], ['transactions.0.description' => new IsDuplicateTransaction()]);
 | 
			
		||||
 | 
			
		||||
            throw new ValidationException($validator); // @phpstan-ignore-line
 | 
			
		||||
            throw new ValidationException($validator);
 | 
			
		||||
        }
 | 
			
		||||
        app('preferences')->mark();
 | 
			
		||||
        $applyRules         = $data['apply_rules'] ?? true;
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@ class ShowController extends Controller
 | 
			
		||||
            $default = 1 === $group->pivot->group_default;
 | 
			
		||||
        }
 | 
			
		||||
        $currency->userGroupEnabled = $enabled;
 | 
			
		||||
        $currency->userGroupDefault = $default;
 | 
			
		||||
        $currency->userGroupNative  = $default;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $transformer                = new CurrencyTransformer();
 | 
			
		||||
 
 | 
			
		||||
@@ -27,12 +27,12 @@ namespace FireflyIII\Api\V2\Controllers\Summary;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use FireflyIII\Api\V2\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V2\Request\Generic\DateRequest;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
 | 
			
		||||
use FireflyIII\Helpers\Report\NetWorthInterface;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Models\UserGroup;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\Bill\BillRepositoryInterface;
 | 
			
		||||
@@ -94,7 +94,7 @@ class BasicController extends Controller
 | 
			
		||||
     *
 | 
			
		||||
     * @throws \Exception
 | 
			
		||||
     *
 | 
			
		||||
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.UnusedFormalParameter")
 | 
			
		||||
     */
 | 
			
		||||
    public function basic(DateRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
@@ -118,7 +118,7 @@ class BasicController extends Controller
 | 
			
		||||
    private function getBalanceInformation(Carbon $start, Carbon $end): array
 | 
			
		||||
    {
 | 
			
		||||
        $object    = new SummaryBalanceGrouped();
 | 
			
		||||
        $default   = app('amount')->getDefaultCurrency();
 | 
			
		||||
        $default   = app('amount')->getNativeCurrency();
 | 
			
		||||
 | 
			
		||||
        $object->setDefault($default);
 | 
			
		||||
 | 
			
		||||
@@ -222,7 +222,7 @@ class BasicController extends Controller
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.ExcessiveMethodLength")
 | 
			
		||||
     */
 | 
			
		||||
    private function getLeftToSpendInfo(Carbon $start, Carbon $end): array
 | 
			
		||||
    {
 | 
			
		||||
@@ -233,7 +233,7 @@ class BasicController extends Controller
 | 
			
		||||
        $available    = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
 | 
			
		||||
        $budgets      = $this->budgetRepository->getActiveBudgets();
 | 
			
		||||
        $spent        = $this->opsRepository->listExpenses($start, $end, null, $budgets);
 | 
			
		||||
        $default      = app('amount')->getDefaultCurrency();
 | 
			
		||||
        $default      = app('amount')->getNativeCurrency();
 | 
			
		||||
        $currencies   = [];
 | 
			
		||||
        $converter    = new ExchangeRateConverter();
 | 
			
		||||
 | 
			
		||||
@@ -353,7 +353,7 @@ class BasicController extends Controller
 | 
			
		||||
        $netWorthHelper = app(NetWorthInterface::class);
 | 
			
		||||
        $netWorthHelper->setUserGroup($userGroup);
 | 
			
		||||
        $allAccounts    = $this->accountRepository->getActiveAccountsByType(
 | 
			
		||||
            [AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT]
 | 
			
		||||
            [AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::DEBT->value]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // filter list on preference of being included.
 | 
			
		||||
 
 | 
			
		||||
@@ -26,9 +26,9 @@ namespace FireflyIII\Api\V2\Controllers\Summary;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V2\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V2\Request\Generic\SingleDateRequest;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Helpers\Report\NetWorthInterface;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
@@ -67,7 +67,7 @@ class NetWorthController extends Controller
 | 
			
		||||
    public function get(SingleDateRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $date     = $request->getDate();
 | 
			
		||||
        $accounts = $this->repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
 | 
			
		||||
        $accounts = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value]);
 | 
			
		||||
 | 
			
		||||
        // filter list on preference of being included.
 | 
			
		||||
        $filtered = $accounts->filter(
 | 
			
		||||
 
 | 
			
		||||
@@ -24,9 +24,8 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V2\Request\Autocomplete;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Support\Http\Api\AccountFilter;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ParsesQueryFilters;
 | 
			
		||||
use FireflyIII\Support\Request\ChecksLogin;
 | 
			
		||||
use FireflyIII\Support\Request\ConvertsDataTypes;
 | 
			
		||||
use Illuminate\Foundation\Http\FormRequest;
 | 
			
		||||
@@ -39,7 +38,6 @@ class AutocompleteRequest extends FormRequest
 | 
			
		||||
    use AccountFilter;
 | 
			
		||||
    use ChecksLogin;
 | 
			
		||||
    use ConvertsDataTypes;
 | 
			
		||||
    use ParsesQueryFilters;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Loops over all possible query parameters (these are shared over ALL auto complete requests)
 | 
			
		||||
@@ -67,7 +65,7 @@ class AutocompleteRequest extends FormRequest
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // remove 'initial balance' from allowed types. its internal
 | 
			
		||||
        $array['account_types'] = array_diff($array['account_types'], [AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION, AccountType::CREDITCARD]);
 | 
			
		||||
        $array['account_types'] = array_diff($array['account_types'], [AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::RECONCILIATION->value, AccountTypeEnum::CREDITCARD->value]);
 | 
			
		||||
        $array['account_types'] = $this->getAccountTypeParameter($array['account_types']);
 | 
			
		||||
 | 
			
		||||
        return $array;
 | 
			
		||||
 
 | 
			
		||||
@@ -109,8 +109,8 @@ class InfiniteListRequest extends FormRequest
 | 
			
		||||
    public function rules(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'start'     => 'date',
 | 
			
		||||
            'end'       => 'date|after:start',
 | 
			
		||||
            'start'     => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'end'       => 'date|after:start|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            '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',
 | 
			
		||||
            'end'   => 'date|after:start',
 | 
			
		||||
            'start' => 'date|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
            'end'   => 'date|after:start|after:1900-01-01|before:2099-12-31',
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,26 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * SeparateTimezoneCaster.php
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see https://www.gnu.org/licenses/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Casts;
 | 
			
		||||
 
 | 
			
		||||
@@ -21,25 +21,6 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
/*
 | 
			
		||||
 * ConvertDatesToUTC.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see https://www.gnu.org/licenses/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
@@ -55,34 +36,24 @@ class ConvertsDatesToUTC extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The console command description.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $description = 'Convert stored dates to UTC.';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The name and signature of the console command.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $signature   = 'correction:convert-to-utc';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
     */
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
        $this->friendlyWarning('Please do not use this command.');
 | 
			
		||||
        $this->friendlyWarning('Please do not use this command right now.');
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
        // this variable is ALWAYS en_US.
 | 
			
		||||
        // stops phpstan complaining about dead code.
 | 
			
		||||
        if ('en_US' === config('app.fallback_locale')) {
 | 
			
		||||
            return Command::SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * @var string $model
 | 
			
		||||
         * @var array  $fields
 | 
			
		||||
         */
 | 
			
		||||
        foreach (AddTimezonesToDates::$models as $model => $fields) {
 | 
			
		||||
        foreach (CorrectsTimezoneInformation::$models as $model => $fields) {
 | 
			
		||||
            $this->ConvertModeltoUTC($model, $fields);
 | 
			
		||||
        }
 | 
			
		||||
        // tell the system we are now in UTC mode.
 | 
			
		||||
@@ -122,10 +93,10 @@ class ConvertsDatesToUTC extends Command
 | 
			
		||||
        $items->each(
 | 
			
		||||
            function ($item) use ($field, $timezoneField): void {
 | 
			
		||||
                /** @var Carbon $date */
 | 
			
		||||
                $date                   = Carbon::parse($item->{$field}, $item->{$timezoneField});
 | 
			
		||||
                $date                   = Carbon::parse($item->{$field}, $item->{$timezoneField}); // @phpstan-ignore-line
 | 
			
		||||
                $date->setTimezone('UTC');
 | 
			
		||||
                $item->{$field}         = $date->format('Y-m-d H:i:s');
 | 
			
		||||
                $item->{$timezoneField} = 'UTC';
 | 
			
		||||
                $item->{$field}         = $date->format('Y-m-d H:i:s'); // @phpstan-ignore-line
 | 
			
		||||
                $item->{$timezoneField} = 'UTC';                        // @phpstan-ignore-line
 | 
			
		||||
                $item->save();
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 
 | 
			
		||||
@@ -26,9 +26,9 @@ namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Factory\AccountFactory;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Models\Transaction;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use FireflyIII\Models\TransactionType;
 | 
			
		||||
@@ -111,6 +111,8 @@ class CorrectsAccountTypes extends Command
 | 
			
		||||
            $this->friendlyLine(sprintf('Found %d journals that need to be fixed.', $resultSet->count()));
 | 
			
		||||
            foreach ($resultSet as $entry) {
 | 
			
		||||
                app('log')->debug(sprintf('Now fixing journal #%d', $entry->id));
 | 
			
		||||
 | 
			
		||||
                /** @var null|TransactionJournal $journal */
 | 
			
		||||
                $journal = TransactionJournal::find($entry->id);
 | 
			
		||||
                if (null !== $journal) {
 | 
			
		||||
                    $this->inspectJournal($journal);
 | 
			
		||||
@@ -245,18 +247,18 @@ class CorrectsAccountTypes extends Command
 | 
			
		||||
 | 
			
		||||
    private function shouldBeTransfer(string $transactionType, string $sourceType, string $destinationType): bool
 | 
			
		||||
    {
 | 
			
		||||
        return TransactionType::TRANSFER === $transactionType && AccountType::ASSET === $sourceType && $this->isLiability($destinationType);
 | 
			
		||||
        return TransactionTypeEnum::TRANSFER->value === $transactionType && AccountTypeEnum::ASSET->value === $sourceType && $this->isLiability($destinationType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function isLiability(string $destinationType): bool
 | 
			
		||||
    {
 | 
			
		||||
        return AccountType::LOAN === $destinationType || AccountType::DEBT === $destinationType || AccountType::MORTGAGE === $destinationType;
 | 
			
		||||
        return AccountTypeEnum::LOAN->value === $destinationType || AccountTypeEnum::DEBT->value === $destinationType || AccountTypeEnum::MORTGAGE->value === $destinationType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function makeTransfer(TransactionJournal $journal): void
 | 
			
		||||
    {
 | 
			
		||||
        // from an asset to a liability should be a withdrawal:
 | 
			
		||||
        $withdrawal = TransactionType::whereType(TransactionType::WITHDRAWAL)->first();
 | 
			
		||||
        $withdrawal = TransactionType::whereType(TransactionTypeEnum::WITHDRAWAL->value)->first();
 | 
			
		||||
        $journal->transactionType()->associate($withdrawal);
 | 
			
		||||
        $journal->save();
 | 
			
		||||
        $message    = sprintf('Converted transaction #%d from a transfer to a withdrawal.', $journal->id);
 | 
			
		||||
@@ -268,13 +270,13 @@ class CorrectsAccountTypes extends Command
 | 
			
		||||
 | 
			
		||||
    private function shouldBeDeposit(string $transactionType, string $sourceType, string $destinationType): bool
 | 
			
		||||
    {
 | 
			
		||||
        return TransactionType::TRANSFER === $transactionType && $this->isLiability($sourceType) && AccountType::ASSET === $destinationType;
 | 
			
		||||
        return TransactionTypeEnum::TRANSFER->value === $transactionType && $this->isLiability($sourceType) && AccountTypeEnum::ASSET->value === $destinationType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function makeDeposit(TransactionJournal $journal): void
 | 
			
		||||
    {
 | 
			
		||||
        // from a liability to an asset should be a deposit.
 | 
			
		||||
        $deposit = TransactionType::whereType(TransactionType::DEPOSIT)->first();
 | 
			
		||||
        $deposit = TransactionType::whereType(TransactionTypeEnum::DEPOSIT->value)->first();
 | 
			
		||||
        $journal->transactionType()->associate($deposit);
 | 
			
		||||
        $journal->save();
 | 
			
		||||
        $message = sprintf('Converted transaction #%d from a transfer to a deposit.', $journal->id);
 | 
			
		||||
@@ -286,7 +288,7 @@ class CorrectsAccountTypes extends Command
 | 
			
		||||
 | 
			
		||||
    private function shouldGoToExpenseAccount(string $transactionType, string $sourceType, string $destinationType): bool
 | 
			
		||||
    {
 | 
			
		||||
        return TransactionType::WITHDRAWAL === $transactionType && AccountType::ASSET === $sourceType && AccountType::REVENUE === $destinationType;
 | 
			
		||||
        return TransactionTypeEnum::WITHDRAWAL->value === $transactionType && AccountTypeEnum::ASSET->value === $sourceType && AccountTypeEnum::REVENUE->value === $destinationType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function makeExpenseDestination(TransactionJournal $journal, Transaction $destination): void
 | 
			
		||||
@@ -294,7 +296,7 @@ class CorrectsAccountTypes extends Command
 | 
			
		||||
        // withdrawals with a revenue account as destination instead of an expense account.
 | 
			
		||||
        $this->factory->setUser($journal->user);
 | 
			
		||||
        $oldDest = $destination->account;
 | 
			
		||||
        $result  = $this->factory->findOrCreate($destination->account->name, AccountType::EXPENSE);
 | 
			
		||||
        $result  = $this->factory->findOrCreate($destination->account->name, AccountTypeEnum::EXPENSE->value);
 | 
			
		||||
        $destination->account()->associate($result);
 | 
			
		||||
        $destination->save();
 | 
			
		||||
        $message = sprintf(
 | 
			
		||||
@@ -312,7 +314,7 @@ class CorrectsAccountTypes extends Command
 | 
			
		||||
 | 
			
		||||
    private function shouldComeFromRevenueAccount(string $transactionType, string $sourceType, string $destinationType): bool
 | 
			
		||||
    {
 | 
			
		||||
        return TransactionType::DEPOSIT === $transactionType && AccountType::EXPENSE === $sourceType && AccountType::ASSET === $destinationType;
 | 
			
		||||
        return TransactionTypeEnum::DEPOSIT->value === $transactionType && AccountTypeEnum::EXPENSE->value === $sourceType && AccountTypeEnum::ASSET->value === $destinationType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function makeRevenueSource(TransactionJournal $journal, Transaction $source): void
 | 
			
		||||
@@ -320,7 +322,7 @@ class CorrectsAccountTypes extends Command
 | 
			
		||||
        // deposits with an expense account as source instead of a revenue account.
 | 
			
		||||
        // find revenue account.
 | 
			
		||||
        $this->factory->setUser($journal->user);
 | 
			
		||||
        $result    = $this->factory->findOrCreate($source->account->name, AccountType::REVENUE);
 | 
			
		||||
        $result    = $this->factory->findOrCreate($source->account->name, AccountTypeEnum::REVENUE->value);
 | 
			
		||||
        $oldSource = $source->account;
 | 
			
		||||
        $source->account()->associate($result);
 | 
			
		||||
        $source->save();
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Models\AutoBudget;
 | 
			
		||||
use FireflyIII\Models\AvailableBudget;
 | 
			
		||||
use FireflyIII\Models\Bill;
 | 
			
		||||
@@ -33,8 +34,14 @@ use FireflyIII\Models\CurrencyExchangeRate;
 | 
			
		||||
use FireflyIII\Models\PiggyBank;
 | 
			
		||||
use FireflyIII\Models\RecurrenceTransaction;
 | 
			
		||||
use FireflyIII\Models\RuleTrigger;
 | 
			
		||||
use FireflyIII\Models\Transaction;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use FireflyIII\Models\TransactionType;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Facades\Amount;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
class CorrectsAmounts extends Command
 | 
			
		||||
{
 | 
			
		||||
@@ -45,6 +52,8 @@ class CorrectsAmounts extends Command
 | 
			
		||||
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
        // transfers must not have foreign currency info if both accounts have the same currency.
 | 
			
		||||
        $this->correctTransfers();
 | 
			
		||||
        // auto budgets must be positive
 | 
			
		||||
        $this->fixAutoBudgets();
 | 
			
		||||
        // available budgets must be positive
 | 
			
		||||
@@ -62,6 +71,7 @@ class CorrectsAmounts extends Command
 | 
			
		||||
        // rule_triggers must be positive or zero (amount_less, amount_more, amount_is)
 | 
			
		||||
        $this->fixRuleTriggers();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -182,4 +192,63 @@ class CorrectsAmounts extends Command
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function correctTransfers(): void
 | 
			
		||||
    {
 | 
			
		||||
        /** @var AccountRepositoryInterface $repository */
 | 
			
		||||
        $repository = app(AccountRepositoryInterface::class);
 | 
			
		||||
        $type       = TransactionType::where('type', TransactionTypeEnum::TRANSFER->value)->first();
 | 
			
		||||
        $journals   = TransactionJournal::where('transaction_type_id', $type->id)->get();
 | 
			
		||||
 | 
			
		||||
        /** @var TransactionJournal $journal */
 | 
			
		||||
        foreach ($journals as $journal) {
 | 
			
		||||
            $repository->setUser($journal->user);
 | 
			
		||||
            $native         = Amount::getNativeCurrencyByUserGroup($journal->userGroup);
 | 
			
		||||
 | 
			
		||||
            /** @var null|Transaction $source */
 | 
			
		||||
            $source         = $journal->transactions()->where('amount', '<', 0)->first();
 | 
			
		||||
 | 
			
		||||
            /** @var null|Transaction $destination */
 | 
			
		||||
            $destination    = $journal->transactions()->where('amount', '>', 0)->first();
 | 
			
		||||
            if (null === $source || null === $destination) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if (null === $source->foreign_currency_id || null === $destination->foreign_currency_id) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            $sourceAccount  = $source->account;
 | 
			
		||||
            $destAccount    = $destination->account;
 | 
			
		||||
            if (null === $sourceAccount || null === $destAccount) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            $sourceCurrency = $repository->getAccountCurrency($sourceAccount) ?? $native;
 | 
			
		||||
            $destCurrency   = $repository->getAccountCurrency($destAccount) ?? $native;
 | 
			
		||||
 | 
			
		||||
            if ($sourceCurrency->id === $destCurrency->id) {
 | 
			
		||||
                Log::debug('Both accounts have the same currency. Removing foreign currency info.');
 | 
			
		||||
                $source->foreign_currency_id      = null;
 | 
			
		||||
                $source->foreign_amount           = null;
 | 
			
		||||
                $source->save();
 | 
			
		||||
                $destination->foreign_currency_id = null;
 | 
			
		||||
                $destination->foreign_amount      = null;
 | 
			
		||||
                $destination->save();
 | 
			
		||||
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // validate source
 | 
			
		||||
            if ($destCurrency->id !== $source->foreign_currency_id) {
 | 
			
		||||
                Log::debug(sprintf('Journal #%d: Transaction #%d refers to "%s" but should refer to "%s".', $journal->id, $source->id, $source->foreignCurrency->code, $destCurrency->code));
 | 
			
		||||
                $source->foreign_currency_id = $destCurrency->id;
 | 
			
		||||
                $source->save();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // validate destination:
 | 
			
		||||
            if ($sourceCurrency->id !== $destination->foreign_currency_id) {
 | 
			
		||||
                Log::debug(sprintf('Journal #%d: Transaction #%d refers to "%s" but should refer to "%s".', $journal->id, $destination->id, $destination->foreignCurrency->code, $sourceCurrency->code));
 | 
			
		||||
                $destination->foreign_currency_id = $sourceCurrency->id;
 | 
			
		||||
                $destination->save();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,7 @@ class CorrectsCurrencies extends Command
 | 
			
		||||
        $repos           = app(CurrencyRepositoryInterface::class);
 | 
			
		||||
 | 
			
		||||
        // first check if the user has any default currency (not necessarily the case, so can be forced).
 | 
			
		||||
        $defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($userGroup);
 | 
			
		||||
        $defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($userGroup);
 | 
			
		||||
 | 
			
		||||
        Log::debug(sprintf('Now correcting currencies for user group #%d', $userGroup->id));
 | 
			
		||||
        $found           = [$defaultCurrency->id];
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Models\Preference;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
@@ -73,7 +73,7 @@ class CorrectsFrontpageAccounts extends Command
 | 
			
		||||
                $accountIdInt = (int) $accountId;
 | 
			
		||||
                $account      = $repository->find($accountIdInt);
 | 
			
		||||
                if (null !== $account
 | 
			
		||||
                    && in_array($account->accountType->type, [AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE], true)
 | 
			
		||||
                    && in_array($account->accountType->type, [AccountTypeEnum::ASSET->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value], true)
 | 
			
		||||
                    && true === $account->active) {
 | 
			
		||||
                    $fixed[] = $account->id;
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -25,8 +25,8 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
 | 
			
		||||
@@ -78,14 +78,14 @@ class CorrectsIbans extends Command
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            $type   = $account->accountType->type;
 | 
			
		||||
            if (in_array($type, [AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], true)) {
 | 
			
		||||
            if (in_array($type, [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value], true)) {
 | 
			
		||||
                $type = 'liabilities';
 | 
			
		||||
            }
 | 
			
		||||
            if (array_key_exists($iban, $set[$userId])) {
 | 
			
		||||
                // iban already in use! two exceptions exist:
 | 
			
		||||
                if (
 | 
			
		||||
                    !(AccountType::EXPENSE === $set[$userId][$iban] && AccountType::REVENUE === $type) // allowed combination
 | 
			
		||||
                    && !(AccountType::REVENUE === $set[$userId][$iban] && AccountType::EXPENSE === $type) // also allowed combination.
 | 
			
		||||
                    !(AccountTypeEnum::EXPENSE->value === $set[$userId][$iban] && AccountTypeEnum::REVENUE->value === $type) // allowed combination
 | 
			
		||||
                    && !(AccountTypeEnum::REVENUE->value === $set[$userId][$iban] && AccountTypeEnum::EXPENSE->value === $type) // also allowed combination.
 | 
			
		||||
                ) {
 | 
			
		||||
                    $this->friendlyWarning(
 | 
			
		||||
                        sprintf(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * RecalculateNativeAmounts.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 * CorrectsNativeAmounts.php
 | 
			
		||||
 * Copyright (c) 2025 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -21,6 +21,8 @@ declare(strict_types=1);
 | 
			
		||||
 * along with this program.  If not, see https://www.gnu.org/licenses/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
@@ -59,7 +61,7 @@ class CorrectsNativeAmounts extends Command
 | 
			
		||||
     */
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
        if (!config('cer.enabled')) {
 | 
			
		||||
        if (false === config('cer.enabled')) {
 | 
			
		||||
            $this->friendlyInfo('This command will not run because currency exchange rates are disabled.');
 | 
			
		||||
 | 
			
		||||
            return 0;
 | 
			
		||||
@@ -86,7 +88,7 @@ class CorrectsNativeAmounts extends Command
 | 
			
		||||
 | 
			
		||||
        // do a check with the group's currency so we can skip some stuff.
 | 
			
		||||
        Preferences::mark();
 | 
			
		||||
        $currency = app('amount')->getDefaultCurrencyByUserGroup($userGroup);
 | 
			
		||||
        $currency = app('amount')->getNativeCurrencyByUserGroup($userGroup);
 | 
			
		||||
 | 
			
		||||
        $this->recalculatePiggyBanks($userGroup, $currency);
 | 
			
		||||
        $this->recalculateBudgets($userGroup, $currency);
 | 
			
		||||
@@ -100,7 +102,14 @@ class CorrectsNativeAmounts extends Command
 | 
			
		||||
    {
 | 
			
		||||
        $set = $userGroup->accounts()->where(function (EloquentBuilder $q): void {
 | 
			
		||||
            $q->whereNotNull('virtual_balance');
 | 
			
		||||
            $q->orWhere('virtual_balance', '!=', '');
 | 
			
		||||
 | 
			
		||||
            // this needs a different piece of code for postgres.
 | 
			
		||||
            if ('pgsql' === config('database.default')) {
 | 
			
		||||
                $q->orWhere(DB::raw('CAST(virtual_balance AS TEXT)'), '!=', '');
 | 
			
		||||
            }
 | 
			
		||||
            if ('pgsql' !== config('database.default')) {
 | 
			
		||||
                $q->orWhere('virtual_balance', '!=', '');
 | 
			
		||||
            }
 | 
			
		||||
        })->get();
 | 
			
		||||
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
@@ -144,7 +153,7 @@ class CorrectsNativeAmounts extends Command
 | 
			
		||||
    {
 | 
			
		||||
        $set = $piggyBank->piggyBankEvents()->get();
 | 
			
		||||
        $set->each(
 | 
			
		||||
            static function (PiggyBankEvent $event): void {
 | 
			
		||||
            static function (PiggyBankEvent $event): void { // @phpstan-ignore-line
 | 
			
		||||
                $event->touch();
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@@ -216,7 +225,6 @@ class CorrectsNativeAmounts extends Command
 | 
			
		||||
        $set                              = DB::table('transactions')
 | 
			
		||||
            ->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
 | 
			
		||||
            ->where('transaction_journals.user_group_id', $userGroup->id)
 | 
			
		||||
 | 
			
		||||
            ->where(function (DatabaseBuilder $q1) use ($currency): void {
 | 
			
		||||
                $q1->where(function (DatabaseBuilder $q2) use ($currency): void {
 | 
			
		||||
                    $q2->whereNot('transactions.transaction_currency_id', $currency->id)->whereNull('transactions.foreign_currency_id');
 | 
			
		||||
@@ -234,8 +242,9 @@ class CorrectsNativeAmounts extends Command
 | 
			
		||||
        TransactionObserver::$recalculate = false;
 | 
			
		||||
        foreach ($set as $item) {
 | 
			
		||||
            // here we are.
 | 
			
		||||
            /** @var null|Transaction $transaction */
 | 
			
		||||
            $transaction = Transaction::find($item->id);
 | 
			
		||||
            $transaction->touch();
 | 
			
		||||
            $transaction?->touch();
 | 
			
		||||
        }
 | 
			
		||||
        TransactionObserver::$recalculate = true;
 | 
			
		||||
        Log::debug(sprintf('Recalculated %d transactions.', $set->count()));
 | 
			
		||||
 
 | 
			
		||||
@@ -25,12 +25,12 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Models\Transaction;
 | 
			
		||||
use FireflyIII\Models\TransactionCurrency;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use FireflyIII\Models\TransactionType;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
@@ -65,10 +65,10 @@ class CorrectsOpeningBalanceCurrencies extends Command
 | 
			
		||||
 | 
			
		||||
    private function getJournals(): Collection
 | 
			
		||||
    {
 | 
			
		||||
        // @var Collection
 | 
			
		||||
        /** @var Collection */
 | 
			
		||||
        return TransactionJournal::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
 | 
			
		||||
            ->whereNull('transaction_journals.deleted_at')
 | 
			
		||||
            ->where('transaction_types.type', TransactionType::OPENING_BALANCE)->get(['transaction_journals.*'])
 | 
			
		||||
            ->where('transaction_types.type', TransactionTypeEnum::OPENING_BALANCE->value)->get(['transaction_journals.*'])
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -96,7 +96,7 @@ class CorrectsOpeningBalanceCurrencies extends Command
 | 
			
		||||
        foreach ($transactions as $transaction) {
 | 
			
		||||
            /** @var null|Account $account */
 | 
			
		||||
            $account = $transaction->account()->first();
 | 
			
		||||
            if (null !== $account && AccountType::INITIAL_BALANCE !== $account->accountType()->first()->type) {
 | 
			
		||||
            if (null !== $account && AccountTypeEnum::INITIAL_BALANCE->value !== $account->accountType()->first()->type) {
 | 
			
		||||
                return $account;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -132,6 +132,6 @@ class CorrectsOpeningBalanceCurrencies extends Command
 | 
			
		||||
        $repos = app(AccountRepositoryInterface::class);
 | 
			
		||||
        $repos->setUser($account->user);
 | 
			
		||||
 | 
			
		||||
        return $repos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->userGroup);
 | 
			
		||||
        return $repos->getAccountCurrency($account) ?? app('amount')->getNativeCurrencyByUserGroup($account->userGroup);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user