mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-11-04 05:15:39 +00:00 
			
		
		
		
	Compare commits
	
		
			174 Commits
		
	
	
		
			branch-v6.
			...
			develop-20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					b4c67c02a7 | ||
| 
						 | 
					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 | ||
| 
						 | 
					b58d809063 | ||
| 
						 | 
					9e34314dbc | ||
| 
						 | 
					e4aa218b5f | ||
| 
						 | 
					31722477d4 | ||
| 
						 | 
					ec82105433 | ||
| 
						 | 
					146e164f04 | ||
| 
						 | 
					7d37c93988 | ||
| 
						 | 
					73dffacd9a | ||
| 
						 | 
					d37304fa68 | ||
| 
						 | 
					62f4da6063 | ||
| 
						 | 
					760da08ab7 | ||
| 
						 | 
					e68c4d4408 | ||
| 
						 | 
					46a200aa1f | ||
| 
						 | 
					c422039335 | ||
| 
						 | 
					0579c8565d | ||
| 
						 | 
					9f25880a59 | ||
| 
						 | 
					05f1819f7d | ||
| 
						 | 
					fa2149f957 | ||
| 
						 | 
					c21a79e029 | ||
| 
						 | 
					03e31ebb5e | ||
| 
						 | 
					3c20e5f3af | ||
| 
						 | 
					9a9dd9e075 | ||
| 
						 | 
					7189986c03 | ||
| 
						 | 
					b407d8d315 | ||
| 
						 | 
					41fa2a6208 | ||
| 
						 | 
					fe00c4c373 | ||
| 
						 | 
					7248a76c63 | ||
| 
						 | 
					ee3c618797 | ||
| 
						 | 
					a1241ebedb | ||
| 
						 | 
					af78d998db | ||
| 
						 | 
					d96c235ffe | ||
| 
						 | 
					79ca1b5f4e | ||
| 
						 | 
					0f68735e1c | ||
| 
						 | 
					82abee37de | ||
| 
						 | 
					507040f1fd | ||
| 
						 | 
					42dc8486e9 | ||
| 
						 | 
					6c655634bc | ||
| 
						 | 
					f2166b97b8 | ||
| 
						 | 
					da88e02be0 | ||
| 
						 | 
					0d56b7d251 | ||
| 
						 | 
					0a089efcac | ||
| 
						 | 
					89ab360391 | ||
| 
						 | 
					2bd97d9a99 | ||
| 
						 | 
					103b9056e4 | ||
| 
						 | 
					23c4352c18 | ||
| 
						 | 
					2dddaa36d5 | ||
| 
						 | 
					8ab7cf2388 | ||
| 
						 | 
					f191086adb | ||
| 
						 | 
					68b446db18 | ||
| 
						 | 
					3d49d81856 | ||
| 
						 | 
					96493425d1 | ||
| 
						 | 
					419975285c | ||
| 
						 | 
					aa5bde122e | ||
| 
						 | 
					0fa3c2bd8d | ||
| 
						 | 
					b9249a4d96 | ||
| 
						 | 
					6638ca270f | ||
| 
						 | 
					9bfef892f8 | ||
| 
						 | 
					32e5efec7c | ||
| 
						 | 
					36457455ca | ||
| 
						 | 
					062c148e43 | ||
| 
						 | 
					2314ce8004 | ||
| 
						 | 
					a3ff73903a | ||
| 
						 | 
					7c8445707e | ||
| 
						 | 
					291e73da4b | ||
| 
						 | 
					286a29ca3e | ||
| 
						 | 
					71cf6c6a5e | ||
| 
						 | 
					1e8f0adaf8 | ||
| 
						 | 
					33531244aa | ||
| 
						 | 
					06049a9a28 | ||
| 
						 | 
					d313f5fdf5 | ||
| 
						 | 
					f4868126c1 | ||
| 
						 | 
					00147e98dd | ||
| 
						 | 
					6d22663ca2 | ||
| 
						 | 
					756bb9cf5e | ||
| 
						 | 
					399d7968f5 | ||
| 
						 | 
					966b68f42e | ||
| 
						 | 
					134c551c12 | ||
| 
						 | 
					9aeca15355 | ||
| 
						 | 
					6c6d31830b | ||
| 
						 | 
					5971d155ef | ||
| 
						 | 
					cea52c0ac7 | ||
| 
						 | 
					1b33ff9c25 | ||
| 
						 | 
					594ba205bb | ||
| 
						 | 
					495f5c71c3 | ||
| 
						 | 
					7e80f607b7 | ||
| 
						 | 
					d93732e451 | ||
| 
						 | 
					1b57bc7889 | ||
| 
						 | 
					9e373a9b0d | ||
| 
						 | 
					4fb61646b4 | ||
| 
						 | 
					e2f1fc307f | 
@@ -29,7 +29,7 @@ $paths = [
 | 
			
		||||
    $current . '/../../database',
 | 
			
		||||
    $current . '/../../routes',
 | 
			
		||||
    $current . '/../../tests',
 | 
			
		||||
    $current . '/../../resources/lang',
 | 
			
		||||
    $current . '/../../resources/lang/en_US',
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
$finder = PhpCsFixer\Finder::create()
 | 
			
		||||
@@ -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'],
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								.ci/php-cs-fixer/composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										102
									
								
								.ci/php-cs-fixer/composer.lock
									
									
									
										generated
									
									
									
								
							@@ -406,16 +406,16 @@
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "friendsofphp/php-cs-fixer",
 | 
			
		||||
            "version": "v3.65.0",
 | 
			
		||||
            "version": "v3.66.0",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
 | 
			
		||||
                "reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f"
 | 
			
		||||
                "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/79d4f3e77b250a7d8043d76c6af8f0695e8a469f",
 | 
			
		||||
                "reference": "79d4f3e77b250a7d8043d76c6af8f0695e8a469f",
 | 
			
		||||
                "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/5f5f2a142ff36b93c41885bca29cc5f861c013e6",
 | 
			
		||||
                "reference": "5f5f2a142ff36b93c41885bca29cc5f861c013e6",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -441,7 +441,7 @@
 | 
			
		||||
                "symfony/polyfill-mbstring": "^1.28",
 | 
			
		||||
                "symfony/polyfill-php80": "^1.28",
 | 
			
		||||
                "symfony/polyfill-php81": "^1.28",
 | 
			
		||||
                "symfony/process": "^5.4 || ^6.0 || ^7.0",
 | 
			
		||||
                "symfony/process": "^5.4 || ^6.0 || ^7.0 <7.2",
 | 
			
		||||
                "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
@@ -497,7 +497,7 @@
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
 | 
			
		||||
                "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.65.0"
 | 
			
		||||
                "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.66.0"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
@@ -505,7 +505,7 @@
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2024-11-25T00:39:24+00:00"
 | 
			
		||||
            "time": "2024-12-29T13:46:23+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "psr/container",
 | 
			
		||||
@@ -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",
 | 
			
		||||
@@ -1369,12 +1365,12 @@
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "url": "https://github.com/symfony/contracts",
 | 
			
		||||
                    "name": "symfony/contracts"
 | 
			
		||||
                },
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-main": "3.5-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/contracts",
 | 
			
		||||
                    "url": "https://github.com/symfony/contracts"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
@@ -1517,12 +1513,12 @@
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "url": "https://github.com/symfony/contracts",
 | 
			
		||||
                    "name": "symfony/contracts"
 | 
			
		||||
                },
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-main": "3.5-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/contracts",
 | 
			
		||||
                    "url": "https://github.com/symfony/contracts"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
@@ -1641,16 +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.2.0",
 | 
			
		||||
            "version": "v7.1.8",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/process.git",
 | 
			
		||||
                "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e"
 | 
			
		||||
                "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/process/zipball/d34b22ba9390ec19d2dd966c40aa9e8462f27a7e",
 | 
			
		||||
                "reference": "d34b22ba9390ec19d2dd966c40aa9e8462f27a7e",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/process/zipball/42783370fda6e538771f7c7a36e9fa2ee3a84892",
 | 
			
		||||
                "reference": "42783370fda6e538771f7c7a36e9fa2ee3a84892",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
@@ -2287,7 +2283,7 @@
 | 
			
		||||
            "description": "Executes commands in sub-processes",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "support": {
 | 
			
		||||
                "source": "https://github.com/symfony/process/tree/v7.2.0"
 | 
			
		||||
                "source": "https://github.com/symfony/process/tree/v7.1.8"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
@@ -2303,7 +2299,7 @@
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2024-11-06T14:24:19+00:00"
 | 
			
		||||
            "time": "2024-11-06T14:23:19+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/service-contracts",
 | 
			
		||||
@@ -2329,12 +2325,12 @@
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "url": "https://github.com/symfony/contracts",
 | 
			
		||||
                    "name": "symfony/contracts"
 | 
			
		||||
                },
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-main": "3.5-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/contracts",
 | 
			
		||||
                    "url": "https://github.com/symfony/contracts"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
@@ -2390,16 +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=$?
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										115
									
								
								.ci/phpstan.neon
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								.ci/phpstan.neon
									
									
									
									
									
								
							@@ -1,61 +1,76 @@
 | 
			
		||||
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: 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#'
 | 
			
		||||
    # - '#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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  # 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.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										77
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										77
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -10,7 +10,7 @@ on:
 | 
			
		||||
      phpversion:
 | 
			
		||||
        description: 'PHP version'
 | 
			
		||||
        required: true
 | 
			
		||||
        default: '8.3'
 | 
			
		||||
        default: '8.4'
 | 
			
		||||
  schedule:
 | 
			
		||||
    - cron: '0 3 * * MON'
 | 
			
		||||
 | 
			
		||||
@@ -168,7 +168,7 @@ jobs:
 | 
			
		||||
 | 
			
		||||
          # if this is a develop build, slightly different variable names.
 | 
			
		||||
          if [[ "develop" == "$version" ]]; then
 | 
			
		||||
            [[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
 | 
			
		||||
            #[[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
 | 
			
		||||
            releaseName=$version-$(date +'%Y%m%d')
 | 
			
		||||
            originalName=$releaseName
 | 
			
		||||
            zipName=FireflyIII-develop.zip
 | 
			
		||||
@@ -177,7 +177,7 @@ jobs:
 | 
			
		||||
 | 
			
		||||
          # if this is a branch build, also slightly different variable names.
 | 
			
		||||
          if [[ "$version" == branch* ]]; then
 | 
			
		||||
            [[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
 | 
			
		||||
            #[[ -z $(git status --untracked-files=normal --porcelain) ]] && echo "this branch is clean, no need to push..." && exit 0;
 | 
			
		||||
            # branch builds overrule develop
 | 
			
		||||
            releaseName=$version-$(date +'%Y%m%d')
 | 
			
		||||
            originalName=$releaseName
 | 
			
		||||
@@ -229,7 +229,7 @@ jobs:
 | 
			
		||||
          # describe the development release.
 | 
			
		||||
          if [[ "develop" == "$version" ]]; then
 | 
			
		||||
            echo 'Develop release.'
 | 
			
		||||
            rm output.txt
 | 
			
		||||
            rm -f output.txt
 | 
			
		||||
            touch output.txt
 | 
			
		||||
            sudo chown -R runner:docker output.txt
 | 
			
		||||
            echo "Weekly development release of Firefly III with the latest fixes, translations and features. Docker users can find this release under the \`develop\` tag." >> output.txt
 | 
			
		||||
@@ -244,7 +244,7 @@ jobs:
 | 
			
		||||
          # describe a branch release
 | 
			
		||||
          if [[ "$version" == branch* ]]; then
 | 
			
		||||
            echo 'Branch release.'
 | 
			
		||||
            rm output.txt
 | 
			
		||||
            rm -f output.txt
 | 
			
		||||
            touch output.txt
 | 
			
		||||
            sudo chown -R runner:docker output.txt
 | 
			
		||||
            echo "Irregular BRANCH release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
 | 
			
		||||
@@ -257,9 +257,45 @@ jobs:
 | 
			
		||||
            echo ":warning: Please be careful with this branch pre-release, as it may not work as expected." >> output.txt
 | 
			
		||||
          fi
 | 
			
		||||
          # describe the main release
 | 
			
		||||
          if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]]; then
 | 
			
		||||
            sudo chown -R runner:docker output.txt
 | 
			
		||||
          if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]] && [[ "$version" != *alpha* ]] && [[ "$version" != *beta* ]]; then
 | 
			
		||||
            echo 'Main release.'
 | 
			
		||||
            sudo chown -R runner:docker output.txt
 | 
			
		||||
            echo '' >> output.txt
 | 
			
		||||
            echo '### Instructions' >> output.txt
 | 
			
		||||
            echo '' >> output.txt
 | 
			
		||||
            echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
 | 
			
		||||
            echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
 | 
			
		||||
            echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
 | 
			
		||||
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
          # describe alpha release
 | 
			
		||||
          if [[ "$version" == *alpha* ]]; then
 | 
			
		||||
            echo 'ALPHA release.'
 | 
			
		||||
            rm -f output.txt
 | 
			
		||||
            touch output.txt
 | 
			
		||||
            sudo chown -R runner:docker output.txt
 | 
			
		||||
            echo "Very early ALPHA release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
 | 
			
		||||
            echo '' >> output.txt
 | 
			
		||||
            echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
 | 
			
		||||
            echo '' >> output.txt
 | 
			
		||||
            echo '### Instructions' >> output.txt
 | 
			
		||||
            echo '' >> output.txt
 | 
			
		||||
            echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
 | 
			
		||||
            echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
 | 
			
		||||
            echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
 | 
			
		||||
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
          # describe beta release
 | 
			
		||||
          if [[ "$version" == *beta* ]]; then
 | 
			
		||||
            echo 'BETA release.'
 | 
			
		||||
            rm -f output.txt
 | 
			
		||||
            touch output.txt
 | 
			
		||||
            sudo chown -R runner:docker output.txt
 | 
			
		||||
            echo "Very early BETA release of Firefly III. This release contains specific features or changes. Docker users can find this release under the \`$version\` tag." >> output.txt
 | 
			
		||||
            echo '' >> output.txt
 | 
			
		||||
            echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
 | 
			
		||||
            echo '' >> output.txt
 | 
			
		||||
            echo '### Instructions' >> output.txt
 | 
			
		||||
            echo '' >> output.txt
 | 
			
		||||
@@ -278,6 +314,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
 | 
			
		||||
 | 
			
		||||
@@ -291,6 +328,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
 | 
			
		||||
 | 
			
		||||
@@ -316,7 +354,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
 | 
			
		||||
@@ -336,12 +385,12 @@ jobs:
 | 
			
		||||
            gh release upload $releaseName HEAD.txt
 | 
			
		||||
 | 
			
		||||
            # remove all temporary files
 | 
			
		||||
            rm output.txt
 | 
			
		||||
            rm HEAD.txt
 | 
			
		||||
            rm $zipName
 | 
			
		||||
            rm $zipName.sha256
 | 
			
		||||
            rm $tarName
 | 
			
		||||
            rm $tarName.sha256
 | 
			
		||||
            rm -f output.txt
 | 
			
		||||
            rm -f HEAD.txt
 | 
			
		||||
            rm -f $zipName
 | 
			
		||||
            rm -f $zipName.sha256
 | 
			
		||||
            rm -f $tarName
 | 
			
		||||
            rm -f $tarName.sha256
 | 
			
		||||
 | 
			
		||||
            # merge main back into develop
 | 
			
		||||
            git checkout develop
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								.github/workflows/sonarcloud.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.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
 | 
			
		||||
@@ -19,7 +19,7 @@ jobs:
 | 
			
		||||
      - name: Setup PHP with Xdebug
 | 
			
		||||
        uses: shivammathur/setup-php@v2
 | 
			
		||||
        with:
 | 
			
		||||
          php-version: '8.3'
 | 
			
		||||
          php-version: '8.4'
 | 
			
		||||
          coverage: xdebug
 | 
			
		||||
          extensions: >-
 | 
			
		||||
            bcmath
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@ Over time, many people have contributed to Firefly III. Their efforts are not al
 | 
			
		||||
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
 | 
			
		||||
 | 
			
		||||
## 2024
 | 
			
		||||
- Sobuno
 | 
			
		||||
- TasneemTantawy
 | 
			
		||||
- Antônio Franco
 | 
			
		||||
- yparitcher
 | 
			
		||||
- Jhon Pedroza
 | 
			
		||||
 
 | 
			
		||||
@@ -26,9 +26,9 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Facades\Steam;
 | 
			
		||||
use FireflyIII\Support\Http\Api\AccountFilter;
 | 
			
		||||
@@ -62,7 +62,7 @@ class AccountController extends Controller
 | 
			
		||||
                return $next($request);
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
        $this->balanceTypes = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
 | 
			
		||||
        $this->balanceTypes = [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -74,27 +74,27 @@ class AccountController extends Controller
 | 
			
		||||
     */
 | 
			
		||||
    public function accounts(AutocompleteRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $data            = $request->getData();
 | 
			
		||||
        $types           = $data['types'];
 | 
			
		||||
        $query           = $data['query'];
 | 
			
		||||
        $date            = $data['date'] ?? today(config('app.timezone'));
 | 
			
		||||
        $return          = [];
 | 
			
		||||
        $result          = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
 | 
			
		||||
 | 
			
		||||
        // TODO this code is duplicated in the V2 Autocomplete controller, which means this code is due to be deprecated.
 | 
			
		||||
        $defaultCurrency = app('amount')->getDefaultCurrency();
 | 
			
		||||
        $data   = $request->getData();
 | 
			
		||||
        $types  = $data['types'];
 | 
			
		||||
        $query  = $data['query'];
 | 
			
		||||
        $date   = $data['date'] ?? today(config('app.timezone'));
 | 
			
		||||
        $return = [];
 | 
			
		||||
        $result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
 | 
			
		||||
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        foreach ($result as $account) {
 | 
			
		||||
            $nameWithBalance = $account->name;
 | 
			
		||||
            $currency        = $this->repository->getAccountCurrency($account) ?? $defaultCurrency;
 | 
			
		||||
 | 
			
		||||
            $currency        = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
 | 
			
		||||
            $useCurrency     = $currency;
 | 
			
		||||
            if (in_array($account->accountType->type, $this->balanceTypes, true)) {
 | 
			
		||||
                $balance         = Steam::finalAccountBalance($account, $date);
 | 
			
		||||
                $key             = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
 | 
			
		||||
                $useCurrency     = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? $this->defaultCurrency : $currency;
 | 
			
		||||
                $amount          = $balance[$key] ?? '0';
 | 
			
		||||
                $nameWithBalance = sprintf(
 | 
			
		||||
                    '%s (%s)',
 | 
			
		||||
                    $account->name,
 | 
			
		||||
                    app('amount')->formatAnything($currency, $balance['balance'], false)
 | 
			
		||||
                    app('amount')->formatAnything($useCurrency, $amount, false)
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -103,11 +103,11 @@ class AccountController extends Controller
 | 
			
		||||
                'name'                    => $account->name,
 | 
			
		||||
                'name_with_balance'       => $nameWithBalance,
 | 
			
		||||
                'type'                    => $account->accountType->type,
 | 
			
		||||
                'currency_id'             => (string) $currency->id,
 | 
			
		||||
                'currency_name'           => $currency->name,
 | 
			
		||||
                'currency_code'           => $currency->code,
 | 
			
		||||
                'currency_symbol'         => $currency->symbol,
 | 
			
		||||
                'currency_decimal_places' => $currency->decimal_places,
 | 
			
		||||
                'currency_id'             => (string) $useCurrency->id,
 | 
			
		||||
                'currency_name'           => $useCurrency->name,
 | 
			
		||||
                'currency_code'           => $useCurrency->code,
 | 
			
		||||
                'currency_symbol'         => $useCurrency->symbol,
 | 
			
		||||
                'currency_decimal_places' => $useCurrency->decimal_places,
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -115,7 +115,7 @@ class AccountController extends Controller
 | 
			
		||||
        usort(
 | 
			
		||||
            $return,
 | 
			
		||||
            static function (array $left, array $right) {
 | 
			
		||||
                $order = [AccountType::ASSET, AccountType::REVENUE, AccountType::EXPENSE];
 | 
			
		||||
                $order = [AccountTypeEnum::ASSET->value, AccountTypeEnum::REVENUE->value, AccountTypeEnum::EXPENSE->value];
 | 
			
		||||
                $posA  = (int) array_search($left['type'], $order, true);
 | 
			
		||||
                $posB  = (int) array_search($right['type'], $order, true);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,9 +27,9 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Data\DateRequest;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Models\Preference;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ApiSupport;
 | 
			
		||||
@@ -81,11 +81,10 @@ class AccountController extends Controller
 | 
			
		||||
        $end        = $dates['end'];
 | 
			
		||||
 | 
			
		||||
        // user's preferences
 | 
			
		||||
        $defaultSet = $this->repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray();
 | 
			
		||||
        $defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
 | 
			
		||||
 | 
			
		||||
        /** @var Preference $frontpage */
 | 
			
		||||
        $frontpage  = app('preferences')->get('frontpageAccounts', $defaultSet);
 | 
			
		||||
        $default    = app('amount')->getDefaultCurrency();
 | 
			
		||||
 | 
			
		||||
        if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) {
 | 
			
		||||
            $frontpage->data = $defaultSet;
 | 
			
		||||
@@ -98,10 +97,8 @@ class AccountController extends Controller
 | 
			
		||||
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        foreach ($accounts as $account) {
 | 
			
		||||
            $currency     = $this->repository->getAccountCurrency($account);
 | 
			
		||||
            if (null === $currency) {
 | 
			
		||||
                $currency = $default;
 | 
			
		||||
            }
 | 
			
		||||
            $currency     = $this->repository->getAccountCurrency($account) ?? $this->defaultCurrency;
 | 
			
		||||
            $field        = $this->convertToNative && $currency->id !== $this->defaultCurrency->id ? 'native_balance' : 'balance';
 | 
			
		||||
            $currentSet   = [
 | 
			
		||||
                'label'                   => $account->name,
 | 
			
		||||
                'currency_id'             => (string) $currency->id,
 | 
			
		||||
@@ -116,13 +113,12 @@ 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);
 | 
			
		||||
            // 2022-10-11 this method no longer converts to float.
 | 
			
		||||
            $previous     = array_values($range)[0];
 | 
			
		||||
            $range        = app('steam')->finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
 | 
			
		||||
            $previous     = array_values($range)[0][$field];
 | 
			
		||||
            while ($currentStart <= $end) {
 | 
			
		||||
                $format                        = $currentStart->format('Y-m-d');
 | 
			
		||||
                $label                         = $currentStart->toAtomString();
 | 
			
		||||
                $balance                       = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous;
 | 
			
		||||
                $balance                       = array_key_exists($format, $range) ? $range[$format][$field] : $previous;
 | 
			
		||||
                $previous                      = $balance;
 | 
			
		||||
                $currentStart->addDay();
 | 
			
		||||
                $currentSet['entries'][$label] = $balance;
 | 
			
		||||
 
 | 
			
		||||
@@ -25,9 +25,11 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Api\V1\Controllers;
 | 
			
		||||
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use Carbon\Exceptions\InvalidDateException;
 | 
			
		||||
use Carbon\Exceptions\InvalidFormatException;
 | 
			
		||||
use FireflyIII\Models\Preference;
 | 
			
		||||
use FireflyIII\Models\TransactionCurrency;
 | 
			
		||||
use FireflyIII\Support\Facades\Amount;
 | 
			
		||||
use FireflyIII\Support\Facades\Steam;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
 | 
			
		||||
use Illuminate\Foundation\Bus\DispatchesJobs;
 | 
			
		||||
@@ -41,8 +43,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
 | 
			
		||||
{
 | 
			
		||||
@@ -50,11 +52,13 @@ 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';
 | 
			
		||||
 | 
			
		||||
    /** @var array<int, string> */
 | 
			
		||||
    protected array        $allowedSort;
 | 
			
		||||
    protected ParameterBag $parameters;
 | 
			
		||||
    protected bool        $convertToNative = false;
 | 
			
		||||
    protected TransactionCurrency $defaultCurrency;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Controller constructor.
 | 
			
		||||
@@ -67,8 +71,11 @@ abstract class Controller extends BaseController
 | 
			
		||||
            function ($request, $next) {
 | 
			
		||||
                $this->parameters = $this->getParameters();
 | 
			
		||||
                if (auth()->check()) {
 | 
			
		||||
                    $language = app('steam')->getLanguage();
 | 
			
		||||
                    $language              = Steam::getLanguage();
 | 
			
		||||
                    $this->convertToNative = Amount::convertToNative();
 | 
			
		||||
                    $this->defaultCurrency = Amount::getDefaultCurrency();
 | 
			
		||||
                    app()->setLocale($language);
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return $next($request);
 | 
			
		||||
@@ -108,7 +115,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(
 | 
			
		||||
 
 | 
			
		||||
@@ -26,10 +26,10 @@ namespace FireflyIII\Api\V1\Controllers\Data;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Data\DestroyRequest;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
 | 
			
		||||
@@ -66,9 +66,9 @@ class DestroyController extends Controller
 | 
			
		||||
        $objects         = $request->getObjects();
 | 
			
		||||
        $this->unused    = $request->boolean('unused', false);
 | 
			
		||||
 | 
			
		||||
        $allExceptAssets = [AccountType::BENEFICIARY, AccountType::CASH, AccountType::CREDITCARD, AccountType::DEFAULT, AccountType::EXPENSE, AccountType::IMPORT, AccountType::INITIAL_BALANCE, AccountType::LIABILITY_CREDIT, AccountType::RECONCILIATION, AccountType::REVENUE];
 | 
			
		||||
        $all             = [AccountType::ASSET, AccountType::BENEFICIARY, AccountType::CASH, AccountType::CREDITCARD, AccountType::DEBT, AccountType::DEFAULT, AccountType::EXPENSE, AccountType::IMPORT, AccountType::INITIAL_BALANCE, AccountType::LIABILITY_CREDIT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::RECONCILIATION];
 | 
			
		||||
        $liabilities     = [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD];
 | 
			
		||||
        $allExceptAssets = [AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::CASH->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::RECONCILIATION->value, AccountTypeEnum::REVENUE->value];
 | 
			
		||||
        $all             = [AccountTypeEnum::ASSET->value, AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::CASH->value, AccountTypeEnum::CREDITCARD->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::IMPORT->value, AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::LIABILITY_CREDIT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::RECONCILIATION->value];
 | 
			
		||||
        $liabilities     = [AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::CREDITCARD->value];
 | 
			
		||||
        $transactions    = [TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::TRANSFER->value, TransactionTypeEnum::RECONCILIATION->value];
 | 
			
		||||
 | 
			
		||||
        match ($objects) {
 | 
			
		||||
@@ -82,9 +82,9 @@ class DestroyController extends Controller
 | 
			
		||||
            'object_groups'          => $this->destroyObjectGroups(),
 | 
			
		||||
            'not_assets_liabilities' => $this->destroyAccounts($allExceptAssets),
 | 
			
		||||
            'accounts'               => $this->destroyAccounts($all),
 | 
			
		||||
            'asset_accounts'         => $this->destroyAccounts([AccountType::ASSET, AccountType::DEFAULT]),
 | 
			
		||||
            'expense_accounts'       => $this->destroyAccounts([AccountType::BENEFICIARY, AccountType::EXPENSE]),
 | 
			
		||||
            'revenue_accounts'       => $this->destroyAccounts([AccountType::REVENUE]),
 | 
			
		||||
            'asset_accounts'         => $this->destroyAccounts([AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]),
 | 
			
		||||
            'expense_accounts'       => $this->destroyAccounts([AccountTypeEnum::BENEFICIARY->value, AccountTypeEnum::EXPENSE->value]),
 | 
			
		||||
            'revenue_accounts'       => $this->destroyAccounts([AccountTypeEnum::REVENUE->value]),
 | 
			
		||||
            'liabilities'            => $this->destroyAccounts($liabilities),
 | 
			
		||||
            'transactions'           => $this->destroyTransactions($transactions),
 | 
			
		||||
            'withdrawals'            => $this->destroyTransactions([TransactionTypeEnum::WITHDRAWAL->value]),
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,9 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
 | 
			
		||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Facades\Amount;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class BillController
 | 
			
		||||
@@ -63,11 +65,13 @@ class BillController extends Controller
 | 
			
		||||
     */
 | 
			
		||||
    public function bill(GenericRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $accounts   = $request->getAssetAccounts();
 | 
			
		||||
        $bills      = $request->getBills();
 | 
			
		||||
        $start      = $request->getStart();
 | 
			
		||||
        $end        = $request->getEnd();
 | 
			
		||||
        $response   = [];
 | 
			
		||||
        $accounts        = $request->getAssetAccounts();
 | 
			
		||||
        $bills           = $request->getBills();
 | 
			
		||||
        $start           = $request->getStart();
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
 | 
			
		||||
        // get all bills:
 | 
			
		||||
        if (0 === $bills->count()) {
 | 
			
		||||
@@ -75,17 +79,30 @@ class BillController extends Controller
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type) by the given bills and accounts.
 | 
			
		||||
        $collector  = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
 | 
			
		||||
        $collector->setBills($bills);
 | 
			
		||||
 | 
			
		||||
        $genericSet = $collector->getExtractedJournals();
 | 
			
		||||
        $genericSet      = $collector->getExtractedJournals();
 | 
			
		||||
        foreach ($genericSet as $journal) {
 | 
			
		||||
            $billId            = (int) $journal['bill_id'];
 | 
			
		||||
            $currencyId        = (int) $journal['currency_id'];
 | 
			
		||||
            $foreignCurrencyId = (int) $journal['foreign_currency_id'];
 | 
			
		||||
            $key               = sprintf('%d-%d', $billId, $currencyId);
 | 
			
		||||
            $foreignKey        = sprintf('%d-%d', $billId, $foreignCurrencyId);
 | 
			
		||||
            $billId       = (int) $journal['bill_id'];
 | 
			
		||||
            $currencyId   = (int) $journal['currency_id'];
 | 
			
		||||
            $currencyCode = $journal['currency_code'];
 | 
			
		||||
            $field        = 'amount';
 | 
			
		||||
 | 
			
		||||
            // use the native amount if the user wants to convert to native currency
 | 
			
		||||
            if ($convertToNative && $currencyId !== $default->id) {
 | 
			
		||||
                $currencyId   = $default->id;
 | 
			
		||||
                $currencyCode = $default->code;
 | 
			
		||||
                $field        = 'native_amount';
 | 
			
		||||
            }
 | 
			
		||||
            // use foreign amount when the foreign currency IS the default currency.
 | 
			
		||||
            if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
 | 
			
		||||
                $field = 'foreign_amount';
 | 
			
		||||
            }
 | 
			
		||||
            Log::debug(sprintf('Journal #%d in bill #%d will use %s (%s %s)', $journal['transaction_group_id'], $billId, $field, $currencyCode, $journal[$field] ?? '0'));
 | 
			
		||||
 | 
			
		||||
            $key          = sprintf('%d-%d', $billId, $currencyId);
 | 
			
		||||
 | 
			
		||||
            if (0 !== $currencyId) {
 | 
			
		||||
                $response[$key] ??= [
 | 
			
		||||
@@ -94,21 +111,11 @@ class BillController extends Controller
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $currencyId,
 | 
			
		||||
                    'currency_code'    => $journal['currency_code'],
 | 
			
		||||
                    'currency_code'    => $currencyCode,
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$key]['difference']       = bcadd($response[$key]['difference'], $journal['amount']);
 | 
			
		||||
                $response[$key]['difference']       = bcadd($response[$key]['difference'], (string) ($journal[$field] ?? '0'));
 | 
			
		||||
                $response[$key]['difference_float'] = (float) $response[$key]['difference']; // intentional float
 | 
			
		||||
            }
 | 
			
		||||
            if (0 !== $foreignCurrencyId) {
 | 
			
		||||
                $response[$foreignKey] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $foreignCurrencyId,
 | 
			
		||||
                    'currency_code'    => $journal['foreign_currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$foreignKey]['difference']       = bcadd($response[$foreignKey]['difference'], $journal['foreign_amount']);
 | 
			
		||||
                $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // intentional float
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(array_values($response));
 | 
			
		||||
@@ -122,42 +129,47 @@ class BillController extends Controller
 | 
			
		||||
     */
 | 
			
		||||
    public function noBill(GenericRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $accounts   = $request->getAssetAccounts();
 | 
			
		||||
        $start      = $request->getStart();
 | 
			
		||||
        $end        = $request->getEnd();
 | 
			
		||||
        $response   = [];
 | 
			
		||||
        $accounts        = $request->getAssetAccounts();
 | 
			
		||||
        $start           = $request->getStart();
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type) by the given bills and accounts.
 | 
			
		||||
        $collector  = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
 | 
			
		||||
        $collector->withoutBill();
 | 
			
		||||
 | 
			
		||||
        $genericSet = $collector->getExtractedJournals();
 | 
			
		||||
        $genericSet      = $collector->getExtractedJournals();
 | 
			
		||||
 | 
			
		||||
        foreach ($genericSet as $journal) {
 | 
			
		||||
            $currencyId        = (int) $journal['currency_id'];
 | 
			
		||||
            $foreignCurrencyId = (int) $journal['foreign_currency_id'];
 | 
			
		||||
            $currencyId   = (int) $journal['currency_id'];
 | 
			
		||||
            $currencyCode = $journal['currency_code'];
 | 
			
		||||
            $field        = 'amount';
 | 
			
		||||
 | 
			
		||||
            // use the native amount if the user wants to convert to native currency
 | 
			
		||||
            if ($convertToNative && $currencyId !== $default->id) {
 | 
			
		||||
                $currencyId   = $default->id;
 | 
			
		||||
                $currencyCode = $default->code;
 | 
			
		||||
                $field        = 'native_amount';
 | 
			
		||||
            }
 | 
			
		||||
            // use foreign amount when the foreign currency IS the default currency.
 | 
			
		||||
            if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
 | 
			
		||||
                $field = 'foreign_amount';
 | 
			
		||||
            }
 | 
			
		||||
            Log::debug(sprintf('Journal #%d will use %s (%s %s)', $journal['transaction_group_id'], $field, $currencyCode, $journal[$field] ?? '0'));
 | 
			
		||||
 | 
			
		||||
            if (0 !== $currencyId) {
 | 
			
		||||
                $response[$currencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $currencyId,
 | 
			
		||||
                    'currency_code'    => $journal['currency_code'],
 | 
			
		||||
                    'currency_code'    => $currencyCode,
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], $journal['amount']);
 | 
			
		||||
                $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], (string) ($journal[$field] ?? '0'));
 | 
			
		||||
                $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // intentional float
 | 
			
		||||
            }
 | 
			
		||||
            if (0 !== $foreignCurrencyId) {
 | 
			
		||||
                $response[$foreignCurrencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $foreignCurrencyId,
 | 
			
		||||
                    'currency_code'    => $journal['foreign_currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$foreignCurrencyId]['difference']       = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
 | 
			
		||||
                $response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference']; // intentional float
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(array_values($response));
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
 | 
			
		||||
use FireflyIII\Support\Facades\Amount;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class PeriodController
 | 
			
		||||
@@ -41,39 +43,49 @@ class PeriodController extends Controller
 | 
			
		||||
     */
 | 
			
		||||
    public function total(GenericRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $accounts   = $request->getAssetAccounts();
 | 
			
		||||
        $start      = $request->getStart();
 | 
			
		||||
        $end        = $request->getEnd();
 | 
			
		||||
        $response   = [];
 | 
			
		||||
        $accounts        = $request->getAssetAccounts();
 | 
			
		||||
        $start           = $request->getStart();
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type)
 | 
			
		||||
        $collector  = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
 | 
			
		||||
        $genericSet = $collector->getExtractedJournals();
 | 
			
		||||
        $genericSet      = $collector->getExtractedJournals();
 | 
			
		||||
        foreach ($genericSet as $journal) {
 | 
			
		||||
            $currencyId        = (int) $journal['currency_id'];
 | 
			
		||||
            $foreignCurrencyId = (int) $journal['foreign_currency_id'];
 | 
			
		||||
            // same code as many other sumExpense methods. I think this needs some kind of generic method.
 | 
			
		||||
            $amount                                    = '0';
 | 
			
		||||
            $currencyId                                = (int) $journal['currency_id'];
 | 
			
		||||
            $currencyCode                              = $journal['currency_code'];
 | 
			
		||||
            if ($convertToNative) {
 | 
			
		||||
                $amount = Amount::getAmountFromJournal($journal);
 | 
			
		||||
                if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) {
 | 
			
		||||
                    $currencyId   = $default->id;
 | 
			
		||||
                    $currencyCode = $default->code;
 | 
			
		||||
                }
 | 
			
		||||
                if ($default->id !== (int) $journal['currency_id'] && $default->id === (int) $journal['foreign_currency_id']) {
 | 
			
		||||
                    $currencyId   = $journal['foreign_currency_id'];
 | 
			
		||||
                    $currencyCode = $journal['foreign_currency_code'];
 | 
			
		||||
                }
 | 
			
		||||
                Log::debug(sprintf('[a] Add amount %s %s', $currencyCode, $amount));
 | 
			
		||||
            }
 | 
			
		||||
            if (!$convertToNative) {
 | 
			
		||||
                // ignore the amount in foreign currency.
 | 
			
		||||
                Log::debug(sprintf('[b] Add amount %s %s', $currencyCode, $journal['amount']));
 | 
			
		||||
                $amount = $journal['amount'];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (0 !== $currencyId) {
 | 
			
		||||
                $response[$currencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $currencyId,
 | 
			
		||||
                    'currency_code'    => $journal['currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], $journal['amount']);
 | 
			
		||||
                $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // intentional float
 | 
			
		||||
            }
 | 
			
		||||
            if (0 !== $foreignCurrencyId) {
 | 
			
		||||
                $response[$foreignCurrencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $foreignCurrencyId,
 | 
			
		||||
                    'currency_code'    => $journal['foreign_currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$foreignCurrencyId]['difference']       = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
 | 
			
		||||
                $response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference']; // intentional float
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $response[$currencyId] ??= [
 | 
			
		||||
                'difference'       => '0',
 | 
			
		||||
                'difference_float' => 0,
 | 
			
		||||
                'currency_id'      => (string) $currencyId,
 | 
			
		||||
                'currency_code'    => $currencyCode,
 | 
			
		||||
            ];
 | 
			
		||||
            $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], $amount);
 | 
			
		||||
            $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // intentional float
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(array_values($response));
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,9 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
 | 
			
		||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Facades\Amount;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class TagController
 | 
			
		||||
@@ -62,42 +64,51 @@ class TagController extends Controller
 | 
			
		||||
     */
 | 
			
		||||
    public function noTag(GenericRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $accounts   = $request->getAssetAccounts();
 | 
			
		||||
        $start      = $request->getStart();
 | 
			
		||||
        $end        = $request->getEnd();
 | 
			
		||||
        $response   = [];
 | 
			
		||||
        $accounts        = $request->getAssetAccounts();
 | 
			
		||||
        $start           = $request->getStart();
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type) by the given bills and accounts.
 | 
			
		||||
        $collector  = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->setRange($start, $end)->setSourceAccounts($accounts);
 | 
			
		||||
        $collector->withoutTags();
 | 
			
		||||
 | 
			
		||||
        $genericSet = $collector->getExtractedJournals();
 | 
			
		||||
        $genericSet      = $collector->getExtractedJournals();
 | 
			
		||||
 | 
			
		||||
        foreach ($genericSet as $journal) {
 | 
			
		||||
            $currencyId        = (int) $journal['currency_id'];
 | 
			
		||||
            $foreignCurrencyId = (int) $journal['foreign_currency_id'];
 | 
			
		||||
            // same code as many other sumExpense methods. I think this needs some kind of generic method.
 | 
			
		||||
            $amount                                    = '0';
 | 
			
		||||
            $currencyId                                = (int) $journal['currency_id'];
 | 
			
		||||
            $currencyCode                              = $journal['currency_code'];
 | 
			
		||||
            if ($convertToNative) {
 | 
			
		||||
                $amount = Amount::getAmountFromJournal($journal);
 | 
			
		||||
                if ($default->id !== (int) $journal['currency_id'] && $default->id !== (int) $journal['foreign_currency_id']) {
 | 
			
		||||
                    $currencyId   = $default->id;
 | 
			
		||||
                    $currencyCode = $default->code;
 | 
			
		||||
                }
 | 
			
		||||
                if ($default->id !== (int) $journal['currency_id'] && $default->id === (int) $journal['foreign_currency_id']) {
 | 
			
		||||
                    $currencyId   = $journal['foreign_currency_id'];
 | 
			
		||||
                    $currencyCode = $journal['foreign_currency_code'];
 | 
			
		||||
                }
 | 
			
		||||
                Log::debug(sprintf('[a] Add amount %s %s', $currencyCode, $amount));
 | 
			
		||||
            }
 | 
			
		||||
            if (!$convertToNative) {
 | 
			
		||||
                // ignore the amount in foreign currency.
 | 
			
		||||
                Log::debug(sprintf('[b] Add amount %s %s', $currencyCode, $journal['amount']));
 | 
			
		||||
                $amount = $journal['amount'];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (0 !== $currencyId) {
 | 
			
		||||
                $response[$currencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $currencyId,
 | 
			
		||||
                    'currency_code'    => $journal['currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], $journal['amount']);
 | 
			
		||||
                $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
 | 
			
		||||
            }
 | 
			
		||||
            if (0 !== $foreignCurrencyId) {
 | 
			
		||||
                $response[$foreignCurrencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $foreignCurrencyId,
 | 
			
		||||
                    'currency_code'    => $journal['foreign_currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$foreignCurrencyId]['difference']       = bcadd($response[$foreignCurrencyId]['difference'], $journal['foreign_amount']);
 | 
			
		||||
                $response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference']; // float but on purpose.
 | 
			
		||||
            }
 | 
			
		||||
            $response[$currencyId] ??= [
 | 
			
		||||
                'difference'       => '0',
 | 
			
		||||
                'difference_float' => 0,
 | 
			
		||||
                'currency_id'      => (string) $currencyId,
 | 
			
		||||
                'currency_code'    => $currencyCode,
 | 
			
		||||
            ];
 | 
			
		||||
            $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], $amount);
 | 
			
		||||
            $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(array_values($response));
 | 
			
		||||
 
 | 
			
		||||
@@ -73,6 +73,7 @@ class AccountController extends Controller
 | 
			
		||||
        $start         = $request->getStart();
 | 
			
		||||
        $end           = $request->getEnd();
 | 
			
		||||
        $assetAccounts = $request->getAssetAccounts();
 | 
			
		||||
 | 
			
		||||
        $income        = $this->opsRepository->sumIncomeByDestination($start, $end, $assetAccounts);
 | 
			
		||||
        $result        = [];
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
 | 
			
		||||
use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
 | 
			
		||||
use FireflyIII\Support\Facades\Amount;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -41,42 +42,41 @@ class PeriodController extends Controller
 | 
			
		||||
     */
 | 
			
		||||
    public function total(GenericRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $accounts   = $request->getAssetAccounts();
 | 
			
		||||
        $start      = $request->getStart();
 | 
			
		||||
        $end        = $request->getEnd();
 | 
			
		||||
        $response   = [];
 | 
			
		||||
        $accounts        = $request->getAssetAccounts();
 | 
			
		||||
        $start           = $request->getStart();
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type)
 | 
			
		||||
        $collector  = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $genericSet = $collector->getExtractedJournals();
 | 
			
		||||
        $genericSet      = $collector->getExtractedJournals();
 | 
			
		||||
        foreach ($genericSet as $journal) {
 | 
			
		||||
            $currencyId        = (int) $journal['currency_id'];
 | 
			
		||||
            $foreignCurrencyId = (int) $journal['foreign_currency_id'];
 | 
			
		||||
            // currency
 | 
			
		||||
            $currencyId                                = $journal['currency_id'];
 | 
			
		||||
            $currencyCode                              = $journal['currency_code'];
 | 
			
		||||
            $field                                     = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
 | 
			
		||||
 | 
			
		||||
            if (0 !== $currencyId) {
 | 
			
		||||
                $response[$currencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $currencyId,
 | 
			
		||||
                    'currency_code'    => $journal['currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
 | 
			
		||||
                $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
 | 
			
		||||
            // perhaps use default currency instead?
 | 
			
		||||
            if ($convertToNative && $journal['currency_id'] !== $default->id) {
 | 
			
		||||
                $currencyId   = $default->id;
 | 
			
		||||
                $currencyCode = $default->code;
 | 
			
		||||
            }
 | 
			
		||||
            if (0 !== $foreignCurrencyId) {
 | 
			
		||||
                $response[$foreignCurrencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $foreignCurrencyId,
 | 
			
		||||
                    'currency_code'    => $journal['foreign_currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$foreignCurrencyId]['difference']       = bcadd(
 | 
			
		||||
                    $response[$foreignCurrencyId]['difference'],
 | 
			
		||||
                    app('steam')->positive($journal['foreign_amount'])
 | 
			
		||||
                );
 | 
			
		||||
                $response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference']; // float but on purpose.
 | 
			
		||||
            // use foreign amount when the foreign currency IS the default currency.
 | 
			
		||||
            if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
 | 
			
		||||
                $field = 'foreign_amount';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $response[$currencyId] ??= [
 | 
			
		||||
                'difference'       => '0',
 | 
			
		||||
                'difference_float' => 0,
 | 
			
		||||
                'currency_id'      => (string) $currencyId,
 | 
			
		||||
                'currency_code'    => $currencyCode,
 | 
			
		||||
            ];
 | 
			
		||||
            $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
 | 
			
		||||
            $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(array_values($response));
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
 | 
			
		||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Facades\Amount;
 | 
			
		||||
use Illuminate\Http\JsonResponse;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -63,45 +64,45 @@ class TagController extends Controller
 | 
			
		||||
     */
 | 
			
		||||
    public function noTag(GenericRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $accounts   = $request->getAssetAccounts();
 | 
			
		||||
        $start      = $request->getStart();
 | 
			
		||||
        $end        = $request->getEnd();
 | 
			
		||||
        $response   = [];
 | 
			
		||||
        $accounts        = $request->getAssetAccounts();
 | 
			
		||||
        $start           = $request->getStart();
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type) by the given bills and accounts.
 | 
			
		||||
        $collector  = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::DEPOSIT->value])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $collector->withoutTags();
 | 
			
		||||
 | 
			
		||||
        $genericSet = $collector->getExtractedJournals();
 | 
			
		||||
        $genericSet      = $collector->getExtractedJournals();
 | 
			
		||||
 | 
			
		||||
        foreach ($genericSet as $journal) {
 | 
			
		||||
            $currencyId        = (int) $journal['currency_id'];
 | 
			
		||||
            $foreignCurrencyId = (int) $journal['foreign_currency_id'];
 | 
			
		||||
            // currency
 | 
			
		||||
            $currencyId                                = $journal['currency_id'];
 | 
			
		||||
            $currencyCode                              = $journal['currency_code'];
 | 
			
		||||
            $field                                     = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
 | 
			
		||||
 | 
			
		||||
            if (0 !== $currencyId) {
 | 
			
		||||
                $response[$currencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $currencyId,
 | 
			
		||||
                    'currency_code'    => $journal['currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
 | 
			
		||||
                $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
 | 
			
		||||
            // perhaps use default currency instead?
 | 
			
		||||
            if ($convertToNative && $journal['currency_id'] !== $default->id) {
 | 
			
		||||
                $currencyId   = $default->id;
 | 
			
		||||
                $currencyCode = $default->code;
 | 
			
		||||
            }
 | 
			
		||||
            if (0 !== $foreignCurrencyId) {
 | 
			
		||||
                $response[$foreignCurrencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $foreignCurrencyId,
 | 
			
		||||
                    'currency_code'    => $journal['foreign_currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$foreignCurrencyId]['difference']       = bcadd(
 | 
			
		||||
                    $response[$foreignCurrencyId]['difference'],
 | 
			
		||||
                    app('steam')->positive($journal['foreign_amount'])
 | 
			
		||||
                );
 | 
			
		||||
                $response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference'];
 | 
			
		||||
            // use foreign amount when the foreign currency IS the default currency.
 | 
			
		||||
            if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
 | 
			
		||||
                $field = 'foreign_amount';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $response[$currencyId] ??= [
 | 
			
		||||
                'difference'       => '0',
 | 
			
		||||
                'difference_float' => 0,
 | 
			
		||||
                'currency_id'      => (string) $currencyId,
 | 
			
		||||
                'currency_code'    => $currencyCode,
 | 
			
		||||
            ];
 | 
			
		||||
            $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
 | 
			
		||||
            $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(array_values($response));
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,9 @@ 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -41,42 +42,42 @@ class PeriodController extends Controller
 | 
			
		||||
     */
 | 
			
		||||
    public function total(GenericRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $accounts   = $request->getAssetAccounts();
 | 
			
		||||
        $start      = $request->getStart();
 | 
			
		||||
        $end        = $request->getEnd();
 | 
			
		||||
        $response   = [];
 | 
			
		||||
        $accounts        = $request->getAssetAccounts();
 | 
			
		||||
        $start           = $request->getStart();
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type)
 | 
			
		||||
        $collector  = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $genericSet = $collector->getExtractedJournals();
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::TRANSFER->value])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $genericSet      = $collector->getExtractedJournals();
 | 
			
		||||
        foreach ($genericSet as $journal) {
 | 
			
		||||
            $currencyId        = (int) $journal['currency_id'];
 | 
			
		||||
            $foreignCurrencyId = (int) $journal['foreign_currency_id'];
 | 
			
		||||
            // currency
 | 
			
		||||
            $currencyId                                = $journal['currency_id'];
 | 
			
		||||
            $currencyCode                              = $journal['currency_code'];
 | 
			
		||||
            $field                                     = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
 | 
			
		||||
 | 
			
		||||
            if (0 !== $currencyId) {
 | 
			
		||||
                $response[$currencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $currencyId,
 | 
			
		||||
                    'currency_code'    => $journal['currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
 | 
			
		||||
                $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
 | 
			
		||||
            // perhaps use default currency instead?
 | 
			
		||||
            if ($convertToNative && $journal['currency_id'] !== $default->id) {
 | 
			
		||||
                $currencyId   = $default->id;
 | 
			
		||||
                $currencyCode = $default->code;
 | 
			
		||||
            }
 | 
			
		||||
            if (0 !== $foreignCurrencyId) {
 | 
			
		||||
                $response[$foreignCurrencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $foreignCurrencyId,
 | 
			
		||||
                    'currency_code'    => $journal['foreign_currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$foreignCurrencyId]['difference']       = bcadd(
 | 
			
		||||
                    $response[$foreignCurrencyId]['difference'],
 | 
			
		||||
                    app('steam')->positive($journal['foreign_amount'])
 | 
			
		||||
                );
 | 
			
		||||
                $response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference'];
 | 
			
		||||
            // use foreign amount when the foreign currency IS the default currency.
 | 
			
		||||
            if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
 | 
			
		||||
                $field = 'foreign_amount';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $response[$currencyId] ??= [
 | 
			
		||||
                'difference'       => '0',
 | 
			
		||||
                'difference_float' => 0,
 | 
			
		||||
                'currency_id'      => (string) $currencyId,
 | 
			
		||||
                'currency_code'    => $currencyCode,
 | 
			
		||||
            ];
 | 
			
		||||
            $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
 | 
			
		||||
            $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(array_values($response));
 | 
			
		||||
 
 | 
			
		||||
@@ -26,9 +26,10 @@ 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -61,45 +62,46 @@ class TagController extends Controller
 | 
			
		||||
     */
 | 
			
		||||
    public function noTag(GenericRequest $request): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        $accounts   = $request->getAssetAccounts();
 | 
			
		||||
        $start      = $request->getStart();
 | 
			
		||||
        $end        = $request->getEnd();
 | 
			
		||||
        $response   = [];
 | 
			
		||||
        $accounts        = $request->getAssetAccounts();
 | 
			
		||||
        $start           = $request->getStart();
 | 
			
		||||
        $end             = $request->getEnd();
 | 
			
		||||
        $response        = [];
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // collect all expenses in this period (regardless of type) by the given bills and accounts.
 | 
			
		||||
        $collector  = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionType::TRANSFER])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $collector       = app(GroupCollectorInterface::class);
 | 
			
		||||
        $collector->setTypes([TransactionTypeEnum::TRANSFER->value])->setRange($start, $end)->setDestinationAccounts($accounts);
 | 
			
		||||
        $collector->withoutTags();
 | 
			
		||||
 | 
			
		||||
        $genericSet = $collector->getExtractedJournals();
 | 
			
		||||
        $genericSet      = $collector->getExtractedJournals();
 | 
			
		||||
 | 
			
		||||
        foreach ($genericSet as $journal) {
 | 
			
		||||
            $currencyId        = (int) $journal['currency_id'];
 | 
			
		||||
            $foreignCurrencyId = (int) $journal['foreign_currency_id'];
 | 
			
		||||
            // currency
 | 
			
		||||
            $currencyId                                = $journal['currency_id'];
 | 
			
		||||
            $currencyCode                              = $journal['currency_code'];
 | 
			
		||||
            $field                                     = $convertToNative && $currencyId !== $default->id ? 'native_amount' : 'amount';
 | 
			
		||||
 | 
			
		||||
            if (0 !== $currencyId) {
 | 
			
		||||
                $response[$currencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $currencyId,
 | 
			
		||||
                    'currency_code'    => $journal['currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal['amount']));
 | 
			
		||||
                $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
 | 
			
		||||
            // perhaps use default currency instead?
 | 
			
		||||
            if ($convertToNative && $journal['currency_id'] !== $default->id) {
 | 
			
		||||
                $currencyId   = $default->id;
 | 
			
		||||
                $currencyCode = $default->code;
 | 
			
		||||
            }
 | 
			
		||||
            if (0 !== $foreignCurrencyId) {
 | 
			
		||||
                $response[$foreignCurrencyId] ??= [
 | 
			
		||||
                    'difference'       => '0',
 | 
			
		||||
                    'difference_float' => 0,
 | 
			
		||||
                    'currency_id'      => (string) $foreignCurrencyId,
 | 
			
		||||
                    'currency_code'    => $journal['foreign_currency_code'],
 | 
			
		||||
                ];
 | 
			
		||||
                $response[$foreignCurrencyId]['difference']       = bcadd(
 | 
			
		||||
                    $response[$foreignCurrencyId]['difference'],
 | 
			
		||||
                    app('steam')->positive($journal['foreign_amount'])
 | 
			
		||||
                );
 | 
			
		||||
                $response[$foreignCurrencyId]['difference_float'] = (float) $response[$foreignCurrencyId]['difference'];
 | 
			
		||||
            // use foreign amount when the foreign currency IS the default currency.
 | 
			
		||||
            if ($convertToNative && $journal['currency_id'] !== $default->id && $default->id === $journal['foreign_currency_id']) {
 | 
			
		||||
                $field = 'foreign_amount';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $response[$currencyId] ??= [
 | 
			
		||||
                'difference'       => '0',
 | 
			
		||||
                'difference_float' => 0,
 | 
			
		||||
                'currency_id'      => (string) $currencyId,
 | 
			
		||||
                'currency_code'    => $currencyCode,
 | 
			
		||||
            ];
 | 
			
		||||
            $response[$currencyId]['difference']       = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field]));
 | 
			
		||||
            $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(array_values($response));
 | 
			
		||||
@@ -126,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();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -239,7 +239,7 @@ class ListController extends Controller
 | 
			
		||||
        $unfiltered     = $recurringRepos->getAll();
 | 
			
		||||
 | 
			
		||||
        // 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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -105,19 +105,18 @@ class ShowController extends Controller
 | 
			
		||||
    public function show(TransactionCurrency $currency): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        /** @var User $user */
 | 
			
		||||
        $user            = auth()->user();
 | 
			
		||||
        $manager         = $this->getManager();
 | 
			
		||||
        $defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
 | 
			
		||||
        $this->parameters->set('defaultCurrency', $defaultCurrency);
 | 
			
		||||
        $user        = auth()->user();
 | 
			
		||||
        $manager     = $this->getManager();
 | 
			
		||||
        $this->parameters->set('defaultCurrency', $this->defaultCurrency);
 | 
			
		||||
 | 
			
		||||
        // update fields with user info.
 | 
			
		||||
        $currency->refreshForUser($user);
 | 
			
		||||
 | 
			
		||||
        /** @var CurrencyTransformer $transformer */
 | 
			
		||||
        $transformer     = app(CurrencyTransformer::class);
 | 
			
		||||
        $transformer = app(CurrencyTransformer::class);
 | 
			
		||||
        $transformer->setParameters($this->parameters);
 | 
			
		||||
 | 
			
		||||
        $resource        = new Item($currency, $transformer, 'currencies');
 | 
			
		||||
        $resource    = new Item($currency, $transformer, 'currencies');
 | 
			
		||||
 | 
			
		||||
        return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
 | 
			
		||||
    }
 | 
			
		||||
@@ -135,7 +134,7 @@ class ShowController extends Controller
 | 
			
		||||
        /** @var User $user */
 | 
			
		||||
        $user        = auth()->user();
 | 
			
		||||
        $manager     = $this->getManager();
 | 
			
		||||
        $currency    = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
 | 
			
		||||
        $currency    = $this->defaultCurrency;
 | 
			
		||||
 | 
			
		||||
        // update fields with user info.
 | 
			
		||||
        $currency->refreshForUser($user);
 | 
			
		||||
 
 | 
			
		||||
@@ -103,10 +103,10 @@ class BasicController extends Controller
 | 
			
		||||
        $billData     = $this->getBillInformation($start, $end);
 | 
			
		||||
        $spentData    = $this->getLeftToSpendInfo($start, $end);
 | 
			
		||||
        $netWorthData = $this->getNetWorthInfo($start, $end);
 | 
			
		||||
        //        $balanceData  = [];
 | 
			
		||||
        //        $billData     = [];
 | 
			
		||||
        //        $spentData    = [];
 | 
			
		||||
        //        $netWorthData = [];
 | 
			
		||||
        //                $balanceData  = [];
 | 
			
		||||
        //                $billData     = [];
 | 
			
		||||
        //                $spentData    = [];
 | 
			
		||||
        //                $netWorthData = [];
 | 
			
		||||
        $total        = array_merge($balanceData, $billData, $spentData, $netWorthData);
 | 
			
		||||
 | 
			
		||||
        // give new keys
 | 
			
		||||
@@ -123,8 +123,8 @@ class BasicController extends Controller
 | 
			
		||||
    private function getBalanceInformation(Carbon $start, Carbon $end): array
 | 
			
		||||
    {
 | 
			
		||||
        // some config settings
 | 
			
		||||
        $convertToNative = app('preferences')->get('convert_to_native', false)->data;
 | 
			
		||||
        $default         = app('amount')->getDefaultCurrency();
 | 
			
		||||
        $convertToNative = Amount::convertToNative();
 | 
			
		||||
        $default         = Amount::getDefaultCurrency();
 | 
			
		||||
        // prep some arrays:
 | 
			
		||||
        $incomes         = [];
 | 
			
		||||
        $expenses        = [];
 | 
			
		||||
@@ -276,13 +276,13 @@ class BasicController extends Controller
 | 
			
		||||
     */
 | 
			
		||||
    private function getLeftToSpendInfo(Carbon $start, Carbon $end): array
 | 
			
		||||
    {
 | 
			
		||||
        Log::debug(sprintf('Now in getLeftToSpendInfo("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
 | 
			
		||||
        $return    = [];
 | 
			
		||||
        $today     = today(config('app.timezone'));
 | 
			
		||||
        $available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
 | 
			
		||||
        $budgets   = $this->budgetRepository->getActiveBudgets();
 | 
			
		||||
        $spent     = $this->opsRepository->sumExpenses($start, $end, null, $budgets);
 | 
			
		||||
        $days      = (int) $today->diffInDays($end, true) + 1;
 | 
			
		||||
        Log::debug(sprintf('Now in getLeftToSpendInfo("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
 | 
			
		||||
 | 
			
		||||
        foreach ($spent as $row) {
 | 
			
		||||
            // either an amount was budgeted or 0 is available.
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -118,7 +118,7 @@ class AccountController extends Controller
 | 
			
		||||
            'native_entries'                 => [],
 | 
			
		||||
        ];
 | 
			
		||||
        $currentStart   = clone $params['start'];
 | 
			
		||||
        $range          = app('steam')->finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $currency);
 | 
			
		||||
        $range          = app('steam')->finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
 | 
			
		||||
 | 
			
		||||
        $previous       = array_values($range)[0]['balance'];
 | 
			
		||||
        $previousNative = array_values($range)[0]['native_balance'];
 | 
			
		||||
 
 | 
			
		||||
@@ -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,7 +81,7 @@ 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]);
 | 
			
		||||
        $accounts   = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]);
 | 
			
		||||
        $default    = app('amount')->getDefaultCurrency();
 | 
			
		||||
        $converter  = new ExchangeRateConverter();
 | 
			
		||||
        $currencies = [];
 | 
			
		||||
 
 | 
			
		||||
@@ -47,16 +47,17 @@ use Symfony\Component\HttpFoundation\ParameterBag;
 | 
			
		||||
/**
 | 
			
		||||
 * Class Controller
 | 
			
		||||
 *
 | 
			
		||||
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 | 
			
		||||
 * @SuppressWarnings(PHPMD.NumberOfChildren)
 | 
			
		||||
 * @SuppressWarnings("PHPMD.CouplingBetweenObjects")
 | 
			
		||||
 * @SuppressWarnings("PHPMD.NumberOfChildren")
 | 
			
		||||
 */
 | 
			
		||||
class Controller extends BaseController
 | 
			
		||||
{
 | 
			
		||||
    use ValidatesUserGroupTrait;
 | 
			
		||||
 | 
			
		||||
    protected const string CONTENT_TYPE   = 'application/vnd.api+json';
 | 
			
		||||
    protected array        $acceptedRoles = [UserRoleEnum::READ_ONLY];
 | 
			
		||||
    protected const string CONTENT_TYPE     = 'application/vnd.api+json';
 | 
			
		||||
    protected array        $acceptedRoles   = [UserRoleEnum::READ_ONLY];
 | 
			
		||||
    protected ParameterBag $parameters;
 | 
			
		||||
    protected bool         $convertToNative = false;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
@@ -73,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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,113 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * AccountController.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see https://www.gnu.org/licenses/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Api\V2\Controllers\JsonApi;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Http\Controllers\Controller;
 | 
			
		||||
use FireflyIII\JsonApi\V2\Accounts\AccountCollectionQuery;
 | 
			
		||||
use FireflyIII\JsonApi\V2\Accounts\AccountSchema;
 | 
			
		||||
use FireflyIII\JsonApi\V2\Accounts\AccountSingleQuery;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use Illuminate\Contracts\Support\Responsable;
 | 
			
		||||
use Illuminate\Http\Response;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
use LaravelJsonApi\Core\Responses\DataResponse;
 | 
			
		||||
use LaravelJsonApi\Laravel\Http\Controllers\Actions;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class AccountController
 | 
			
		||||
 *
 | 
			
		||||
 * This class handles api/v2 requests for accounts.
 | 
			
		||||
 * Most stuff is default stuff.
 | 
			
		||||
 */
 | 
			
		||||
class AccountController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    use Actions\AttachRelationship;
 | 
			
		||||
    use Actions\Destroy;
 | 
			
		||||
    use Actions\DetachRelationship;
 | 
			
		||||
 | 
			
		||||
    use Actions\FetchMany;
 | 
			
		||||
 | 
			
		||||
    // use Actions\FetchOne;
 | 
			
		||||
    use Actions\FetchRelated;
 | 
			
		||||
    use Actions\FetchRelationship;
 | 
			
		||||
    use Actions\Store;
 | 
			
		||||
    use Actions\Update;
 | 
			
		||||
    use Actions\UpdateRelationship;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch zero to many JSON API resources.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Responsable|Response
 | 
			
		||||
     */
 | 
			
		||||
    public function index(AccountSchema $schema, AccountCollectionQuery $request)
 | 
			
		||||
    {
 | 
			
		||||
        Log::debug(__METHOD__);
 | 
			
		||||
        $models = $schema
 | 
			
		||||
            ->repository()
 | 
			
		||||
            ->queryAll()
 | 
			
		||||
            ->withRequest($request)
 | 
			
		||||
            ->get()
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
        // do something custom...
 | 
			
		||||
 | 
			
		||||
        return new DataResponse($models);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch zero to one JSON API resource by id.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Responsable|Response
 | 
			
		||||
     */
 | 
			
		||||
    public function show(AccountSchema $schema, AccountSingleQuery $request, Account $account)
 | 
			
		||||
    {
 | 
			
		||||
        Log::debug(__METHOD__);
 | 
			
		||||
        $model = $schema->repository()
 | 
			
		||||
            ->queryOne($account)
 | 
			
		||||
            ->withRequest($request)
 | 
			
		||||
            ->first()
 | 
			
		||||
        ;
 | 
			
		||||
        Log::debug(sprintf('%s again!', __METHOD__));
 | 
			
		||||
 | 
			
		||||
        // do something custom...
 | 
			
		||||
 | 
			
		||||
        return new DataResponse($model);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //    public function readAccountBalances(AnonymousQuery $query, AccountBalanceSchema $schema, Account $account): Responsable
 | 
			
		||||
    //    {
 | 
			
		||||
    //        $schema = JsonApi::server()->schemas()->schemaFor('account-balances');
 | 
			
		||||
    //
 | 
			
		||||
    //        $models = $schema
 | 
			
		||||
    //            ->repository()
 | 
			
		||||
    //            ->queryAll()
 | 
			
		||||
    //            ->withRequest($query)
 | 
			
		||||
    //            ->withAccount($account)
 | 
			
		||||
    //            ->get()
 | 
			
		||||
    //        ;
 | 
			
		||||
    //
 | 
			
		||||
    //        return DataResponse::make($models);
 | 
			
		||||
    //    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V2\Controllers\Model\ExchangeRate;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    {
 | 
			
		||||
@@ -222,7 +222,7 @@ class BasicController extends Controller
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
 | 
			
		||||
     * @SuppressWarnings("PHPMD.ExcessiveMethodLength")
 | 
			
		||||
     */
 | 
			
		||||
    private function getLeftToSpendInfo(Carbon $start, Carbon $end): array
 | 
			
		||||
    {
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,6 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Api\V2\Request\Chart;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Enums\UserRoleEnum;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ParsesQueryFilters;
 | 
			
		||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
 | 
			
		||||
use FireflyIII\Support\Request\ChecksLogin;
 | 
			
		||||
use FireflyIII\Support\Request\ConvertsDataTypes;
 | 
			
		||||
@@ -40,7 +39,6 @@ class ChartRequest extends FormRequest
 | 
			
		||||
{
 | 
			
		||||
    use ChecksLogin;
 | 
			
		||||
    use ConvertsDataTypes;
 | 
			
		||||
    use ParsesQueryFilters;
 | 
			
		||||
    use ValidatesUserGroupTrait;
 | 
			
		||||
 | 
			
		||||
    protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,25 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ConvertsDatesToUTC.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);
 | 
			
		||||
/*
 | 
			
		||||
 * ConvertDatesToUTC.php
 | 
			
		||||
@@ -21,7 +41,7 @@ declare(strict_types=1);
 | 
			
		||||
 * along with this program.  If not, see https://www.gnu.org/licenses/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Console\Commands\Integrity;
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
@@ -31,34 +51,28 @@ use Illuminate\Database\QueryException;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
class ConvertDatesToUTC extends Command
 | 
			
		||||
class ConvertsDatesToUTC extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The console command description.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $description = 'Convert stored dates to UTC.';
 | 
			
		||||
    protected $signature   = 'correction:convert-to-utc';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The name and signature of the console command.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $signature   = 'firefly-iii:migrate-to-utc';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
     */
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
        $this->friendlyWarning('Please do not use this command right now.');
 | 
			
		||||
 | 
			
		||||
        // 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.
 | 
			
		||||
@@ -98,10 +112,10 @@ class ConvertDatesToUTC 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();
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@@ -4,10 +4,6 @@ namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CorrectionSkeleton
 | 
			
		||||
 * TODO DONT FORGET TO ADD THIS TO THE DOCKER BUILD
 | 
			
		||||
 */
 | 
			
		||||
class CorrectionSkeleton extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 
 | 
			
		||||
@@ -29,15 +29,12 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FixAccountOrder
 | 
			
		||||
 */
 | 
			
		||||
class FixAccountOrder extends Command
 | 
			
		||||
class CorrectsAccountOrder extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Make sure account order is correct.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-account-order';
 | 
			
		||||
    protected $signature   = 'correction:account-order';
 | 
			
		||||
 | 
			
		||||
    private AccountRepositoryInterface $repository;
 | 
			
		||||
 | 
			
		||||
@@ -54,8 +51,6 @@ class FixAccountOrder extends Command
 | 
			
		||||
            $this->repository->resetAccountOrder();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->friendlyPositive('All accounts are ordered correctly');
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -36,15 +36,12 @@ use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Illuminate\Database\Query\JoinClause;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FixAccountTypes
 | 
			
		||||
 */
 | 
			
		||||
class FixAccountTypes extends Command
 | 
			
		||||
class CorrectsAccountTypes extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Make sure all journals have the correct from/to account types.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-account-types';
 | 
			
		||||
    protected $signature   = 'correction:account-types';
 | 
			
		||||
    private int            $count;
 | 
			
		||||
    private array          $expected;
 | 
			
		||||
    private AccountFactory $factory;
 | 
			
		||||
@@ -114,15 +111,14 @@ class FixAccountTypes 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);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $this->count) {
 | 
			
		||||
            $this->friendlyPositive('All account types are OK');
 | 
			
		||||
        }
 | 
			
		||||
        if (0 !== $this->count) {
 | 
			
		||||
            app('log')->debug(sprintf('%d journals had to be fixed.', $this->count));
 | 
			
		||||
            $this->friendlyInfo(sprintf('Acted on %d transaction(s)', $this->count));
 | 
			
		||||
@@ -251,18 +247,18 @@ class FixAccountTypes 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);
 | 
			
		||||
@@ -274,13 +270,13 @@ class FixAccountTypes 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);
 | 
			
		||||
@@ -292,7 +288,7 @@ class FixAccountTypes 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
 | 
			
		||||
@@ -300,7 +296,7 @@ class FixAccountTypes 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(
 | 
			
		||||
@@ -318,7 +314,7 @@ class FixAccountTypes 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
 | 
			
		||||
@@ -326,7 +322,7 @@ class FixAccountTypes 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();
 | 
			
		||||
@@ -36,15 +36,12 @@ use FireflyIII\Models\RuleTrigger;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ReportSkeleton
 | 
			
		||||
 */
 | 
			
		||||
class CorrectAmounts extends Command
 | 
			
		||||
class CorrectsAmounts extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'This command makes sure positive and negative amounts are recorded correctly.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-amount-pos-neg';
 | 
			
		||||
    protected $signature   = 'correction:amounts';
 | 
			
		||||
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
@@ -72,7 +69,6 @@ class CorrectAmounts extends Command
 | 
			
		||||
    {
 | 
			
		||||
        $count = AutoBudget::where('amount', '<', 0)->update(['amount' => DB::raw('amount * -1')]);
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All auto budget amounts are positive.');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -83,7 +79,6 @@ class CorrectAmounts extends Command
 | 
			
		||||
    {
 | 
			
		||||
        $count = AvailableBudget::where('amount', '<', 0)->update(['amount' => DB::raw('amount * -1')]);
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All available budget amounts are positive.');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -96,7 +91,6 @@ class CorrectAmounts extends Command
 | 
			
		||||
        $count += Bill::where('amount_max', '<', 0)->update(['amount_max' => DB::raw('amount_max * -1')]);
 | 
			
		||||
        $count += Bill::where('amount_min', '<', 0)->update(['amount_min' => DB::raw('amount_min * -1')]);
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All bill amounts are positive.');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -107,7 +101,6 @@ class CorrectAmounts extends Command
 | 
			
		||||
    {
 | 
			
		||||
        $count = BudgetLimit::where('amount', '<', 0)->update(['amount' => DB::raw('amount * -1')]);
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All budget limit amounts are positive.');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -118,7 +111,6 @@ class CorrectAmounts extends Command
 | 
			
		||||
    {
 | 
			
		||||
        $count = CurrencyExchangeRate::where('rate', '<', 0)->update(['rate' => DB::raw('rate * -1')]);
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All currency exchange rates are positive.');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -129,7 +121,6 @@ class CorrectAmounts extends Command
 | 
			
		||||
    {
 | 
			
		||||
        $count = PiggyBank::where('target_amount', '<', 0)->update(['target_amount' => DB::raw('target_amount * -1')]);
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All piggy bank amounts are positive.');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -142,7 +133,6 @@ class CorrectAmounts extends Command
 | 
			
		||||
        $count += RecurrenceTransaction::where('amount', '<', 0)->update(['amount' => DB::raw('amount * -1')]);
 | 
			
		||||
        $count += RecurrenceTransaction::where('foreign_amount', '<', 0)->update(['foreign_amount' => DB::raw('foreign_amount * -1')]);
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All recurring transaction amounts are positive.');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -165,7 +155,6 @@ class CorrectAmounts extends Command
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $fixed) {
 | 
			
		||||
            $this->friendlyPositive('All rule trigger amounts are positive.');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -37,15 +37,12 @@ use Illuminate\Support\Collection;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
use Symfony\Component\Console\Command\Command as CommandAlias;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class EnableCurrencies
 | 
			
		||||
 */
 | 
			
		||||
class EnableCurrencies extends Command
 | 
			
		||||
class CorrectsCurrencies extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Enables all currencies in use.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:enable-currencies';
 | 
			
		||||
    protected $signature   = 'correction:currencies';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -27,14 +27,11 @@ namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CorrectDatabase
 | 
			
		||||
 */
 | 
			
		||||
class CorrectDatabase extends Command
 | 
			
		||||
class CorrectsDatabase extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Will correct the integrity of your database, if necessary.';
 | 
			
		||||
    protected $description = 'Will validate and correct the integrity of your database, if necessary.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:correct-database';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -49,32 +46,36 @@ class CorrectDatabase extends Command
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
        $commands = [
 | 
			
		||||
            'firefly-iii:fix-piggies',
 | 
			
		||||
            'firefly-iii:create-link-types',
 | 
			
		||||
            'firefly-iii:create-access-tokens',
 | 
			
		||||
            'firefly-iii:remove-bills',
 | 
			
		||||
            'firefly-iii:fix-amount-pos-neg',
 | 
			
		||||
            'firefly-iii:enable-currencies',
 | 
			
		||||
            'firefly-iii:fix-transfer-budgets',
 | 
			
		||||
            'firefly-iii:fix-uneven-amount',
 | 
			
		||||
            'firefly-iii:delete-zero-amount',
 | 
			
		||||
            'firefly-iii:delete-orphaned-transactions',
 | 
			
		||||
            'firefly-iii:delete-empty-journals',
 | 
			
		||||
            'firefly-iii:delete-empty-groups',
 | 
			
		||||
            'firefly-iii:fix-account-types',
 | 
			
		||||
            'firefly-iii:fix-ibans',
 | 
			
		||||
            'firefly-iii:fix-account-order',
 | 
			
		||||
            'firefly-iii:rename-meta-fields',
 | 
			
		||||
            'firefly-iii:fix-ob-currencies',
 | 
			
		||||
            'firefly-iii:fix-long-descriptions',
 | 
			
		||||
            'firefly-iii:fix-recurring-transactions',
 | 
			
		||||
            'firefly-iii:upgrade-group-information',
 | 
			
		||||
            // 'firefly-iii:fix-transaction-types', // very resource heavy.
 | 
			
		||||
            'firefly-iii:fix-frontpage-accounts',
 | 
			
		||||
            // new!
 | 
			
		||||
            'firefly-iii:unify-group-accounts',
 | 
			
		||||
            'firefly-iii:trigger-credit-recalculation',
 | 
			
		||||
            'firefly-iii:migrate-preferences',
 | 
			
		||||
            'correction:restore-oauth-keys',
 | 
			
		||||
            'correction:timezones',
 | 
			
		||||
            'correction:create-group-memberships',
 | 
			
		||||
            'correction:group-information',
 | 
			
		||||
            'correction:piggy-banks',
 | 
			
		||||
            'correction:link-types',
 | 
			
		||||
            'correction:access-tokens',
 | 
			
		||||
            'correction:bills',
 | 
			
		||||
            'correction:amounts',
 | 
			
		||||
            'correction:currencies',
 | 
			
		||||
            'correction:transfer-budgets',
 | 
			
		||||
            'correction:uneven-amounts',
 | 
			
		||||
            'correction:zero-amounts',
 | 
			
		||||
            'correction:orphaned-transactions',
 | 
			
		||||
            'correction:empty-journals',
 | 
			
		||||
            'correction:empty-groups',
 | 
			
		||||
            'correction:account-types',
 | 
			
		||||
            'correction:ibans',
 | 
			
		||||
            'correction:account-order',
 | 
			
		||||
            'correction:meta-fields',
 | 
			
		||||
            'correction:opening-balance-currencies',
 | 
			
		||||
            'correction:long-descriptions',
 | 
			
		||||
            'correction:recurring-transactions',
 | 
			
		||||
            'correction:frontpage-accounts',
 | 
			
		||||
            'correction:group-accounts',
 | 
			
		||||
            'correction:recalculates-liabilities',
 | 
			
		||||
            'correction:preferences',
 | 
			
		||||
            // 'correction:transaction-types', // resource heavy, disabled.
 | 
			
		||||
            'correction:recalculate-native-amounts', // not necessary, disabled.
 | 
			
		||||
            'firefly-iii:report-integrity',
 | 
			
		||||
        ];
 | 
			
		||||
        foreach ($commands as $command) {
 | 
			
		||||
            $this->friendlyLine(sprintf('Now executing command "%s"', $command));
 | 
			
		||||
@@ -25,21 +25,18 @@ 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;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FixFrontpageAccounts
 | 
			
		||||
 */
 | 
			
		||||
class FixFrontpageAccounts extends Command
 | 
			
		||||
class CorrectsFrontpageAccounts extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Fixes a preference that may include deleted accounts or accounts of another type.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-frontpage-accounts';
 | 
			
		||||
    protected $signature   = 'correction:frontpage-accounts';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -55,7 +52,6 @@ class FixFrontpageAccounts extends Command
 | 
			
		||||
                $this->fixPreference($preference);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $this->friendlyPositive('Account preferences are OK');
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -77,7 +73,7 @@ class FixFrontpageAccounts 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;
 | 
			
		||||
                }
 | 
			
		||||
@@ -31,15 +31,12 @@ use FireflyIII\Models\TransactionGroup;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FixGroupAccounts
 | 
			
		||||
 */
 | 
			
		||||
class FixGroupAccounts extends Command
 | 
			
		||||
class CorrectsGroupAccounts extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Unify the source / destination accounts of split groups.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:unify-group-accounts';
 | 
			
		||||
    protected $signature   = 'correction:group-accounts';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -64,8 +61,6 @@ class FixGroupAccounts extends Command
 | 
			
		||||
            $handler->unifyAccounts($event);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->friendlyPositive('Updated possible inconsistent transaction groups.');
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * UpdateGroupInformation.php
 | 
			
		||||
 * Copyright (c) 2022 james@firefly-iii.org
 | 
			
		||||
 * CorrectsGroupInformation.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -17,12 +17,12 @@
 | 
			
		||||
 * 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\Console\Commands\Integrity;
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
@@ -45,15 +45,12 @@ use FireflyIII\User;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Database\QueryException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class UpdateGroupInformation
 | 
			
		||||
 */
 | 
			
		||||
class UpdateGroupInformation extends Command
 | 
			
		||||
class CorrectsGroupInformation extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Makes sure that every object is linked to a group';
 | 
			
		||||
    protected $signature   = 'firefly-iii:upgrade-group-information';
 | 
			
		||||
    protected $signature   = 'correction:group-information';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -25,20 +25,17 @@ 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FixIbans
 | 
			
		||||
 */
 | 
			
		||||
class FixIbans extends Command
 | 
			
		||||
class CorrectsIbans extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Removes spaces from IBANs';
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-ibans';
 | 
			
		||||
    protected $signature   = 'correction:ibans';
 | 
			
		||||
    private int $count     = 0;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -49,9 +46,6 @@ class FixIbans extends Command
 | 
			
		||||
        $accounts = Account::whereNotNull('iban')->get();
 | 
			
		||||
        $this->filterIbans($accounts);
 | 
			
		||||
        $this->countAndCorrectIbans($accounts);
 | 
			
		||||
        if (0 === $this->count) {
 | 
			
		||||
            $this->friendlyPositive('All IBANs are valid.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -84,14 +78,14 @@ class FixIbans 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(
 | 
			
		||||
@@ -28,24 +28,22 @@ use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Models\TransactionGroup;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FixLongDescriptions
 | 
			
		||||
 */
 | 
			
		||||
class FixLongDescriptions extends Command
 | 
			
		||||
class CorrectsLongDescriptions extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    private const int MAX_LENGTH = 1000;
 | 
			
		||||
    protected $description       = 'Fixes long descriptions in journals and groups.';
 | 
			
		||||
    protected $signature         = 'firefly-iii:fix-long-descriptions';
 | 
			
		||||
    protected $signature         = 'correction:long-descriptions';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
     */
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
        $journals = TransactionJournal::get(['id', 'description']);
 | 
			
		||||
        $journals = TransactionJournal::where(DB::raw('LENGTH(description)'), '>', self::MAX_LENGTH)->get(['id', 'description']);
 | 
			
		||||
        $count    = 0;
 | 
			
		||||
 | 
			
		||||
        /** @var TransactionJournal $journal */
 | 
			
		||||
@@ -58,7 +56,7 @@ class FixLongDescriptions extends Command
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $groups   = TransactionGroup::get(['id', 'title']);
 | 
			
		||||
        $groups   = TransactionGroup::where(DB::raw('LENGTH(title)'), '>', self::MAX_LENGTH)->get(['id', 'title']);
 | 
			
		||||
 | 
			
		||||
        /** @var TransactionGroup $group */
 | 
			
		||||
        foreach ($groups as $group) {
 | 
			
		||||
@@ -69,9 +67,6 @@ class FixLongDescriptions extends Command
 | 
			
		||||
                ++$count;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All transaction group and journal title lengths are within bounds.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -26,16 +26,14 @@ namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class RenameMetaFields
 | 
			
		||||
 */
 | 
			
		||||
class RenameMetaFields extends Command
 | 
			
		||||
class CorrectsMetaDataFields extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Rename changed meta fields.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:rename-meta-fields';
 | 
			
		||||
    protected $signature   = 'correction:meta-fields';
 | 
			
		||||
 | 
			
		||||
    private int $count     = 0;
 | 
			
		||||
 | 
			
		||||
@@ -61,9 +59,6 @@ class RenameMetaFields extends Command
 | 
			
		||||
        foreach ($changes as $original => $update) {
 | 
			
		||||
            $this->rename($original, $update);
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $this->count) {
 | 
			
		||||
            $this->friendlyPositive('All meta fields are correct.');
 | 
			
		||||
        }
 | 
			
		||||
        if (0 !== $this->count) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('Renamed %d meta field(s).', $this->count));
 | 
			
		||||
        }
 | 
			
		||||
@@ -73,7 +68,7 @@ class RenameMetaFields extends Command
 | 
			
		||||
 | 
			
		||||
    private function rename(string $original, string $update): void
 | 
			
		||||
    {
 | 
			
		||||
        $total = \DB::table('journal_meta')
 | 
			
		||||
        $total = DB::table('journal_meta')
 | 
			
		||||
            ->where('name', '=', $original)
 | 
			
		||||
            ->update(['name' => $update])
 | 
			
		||||
        ;
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -46,19 +48,24 @@ use Illuminate\Database\Query\Builder as DatabaseBuilder;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
class RecalculateNativeAmounts extends Command
 | 
			
		||||
class CorrectsNativeAmounts extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Recalculate native amounts for all objects.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:recalculate-native-amounts';
 | 
			
		||||
    protected $signature   = 'correction:recalculate-native-amounts';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
     */
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
        if (false === config('cer.enabled')) {
 | 
			
		||||
            $this->friendlyInfo('This command will not run because currency exchange rates are disabled.');
 | 
			
		||||
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        Log::debug('Will update all native amounts. This may take some time.');
 | 
			
		||||
        $this->friendlyWarning('Recalculating native amounts for all objects. This may take some time!');
 | 
			
		||||
 | 
			
		||||
@@ -102,7 +109,7 @@ class RecalculateNativeAmounts extends Command
 | 
			
		||||
        foreach ($set as $account) {
 | 
			
		||||
            $account->touch();
 | 
			
		||||
        }
 | 
			
		||||
        Log::debug(sprintf('Recalculated %d accounts', $set->count()));
 | 
			
		||||
        Log::debug(sprintf('Recalculated %d accounts for user group #%d.', $set->count(), $userGroup->id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function recalculatePiggyBanks(UserGroup $userGroup, TransactionCurrency $currency): void
 | 
			
		||||
@@ -124,14 +131,14 @@ class RecalculateNativeAmounts extends Command
 | 
			
		||||
 | 
			
		||||
            foreach ($piggyBank->accounts as $account) {
 | 
			
		||||
                $account->pivot->native_current_amount = null;
 | 
			
		||||
                if (0 !== bccomp($account->pivot->current_amount, '0')) {
 | 
			
		||||
                    $account->pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $currency, today(), $account->pivot->current_amount);
 | 
			
		||||
                if (0 !== bccomp((string) $account->pivot->current_amount, '0')) {
 | 
			
		||||
                    $account->pivot->native_current_amount = $converter->convert($piggyBank->transactionCurrency, $currency, today(), (string) $account->pivot->current_amount);
 | 
			
		||||
                }
 | 
			
		||||
                $account->pivot->save();
 | 
			
		||||
            }
 | 
			
		||||
            $this->recalculatePiggyBankEvents($piggyBank);
 | 
			
		||||
        }
 | 
			
		||||
        Log::debug(sprintf('Recalculated %d piggy banks.', $set->count()));
 | 
			
		||||
        Log::debug(sprintf('Recalculated %d piggy banks for user group #%d.', $set->count(), $userGroup->id));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -139,7 +146,7 @@ class RecalculateNativeAmounts extends Command
 | 
			
		||||
    {
 | 
			
		||||
        $set = $piggyBank->piggyBankEvents()->get();
 | 
			
		||||
        $set->each(
 | 
			
		||||
            static function (PiggyBankEvent $event): void {
 | 
			
		||||
            static function (PiggyBankEvent $event): void { // @phpstan-ignore-line
 | 
			
		||||
                $event->touch();
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
@@ -168,7 +175,7 @@ class RecalculateNativeAmounts extends Command
 | 
			
		||||
            $limit->touch();
 | 
			
		||||
            Log::debug(sprintf('Done with touch BL #%d', $limit->id));
 | 
			
		||||
        }
 | 
			
		||||
        Log::debug(sprintf('Recalculated %d budget limits.', $set->count()));
 | 
			
		||||
        Log::debug(sprintf('Recalculated %d budget limits for budget #%d.', $set->count(), $budget->id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function recalculateAutoBudgets(Budget $budget, TransactionCurrency $currency): void
 | 
			
		||||
@@ -179,7 +186,7 @@ class RecalculateNativeAmounts extends Command
 | 
			
		||||
        foreach ($set as $autoBudget) {
 | 
			
		||||
            $autoBudget->touch();
 | 
			
		||||
        }
 | 
			
		||||
        Log::debug(sprintf('Recalculated %d auto budgets.', $set->count()));
 | 
			
		||||
        Log::debug(sprintf('Recalculated %d auto budgets for budget #%d.', $set->count(), $budget->id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function recalculateAvailableBudgets(UserGroup $userGroup, TransactionCurrency $currency): void
 | 
			
		||||
@@ -229,8 +236,9 @@ class RecalculateNativeAmounts 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,25 +25,22 @@ 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CorrectOpeningBalanceCurrencies
 | 
			
		||||
 */
 | 
			
		||||
class CorrectOpeningBalanceCurrencies extends Command
 | 
			
		||||
class CorrectsOpeningBalanceCurrencies extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Will make sure that opening balance transaction currencies match the account they\'re for.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-ob-currencies';
 | 
			
		||||
    protected $signature   = 'correction:opening-balance-currencies';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -62,20 +59,16 @@ class CorrectOpeningBalanceCurrencies extends Command
 | 
			
		||||
            $message = sprintf('Corrected %d opening balance transaction(s).', $count);
 | 
			
		||||
            $this->friendlyInfo($message);
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $message = 'There was nothing to fix in the opening balance transactions.';
 | 
			
		||||
            $this->friendlyPositive($message);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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.*'])
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -103,7 +96,7 @@ class CorrectOpeningBalanceCurrencies 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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -29,17 +29,12 @@ use FireflyIII\Models\PiggyBankEvent;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Report (and fix) piggy banks.
 | 
			
		||||
 *
 | 
			
		||||
 * Class FixPiggies
 | 
			
		||||
 */
 | 
			
		||||
class FixPiggies extends Command
 | 
			
		||||
class CorrectsPiggyBanks extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Fixes common issues with piggy banks.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-piggies';
 | 
			
		||||
    protected $signature   = 'correction:piggy-banks';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -66,9 +61,6 @@ class FixPiggies extends Command
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All piggy bank events are OK.');
 | 
			
		||||
        }
 | 
			
		||||
        if (0 !== $count) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('Fixed %d piggy bank event(s).', $count));
 | 
			
		||||
        }
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * MigratePreferences.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 * CorrectsPreferences.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\Models\Preference;
 | 
			
		||||
@@ -28,11 +30,11 @@ use FireflyIII\User;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Symfony\Component\Console\Command\Command as CommandAlias;
 | 
			
		||||
 | 
			
		||||
class MigratePreferences extends Command
 | 
			
		||||
class CorrectsPreferences extends Command
 | 
			
		||||
{
 | 
			
		||||
    protected $description = 'Give Firefly III preferences a user group ID so they can be made administration specific.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:migrate-preferences';
 | 
			
		||||
    protected $signature   = 'correction:preferences';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -50,7 +52,7 @@ class MigratePreferences extends Command
 | 
			
		||||
                if (null === $preference) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                if (null !== $preference->user_group_id) {
 | 
			
		||||
                if (null === $preference->user_group_id) {
 | 
			
		||||
                    $preference->user_group_id = $user->user_group_id;
 | 
			
		||||
                    $preference->save();
 | 
			
		||||
                    ++$count;
 | 
			
		||||
@@ -33,15 +33,12 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FixRecurringTransactions
 | 
			
		||||
 */
 | 
			
		||||
class FixRecurringTransactions extends Command
 | 
			
		||||
class CorrectsRecurringTransactions extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description                      = 'Fixes recurring transactions with the wrong transaction type.';
 | 
			
		||||
    protected $signature                        = 'firefly-iii:fix-recurring-transactions';
 | 
			
		||||
    protected $signature                        = 'correction:recurring-transactions';
 | 
			
		||||
    private int                          $count = 0;
 | 
			
		||||
    private RecurringRepositoryInterface $recurringRepos;
 | 
			
		||||
    private UserRepositoryInterface      $userRepos;
 | 
			
		||||
@@ -53,9 +50,6 @@ class FixRecurringTransactions extends Command
 | 
			
		||||
    {
 | 
			
		||||
        $this->stupidLaravel();
 | 
			
		||||
        $this->correctTransactions();
 | 
			
		||||
        if (0 === $this->count) {
 | 
			
		||||
            $this->friendlyPositive('All recurring transactions are OK.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1,5 +1,25 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * CorrectsTimezoneInformation.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);
 | 
			
		||||
/*
 | 
			
		||||
 * AddTimezonesToDates.php
 | 
			
		||||
@@ -21,7 +41,7 @@ declare(strict_types=1);
 | 
			
		||||
 * along with this program.  If not, see https://www.gnu.org/licenses/.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Console\Commands\Integrity;
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Models\AccountBalance;
 | 
			
		||||
@@ -41,7 +61,7 @@ use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Database\QueryException;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
class AddTimezonesToDates extends Command
 | 
			
		||||
class CorrectsTimezoneInformation extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
@@ -61,19 +81,8 @@ class AddTimezonesToDates extends Command
 | 
			
		||||
            TransactionJournal::class   => ['date'],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The console command description.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $description = 'Make sure all dates have a timezone.';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The name and signature of the console command.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $signature   = 'firefly-iii:add-timezones-to-dates';
 | 
			
		||||
    protected $signature   = 'correction:timezones';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -107,8 +116,6 @@ class AddTimezonesToDates extends Command
 | 
			
		||||
            Log::error($e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive(sprintf('Timezone information is present in field "%s" of model "%s".', $field, $shortModel));
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        $this->friendlyInfo(sprintf('Adding timezone information to field "%s" of model "%s".', $field, $shortModel));
 | 
			
		||||
@@ -34,15 +34,12 @@ use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FixTransactionTypes
 | 
			
		||||
 */
 | 
			
		||||
class FixTransactionTypes extends Command
 | 
			
		||||
class CorrectsTransactionTypes extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Make sure all transactions are of the correct type, based on source + dest.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-transaction-types';
 | 
			
		||||
    protected $signature   = 'correction:transaction-types';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -25,19 +25,16 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use FireflyIII\Models\TransactionType;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class TransferBudgets
 | 
			
		||||
 */
 | 
			
		||||
class TransferBudgets extends Command
 | 
			
		||||
class CorrectsTransferBudgets extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Removes budgets from transfers.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-transfer-budgets';
 | 
			
		||||
    protected $signature   = 'correction:transfer-budgets';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -47,7 +44,7 @@ class TransferBudgets extends Command
 | 
			
		||||
        $set   = TransactionJournal::distinct()
 | 
			
		||||
            ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
 | 
			
		||||
            ->leftJoin('budget_transaction_journal', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id')
 | 
			
		||||
            ->whereNotIn('transaction_types.type', [TransactionType::WITHDRAWAL])
 | 
			
		||||
            ->whereNotIn('transaction_types.type', [TransactionTypeEnum::WITHDRAWAL->value])
 | 
			
		||||
            ->whereNotNull('budget_transaction_journal.budget_id')->get(['transaction_journals.*'])
 | 
			
		||||
        ;
 | 
			
		||||
        $count = 0;
 | 
			
		||||
@@ -60,10 +57,6 @@ class TransferBudgets extends Command
 | 
			
		||||
            $entry->budgets()->sync([]);
 | 
			
		||||
            ++$count;
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $message = 'No invalid budget/journal entries.';
 | 
			
		||||
            $this->friendlyPositive($message);
 | 
			
		||||
        }
 | 
			
		||||
        if (0 !== $count) {
 | 
			
		||||
            $message = sprintf('Corrected %d invalid budget/journal entries (entry).', $count);
 | 
			
		||||
            app('log')->debug($message);
 | 
			
		||||
@@ -28,20 +28,16 @@ use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Models\Transaction;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use FireflyIII\Models\TransactionType;
 | 
			
		||||
use FireflyIII\Support\Models\AccountBalanceCalculator;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FixUnevenAmount
 | 
			
		||||
 */
 | 
			
		||||
class FixUnevenAmount extends Command
 | 
			
		||||
class CorrectsUnevenAmount extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Fix journals with uneven amounts.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-uneven-amount';
 | 
			
		||||
    protected $signature   = 'correction:uneven-amounts';
 | 
			
		||||
    private int $count;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -53,7 +49,7 @@ class FixUnevenAmount extends Command
 | 
			
		||||
        $this->convertOldStyleTransfers();
 | 
			
		||||
        $this->fixUnevenAmounts();
 | 
			
		||||
        $this->matchCurrencies();
 | 
			
		||||
        if (config('firefly.feature_flags.running_balance_column')) {
 | 
			
		||||
        if (true === config('firefly.feature_flags.running_balance_column')) {
 | 
			
		||||
            $this->friendlyInfo('Will recalculate transaction running balance columns. This may take a LONG time. Please be patient.');
 | 
			
		||||
            AccountBalanceCalculator::recalculateAll(false);
 | 
			
		||||
            $this->friendlyInfo('Done recalculating transaction running balance columns.');
 | 
			
		||||
@@ -87,7 +83,7 @@ class FixUnevenAmount extends Command
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            // needs to be a transfer.
 | 
			
		||||
            if (TransactionType::TRANSFER !== $journal->transactionType->type) {
 | 
			
		||||
            if (TransactionTypeEnum::TRANSFER->value !== $journal->transactionType->type) {
 | 
			
		||||
                Log::debug('Must be a transfer, continue.');
 | 
			
		||||
 | 
			
		||||
                continue;
 | 
			
		||||
@@ -118,11 +114,6 @@ class FixUnevenAmount extends Command
 | 
			
		||||
                ++$count;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('No "old style" foreign currency transfers.');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function fixUnevenAmounts(): void
 | 
			
		||||
@@ -130,7 +121,7 @@ class FixUnevenAmount extends Command
 | 
			
		||||
        $journals = \DB::table('transactions')
 | 
			
		||||
            ->groupBy('transaction_journal_id')
 | 
			
		||||
            ->whereNull('deleted_at')
 | 
			
		||||
            ->get(['transaction_journal_id', \DB::raw('SUM(amount) AS the_sum')])
 | 
			
		||||
            ->get(['transaction_journal_id', \DB::raw('SUM(amount) AS the_sum')])  // @phpstan-ignore-line
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
        /** @var \stdClass $entry */
 | 
			
		||||
@@ -164,9 +155,6 @@ class FixUnevenAmount extends Command
 | 
			
		||||
                $this->fixJournal($entry->transaction_journal_id);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $this->count) {
 | 
			
		||||
            $this->friendlyPositive('Database amount integrity is OK');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function fixJournal(int $param): void
 | 
			
		||||
@@ -239,7 +227,7 @@ class FixUnevenAmount extends Command
 | 
			
		||||
 | 
			
		||||
    private function isForeignCurrencyTransfer(TransactionJournal $journal): bool
 | 
			
		||||
    {
 | 
			
		||||
        if (TransactionType::TRANSFER !== $journal->transactionType->type) {
 | 
			
		||||
        if (TransactionTypeEnum::TRANSFER->value !== $journal->transactionType->type) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -291,8 +279,6 @@ class FixUnevenAmount extends Command
 | 
			
		||||
            Log::debug(sprintf('Can skip foreign currency transfer #%d.', $journal->id));
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('Journal currency integrity is OK');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -29,16 +29,13 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CreateAccessTokens
 | 
			
		||||
 */
 | 
			
		||||
class CreateAccessTokens extends Command
 | 
			
		||||
class CreatesAccessTokens extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Creates user access tokens which are used for command line access to personal data.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:create-access-tokens';
 | 
			
		||||
    protected $signature   = 'correction:access-tokens';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -64,9 +61,6 @@ class CreateAccessTokens extends Command
 | 
			
		||||
                ++$count;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('Verified access tokens.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * CreateGroupMemberships.php
 | 
			
		||||
 * Copyright (c) 2023 james@firefly-iii.org
 | 
			
		||||
 * CreatesGroupMemberships.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -17,12 +17,12 @@
 | 
			
		||||
 * 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\Console\Commands\Integrity;
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Enums\UserRoleEnum;
 | 
			
		||||
@@ -33,16 +33,13 @@ use FireflyIII\Models\UserRole;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CreateGroupMemberships
 | 
			
		||||
 */
 | 
			
		||||
class CreateGroupMemberships extends Command
 | 
			
		||||
class CreatesGroupMemberships extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    public const string CONFIG_NAME = '560_create_group_memberships';
 | 
			
		||||
    protected $description          = 'Update group memberships';
 | 
			
		||||
    protected $signature            = 'firefly-iii:create-group-memberships';
 | 
			
		||||
    protected $signature            = 'correction:create-group-memberships';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -52,7 +49,6 @@ class CreateGroupMemberships extends Command
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
        $this->createGroupMemberships();
 | 
			
		||||
        $this->friendlyPositive('Validated group memberships');
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -28,16 +28,13 @@ use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Models\LinkType;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CreateLinkTypes. Created all link types in case a migration hasn't fired.
 | 
			
		||||
 */
 | 
			
		||||
class CreateLinkTypes extends Command
 | 
			
		||||
class CreatesLinkTypes extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Creates all link types.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:create-link-types';
 | 
			
		||||
    protected $signature   = 'correction:link-types';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -66,9 +63,6 @@ class CreateLinkTypes extends Command
 | 
			
		||||
            $link->editable = false;
 | 
			
		||||
            $link->save();
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All link types are OK');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -25,19 +25,17 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Enums\TransactionTypeEnum;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use FireflyIII\Models\TransactionType;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class RemoveBills
 | 
			
		||||
 */
 | 
			
		||||
class RemoveBills extends Command
 | 
			
		||||
class RemovesBills extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Remove bills from transactions that shouldn\'t have one.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:remove-bills';
 | 
			
		||||
    protected $signature   = 'correction:bills';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -45,7 +43,7 @@ class RemoveBills extends Command
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
        /** @var null|TransactionType $withdrawal */
 | 
			
		||||
        $withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first();
 | 
			
		||||
        $withdrawal = TransactionType::where('type', TransactionTypeEnum::WITHDRAWAL->value)->first();
 | 
			
		||||
        if (null === $withdrawal) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
@@ -60,7 +58,6 @@ class RemoveBills extends Command
 | 
			
		||||
        if ($journals->count() > 0) {
 | 
			
		||||
            $this->friendlyInfo('Fixed all transaction journals so they have correct bill information.');
 | 
			
		||||
        }
 | 
			
		||||
        $this->friendlyPositive('All bills and journals are OK');
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -24,25 +24,21 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Models\TransactionGroup;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class DeleteEmptyGroups
 | 
			
		||||
 */
 | 
			
		||||
class DeleteEmptyGroups extends Command
 | 
			
		||||
class RemovesEmptyGroups extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Delete empty transaction groups.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:delete-empty-groups';
 | 
			
		||||
    protected $signature   = 'correction:empty-groups';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
     *
 | 
			
		||||
     * @throws Exception;
 | 
			
		||||
     * @throws \Exception
 | 
			
		||||
     */
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
@@ -61,9 +57,6 @@ class DeleteEmptyGroups extends Command
 | 
			
		||||
                TransactionGroup::whereNull('deleted_at')->whereIn('id', $chunk)->delete();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $total) {
 | 
			
		||||
            $this->friendlyInfo('Verified there are no empty groups.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -30,16 +30,13 @@ use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Database\QueryException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class DeleteEmptyJournals
 | 
			
		||||
 */
 | 
			
		||||
class DeleteEmptyJournals extends Command
 | 
			
		||||
class RemovesEmptyJournals extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Delete empty and uneven transaction journals.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:delete-empty-journals';
 | 
			
		||||
    protected $signature   = 'correction:empty-journals';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -69,7 +66,9 @@ class DeleteEmptyJournals extends Command
 | 
			
		||||
            if (1 === $count % 2) {
 | 
			
		||||
                // uneven number, delete journal and transactions:
 | 
			
		||||
                try {
 | 
			
		||||
                    TransactionJournal::find($row->transaction_journal_id)->delete();
 | 
			
		||||
                    /** @var null|TransactionJournal $journal */
 | 
			
		||||
                    $journal = TransactionJournal::find($row->transaction_journal_id);
 | 
			
		||||
                    $journal?->delete();
 | 
			
		||||
                } catch (QueryException $e) {
 | 
			
		||||
                    app('log')->info(sprintf('Could not delete journal: %s', $e->getMessage()));
 | 
			
		||||
                    app('log')->error($e->getTraceAsString());
 | 
			
		||||
@@ -82,9 +81,6 @@ class DeleteEmptyJournals extends Command
 | 
			
		||||
                ++$total;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $total) {
 | 
			
		||||
            $this->friendlyPositive('No uneven transaction journals.');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function deleteEmptyJournals(): void
 | 
			
		||||
@@ -98,7 +94,9 @@ class DeleteEmptyJournals extends Command
 | 
			
		||||
 | 
			
		||||
        foreach ($set as $entry) {
 | 
			
		||||
            try {
 | 
			
		||||
                TransactionJournal::find($entry->id)->delete();
 | 
			
		||||
                /** @var null|TransactionJournal $journal */
 | 
			
		||||
                $journal = TransactionJournal::find($entry->id);
 | 
			
		||||
                $journal?->delete();
 | 
			
		||||
            } catch (QueryException $e) {
 | 
			
		||||
                app('log')->info(sprintf('Could not delete entry: %s', $e->getMessage()));
 | 
			
		||||
                app('log')->error($e->getTraceAsString());
 | 
			
		||||
@@ -107,8 +105,5 @@ class DeleteEmptyJournals extends Command
 | 
			
		||||
            $this->friendlyInfo(sprintf('Deleted empty transaction journal #%d', $entry->id));
 | 
			
		||||
            ++$count;
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('No empty transaction journals.');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -32,13 +32,13 @@ use Illuminate\Console\Command;
 | 
			
		||||
/**
 | 
			
		||||
 * Deletes transactions where the journal has been deleted.
 | 
			
		||||
 */
 | 
			
		||||
class DeleteOrphanedTransactions extends Command
 | 
			
		||||
class RemovesOrphanedTransactions extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Deletes orphaned transactions.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:delete-orphaned-transactions';
 | 
			
		||||
    protected $signature   = 'correction:orphaned-transactions';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -63,12 +63,13 @@ class DeleteOrphanedTransactions extends Command
 | 
			
		||||
        ;
 | 
			
		||||
        $count = $set->count();
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('No orphaned journals.');
 | 
			
		||||
            // $this->friendlyPositive('No orphaned journals.');
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        $this->friendlyInfo(sprintf('Found %d orphaned journal(s).', $count));
 | 
			
		||||
        foreach ($set as $entry) {
 | 
			
		||||
            /** @var null|TransactionJournal $journal */
 | 
			
		||||
            $journal = TransactionJournal::withTrashed()->find($entry->id);
 | 
			
		||||
            if (null !== $journal) {
 | 
			
		||||
                $journal->delete();
 | 
			
		||||
@@ -116,9 +117,6 @@ class DeleteOrphanedTransactions extends Command
 | 
			
		||||
                ++$count;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('No orphaned transactions.');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function deleteFromOrphanedAccounts(): void
 | 
			
		||||
@@ -133,6 +131,7 @@ class DeleteOrphanedTransactions extends Command
 | 
			
		||||
        /** @var Transaction $transaction */
 | 
			
		||||
        foreach ($set as $transaction) {
 | 
			
		||||
            // delete journals
 | 
			
		||||
            /** @var null|TransactionJournal $journal */
 | 
			
		||||
            $journal = TransactionJournal::find($transaction->transaction_journal_id);
 | 
			
		||||
            if (null !== $journal) {
 | 
			
		||||
                $journal->delete();
 | 
			
		||||
@@ -147,8 +146,5 @@ class DeleteOrphanedTransactions extends Command
 | 
			
		||||
            );
 | 
			
		||||
            ++$count;
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('No orphaned accounts.');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -29,16 +29,13 @@ use FireflyIII\Models\Transaction;
 | 
			
		||||
use FireflyIII\Models\TransactionJournal;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class DeleteZeroAmount
 | 
			
		||||
 */
 | 
			
		||||
class DeleteZeroAmount extends Command
 | 
			
		||||
class RemovesZeroAmount extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Delete transactions with zero amount.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:delete-zero-amount';
 | 
			
		||||
    protected $signature   = 'correction:zero-amounts';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -56,9 +53,6 @@ class DeleteZeroAmount extends Command
 | 
			
		||||
 | 
			
		||||
            Transaction::where('transaction_journal_id', $journal->id)->delete();
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $journals->count()) {
 | 
			
		||||
            $this->friendlyPositive('No zero-amount transaction journals.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * RestoreOAuthKeys.php
 | 
			
		||||
 * Copyright (c) 2020 james@firefly-iii.org
 | 
			
		||||
/*
 | 
			
		||||
 * RestoresOAuthKeys.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
			
		||||
 *
 | 
			
		||||
@@ -17,26 +17,23 @@
 | 
			
		||||
 * 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\Console\Commands\Integrity;
 | 
			
		||||
namespace FireflyIII\Console\Commands\Correction;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Support\System\OAuthKeys;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class RestoreOAuthKeys
 | 
			
		||||
 */
 | 
			
		||||
class RestoreOAuthKeys extends Command
 | 
			
		||||
class RestoresOAuthKeys extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Will restore the OAuth keys generated for the system.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:restore-oauth-keys';
 | 
			
		||||
    protected $signature   = 'correction:restore-oauth-keys';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -76,7 +73,6 @@ class RestoreOAuthKeys extends Command
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        $this->friendlyPositive('OAuth keys are OK');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function keysInDatabase(): bool
 | 
			
		||||
@@ -28,13 +28,10 @@ use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Services\Internal\Support\CreditRecalculateService;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CorrectionSkeleton
 | 
			
		||||
 */
 | 
			
		||||
class TriggerCreditCalculation extends Command
 | 
			
		||||
class TriggersCreditCalculation extends Command
 | 
			
		||||
{
 | 
			
		||||
    protected $description = 'Triggers the credit recalculation service for liabilities.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:trigger-credit-recalculation';
 | 
			
		||||
    protected $signature   = 'correction:recalculates-liabilities';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -27,19 +27,16 @@ namespace FireflyIII\Console\Commands\Export;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Console\Commands\VerifiesAccessToken;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
 | 
			
		||||
use FireflyIII\Support\Export\ExportDataGenerator;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ExportData
 | 
			
		||||
 */
 | 
			
		||||
class ExportData extends Command
 | 
			
		||||
class ExportsData extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
    use VerifiesAccessToken;
 | 
			
		||||
@@ -232,7 +229,7 @@ class ExportData extends Command
 | 
			
		||||
        $final       = new Collection();
 | 
			
		||||
        $accounts    = new Collection();
 | 
			
		||||
        $accountList = (string) $this->option('accounts');
 | 
			
		||||
        $types       = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
 | 
			
		||||
        $types       = [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value];
 | 
			
		||||
        if ('' !== $accountList) {
 | 
			
		||||
            $accountIds = explode(',', $accountList);
 | 
			
		||||
            $accounts   = $this->accountRepository->getAccountsById($accountIds);
 | 
			
		||||
@@ -4,10 +4,6 @@ namespace FireflyIII\Console\Commands\Integrity;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ReportSkeleton
 | 
			
		||||
 * TODO DONT FORGET TO ADD THIS TO THE DOCKER BUILD
 | 
			
		||||
 */
 | 
			
		||||
class ReportSkeleton extends Command
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -31,16 +31,13 @@ use FireflyIII\Models\Category;
 | 
			
		||||
use FireflyIII\Models\Tag;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ReportEmptyObjects
 | 
			
		||||
 */
 | 
			
		||||
class ReportEmptyObjects extends Command
 | 
			
		||||
class ReportsEmptyObjects extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Reports on empty database objects.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:report-empty-objects';
 | 
			
		||||
    protected $signature   = 'integrity:empty-objects';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -27,10 +27,7 @@ namespace FireflyIII\Console\Commands\Integrity;
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ReportIntegrity
 | 
			
		||||
 */
 | 
			
		||||
class ReportIntegrity extends Command
 | 
			
		||||
class ReportsIntegrity extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
@@ -48,11 +45,8 @@ class ReportIntegrity extends Command
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
        $commands = [
 | 
			
		||||
            'firefly-iii:add-timezones-to-dates',
 | 
			
		||||
            'firefly-iii:create-group-memberships',
 | 
			
		||||
            'firefly-iii:report-empty-objects',
 | 
			
		||||
            'firefly-iii:report-sum',
 | 
			
		||||
            'firefly-iii:upgrade-group-information',
 | 
			
		||||
            'integrity:empty-objects',
 | 
			
		||||
            'integrity:total-sums',
 | 
			
		||||
        ];
 | 
			
		||||
        foreach ($commands as $command) {
 | 
			
		||||
            $this->friendlyLine(sprintf('Now executing %s', $command));
 | 
			
		||||
@@ -29,15 +29,12 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ReportSkeleton
 | 
			
		||||
 */
 | 
			
		||||
class ReportSum extends Command
 | 
			
		||||
class ReportsSums extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Report on the total sum of transactions. Must be 0.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:report-sum';
 | 
			
		||||
    protected $signature   = 'integrity:total-sums';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -64,12 +61,7 @@ class ReportSum extends Command
 | 
			
		||||
            $sum     = '' === $sum ? '0' : $sum;
 | 
			
		||||
            $foreign = '' === $foreign ? '0' : $foreign;
 | 
			
		||||
            $total   = bcadd($sum, $foreign);
 | 
			
		||||
            if (!is_numeric($total)) {
 | 
			
		||||
                $message = sprintf('Error: Transactions for user #%d (%s) have an invalid sum ("%s").', $user->id, $user->email, $total);
 | 
			
		||||
                $this->friendlyError($message);
 | 
			
		||||
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if (0 !== bccomp($total, '0')) {
 | 
			
		||||
                $message = sprintf('Error: Transactions for user #%d (%s) are off by %s!', $user->id, $user->email, $total);
 | 
			
		||||
                $this->friendlyError($message);
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * LaravelPassportKeys.php
 | 
			
		||||
 * Copyright (c) 2024 james@firefly-iii.org.
 | 
			
		||||
 * CallsLaravelPassportKeys.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\System;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
@@ -28,7 +30,7 @@ use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Facades\Artisan;
 | 
			
		||||
use Symfony\Component\Console\Command\Command as CommandAlias;
 | 
			
		||||
 | 
			
		||||
class LaravelPassportKeys extends Command
 | 
			
		||||
class CallsLaravelPassportKeys extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
@@ -28,10 +28,7 @@ use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use PDO;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CreateDatabase
 | 
			
		||||
 */
 | 
			
		||||
class CreateDatabase extends Command
 | 
			
		||||
class CreatesDatabase extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
@@ -39,24 +36,19 @@ class CreateDatabase extends Command
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:create-database';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
     *
 | 
			
		||||
     * @suppressWarnings(PHPMD.MissingImport)
 | 
			
		||||
     */
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
        if ('mysql' !== env('DB_CONNECTION', 'mysql')) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('CreateDB does not apply to "%s", skipped.', env('DB_CONNECTION')));
 | 
			
		||||
        if ('mysql' !== config('database.default')) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('CreateDB does not apply to "%s", skipped.', config('database.default')));
 | 
			
		||||
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        // try to set up a raw connection:
 | 
			
		||||
        $exists  = false;
 | 
			
		||||
        $dsn     = sprintf('mysql:host=%s;port=%d;charset=utf8mb4', env('DB_HOST', 'localhost'), env('DB_PORT', '3306'));
 | 
			
		||||
        $dsn     = sprintf('mysql:host=%s;port=%d;charset=utf8mb4', config('database.mysql.host'), config('database.mysql.port'));
 | 
			
		||||
 | 
			
		||||
        if ('' !== env('DB_SOCKET', '')) {
 | 
			
		||||
            $dsn = sprintf('mysql:unix_socket=%s;charset=utf8mb4', env('DB_SOCKET', ''));
 | 
			
		||||
        if ('' !== config('database.mysql.unix_socket')) {
 | 
			
		||||
            $dsn = sprintf('mysql:unix_socket=%s;charset=utf8mb4', config('database.mysql.unix_socket'));
 | 
			
		||||
        }
 | 
			
		||||
        $this->friendlyLine(sprintf('DSN is %s', $dsn));
 | 
			
		||||
 | 
			
		||||
@@ -68,7 +60,7 @@ class CreateDatabase extends Command
 | 
			
		||||
 | 
			
		||||
        // when it fails, display error
 | 
			
		||||
        try {
 | 
			
		||||
            $pdo = new \PDO($dsn, env('DB_USERNAME'), env('DB_PASSWORD'), $options);
 | 
			
		||||
            $pdo = new \PDO($dsn, config('database.mysql.username'), config('database.mysql.password'), $options);
 | 
			
		||||
        } catch (\PDOException $e) {
 | 
			
		||||
            $this->friendlyError(sprintf('Error when connecting to DB: %s', $e->getMessage()));
 | 
			
		||||
 | 
			
		||||
@@ -82,19 +74,19 @@ class CreateDatabase extends Command
 | 
			
		||||
        // slightly more complex but less error-prone.
 | 
			
		||||
        foreach ($stmt as $row) {
 | 
			
		||||
            $name = $row['Database'] ?? false;
 | 
			
		||||
            if ($name === env('DB_DATABASE')) {
 | 
			
		||||
            if ($name === config('database.mysql.database')) {
 | 
			
		||||
                $exists = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (false === $exists) {
 | 
			
		||||
            $this->friendlyError(sprintf('Database "%s" does not exist.', env('DB_DATABASE')));
 | 
			
		||||
            $this->friendlyError(sprintf('Database "%s" does not exist.', config('database.mysql.database')));
 | 
			
		||||
 | 
			
		||||
            // try to create it.
 | 
			
		||||
            $pdo->exec(sprintf('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', env('DB_DATABASE')));
 | 
			
		||||
            $this->friendlyInfo(sprintf('Created database "%s"', env('DB_DATABASE')));
 | 
			
		||||
            $pdo->exec(sprintf('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', config('database.mysql.database')));
 | 
			
		||||
            $this->friendlyInfo(sprintf('Created database "%s"', config('database.mysql.database')));
 | 
			
		||||
        }
 | 
			
		||||
        if (true === $exists) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('Database "%s" exists.', env('DB_DATABASE')));
 | 
			
		||||
            $this->friendlyInfo(sprintf('Database "%s" exists.', config('database.mysql.database')));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
@@ -29,16 +29,13 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Facades\Hash;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CreateFirstUser
 | 
			
		||||
 */
 | 
			
		||||
class CreateFirstUser extends Command
 | 
			
		||||
class CreatesFirstUser extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Creates a new user and gives admin rights. Outputs the password on the command line. Strictly for testing.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:create-first-user {email}';
 | 
			
		||||
    protected $signature   = 'system:create-first-user {email}';
 | 
			
		||||
    private UserRepositoryInterface $repository;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -46,7 +43,7 @@ class CreateFirstUser extends Command
 | 
			
		||||
     */
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
        if ('testing' !== env('APP_ENV', 'local')) {
 | 
			
		||||
        if ('testing' !== config('app.env')) {
 | 
			
		||||
            $this->friendlyError('This command only works in the testing environment.');
 | 
			
		||||
 | 
			
		||||
            return 1;
 | 
			
		||||
@@ -44,13 +44,11 @@ use Illuminate\Support\Collection;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ForceDecimalSize
 | 
			
		||||
 *
 | 
			
		||||
 * This command was inspired by https://github.com/elliot-gh. It will check all amount fields
 | 
			
		||||
 * and their values and correct them to the correct number of decimal places. This fixes issues where
 | 
			
		||||
 * Firefly III would store 0.01 as 0.01000000000000000020816681711721685132943093776702880859375.
 | 
			
		||||
 */
 | 
			
		||||
class ForceDecimalSize extends Command
 | 
			
		||||
class ForcesDecimalSize extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
@@ -175,7 +173,7 @@ class ForceDecimalSize extends Command
 | 
			
		||||
         * @var array  $fields
 | 
			
		||||
         */
 | 
			
		||||
        foreach ($this->tables as $name => $fields) {
 | 
			
		||||
            switch ($name) { // @phpstan-ignore-line
 | 
			
		||||
            switch ($name) {
 | 
			
		||||
                default:
 | 
			
		||||
                    $message = sprintf('Cannot handle table "%s"', $name);
 | 
			
		||||
                    $this->friendlyError($message);
 | 
			
		||||
@@ -241,7 +239,7 @@ class ForceDecimalSize extends Command
 | 
			
		||||
        $query->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void {
 | 
			
		||||
            foreach ($fields as $field) {
 | 
			
		||||
                $q->orWhere(
 | 
			
		||||
                    DB::raw(sprintf('CAST(accounts.%s AS %s)', $field, $cast)), // @phpstan-ignore-line
 | 
			
		||||
                    DB::raw(sprintf('CAST(accounts.%s AS %s)', $field, $cast)),
 | 
			
		||||
                    $operator,
 | 
			
		||||
                    DB::raw(sprintf($regularExpression, $currency->decimal_places))
 | 
			
		||||
                );
 | 
			
		||||
@@ -258,15 +256,18 @@ class ForceDecimalSize extends Command
 | 
			
		||||
        foreach ($result as $account) {
 | 
			
		||||
            /** @var string $field */
 | 
			
		||||
            foreach ($fields as $field) {
 | 
			
		||||
                $value   = $account->{$field};
 | 
			
		||||
                $value         = $account->{$field};
 | 
			
		||||
                if (null === $value) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                // fix $field by rounding it down correctly.
 | 
			
		||||
                $pow     = 10 ** $currency->decimal_places;
 | 
			
		||||
                $correct = bcdiv((string) round($value * $pow), (string) $pow, 12);
 | 
			
		||||
                $pow           = 10 ** $currency->decimal_places;
 | 
			
		||||
                $correct       = bcdiv((string) round($value * $pow), (string) $pow, 12);
 | 
			
		||||
                $this->friendlyInfo(sprintf('Account #%d has %s with value "%s", this has been corrected to "%s".', $account->id, $field, $value, $correct));
 | 
			
		||||
                Account::find($account->id)->update([$field => $correct]);
 | 
			
		||||
 | 
			
		||||
                /** @var null|Account $updateAccount */
 | 
			
		||||
                $updateAccount = Account::find($account->id);
 | 
			
		||||
                $updateAccount?->update([$field => $correct]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -288,7 +289,7 @@ class ForceDecimalSize extends Command
 | 
			
		||||
                /** @var string $field */
 | 
			
		||||
                foreach ($fields as $field) {
 | 
			
		||||
                    $q->orWhere(
 | 
			
		||||
                        DB::raw(sprintf('CAST(%s AS %s)', $field, $cast)), // @phpstan-ignore-line
 | 
			
		||||
                        DB::raw(sprintf('CAST(%s AS %s)', $field, $cast)),
 | 
			
		||||
                        $operator,
 | 
			
		||||
                        DB::raw(sprintf($regularExpression, $currency->decimal_places))
 | 
			
		||||
                    );
 | 
			
		||||
@@ -315,7 +316,10 @@ class ForceDecimalSize extends Command
 | 
			
		||||
                $pow     = 10 ** $currency->decimal_places;
 | 
			
		||||
                $correct = bcdiv((string) round($value * $pow), (string) $pow, 12);
 | 
			
		||||
                $this->friendlyWarning(sprintf('%s #%d has %s with value "%s", this has been corrected to "%s".', $table, $item->id, $field, $value, $correct));
 | 
			
		||||
                $class::find($item->id)->update([$field => $correct]);
 | 
			
		||||
 | 
			
		||||
                /** @var null|Model $model */
 | 
			
		||||
                $model   = $class::find($item->id);
 | 
			
		||||
                $model?->update([$field => $correct]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -338,7 +342,7 @@ class ForceDecimalSize extends Command
 | 
			
		||||
            ->where(static function (Builder $q) use ($fields, $currency, $cast, $operator, $regularExpression): void {
 | 
			
		||||
                foreach ($fields as $field) {
 | 
			
		||||
                    $q->orWhere(
 | 
			
		||||
                        DB::raw(sprintf('CAST(piggy_bank_events.%s AS %s)', $field, $cast)), // @phpstan-ignore-line
 | 
			
		||||
                        DB::raw(sprintf('CAST(piggy_bank_events.%s AS %s)', $field, $cast)),
 | 
			
		||||
                        $operator,
 | 
			
		||||
                        DB::raw(sprintf($regularExpression, $currency->decimal_places))
 | 
			
		||||
                    );
 | 
			
		||||
@@ -367,7 +371,10 @@ class ForceDecimalSize extends Command
 | 
			
		||||
                $this->friendlyWarning(
 | 
			
		||||
                    sprintf('Piggy bank event #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct)
 | 
			
		||||
                );
 | 
			
		||||
                PiggyBankEvent::find($item->id)->update([$field => $correct]);
 | 
			
		||||
 | 
			
		||||
                /** @var null|PiggyBankEvent $event */
 | 
			
		||||
                $event   = PiggyBankEvent::find($item->id);
 | 
			
		||||
                $event?->update([$field => $correct]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -391,7 +398,7 @@ class ForceDecimalSize extends Command
 | 
			
		||||
            ->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void {
 | 
			
		||||
                foreach ($fields as $field) {
 | 
			
		||||
                    $q->orWhere(
 | 
			
		||||
                        DB::raw(sprintf('CAST(piggy_bank_repetitions.%s AS %s)', $field, $cast)), // @phpstan-ignore-line
 | 
			
		||||
                        DB::raw(sprintf('CAST(piggy_bank_repetitions.%s AS %s)', $field, $cast)),
 | 
			
		||||
                        $operator,
 | 
			
		||||
                        DB::raw(sprintf($regularExpression, $currency->decimal_places))
 | 
			
		||||
                    );
 | 
			
		||||
@@ -410,17 +417,20 @@ class ForceDecimalSize extends Command
 | 
			
		||||
        foreach ($result as $item) {
 | 
			
		||||
            /** @var string $field */
 | 
			
		||||
            foreach ($fields as $field) {
 | 
			
		||||
                $value   = $item->{$field};
 | 
			
		||||
                $value      = $item->{$field};
 | 
			
		||||
                if (null === $value) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                // fix $field by rounding it down correctly.
 | 
			
		||||
                $pow     = 10 ** $currency->decimal_places;
 | 
			
		||||
                $correct = bcdiv((string) round($value * $pow), (string) $pow, 12);
 | 
			
		||||
                $pow        = 10 ** $currency->decimal_places;
 | 
			
		||||
                $correct    = bcdiv((string) round($value * $pow), (string) $pow, 12);
 | 
			
		||||
                $this->friendlyWarning(
 | 
			
		||||
                    sprintf('Piggy bank repetition #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct)
 | 
			
		||||
                );
 | 
			
		||||
                PiggyBankRepetition::find($item->id)->update([$field => $correct]);
 | 
			
		||||
 | 
			
		||||
                /** @var null|PiggyBankRepetition $repetition */
 | 
			
		||||
                $repetition = PiggyBankRepetition::find($item->id);
 | 
			
		||||
                $repetition->update([$field => $correct]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -442,7 +452,7 @@ class ForceDecimalSize extends Command
 | 
			
		||||
            ->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void {
 | 
			
		||||
                foreach ($fields as $field) {
 | 
			
		||||
                    $q->orWhere(
 | 
			
		||||
                        DB::raw(sprintf('CAST(piggy_banks.%s AS %s)', $field, $cast)), // @phpstan-ignore-line
 | 
			
		||||
                        DB::raw(sprintf('CAST(piggy_banks.%s AS %s)', $field, $cast)),
 | 
			
		||||
                        $operator,
 | 
			
		||||
                        DB::raw(sprintf($regularExpression, $currency->decimal_places))
 | 
			
		||||
                    );
 | 
			
		||||
@@ -461,15 +471,18 @@ class ForceDecimalSize extends Command
 | 
			
		||||
        foreach ($result as $item) {
 | 
			
		||||
            /** @var string $field */
 | 
			
		||||
            foreach ($fields as $field) {
 | 
			
		||||
                $value   = $item->{$field};
 | 
			
		||||
                $value     = $item->{$field};
 | 
			
		||||
                if (null === $value) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                // fix $field by rounding it down correctly.
 | 
			
		||||
                $pow     = 10 ** $currency->decimal_places;
 | 
			
		||||
                $correct = bcdiv((string) round($value * $pow), (string) $pow, 12);
 | 
			
		||||
                $pow       = 10 ** $currency->decimal_places;
 | 
			
		||||
                $correct   = bcdiv((string) round($value * $pow), (string) $pow, 12);
 | 
			
		||||
                $this->friendlyWarning(sprintf('Piggy bank #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct));
 | 
			
		||||
                PiggyBank::find($item->id)->update([$field => $correct]);
 | 
			
		||||
 | 
			
		||||
                /** @var null|PiggyBank $piggyBank */
 | 
			
		||||
                $piggyBank = PiggyBank::find($item->id);
 | 
			
		||||
                $piggyBank?->update([$field => $correct]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -482,7 +495,7 @@ class ForceDecimalSize extends Command
 | 
			
		||||
        // select all transactions with this currency and issue.
 | 
			
		||||
        /** @var Builder $query */
 | 
			
		||||
        $query  = Transaction::where('transaction_currency_id', $currency->id)->where(
 | 
			
		||||
            DB::raw(sprintf('CAST(amount as %s)', $this->cast)), // @phpstan-ignore-line
 | 
			
		||||
            DB::raw(sprintf('CAST(amount as %s)', $this->cast)),
 | 
			
		||||
            $this->operator,
 | 
			
		||||
            DB::raw(sprintf($this->regularExpression, $currency->decimal_places))
 | 
			
		||||
        );
 | 
			
		||||
@@ -494,21 +507,24 @@ class ForceDecimalSize extends Command
 | 
			
		||||
 | 
			
		||||
        /** @var Transaction $item */
 | 
			
		||||
        foreach ($result as $item) {
 | 
			
		||||
            $value   = $item->amount;
 | 
			
		||||
            $value       = $item->amount;
 | 
			
		||||
            if ('' === $value) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            // fix $field by rounding it down correctly.
 | 
			
		||||
            $pow     = (float) 10 ** $currency->decimal_places;
 | 
			
		||||
            $correct = bcdiv((string) round((float) $value * $pow), (string) $pow, 12);
 | 
			
		||||
            $pow         = (float) 10 ** $currency->decimal_places;
 | 
			
		||||
            $correct     = bcdiv((string) round((float) $value * $pow), (string) $pow, 12);
 | 
			
		||||
            $this->friendlyWarning(sprintf('Transaction #%d has amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct));
 | 
			
		||||
            Transaction::find($item->id)->update(['amount' => $correct]);
 | 
			
		||||
 | 
			
		||||
            /** @var null|Transaction $transaction */
 | 
			
		||||
            $transaction = Transaction::find($item->id);
 | 
			
		||||
            $transaction?->update(['amount' => $correct]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // select all transactions with this FOREIGN currency and issue.
 | 
			
		||||
        /** @var Builder $query */
 | 
			
		||||
        $query  = Transaction::where('foreign_currency_id', $currency->id)->where(
 | 
			
		||||
            DB::raw(sprintf('CAST(foreign_amount as %s)', $this->cast)), // @phpstan-ignore-line
 | 
			
		||||
            DB::raw(sprintf('CAST(foreign_amount as %s)', $this->cast)),
 | 
			
		||||
            $this->operator,
 | 
			
		||||
            DB::raw(sprintf($this->regularExpression, $currency->decimal_places))
 | 
			
		||||
        );
 | 
			
		||||
@@ -522,17 +538,20 @@ class ForceDecimalSize extends Command
 | 
			
		||||
 | 
			
		||||
        /** @var Transaction $item */
 | 
			
		||||
        foreach ($result as $item) {
 | 
			
		||||
            $value   = $item->foreign_amount;
 | 
			
		||||
            $value       = $item->foreign_amount;
 | 
			
		||||
            if (null === $value) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            // fix $field by rounding it down correctly.
 | 
			
		||||
            $pow     = (float) 10 ** $currency->decimal_places;
 | 
			
		||||
            $correct = bcdiv((string) round((float) $value * $pow), (string) $pow, 12);
 | 
			
		||||
            $pow         = (float) 10 ** $currency->decimal_places;
 | 
			
		||||
            $correct     = bcdiv((string) round((float) $value * $pow), (string) $pow, 12);
 | 
			
		||||
            $this->friendlyWarning(
 | 
			
		||||
                sprintf('Transaction #%d has foreign amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct)
 | 
			
		||||
            );
 | 
			
		||||
            Transaction::find($item->id)->update(['foreign_amount' => $correct]);
 | 
			
		||||
 | 
			
		||||
            /** @var null|Transaction $transaction */
 | 
			
		||||
            $transaction = Transaction::find($item->id);
 | 
			
		||||
            $transaction?->update(['foreign_amount' => $correct]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -33,10 +33,7 @@ use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ForceMigration
 | 
			
		||||
 */
 | 
			
		||||
class ForceMigration extends Command
 | 
			
		||||
class ForcesMigrations extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
    use VerifiesAccessToken;
 | 
			
		||||
@@ -27,16 +27,13 @@ namespace FireflyIII\Console\Commands\System;
 | 
			
		||||
use FireflyIII\Support\System\GeneratesInstallationId;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class UpgradeFireflyInstructions.
 | 
			
		||||
 */
 | 
			
		||||
class UpgradeFireflyInstructions extends Command
 | 
			
		||||
class OutputsInstructions extends Command
 | 
			
		||||
{
 | 
			
		||||
    use GeneratesInstallationId;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Instructions in case of upgrade trouble.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly:instructions {task}';
 | 
			
		||||
    protected $signature   = 'firefly-iii:instructions {task=install}';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -79,7 +76,7 @@ class UpgradeFireflyInstructions extends Command
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $prefix  = 'v';
 | 
			
		||||
        if (str_starts_with($version, 'develop')) {
 | 
			
		||||
        if (str_starts_with($version, 'develop') || str_starts_with($version, 'branch')) {
 | 
			
		||||
            $prefix = '';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -94,6 +91,8 @@ class UpgradeFireflyInstructions extends Command
 | 
			
		||||
            $this->boxedInfo('There are no extra upgrade instructions.');
 | 
			
		||||
            $this->boxed('Firefly III should be ready for use.');
 | 
			
		||||
            $this->boxed('');
 | 
			
		||||
            $this->donationText();
 | 
			
		||||
            $this->boxed('');
 | 
			
		||||
            $this->showLine();
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
@@ -102,6 +101,8 @@ class UpgradeFireflyInstructions extends Command
 | 
			
		||||
        $this->boxed(sprintf('Thank you for updating to Firefly III, %s%s!', $prefix, $version));
 | 
			
		||||
        $this->boxedInfo($text);
 | 
			
		||||
        $this->boxed('');
 | 
			
		||||
        $this->donationText();
 | 
			
		||||
        $this->boxed('');
 | 
			
		||||
        $this->showLine();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -213,6 +214,8 @@ class UpgradeFireflyInstructions extends Command
 | 
			
		||||
            $this->boxedInfo('There are no extra installation instructions.');
 | 
			
		||||
            $this->boxed('Firefly III should be ready for use.');
 | 
			
		||||
            $this->boxed('');
 | 
			
		||||
            $this->donationText();
 | 
			
		||||
            $this->boxed('');
 | 
			
		||||
            $this->showLine();
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
@@ -221,6 +224,15 @@ class UpgradeFireflyInstructions extends Command
 | 
			
		||||
        $this->boxed(sprintf('Thank you for installing Firefly III, %s%s!', $prefix, $version));
 | 
			
		||||
        $this->boxedInfo($text);
 | 
			
		||||
        $this->boxed('');
 | 
			
		||||
        $this->donationText();
 | 
			
		||||
        $this->boxed('');
 | 
			
		||||
        $this->showLine();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function donationText(): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->boxed('Did you know you can support the development of Firefly III?');
 | 
			
		||||
        $this->boxed('You can donate in many ways, like GitHub Sponsors or Patreon.');
 | 
			
		||||
        $this->boxed('For more information, please visit https://bit.ly/donate-to-Firefly-III');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -26,10 +26,7 @@ namespace FireflyIII\Console\Commands\System;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class OutputVersion
 | 
			
		||||
 */
 | 
			
		||||
class OutputVersion extends Command
 | 
			
		||||
class OutputsVersion extends Command
 | 
			
		||||
{
 | 
			
		||||
    protected $description = 'Outputs the Firefly III version';
 | 
			
		||||
 | 
			
		||||
@@ -29,10 +29,7 @@ use FireflyIII\Models\Attachment;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Contracts\Encryption\DecryptException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ScanAttachments.
 | 
			
		||||
 */
 | 
			
		||||
class ScanAttachments extends Command
 | 
			
		||||
class ScansAttachments extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
@@ -27,10 +27,7 @@ namespace FireflyIII\Console\Commands\System;
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class SetLatestVersion
 | 
			
		||||
 */
 | 
			
		||||
class SetLatestVersion extends Command
 | 
			
		||||
class SetsLatestVersion extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
@@ -29,9 +29,6 @@ use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Database\QueryException;
 | 
			
		||||
use League\Flysystem\FilesystemException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class VerifySecurityAlerts
 | 
			
		||||
 */
 | 
			
		||||
class VerifySecurityAlerts extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 
 | 
			
		||||
@@ -27,8 +27,8 @@ namespace FireflyIII\Console\Commands\Tools;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Console\Commands\VerifiesAccessToken;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Models\Rule;
 | 
			
		||||
use FireflyIII\Models\RuleGroup;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
@@ -40,9 +40,6 @@ use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ApplyRules
 | 
			
		||||
 */
 | 
			
		||||
class ApplyRules extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
@@ -128,7 +125,7 @@ class ApplyRules extends Command
 | 
			
		||||
        $ruleEngine->addOperator(['type' => 'account_id', 'value' => $list]);
 | 
			
		||||
 | 
			
		||||
        // add the date as a filter:
 | 
			
		||||
        $ruleEngine->addOperator(['type' => 'date_after', 'value' => $this->start_date->format('Y-m-d')]);
 | 
			
		||||
        $ruleEngine->addOperator(['type' => 'date_after', 'value' => $this->startDate->format('Y-m-d')]);
 | 
			
		||||
        $ruleEngine->addOperator(['type' => 'date_before', 'value' => $this->endDate->format('Y-m-d')]);
 | 
			
		||||
 | 
			
		||||
        // start running rules.
 | 
			
		||||
@@ -157,7 +154,7 @@ class ApplyRules extends Command
 | 
			
		||||
        $this->ruleGroupSelection  = [];
 | 
			
		||||
        $this->ruleRepository      = app(RuleRepositoryInterface::class);
 | 
			
		||||
        $this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class);
 | 
			
		||||
        $this->acceptedAccounts    = [AccountType::DEFAULT, AccountType::DEBT, AccountType::ASSET, AccountType::LOAN, AccountType::MORTGAGE];
 | 
			
		||||
        $this->acceptedAccounts    = [AccountTypeEnum::DEFAULT->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value];
 | 
			
		||||
        $this->groups              = new Collection();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -229,7 +226,7 @@ class ApplyRules extends Command
 | 
			
		||||
 | 
			
		||||
        foreach ($ruleGroupList as $ruleGroupId) {
 | 
			
		||||
            $ruleGroup = $this->ruleGroupRepository->find((int) $ruleGroupId);
 | 
			
		||||
            if ($ruleGroup->active) {
 | 
			
		||||
            if (true === $ruleGroup->active) {
 | 
			
		||||
                $this->ruleGroupSelection[] = $ruleGroup->id;
 | 
			
		||||
            }
 | 
			
		||||
            if (false === $ruleGroup->active) {
 | 
			
		||||
@@ -251,7 +248,7 @@ class ApplyRules extends Command
 | 
			
		||||
 | 
			
		||||
        foreach ($ruleList as $ruleId) {
 | 
			
		||||
            $rule = $this->ruleRepository->find((int) $ruleId);
 | 
			
		||||
            if (null !== $rule && $rule->active) {
 | 
			
		||||
            if (null !== $rule && true === $rule->active) {
 | 
			
		||||
                $this->ruleSelection[] = $rule->id;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -265,8 +262,8 @@ class ApplyRules extends Command
 | 
			
		||||
    private function verifyInputDates(): void
 | 
			
		||||
    {
 | 
			
		||||
        // parse start date.
 | 
			
		||||
        $inputStart       = today(config('app.timezone'))->startOfMonth();
 | 
			
		||||
        $startString      = $this->option('start_date');
 | 
			
		||||
        $inputStart      = today(config('app.timezone'))->startOfMonth();
 | 
			
		||||
        $startString     = $this->option('start_date');
 | 
			
		||||
        if (null === $startString) {
 | 
			
		||||
            /** @var JournalRepositoryInterface $repository */
 | 
			
		||||
            $repository = app(JournalRepositoryInterface::class);
 | 
			
		||||
@@ -281,8 +278,8 @@ class ApplyRules extends Command
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // parse end date
 | 
			
		||||
        $inputEnd         = today(config('app.timezone'));
 | 
			
		||||
        $endString        = $this->option('end_date');
 | 
			
		||||
        $inputEnd        = today(config('app.timezone'));
 | 
			
		||||
        $endString       = $this->option('end_date');
 | 
			
		||||
        if (null !== $endString && '' !== $endString) {
 | 
			
		||||
            $inputEnd = Carbon::createFromFormat('Y-m-d', $endString);
 | 
			
		||||
        }
 | 
			
		||||
@@ -296,8 +293,8 @@ class ApplyRules extends Command
 | 
			
		||||
            [$inputEnd, $inputStart] = [$inputStart, $inputEnd];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->start_date = $inputStart;
 | 
			
		||||
        $this->endDate    = $inputEnd;
 | 
			
		||||
        $this->startDate = $inputStart;
 | 
			
		||||
        $this->endDate   = $inputEnd;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function grabAllRules(): void
 | 
			
		||||
 
 | 
			
		||||
@@ -34,9 +34,6 @@ use FireflyIII\Support\Cronjobs\RecurringCronjob;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Support\Facades\Log;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class Cron
 | 
			
		||||
 */
 | 
			
		||||
class Cron extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 
 | 
			
		||||
@@ -32,16 +32,13 @@ use FireflyIII\Repositories\Journal\JournalCLIRepositoryInterface;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Database\QueryException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class TransactionIdentifier
 | 
			
		||||
 */
 | 
			
		||||
class TransactionIdentifier extends Command
 | 
			
		||||
class AddsTransactionIdentifiers extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    public const string CONFIG_NAME = '480_transaction_identifier';
 | 
			
		||||
    protected $description          = 'Fixes transaction identifiers.';
 | 
			
		||||
    protected $signature            = 'firefly-iii:transaction-identifiers {--F|force : Force the execution of this command.}';
 | 
			
		||||
    protected $signature            = 'upgrade:480-transaction-identifiers {--F|force : Force the execution of this command.}';
 | 
			
		||||
    private JournalCLIRepositoryInterface $cliRepository;
 | 
			
		||||
    private int                           $count;
 | 
			
		||||
 | 
			
		||||
@@ -79,9 +76,6 @@ class TransactionIdentifier extends Command
 | 
			
		||||
            $this->updateJournalIdentifiers($journal);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (0 === $this->count) {
 | 
			
		||||
            $this->friendlyPositive('All split journal transaction identifiers are OK.');
 | 
			
		||||
        }
 | 
			
		||||
        if (0 !== $this->count) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('Fixed %d split journal transaction identifier(s).', $this->count));
 | 
			
		||||
        }
 | 
			
		||||
@@ -30,15 +30,12 @@ use FireflyIII\Models\Preference;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
use Illuminate\Contracts\Encryption\DecryptException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class DecryptDatabase
 | 
			
		||||
 */
 | 
			
		||||
class DecryptDatabase extends Command
 | 
			
		||||
class RemovesDatabaseDecryption extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Decrypts the database.';
 | 
			
		||||
    protected $signature   = 'firefly-iii:decrypt-all';
 | 
			
		||||
    protected $signature   = 'upgrade:480-decrypt-all';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -73,7 +70,6 @@ class DecryptDatabase extends Command
 | 
			
		||||
    private function decryptTable(string $table, array $fields): void
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->isDecrypted($table)) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('No decryption required for table "%s".', $table));
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -28,16 +28,13 @@ use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Support\Models\AccountBalanceCalculator;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CorrectionSkeleton
 | 
			
		||||
 */
 | 
			
		||||
class CorrectAccountBalance extends Command
 | 
			
		||||
class RepairsAccountBalances extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    public const string CONFIG_NAME = '610_correct_balances';
 | 
			
		||||
    protected $description          = 'Recalculate all account balance amounts';
 | 
			
		||||
    protected $signature            = 'firefly-iii:correct-account-balance {--F|force : Force the execution of this command.}';
 | 
			
		||||
    protected $signature            = 'upgrade:610-account-balances {--F|force : Force the execution of this command.}';
 | 
			
		||||
 | 
			
		||||
    public function handle(): int
 | 
			
		||||
    {
 | 
			
		||||
@@ -46,7 +43,7 @@ class CorrectAccountBalance extends Command
 | 
			
		||||
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (config('firefly.feature_flags.running_balance_column')) {
 | 
			
		||||
        if (true === config('firefly.feature_flags.running_balance_column')) {
 | 
			
		||||
            $this->friendlyInfo('Will recalculate account balances. This may take a LONG time. Please be patient.');
 | 
			
		||||
            $this->markAsExecuted();
 | 
			
		||||
            $this->correctBalanceAmounts();
 | 
			
		||||
@@ -73,7 +70,6 @@ class CorrectAccountBalance extends Command
 | 
			
		||||
 | 
			
		||||
    private function correctBalanceAmounts(): void
 | 
			
		||||
    {
 | 
			
		||||
        return;
 | 
			
		||||
        AccountBalanceCalculator::recalculateAll(true);
 | 
			
		||||
        AccountBalanceCalculator::recalculateAll(false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -27,16 +27,13 @@ namespace FireflyIII\Console\Commands\Upgrade;
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class FixPostgresSequences
 | 
			
		||||
 */
 | 
			
		||||
class FixPostgresSequences extends Command
 | 
			
		||||
class RepairsPostgresSequences extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    protected $description = 'Fixes issues with PostgreSQL sequences.';
 | 
			
		||||
 | 
			
		||||
    protected $signature   = 'firefly-iii:fix-pgsql-sequences';
 | 
			
		||||
    protected $signature   = 'upgrade:600-pgsql-sequences';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -4,9 +4,6 @@ namespace FireflyIII\Console\Commands\Upgrade;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class UpgradeSkeleton.
 | 
			
		||||
 */
 | 
			
		||||
class UpgradeSkeleton extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
@@ -14,7 +11,7 @@ class UpgradeSkeleton extends Command
 | 
			
		||||
 | 
			
		||||
    protected $description = 'SOME DESCRIPTION';
 | 
			
		||||
 | 
			
		||||
    protected $signature = 'firefly-iii:UPGRSKELETON {--F|force : Force the execution of this command.}';
 | 
			
		||||
    protected $signature = 'upgrade:UPGRSKELETON {--F|force : Force the execution of this command.}';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
 
 | 
			
		||||
@@ -25,10 +25,10 @@ declare(strict_types=1);
 | 
			
		||||
namespace FireflyIII\Console\Commands\Upgrade;
 | 
			
		||||
 | 
			
		||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
 | 
			
		||||
use FireflyIII\Enums\AccountTypeEnum;
 | 
			
		||||
use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Models\Account;
 | 
			
		||||
use FireflyIII\Models\AccountMeta;
 | 
			
		||||
use FireflyIII\Models\AccountType;
 | 
			
		||||
use FireflyIII\Models\Transaction;
 | 
			
		||||
use FireflyIII\Models\TransactionCurrency;
 | 
			
		||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
			
		||||
@@ -36,17 +36,14 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class AccountCurrencies
 | 
			
		||||
 */
 | 
			
		||||
class AccountCurrencies extends Command
 | 
			
		||||
class UpgradesAccountCurrencies extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
    public const string CONFIG_NAME = '480_account_currencies';
 | 
			
		||||
 | 
			
		||||
    protected $description          = 'Give all accounts proper currency info.';
 | 
			
		||||
    protected $signature            = 'firefly-iii:account-currencies {--F|force : Force the execution of this command.}';
 | 
			
		||||
    protected $signature            = 'upgrade:480-account-currencies {--F|force : Force the execution of this command.}';
 | 
			
		||||
    private AccountRepositoryInterface $accountRepos;
 | 
			
		||||
    private int                        $count;
 | 
			
		||||
    private UserRepositoryInterface    $userRepos;
 | 
			
		||||
@@ -65,9 +62,6 @@ class AccountCurrencies extends Command
 | 
			
		||||
        }
 | 
			
		||||
        $this->updateAccountCurrencies();
 | 
			
		||||
 | 
			
		||||
        if (0 === $this->count) {
 | 
			
		||||
            $this->friendlyPositive('All account currencies are OK.');
 | 
			
		||||
        }
 | 
			
		||||
        if (0 !== $this->count) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('Corrected %d account(s).', $this->count));
 | 
			
		||||
        }
 | 
			
		||||
@@ -110,7 +104,7 @@ class AccountCurrencies extends Command
 | 
			
		||||
    private function updateCurrenciesForUser(User $user): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->accountRepos->setUser($user);
 | 
			
		||||
        $accounts        = $this->accountRepos->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
 | 
			
		||||
        $accounts        = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value]);
 | 
			
		||||
 | 
			
		||||
        // get user's currency preference:
 | 
			
		||||
        $defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
 | 
			
		||||
@@ -29,10 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
 | 
			
		||||
use FireflyIII\Models\AccountMeta;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class RenameAccountMeta
 | 
			
		||||
 */
 | 
			
		||||
class RenameAccountMeta extends Command
 | 
			
		||||
class UpgradesAccountMetaData extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
@@ -40,7 +37,7 @@ class RenameAccountMeta extends Command
 | 
			
		||||
 | 
			
		||||
    protected $description          = 'Rename account meta-data to new format.';
 | 
			
		||||
 | 
			
		||||
    protected $signature            = 'firefly-iii:rename-account-meta {--F|force : Force the execution of this command.}';
 | 
			
		||||
    protected $signature            = 'upgrade:480-account-meta {--F|force : Force the execution of this command.}';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -76,9 +73,6 @@ class RenameAccountMeta extends Command
 | 
			
		||||
 | 
			
		||||
        $this->markAsExecuted();
 | 
			
		||||
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All account meta is OK.');
 | 
			
		||||
        }
 | 
			
		||||
        if (0 !== $count) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('Renamed %d account meta entries (entry).', $count));
 | 
			
		||||
        }
 | 
			
		||||
@@ -30,10 +30,7 @@ use FireflyIII\Models\Attachment;
 | 
			
		||||
use FireflyIII\Models\Note;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class MigrateAttachments
 | 
			
		||||
 */
 | 
			
		||||
class MigrateAttachments extends Command
 | 
			
		||||
class UpgradesAttachments extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
@@ -41,7 +38,7 @@ class MigrateAttachments extends Command
 | 
			
		||||
 | 
			
		||||
    protected $description          = 'Migrates attachment meta-data.';
 | 
			
		||||
 | 
			
		||||
    protected $signature            = 'firefly-iii:migrate-attachments {--F|force : Force the execution of this command.}';
 | 
			
		||||
    protected $signature            = 'upgrade:480-attachments {--F|force : Force the execution of this command.}';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
@@ -82,9 +79,6 @@ class MigrateAttachments extends Command
 | 
			
		||||
                ++$count;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (0 === $count) {
 | 
			
		||||
            $this->friendlyPositive('All attachments are OK.');
 | 
			
		||||
        }
 | 
			
		||||
        if (0 !== $count) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('Updated %d attachment(s).', $count));
 | 
			
		||||
        }
 | 
			
		||||
@@ -36,10 +36,7 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
 | 
			
		||||
use FireflyIII\User;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class MigrateToRules
 | 
			
		||||
 */
 | 
			
		||||
class MigrateToRules extends Command
 | 
			
		||||
class UpgradesBillsToRules extends Command
 | 
			
		||||
{
 | 
			
		||||
    use ShowsFriendlyMessages;
 | 
			
		||||
 | 
			
		||||
@@ -47,7 +44,7 @@ class MigrateToRules extends Command
 | 
			
		||||
 | 
			
		||||
    protected $description          = 'Migrate bills to rules.';
 | 
			
		||||
 | 
			
		||||
    protected $signature            = 'firefly-iii:bills-to-rules {--F|force : Force the execution of this command.}';
 | 
			
		||||
    protected $signature            = 'upgrade:480-bills-to-rules {--F|force : Force the execution of this command.}';
 | 
			
		||||
    private BillRepositoryInterface      $billRepository;
 | 
			
		||||
    private int                          $count;
 | 
			
		||||
    private RuleGroupRepositoryInterface $ruleGroupRepository;
 | 
			
		||||
@@ -76,9 +73,6 @@ class MigrateToRules extends Command
 | 
			
		||||
            $this->migrateUser($user);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (0 === $this->count) {
 | 
			
		||||
            $this->friendlyPositive('All bills are OK.');
 | 
			
		||||
        }
 | 
			
		||||
        if (0 !== $this->count) {
 | 
			
		||||
            $this->friendlyInfo(sprintf('Verified and fixed %d bill(s).', $this->count));
 | 
			
		||||
        }
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user