Compare commits

...

125 Commits

Author SHA1 Message Date
github-actions[bot]
c525c70ec0 Merge pull request #10657 from firefly-iii/release-1753673814
🤖 Automatically merge the PR into the develop branch.
2025-07-28 05:37:03 +02:00
JC5
1f7d6e218b 🤖 Auto commit for release 'develop' on 2025-07-28 2025-07-28 05:36:54 +02:00
James Cole
a69b6d9ce2 Respond to "convert to native". 2025-07-27 20:45:08 +02:00
James Cole
28b2ddde18 Account chart can do live update 2025-07-27 07:36:23 +02:00
James Cole
a16cc73c77 Sync "convert to native" 2025-07-26 19:17:26 +02:00
James Cole
46395e350a Improved budget chart. 2025-07-26 06:47:21 +02:00
Sander Dorigo
f62e49090c Merge branch 'main' into develop 2025-07-25 11:18:24 +02:00
James Cole
af3b40a314 Delete .github/workflows/sonarcloud.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2025-07-25 11:10:05 +02:00
James Cole
c3cea0fa9e Update cleanup.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2025-07-25 11:09:55 +02:00
James Cole
6cbdb2ce70 Update index.js
Fix thnigie

Signed-off-by: James Cole <james@firefly-iii.org>
2025-07-25 10:56:42 +02:00
James Cole
b78460100d Fix #10646 2025-07-25 05:44:03 +02:00
github-actions[bot]
bf6e1cb0e1 Merge pull request #10642 from firefly-iii/release-1753333227
🤖 Automatically merge the PR into the develop branch.
2025-07-24 07:00:35 +02:00
JC5
6a53f5031c 🤖 Auto commit for release 'develop' on 2025-07-24 2025-07-24 07:00:27 +02:00
James Cole
ae15ec01e8 Merge branch 'main' into develop 2025-07-24 06:56:07 +02:00
James Cole
fe3c7c47c4 Filter list of bills. 2025-07-24 06:55:53 +02:00
James Cole
68b934010c Merge pull request #10640 from firefly-iii/dependabot/npm_and_yarn/npm_and_yarn-25988072ba
Bump the npm_and_yarn group across 1 directory with 2 updates
2025-07-23 19:37:09 +02:00
dependabot[bot]
22852bd238 Bump the npm_and_yarn group across 1 directory with 2 updates
Bumps the npm_and_yarn group with 1 update in the / directory: [axios](https://github.com/axios/axios).


Updates `axios` from 1.10.0 to 1.11.0
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.10.0...v1.11.0)

Updates `form-data` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/form-data/form-data/releases)
- [Changelog](https://github.com/form-data/form-data/blob/master/CHANGELOG.md)
- [Commits](https://github.com/form-data/form-data/compare/v4.0.3...v4.0.4)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.11.0
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: form-data
  dependency-version: 4.0.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-23 16:51:30 +00:00
github-actions[bot]
5b3b1804f3 Merge pull request #10638 from firefly-iii/release-1753247140
🤖 Automatically merge the PR into the develop branch.
2025-07-23 07:05:49 +02:00
JC5
f2588eb343 🤖 Auto commit for release 'develop' on 2025-07-23 2025-07-23 07:05:40 +02:00
James Cole
64a643ceec Expand balances. 2025-07-23 07:01:10 +02:00
github-actions[bot]
1add505644 Merge pull request #10634 from firefly-iii/release-1753068994
🤖 Automatically merge the PR into the develop branch.
2025-07-21 05:36:42 +02:00
JC5
9663eb6a19 🤖 Auto commit for release 'develop' on 2025-07-21 2025-07-21 05:36:34 +02:00
github-actions[bot]
f30a24a02f Merge pull request #10629 from firefly-iii/release-1753029916
🤖 Automatically merge the PR into the develop branch.
2025-07-20 18:45:22 +02:00
JC5
68655d60a6 🤖 Auto commit for release 'develop' on 2025-07-20 2025-07-20 18:45:16 +02:00
James Cole
63b0efcd81 Remove sonarcloud flow. 2025-07-20 18:41:05 +02:00
James Cole
93284682c8 Improve bill overview. 2025-07-20 14:02:53 +02:00
github-actions[bot]
3bafcb6ad2 Merge pull request #10625 from firefly-iii/release-1753007822
🤖 Automatically merge the PR into the develop branch.
2025-07-20 12:37:09 +02:00
JC5
942d027556 🤖 Auto commit for release 'develop' on 2025-07-20 2025-07-20 12:37:02 +02:00
James Cole
a60882d5f5 Clean up v2. 2025-07-20 12:32:53 +02:00
James Cole
680f554981 Fix #10618 2025-07-19 21:08:37 +02:00
James Cole
20e4dc07ce Bad quote in html 2025-07-18 19:53:22 +02:00
James Cole
184d8eb027 Use new settings for php cs fixer. 2025-07-17 06:54:20 +02:00
github-actions[bot]
59725b088a Merge pull request #10608 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-07-17 06:46:17 +02:00
github-actions[bot]
32fca4a9f5 Merge pull request #10607 from firefly-iii/release-1752727561
🤖 Automatically merge the PR into the develop branch.
2025-07-17 06:46:12 +02:00
JC5
7dccf6ec48 🤖 Auto commit for release 'v6.2.21' on 2025-07-17 2025-07-17 06:46:01 +02:00
github-actions[bot]
917665feac Merge pull request #10606 from firefly-iii/release-1752727317
🤖 Automatically merge the PR into the develop branch.
2025-07-17 06:42:04 +02:00
JC5
06c50b68c2 🤖 Auto commit for release 'develop' on 2025-07-17 2025-07-17 06:41:57 +02:00
James Cole
7035c399d8 Update changelog. 2025-07-17 06:36:37 +02:00
James Cole
7c0ac5805c Fix #10601 2025-07-16 17:09:37 +02:00
James Cole
3424741583 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-07-14 07:00:16 +02:00
James Cole
baf0297994 Update vite 2025-07-14 07:00:10 +02:00
github-actions[bot]
31d06752fa Merge pull request #10591 from firefly-iii/release-1752464168
🤖 Automatically merge the PR into the develop branch.
2025-07-14 05:36:14 +02:00
JC5
8a27154798 🤖 Auto commit for release 'develop' on 2025-07-14 2025-07-14 05:36:08 +02:00
github-actions[bot]
6d87e38ec0 Merge pull request #10583 from firefly-iii/release-1752300569
🤖 Automatically merge the PR into the develop branch.
2025-07-12 08:09:37 +02:00
JC5
ccdc30a6fb 🤖 Auto commit for release 'develop' on 2025-07-12 2025-07-12 08:09:29 +02:00
James Cole
90005538d3 Fix one tiny date thing. 2025-07-12 08:05:30 +02:00
James Cole
f4e0428ebc Limit date ranges to fix #10581 2025-07-12 06:18:25 +02:00
github-actions[bot]
bd1326eca9 Merge pull request #10577 from firefly-iii/release-1752124263
🤖 Automatically merge the PR into the develop branch.
2025-07-10 07:11:12 +02:00
JC5
bdfa834251 🤖 Auto commit for release 'develop' on 2025-07-10 2025-07-10 07:11:04 +02:00
James Cole
4a9aeb4e44 Rename tagMode to tag_mode. 2025-07-10 07:04:20 +02:00
github-actions[bot]
3886c0fbde Merge pull request #10563 from firefly-iii/release-1751859243
🤖 Automatically merge the PR into the develop branch.
2025-07-07 05:34:17 +02:00
JC5
d998eff56e 🤖 Auto commit for release 'develop' on 2025-07-07 2025-07-07 05:34:03 +02:00
github-actions[bot]
d73df9bf0a Merge pull request #10559 from firefly-iii/release-1751823330
🤖 Automatically merge the PR into the develop branch.
2025-07-06 19:35:38 +02:00
JC5
754f2f3a34 🤖 Auto commit for release 'develop' on 2025-07-06 2025-07-06 19:35:30 +02:00
James Cole
43fd7c928a Add build_time 2025-07-06 19:32:01 +02:00
github-actions[bot]
05768c2e73 Merge pull request #10548 from firefly-iii/release-1751477916
🤖 Automatically merge the PR into the develop branch.
2025-07-02 19:38:43 +02:00
JC5
3feb2c9955 🤖 Auto commit for release 'develop' on 2025-07-02 2025-07-02 19:38:36 +02:00
James Cole
7d9f3ac473 Fix logs. 2025-07-02 19:35:01 +02:00
James Cole
8a5755c8f1 Add debug information. 2025-07-02 19:34:05 +02:00
github-actions[bot]
a75a760019 Merge pull request #10547 from firefly-iii/release-1751476883
🤖 Automatically merge the PR into the develop branch.
2025-07-02 19:21:31 +02:00
JC5
78d1a130d2 🤖 Auto commit for release 'develop' on 2025-07-02 2025-07-02 19:21:23 +02:00
github-actions[bot]
79fd43f32b Merge pull request #10538 from firefly-iii/release-1751429580
🤖 Automatically merge the PR into the develop branch.
2025-07-02 06:13:10 +02:00
JC5
7a7bd65a27 🤖 Auto commit for release 'develop' on 2025-07-02 2025-07-02 06:13:00 +02:00
github-actions[bot]
01a9ecccac Merge pull request #10537 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-07-02 06:03:28 +02:00
github-actions[bot]
c1b3c71090 Merge pull request #10536 from firefly-iii/release-1751428997
🤖 Automatically merge the PR into the develop branch.
2025-07-02 06:03:24 +02:00
JC5
323d04fe6c 🤖 Auto commit for release 'v6.2.20' on 2025-07-02 2025-07-02 06:03:17 +02:00
James Cole
80c2f1ea3f Update changelog. 2025-07-02 05:59:25 +02:00
James Cole
784494871d Fix #10530 2025-07-01 19:33:43 +02:00
James Cole
8e93af5cc7 Fix #10535 2025-07-01 19:31:27 +02:00
James Cole
ebfdeeedaa Fix #10517 2025-06-30 20:28:29 +02:00
github-actions[bot]
1d02ed6a56 Merge pull request #10525 from firefly-iii/release-1751254389
🤖 Automatically merge the PR into the develop branch.
2025-06-30 05:33:15 +02:00
JC5
cca53cb0e8 🤖 Auto commit for release 'develop' on 2025-06-30 2025-06-30 05:33:09 +02:00
github-actions[bot]
ab33aee4b1 Merge pull request #10521 from firefly-iii/release-1751208250
🤖 Automatically merge the PR into the develop branch.
2025-06-29 16:44:18 +02:00
JC5
41d4fab071 🤖 Auto commit for release 'develop' on 2025-06-29 2025-06-29 16:44:10 +02:00
James Cole
f0a1913dc6 Enable new query parser by default. 2025-06-29 06:46:40 +02:00
github-actions[bot]
b956b463c2 Merge pull request #10515 from firefly-iii/release-1751095523
🤖 Automatically merge the PR into the develop branch.
2025-06-28 09:25:30 +02:00
JC5
43603c4990 🤖 Auto commit for release 'develop' on 2025-06-28 2025-06-28 09:25:23 +02:00
github-actions[bot]
196e738f60 Merge pull request #10514 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-06-28 08:53:36 +02:00
github-actions[bot]
59e2ea357a Merge pull request #10513 from firefly-iii/release-1751093606
🤖 Automatically merge the PR into the develop branch.
2025-06-28 08:53:32 +02:00
JC5
5e9d942069 🤖 Auto commit for release 'v6.2.19' on 2025-06-28 2025-06-28 08:53:26 +02:00
James Cole
53d5bedd85 Update changelog and config. 2025-06-28 08:48:53 +02:00
James Cole
49c68af07b Fix #10510 2025-06-27 20:59:47 +02:00
James Cole
c84c8e1aef Fix #10507 2025-06-27 11:10:41 +02:00
James Cole
a8d43d7174 Add donation text. 2025-06-26 17:32:06 +02:00
James Cole
1087278890 Make sure phpcs and rector agree on styles. 2025-06-26 11:57:15 +02:00
James Cole
ae5912ab52 Remove some logs. 2025-06-26 11:45:31 +02:00
github-actions[bot]
035bd96ae5 Merge pull request #10501 from firefly-iii/release-1750913017
🤖 Automatically merge the PR into the develop branch.
2025-06-26 06:43:46 +02:00
JC5
7283c616a0 🤖 Auto commit for release 'develop' on 2025-06-26 2025-06-26 06:43:37 +02:00
James Cole
5706666bb6 Fewer loops. 2025-06-26 06:40:00 +02:00
James Cole
4607466fb6 Remove some debug logging. 2025-06-26 06:36:15 +02:00
James Cole
34bcfcfe9b Fix #10499 2025-06-25 21:35:52 +02:00
github-actions[bot]
05986cb6a6 Merge pull request #10495 from firefly-iii/release-1750873643
🤖 Automatically merge the PR into the develop branch.
2025-06-25 19:47:30 +02:00
JC5
0c4ee9f043 🤖 Auto commit for release 'develop' on 2025-06-25 2025-06-25 19:47:23 +02:00
James Cole
ff222795cf Add date to compare hash. 2025-06-25 19:43:03 +02:00
James Cole
e0c76695ee Fix tests 2025-06-24 13:25:03 +02:00
James Cole
ae126e8322 Fix #10493 2025-06-24 13:14:31 +02:00
James Cole
8f9c35fbe8 Experimental fix for #10489 2025-06-23 20:45:00 +02:00
github-actions[bot]
84efd6e2ee Merge pull request #10487 from firefly-iii/release-1750649637
🤖 Automatically merge the PR into the develop branch.
2025-06-23 05:34:05 +02:00
JC5
b1fbe4e909 🤖 Auto commit for release 'develop' on 2025-06-23 2025-06-23 05:33:57 +02:00
James Cole
8576877072 Reverse currency change. 2025-06-20 07:45:41 +02:00
github-actions[bot]
c298aced01 Merge pull request #10479 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-06-20 06:45:28 +02:00
github-actions[bot]
ac61a78d8d Merge pull request #10478 from firefly-iii/release-1750394715
🤖 Automatically merge the PR into the develop branch.
2025-06-20 06:45:22 +02:00
JC5
fce90a94c4 🤖 Auto commit for release 'v6.2.18' on 2025-06-20 2025-06-20 06:45:15 +02:00
github-actions[bot]
023a4f178d Merge pull request #10477 from firefly-iii/release-1750393987
🤖 Automatically merge the PR into the develop branch.
2025-06-20 06:33:14 +02:00
JC5
ef254995ad 🤖 Auto commit for release 'develop' on 2025-06-20 2025-06-20 06:33:07 +02:00
James Cole
faeb74634b Merge branch 'main' into develop 2025-06-20 06:28:53 +02:00
James Cole
b5baae373f Move changelog. 2025-06-20 06:28:42 +02:00
James Cole
63de711cda Update changelog. 2025-06-20 06:24:19 +02:00
James Cole
bd28d116cb Fix currency seeder, add some debug logs. 2025-06-20 05:59:44 +02:00
github-actions[bot]
7efc2861bc Merge pull request #10468 from firefly-iii/release-1750044727
🤖 Automatically merge the PR into the develop branch.
2025-06-16 05:32:16 +02:00
JC5
5c689a2ca2 🤖 Auto commit for release 'develop' on 2025-06-16 2025-06-16 05:32:08 +02:00
github-actions[bot]
d5d65df76f Merge pull request #10459 from firefly-iii/release-1749897382
🤖 Automatically merge the PR into the develop branch.
2025-06-14 12:36:32 +02:00
JC5
df7d4f700c 🤖 Auto commit for release 'develop' on 2025-06-14 2025-06-14 12:36:22 +02:00
James Cole
efebe3cb41 Remove debug letters. 2025-06-14 12:31:54 +02:00
James Cole
2ba5b6ae49 Fix #10454 2025-06-14 10:18:58 +02:00
github-actions[bot]
31d93efab2 Merge pull request #10451 from firefly-iii/release-1749735701
🤖 Automatically merge the PR into the develop branch.
2025-06-12 15:41:49 +02:00
JC5
657b95485c 🤖 Auto commit for release 'develop' on 2025-06-12 2025-06-12 15:41:41 +02:00
Sander Dorigo
3bfc12f93b Try to be more clear about OAuth errors 2025-06-12 15:36:38 +02:00
James Cole
ccfd2f2ac3 Update fr.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2025-06-12 13:12:50 +02:00
James Cole
fb3fe0d87b Update bug.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2025-06-12 13:11:55 +02:00
James Cole
c80c6d52fe Update config.yml
Signed-off-by: James Cole <james@firefly-iii.org>
2025-06-12 13:02:14 +02:00
Sander Dorigo
0fb3c0c7bf Add missing variable name 2025-06-11 15:51:39 +02:00
github-actions[bot]
43c625bee2 Merge pull request #10444 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-06-11 14:07:28 +02:00
github-actions[bot]
967a5dd256 Merge pull request #10443 from firefly-iii/release-1749643634
🤖 Automatically merge the PR into the develop branch.
2025-06-11 14:07:22 +02:00
JC5
3c9d1bcaa1 🤖 Auto commit for release 'v6.2.17' on 2025-06-11 2025-06-11 14:07:14 +02:00
160 changed files with 2332 additions and 1664 deletions

View File

@@ -19,26 +19,25 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
$current = __DIR__; $current = __DIR__;
$paths = [ $paths = [
$current . '/../../app', $current . '/../../app',
$current . '/../../config', $current . '/../../config',
$current . '/../../database',
$current . '/../../routes', $current . '/../../routes',
$current . '/../../tests', $current . '/../../tests',
$current . '/../../resources/lang/en_US',
]; ];
$finder = PhpCsFixer\Finder::create() $finder = PhpCsFixer\Finder::create()
->in($paths); ->in($paths);
$config = new PhpCsFixer\Config(); $config = (new PhpCsFixer\Config())
$config->setParallelConfig(ParallelConfigFactory::detect()); // ->setUnsupportedPhpVersionAllowed(true) // use this when PHP 8.5 comes out.
->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
;
return $config->setRules( return $config->setRules(
[ [
// rule sets // rule sets
'@PHP83Migration' => true, '@PHP83Migration' => true,
@@ -53,9 +52,6 @@ return $config->setRules(
'statement_indentation' => true, 'statement_indentation' => true,
'void_return' => true, 'void_return' => true,
// about importing statements
'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true],
// disabled rules // disabled rules
'native_function_invocation' => false, // annoying 'native_function_invocation' => false, // annoying
'php_unit_data_provider_name' => false, // bloody annoying long test names 'php_unit_data_provider_name' => false, // bloody annoying long test names
@@ -64,9 +60,15 @@ return $config->setRules(
'comment_to_phpdoc' => false, // breaks phpstan lines in combination with PHPStorm. 'comment_to_phpdoc' => false, // breaks phpstan lines in combination with PHPStorm.
'type_declaration_spaces' => false, 'type_declaration_spaces' => false,
'cast_spaces' => false, 'cast_spaces' => false,
'phpdoc_to_comment' => false, // do not overrule single line comment style, breaks phpstan.
// enabled rules
'global_namespace_import' => true, // matches with rector.
// complex rules // complex rules
'phpdoc_to_comment' => ['ignored_tags' => ['var']],
'php_unit_test_case_static_method_calls' => [
'call_type' => 'this',
],
'array_syntax' => ['syntax' => 'short'], 'array_syntax' => ['syntax' => 'short'],
'binary_operator_spaces' => [ 'binary_operator_spaces' => [
'default' => 'at_least_single_space', 'default' => 'at_least_single_space',
@@ -76,5 +78,7 @@ return $config->setRules(
'??=' => 'align_single_space_minimal_by_scope', '??=' => 'align_single_space_minimal_by_scope',
], ],
], ],
]) ]
)
->setFinder($finder); ->setFinder($finder);

View File

@@ -406,58 +406,59 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.75.0", "version": "v3.84.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "399a128ff2fdaf4281e4e79b755693286cdf325c" "reference": "38dad0767bf2a9b516b976852200ae722fe984ca"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/399a128ff2fdaf4281e4e79b755693286cdf325c", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/38dad0767bf2a9b516b976852200ae722fe984ca",
"reference": "399a128ff2fdaf4281e4e79b755693286cdf325c", "reference": "38dad0767bf2a9b516b976852200ae722fe984ca",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"clue/ndjson-react": "^1.0", "clue/ndjson-react": "^1.0",
"composer/semver": "^3.4", "composer/semver": "^3.4",
"composer/xdebug-handler": "^3.0.3", "composer/xdebug-handler": "^3.0.5",
"ext-filter": "*", "ext-filter": "*",
"ext-hash": "*", "ext-hash": "*",
"ext-json": "*", "ext-json": "*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"fidry/cpu-core-counter": "^1.2", "fidry/cpu-core-counter": "^1.2",
"php": "^7.4 || ^8.0", "php": "^7.4 || ^8.0",
"react/child-process": "^0.6.5", "react/child-process": "^0.6.6",
"react/event-loop": "^1.0", "react/event-loop": "^1.0",
"react/promise": "^2.0 || ^3.0", "react/promise": "^2.11 || ^3.0",
"react/socket": "^1.0", "react/socket": "^1.0",
"react/stream": "^1.0", "react/stream": "^1.0",
"sebastian/diff": "^4.0 || ^5.1 || ^6.0 || ^7.0", "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
"symfony/console": "^5.4 || ^6.4 || ^7.0", "symfony/console": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/filesystem": "^5.4 || ^6.4 || ^7.0", "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/finder": "^5.4 || ^6.4 || ^7.0", "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0",
"symfony/options-resolver": "^5.4 || ^6.4 || ^7.0", "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0",
"symfony/polyfill-mbstring": "^1.31", "symfony/polyfill-mbstring": "^1.32",
"symfony/polyfill-php80": "^1.31", "symfony/polyfill-php80": "^1.32",
"symfony/polyfill-php81": "^1.31", "symfony/polyfill-php81": "^1.32",
"symfony/process": "^5.4 || ^6.4 || ^7.2", "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2",
"symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0"
}, },
"require-dev": { "require-dev": {
"facile-it/paraunit": "^1.3.1 || ^2.6", "facile-it/paraunit": "^1.3.1 || ^2.6",
"infection/infection": "^0.29.14", "infection/infection": "^0.29.14",
"justinrainbow/json-schema": "^5.3 || ^6.2", "justinrainbow/json-schema": "^5.3 || ^6.4",
"keradus/cli-executor": "^2.1", "keradus/cli-executor": "^2.2",
"mikey179/vfsstream": "^1.6.12", "mikey179/vfsstream": "^1.6.12",
"php-coveralls/php-coveralls": "^2.7", "php-coveralls/php-coveralls": "^2.8",
"php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/accessible-object": "^1.1",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
"phpunit/phpunit": "^9.6.22 || ^10.5.45 || ^11.5.12", "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25",
"symfony/var-dumper": "^5.4.48 || ^6.4.18 || ^7.2.3", "symfony/polyfill-php84": "^1.32",
"symfony/yaml": "^5.4.45 || ^6.4.18 || ^7.2.3" "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1",
"symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1"
}, },
"suggest": { "suggest": {
"ext-dom": "For handling output formats in XML", "ext-dom": "For handling output formats in XML",
@@ -498,7 +499,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.75.0" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.84.0"
}, },
"funding": [ "funding": [
{ {
@@ -506,7 +507,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-03-31T18:40:42+00:00" "time": "2025-07-15T18:21:57+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@@ -1256,16 +1257,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v7.3.0", "version": "v7.3.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44" "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44", "url": "https://api.github.com/repos/symfony/console/zipball/9e27aecde8f506ba0fd1d9989620c04a87697101",
"reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44", "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1330,7 +1331,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v7.3.0" "source": "https://github.com/symfony/console/tree/v7.3.1"
}, },
"funding": [ "funding": [
{ {
@@ -1346,7 +1347,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-05-24T10:34:04+00:00" "time": "2025-06-27T19:55:54+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",

View File

@@ -26,9 +26,10 @@ SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd $SCRIPT_DIR/php-cs-fixer cd $SCRIPT_DIR/php-cs-fixer
composer update --quiet composer update --quiet
rm -f .php-cs-fixer.cache rm -f .php-cs-fixer.cache
PHP_CS_FIXER_IGNORE_ENV=true ./vendor/bin/php-cs-fixer fix \ ./vendor/bin/php-cs-fixer fix \
--config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php \ --config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php \
--format=txt -v \ --format=txt \
-v \
--allow-risky=yes --allow-risky=yes
EXIT_CODE=$? EXIT_CODE=$?

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
use Rector\Config\RectorConfig; use Rector\Config\RectorConfig;
use Rector\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector; use Rector\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector;
use Rector\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector;
use Rector\Transform\Rector\String_\StringToClassConstantRector; use Rector\Transform\Rector\String_\StringToClassConstantRector;
use RectorLaravel\Set\LaravelLevelSetList; use RectorLaravel\Set\LaravelLevelSetList;
@@ -32,6 +33,7 @@ use RectorLaravel\Set\LaravelLevelSetList;
return RectorConfig::configure() return RectorConfig::configure()
->withSkip([ ->withSkip([
ChangeOrIfContinueToMultiContinueRector::class, ChangeOrIfContinueToMultiContinueRector::class,
AddParamBasedOnParentClassMethodRector::class,
StringToClassConstantRector::class => [ StringToClassConstantRector::class => [
__DIR__ . '/../app/Http/Controllers/Auth/LoginController.php', __DIR__ . '/../app/Http/Controllers/Auth/LoginController.php',
], ],

View File

@@ -329,7 +329,7 @@ FIREFLY_III_LAYOUT=v1
# Which Query Parser implementation to use for the search engine and rules # Which Query Parser implementation to use for the search engine and rules
# 'new' is experimental, 'legacy' is the classic one # 'new' is experimental, 'legacy' is the classic one
# #
QUERY_PARSER_IMPLEMENTATION=legacy QUERY_PARSER_IMPLEMENTATION=new
# #
# Please make sure this URL matches the external URL of your Firefly III installation. # Please make sure this URL matches the external URL of your Firefly III installation.

View File

@@ -1,4 +1,4 @@
name: Bug Report name: Bug report
description: Report a bug in Firefly III (or associated tools) description: Report a bug in Firefly III (or associated tools)
body: body:
- type: checkboxes - type: checkboxes
@@ -12,7 +12,7 @@ body:
- type: checkboxes - type: checkboxes
attributes: attributes:
label: I've found a bug and checked that ... label: I've found a bug and checked that ...
description: Make sure that your request fulfills all of the following requirements. If one requirement cannot be satisfied, explain in detail why. description: Make sure that your request fulfills all of the following requirements. If one requirement cannot be satisfied, please explain why.
options: options:
- label: ... [the documentation](https://docs.firefly-iii.org/) does not mention anything about my problem - label: ... [the documentation](https://docs.firefly-iii.org/) does not mention anything about my problem
- label: ... there are no open or closed issues that are related to my problem - label: ... there are no open or closed issues that are related to my problem
@@ -33,13 +33,6 @@ body:
validations: validations:
required: true required: true
- type: textarea
attributes:
label: Expected behaviour
description: Please describe precisely what you'd expect to happen. Be specific.
validations:
required: false
- type: textarea - type: textarea
attributes: attributes:
label: Steps to reproduce label: Steps to reproduce
@@ -54,4 +47,4 @@ body:
- type: textarea - type: textarea
attributes: attributes:
label: Additional info label: Additional info
description: Please provide any additional information that seem useful. description: Please provide any additional information that seems useful.

View File

@@ -3,3 +3,6 @@ contact_links:
- name: Ask a question - name: Ask a question
url: https://github.com/firefly-iii/firefly-iii/discussions url: https://github.com/firefly-iii/firefly-iii/discussions
about: Please ask and answer questions here. about: Please ask and answer questions here.
- name: I need support!
url: https://github.com/firefly-iii/firefly-iii/discussions
about: I think I broke something...

View File

@@ -1,4 +1,4 @@
name: Feature Request name: Feature request
description: Request a feature or enhancement in Firefly III (or associated tools) description: Request a feature or enhancement in Firefly III (or associated tools)
body: body:
- type: checkboxes - type: checkboxes
@@ -31,11 +31,6 @@ body:
validations: validations:
required: true required: true
- type: textarea
attributes:
label: What are alternatives?
description: Please describe what alternatives currently exist.
- type: textarea - type: textarea
attributes: attributes:
label: Additional context label: Additional context

View File

@@ -66,7 +66,6 @@ jobs:
'label-actions.yml', 'label-actions.yml',
'lock.yml', 'lock.yml',
'release.yml', 'release.yml',
'sonarcloud.yml',
'stale.yml' 'stale.yml'
] ]

View File

@@ -259,6 +259,12 @@ jobs:
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
echo "" >> output.txt echo "" >> output.txt
echo ":warning: Please be careful with this pre-release, as it may not work as expected." >> output.txt echo ":warning: Please be careful with this pre-release, as it may not work as expected." >> output.txt
# donations!
echo '' >> output.txt
echo '### Support Firefly III' >> output.txt
echo 'Did you know you can support the development of Firefly III? You can donate in many ways, like GitHub Sponsors or Patreon. For more information, please [follow this link](https://bit.ly/donate-to-Firefly-III) for more information.' >> output.txt
echo '' >> output.txt
fi fi
# describe a branch release # describe a branch release
if [[ "$version" == branch* ]]; then if [[ "$version" == branch* ]]; then
@@ -279,16 +285,31 @@ jobs:
if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]] && [[ "$version" != *alpha* ]] && [[ "$version" != *beta* ]]; then if [[ "develop" != "$version" ]] && [[ "$version" != branch* ]] && [[ "$version" != *alpha* ]] && [[ "$version" != *beta* ]]; then
echo 'Describe the latest release' echo 'Describe the latest release'
sudo chown -R runner:docker output.txt sudo chown -R runner:docker output.txt
# the changelog is in output.txt
mv output.txt output2.txt
touch output.txt touch output.txt
echo '' >> output.txt echo '' >> output.txt
echo "Welcome to release $version of Firefly III. It contains the the latest fixes, translations and features. Docker users can find this release under the \`latest\` tag." >> output.txt echo "Welcome to release $version of Firefly III. It contains the the latest fixes, translations and features. Docker users can find this release under the \`latest\` tag." >> output.txt
echo '' >> output.txt echo '' >> output.txt
# add changelog to file.
cat output2.txt >> output.txt
echo '' >> output.txt
rm -f output2.txt
echo '### Instructions' >> output.txt echo '### Instructions' >> output.txt
echo '' >> 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 "* 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 "* 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 echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
# donations!
echo '' >> output.txt
echo '### Support Firefly III' >> output.txt
echo 'Did you know you can support the development of Firefly III? You can donate in many ways, like GitHub Sponsors or Patreon. For more information, please [follow this link](https://bit.ly/donate-to-Firefly-III) for more information.' >> output.txt
echo '' >> output.txt
fi fi
# describe alpha release # describe alpha release

View File

@@ -1,71 +0,0 @@
name: 'Code - Run Sonarcloud'
on:
pull_request:
workflow_dispatch:
push:
branches:
- main
env:
DB_CONNECTION: sqlite
APP_KEY: TestTestTestTestTestTestTestTest
jobs:
sonarcloud:
name: SonarCloud
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP with Xdebug
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
coverage: xdebug
extensions: >-
bcmath
curl
fileinfo
iconv
intl
json
sqlite3
mbstring
openssl
pdo
session
simplexml
sodium
tokenizer
xml
xmlwriter
- name: Copy standard configuration
run: cp .env.testing .env
- name: Install Composer dependencies
run: composer install --prefer-dist --no-interaction --no-progress --no-scripts
- name: "Create database file"
run: |
touch storage/database/database.sqlite
wget -q https://github.com/firefly-iii/test-fixtures/raw/refs/heads/main/test-database.sqlite -O storage/database/database.sqlite
- name: "Upgrades the database to the latest version"
run: |
php artisan firefly-iii:upgrade-database
chmod 600 storage/oauth-public.key
chmod 600 storage/oauth-private.key
- name: "Integrity Database Report"
run: php artisan firefly-iii:report-integrity
- name: "Run tests with coverage"
run: composer coverage
- name: Fix code coverage paths
run: sed -i 's@'$GITHUB_WORKSPACE'@/github/workspace/@g' coverage.xml
- name: SonarCloud Scan
uses: SonarSource/sonarqube-scan-action@v5.2.0
env:
GITHUB_TOKEN: ${{ secrets.GH_ACTIONS_PERSONAL_ACCESS_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete; namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use Deprecated;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest; use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
@@ -83,9 +84,8 @@ class CurrencyController extends Controller
/** /**
* Documentation for this endpoint is at: * Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getCurrenciesCodeAC * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getCurrenciesCodeAC
*
* @deprecated
*/ */
#[Deprecated]
public function currenciesWithCode(AutocompleteRequest $request): JsonResponse public function currenciesWithCode(AutocompleteRequest $request): JsonResponse
{ {
$data = $request->getData(); $data = $request->getData();

View File

@@ -24,16 +24,16 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Chart; namespace FireflyIII\Api\V1\Controllers\Chart;
use FireflyIII\Exceptions\ValidationException;
use FireflyIII\Models\TransactionCurrency;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Chart\ChartRequest; use FireflyIII\Api\V1\Requests\Chart\ChartRequest;
use FireflyIII\Api\V1\Requests\Data\DateRequest; use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Enums\AccountTypeEnum; use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Exceptions\ValidationException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Preference; use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Chart\ChartData; use FireflyIII\Support\Chart\ChartData;
use FireflyIII\Support\Facades\Preferences; use FireflyIII\Support\Facades\Preferences;
@@ -42,6 +42,7 @@ use FireflyIII\Support\Http\Api\ApiSupport;
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter; use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/** /**
* Class AccountController * Class AccountController
@@ -86,10 +87,12 @@ class AccountController extends Controller
// move date to end of day // move date to end of day
$queryParameters['start']->startOfDay(); $queryParameters['start']->startOfDay();
$queryParameters['end']->endOfDay(); $queryParameters['end']->endOfDay();
Log::debug(sprintf('dashboard(), convert to native: %s', var_export($this->convertToNative, true)));
// loop each account, and collect info: // loop each account, and collect info:
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
Log::debug(sprintf('Account #%d ("%s")', $account->id, $account->name));
$this->renderAccountData($queryParameters, $account); $this->renderAccountData($queryParameters, $account);
} }
@@ -101,7 +104,14 @@ class AccountController extends Controller
*/ */
private function renderAccountData(array $params, Account $account): void private function renderAccountData(array $params, Account $account): void
{ {
Log::debug(sprintf('Now in %s(array, #%d)', __METHOD__, $account->id));
$currency = $this->repository->getAccountCurrency($account); $currency = $this->repository->getAccountCurrency($account);
$currentStart = clone $params['start'];
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
$previous = array_values($range)[0]['balance'];
$nativePrevious = null;
if (!$currency instanceof TransactionCurrency) { if (!$currency instanceof TransactionCurrency) {
$currency = $this->default; $currency = $this->default;
} }
@@ -109,7 +119,7 @@ class AccountController extends Controller
'label' => $account->name, 'label' => $account->name,
// the currency that belongs to the account. // the currency that belongs to the account.
'currency_id' => (string) $currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -121,18 +131,33 @@ class AccountController extends Controller
'period' => '1D', 'period' => '1D',
'entries' => [], 'entries' => [],
]; ];
$currentStart = clone $params['start']; if ($this->convertToNative) {
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative); $currentSet['native_entries'] = [];
$currentSet['native_currency_id'] = (string)$this->nativeCurrency->id;
$currentSet['native_currency_code'] = $this->nativeCurrency->code;
$currentSet['native_currency_symbol'] = $this->nativeCurrency->symbol;
$currentSet['native_currency_decimal_places'] = $this->nativeCurrency->decimal_places;
$nativePrevious = array_values($range)[0]['native_balance'];
}
$previous = array_values($range)[0]['balance'];
while ($currentStart <= $params['end']) { while ($currentStart <= $params['end']) {
$format = $currentStart->format('Y-m-d'); $format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString(); $label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous; $balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous;
$previous = $balance; $previous = $balance;
$currentSet['entries'][$label] = $balance;
// do the same for the native balance, if relevant:
$nativeBalance = null;
if ($this->convertToNative) {
$nativeBalance = array_key_exists($format, $range) ? $range[$format]['native_balance'] : $nativePrevious;
$nativePrevious = $nativeBalance;
$currentSet['native_entries'][$label] = $nativeBalance;
}
$currentStart->addDay(); $currentStart->addDay();
$currentSet['entries'][$label] = $balance;
} }
$this->chartData->add($currentSet); $this->chartData->add($currentSet);
} }
@@ -148,6 +173,7 @@ class AccountController extends Controller
// parameters for chart: // parameters for chart:
$dates = $request->getAll(); $dates = $request->getAll();
/** @var Carbon $start */ /** @var Carbon $start */
$start = $dates['start']; $start = $dates['start'];
@@ -158,28 +184,21 @@ class AccountController extends Controller
$start->startOfDay(); $start->startOfDay();
$end->endOfDay(); $end->endOfDay();
// user's preferences $frontPageIds = $this->getFrontPageAccountIds();
$defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray(); $accounts = $this->repository->getAccountsById($frontPageIds);
/** @var Preference $frontpage */
Preferences::get('frontpageAccounts', $defaultSet);
if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) {
$frontpage->data = $defaultSet;
$frontpage->save();
}
// get accounts:
$accounts = $this->repository->getAccountsById($frontpage->data);
$chartData = []; $chartData = [];
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
Log::debug(sprintf('Rendering chart data for account %s (%d)', $account->name, $account->id));
$currency = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency; $currency = $this->repository->getAccountCurrency($account) ?? $this->nativeCurrency;
$field = $this->convertToNative && $currency->id !== $this->nativeCurrency->id ? 'native_balance' : 'balance'; $currentStart = clone $start;
$range = Steam::finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
$previous = array_values($range)[0]['balance'];
$nativePrevious = null;
$currentSet = [ $currentSet = [
'label' => $account->name, 'label' => $account->name,
'currency_id' => (string) $currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -189,21 +208,57 @@ class AccountController extends Controller
'yAxisID' => 0, // 0, 1, 2 'yAxisID' => 0, // 0, 1, 2
'entries' => [], 'entries' => [],
]; ];
// TODO this code is also present in the V2 chart account controller so this method is due to be deprecated.
$currentStart = clone $start; // add "native_entries" if convertToNative is true:
$range = Steam::finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative); if ($this->convertToNative) {
$previous = array_values($range)[0][$field]; $currentSet['native_entries'] = [];
$currentSet['native_currency_id'] = (string)$this->nativeCurrency->id;
$currentSet['native_currency_code'] = $this->nativeCurrency->code;
$currentSet['native_currency_symbol'] = $this->nativeCurrency->symbol;
$currentSet['native_currency_decimal_places'] = $this->nativeCurrency->decimal_places;
$nativePrevious = array_values($range)[0]['native_balance'];
}
// also get the native balance if convertToNative is true:
while ($currentStart <= $end) { while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d'); $format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString(); $label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format][$field] : $previous;
// balance is based on "balance" from the $range variable.
$balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous;
$previous = $balance; $previous = $balance;
$currentStart->addDay();
$currentSet['entries'][$label] = $balance; $currentSet['entries'][$label] = $balance;
// do the same for the native balance, if relevant:
$nativeBalance = null;
if ($this->convertToNative) {
$nativeBalance = array_key_exists($format, $range) ? $range[$format]['native_balance'] : $nativePrevious;
$nativePrevious = $nativeBalance;
$currentSet['native_entries'][$label] = $nativeBalance;
}
$currentStart->addDay();
} }
$chartData[] = $currentSet; $chartData[] = $currentSet;
} }
return response()->json($chartData); return response()->json($chartData);
} }
private function getFrontPageAccountIds(): array
{
$defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
/** @var Preference $frontpage */
$frontpage = Preferences::get('frontpageAccounts', $defaultSet);
if (!(is_array($frontpage->data) && count($frontpage->data) > 0)) {
$frontpage->data = $defaultSet;
$frontpage->save();
}
return $frontpage->data ?? $defaultSet;
}
} }

View File

@@ -123,7 +123,7 @@ class BudgetController extends Controller
foreach ($rows as $row) { foreach ($rows as $row) {
$current = [ $current = [
'label' => $budget->name, 'label' => $budget->name,
'currency_id' => (string) $row['currency_id'], 'currency_id' => (string)$row['currency_id'],
'currency_code' => $row['currency_code'], 'currency_code' => $row['currency_code'],
'currency_name' => $row['currency_name'], 'currency_name' => $row['currency_name'],
'currency_decimal_places' => $row['currency_decimal_places'], 'currency_decimal_places' => $row['currency_decimal_places'],
@@ -131,6 +131,7 @@ class BudgetController extends Controller
'start' => $row['start'], 'start' => $row['start'],
'end' => $row['end'], 'end' => $row['end'],
'entries' => [ 'entries' => [
'budgeted' => $row['budgeted'],
'spent' => $row['spent'], 'spent' => $row['spent'],
'left' => $row['left'], 'left' => $row['left'],
'overspent' => $row['overspent'], 'overspent' => $row['overspent'],
@@ -159,11 +160,9 @@ class BudgetController extends Controller
* Shared between the "noBudgetLimits" function and "processLimit". Will take a single set of expenses and return * Shared between the "noBudgetLimits" function and "processLimit". Will take a single set of expenses and return
* its info. * its info.
* *
* @param array<int, array<int, string>> $array
*
* @throws FireflyException * @throws FireflyException
*/ */
private function processExpenses(int $budgetId, array $array, Carbon $start, Carbon $end): array private function processExpenses(int $budgetId, array $spent, Carbon $start, Carbon $end): array
{ {
$return = []; $return = [];
@@ -174,16 +173,17 @@ class BudgetController extends Controller
* @var int $currencyId * @var int $currencyId
* @var array $block * @var array $block
*/ */
foreach ($array as $currencyId => $block) { foreach ($spent as $currencyId => $block) {
$this->currencies[$currencyId] ??= TransactionCurrency::find($currencyId); $this->currencies[$currencyId] ??= TransactionCurrency::find($currencyId);
$return[$currencyId] ??= [ $return[$currencyId] ??= [
'currency_id' => (string) $currencyId, 'currency_id' => (string)$currencyId,
'currency_code' => $block['currency_code'], 'currency_code' => $block['currency_code'],
'currency_name' => $block['currency_name'], 'currency_name' => $block['currency_name'],
'currency_symbol' => $block['currency_symbol'], 'currency_symbol' => $block['currency_symbol'],
'currency_decimal_places' => (int) $block['currency_decimal_places'], 'currency_decimal_places' => (int)$block['currency_decimal_places'],
'start' => $start->toAtomString(), 'start' => $start->toAtomString(),
'end' => $end->toAtomString(), 'end' => $end->toAtomString(),
'budgeted' => '0',
'spent' => '0', 'spent' => '0',
'left' => '0', 'left' => '0',
'overspent' => '0', 'overspent' => '0',
@@ -193,7 +193,7 @@ class BudgetController extends Controller
// var_dump($return); // var_dump($return);
/** @var array $journal */ /** @var array $journal */
foreach ($currentBudgetArray['transaction_journals'] as $journal) { foreach ($currentBudgetArray['transaction_journals'] as $journal) {
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], (string) $journal['amount']); $return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], (string)$journal['amount']);
} }
} }
@@ -237,18 +237,17 @@ class BudgetController extends Controller
/** @var array $entry */ /** @var array $entry */
// only spent the entry where the entry's currency matches the budget limit's currency // only spent the entry where the entry's currency matches the budget limit's currency
// so $filtered will only have 1 or 0 entries // so $filtered will only have 1 or 0 entries
$filtered = array_filter($spent, function ($entry) use ($limitCurrencyId) { $filtered = array_filter($spent, fn ($entry) => $entry['currency_id'] === $limitCurrencyId);
return $entry['currency_id'] === $limitCurrencyId;
});
$result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end); $result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end);
if (1 === count($result)) { if (1 === count($result)) {
$compare = bccomp($limit->amount, (string) app('steam')->positive($result[$limitCurrencyId]['spent'])); $compare = bccomp($limit->amount, (string)app('steam')->positive($result[$limitCurrencyId]['spent']));
$result[$limitCurrencyId]['budgeted'] = $limit->amount;
if (1 === $compare) { if (1 === $compare) {
// convert this amount into the native currency: // convert this amount into the native currency:
$result[$limitCurrencyId]['left'] = bcadd($limit->amount, (string) $result[$limitCurrencyId]['spent']); $result[$limitCurrencyId]['left'] = bcadd($limit->amount, (string)$result[$limitCurrencyId]['spent']);
} }
if ($compare <= 0) { if ($compare <= 0) {
$result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, (string) $result[$limitCurrencyId]['spent'])); $result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, (string)$result[$limitCurrencyId]['spent']));
} }
} }

View File

@@ -147,6 +147,7 @@ class ShowController extends Controller
$enrichment->setUser($admin); $enrichment->setUser($admin);
$selectedGroup = $enrichment->enrichSingle($selectedGroup); $selectedGroup = $enrichment->enrichSingle($selectedGroup);
/** @var TransactionGroupTransformer $transformer */ /** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class); $transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);

View File

@@ -58,7 +58,7 @@ class AutocompleteRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'date|after:1900-01-01|before:2099-12-31', 'date' => 'date|after:1970-01-02|before:2038-01-17',
]; ];
} }
} }

View File

@@ -60,8 +60,8 @@ class ChartRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'required|date|after:1900-01-01|before:2099-12-31|before_or_equal:end', 'start' => 'required|date|after:1970-01-02|before:2038-01-17|before_or_equal:end',
'end' => 'required|date|after:1900-01-01|before:2099-12-31|after_or_equal:start', 'end' => 'required|date|after:1970-01-02|before:2038-01-17|after_or_equal:start',
'preselected' => sprintf('nullable|in:%s', implode(',', config('firefly.preselected_accounts'))), 'preselected' => sprintf('nullable|in:%s', implode(',', config('firefly.preselected_accounts'))),
'period' => sprintf('nullable|in:%s', implode(',', config('firefly.valid_view_ranges'))), 'period' => sprintf('nullable|in:%s', implode(',', config('firefly.valid_view_ranges'))),
'accounts.*' => 'exists:accounts,id', 'accounts.*' => 'exists:accounts,id',

View File

@@ -65,9 +65,9 @@ class DateRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'date|after:1900-01-01|before:2099-12-31', 'date' => 'date|after:1970-01-02|before:2038-01-17',
'start' => 'date|after:1900-01-01|before:2099-12-31|before:end|required_with:end', 'start' => 'date|after:1970-01-02|before:2038-01-17|before:end|required_with:end',
'end' => 'date|after:1900-01-01|before:2099-12-31|after:start|required_with:start', 'end' => 'date|after:1970-01-02|before:2038-01-17|after:start|required_with:start',
]; ];
} }
} }

View File

@@ -55,8 +55,8 @@ class DateRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'required|date|after:1900-01-01|before:2099-12-31', 'start' => 'required|date|after:1970-01-02|before:2038-01-17',
'end' => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01', 'end' => 'required|date|after_or_equal:start|before:2038-01-17|after:1970-01-02',
]; ];
} }
} }

View File

@@ -53,7 +53,7 @@ class SingleDateRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'required|date|after:1900-01-01|before:2099-12-31', 'date' => 'required|date|after:1970-01-02|before:2038-01-17',
]; ];
} }
} }

View File

@@ -66,8 +66,8 @@ class Request extends FormRequest
'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
'amount' => ['nullable', new IsValidPositiveAmount()], 'amount' => ['nullable', new IsValidPositiveAmount()],
'start' => 'date|after:1900-01-01|before:2099-12-31', 'start' => 'date|after:1970-01-02|before:2038-01-17',
'end' => 'date|after:1900-01-01|before:2099-12-31', 'end' => 'date|after:1970-01-02|before:2038-01-17',
]; ];
} }

View File

@@ -80,9 +80,9 @@ class StoreRequest extends FormRequest
'amount_max' => ['required', new IsValidPositiveAmount()], 'amount_max' => ['required', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
'date' => 'date|required|after:1900-01-01|before:2099-12-31', 'date' => 'date|required|after:1970-01-02|before:2038-01-17',
'end_date' => 'nullable|date|after:date|after:1900-01-01|before:2099-12-31', 'end_date' => 'nullable|date|after:date|after:1970-01-02|before:2038-01-17',
'extension_date' => 'nullable|date|after:date|after:1900-01-01|before:2099-12-31', 'extension_date' => 'nullable|date|after:date|after:1970-01-02|before:2038-01-17',
'repeat_freq' => 'in:weekly,monthly,quarterly,half-year,yearly|required', 'repeat_freq' => 'in:weekly,monthly,quarterly,half-year,yearly|required',
'skip' => 'min:0|max:31|numeric', 'skip' => 'min:0|max:31|numeric',
'active' => [new IsBoolean()], 'active' => [new IsBoolean()],

View File

@@ -81,9 +81,9 @@ class UpdateRequest extends FormRequest
'amount_max' => ['nullable', new IsValidPositiveAmount()], 'amount_max' => ['nullable', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
'date' => 'date|after:1900-01-01|before:2099-12-31', 'date' => 'date|after:1970-01-02|before:2038-01-17',
'end_date' => 'date|after:date|after:1900-01-01|before:2099-12-31', 'end_date' => 'date|after:date|after:1970-01-02|before:2038-01-17',
'extension_date' => 'date|after:date|after:1900-01-01|before:2099-12-31', 'extension_date' => 'date|after:date|after:1970-01-02|before:2038-01-17',
'repeat_freq' => 'in:weekly,monthly,quarterly,half-year,yearly', 'repeat_freq' => 'in:weekly,monthly,quarterly,half-year,yearly',
'skip' => 'min:0|max:31|numeric', 'skip' => 'min:0|max:31|numeric',
'active' => [new IsBoolean()], 'active' => [new IsBoolean()],

View File

@@ -67,8 +67,8 @@ class UpdateRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'date|after:1900-01-01|before:2099-12-31', 'start' => 'date|after:1970-01-02|before:2038-01-17',
'end' => 'date|after:1900-01-01|before:2099-12-31', 'end' => 'date|after:1970-01-02|before:2038-01-17',
'amount' => ['nullable', new IsValidPositiveAmount()], 'amount' => ['nullable', new IsValidPositiveAmount()],
'currency_id' => 'numeric|exists:transaction_currencies,id', 'currency_id' => 'numeric|exists:transaction_currencies,id',
'currency_code' => 'min:3|max:51|exists:transaction_currencies,code', 'currency_code' => 'min:3|max:51|exists:transaction_currencies,code',

View File

@@ -45,7 +45,7 @@ class DestroyRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'required|date|after:1900-01-01|before:2099-12-31', 'date' => 'required|date|after:1970-01-02|before:2038-01-17',
]; ];
} }
} }

View File

@@ -61,7 +61,7 @@ class StoreRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'required|date|after:1900-01-01|before:2099-12-31', 'date' => 'required|date|after:1970-01-02|before:2038-01-17',
'rate' => 'required|numeric|gt:0', 'rate' => 'required|numeric|gt:0',
'from' => 'required|exists:transaction_currencies,code', 'from' => 'required|exists:transaction_currencies,code',
'to' => 'required|exists:transaction_currencies,code', 'to' => 'required|exists:transaction_currencies,code',

View File

@@ -50,7 +50,7 @@ class UpdateRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'date|after:1900-01-01|before:2099-12-31', 'date' => 'date|after:1970-01-02|before:2038-01-17',
'rate' => 'required|numeric|gt:0', 'rate' => 'required|numeric|gt:0',
]; ];
} }

View File

@@ -154,7 +154,7 @@ class UpdateRequest extends FormRequest
return [ return [
'title' => sprintf('min:1|max:255|uniqueObjectForUser:recurrences,title,%d', $recurrence->id), 'title' => sprintf('min:1|max:255|uniqueObjectForUser:recurrences,title,%d', $recurrence->id),
'description' => 'min:1|max:32768', 'description' => 'min:1|max:32768',
'first_date' => 'date|after:1900-01-01|before:2099-12-31', 'first_date' => 'date|after:1970-01-02|before:2038-01-17',
'apply_rules' => [new IsBoolean()], 'apply_rules' => [new IsBoolean()],
'active' => [new IsBoolean()], 'active' => [new IsBoolean()],
'repeat_until' => 'nullable|date', 'repeat_until' => 'nullable|date',

View File

@@ -71,8 +71,8 @@ class TestRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'date|after:1900-01-01|before:2099-12-31', 'start' => 'date|after:1970-01-02|before:2038-01-17',
'end' => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31', 'end' => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17',
'accounts' => '', 'accounts' => '',
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts', 'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
]; ];

View File

@@ -65,8 +65,8 @@ class TriggerRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'date|after:1900-01-01|before:2099-12-31', 'start' => 'date|after:1970-01-02|before:2038-01-17',
'end' => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31', 'end' => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17',
'accounts' => '', 'accounts' => '',
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts', 'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
]; ];

View File

@@ -65,8 +65,8 @@ class TestRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'date|after:1900-01-01|before:2099-12-31', 'start' => 'date|after:1970-01-02|before:2038-01-17',
'end' => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31', 'end' => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17',
'accounts' => '', 'accounts' => '',
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts', 'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
]; ];

View File

@@ -69,8 +69,8 @@ class TriggerRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'date|after:1900-01-01|before:2099-12-31', 'start' => 'date|after:1970-01-02|before:2038-01-17',
'end' => 'date|after_or_equal:start|after:1900-01-01|before:2099-12-31', 'end' => 'date|after_or_equal:start|after:1970-01-02|before:2038-01-17',
]; ];
} }
} }

View File

@@ -62,7 +62,7 @@ class StoreRequest extends FormRequest
$rules = [ $rules = [
'tag' => 'required|min:1|uniqueObjectForUser:tags,tag|max:1024', 'tag' => 'required|min:1|uniqueObjectForUser:tags,tag|max:1024',
'description' => 'min:1|nullable|max:32768', 'description' => 'min:1|nullable|max:32768',
'date' => 'date|nullable|after:1900-01-01|before:2099-12-31', 'date' => 'date|nullable|after:1970-01-02|before:2038-01-17',
]; ];
return Location::requestRules($rules); return Location::requestRules($rules);

View File

@@ -66,7 +66,7 @@ class UpdateRequest extends FormRequest
$rules = [ $rules = [
'tag' => 'min:1|max:1024|uniqueObjectForUser:tags,tag,'.$tag->id, 'tag' => 'min:1|max:1024|uniqueObjectForUser:tags,tag,'.$tag->id,
'description' => 'min:1|nullable|max:32768', 'description' => 'min:1|nullable|max:32768',
'date' => 'date|nullable|after:1900-01-01|before:2099-12-31', 'date' => 'date|nullable|after:1970-01-02|before:2038-01-17',
]; ];
return Location::requestRules($rules); return Location::requestRules($rules);

View File

@@ -73,7 +73,7 @@ class CronRequest extends FormRequest
{ {
return [ return [
'force' => 'in:true,false', 'force' => 'in:true,false',
'date' => 'nullable|date|after:1900-01-01|before:2099-12-31', 'date' => 'nullable|date|after:1970-01-02|before:2038-01-17',
]; ];
} }
} }

View File

@@ -116,7 +116,7 @@ class Controller extends BaseController
app('log')->warning(sprintf('Ignored invalid date "%s" in API v2 controller parameter check: %s', substr((string) $date, 0, 20), $e->getMessage())); app('log')->warning(sprintf('Ignored invalid date "%s" in API v2 controller parameter check: %s', substr((string) $date, 0, 20), $e->getMessage()));
} }
// out of range? set to null. // out of range? set to null.
if ($obj instanceof Carbon && ($obj->year <= 1900 || $obj->year > 2099)) { if ($obj instanceof Carbon && ($obj->year <= 1970 || $obj->year > 2038)) {
app('log')->warning(sprintf('Refuse to use date "%s" in API v2 controller parameter check: %s', $field, $obj->toAtomString())); app('log')->warning(sprintf('Refuse to use date "%s" in API v2 controller parameter check: %s', $field, $obj->toAtomString()));
$obj = null; $obj = null;
} }

View File

@@ -86,7 +86,7 @@ class AutocompleteRequest extends FormRequest
$valid = array_keys($this->types); $valid = array_keys($this->types);
return [ return [
'date' => 'nullable|date|after:1900-01-01|before:2100-01-01', 'date' => 'nullable|date|after:1970-01-02|before:2038-01-17',
'query' => 'nullable|string', 'query' => 'nullable|string',
'size' => 'nullable|integer|min:1|max:100', 'size' => 'nullable|integer|min:1|max:100',
'page' => 'nullable|integer|min:1', 'page' => 'nullable|integer|min:1',

View File

@@ -60,8 +60,8 @@ class BalanceChartRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'required|date|after:1900-01-01|before:2099-12-31', 'start' => 'required|date|after:1970-01-02|before:2038-01-17',
'end' => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01', 'end' => 'required|date|after_or_equal:start|before:2038-01-17|after:1970-01-02',
'accounts.*' => 'required|exists:accounts,id', 'accounts.*' => 'required|exists:accounts,id',
'period' => sprintf('required|in:%s', implode(',', config('firefly.valid_view_ranges'))), 'period' => sprintf('required|in:%s', implode(',', config('firefly.valid_view_ranges'))),
]; ];

View File

@@ -61,8 +61,8 @@ class ChartRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'required|date|after:1900-01-01|before:2099-12-31|before_or_equal:end', 'start' => 'required|date|after:1970-01-02|before:2038-01-17|before_or_equal:end',
'end' => 'required|date|after:1900-01-01|before:2099-12-31|after_or_equal:start', 'end' => 'required|date|after:1970-01-02|before:2038-01-17|after_or_equal:start',
'preselected' => sprintf('nullable|in:%s', implode(',', config('firefly.preselected_accounts'))), 'preselected' => sprintf('nullable|in:%s', implode(',', config('firefly.preselected_accounts'))),
'period' => sprintf('nullable|in:%s', implode(',', config('firefly.valid_view_ranges'))), 'period' => sprintf('nullable|in:%s', implode(',', config('firefly.valid_view_ranges'))),
'accounts.*' => 'exists:accounts,id', 'accounts.*' => 'exists:accounts,id',

View File

@@ -60,8 +60,8 @@ class DashboardChartRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'required|date|after:1900-01-01|before:2099-12-31', 'start' => 'required|date|after:1970-01-02|before:2038-01-17',
'end' => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01', 'end' => 'required|date|after_or_equal:start|before:2038-01-17|after:1970-01-02',
'preselected' => sprintf('in:%s', implode(',', config('firefly.preselected_accounts'))), 'preselected' => sprintf('in:%s', implode(',', config('firefly.preselected_accounts'))),
'accounts.*' => 'exists:accounts,id', 'accounts.*' => 'exists:accounts,id',
]; ];

View File

@@ -55,8 +55,8 @@ class DateRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'required|date|after:1900-01-01|before:2099-12-31', 'start' => 'required|date|after:1970-01-02|before:2038-01-17',
'end' => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01', 'end' => 'required|date|after_or_equal:start|before:2038-01-17|after:1970-01-02',
]; ];
} }
} }

View File

@@ -53,7 +53,7 @@ class SingleDateRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'required|date|after:1900-01-01|before:2099-12-31', 'date' => 'required|date|after:1970-01-02|before:2038-01-17',
]; ];
} }
} }

View File

@@ -63,9 +63,9 @@ class IndexRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'date|after:1900-01-01|before:2099-12-31', 'date' => 'date|after:1970-01-02|before:2038-01-17',
'start' => 'date|after:1900-01-01|before:2099-12-31|before:end|required_with:end', 'start' => 'date|after:1970-01-02|before:2038-01-17|before:end|required_with:end',
'end' => 'date|after:1900-01-01|before:2099-12-31|after:start|required_with:start', 'end' => 'date|after:1970-01-02|before:2038-01-17|after:start|required_with:start',
]; ];
} }
} }

View File

@@ -109,8 +109,8 @@ class InfiniteListRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'date|after:1900-01-01|before:2099-12-31', 'start' => 'date|after:1970-01-02|before:2038-01-17',
'end' => 'date|after:start|after:1900-01-01|before:2099-12-31', 'end' => 'date|after:start|after:1970-01-02|before:2038-01-17',
'start_row' => 'integer|min:0|max:4294967296', 'start_row' => 'integer|min:0|max:4294967296',
'end_row' => 'integer|min:0|max:4294967296|gt:start_row', 'end_row' => 'integer|min:0|max:4294967296|gt:start_row',
]; ];

View File

@@ -84,8 +84,8 @@ class ListRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'date|after:1900-01-01|before:2099-12-31', 'start' => 'date|after:1970-01-02|before:2038-01-17',
'end' => 'date|after:start|after:1900-01-01|before:2099-12-31', 'end' => 'date|after:start|after:1970-01-02|before:2038-01-17',
]; ];
} }
} }

View File

@@ -58,6 +58,8 @@ use function Safe\parse_url;
*/ */
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
{ {
public static ?Throwable $lastError = null;
/** /**
* @var array<int, class-string<Throwable>> * @var array<int, class-string<Throwable>>
*/ */
@@ -123,7 +125,7 @@ class Handler extends ExceptionHandler
// somehow Laravel handler does not catch this: // somehow Laravel handler does not catch this:
app('log')->debug('Return JSON unauthenticated error.'); app('log')->debug('Return JSON unauthenticated error.');
return response()->json(['message' => 'Unauthenticated', 'exception' => 'AuthenticationException'], 401); return response()->json(['message' => $e->getMessage(), 'exception' => 'AuthenticationException'], 401);
} }
if ($e instanceof OAuthServerException && $expectsJson) { if ($e instanceof OAuthServerException && $expectsJson) {
@@ -215,6 +217,7 @@ class Handler extends ExceptionHandler
#[Override] #[Override]
public function report(Throwable $e): void public function report(Throwable $e): void
{ {
self::$lastError = $e;
$doMailError = (bool) config('firefly.send_error_message'); $doMailError = (bool) config('firefly.send_error_message');
if ($this->shouldntReportLocal($e) || !$doMailError) { if ($this->shouldntReportLocal($e) || !$doMailError) {
parent::report($e); parent::report($e);

View File

@@ -78,7 +78,7 @@ class TagFactory
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'user_group_id' => $this->userGroup->id, 'user_group_id' => $this->userGroup->id,
'tag' => trim((string) $data['tag']), 'tag' => trim((string) $data['tag']),
'tagMode' => 'nothing', 'tag_mode' => 'nothing',
'date' => $data['date'], 'date' => $data['date'],
'description' => $data['description'], 'description' => $data['description'],
'latitude' => null, 'latitude' => null,

View File

@@ -32,11 +32,14 @@ use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Webhook; use FireflyIII\Models\Webhook;
use FireflyIII\Models\WebhookMessage; use FireflyIII\Models\WebhookMessage;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer; use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\ParameterBag;
@@ -59,14 +62,14 @@ class StandardMessageGenerator implements MessageGeneratorInterface
public function generateMessages(): void public function generateMessages(): void
{ {
app('log')->debug(__METHOD__); Log::debug(__METHOD__);
// get the webhooks: // get the webhooks:
if (0 === $this->webhooks->count()) { if (0 === $this->webhooks->count()) {
$this->webhooks = $this->getWebhooks(); $this->webhooks = $this->getWebhooks();
} }
// do some debugging // do some debugging
app('log')->debug( Log::debug(
sprintf('StandardMessageGenerator will generate messages for %d object(s) and %d webhook(s).', $this->objects->count(), $this->webhooks->count()) sprintf('StandardMessageGenerator will generate messages for %d object(s) and %d webhook(s).', $this->objects->count(), $this->webhooks->count())
); );
$this->run(); $this->run();
@@ -79,13 +82,13 @@ class StandardMessageGenerator implements MessageGeneratorInterface
private function run(): void private function run(): void
{ {
app('log')->debug('Now in StandardMessageGenerator::run'); Log::debug('Now in StandardMessageGenerator::run');
/** @var Webhook $webhook */ /** @var Webhook $webhook */
foreach ($this->webhooks as $webhook) { foreach ($this->webhooks as $webhook) {
$this->runWebhook($webhook); $this->runWebhook($webhook);
} }
app('log')->debug('Done with StandardMessageGenerator::run'); Log::debug('Done with StandardMessageGenerator::run');
} }
/** /**
@@ -93,7 +96,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface
*/ */
private function runWebhook(Webhook $webhook): void private function runWebhook(Webhook $webhook): void
{ {
app('log')->debug(sprintf('Now in runWebhook(#%d)', $webhook->id)); Log::debug(sprintf('Now in runWebhook(#%d)', $webhook->id));
/** @var Model $object */ /** @var Model $object */
foreach ($this->objects as $object) { foreach ($this->objects as $object) {
@@ -108,7 +111,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface
{ {
$class = $model::class; $class = $model::class;
// Line is ignored because all of Firefly III's Models have an id property. // Line is ignored because all of Firefly III's Models have an id property.
app('log')->debug(sprintf('Now in generateMessage(#%d, %s#%d)', $webhook->id, $class, $model->id)); Log::debug(sprintf('Now in generateMessage(#%d, %s#%d)', $webhook->id, $class, $model->id));
$uuid = Uuid::uuid4(); $uuid = Uuid::uuid4();
$basicMessage = [ $basicMessage = [
@@ -125,7 +128,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface
switch ($class) { switch ($class) {
default: default:
// Line is ignored because all of Firefly III's Models have an id property. // Line is ignored because all of Firefly III's Models have an id property.
app('log')->error( Log::error(
sprintf('Webhook #%d was given %s#%d to deal with but can\'t extract user ID from it.', $webhook->id, $class, $model->id) sprintf('Webhook #%d was given %s#%d to deal with but can\'t extract user ID from it.', $webhook->id, $class, $model->id)
); );
@@ -141,7 +144,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface
// then depends on the response what to put in the message: // then depends on the response what to put in the message:
switch ($webhook->response) { switch ($webhook->response) {
default: default:
app('log')->error( Log::error(
sprintf('The response code for webhook #%d is "%d" and the message generator cant handle it. Soft fail.', $webhook->id, $webhook->response) sprintf('The response code for webhook #%d is "%d" and the message generator cant handle it. Soft fail.', $webhook->id, $webhook->response)
); );
@@ -159,10 +162,10 @@ class StandardMessageGenerator implements MessageGeneratorInterface
try { try {
$basicMessage['content'] = $transformer->transformObject($model); $basicMessage['content'] = $transformer->transformObject($model);
} catch (FireflyException $e) { } catch (FireflyException $e) {
app('log')->error( Log::error(
sprintf('The transformer could not include the requested transaction group for webhook #%d: %s', $webhook->id, $e->getMessage()) sprintf('The transformer could not include the requested transaction group for webhook #%d: %s', $webhook->id, $e->getMessage())
); );
app('log')->error($e->getTraceAsString()); Log::error($e->getTraceAsString());
return; return;
} }
@@ -172,6 +175,10 @@ class StandardMessageGenerator implements MessageGeneratorInterface
case WebhookResponse::ACCOUNTS->value: case WebhookResponse::ACCOUNTS->value:
/** @var TransactionGroup $model */ /** @var TransactionGroup $model */
$accounts = $this->collectAccounts($model); $accounts = $this->collectAccounts($model);
$enrichment = new AccountEnrichment();
$enrichment->setUser($model->user);
$enrichment->setNative(Amount::getNativeCurrencyByUserGroup($model->userGroup));
$accounts = $enrichment->enrich($accounts);
foreach ($accounts as $account) { foreach ($accounts as $account) {
$transformer = new AccountTransformer(); $transformer = new AccountTransformer();
$transformer->setParameters(new ParameterBag()); $transformer->setParameters(new ParameterBag());
@@ -210,7 +217,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface
$webhookMessage->uuid = $message['uuid']; $webhookMessage->uuid = $message['uuid'];
$webhookMessage->message = $message; $webhookMessage->message = $message;
$webhookMessage->save(); $webhookMessage->save();
app('log')->debug(sprintf('Stored new webhook message #%d', $webhookMessage->id)); Log::debug(sprintf('Stored new webhook message #%d', $webhookMessage->id));
} }
public function setObjects(Collection $objects): void public function setObjects(Collection $objects): void

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Events; namespace FireflyIII\Handlers\Events;
use Deprecated;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Events\RequestedVersionCheckStatus; use FireflyIII\Events\RequestedVersionCheckStatus;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
@@ -42,9 +43,8 @@ class VersionCheckEventHandler
* Checks with GitHub to see if there is a new version. * Checks with GitHub to see if there is a new version.
* *
* @throws FireflyException * @throws FireflyException
*
* @deprecated ?
*/ */
#[Deprecated(message: '?')]
public function checkForUpdates(RequestedVersionCheckStatus $event): void public function checkForUpdates(RequestedVersionCheckStatus $event): void
{ {
Log::debug('Now in checkForUpdates()'); Log::debug('Now in checkForUpdates()');

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Handlers\Events;
use FireflyIII\Jobs\SendWebhookMessage; use FireflyIII\Jobs\SendWebhookMessage;
use FireflyIII\Models\WebhookMessage; use FireflyIII\Models\WebhookMessage;
use Illuminate\Support\Facades\Log;
/** /**
* Class WebhookEventHandler * Class WebhookEventHandler
@@ -37,7 +38,13 @@ class WebhookEventHandler
*/ */
public function sendWebhookMessages(): void public function sendWebhookMessages(): void
{ {
app('log')->debug(sprintf('Now in %s', __METHOD__)); Log::debug(sprintf('Now in %s', __METHOD__));
if (false === config('firefly.feature_flags.webhooks') || false === config('firefly.allow_webhooks')) {
Log::info('Webhook event handler is disabled, do not run sendWebhookMessages().');
return;
}
// kick off the job! // kick off the job!
$messages = WebhookMessage::where('webhook_messages.sent', false) $messages = WebhookMessage::where('webhook_messages.sent', false)
->get(['webhook_messages.*']) ->get(['webhook_messages.*'])
@@ -45,14 +52,14 @@ class WebhookEventHandler
static fn (WebhookMessage $message) => $message->webhookAttempts()->count() <= 2 static fn (WebhookMessage $message) => $message->webhookAttempts()->count() <= 2
)->splice(0, 5) )->splice(0, 5)
; ;
app('log')->debug(sprintf('Found %d webhook message(s) ready to be send.', $messages->count())); Log::debug(sprintf('Found %d webhook message(s) ready to be send.', $messages->count()));
foreach ($messages as $message) { foreach ($messages as $message) {
if (false === $message->sent) { if (false === $message->sent) {
app('log')->debug(sprintf('Send message #%d', $message->id)); Log::debug(sprintf('Send message #%d', $message->id));
SendWebhookMessage::dispatch($message)->afterResponse(); SendWebhookMessage::dispatch($message)->afterResponse();
} }
if (false !== $message->sent) { if (false !== $message->sent) {
app('log')->debug(sprintf('Skip message #%d', $message->id)); Log::debug(sprintf('Skip message #%d', $message->id));
} }
} }
} }

View File

@@ -434,6 +434,7 @@ class GroupCollector implements GroupCollectorInterface
public function findNothing(): GroupCollectorInterface public function findNothing(): GroupCollectorInterface
{ {
Log::warning('The search engine was instructed to FIND NOTHING. This may be a bug.');
$this->query->where('transaction_groups.id', -1); $this->query->where('transaction_groups.id', -1);
return $this; return $this;
@@ -557,7 +558,6 @@ class GroupCollector implements GroupCollectorInterface
$groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedJournal($augumentedJournal); $groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedJournal($augumentedJournal);
} }
} }
$groups = $this->parseSums($groups); $groups = $this->parseSums($groups);
return new Collection($groups); return new Collection($groups);
@@ -1094,6 +1094,10 @@ class GroupCollector implements GroupCollectorInterface
->whereNull('transaction_groups.deleted_at') ->whereNull('transaction_groups.deleted_at')
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
->whereNull('source.deleted_at') ->whereNull('source.deleted_at')
// #10507 ignore opening balance.
->where('transaction_types.type', '!=', TransactionTypeEnum::OPENING_BALANCE->value)
->whereNotNull('transaction_groups.id') ->whereNotNull('transaction_groups.id')
->whereNull('destination.deleted_at') ->whereNull('destination.deleted_at')
->orderBy('transaction_journals.date', 'DESC') ->orderBy('transaction_journals.date', 'DESC')

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Report; namespace FireflyIII\Helpers\Report;
use Deprecated;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Enums\AccountTypeEnum; use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
@@ -81,7 +82,7 @@ class NetWorth implements NetWorthInterface
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
Log::debug(sprintf('Now at account #%d ("%s")', $account->id, $account->name)); // Log::debug(sprintf('Now at account #%d ("%s")', $account->id, $account->name));
$currency = $this->accountRepository->getAccountCurrency($account) ?? $default; $currency = $this->accountRepository->getAccountCurrency($account) ?? $default;
$useNative = $convertToNative && $default->id !== $currency->id; $useNative = $convertToNative && $default->id !== $currency->id;
$currency = $useNative ? $default : $currency; $currency = $useNative ? $default : $currency;
@@ -92,12 +93,12 @@ class NetWorth implements NetWorthInterface
$balance = $balances[$account->id]['balance'] ?? '0'; $balance = $balances[$account->id]['balance'] ?? '0';
$nativeBalance = $balances[$account->id]['native_balance'] ?? '0'; $nativeBalance = $balances[$account->id]['native_balance'] ?? '0';
} }
Log::debug(sprintf('Balance is %s, native balance is %s', $balance, $nativeBalance)); // Log::debug(sprintf('Balance is %s, native balance is %s', $balance, $nativeBalance));
// always subtract virtual balance again. // always subtract virtual balance again.
$balance = '' !== (string) $account->virtual_balance ? bcsub($balance, (string) $account->virtual_balance) : $balance; $balance = '' !== (string) $account->virtual_balance ? bcsub($balance, (string) $account->virtual_balance) : $balance;
$nativeBalance = '' !== (string) $account->native_virtual_balance ? bcsub($nativeBalance, (string) $account->native_virtual_balance) : $nativeBalance; $nativeBalance = '' !== (string) $account->native_virtual_balance ? bcsub($nativeBalance, (string) $account->native_virtual_balance) : $nativeBalance;
$amountToUse = $useNative ? $nativeBalance : $balance; $amountToUse = $useNative ? $nativeBalance : $balance;
Log::debug(sprintf('Will use %s %s', $currencyCode, $amountToUse)); // Log::debug(sprintf('Will use %s %s', $currencyCode, $amountToUse));
$netWorth[$currencyCode] ??= [ $netWorth[$currencyCode] ??= [
'balance' => '0', 'balance' => '0',
@@ -134,9 +135,7 @@ class NetWorth implements NetWorthInterface
$this->currencyRepos->setUserGroup($this->userGroup); $this->currencyRepos->setUserGroup($this->userGroup);
} }
/** #[Deprecated]
* @deprecated
*/
public function sumNetWorthByCurrency(Carbon $date): array public function sumNetWorthByCurrency(Carbon $date): array
{ {
/** /**

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Report; namespace FireflyIII\Helpers\Report;
use Deprecated;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\UserGroup; use FireflyIII\Models\UserGroup;
use FireflyIII\User; use FireflyIII\User;
@@ -53,8 +54,7 @@ interface NetWorthInterface
* TODO move to repository * TODO move to repository
* *
* Same as above but cleaner function with less dependencies. * Same as above but cleaner function with less dependencies.
*
* @deprecated
*/ */
#[Deprecated]
public function sumNetWorthByCurrency(Carbon $date): array; public function sumNetWorthByCurrency(Carbon $date): array;
} }

View File

@@ -88,7 +88,9 @@ class IndexController extends Controller
/** @var Carbon $end */ /** @var Carbon $end */
$end = clone session('end', today(config('app.timezone'))->endOfMonth()); $end = clone session('end', today(config('app.timezone'))->endOfMonth());
$start->subDay();
// #10618 go to the end of the previous day.
$start->subSecond();
$ids = $accounts->pluck('id')->toArray(); $ids = $accounts->pluck('id')->toArray();
Log::debug(sprintf('inactive start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s'))); Log::debug(sprintf('inactive start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
@@ -164,8 +166,8 @@ class IndexController extends Controller
/** @var Carbon $end */ /** @var Carbon $end */
$end = clone session('end', today(config('app.timezone'))->endOfMonth()); $end = clone session('end', today(config('app.timezone'))->endOfMonth());
// 2025-05-11 removed this so start is exactly the start of the month. // #10618 go to the end of the previous day.
// $start->subDay(); $start->subSecond();
$ids = $accounts->pluck('id')->toArray(); $ids = $accounts->pluck('id')->toArray();
Log::debug(sprintf('index start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s'))); Log::debug(sprintf('index start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));

View File

@@ -91,7 +91,7 @@ class IndexController extends Controller
public function index(?Carbon $start = null, ?Carbon $end = null) public function index(?Carbon $start = null, ?Carbon $end = null)
{ {
$this->abRepository->cleanup(); $this->abRepository->cleanup();
app('log')->debug(sprintf('Start of IndexController::index("%s", "%s")', $start?->format('Y-m-d'), $end?->format('Y-m-d'))); Log::debug(sprintf('Start of IndexController::index("%s", "%s")', $start?->format('Y-m-d'), $end?->format('Y-m-d')));
// collect some basic vars: // collect some basic vars:
$range = app('navigation')->getViewRange(true); $range = app('navigation')->getViewRange(true);
@@ -199,12 +199,12 @@ class IndexController extends Controller
// get all budgets, and paginate them into $budgets. // get all budgets, and paginate them into $budgets.
$collection = $this->repository->getActiveBudgets(); $collection = $this->repository->getActiveBudgets();
$budgets = []; $budgets = [];
app('log')->debug(sprintf('7) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); Log::debug(sprintf('(getAllBudgets) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// complement budget with budget limits in range, and expenses in currency X in range. // complement budget with budget limits in range, and expenses in currency X in range.
/** @var Budget $current */ /** @var Budget $current */
foreach ($collection as $current) { foreach ($collection as $current) {
app('log')->debug(sprintf('Working on budget #%d ("%s")', $current->id, $current->name)); Log::debug(sprintf('Working on budget #%d ("%s")', $current->id, $current->name));
$array = $current->toArray(); $array = $current->toArray();
$array['spent'] = []; $array['spent'] = [];
$array['spent_total'] = []; $array['spent_total'] = [];
@@ -215,7 +215,7 @@ class IndexController extends Controller
/** @var BudgetLimit $limit */ /** @var BudgetLimit $limit */
foreach ($budgetLimits as $limit) { foreach ($budgetLimits as $limit) {
app('log')->debug(sprintf('Working on budget limit #%d', $limit->id)); Log::debug(sprintf('Working on budget limit #%d', $limit->id));
$currency = $limit->transactionCurrency ?? $defaultCurrency; $currency = $limit->transactionCurrency ?? $defaultCurrency;
$amount = app('steam')->bcround($limit->amount, $currency->decimal_places); $amount = app('steam')->bcround($limit->amount, $currency->decimal_places);
$array['budgeted'][] = [ $array['budgeted'][] = [
@@ -231,9 +231,11 @@ class IndexController extends Controller
'currency_name' => $currency->name, 'currency_name' => $currency->name,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
]; ];
app('log')->debug(sprintf('The amount budgeted for budget limit #%d is %s %s', $limit->id, $currency->code, $amount)); Log::debug(sprintf('The amount budgeted for budget limit #%d is %s %s', $limit->id, $currency->code, $amount));
} }
// #10463
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
foreach ($currencies as $currency) { foreach ($currencies as $currency) {
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$current]), $currency, false); $spentArr = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$current]), $currency, false);
@@ -260,6 +262,8 @@ class IndexController extends Controller
/** @var array $budget */ /** @var array $budget */
foreach ($budgets as $budget) { foreach ($budgets as $budget) {
Log::debug(sprintf('Now working on budget #%d ("%s")', $budget['id'], $budget['name']));
/** @var array $spent */ /** @var array $spent */
foreach ($budget['spent'] as $spent) { foreach ($budget['spent'] as $spent) {
$currencyId = $spent['currency_id']; $currencyId = $spent['currency_id'];

View File

@@ -23,8 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers; namespace FireflyIII\Http\Controllers;
use function Safe\realpath;
use function Safe\ini_get;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
@@ -38,6 +36,9 @@ use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\View; use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use function Safe\realpath;
use function Safe\ini_get;
/** /**
* Class Controller. * Class Controller.
* *
@@ -83,7 +84,7 @@ abstract class Controller extends BaseController
// overrule v2 layout back to v1. // overrule v2 layout back to v1.
if ('true' === request()->get('force_default_layout') && 'v2' === config('view.layout')) { if ('true' === request()->get('force_default_layout') && 'v2' === config('view.layout')) {
//config('view.layout','v1'); // config('view.layout','v1');
Config::set('view.layout', 'v1'); Config::set('view.layout', 'v1');
View::getFinder()->setPaths([realpath(base_path('resources/views'))]); // @phpstan-ignore-line View::getFinder()->setPaths([realpath(base_path('resources/views'))]); // @phpstan-ignore-line
} }

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Json; namespace FireflyIII\Http\Controllers\Json;
use Deprecated;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Enums\AccountTypeEnum; use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
@@ -46,9 +47,8 @@ class BoxController extends Controller
/** /**
* Deprecated method, no longer in use. * Deprecated method, no longer in use.
*
* @deprecated
*/ */
#[Deprecated]
public function available(): JsonResponse public function available(): JsonResponse
{ {
return response()->json([]); return response()->json([]);

View File

@@ -107,7 +107,7 @@ class RecurrenceController extends Controller
$repetitionMoment = str_ireplace('ndom,', '', $request->get('type')); $repetitionMoment = str_ireplace('ndom,', '', $request->get('type'));
} }
if ('yearly' === $repetitionType) { if ('yearly' === $repetitionType) {
$repetitionMoment = explode(',', (string) $request->get('type'))[1] ?? '2018-01-01'; $repetitionMoment = explode(',', (string) $request->get('type'))[1] ?? '2025-01-01';
} }
$actualStart->startOfDay(); $actualStart->startOfDay();
$repetition = new RecurrenceRepetition(); $repetition = new RecurrenceRepetition();

View File

@@ -26,10 +26,12 @@ namespace FireflyIII\Http\Middleware;
use Closure; use Closure;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Exceptions\Handler;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Auth\Factory as Auth; use Illuminate\Contracts\Auth\Factory as Auth;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use League\OAuth2\Server\Exception\OAuthServerException;
/** /**
* Class Authenticate * Class Authenticate
@@ -84,6 +86,7 @@ class Authenticate
if ($this->auth->check()) { if ($this->auth->check()) {
// do an extra check on user object. // do an extra check on user object.
/** @noinspection PhpUndefinedMethodInspection */ /** @noinspection PhpUndefinedMethodInspection */
/** @var User $user */ /** @var User $user */
$user = $this->auth->authenticate(); $user = $this->auth->authenticate();
$this->validateBlockedUser($user, $guards); $this->validateBlockedUser($user, $guards);
@@ -107,7 +110,14 @@ class Authenticate
} }
} }
throw new AuthenticationException('Unauthenticated.', $guards); // this is a massive hack, but if the handler has the oauth exception
// at this point we can report its error instead of a generic one.
$message = 'Unauthenticated.';
if (Handler::$lastError instanceof OAuthServerException) {
$message = Handler::$lastError->getHint();
}
throw new AuthenticationException($message, $guards);
} }
/** /**

View File

@@ -41,8 +41,8 @@ class SelectTransactionsRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'required|date|after:1900-01-01|before:2099-12-31|before:end|required_with:end', 'start' => 'required|date|after:1970-01-02|before:2038-01-17|before:end|required_with:end',
'end' => 'required|date|after:1900-01-01|before:2099-12-31|after:start|required_with:start', 'end' => 'required|date|after:1970-01-02|before:2038-01-17|after:start|required_with:start',
'accounts' => 'required', 'accounts' => 'required',
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts', 'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
]; ];

View File

@@ -74,7 +74,7 @@ class TagFormRequest extends FormRequest
'tag' => $tagRule, 'tag' => $tagRule,
'id' => $idRule, 'id' => $idRule,
'description' => 'max:32768|min:1|nullable', 'description' => 'max:32768|min:1|nullable',
'date' => 'date|nullable|after:1984-09-17', 'date' => 'date|nullable|after:1970-01-02|before:2038-01-17',
]; ];
return Location::requestRules($rules); return Location::requestRules($rules);

View File

@@ -40,7 +40,7 @@ class Tag extends Model
use ReturnsIntegerUserIdTrait; use ReturnsIntegerUserIdTrait;
use SoftDeletes; use SoftDeletes;
protected $fillable = ['user_id', 'user_group_id', 'tag', 'date', 'date_tz', 'description', 'tagMode']; protected $fillable = ['user_id', 'user_group_id', 'tag', 'date', 'date_tz', 'description', 'tag_mode'];
protected $hidden = ['zoomLevel', 'latitude', 'longitude']; protected $hidden = ['zoomLevel', 'latitude', 'longitude'];

View File

@@ -312,11 +312,23 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
Log::debug(sprintf('Search for linked journals between %s and %s', $start->toW3cString(), $end->toW3cString())); Log::debug(sprintf('Search for linked journals between %s and %s', $start->toW3cString(), $end->toW3cString()));
return $bill->transactionJournals() return $bill->transactionJournals()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('transaction_currencies AS currency', 'currency.id', '=', 'transactions.transaction_currency_id')
->leftJoin('transaction_currencies AS foreign_currency', 'foreign_currency.id', '=', 'transactions.foreign_currency_id')
->where('transactions.amount', '>', 0)
->before($end)->after($start)->get( ->before($end)->after($start)->get(
[ [
'transaction_journals.id', 'transaction_journals.id',
'transaction_journals.date', 'transaction_journals.date',
'transaction_journals.transaction_group_id', 'transaction_journals.transaction_group_id',
'transactions.transaction_currency_id',
'currency.code AS transaction_currency_code',
'currency.decimal_places AS transaction_currency_decimal_places',
'transactions.foreign_currency_id',
'foreign_currency.code AS foreign_currency_code',
'foreign_currency.decimal_places AS foreign_currency_decimal_places',
'transactions.amount',
'transactions.foreign_amount',
] ]
) )
; ;

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Budget; namespace FireflyIII\Repositories\Budget;
use Deprecated;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\AvailableBudget; use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
@@ -205,9 +206,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
; ;
} }
/** #[Deprecated]
* @deprecated
*/
public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): AvailableBudget public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): AvailableBudget
{ {
/** @var null|AvailableBudget */ /** @var null|AvailableBudget */

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Budget; namespace FireflyIII\Repositories\Budget;
use Deprecated;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Enums\UserRoleEnum; use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\AvailableBudget; use FireflyIII\Models\AvailableBudget;
@@ -66,9 +67,7 @@ interface AvailableBudgetRepositoryInterface
*/ */
public function get(?Carbon $start = null, ?Carbon $end = null): Collection; public function get(?Carbon $start = null, ?Carbon $end = null): Collection;
/** #[Deprecated]
* @deprecated
*/
public function getAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end): string; public function getAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end): string;
public function getAvailableBudgetWithCurrency(Carbon $start, Carbon $end): array; public function getAvailableBudgetWithCurrency(Carbon $start, Carbon $end): array;
@@ -90,9 +89,7 @@ interface AvailableBudgetRepositoryInterface
*/ */
public function getByCurrencyDate(Carbon $start, Carbon $end, TransactionCurrency $currency): ?AvailableBudget; public function getByCurrencyDate(Carbon $start, Carbon $end, TransactionCurrency $currency): ?AvailableBudget;
/** #[Deprecated]
* @deprecated
*/
public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): AvailableBudget; public function setAvailableBudget(TransactionCurrency $currency, Carbon $start, Carbon $end, string $amount): AvailableBudget;
public function store(array $data): ?AvailableBudget; public function store(array $data): ?AvailableBudget;

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Budget; namespace FireflyIII\Repositories\Budget;
use Deprecated;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Enums\UserRoleEnum; use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
@@ -44,9 +45,7 @@ use Illuminate\Support\Collection;
*/ */
interface NoBudgetRepositoryInterface interface NoBudgetRepositoryInterface
{ {
/** #[Deprecated]
* @deprecated
*/
public function getNoBudgetPeriodReport(Collection $accounts, Carbon $start, Carbon $end): array; public function getNoBudgetPeriodReport(Collection $accounts, Carbon $start, Carbon $end): array;
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array; public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array;

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Budget; namespace FireflyIII\Repositories\Budget;
use Deprecated;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
@@ -74,9 +75,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
/** /**
* This method is being used to generate the budget overview in the year/multi-year report. Its used * This method is being used to generate the budget overview in the year/multi-year report. Its used
* in both the year/multi-year budget overview AND in the accompanying chart. * in both the year/multi-year budget overview AND in the accompanying chart.
*
* @deprecated
*/ */
#[Deprecated]
public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array
{ {
$carbonFormat = app('navigation')->preferredCarbonFormat($start, $end); $carbonFormat = app('navigation')->preferredCarbonFormat($start, $end);
@@ -204,7 +204,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
?TransactionCurrency $currency = null, ?TransactionCurrency $currency = null,
bool $convertToNative = false bool $convertToNative = false
): array { ): array {
Log::debug(sprintf('Start of %s(date, date, array, array, "%s", "%s").', __METHOD__, $currency?->code, var_export($convertToNative, true))); Log::debug(sprintf('Start of %s(date, date, array, array, "%s", %s).', __METHOD__, $currency?->code, var_export($convertToNative, true)));
// this collector excludes all transfers TO liabilities (which are also withdrawals) // this collector excludes all transfers TO liabilities (which are also withdrawals)
// because those expenses only become expenses once they move from the liability to the friend. // because those expenses only become expenses once they move from the liability to the friend.
// 2024-12-24 disable the exclusion for now. // 2024-12-24 disable the exclusion for now.

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Budget; namespace FireflyIII\Repositories\Budget;
use Deprecated;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Enums\UserRoleEnum; use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
@@ -51,9 +52,7 @@ interface OperationsRepositoryInterface
*/ */
public function budgetedPerDay(Budget $budget): string; public function budgetedPerDay(Budget $budget): string;
/** #[Deprecated]
* @deprecated
*/
public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array; public function getBudgetPeriodReport(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end): array;
/** /**
@@ -71,6 +70,7 @@ interface OperationsRepositoryInterface
Carbon $end, Carbon $end,
?Collection $accounts = null, ?Collection $accounts = null,
?Collection $budgets = null, ?Collection $budgets = null,
?TransactionCurrency $currency = null ?TransactionCurrency $currency = null,
bool $convertToNative = false
): array; ): array;
} }

View File

@@ -444,7 +444,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
{ {
$piggyBank->piggyBankEvents()->delete(); $piggyBank->piggyBankEvents()->delete();
foreach ($piggyBank->accounts as $account) { foreach ($piggyBank->accounts as $account) {
if (0 !== bccomp('0', $account->pivot->current_amount)) { if (0 !== bccomp('0', (string) $account->pivot->current_amount)) {
event(new ChangedAmount($piggyBank, $account->pivot->current_amount, null, null)); event(new ChangedAmount($piggyBank, $account->pivot->current_amount, null, null));
} }
} }

View File

@@ -440,10 +440,12 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface,
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
foreach ($group->transactionJournals as $journal) { foreach ($group->transactionJournals as $journal) {
$names = sprintf('%s%s', $names, $journal->date->format('Y-m-d-H:i:s'));
/** @var Transaction $transaction */ /** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) { foreach ($journal->transactions as $transaction) {
if (-1 === bccomp('0', (string)$transaction->amount)) { if (-1 === bccomp('0', (string)$transaction->amount)) {
$sum = bcadd($sum, $transaction->amount); $sum = bcadd($sum, (string) $transaction->amount);
$names = sprintf('%s%s', $names, $transaction->account->name); $names = sprintf('%s%s', $names, $transaction->account->name);
} }
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Services\Internal\Support; namespace FireflyIII\Services\Internal\Support;
use Deprecated;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Enums\AccountTypeEnum; use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\DuplicateTransactionException; use FireflyIII\Exceptions\DuplicateTransactionException;
@@ -193,8 +194,8 @@ trait AccountServiceTrait
/** /**
* @throws FireflyException * @throws FireflyException
* * * *
* @deprecated
*/ */
#[Deprecated]
protected function createOBGroup(Account $account, array $data): TransactionGroup protected function createOBGroup(Account $account, array $data): TransactionGroup
{ {
app('log')->debug('Now going to create an OB group.'); app('log')->debug('Now going to create an OB group.');

View File

@@ -825,7 +825,13 @@ class JournalUpdateService
public function isCompareHashChanged(): bool public function isCompareHashChanged(): bool
{ {
Log::debug(sprintf('Now in %s', __METHOD__)); Log::debug(sprintf('Now in %s', __METHOD__));
$compareHash = $this->transactionGroupRepository->getCompareHash($this->transactionGroup); $compareHash = hash('sha256', sprintf('%s', Carbon::now()->getTimestamp()));
if (!$this->transactionGroup instanceof TransactionGroup) {
$compareHash = $this->transactionGroupRepository->getCompareHash($this->transactionJournal->transactionGroup);
}
if ($this->transactionGroup instanceof TransactionGroup) {
$this->transactionGroupRepository->getCompareHash($this->transactionGroup);
}
Log::debug(sprintf('Compare hash is "%s".', $compareHash)); Log::debug(sprintf('Compare hash is "%s".', $compareHash));
Log::debug(sprintf('Start compare hash is "%s".', $this->startCompareHash)); Log::debug(sprintf('Start compare hash is "%s".', $this->startCompareHash));

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Support; namespace FireflyIII\Support;
use Deprecated;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
@@ -31,6 +32,7 @@ use FireflyIII\Models\UserGroup;
use FireflyIII\Support\Facades\Preferences; use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use NumberFormatter; use NumberFormatter;
/** /**
@@ -65,13 +67,13 @@ class Amount
$fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $symbol); $fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $symbol);
$fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces); $fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $decimalPlaces);
$fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces); $fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimalPlaces);
$result = (string) $fmt->format((float) $rounded); // intentional float $result = (string)$fmt->format((float)$rounded); // intentional float
if (true === $coloured) { if (true === $coloured) {
if (1 === bccomp((string) $rounded, '0')) { if (1 === bccomp((string)$rounded, '0')) {
return sprintf('<span class="text-success money-positive">%s</span>', $result); return sprintf('<span class="text-success money-positive">%s</span>', $result);
} }
if (-1 === bccomp((string) $rounded, '0')) { if (-1 === bccomp((string)$rounded, '0')) {
return sprintf('<span class="text-danger money-negative">%s</span>', $result); return sprintf('<span class="text-danger money-negative">%s</span>', $result);
} }
@@ -105,23 +107,21 @@ class Amount
$amount = $journal[$field] ?? '0'; $amount = $journal[$field] ?? '0';
// Log::debug(sprintf('Field is %s, amount is %s', $field, $amount)); // Log::debug(sprintf('Field is %s, amount is %s', $field, $amount));
// fallback, the transaction has a foreign amount in $currency. // fallback, the transaction has a foreign amount in $currency.
if ($convertToNative && null !== $journal['foreign_amount'] && $currency->id === (int) $journal['foreign_currency_id']) { if ($convertToNative && null !== $journal['foreign_amount'] && $currency->id === (int)$journal['foreign_currency_id']) {
$amount = $journal['foreign_amount']; $amount = $journal['foreign_amount'];
// Log::debug(sprintf('Overruled, amount is now %s', $amount)); // Log::debug(sprintf('Overruled, amount is now %s', $amount));
} }
return (string) $amount; return (string)$amount;
} }
public function convertToNative(?User $user = null): bool public function convertToNative(?User $user = null): bool
{ {
if (!$user instanceof User) { if (!$user instanceof User) {
return true === Preferences::get('convert_to_native', false)->data && true === config('cer.enabled'); return true === Preferences::get('convert_to_native', false)->data && true === config('cer.enabled');
// Log::debug(sprintf('convertToNative [a]: %s', var_export($result, true)));
} }
return true === Preferences::getForUser($user, 'convert_to_native', false)->data && true === config('cer.enabled'); return true === Preferences::getForUser($user, 'convert_to_native', false)->data && true === config('cer.enabled');
// Log::debug(sprintf('convertToNative [b]: %s', var_export($result, true)));
} }
public function getNativeCurrency(): TransactionCurrency public function getNativeCurrency(): TransactionCurrency
@@ -179,9 +179,9 @@ class Amount
return '0'; return '0';
} }
$amount = $sourceTransaction->{$field} ?? '0'; $amount = $sourceTransaction->{$field} ?? '0';
if ((int) $sourceTransaction->foreign_currency_id === $currency->id) { if ((int)$sourceTransaction->foreign_currency_id === $currency->id) {
// use foreign amount instead! // use foreign amount instead!
$amount = (string) $sourceTransaction->foreign_amount; // hard coded to be foreign amount. $amount = (string)$sourceTransaction->foreign_amount; // hard coded to be foreign amount.
} }
return $amount; return $amount;
@@ -195,25 +195,19 @@ class Amount
return $user->currencies()->orderBy('code', 'ASC')->get(); return $user->currencies()->orderBy('code', 'ASC')->get();
} }
/** #[Deprecated]
* @deprecated
*/
public function getDefaultCurrency(): TransactionCurrency public function getDefaultCurrency(): TransactionCurrency
{ {
return $this->getNativeCurrency(); return $this->getNativeCurrency();
} }
/** #[Deprecated(message: 'use getDefaultCurrencyByUserGroup instead')]
* @deprecated use getDefaultCurrencyByUserGroup instead
*/
public function getDefaultCurrencyByUser(User $user): TransactionCurrency public function getDefaultCurrencyByUser(User $user): TransactionCurrency
{ {
return $this->getDefaultCurrencyByUserGroup($user->userGroup); return $this->getDefaultCurrencyByUserGroup($user->userGroup);
} }
/** #[Deprecated]
* @deprecated
*/
public function getDefaultCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency public function getDefaultCurrencyByUserGroup(UserGroup $userGroup): TransactionCurrency
{ {
return $this->getNativeCurrencyByUserGroup($userGroup); return $this->getNativeCurrencyByUserGroup($userGroup);

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Support\Authentication; namespace FireflyIII\Support\Authentication;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Auth\Guard;
@@ -86,14 +87,14 @@ class RemoteUserGuard implements Guard
if (null !== $header) { if (null !== $header) {
$emailAddress = (string) (request()->server($header) ?? apache_request_headers()[$header] ?? null); $emailAddress = (string) (request()->server($header) ?? apache_request_headers()[$header] ?? null);
$preference = app('preferences')->getForUser($retrievedUser, 'remote_guard_alt_email'); $preference = Preferences::getForUser($retrievedUser, 'remote_guard_alt_email');
if ('' !== $emailAddress && null === $preference && $emailAddress !== $userID) { if ('' !== $emailAddress && null === $preference && $emailAddress !== $userID) {
app('preferences')->setForUser($retrievedUser, 'remote_guard_alt_email', $emailAddress); Preferences::setForUser($retrievedUser, 'remote_guard_alt_email', $emailAddress);
} }
// if the pref isn't null and the object returned isn't null, update the email address. // if the pref isn't null and the object returned isn't null, update the email address.
if ('' !== $emailAddress && null !== $preference && $emailAddress !== $preference->data) { if ('' !== $emailAddress && null !== $preference && $emailAddress !== $preference->data) {
app('preferences')->setForUser($retrievedUser, 'remote_guard_alt_email', $emailAddress); Preferences::setForUser($retrievedUser, 'remote_guard_alt_email', $emailAddress);
} }
} }

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Support\Cronjobs;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Jobs\CreateAutoBudgetLimits; use FireflyIII\Jobs\CreateAutoBudgetLimits;
use FireflyIII\Models\Configuration; use FireflyIII\Models\Configuration;
use FireflyIII\Support\Facades\FireflyConfig;
/** /**
* Class AutoBudgetCronjob * Class AutoBudgetCronjob
@@ -36,7 +37,7 @@ class AutoBudgetCronjob extends AbstractCronjob
public function fire(): void public function fire(): void
{ {
/** @var Configuration $config */ /** @var Configuration $config */
$config = app('fireflyconfig')->get('last_ab_job', 0); $config = FireflyConfig::get('last_ab_job', 0);
$lastTime = (int) $config->data; $lastTime = (int) $config->data;
$diff = Carbon::now()->getTimestamp() - $lastTime; $diff = Carbon::now()->getTimestamp() - $lastTime;
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true); $diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
@@ -78,7 +79,7 @@ class AutoBudgetCronjob extends AbstractCronjob
$this->jobSucceeded = true; $this->jobSucceeded = true;
$this->message = 'Auto-budget cron job fired successfully.'; $this->message = 'Auto-budget cron job fired successfully.';
app('fireflyconfig')->set('last_ab_job', (int) $this->date->format('U')); FireflyConfig::set('last_ab_job', (int) $this->date->format('U'));
app('log')->info('Done with auto budget cron job task.'); app('log')->info('Done with auto budget cron job task.');
} }
} }

View File

@@ -50,9 +50,9 @@ class CurrencyForm
} }
/** /**
* @throws FireflyException
*
* @phpstan-param view-string $view * @phpstan-param view-string $view
*
* @throws FireflyException
*/ */
protected function currencyField(string $name, string $view, mixed $value = null, ?array $options = null): string protected function currencyField(string $name, string $view, mixed $value = null, ?array $options = null): string
{ {

View File

@@ -106,7 +106,7 @@ trait AugumentData
{ {
/** @var AccountRepositoryInterface $repository */ /** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$accounts = $repository->getAccountsByType([AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::CASH->value]); $accounts = $repository->getAccountsByType([AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::EXPENSE->value, AccountTypeEnum::CASH->value]);
$grouped = $accounts->groupBy('id')->toArray(); $grouped = $accounts->groupBy('id')->toArray();
$return = []; $return = [];
foreach ($accountIds as $combinedId) { foreach ($accountIds as $combinedId) {

View File

@@ -70,7 +70,7 @@ trait PeriodOverview
protected JournalRepositoryInterface $journalRepos; protected JournalRepositoryInterface $journalRepos;
/** /**
* This method returns "period entries", so nov-2015, dec-2015, etc etc (this depends on the users session range) * This method returns "period entries", so nov-2015, dec-2015, etc. (this depends on the users session range)
* and for each period, the amount of money spent and earned. This is a complex operation which is cached for * and for each period, the amount of money spent and earned. This is a complex operation which is cached for
* performance reasons. * performance reasons.
* *
@@ -97,18 +97,26 @@ trait PeriodOverview
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = []; $entries = [];
$spent = [];
$earned = [];
$transferredAway = [];
$transferredIn = [];
// run a custom query because doing this with the collector is MEGA slow. // run a custom query because doing this with the collector is MEGA slow.
$transactions = $this->accountRepository->periodCollection($account, $start, $end); $transactions = $this->accountRepository->periodCollection($account, $start, $end);
// loop dates // loop dates
Log::debug(sprintf('Count of loops: %d', count($dates))); Log::debug(sprintf('Count of loops: %d', count($dates)));
$loops = 0;
// stop after 10 loops for memory reasons.
foreach ($dates as $currentDate) { foreach ($dates as $currentDate) {
$title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']); $title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
if ($loops < 10) {
[$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']); [$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']);
[$transactions, $earned] = $this->filterTransactionsByType(TransactionTypeEnum::DEPOSIT, $transactions, $currentDate['start'], $currentDate['end']); [$transactions, $earned] = $this->filterTransactionsByType(TransactionTypeEnum::DEPOSIT, $transactions, $currentDate['start'], $currentDate['end']);
[$transactions, $transferredAway] = $this->filterTransfers('away', $transactions, $currentDate['start'], $currentDate['end']); [$transactions, $transferredAway] = $this->filterTransfers('away', $transactions, $currentDate['start'], $currentDate['end']);
[$transactions, $transferredIn] = $this->filterTransfers('in', $transactions, $currentDate['start'], $currentDate['end']); [$transactions, $transferredIn] = $this->filterTransfers('in', $transactions, $currentDate['start'], $currentDate['end']);
}
$entries[] $entries[]
= [ = [
'title' => $title, 'title' => $title,
@@ -119,6 +127,7 @@ trait PeriodOverview
'transferred_away' => $this->groupByCurrency($transferredAway), 'transferred_away' => $this->groupByCurrency($transferredAway),
'transferred_in' => $this->groupByCurrency($transferredIn), 'transferred_in' => $this->groupByCurrency($transferredIn),
]; ];
++$loops;
} }
$cache->store($entries); $cache->store($entries);
Timer::stop('account-period-total'); Timer::stop('account-period-total');
@@ -548,18 +557,19 @@ trait PeriodOverview
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = app('navigation')->blockPeriods($start, $end, $range);
$entries = []; $entries = [];
$spent = [];
$earned = [];
$transferred = [];
// collect all journals in this period (regardless of type) // collect all journals in this period (regardless of type)
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setTypes($types)->setRange($start, $end); $collector->setTypes($types)->setRange($start, $end);
$genericSet = $collector->getExtractedJournals(); $genericSet = $collector->getExtractedJournals();
$loops = 0;
foreach ($dates as $currentDate) { foreach ($dates as $currentDate) {
$spent = [];
$earned = [];
$transferred = [];
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
if ($loops < 10) {
// set to correct array // set to correct array
if ('expenses' === $transactionType || 'withdrawal' === $transactionType) { if ('expenses' === $transactionType || 'withdrawal' === $transactionType) {
$spent = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']); $spent = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
@@ -570,6 +580,7 @@ trait PeriodOverview
if ('transfer' === $transactionType || 'transfers' === $transactionType) { if ('transfer' === $transactionType || 'transfers' === $transactionType) {
$transferred = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']); $transferred = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
} }
}
$entries[] $entries[]
= [ = [
'title' => $title, 'title' => $title,
@@ -579,6 +590,7 @@ trait PeriodOverview
'earned' => $this->groupByCurrency($earned), 'earned' => $this->groupByCurrency($earned),
'transferred' => $this->groupByCurrency($transferred), 'transferred' => $this->groupByCurrency($transferred),
]; ];
++$loops;
} }
return $entries; return $entries;

View File

@@ -34,7 +34,7 @@ use Illuminate\Contracts\Validation\Validator as ValidatorContract;
use Illuminate\Routing\Route; use Illuminate\Routing\Route;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Route as RouteFacade; use Illuminate\Support\Facades\Route as RouteFacade;
use Hash; use Illuminate\Support\Facades\Hash;
use function Safe\parse_url; use function Safe\parse_url;

View File

@@ -54,7 +54,7 @@ class TransactionGroupEnrichment implements EnrichmentInterface
private array $notes; // @phpstan-ignore-line private array $notes; // @phpstan-ignore-line
private array $tags; private array $tags;
private User $user; private User $user;
private TransactionCurrency $nativeCurrency; private readonly TransactionCurrency $nativeCurrency;
private UserGroup $userGroup; private UserGroup $userGroup;
public function __construct() public function __construct()
@@ -149,7 +149,9 @@ class TransactionGroupEnrichment implements EnrichmentInterface
continue; continue;
} }
if (in_array($name, $this->dateFields, true)) { if (in_array($name, $this->dateFields, true)) {
$this->metaData[$entry['transaction_journal_id']][$name] = Carbon::parse($data); Log::debug(sprintf('Meta data for "%s" is a date : "%s"', $name, $data));
$this->metaData[$entry['transaction_journal_id']][$name] = Carbon::parse($data, config('app.timezone'));
Log::debug(sprintf('Meta data for "%s" converts to: "%s"', $name, $this->metaData[$entry['transaction_journal_id']][$name]->toW3CString()));
continue; continue;
} }

View File

@@ -582,7 +582,7 @@ class Navigation
*/ */
public function preferredEndOfPeriod(Carbon $start, Carbon $end): string public function preferredEndOfPeriod(Carbon $start, Carbon $end): string
{ {
if ((int) $start->diffInMonths($end, true) > 1) { if ((int) $start->diffInMonths($end, true) > 1 && (int) $start->diffInMonths($end, true) <= 12) {
return 'endOfMonth'; return 'endOfMonth';
} }
@@ -599,7 +599,7 @@ class Navigation
*/ */
public function preferredRangeFormat(Carbon $start, Carbon $end): string public function preferredRangeFormat(Carbon $start, Carbon $end): string
{ {
if ((int) $start->diffInMonths($end, true) > 1) { if ((int) $start->diffInMonths($end, true) > 1 && (int) $start->diffInMonths($end, true) <= 12) {
return '1M'; return '1M';
} }
@@ -616,7 +616,7 @@ class Navigation
*/ */
public function preferredSqlFormat(Carbon $start, Carbon $end): string public function preferredSqlFormat(Carbon $start, Carbon $end): string
{ {
if ((int) $start->diffInMonths($end, true) > 1) { if ((int) $start->diffInMonths($end, true) > 1 && (int) $start->diffInMonths($end, true) <= 12) {
return '%Y-%m'; return '%Y-%m';
} }

View File

@@ -51,7 +51,7 @@ class TransactionSummarizer
public function groupByCurrencyId(array $journals, string $method = 'negative', bool $includeForeign = true): array public function groupByCurrencyId(array $journals, string $method = 'negative', bool $includeForeign = true): array
{ {
Log::debug(sprintf('Now in groupByCurrencyId([%d journals], "%s")', count($journals), $method)); Log::debug(sprintf('Now in groupByCurrencyId([%d journals], "%s", %s)', count($journals), $method, var_export($includeForeign, true)));
$array = []; $array = [];
foreach ($journals as $journal) { foreach ($journals as $journal) {
$field = 'amount'; $field = 'amount';
@@ -71,12 +71,12 @@ class TransactionSummarizer
$foreignCurrencyDecimalPlaces = null; $foreignCurrencyDecimalPlaces = null;
if ($this->convertToNative) { if ($this->convertToNative) {
Log::debug('convertToNative is true.'); // Log::debug('convertToNative is true.');
// if convert to native, use the native amount yes or no? // if convert to native, use the native amount yes or no?
$useNative = $this->default->id !== (int) $journal['currency_id']; $useNative = $this->default->id !== (int) $journal['currency_id'];
$useForeign = $this->default->id === (int) $journal['foreign_currency_id']; $useForeign = $this->default->id === (int) $journal['foreign_currency_id'];
if ($useNative) { if ($useNative) {
Log::debug(sprintf('Journal #%d switches to native amount (original is %s)', $journal['transaction_journal_id'], $journal['currency_code'])); // Log::debug(sprintf('Journal #%d switches to native amount (original is %s)', $journal['transaction_journal_id'], $journal['currency_code']));
$field = 'native_amount'; $field = 'native_amount';
$currencyId = $this->default->id; $currencyId = $this->default->id;
$currencyName = $this->default->name; $currencyName = $this->default->name;
@@ -85,7 +85,7 @@ class TransactionSummarizer
$currencyDecimalPlaces = $this->default->decimal_places; $currencyDecimalPlaces = $this->default->decimal_places;
} }
if ($useForeign) { if ($useForeign) {
Log::debug(sprintf('Journal #%d switches to foreign amount (foreign is %s)', $journal['transaction_journal_id'], $journal['foreign_currency_code'])); // Log::debug(sprintf('Journal #%d switches to foreign amount (foreign is %s)', $journal['transaction_journal_id'], $journal['foreign_currency_code']));
$field = 'foreign_amount'; $field = 'foreign_amount';
$currencyId = (int) $journal['foreign_currency_id']; $currencyId = (int) $journal['foreign_currency_id'];
$currencyName = $journal['foreign_currency_name']; $currencyName = $journal['foreign_currency_name'];
@@ -95,7 +95,7 @@ class TransactionSummarizer
} }
} }
if (!$this->convertToNative) { if (!$this->convertToNative) {
Log::debug('convertToNative is false.'); // Log::debug('convertToNative is false.');
// use foreign amount? // use foreign amount?
$foreignCurrencyId = (int) $journal['foreign_currency_id']; $foreignCurrencyId = (int) $journal['foreign_currency_id'];
if (0 !== $foreignCurrencyId) { if (0 !== $foreignCurrencyId) {

View File

@@ -257,16 +257,16 @@ trait ConvertsDataTypes
try { try {
$carbon = Carbon::createFromFormat('Y-m-d', $value); $carbon = Carbon::createFromFormat('Y-m-d', $value);
} catch (InvalidDateException $e) { // @phpstan-ignore-line } catch (InvalidDateException $e) { // @phpstan-ignore-line
app('log')->error(sprintf('[1] "%s" is not a valid date: %s', $value, $e->getMessage())); Log::error(sprintf('[1] "%s" is not a valid date: %s', $value, $e->getMessage()));
return null; return null;
} catch (InvalidFormatException $e) { // @phpstan-ignore-line } catch (InvalidFormatException $e) { // @phpstan-ignore-line
app('log')->error(sprintf('[2] "%s" is of an invalid format: %s', $value, $e->getMessage())); Log::error(sprintf('[2] "%s" is of an invalid format: %s', $value, $e->getMessage()));
return null; return null;
} }
if (!$carbon instanceof Carbon) { if (!$carbon instanceof Carbon) {
app('log')->error(sprintf('[2] "%s" is of an invalid format.', $value)); Log::error(sprintf('[2] "%s" is of an invalid format.', $value));
return null; return null;
} }
@@ -278,11 +278,11 @@ trait ConvertsDataTypes
try { try {
$carbon = Carbon::parse($value); $carbon = Carbon::parse($value);
} catch (InvalidDateException $e) { // @phpstan-ignore-line } catch (InvalidDateException $e) { // @phpstan-ignore-line
app('log')->error(sprintf('[3] "%s" is not a valid date or time: %s', $value, $e->getMessage())); Log::error(sprintf('[3] "%s" is not a valid date or time: %s', $value, $e->getMessage()));
return null; return null;
} catch (InvalidFormatException $e) { } catch (InvalidFormatException $e) {
app('log')->error(sprintf('[4] "%s" is of an invalid format: %s', $value, $e->getMessage())); Log::error(sprintf('[4] "%s" is of an invalid format: %s', $value, $e->getMessage()));
return null; return null;
} }
@@ -306,6 +306,7 @@ trait ConvertsDataTypes
protected function dateFromValue(?string $string): ?Carbon protected function dateFromValue(?string $string): ?Carbon
{ {
if (null === $string) { if (null === $string) {
return null; return null;
} }
if ('' === $string) { if ('' === $string) {
@@ -319,11 +320,11 @@ trait ConvertsDataTypes
// @ignoreException // @ignoreException
} }
if (!$carbon instanceof Carbon) { if (!$carbon instanceof Carbon) {
app('log')->debug(sprintf('Invalid date: %s', $string)); Log::debug(sprintf('Invalid date: %s', $string));
return null; return null;
} }
app('log')->debug(sprintf('Date object: %s (%s)', $carbon->toW3cString(), $carbon->getTimezone())); Log::debug(sprintf('Date object: %s (%s) from "%s"', $carbon->toW3cString(), $carbon->getTimezone(), $string));
return $carbon; return $carbon;
} }
@@ -383,7 +384,7 @@ trait ConvertsDataTypes
Log::debug(sprintf('Exception when parsing date "%s".', $this->get($field))); Log::debug(sprintf('Exception when parsing date "%s".', $this->get($field)));
} }
if (!$result instanceof Carbon) { if (!$result instanceof Carbon) {
app('log')->debug(sprintf('Exception when parsing date "%s".', $this->get($field))); Log::debug(sprintf('Exception when parsing date "%s".', $this->get($field)));
} }
return $result; return $result;

File diff suppressed because it is too large Load Diff

View File

@@ -93,7 +93,7 @@ class Steam
return []; return [];
} }
$defaultCurrency = app('amount')->getNativeCurrency(); $defaultCurrency = Amount::getNativeCurrency();
if ($convertToNative) { if ($convertToNative) {
if ($defaultCurrency->id === $currency?->id) { if ($defaultCurrency->id === $currency?->id) {
Log::debug(sprintf('Unset [%s] for account #%d (no longer unset "native_balance")', $defaultCurrency->code, $account->id)); Log::debug(sprintf('Unset [%s] for account #%d (no longer unset "native_balance")', $defaultCurrency->code, $account->id));
@@ -224,7 +224,7 @@ class Steam
$request->subDay()->endOfDay(); $request->subDay()->endOfDay();
Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String())); Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String()));
$startBalance = $this->finalAccountBalance($account, $request); $startBalance = $this->finalAccountBalance($account, $request);
$nativeCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup); $nativeCurrency = Amount::getNativeCurrencyByUserGroup($account->user->userGroup);
$accountCurrency = $this->getAccountCurrency($account); $accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = $accountCurrency instanceof TransactionCurrency; $hasCurrency = $accountCurrency instanceof TransactionCurrency;
$currency = $accountCurrency ?? $nativeCurrency; $currency = $accountCurrency ?? $nativeCurrency;
@@ -294,7 +294,7 @@ class Steam
$currentBalance[$entryCurrency->code] ??= '0'; $currentBalance[$entryCurrency->code] ??= '0';
$currentBalance[$entryCurrency->code] = bcadd($sumOfDay, (string) $currentBalance[$entryCurrency->code]); $currentBalance[$entryCurrency->code] = bcadd($sumOfDay, (string) $currentBalance[$entryCurrency->code]);
// if not convert to native, add the amount to "balance", do nothing else. // if not requested to convert to native, add the amount to "balance", do nothing else.
if (!$convertToNative) { if (!$convertToNative) {
$currentBalance['balance'] = bcadd((string) $currentBalance['balance'], $sumOfDay); $currentBalance['balance'] = bcadd((string) $currentBalance['balance'], $sumOfDay);
} }
@@ -302,13 +302,13 @@ class Steam
// if there is a request to convert, convert to "native_balance" and use "balance" for whichever amount is in the native currency. // if there is a request to convert, convert to "native_balance" and use "balance" for whichever amount is in the native currency.
if ($convertToNative) { if ($convertToNative) {
$nativeSumOfDay = $converter->convert($entryCurrency, $nativeCurrency, $carbon, $sumOfDay); $nativeSumOfDay = $converter->convert($entryCurrency, $nativeCurrency, $carbon, $sumOfDay);
$currentBalance['native_balance'] = bcadd((string) $currentBalance['native_balance'], $nativeSumOfDay); $currentBalance['native_balance'] = bcadd((string) ($currentBalance['native_balance'] ?? '0'), $nativeSumOfDay);
// if it's the same currency as the entry, also add to balance (see other code).
if ($currency->id === $entryCurrency->id) { if ($currency->id === $entryCurrency->id) {
$currentBalance['balance'] = bcadd((string) $currentBalance['balance'], $sumOfDay); $currentBalance['balance'] = bcadd((string) $currentBalance['balance'], $sumOfDay);
} }
} }
// just set it. // add to final array.
$balances[$carbonKey] = $currentBalance; $balances[$carbonKey] = $currentBalance;
Log::debug(sprintf('Updated entry [%s]', $carbonKey), $currentBalance); Log::debug(sprintf('Updated entry [%s]', $carbonKey), $currentBalance);
} }
@@ -342,7 +342,7 @@ class Steam
return $cache->get(); return $cache->get();
} }
Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s'))); // Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
if (null === $convertToNative) { if (null === $convertToNative) {
$convertToNative = Amount::convertToNative($account->user); $convertToNative = Amount::convertToNative($account->user);
} }
@@ -401,7 +401,7 @@ class Steam
// Log::debug(sprintf('Virtual balance makes the (native) total %s', $return['balance'])); // Log::debug(sprintf('Virtual balance makes the (native) total %s', $return['balance']));
} }
$final = array_merge($return, $others); $final = array_merge($return, $others);
Log::debug('Final balance is', $final); // Log::debug('Final balance is', $final);
$cache->store($final); $cache->store($final);
return $final; return $final;

View File

@@ -28,6 +28,7 @@ use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\TransactionRules\Traits\RefreshNotesTrait; use FireflyIII\TransactionRules\Traits\RefreshNotesTrait;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/** /**
* Class SetDescription. * Class SetDescription.
@@ -51,7 +52,12 @@ class SetDescription implements ActionInterface
$after = $this->action->getValue($journal); $after = $this->action->getValue($journal);
// replace newlines. // replace newlines.
$after = str_replace(["\r", "\n", "\t", "\036", "\025"], '', $after); $after = trim(str_replace(["\r", "\n", "\t", "\036", "\025"], '', $after));
if ('' === $after) {
Log::warning('Action resulted in an empty description, reset to default value.');
$after = '(no description)';
}
DB::table('transaction_journals') DB::table('transaction_journals')
->where('id', '=', $journal['transaction_journal_id']) ->where('id', '=', $journal['transaction_journal_id'])

View File

@@ -67,8 +67,8 @@ class AccountTransformer extends AbstractTransformer
} }
// get account type: // get account type:
$accountType = (string) config(sprintf('firefly.shortNamesByFullName.%s', $account->full_account_type)); $accountType = (string)config(sprintf('firefly.shortNamesByFullName.%s', $account->full_account_type));
$liabilityType = (string) config(sprintf('firefly.shortLiabilityNameByFullName.%s', $account->full_account_type)); $liabilityType = (string)config(sprintf('firefly.shortLiabilityNameByFullName.%s', $account->full_account_type));
$liabilityType = '' === $liabilityType ? null : strtolower($liabilityType); $liabilityType = '' === $liabilityType ? null : strtolower($liabilityType);
$liabilityDirection = $account->meta['liability_direction'] ?? null; $liabilityDirection = $account->meta['liability_direction'] ?? null;
@@ -89,10 +89,10 @@ class AccountTransformer extends AbstractTransformer
$native = null; $native = null;
} }
$decimalPlaces = (int) $account->meta['currency']?->decimal_places; $decimalPlaces = (int)$account->meta['currency']?->decimal_places;
$decimalPlaces = 0 === $decimalPlaces ? 2 : $decimalPlaces; $decimalPlaces = 0 === $decimalPlaces ? 2 : $decimalPlaces;
$openingBalance = Steam::bcround($openingBalance, $decimalPlaces); $openingBalanceRounded = Steam::bcround($openingBalance, $decimalPlaces);
$includeNetWorth = 1 === (int) ($account->meta['include_net_worth'] ?? 0); $includeNetWorth = 1 === (int)($account->meta['include_net_worth'] ?? 0);
$longitude = $account->meta['location']['longitude'] ?? null; $longitude = $account->meta['location']['longitude'] ?? null;
$latitude = $account->meta['location']['latitude'] ?? null; $latitude = $account->meta['location']['latitude'] ?? null;
$zoomLevel = $account->meta['location']['zoom_level'] ?? null; $zoomLevel = $account->meta['location']['zoom_level'] ?? null;
@@ -112,8 +112,55 @@ class AccountTransformer extends AbstractTransformer
$currentBalance = Steam::bcround($finalBalance['balance'] ?? '0', $decimalPlaces); $currentBalance = Steam::bcround($finalBalance['balance'] ?? '0', $decimalPlaces);
$nativeCurrentBalance = $this->convertToNative ? Steam::bcround($finalBalance['native_balance'] ?? '0', $native->decimal_places) : null; $nativeCurrentBalance = $this->convertToNative ? Steam::bcround($finalBalance['native_balance'] ?? '0', $native->decimal_places) : null;
// set up balances array:
$balances = [];
$balances[]
= [
'type' => 'current',
'amount' => $currentBalance,
'currency_id' => $account->meta['currency_id'] ?? null,
'currency_code' => $account->meta['currency']?->code,
'currency_symbol' => $account->meta['currency']?->symbol,
'currency_decimal_places' => $account->meta['currency']?->decimal_places,
'date' => $date->toAtomString(),
];
if (null !== $nativeCurrentBalance) {
$balances[] = [
'type' => 'native_current',
'amount' => $nativeCurrentBalance,
'currency_id' => $native instanceof TransactionCurrency ? (string)$native->id : null,
'currency_code' => $native?->code,
'currency_symbol' => $native?->symbol,
'ccurrency_decimal_places' => $native?->decimal_places,
'date' => $date->toAtomString(),
];
}
if (null !== $openingBalance) {
$balances[] = [
'type' => 'opening',
'amount' => $openingBalanceRounded,
'currency_id' => $account->meta['currency_id'] ?? null,
'currency_code' => $account->meta['currency']?->code,
'currency_symbol' => $account->meta['currency']?->symbol,
'currency_decimal_places' => $account->meta['currency']?->decimal_places,
'date' => $openingBalanceDate,
];
}
if (null !== $account->virtual_balance) {
$balances[] = [
'type' => 'virtual',
'amount' => Steam::bcround($account->virtual_balance, $decimalPlaces),
'currency_id' => $account->meta['currency_id'] ?? null,
'currency_code' => $account->meta['currency']?->code,
'currency_symbol' => $account->meta['currency']?->symbol,
'currency_decimal_places' => $account->meta['currency']?->decimal_places,
'date' => $date->toAtomString(),
];
}
return [ return [
'id' => (string) $account->id, 'id' => (string)$account->id,
'created_at' => $account->created_at->toAtomString(), 'created_at' => $account->created_at->toAtomString(),
'updated_at' => $account->updated_at->toAtomString(), 'updated_at' => $account->updated_at->toAtomString(),
'active' => $account->active, 'active' => $account->active,
@@ -125,7 +172,7 @@ class AccountTransformer extends AbstractTransformer
'currency_code' => $account->meta['currency']?->code, 'currency_code' => $account->meta['currency']?->code,
'currency_symbol' => $account->meta['currency']?->symbol, 'currency_symbol' => $account->meta['currency']?->symbol,
'currency_decimal_places' => $account->meta['currency']?->decimal_places, 'currency_decimal_places' => $account->meta['currency']?->decimal_places,
'native_currency_id' => $native instanceof TransactionCurrency ? (string) $native->id : null, 'native_currency_id' => $native instanceof TransactionCurrency ? (string)$native->id : null,
'native_currency_code' => $native?->code, 'native_currency_code' => $native?->code,
'native_currency_symbol' => $native?->symbol, 'native_currency_symbol' => $native?->symbol,
'native_currency_decimal_places' => $native?->decimal_places, 'native_currency_decimal_places' => $native?->decimal_places,
@@ -140,7 +187,7 @@ class AccountTransformer extends AbstractTransformer
'bic' => $account->meta['BIC'] ?? null, 'bic' => $account->meta['BIC'] ?? null,
'virtual_balance' => Steam::bcround($account->virtual_balance, $decimalPlaces), 'virtual_balance' => Steam::bcround($account->virtual_balance, $decimalPlaces),
'native_virtual_balance' => $this->convertToNative ? Steam::bcround($account->native_virtual_balance, $native->decimal_places) : null, 'native_virtual_balance' => $this->convertToNative ? Steam::bcround($account->native_virtual_balance, $native->decimal_places) : null,
'opening_balance' => $openingBalance, 'opening_balance' => $openingBalanceRounded,
'native_opening_balance' => $nativeOpeningBalance, 'native_opening_balance' => $nativeOpeningBalance,
'opening_balance_date' => $openingBalanceDate, 'opening_balance_date' => $openingBalanceDate,
'liability_type' => $liabilityType, 'liability_type' => $liabilityType,
@@ -153,6 +200,7 @@ class AccountTransformer extends AbstractTransformer
'latitude' => $latitude, 'latitude' => $latitude,
'zoom_level' => $zoomLevel, 'zoom_level' => $zoomLevel,
'last_activity' => array_key_exists('last_activity', $account->meta) ? $account->meta['last_activity']->toAtomString() : null, 'last_activity' => array_key_exists('last_activity', $account->meta) ? $account->meta['last_activity']->toAtomString() : null,
'balances' => $balances,
'links' => [ 'links' => [
[ [
'rel' => 'self', 'rel' => 'self',
@@ -165,7 +213,7 @@ class AccountTransformer extends AbstractTransformer
private function getAccountRole(Account $account, string $accountType): ?string private function getAccountRole(Account $account, string $accountType): ?string
{ {
$accountRole = $account->meta['account_role'] ?? null; $accountRole = $account->meta['account_role'] ?? null;
if ('asset' !== $accountType || '' === (string) $accountRole) { if ('asset' !== $accountType || '' === (string)$accountRole) {
return null; return null;
} }
@@ -201,7 +249,7 @@ class AccountTransformer extends AbstractTransformer
} }
$monthlyPaymentDate = $object->toAtomString(); $monthlyPaymentDate = $object->toAtomString();
} }
if (10 !== strlen((string) $monthlyPaymentDate)) { if (10 !== strlen((string)$monthlyPaymentDate)) {
$monthlyPaymentDate = Carbon::parse($monthlyPaymentDate, config('app.timezone'))->toAtomString(); $monthlyPaymentDate = Carbon::parse($monthlyPaymentDate, config('app.timezone'))->toAtomString();
} }
} }

View File

@@ -32,8 +32,10 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Models\BillDateCalculator; use FireflyIII\Support\Models\BillDateCalculator;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/** /**
* Class BillTransformer * Class BillTransformer
@@ -150,11 +152,11 @@ class BillTransformer extends AbstractTransformer
'id' => $bill->id, 'id' => $bill->id,
'created_at' => $bill->created_at->toAtomString(), 'created_at' => $bill->created_at->toAtomString(),
'updated_at' => $bill->updated_at->toAtomString(), 'updated_at' => $bill->updated_at->toAtomString(),
'currency_id' => (string) $bill->transaction_currency_id, 'currency_id' => (string)$bill->transaction_currency_id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
'native_currency_id' => null === $default ? null : (string) $default->id, 'native_currency_id' => null === $default ? null : (string)$default->id,
'native_currency_code' => $default?->code, 'native_currency_code' => $default?->code,
'native_currency_symbol' => $default?->symbol, 'native_currency_symbol' => $default?->symbol,
'native_currency_decimal_places' => $default?->decimal_places, 'native_currency_decimal_places' => $default?->decimal_places,
@@ -171,7 +173,7 @@ class BillTransformer extends AbstractTransformer
'active' => $bill->active, 'active' => $bill->active,
'order' => $bill->order, 'order' => $bill->order,
'notes' => $notes, 'notes' => $notes,
'object_group_id' => null !== $objectGroupId ? (string) $objectGroupId : null, 'object_group_id' => null !== $objectGroupId ? (string)$objectGroupId : null,
'object_group_order' => $objectGroupOrder, 'object_group_order' => $objectGroupOrder,
'object_group_title' => $objectGroupTitle, 'object_group_title' => $objectGroupTitle,
@@ -194,9 +196,9 @@ class BillTransformer extends AbstractTransformer
*/ */
protected function paidData(Bill $bill): array protected function paidData(Bill $bill): array
{ {
app('log')->debug(sprintf('Now in paidData for bill #%d', $bill->id)); Log::debug(sprintf('Now in paidData for bill #%d', $bill->id));
if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) { if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) {
app('log')->debug('parameters are NULL, return empty array'); Log::debug('parameters are NULL, return empty array');
return []; return [];
} }
@@ -217,27 +219,40 @@ class BillTransformer extends AbstractTransformer
$searchStart->startOfDay(); $searchStart->startOfDay();
$searchEnd->endOfDay(); $searchEnd->endOfDay();
app('log')->debug(sprintf('Parameters are start: %s end: %s', $start->format('Y-m-d'), $end->format('Y-m-d'))); Log::debug(sprintf('Parameters are start: %s end: %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
app('log')->debug(sprintf('Search parameters are: start: %s', $searchStart->format('Y-m-d'))); Log::debug(sprintf('Search parameters are: start: %s', $searchStart->format('Y-m-d')));
// Get from database when bill was paid. // Get from database when bill was paid.
$set = $this->repository->getPaidDatesInRange($bill, $searchStart, $searchEnd); $set = $this->repository->getPaidDatesInRange($bill, $searchStart, $searchEnd);
app('log')->debug(sprintf('Count %d entries in getPaidDatesInRange()', $set->count())); Log::debug(sprintf('Count %d entries in getPaidDatesInRange()', $set->count()));
// Grab from array the most recent payment. If none exist, fall back to the start date and pretend *that* was the last paid date. // Grab from array the most recent payment. If none exist, fall back to the start date and pretend *that* was the last paid date.
app('log')->debug(sprintf('Grab last paid date from function, return %s if it comes up with nothing.', $start->format('Y-m-d'))); Log::debug(sprintf('Grab last paid date from function, return %s if it comes up with nothing.', $start->format('Y-m-d')));
$lastPaidDate = $this->lastPaidDate($set, $start); $lastPaidDate = $this->lastPaidDate($set, $start);
app('log')->debug(sprintf('Result of lastPaidDate is %s', $lastPaidDate->format('Y-m-d'))); Log::debug(sprintf('Result of lastPaidDate is %s', $lastPaidDate->format('Y-m-d')));
// At this point the "next match" is exactly after the last time the bill was paid. // At this point the "next match" is exactly after the last time the bill was paid.
$result = []; $result = [];
foreach ($set as $entry) { foreach ($set as $entry) {
$result[] = [ $array = [
'transaction_group_id' => (string) $entry->transaction_group_id, 'transaction_group_id' => (string)$entry->transaction_group_id,
'transaction_journal_id' => (string) $entry->id, 'transaction_journal_id' => (string)$entry->id,
'date' => $entry->date->format('Y-m-d'), 'date' => $entry->date->format('Y-m-d'),
'date_object' => $entry->date, 'date_object' => $entry->date,
'currency_id' => $entry->transaction_currency_id,
'currency_code' => $entry->transaction_currency_code,
'currency_decimal_places' => $entry->transaction_currency_decimal_places,
'amount' => Steam::bcround($entry->amount, $entry->transaction_currency_decimal_places),
]; ];
if (null !== $entry->foreign_amount && null !== $entry->foreign_currency_code) {
$array['foreign_currency_id'] = $entry->foreign_currency_id;
$array['foreign_currency_code'] = $entry->foreign_currency_code;
$array['foreign_currency_decimal_places'] = $entry->foreign_currency_decimal_places;
$array['foreign_amount'] = Steam::bcround($entry->foreign_amount, $entry->foreign_currency_decimal_places);
}
$result[] = $array;
} }
return $result; return $result;
@@ -265,7 +280,7 @@ class BillTransformer extends AbstractTransformer
private function getLastPaidDate(array $paidData): ?Carbon private function getLastPaidDate(array $paidData): ?Carbon
{ {
app('log')->debug('getLastPaidDate()'); Log::debug('getLastPaidDate()');
$return = null; $return = null;
foreach ($paidData as $entry) { foreach ($paidData as $entry) {
if (null !== $return) { if (null !== $return) {
@@ -274,15 +289,15 @@ class BillTransformer extends AbstractTransformer
if ($current->gt($return)) { if ($current->gt($return)) {
$return = clone $current; $return = clone $current;
} }
app('log')->debug(sprintf('Last paid date is: %s', $return->format('Y-m-d'))); Log::debug(sprintf('Last paid date is: %s', $return->format('Y-m-d')));
} }
if (null === $return) { if (null === $return) {
/** @var Carbon $return */ /** @var Carbon $return */
$return = $entry['date_object']; $return = $entry['date_object'];
app('log')->debug(sprintf('Last paid date is: %s', $return->format('Y-m-d'))); Log::debug(sprintf('Last paid date is: %s', $return->format('Y-m-d')));
} }
} }
app('log')->debug(sprintf('Last paid date is: "%s"', $return?->format('Y-m-d'))); Log::debug(sprintf('Last paid date is: "%s"', $return?->format('Y-m-d')));
return $return; return $return;
} }

View File

@@ -121,6 +121,15 @@ class TransactionGroupTransformer extends AbstractTransformer
if (null !== $transaction['foreign_amount'] && '' !== $transaction['foreign_amount'] && 0 !== bccomp('0', (string) $transaction['foreign_amount'])) { if (null !== $transaction['foreign_amount'] && '' !== $transaction['foreign_amount'] && 0 !== bccomp('0', (string) $transaction['foreign_amount'])) {
$foreignAmount = app('steam')->positive($transaction['foreign_amount']); $foreignAmount = app('steam')->positive($transaction['foreign_amount']);
} }
// set native amount to the normal amount if the currency matches.
if ($transaction['native_currency']['id'] ?? null === $transaction['currency_id']) {
$transaction['native_amount'] = $amount;
}
if (array_key_exists('native_amount', $transaction) && null !== $transaction['native_amount']) {
$transaction['native_amount'] = app('steam')->positive($transaction['native_amount']);
}
$type = $this->stringFromArray($transaction, 'transaction_type_type', TransactionTypeEnum::WITHDRAWAL->value); $type = $this->stringFromArray($transaction, 'transaction_type_type', TransactionTypeEnum::WITHDRAWAL->value);
// must be 0 (int) or NULL // must be 0 (int) or NULL
@@ -220,12 +229,12 @@ class TransactionGroupTransformer extends AbstractTransformer
'sepa_ci' => $transaction['meta']['sepa_ci'] ?? null, 'sepa_ci' => $transaction['meta']['sepa_ci'] ?? null,
'sepa_batch_id' => $transaction['meta']['sepa_batch_id'] ?? null, 'sepa_batch_id' => $transaction['meta']['sepa_batch_id'] ?? null,
'interest_date' => $transaction['meta_date']['interest_date'] ?? null, 'interest_date' => array_key_exists('interest_date', $transaction['meta_date']) ? $transaction['meta_date']['interest_date']->toW3CString() : null,
'book_date' => $transaction['meta_date']['book_date'] ?? null, 'book_date' => array_key_exists('book_date', $transaction['meta_date']) ? $transaction['meta_date']['book_date']->toW3CString() : null,
'process_date' => $transaction['meta_date']['process_date'] ?? null, 'process_date' => array_key_exists('process_date', $transaction['meta_date']) ? $transaction['meta_date']['process_date']->toW3CString() : null,
'due_date' => $transaction['meta_date']['due_date'] ?? null, 'due_date' => array_key_exists('due_date', $transaction['meta_date']) ? $transaction['meta_date']['due_date']->toW3CString() : null,
'payment_date' => $transaction['meta_date']['payment_date'] ?? null, 'payment_date' => array_key_exists('payment_date', $transaction['meta_date']) ? $transaction['meta_date']['payment_date']->toW3CString() : null,
'invoice_date' => $transaction['meta_date']['invoice_date'] ?? null, 'invoice_date' => array_key_exists('invoice_date', $transaction['meta_date']) ? $transaction['meta_date']['invoice_date']->toW3CString() : null,
// location data // location data
'longitude' => $transaction['location']['longitude'], 'longitude' => $transaction['location']['longitude'],
'latitude' => $transaction['location']['latitude'], 'latitude' => $transaction['location']['latitude'],

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII; namespace FireflyIII;
use Deprecated;
use FireflyIII\Enums\UserRoleEnum; use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Events\RequestedNewPassword; use FireflyIII\Events\RequestedNewPassword;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
@@ -188,9 +189,8 @@ class User extends Authenticatable
* Get the models LDAP domain. * Get the models LDAP domain.
* *
* @return string * @return string
*
* @deprecated
*/ */
#[Deprecated]
public function getLdapDomain() public function getLdapDomain()
{ {
return $this->{$this->getLdapDomainColumn()}; return $this->{$this->getLdapDomainColumn()};
@@ -200,9 +200,8 @@ class User extends Authenticatable
* Get the database column name of the domain. * Get the database column name of the domain.
* *
* @return string * @return string
*
* @deprecated
*/ */
#[Deprecated]
public function getLdapDomainColumn() public function getLdapDomainColumn()
{ {
return 'domain'; return 'domain';
@@ -212,9 +211,8 @@ class User extends Authenticatable
* Get the models LDAP GUID. * Get the models LDAP GUID.
* *
* @return string * @return string
*
* @deprecated
*/ */
#[Deprecated]
public function getLdapGuid() public function getLdapGuid()
{ {
return $this->{$this->getLdapGuidColumn()}; return $this->{$this->getLdapGuidColumn()};
@@ -224,9 +222,8 @@ class User extends Authenticatable
* Get the models LDAP GUID database column name. * Get the models LDAP GUID database column name.
* *
* @return string * @return string
*
* @deprecated
*/ */
#[Deprecated]
public function getLdapGuidColumn() public function getLdapGuidColumn()
{ {
return 'objectguid'; return 'objectguid';
@@ -468,9 +465,8 @@ class User extends Authenticatable
* Set the models LDAP domain. * Set the models LDAP domain.
* *
* @param string $domain * @param string $domain
*
* @deprecated
*/ */
#[Deprecated]
public function setLdapDomain($domain): void public function setLdapDomain($domain): void
{ {
$this->{$this->getLdapDomainColumn()} = $domain; $this->{$this->getLdapDomainColumn()} = $domain;
@@ -480,9 +476,8 @@ class User extends Authenticatable
* Set the models LDAP GUID. * Set the models LDAP GUID.
* *
* @param string $guid * @param string $guid
*
* @deprecated
*/ */
#[Deprecated]
public function setLdapGuid($guid): void public function setLdapGuid($guid): void
{ {
$this->{$this->getLdapGuidColumn()} = $guid; $this->{$this->getLdapGuidColumn()} = $guid;

View File

@@ -3,6 +3,66 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
## 6.2.21 - 2025-07-18
### Added
- Debug information to search engine.
### Changed
- Rename table field for postgres databases.
### Fixed
- [Issue 10581](https://github.com/firefly-iii/firefly-iii/issues/10581) (Epoch doesn't fit in a PHP integer error on 32-bit systems due to strict date validation) reported by @kksandr7
- [Discussion 10601](https://github.com/orgs/firefly-iii/discussions/10601) (Edit a transaction will result in an incorrect date) started by @MasterZhang007
## 6.2.20 - 2025-07-02
### Changed
- New query parser is now the default.
### Fixed
- [Issue 10517](https://github.com/firefly-iii/firefly-iii/issues/10517) (401 when trying to create personal access token with Remote user authentication) reported by @MaxPelly
- [Discussion 10530](https://github.com/orgs/firefly-iii/discussions/10530) (Find and delete transactions with empty descriptions) started by @umfk
- [Issue 10535](https://github.com/firefly-iii/firefly-iii/issues/10535) (Internal Firefly III Exception: Undefined array key "currency") reported by @MaelFr
## 6.2.19 - 2025-06-29
### Changed
- Currency seeder adds "CNY" again, because it turns out "RMB" is not the official, ISO 4217 code for the Chinese Yuan.
- The "period overview" next to the transaction lists (withdrawals, deposits and transfers) is limited to 10 entries because it uses a lot of memory. I still have to fix this.
### Removed
- Support for ntfy, since the underlying library is no longer maintained. Will be replaced in the future.
### Fixed
- Running balance calculation also triggers on edit.
- [Issue 10489](https://github.com/firefly-iii/firefly-iii/issues/10489) (Cannot create personal access token if using remote guard auth in latest version) reported by @Palomox
- [Issue 10493](https://github.com/firefly-iii/firefly-iii/issues/10493) (Reports First Graph Wrong) reported by @nicolopozzato
- [Issue 10499](https://github.com/firefly-iii/firefly-iii/issues/10499) (Password change results in error 500 (Class "Hash" not found)) reported by @willermo
- [Issue 10507](https://github.com/firefly-iii/firefly-iii/issues/10507) (Opening balance transactions includes in `has_no_category` filter) reported by @lompi
- [Issue 10510](https://github.com/firefly-iii/firefly-iii/issues/10510) (Liability accounts show as 'no name' on budget transaction report pie chart.) reported by @slackspace-io
## 6.2.18 - 2025-06-20
### Changed
- Give more details about OAuth errors.
- Currency seeder adds "RMB" instead of "CNY" for Chinese Yuan.
### Fixed
- [Issue 10454](https://github.com/firefly-iii/firefly-iii/issues/10454) (Bulk edit individually give an error) reported by @Rick45
- [Issue 10470](https://github.com/firefly-iii/firefly-iii/issues/10470) (API endpoint `/api/v1/chart/account/overview` throws error) reported by @dreautall
- Remove some leftover debug info
## 6.2.17 - 2025-06-12 ## 6.2.17 - 2025-06-12
### Changed ### Changed

512
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -78,9 +78,10 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false), 'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag. // see cer.php for exchange rates feature flag.
], ],
'version' => 'develop/2025-06-11', 'version' => 'develop/2025-07-28',
'build_time' => 1753673705,
'api_version' => '2.1.0', // field is no longer used. 'api_version' => '2.1.0', // field is no longer used.
'db_version' => 25, 'db_version' => 26,
// generic settings // generic settings
'maxUploadSize' => 1073741824, // 1 GB 'maxUploadSize' => 1073741824, // 1 GB

View File

@@ -26,7 +26,7 @@ return [
'channels' => [ 'channels' => [
'email' => ['enabled' => true, 'ui_configurable' => 0], 'email' => ['enabled' => true, 'ui_configurable' => 0],
'slack' => ['enabled' => true, 'ui_configurable' => 1], 'slack' => ['enabled' => true, 'ui_configurable' => 1],
'ntfy' => ['enabled' => false, 'ui_configurable' => 1], // 'ntfy' => ['enabled' => false, 'ui_configurable' => 1],
'pushover' => ['enabled' => true, 'ui_configurable' => 1], 'pushover' => ['enabled' => true, 'ui_configurable' => 1],
// 'gotify' => ['enabled' => false, 'ui_configurable' => 0], // 'gotify' => ['enabled' => false, 'ui_configurable' => 0],
// 'pushbullet' => ['enabled' => false, 'ui_configurable' => 0], // 'pushbullet' => ['enabled' => false, 'ui_configurable' => 0],

View File

@@ -260,8 +260,6 @@ return [
'destination_balance_lt' => ['alias' => false, 'needs_context' => true], 'destination_balance_lt' => ['alias' => false, 'needs_context' => true],
'destination_balance_is' => ['alias' => false, 'needs_context' => true], 'destination_balance_is' => ['alias' => false, 'needs_context' => true],
], ],
/** // Which query parser to use - 'new' or 'legacy'
* Which query parser to use - 'new' or 'legacy'
*/
'query_parser' => env('QUERY_PARSER_IMPLEMENTATION', 'legacy'), 'query_parser' => env('QUERY_PARSER_IMPLEMENTATION', 'legacy'),
]; ];

View File

@@ -65,6 +65,7 @@ return [
'interest_calc_half-year', 'interest_calc_half-year',
'interest_calc_quarterly', 'interest_calc_quarterly',
'spent', 'spent',
'budgeted',
'administration_owner', 'administration_owner',
'administration_you', 'administration_you',
'administration_role_owner', 'administration_role_owner',

View File

@@ -0,0 +1,47 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
try {
// normal case
Schema::table('tags', static function (Blueprint $table): void {
if (Schema::hasColumn('tags', 'tagMode') && !Schema::hasColumn('piggy_banks', 'tag_mode')) {
$table->renameColumn('tagMode', 'tag_mode');
}
});
// lower case just in case (haha)
Schema::table('tags', static function (Blueprint $table): void {
if (Schema::hasColumn('tags', 'tagmode') && !Schema::hasColumn('piggy_banks', 'tag_mode')) {
$table->renameColumn('tagmode', 'tag_mode');
}
});
} catch (RuntimeException $e) {
Log::error(sprintf('Could not rename column: %s', $e->getMessage()));
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
try {
Schema::table('tags', static function (Blueprint $table): void {
if (Schema::hasColumn('tags', 'tag_mode') && !Schema::hasColumn('piggy_banks', 'tagMode')) {
$table->renameColumn('tag_mode', 'tagMode');
}
});
} catch (RuntimeException $e) {
Log::error(sprintf('Could not rename column: %s', $e->getMessage()));
}
}
};

View File

@@ -67,6 +67,7 @@ class TransactionCurrencySeeder extends Seeder
// asian currencies // asian currencies
$currencies[] = ['code' => 'JPY', 'name' => 'Japanese yen', 'symbol' => '¥', 'decimal_places' => 0]; $currencies[] = ['code' => 'JPY', 'name' => 'Japanese yen', 'symbol' => '¥', 'decimal_places' => 0];
$currencies[] = ['code' => 'CNY', 'name' => 'Chinese yuan', 'symbol' => '¥', 'decimal_places' => 2]; $currencies[] = ['code' => 'CNY', 'name' => 'Chinese yuan', 'symbol' => '¥', 'decimal_places' => 2];
// $currencies[] = ['code' => 'RMB', 'name' => 'Chinese yuan', 'symbol' => '¥', 'decimal_places' => 2];
$currencies[] = ['code' => 'RUB', 'name' => 'Russian ruble', 'symbol' => '₽', 'decimal_places' => 2]; $currencies[] = ['code' => 'RUB', 'name' => 'Russian ruble', 'symbol' => '₽', 'decimal_places' => 2];
$currencies[] = ['code' => 'INR', 'name' => 'Indian rupee', 'symbol' => '₹', 'decimal_places' => 2]; $currencies[] = ['code' => 'INR', 'name' => 'Indian rupee', 'symbol' => '₹', 'decimal_places' => 2];

1192
package-lock.json generated

File diff suppressed because it is too large Load Diff

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