Compare commits

...

65 Commits

Author SHA1 Message Date
github-actions[bot]
230a3a0180 Merge pull request #11371 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-12-16 06:25:04 +01:00
github-actions[bot]
002454b995 Merge pull request #11370 from firefly-iii/release-1765862692
🤖 Automatically merge the PR into the develop branch.
2025-12-16 06:24:59 +01:00
JC5
e6d9c2e218 🤖 Auto commit for release 'v6.4.12' on 2025-12-16 2025-12-16 06:24:52 +01:00
github-actions[bot]
eaa5054b00 Merge pull request #11369 from firefly-iii/release-1765861996
🤖 Automatically merge the PR into the develop branch.
2025-12-16 06:13:25 +01:00
JC5
4e9e63ed08 🤖 Auto commit for release 'develop' on 2025-12-16 2025-12-16 06:13:16 +01:00
James Cole
76ea5b6e34 Fix #11367 2025-12-16 06:08:38 +01:00
Sander Dorigo
2f788f7397 Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop 2025-12-15 15:51:13 +01:00
Sander Dorigo
29766aa9b7 Add better running balance 2025-12-15 14:56:58 +01:00
github-actions[bot]
cc30376297 Merge pull request #11364 from firefly-iii/release-1765805210
🤖 Automatically merge the PR into the develop branch.
2025-12-15 14:26:58 +01:00
JC5
5b007fbe01 🤖 Auto commit for release 'develop' on 2025-12-15 2025-12-15 14:26:50 +01:00
Sander Dorigo
e1f8ea3b1a Fix missing user property 2025-12-15 14:19:43 +01:00
James Cole
6f019f0bb4 Merge pull request #11363 from firefly-iii/main
Merge main into develop
2025-12-15 10:48:19 +01:00
github-actions[bot]
f475947776 Merge pull request #11362 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-12-15 09:01:26 +01:00
github-actions[bot]
ee6901eb92 Merge pull request #11361 from firefly-iii/release-1765785673
🤖 Automatically merge the PR into the develop branch.
2025-12-15 09:01:21 +01:00
JC5
84d7523d6c 🤖 Auto commit for release 'v6.4.11' on 2025-12-15 2025-12-15 09:01:13 +01:00
github-actions[bot]
6900dc7dae Merge pull request #11360 from firefly-iii/release-1765785184
🤖 Automatically merge the PR into the develop branch.
2025-12-15 08:53:14 +01:00
JC5
6247e516c6 🤖 Auto commit for release 'develop' on 2025-12-15 2025-12-15 08:53:05 +01:00
Sander Dorigo
cdf970a88c Add changelog 2025-12-15 08:42:10 +01:00
Sander Dorigo
a447c387f9 Fix #11357 2025-12-15 08:41:07 +01:00
Sander Dorigo
ce2c94efed Fix #11356 2025-12-15 08:40:19 +01:00
James Cole
205ea4270b Merge pull request #11358 from firefly-iii/dependabot/github_actions/dessant/label-actions-5 2025-12-15 07:27:43 +01:00
github-actions[bot]
dcbb2428f2 Merge pull request #11359 from firefly-iii/release-1765769737
🤖 Automatically merge the PR into the develop branch.
2025-12-15 04:35:45 +01:00
JC5
319916fc8f 🤖 Auto commit for release 'develop' on 2025-12-15 2025-12-15 04:35:37 +01:00
dependabot[bot]
088b0e2f30 Bump dessant/label-actions from 4 to 5
Bumps [dessant/label-actions](https://github.com/dessant/label-actions) from 4 to 5.
- [Release notes](https://github.com/dessant/label-actions/releases)
- [Changelog](https://github.com/dessant/label-actions/blob/main/CHANGELOG.md)
- [Commits](https://github.com/dessant/label-actions/compare/v4...v5)

---
updated-dependencies:
- dependency-name: dessant/label-actions
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 03:06:09 +00:00
github-actions[bot]
b45aadf8a3 Merge pull request #11355 from firefly-iii/develop
🤖 Automatically merge the PR into the main branch.
2025-12-14 19:13:25 +01:00
github-actions[bot]
1fafeb1515 Merge pull request #11354 from firefly-iii/release-1765735989
🤖 Automatically merge the PR into the develop branch.
2025-12-14 19:13:19 +01:00
JC5
f60c64c9c1 🤖 Auto commit for release 'v6.4.10' on 2025-12-14 2025-12-14 19:13:09 +01:00
James Cole
564dcb1c6d Expand changelog. 2025-12-14 19:09:08 +01:00
github-actions[bot]
4044bb85a9 Merge pull request #11353 from firefly-iii/release-1765725243
🤖 Automatically merge the PR into the develop branch.
2025-12-14 16:14:10 +01:00
JC5
18bb0eecff 🤖 Auto commit for release 'develop' on 2025-12-14 2025-12-14 16:14:03 +01:00
James Cole
9af95907e3 Fix patch etc. 2025-12-14 16:10:21 +01:00
James Cole
40ecba4b5a No longer need patch. 2025-12-14 10:31:35 +01:00
James Cole
73312a4ccc Fix #11310 2025-12-14 10:24:27 +01:00
James Cole
d747ac237b Validate title, fix running balance display 2025-12-13 06:36:20 +01:00
github-actions[bot]
b6c4253d76 Merge pull request #11349 from firefly-iii/release-1765602800
🤖 Automatically merge the PR into the develop branch.
2025-12-13 06:13:28 +01:00
JC5
d74d67633d 🤖 Auto commit for release 'develop' on 2025-12-13 2025-12-13 06:13:20 +01:00
James Cole
0b00f35101 Update packages, another fix for the same issue. 2025-12-13 06:08:58 +01:00
James Cole
8f81cb8cc4 Fix #11346 2025-12-13 06:05:39 +01:00
github-actions[bot]
fa665286b5 Merge pull request #11344 from firefly-iii/release-1765164810
🤖 Automatically merge the PR into the develop branch.
2025-12-08 04:33:39 +01:00
JC5
58ae0c1c9b 🤖 Auto commit for release 'develop' on 2025-12-08 2025-12-08 04:33:30 +01:00
github-actions[bot]
7eab4834c8 Merge pull request #11340 from firefly-iii/release-1765124558
🤖 Automatically merge the PR into the develop branch.
2025-12-07 17:22:47 +01:00
JC5
d1332eb592 🤖 Auto commit for release 'develop' on 2025-12-07 2025-12-07 17:22:38 +01:00
James Cole
346f2dfaea Add amount event. 2025-12-07 16:47:04 +01:00
James Cole
f6037318f4 Fix #11337 2025-12-07 07:00:50 +01:00
James Cole
babf9fe96f Add file permissions checks. #11323 2025-12-06 14:55:15 +01:00
James Cole
ca3922d00a Fix #11313 2025-12-06 13:50:51 +01:00
James Cole
aadb685b57 Add YTD fix. 2025-12-06 08:12:18 +01:00
github-actions[bot]
bee62b2115 Merge pull request #11335 from firefly-iii/release-1765004138
🤖 Automatically merge the PR into the develop branch.
2025-12-06 07:55:46 +01:00
JC5
205169a8ad 🤖 Auto commit for release 'develop' on 2025-12-06 2025-12-06 07:55:38 +01:00
James Cole
5f36bb84a4 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-12-06 07:51:19 +01:00
James Cole
5b395d870b Fix #11333 2025-12-06 07:32:43 +01:00
github-actions[bot]
bceb526cb3 Merge pull request #11334 from firefly-iii/release-1765002701
🤖 Automatically merge the PR into the develop branch.
2025-12-06 07:31:52 +01:00
JC5
1f89dddb08 🤖 Auto commit for release 'develop' on 2025-12-06 2025-12-06 07:31:41 +01:00
James Cole
a93f2d66af Fix #11329 2025-12-06 07:27:41 +01:00
James Cole
551909ea60 Merge branch 'main' into develop 2025-12-05 08:21:34 +01:00
Sander Dorigo
5667044349 Fix #11328 2025-12-04 17:27:20 +01:00
James Cole
6f73e4f2c9 Merge pull request #11316 from firefly-iii/dependabot/composer/develop/symfony/mailgun-mailer-8.0.0
Bump symfony/mailgun-mailer from 7.4.0 to 8.0.0
2025-12-01 14:32:55 +01:00
dependabot[bot]
1f19f20734 Bump symfony/mailgun-mailer from 7.4.0 to 8.0.0
Bumps [symfony/mailgun-mailer](https://github.com/symfony/mailgun-mailer) from 7.4.0 to 8.0.0.
- [Release notes](https://github.com/symfony/mailgun-mailer/releases)
- [Changelog](https://github.com/symfony/mailgun-mailer/blob/7.3/CHANGELOG.md)
- [Commits](https://github.com/symfony/mailgun-mailer/compare/v7.4.0...v8.0.0)

---
updated-dependencies:
- dependency-name: symfony/mailgun-mailer
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 10:45:09 +00:00
James Cole
91c8f0db80 Merge pull request #11317 from firefly-iii/dependabot/composer/develop/symfony/expression-language-8.0.0
Bump symfony/expression-language from 7.4.0 to 8.0.0
2025-12-01 11:41:22 +01:00
dependabot[bot]
2cdd1aa147 Bump symfony/expression-language from 7.4.0 to 8.0.0
Bumps [symfony/expression-language](https://github.com/symfony/expression-language) from 7.4.0 to 8.0.0.
- [Release notes](https://github.com/symfony/expression-language/releases)
- [Changelog](https://github.com/symfony/expression-language/blob/7.3/CHANGELOG.md)
- [Commits](https://github.com/symfony/expression-language/compare/v7.4.0...v8.0.0)

---
updated-dependencies:
- dependency-name: symfony/expression-language
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 08:17:15 +00:00
James Cole
5ac51218aa Merge pull request #11319 from firefly-iii/dependabot/github_actions/github/command-2.0.3 2025-12-01 05:15:37 +01:00
James Cole
80abd277a0 Merge pull request #11315 from firefly-iii/dependabot/composer/develop/symfony/http-client-8.0.0 2025-12-01 05:14:44 +01:00
mergify[bot]
b644f28882 Merge branch 'develop' into dependabot/composer/develop/symfony/http-client-8.0.0 2025-12-01 03:40:11 +00:00
dependabot[bot]
b799379a0a Bump github/command from 2.0.2 to 2.0.3
Bumps [github/command](https://github.com/github/command) from 2.0.2 to 2.0.3.
- [Release notes](https://github.com/github/command/releases)
- [Commits](https://github.com/github/command/compare/v2.0.2...v2.0.3)

---
updated-dependencies:
- dependency-name: github/command
  dependency-version: 2.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 03:10:25 +00:00
dependabot[bot]
c8edaee848 Bump symfony/http-client from 7.4.0 to 8.0.0
Bumps [symfony/http-client](https://github.com/symfony/http-client) from 7.4.0 to 8.0.0.
- [Release notes](https://github.com/symfony/http-client/releases)
- [Changelog](https://github.com/symfony/http-client/blob/7.3/CHANGELOG.md)
- [Commits](https://github.com/symfony/http-client/compare/v7.4.0...v8.0.0)

---
updated-dependencies:
- dependency-name: symfony/http-client
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 03:03:40 +00:00
41 changed files with 1119 additions and 956 deletions

View File

@@ -402,16 +402,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.91.0", "version": "v3.92.1",
"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": "c4a25f20390337789c26b693ae46faa125040352" "reference": "ed33ad03313a019533ba065eba6c86af0a382873"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/c4a25f20390337789c26b693ae46faa125040352", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/ed33ad03313a019533ba065eba6c86af0a382873",
"reference": "c4a25f20390337789c26b693ae46faa125040352", "reference": "ed33ad03313a019533ba065eba6c86af0a382873",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -451,6 +451,7 @@
"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.25 || ^10.5.53 || ^11.5.34", "phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34",
"symfony/polyfill-php85": "^1.33",
"symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2 || ^8.0", "symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2 || ^8.0",
"symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2 || ^8.0" "symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2 || ^8.0"
}, },
@@ -467,7 +468,7 @@
"PhpCsFixer\\": "src/" "PhpCsFixer\\": "src/"
}, },
"exclude-from-classmap": [ "exclude-from-classmap": [
"src/Fixer/Internal/*" "src/**/Internal/"
] ]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@@ -493,7 +494,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.91.0" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.92.1"
}, },
"funding": [ "funding": [
{ {
@@ -501,7 +502,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-11-28T22:07:42+00:00" "time": "2025-12-15T23:09:01+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@@ -1251,16 +1252,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v8.0.0", "version": "v8.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "307d3cf852f5ead3618ac60ecbedbdd512c348b1" "reference": "fcb73f69d655b48fcb894a262f074218df08bd58"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/307d3cf852f5ead3618ac60ecbedbdd512c348b1", "url": "https://api.github.com/repos/symfony/console/zipball/fcb73f69d655b48fcb894a262f074218df08bd58",
"reference": "307d3cf852f5ead3618ac60ecbedbdd512c348b1", "reference": "fcb73f69d655b48fcb894a262f074218df08bd58",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1317,7 +1318,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v8.0.0" "source": "https://github.com/symfony/console/tree/v8.0.1"
}, },
"funding": [ "funding": [
{ {
@@ -1337,7 +1338,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-11-21T13:19:49+00:00" "time": "2025-12-05T15:25:33+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@@ -1569,16 +1570,16 @@
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
"version": "v8.0.0", "version": "v8.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/filesystem.git", "url": "https://github.com/symfony/filesystem.git",
"reference": "7fc96ae83372620eaba3826874f46e26295768ca" "reference": "d937d400b980523dc9ee946bb69972b5e619058d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7fc96ae83372620eaba3826874f46e26295768ca", "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d",
"reference": "7fc96ae83372620eaba3826874f46e26295768ca", "reference": "d937d400b980523dc9ee946bb69972b5e619058d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1615,7 +1616,7 @@
"description": "Provides basic utilities for the filesystem", "description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/filesystem/tree/v8.0.0" "source": "https://github.com/symfony/filesystem/tree/v8.0.1"
}, },
"funding": [ "funding": [
{ {
@@ -1635,7 +1636,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-11-05T14:36:47+00:00" "time": "2025-12-01T09:13:36+00:00"
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
@@ -2575,16 +2576,16 @@
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
"version": "v8.0.0", "version": "v8.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/string.git", "url": "https://github.com/symfony/string.git",
"reference": "f929eccf09531078c243df72398560e32fa4cf4f" "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/f929eccf09531078c243df72398560e32fa4cf4f", "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc",
"reference": "f929eccf09531078c243df72398560e32fa4cf4f", "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2641,7 +2642,7 @@
"utf8" "utf8"
], ],
"support": { "support": {
"source": "https://github.com/symfony/string/tree/v8.0.0" "source": "https://github.com/symfony/string/tree/v8.0.1"
}, },
"funding": [ "funding": [
{ {
@@ -2661,7 +2662,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-09-11T14:37:55+00:00" "time": "2025-12-01T09:13:36+00:00"
} }
], ],
"packages-dev": [], "packages-dev": [],

View File

@@ -13,7 +13,7 @@ jobs:
close_duplicates: close_duplicates:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: github/command@v2.0.2 - uses: github/command@v2.0.3
id: command id: command
with: with:
allowed_contexts: "issue" allowed_contexts: "issue"

View File

@@ -18,4 +18,4 @@ jobs:
action: action:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: dessant/label-actions@v4 - uses: dessant/label-actions@v5

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Chart; namespace FireflyIII\Api\V1\Controllers\Chart;
use Illuminate\Http\Request;
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\Enums\UserRoleEnum; use FireflyIII\Enums\UserRoleEnum;
@@ -32,11 +31,13 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Navigation;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\ApiSupport; use FireflyIII\Support\Http\Api\ApiSupport;
use FireflyIII\Support\Http\Api\CleansChartData; use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter; use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
/** /**
@@ -103,7 +104,7 @@ class AccountController extends Controller
$currency = $this->repository->getAccountCurrency($account); $currency = $this->repository->getAccountCurrency($account);
$currentStart = clone $params['start']; $currentStart = clone $params['start'];
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToPrimary); $range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToPrimary);
$period = $params['period'] ?? '1D';
$previous = array_values($range)[0]['balance']; $previous = array_values($range)[0]['balance'];
$pcPrevious = null; $pcPrevious = null;
@@ -129,7 +130,7 @@ class AccountController extends Controller
'end_date' => $params['end']->toAtomString(), 'end_date' => $params['end']->toAtomString(),
'type' => 'line', 'type' => 'line',
'yAxisID' => 0, 'yAxisID' => 0,
'period' => '1D', 'period' => $period,
'entries' => [], 'entries' => [],
'pc_entries' => [], 'pc_entries' => [],
]; ];
@@ -141,7 +142,7 @@ class AccountController extends Controller
$currentSet['primary_currency_decimal_places'] = $this->primaryCurrency->decimal_places; $currentSet['primary_currency_decimal_places'] = $this->primaryCurrency->decimal_places;
$pcPrevious = array_values($range)[0]['pc_balance']; $pcPrevious = array_values($range)[0]['pc_balance'];
} }
// create array of values to collect.
while ($currentStart <= $params['end']) { while ($currentStart <= $params['end']) {
$format = $currentStart->format('Y-m-d'); $format = $currentStart->format('Y-m-d');
@@ -158,8 +159,8 @@ class AccountController extends Controller
$pcPrevious = $pcBalance; $pcPrevious = $pcBalance;
$currentSet['pc_entries'][$label] = $pcBalance; $currentSet['pc_entries'][$label] = $pcBalance;
} }
$currentStart = Navigation::addPeriod($currentStart, $period);
$currentStart->addDay(); // $currentStart->addDay();
} }
$this->chartData[] = $currentSet; $this->chartData[] = $currentSet;
} }

View File

@@ -486,7 +486,7 @@ class BasicController extends Controller
'currency_decimal_places' => $currencies[$currencyId]->decimal_places, 'currency_decimal_places' => $currencies[$currencyId]->decimal_places,
'value_parsed' => Amount::formatFlat($currencies[$currencyId]->symbol, $currencies[$currencyId]->decimal_places, $availableBudget, false), 'value_parsed' => Amount::formatFlat($currencies[$currencyId]->symbol, $currencies[$currencyId]->decimal_places, $availableBudget, false),
'local_icon' => 'money', 'local_icon' => 'money',
'sub_title' => Amount::formatFlat($currencies[$currencyId]->symbol, $currencies[$currencyId]->decimal_places, $availableBudget, false), 'sub_title' => Amount::formatFlat($currencies[$currencyId]->symbol, $currencies[$currencyId]->decimal_places, bcdiv($availableBudget, (string)$days), false),
]; ];
} }
foreach ($spent as $row) { foreach ($spent as $row) {

View File

@@ -339,6 +339,9 @@ class UpdateRequest extends FormRequest
// if more than one, verify that there are journal ID's present. // if more than one, verify that there are journal ID's present.
$this->validateJournalIds($validator, $transactionGroup); $this->validateJournalIds($validator, $transactionGroup);
// if more than one split, needs group title
$this->validateGroupDescription($validator);
// all transaction types must be equal: // all transaction types must be equal:
$this->validateTransactionTypesForUpdate($validator); $this->validateTransactionTypesForUpdate($validator);

View File

@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
/*
* ClearsEmptyForeignAmounts.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Console\Commands\Correction;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Models\Transaction;
use Illuminate\Console\Command;
class ClearsEmptyForeignAmounts extends Command
{
use ShowsFriendlyMessages;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'correction:clears-empty-foreign-amounts';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Removes references to foreign amounts if there is no amount.';
/**
* Execute the console command.
*/
public function handle(): int
{
// transaction: has no amount, but reference to currency.
$count = Transaction::whereNull('foreign_amount')->whereNotNull('foreign_currency_id')->count();
if ($count > 0) {
Transaction::whereNull('foreign_amount')->whereNotNull('foreign_currency_id')->update(['foreign_currency_id' => null]);
$this->friendlyInfo(sprintf('Corrected %d invalid foreign amount reference(s)', $count));
}
// transaction: has amount, but no currency.
$count = Transaction::whereNull('foreign_currency_id')->whereNotNull('foreign_amount')->count();
if ($count > 0) {
Transaction::whereNull('foreign_currency_id')->whereNotNull('foreign_amount')->update(['foreign_amount' => null]);
$this->friendlyInfo(sprintf('Corrected %d invalid foreign amount reference(s)', $count));
}
return self::SUCCESS;
}
}

View File

@@ -78,6 +78,7 @@ class CorrectsDatabase extends Command
// 'correction:transaction-types', // resource heavy, disabled. // 'correction:transaction-types', // resource heavy, disabled.
'correction:recalculate-pc-amounts', 'correction:recalculate-pc-amounts',
'correction:remove-links-to-deleted-objects', 'correction:remove-links-to-deleted-objects',
'correction:clears-empty-foreign-amounts',
'firefly-iii:report-integrity', 'firefly-iii:report-integrity',
]; ];
foreach ($commands as $command) { foreach ($commands as $command) {

View File

@@ -86,17 +86,27 @@ class RemovesLinksToDeletedObjects extends Command
private function cleanupJournals(array $journals): void private function cleanupJournals(array $journals): void
{ {
$count = DB::table('tag_transaction_journal')->whereIn('transaction_journal_id', $journals)->delete(); $countTags = 0;
if ($count > 0) { $countBudgets = 0;
$this->friendlyInfo(sprintf('Removed %d old relationship(s) between tags and transactions.', $count)); $countCategories = 0;
// #11333
foreach (array_chunk($journals, 1337) as $set) {
$countTags += DB::table('tag_transaction_journal')->whereIn('transaction_journal_id', $set)->delete();
$countBudgets += DB::table('budget_transaction_journal')->whereIn('transaction_journal_id', $set)->delete();
$countCategories += DB::table('category_transaction_journal')->whereIn('transaction_journal_id', $set)->delete();
} }
$count = DB::table('budget_transaction_journal')->whereIn('transaction_journal_id', $journals)->delete();
if ($count > 0) {
$this->friendlyInfo(sprintf('Removed %d old relationship(s) between budgets and transactions.', $count));
if ($countTags > 0) {
$this->friendlyInfo(sprintf('Removed %d old relationship(s) between tags and transactions.', $countTags));
} }
$count = DB::table('category_transaction_journal')->whereIn('transaction_journal_id', $journals)->delete();
if ($count > 0) { if ($countBudgets > 0) {
$this->friendlyInfo(sprintf('Removed %d old relationship(s) categories and transactions.', $count)); $this->friendlyInfo(sprintf('Removed %d old relationship(s) between budgets and transactions.', $countBudgets));
}
if ($countCategories > 0) {
$this->friendlyInfo(sprintf('Removed %d old relationship(s) categories and transactions.', $countCategories));
} }
} }

View File

@@ -1,26 +0,0 @@
<?php
namespace FireflyIII\Console\Commands\Integrity;
use Illuminate\Console\Command;
class ReportSkeleton extends Command
{
protected $description = 'DESCRIPTION HERE';
protected $signature = 'firefly-iii:INT_COMMAND';
/**
* Execute the console command.
*
* @return int
*/
public function handle(): int
{
//
$this->warn('Congrats, you found the skeleton command. Boo!');
return 0;
}
}

View File

@@ -48,6 +48,7 @@ class ReportsIntegrity extends Command
$commands = [ $commands = [
'integrity:empty-objects', 'integrity:empty-objects',
'integrity:total-sums', 'integrity:total-sums',
'integrity:file-permissions',
]; ];
foreach ($commands as $command) { foreach ($commands as $command) {
$this->friendlyLine(sprintf('Now executing %s', $command)); $this->friendlyLine(sprintf('Now executing %s', $command));

View File

@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
/*
* ValidatesFilePermissions.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Console\Commands\Integrity;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use Illuminate\Console\Command;
class ValidatesFilePermissions extends Command
{
use ShowsFriendlyMessages;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'integrity:file-permissions';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*/
public function handle(): int
{
$directories = [storage_path('upload')];
$errors = false;
/** @var string $directory */
foreach ($directories as $directory) {
if (!is_dir($directory)) {
$this->friendlyError(sprintf('Directory "%s" cannot found. It is necessary to allow files to be uploaded.', $directory));
$errors = true;
continue;
}
if (!is_writable($directory)) {
$this->friendlyError(sprintf('Directory "%s" is not writeable. Uploading attachments may fail silently.', $directory));
$errors = true;
}
}
if (false === $errors) {
$this->friendlyInfo('All necessary file paths seem to exist, and are writeable.');
}
return self::SUCCESS;
}
}

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
/*
* TriggeredStoredTransactionGroup.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Events\Model\TransactionGroup;
use FireflyIII\Events\Event;
use FireflyIII\Models\TransactionGroup;
use Illuminate\Queue\SerializesModels;
class TriggeredStoredTransactionGroup extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(public TransactionGroup $transactionGroup) {}
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Events; namespace FireflyIII\Handlers\Events;
use FireflyIII\Enums\WebhookTrigger; use FireflyIII\Enums\WebhookTrigger;
use FireflyIII\Events\Model\TransactionGroup\TriggeredStoredTransactionGroup;
use FireflyIII\Events\RequestedSendWebhookMessages; use FireflyIII\Events\RequestedSendWebhookMessages;
use FireflyIII\Events\StoredTransactionGroup; use FireflyIII\Events\StoredTransactionGroup;
use FireflyIII\Generator\Webhook\MessageGeneratorInterface; use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
@@ -51,6 +52,12 @@ class StoredGroupEventHandler
$this->removePeriodStatistics($event); $this->removePeriodStatistics($event);
} }
public function triggerRulesManually(TriggeredStoredTransactionGroup $event): void
{
$newEvent = new StoredTransactionGroup($event->transactionGroup, true, false);
$this->processRules($newEvent);
}
/** /**
* This method grabs all the users rules and processes them. * This method grabs all the users rules and processes them.
*/ */

View File

@@ -122,6 +122,9 @@ class IndexController extends Controller
$availableBudgets = $this->getAllAvailableBudgets($start, $end); $availableBudgets = $this->getAllAvailableBudgets($start, $end);
// get all active budgets: // get all active budgets:
$budgets = $this->getAllBudgets($start, $end, $currencies, $this->primaryCurrency); $budgets = $this->getAllBudgets($start, $end, $currencies, $this->primaryCurrency);
// echo '<pre>';
// var_dump($budgets[0]);exit;
$sums = $this->getSums($budgets); $sums = $this->getSums($budgets);
// get budgeted for default currency: // get budgeted for default currency:

View File

@@ -113,6 +113,8 @@ class ProfileController extends Controller
throw new FireflyException('Invalid token.'); throw new FireflyException('Invalid token.');
} }
$repository->unblockUser($user); $repository->unblockUser($user);
// also remove the "remote_guard_alt_email" preference.
Preferences::delete('remote_guard_alt_email');
// return to log in. // return to log in.
session()->flash('success', (string) trans('firefly.login_with_new_email')); session()->flash('success', (string) trans('firefly.login_with_new_email'));

View File

@@ -26,14 +26,16 @@ namespace FireflyIII\Http\Controllers\RuleGroup;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use FireflyIII\Events\Model\TransactionGroup\TriggeredStoredTransactionGroup;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\SelectTransactionsRequest; use FireflyIII\Http\Requests\SelectTransactionsRequest;
use FireflyIII\Models\RuleGroup; use FireflyIII\Models\RuleGroup;
use FireflyIII\TransactionRules\Engine\RuleEngineInterface; use FireflyIII\Models\TransactionGroup;
use FireflyIII\User; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Collection; use Illuminate\Support\Facades\Log;
use Illuminate\View\View; use Illuminate\View\View;
/** /**
@@ -41,18 +43,20 @@ use Illuminate\View\View;
*/ */
class ExecutionController extends Controller class ExecutionController extends Controller
{ {
private readonly AccountRepositoryInterface $repository;
/** /**
* ExecutionController constructor. * ExecutionController constructor.
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
$this->repository = app(AccountRepositoryInterface::class);
$this->middleware( $this->middleware(
function ($request, $next) { function ($request, $next) {
app('view')->share('title', (string) trans('firefly.rules')); app('view')->share('title', (string)trans('firefly.rules'));
app('view')->share('mainTitleIcon', 'fa-random'); app('view')->share('mainTitleIcon', 'fa-random');
$this->repository->setUser(auth()->user());
return $next($request); return $next($request);
} }
@@ -67,34 +71,37 @@ class ExecutionController extends Controller
public function execute(SelectTransactionsRequest $request, RuleGroup $ruleGroup): RedirectResponse public function execute(SelectTransactionsRequest $request, RuleGroup $ruleGroup): RedirectResponse
{ {
// Get parameters specified by the user // Get parameters specified by the user
/** @var User $user */ $accounts = $request->get('accounts');
$user = auth()->user(); $set = $this->repository->getAccountsById($accounts);
$accounts = implode(',', $request->get('accounts'));
// create new rule engine:
$newRuleEngine = app(RuleEngineInterface::class);
$newRuleEngine->setUser($user);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($set);
// add date operators. // add date operators.
if (null !== $request->get('start')) { if (null !== $request->get('start')) {
$startDate = new Carbon($request->get('start')); $startDate = new Carbon($request->get('start'));
$newRuleEngine->addOperator(['type' => 'date_after', 'value' => $startDate->format('Y-m-d')]); $collector->setStart($startDate);
} }
if (null !== $request->get('end')) { if (null !== $request->get('end')) {
$endDate = new Carbon($request->get('end')); $endDate = new Carbon($request->get('end'));
$newRuleEngine->addOperator(['type' => 'date_before', 'value' => $endDate->format('Y-m-d')]); $collector->setEnd($endDate);
}
$final = $collector->getGroups();
$ids = $final->pluck('id')->toArray();
Log::debug(sprintf('Found %d groups collected from %d account(s)', $final->count(), $set->count()));
foreach (array_chunk($ids, 1337) as $setOfIds) {
Log::debug(sprintf('Now processing %d groups', count($setOfIds)));
$groups = TransactionGroup::whereIn('id', $setOfIds)->get();
/** @var TransactionGroup $group */
foreach ($groups as $group) {
Log::debug(sprintf('Processing group #%d.', $group->id));
event(new TriggeredStoredTransactionGroup($group));
}
} }
// add extra operators:
$newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]);
// set rules:
// #10427, file rule group and not the set of rules.
$collection = new Collection()->push($ruleGroup);
$newRuleEngine->setRuleGroups($collection);
$newRuleEngine->fire();
// Tell the user that the job is queued // Tell the user that the job is queued
session()->flash('success', (string) trans('firefly.applied_rule_group_selection', ['title' => $ruleGroup->title])); session()->flash('success', (string)trans('firefly.applied_rule_group_selection', ['title' => $ruleGroup->title]));
return redirect()->route('rules.index'); return redirect()->route('rules.index');
} }
@@ -106,7 +113,7 @@ class ExecutionController extends Controller
*/ */
public function selectTransactions(RuleGroup $ruleGroup): Factory|\Illuminate\Contracts\View\View public function selectTransactions(RuleGroup $ruleGroup): Factory|\Illuminate\Contracts\View\View
{ {
$subTitle = (string) trans('firefly.apply_rule_group_selection', ['title' => $ruleGroup->title]); $subTitle = (string)trans('firefly.apply_rule_group_selection', ['title' => $ruleGroup->title]);
return view('rules.rule-group.select-transactions', ['ruleGroup' => $ruleGroup, 'subTitle' => $subTitle]); return view('rules.rule-group.select-transactions', ['ruleGroup' => $ruleGroup, 'subTitle' => $subTitle]);
} }

View File

@@ -24,13 +24,13 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Transaction; namespace FireflyIII\Http\Controllers\Transaction;
use FireflyIII\Support\Facades\Preferences;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Controllers\PeriodOverview; use FireflyIII\Support\Http\Controllers\PeriodOverview;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -58,7 +58,7 @@ class IndexController extends Controller
$this->middleware( $this->middleware(
function ($request, $next) { function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-exchange'); app('view')->share('mainTitleIcon', 'fa-exchange');
app('view')->share('title', (string) trans('firefly.transactions')); app('view')->share('title', (string)trans('firefly.transactions'));
$this->repository = app(JournalRepositoryInterface::class); $this->repository = app(JournalRepositoryInterface::class);
@@ -84,8 +84,8 @@ class IndexController extends Controller
$subTitleIcon = config('firefly.transactionIconsByType.'.$objectType); $subTitleIcon = config('firefly.transactionIconsByType.'.$objectType);
$types = config('firefly.transactionTypesByType.'.$objectType); $types = config('firefly.transactionTypesByType.'.$objectType);
$page = (int) $request->get('page'); $page = (int)$request->get('page');
$pageSize = (int) Preferences::get('listPageSize', 50)->data; $pageSize = (int)Preferences::get('listPageSize', 50)->data;
if (!$start instanceof Carbon) { if (!$start instanceof Carbon) {
$start = session('start'); $start = session('start');
@@ -100,11 +100,17 @@ class IndexController extends Controller
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
$startStr = $start->isoFormat($this->monthAndDayFormat); $startStr = $start->isoFormat($this->monthAndDayFormat);
$endStr = $end->isoFormat($this->monthAndDayFormat); $endStr = $end->isoFormat($this->monthAndDayFormat);
$subTitle = (string) trans(sprintf('firefly.title_%s_between', $objectType), ['start' => $startStr, 'end' => $endStr]); $subTitle = (string)trans(sprintf('firefly.title_%s_between', $objectType), ['start' => $startStr, 'end' => $endStr]);
$path = route('transactions.index', [$objectType, $start->format('Y-m-d'), $end->format('Y-m-d')]); $path = route('transactions.index', [$objectType, $start->format('Y-m-d'), $end->format('Y-m-d')]);
$firstJournal = $this->repository->firstNull(); $firstJournal = $this->repository->firstNull();
$startPeriod = $firstJournal instanceof TransactionJournal ? $firstJournal->date : new Carbon(); $startPeriod = $firstJournal instanceof TransactionJournal ? $firstJournal->date : new Carbon();
$endPeriod = clone $end; $endPeriod = clone $end;
// limit to 3 years for the time being.
if (now()->diffInYears($startPeriod, true) > 3) {
$startPeriod = now()->subYears(3);
}
$periods = $this->getTransactionPeriodOverview($objectType, $startPeriod, $endPeriod); $periods = $this->getTransactionPeriodOverview($objectType, $startPeriod, $endPeriod);
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
@@ -137,14 +143,14 @@ class IndexController extends Controller
{ {
$subTitleIcon = config('firefly.transactionIconsByType.'.$objectType); $subTitleIcon = config('firefly.transactionIconsByType.'.$objectType);
$types = config('firefly.transactionTypesByType.'.$objectType); $types = config('firefly.transactionTypesByType.'.$objectType);
$page = (int) $request->get('page'); $page = (int)$request->get('page');
$pageSize = (int) Preferences::get('listPageSize', 50)->data; $pageSize = (int)Preferences::get('listPageSize', 50)->data;
$path = route('transactions.index.all', [$objectType]); $path = route('transactions.index.all', [$objectType]);
$first = $this->repository->firstNull(); $first = $this->repository->firstNull();
$start = $first instanceof TransactionJournal ? $first->date : new Carbon(); $start = $first instanceof TransactionJournal ? $first->date : new Carbon();
$last = $this->repository->getLast(); $last = $this->repository->getLast();
$end = $last instanceof TransactionJournal ? $last->date : today(config('app.timezone')); $end = $last instanceof TransactionJournal ? $last->date : today(config('app.timezone'));
$subTitle = (string) trans('firefly.all_'.$objectType); $subTitle = (string)trans('firefly.all_'.$objectType);
/** @var GroupCollectorInterface $collector */ /** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);

View File

@@ -33,6 +33,7 @@ use FireflyIII\Events\Model\PiggyBank\ChangedAmount;
use FireflyIII\Events\Model\PiggyBank\ChangedName; use FireflyIII\Events\Model\PiggyBank\ChangedName;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray; use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject; use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
use FireflyIII\Events\Model\TransactionGroup\TriggeredStoredTransactionGroup;
use FireflyIII\Events\NewVersionAvailable; use FireflyIII\Events\NewVersionAvailable;
use FireflyIII\Events\Preferences\UserGroupChangedPrimaryCurrency; use FireflyIII\Events\Preferences\UserGroupChangedPrimaryCurrency;
use FireflyIII\Events\RegisteredUser; use FireflyIII\Events\RegisteredUser;
@@ -131,6 +132,9 @@ class EventServiceProvider extends ServiceProvider
StoredTransactionGroup::class => [ StoredTransactionGroup::class => [
'FireflyIII\Handlers\Events\StoredGroupEventHandler@runAllHandlers', 'FireflyIII\Handlers\Events\StoredGroupEventHandler@runAllHandlers',
], ],
TriggeredStoredTransactionGroup::class => [
'FireflyIII\Handlers\Events\StoredGroupEventHandler@triggerRulesManually',
],
// is a Transaction Journal related event. // is a Transaction Journal related event.
UpdatedTransactionGroup::class => [ UpdatedTransactionGroup::class => [
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@runAllHandlers', 'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@runAllHandlers',

View File

@@ -78,9 +78,7 @@ class GroupUpdateService
if (1 === count($transactions) && 1 === $transactionGroup->transactionJournals()->count()) { if (1 === count($transactions) && 1 === $transactionGroup->transactionJournals()->count()) {
/** @var TransactionJournal $first */ /** @var TransactionJournal $first */
$first = $transactionGroup->transactionJournals()->first(); $first = $transactionGroup->transactionJournals()->first();
Log::debug( Log::debug(sprintf('Will now update journal #%d (only journal in group #%d)', $first->id, $transactionGroup->id));
sprintf('Will now update journal #%d (only journal in group #%d)', $first->id, $transactionGroup->id)
);
$this->updateTransactionJournal($transactionGroup, $first, reset($transactions)); $this->updateTransactionJournal($transactionGroup, $first, reset($transactions));
$transactionGroup->touch(); $transactionGroup->touch();
$transactionGroup->refresh(); $transactionGroup->refresh();

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Services\Internal\Update; namespace FireflyIII\Services\Internal\Update;
use FireflyIII\Support\Facades\Preferences;
use Carbon\Carbon; use Carbon\Carbon;
use Carbon\Exceptions\InvalidDateException; use Carbon\Exceptions\InvalidDateException;
use Carbon\Exceptions\InvalidFormatException; use Carbon\Exceptions\InvalidFormatException;
@@ -47,6 +46,7 @@ use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Services\Internal\Support\JournalServiceTrait; use FireflyIII\Services\Internal\Support\JournalServiceTrait;
use FireflyIII\Support\Facades\FireflyConfig; use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\NullArrayObject; use FireflyIII\Support\NullArrayObject;
use FireflyIII\Validation\AccountValidator; use FireflyIII\Validation\AccountValidator;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -66,9 +66,11 @@ class JournalUpdateService
private array $data; private array $data;
private ?Account $destinationAccount = null; private ?Account $destinationAccount = null;
private ?Transaction $destinationTransaction = null; private ?Transaction $destinationTransaction = null;
private array $metaDate = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', private array $metaDate
= ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date',
'invoice_date', ]; 'invoice_date', ];
private array $metaString = [ private array $metaString
= [
'sepa_cc', 'sepa_cc',
'sepa_ct_op', 'sepa_ct_op',
'sepa_ct_id', 'sepa_ct_id',
@@ -492,15 +494,7 @@ class JournalUpdateService
Log::debug(sprintf('Create date value from string "%s".', $value)); Log::debug(sprintf('Create date value from string "%s".', $value));
$this->transactionJournal->date_tz = $value->format('e'); $this->transactionJournal->date_tz = $value->format('e');
} }
event( event(new TriggeredAuditLog($this->transactionJournal->user, $this->transactionJournal, sprintf('update_%s', $fieldName), $this->transactionJournal->{$fieldName}, $value));
new TriggeredAuditLog(
$this->transactionJournal->user,
$this->transactionJournal,
sprintf('update_%s', $fieldName),
$this->transactionJournal->{$fieldName}, // @phpstan-ignore-line
$value
)
);
$this->transactionJournal->{$fieldName} = $value; // @phpstan-ignore-line $this->transactionJournal->{$fieldName} = $value; // @phpstan-ignore-line
Log::debug(sprintf('Updated %s', $fieldName)); Log::debug(sprintf('Updated %s', $fieldName));
@@ -671,6 +665,7 @@ class JournalUpdateService
$origSourceTransaction->balance_dirty = true; $origSourceTransaction->balance_dirty = true;
$origSourceTransaction->save(); $origSourceTransaction->save();
$destTransaction = $this->getDestinationTransaction(); $destTransaction = $this->getDestinationTransaction();
$originalAmount = $destTransaction->amount;
$destTransaction->amount = app('steam')->positive($amount); $destTransaction->amount = app('steam')->positive($amount);
$destTransaction->balance_dirty = true; $destTransaction->balance_dirty = true;
$destTransaction->save(); $destTransaction->save();
@@ -678,6 +673,31 @@ class JournalUpdateService
$this->sourceTransaction->refresh(); $this->sourceTransaction->refresh();
$this->destinationTransaction->refresh(); $this->destinationTransaction->refresh();
Log::debug(sprintf('Updated amount to "%s"', $amount)); Log::debug(sprintf('Updated amount to "%s"', $amount));
$group = $this->transactionGroup;
if (null === $group) {
$group = $this->transactionJournal?->transactionGroup;
}
if (null === $group) {
return;
}
event(new TriggeredAuditLog(
$this->transactionGroup->user,
$this->transactionGroup,
'update_amount',
[
'currency_symbol' => $destTransaction->transactionCurrency->symbol,
'decimal_places' => $destTransaction->transactionCurrency->decimal_places,
'amount' => $originalAmount,
],
[
'currency_symbol' => $destTransaction->transactionCurrency->symbol,
'decimal_places' => $destTransaction->transactionCurrency->decimal_places,
'amount' => $value,
]
));
} }
private function updateForeignAmount(): void private function updateForeignAmount(): void

View File

@@ -151,13 +151,7 @@ class Navigation
public function diffInPeriods(string $period, int $skip, Carbon $beginning, Carbon $end): int public function diffInPeriods(string $period, int $skip, Carbon $beginning, Carbon $end): int
{ {
Log::debug(sprintf( Log::debug(sprintf('diffInPeriods: %s (skip: %d), between %s and %s.', $period, $skip, $beginning->format('Y-m-d'), $end->format('Y-m-d')));
'diffInPeriods: %s (skip: %d), between %s and %s.',
$period,
$skip,
$beginning->format('Y-m-d'),
$end->format('Y-m-d')
));
$map = [ $map = [
'daily' => 'diffInDays', 'daily' => 'diffInDays',
'weekly' => 'diffInWeeks', 'weekly' => 'diffInWeeks',
@@ -211,9 +205,14 @@ class Navigation
// Log::debug(sprintf('Now in endOfPeriod("%s", "%s").', $currentEnd->toIso8601String(), $repeatFreq)); // Log::debug(sprintf('Now in endOfPeriod("%s", "%s").', $currentEnd->toIso8601String(), $repeatFreq));
if ('MTD' === $repeatFreq && $end->isFuture()) { if ('MTD' === $repeatFreq && $end->isFuture()) {
// fall back to a monthly schedule if the requested period is MTD. // fall back to a monthly schedule if the requested period is MTD.
Log::debug('endOfPeriod() requests "MTD", set it to "1M" instead.'); Log::debug('endOfPeriod() requests "MTD" + future, set it to "1M" instead.');
$repeatFreq = '1M'; $repeatFreq = '1M';
} }
if ('YTD' === $repeatFreq && $end->isFuture()) {
// fall back to a yearly schedule if the requested period is YTD.
Log::debug('endOfPeriod() requests "YTD" + future, set it to "1Y" instead.');
$repeatFreq = '1Y';
}
$functionMap = [ $functionMap = [
'1D' => 'endOfDay', '1D' => 'endOfDay',

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use Illuminate\Support\Facades\Log;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray; use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject; use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
@@ -33,10 +32,13 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/** /**
* Class ConvertToTransfer * Class ConvertToTransfer
@@ -77,10 +79,8 @@ class ConvertToTransfer implements ActionInterface
$user = $object->user; $user = $object->user;
$journalId = $object->id; $journalId = $object->id;
if (TransactionTypeEnum::TRANSFER->value === $type) { if (TransactionTypeEnum::TRANSFER->value === $type) {
Log::error( Log::error(sprintf('Journal #%d is already a transfer so cannot be converted (rule #%d).', $object->id, $this->action->rule_id));
sprintf('Journal #%d is already a transfer so cannot be converted (rule #%d).', $object->id, $this->action->rule_id) // event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.is_already_transfer')));
);
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.is_already_transfer')));
return false; return false;
} }
@@ -106,15 +106,7 @@ class ConvertToTransfer implements ActionInterface
$opposing = $repository->findByName($accountName, [$expectedType]); $opposing = $repository->findByName($accountName, [$expectedType]);
if (null === $opposing) { if (null === $opposing) {
Log::error( Log::error(sprintf('Journal #%d cannot be converted because no valid %s account with name "%s" exists (rule #%d).', $expectedType, $journalId, $accountName, $this->action->rule_id));
sprintf(
'Journal #%d cannot be converted because no valid %s account with name "%s" exists (rule #%d).',
$expectedType,
$journalId,
$accountName,
$this->action->rule_id
)
);
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_valid_opposing', ['name' => $accountName]))); event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_valid_opposing', ['name' => $accountName])));
return false; return false;
@@ -167,7 +159,7 @@ class ConvertToTransfer implements ActionInterface
return ''; return '';
} }
return (string) $journal->transactions()->where('amount', '<', 0)->first()?->account?->accountType?->type; return (string)$journal->transactions()->where('amount', '<', 0)->first()?->account?->accountType?->type;
} }
private function getDestinationType(int $journalId): string private function getDestinationType(int $journalId): string
@@ -180,7 +172,7 @@ class ConvertToTransfer implements ActionInterface
return ''; return '';
} }
return (string) $journal->transactions()->where('amount', '>', 0)->first()?->account?->accountType?->type; return (string)$journal->transactions()->where('amount', '>', 0)->first()?->account?->accountType?->type;
} }
/** /**
@@ -192,33 +184,57 @@ class ConvertToTransfer implements ActionInterface
*/ */
private function convertWithdrawalArray(TransactionJournal $journal, Account $opposing): bool private function convertWithdrawalArray(TransactionJournal $journal, Account $opposing): bool
{ {
$repository = app(AccountRepositoryInterface::class);
$sourceAccount = $this->getSourceAccount($journal); $sourceAccount = $this->getSourceAccount($journal);
$repository->setUser($sourceAccount->user);
if ($sourceAccount->id === $opposing->id) { if ($sourceAccount->id === $opposing->id) {
Log::error( Log::error(vsprintf('Journal #%d has already has "%s" as a source asset. ConvertToTransfer failed. (rule #%d).', [$journal->id, $opposing->name, $this->action->rule_id]));
vsprintf(
'Journal #%d has already has "%s" as a source asset. ConvertToTransfer failed. (rule #%d).',
[$journal->id, $opposing->name, $this->action->rule_id]
)
);
event(new RuleActionFailedOnObject($this->action, $journal, trans('rules.already_has_source_asset', ['name' => $opposing->name]))); event(new RuleActionFailedOnObject($this->action, $journal, trans('rules.already_has_source_asset', ['name' => $opposing->name])));
return false; return false;
} }
/** @var Transaction $sourceTransaction */
$sourceTransaction = Transaction::where('transaction_journal_id', '=', $journal->id)->where('amount', '<', 0)->first();
/** @var Transaction $destTransaction */
$destTransaction = Transaction::where('transaction_journal_id', '=', $journal->id)->where('amount', '>', 0)->first();
// update destination transaction: // update destination transaction:
DB::table('transactions') $destTransaction->account_id = $opposing->id;
->where('transaction_journal_id', '=', $journal->id) $destTransaction->save();
->where('amount', '>', 0)
->update(['account_id' => $opposing->id]) // check if the currencies are a match.
; /** @var TransactionCurrency $sourceCurrency */
$sourceCurrency = $repository->getAccountCurrency($sourceAccount);
/** @var TransactionCurrency $destCurrency */
$destCurrency = $repository->getAccountCurrency($opposing);
// if the currencies do not match, need to be smart about the involved amounts:
if ($sourceCurrency->id !== $destCurrency->id) {
Log::debug(sprintf('Accounts have different currencies. Source has %s, dest has %s', $sourceCurrency->code, $destCurrency->code));
$foreignAmount = '' === (string)$sourceTransaction->foreign_amount ? $sourceTransaction->amount : $sourceTransaction->foreign_amount;
Log::debug(sprintf('Foreign amount: %s', $foreignAmount));
// source transaction: set the foreign currency ID and leave as is.
$sourceTransaction->foreign_currency_id = $destCurrency->id;
$sourceTransaction->foreign_amount = Steam::negative($foreignAmount);
$sourceTransaction->save();
Log::debug(sprintf('Set source transaction #%d foreign currency ID to #%d (amount: %s)', $sourceTransaction->id, $destCurrency->id, $foreignAmount));
// dest transaction: set reverse amounts and currency IDs from source transaction.
$destTransaction->foreign_currency_id = $sourceCurrency->transaction_currency_id;
$destTransaction->transaction_currency_id = $sourceTransaction->foreign_currency_id;
$destTransaction->amount = Steam::positive($foreignAmount);
$destTransaction->foreign_amount = Steam::positive($sourceTransaction->amount);
$destTransaction->save();
Log::debug(sprintf('Set dest transaction #%d to #%d %s and foreign #%d %s', $destTransaction->id, $destTransaction->transaction_currency_id, $destTransaction->amount, $destTransaction->foreign_currency_id, $destTransaction->foreign_amount));
}
// change transaction type of journal: // change transaction type of journal:
$newType = TransactionType::whereType(TransactionTypeEnum::TRANSFER->value)->first(); $newType = TransactionType::whereType(TransactionTypeEnum::TRANSFER->value)->first();
DB::table('transaction_journals') DB::table('transaction_journals')->where('id', '=', $journal->id)->update(['transaction_type_id' => $newType->id, 'bill_id' => null]);
->where('id', '=', $journal->id)
->update(['transaction_type_id' => $newType->id, 'bill_id' => null])
;
Log::debug('Converted withdrawal to transfer.'); Log::debug('Converted withdrawal to transfer.');

View File

@@ -3,7 +3,38 @@
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.4.9 - 2025-11-xx ## v6.4.12 - 2025-12-17
### Fixed
- [Issue 11368](https://github.com/firefly-iii/firefly-iii/issues/11368) (Attempt to read property "user" on null) reported by @simonwiles
- [Issue 11367](https://github.com/firefly-iii/firefly-iii/issues/11367) (Expenses page has incorrect summary values) reported by @purplemeteorite
## v6.4.11 - 2025-12-16
### Fixed
- [Issue 11356](https://github.com/firefly-iii/firefly-iii/issues/11356) (Dashboard - Budget - Left To Spend "Per day" shows total budget value) reported by @lucasarrudadev
- [Issue 11357](https://github.com/firefly-iii/firefly-iii/issues/11357) (Firefly III v6.4.10 ran into an error: Undefined variable $uploadDir.) reported by @jgmm81
## v6.4.10 - 2025-12-15
### Added
- Added amount event audit log
### Fixed
- [Issue 11328](https://github.com/firefly-iii/firefly-iii/issues/11328) (Three budget / account display bugs in latest version (annual budget + account list balance)) reported by @qingxianaaa
- [Issue 11329](https://github.com/firefly-iii/firefly-iii/issues/11329) (Imported and auto-converted transfer from different currency issue) reported by @bozho
- [Issue 11333](https://github.com/firefly-iii/firefly-iii/issues/11333) (Prepared statement contains too many placeholders) reported by @wendyliga
- [Issue 11313](https://github.com/firefly-iii/firefly-iii/issues/11313) (Stop Processing and Executing Rule Group on Existing Transaction) reported by @watertrainer
- [Discussion 11323](https://github.com/orgs/firefly-iii/discussions/11323) (File ownership problem) started by @enboig
- [Issue 11337](https://github.com/firefly-iii/firefly-iii/issues/11337) (email notifications are sent to old email address after changing it through the web UI) reported by @xsolinsx
- [Issue 11346](https://github.com/firefly-iii/firefly-iii/issues/11346) (Running balance restart from zero for no reason) reported by @Arkarr
- [Issue 11310](https://github.com/firefly-iii/firefly-iii/issues/11310) (Period parameter doesn't work in API) reported by @kvdb06
## 6.4.9 - 2025-11-28
### Fixed ### Fixed

View File

@@ -107,9 +107,9 @@
"spatie/laravel-html": "^3.2", "spatie/laravel-html": "^3.2",
"spatie/laravel-ignition": "^2", "spatie/laravel-ignition": "^2",
"spatie/period": "^2.4", "spatie/period": "^2.4",
"symfony/expression-language": "^7.0", "symfony/expression-language": "^8.0",
"symfony/http-client": "^7.1", "symfony/http-client": "^8.0",
"symfony/mailgun-mailer": "^7.1", "symfony/mailgun-mailer": "^8.0",
"thecodingmachine/safe": "^3.1" "thecodingmachine/safe": "^3.1"
}, },
"require-dev": { "require-dev": {

539
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -78,8 +78,8 @@ 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-12-01', 'version' => '6.4.12',
'build_time' => 1764560154, 'build_time' => 1765862590,
'api_version' => '2.1.0', // field is no longer used. 'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used. 'db_version' => 28, // field is no longer used.

816
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,5 +8,8 @@
], ],
"devDependencies": { "devDependencies": {
"postcss": "^8.4.47" "postcss": "^8.4.47"
},
"dependencies": {
"patch-package": "^8.0.1"
} }
} }

View File

@@ -1,10 +1,8 @@
diff --git a/node_modules/admin-lte/src/scss/_app-sidebar.scss b/node_modules/admin-lte/src/scss/_app-sidebar.scss diff --git a/node_modules/admin-lte/src/scss/_app-sidebar.scss b/node_modules/admin-lte/src/scss/_app-sidebar.scss
old mode 100644 index 4420bd0..35da532
new mode 100755
index 69dfc16..dc341eb
--- a/node_modules/admin-lte/src/scss/_app-sidebar.scss --- a/node_modules/admin-lte/src/scss/_app-sidebar.scss
+++ b/node_modules/admin-lte/src/scss/_app-sidebar.scss +++ b/node_modules/admin-lte/src/scss/_app-sidebar.scss
@@ -577,7 +577,6 @@ body:not(.app-loaded) { @@ -599,7 +599,6 @@ body:not(.app-loaded) {
@if $enable-dark-mode { @if $enable-dark-mode {
@include color-mode(dark) { @include color-mode(dark) {

View File

@@ -7,7 +7,7 @@
"administration_currency_form_help": "It may take a long time for the page to load if you change the primary currency because transaction may need to be converted to your (new) primary currency.", "administration_currency_form_help": "It may take a long time for the page to load if you change the primary currency because transaction may need to be converted to your (new) primary currency.",
"administrations_page_edit_sub_title_js": "Edit financial administration \"{title}\"", "administrations_page_edit_sub_title_js": "Edit financial administration \"{title}\"",
"table": "Tabel", "table": "Tabel",
"welcome_back": "Ce se red\u0103?", "welcome_back": "Situa\u021bia ta financiar\u0103",
"flash_error": "Eroare!", "flash_error": "Eroare!",
"flash_warning": "Avertizare!", "flash_warning": "Avertizare!",
"flash_success": "Succes!", "flash_success": "Succes!",

View File

@@ -366,13 +366,21 @@
</span> </span>
<br/> <br/>
{% endif %} {% endif %}
{% if spentInfo.currency_id == budgetLimit.currency_id and not budgetLimit.in_range %} {% if spentInfo.currency_id == budgetLimit.currency_id and not budgetLimit.in_range and 0.0 == budgetLimit.total_days %}
<span class="left_span" data-currency="{{ spentInfo.currency_id }}" data-limit="{{ budgetLimit.id }}" <span class="left_span" data-currency="{{ spentInfo.currency_id }}" data-limit="{{ budgetLimit.id }}"
data-value="{{ spentInfo.spent + budgetLimit.amount }}" class="amount_left"> data-value="{{ spentInfo.spent + budgetLimit.amount }}" class="amount_left">
{{ formatAmountBySymbol(spentInfo.spent + budgetLimit.amount, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }} {{ formatAmountBySymbol(spentInfo.spent + budgetLimit.amount, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }}
</span> </span>
<span class="text-muted">({{ 'unknown'|_ }})</span> <span class="text-muted">({{ 'unknown'|_ }})</span>
{% endif %} {% endif %}
{% if spentInfo.currency_id == budgetLimit.currency_id and not budgetLimit.in_range and 0.0 != budgetLimit.total_days %}
<span class="left_span" data-currency="{{ spentInfo.currency_id }}" data-limit="{{ budgetLimit.id }}"
data-value="{{ spentInfo.spent + budgetLimit.amount }}" class="amount_left">
{{ formatAmountBySymbol(spentInfo.spent + budgetLimit.amount, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }}
</span>
({{ formatAmountBySymbol((spentInfo.spent + budgetLimit.amount) / budgetLimit.total_days, spentInfo.currency_symbol, spentInfo.currency_decimal_places) }})
{% endif %}
{% endfor %} {% endfor %}
{% if countLimit == 0 %} {% if countLimit == 0 %}

View File

@@ -277,22 +277,37 @@
{% endif %} {% endif %}
{% elseif transaction.transaction_type_type == 'Withdrawal' %} {% elseif transaction.transaction_type_type == 'Withdrawal' %}
{# withdrawal into a liability #}
{% if 'Loan' == transaction.destination_account_type or 'Mortgage' == transaction.destination_account_type or 'Debt' == transaction.destination_account_type %} {% if 'Loan' == transaction.destination_account_type or 'Mortgage' == transaction.destination_account_type or 'Debt' == transaction.destination_account_type %}
{% if currency.id == transaction.currency_id %} {% if currency.id == transaction.currency_id %}
{% if account.id == transaction.source_account_id %}
{{ formatAmountBySymbol(transaction.source_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }}
{% elseif account.id == transaction.destination_account_id %}
{{ formatAmountBySymbol(transaction.destination_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }} {{ formatAmountBySymbol(transaction.destination_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }}
{% else %}
-
{% endif %}
{% endif %} {% endif %}
{% if currency.id == transaction.foreign_currency_id and null != transaction.destination_balance_after and null != transaction.destination_balance_after %} {% if currency.id == transaction.foreign_currency_id and null != transaction.destination_balance_after and null != transaction.destination_balance_after %}
{{ formatAmountBySymbol(transaction.destination_balance_after, transaction.foreign_currency_symbol ?? transaction.currency_symbol, transaction.foreign_currency_decimal_places ?? transaction.currency_decimal_places) }} {{ formatAmountBySymbol(transaction.destination_balance_after, transaction.foreign_currency_symbol ?? transaction.currency_symbol, transaction.foreign_currency_decimal_places ?? transaction.currency_decimal_places) }}
{% endif %} {% endif %}
{# withdrawal into an expense account #}
{% else %} {% else %}
{% if account.id == transaction.source_account_id %}
{{ formatAmountBySymbol(transaction.source_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }} {{ formatAmountBySymbol(transaction.source_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }}
{% endif %} {% elseif account.id == transaction.destination_account_id %}
{% elseif transaction.transaction_type_type == 'Opening balance' %}
{% if transaction.source_account_type == 'Initial balance account' %}
{{ formatAmountBySymbol(transaction.destination_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }} {{ formatAmountBySymbol(transaction.destination_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }}
{% else %} {% else %}
-
{% endif %}
{% endif %}
{% elseif transaction.transaction_type_type == 'Opening balance' %}
{% if account.id == transaction.source_account_id %}
{{ formatAmountBySymbol(transaction.destination_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }}
{% elseif account.id == transaction.destination_account_id %}
{{ formatAmountBySymbol(transaction.source_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }} {{ formatAmountBySymbol(transaction.source_balance_after, transaction.currency_symbol, transaction.currency_decimal_places) }}
{% else %}
-
{% endif %} {% endif %}
{% elseif transaction.transaction_type_type == 'Transfer' %} {% elseif transaction.transaction_type_type == 'Transfer' %}
{% if account.id == transaction.source_account_id %} {% if account.id == transaction.source_account_id %}

View File

@@ -27,7 +27,6 @@ namespace Tests\unit\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Bimonthly; use FireflyIII\Support\Calendar\Periodicity\Bimonthly;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Support\Calendar\Periodicity; use FireflyIII\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Interval;
/** /**
* @group unit-test * @group unit-test
@@ -41,7 +40,7 @@ use FireflyIII\Support\Calendar\Periodicity\Interval;
*/ */
final class BimonthlyTest extends IntervalTestCase final class BimonthlyTest extends IntervalTestCase
{ {
public static function factory(): Interval public static function factory(): Bimonthly
{ {
return new Bimonthly(); return new Bimonthly();
} }

View File

@@ -27,7 +27,6 @@ namespace Tests\unit\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Daily; use FireflyIII\Support\Calendar\Periodicity\Daily;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Support\Calendar\Periodicity; use FireflyIII\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Interval;
/** /**
* @group unit-test * @group unit-test
@@ -41,7 +40,7 @@ use FireflyIII\Support\Calendar\Periodicity\Interval;
*/ */
final class DailyTest extends IntervalTestCase final class DailyTest extends IntervalTestCase
{ {
public static function factory(): Interval public static function factory(): Daily
{ {
return new Daily(); return new Daily();
} }

View File

@@ -27,7 +27,6 @@ namespace Tests\unit\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Fortnightly; use FireflyIII\Support\Calendar\Periodicity\Fortnightly;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Support\Calendar\Periodicity; use FireflyIII\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Interval;
/** /**
* @group unit-test * @group unit-test
@@ -41,7 +40,7 @@ use FireflyIII\Support\Calendar\Periodicity\Interval;
*/ */
final class FortnightlyTest extends IntervalTestCase final class FortnightlyTest extends IntervalTestCase
{ {
public static function factory(): Interval public static function factory(): Fortnightly
{ {
return new Fortnightly(); return new Fortnightly();
} }

View File

@@ -27,7 +27,6 @@ namespace Tests\unit\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\HalfYearly; use FireflyIII\Support\Calendar\Periodicity\HalfYearly;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Support\Calendar\Periodicity; use FireflyIII\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Interval;
/** /**
* @group unit-test * @group unit-test
@@ -41,7 +40,7 @@ use FireflyIII\Support\Calendar\Periodicity\Interval;
*/ */
final class HalfYearlyTest extends IntervalTestCase final class HalfYearlyTest extends IntervalTestCase
{ {
public static function factory(): Interval public static function factory(): HalfYearly
{ {
return new HalfYearly(); return new HalfYearly();
} }

View File

@@ -27,7 +27,6 @@ namespace Tests\unit\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Monthly; use FireflyIII\Support\Calendar\Periodicity\Monthly;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Support\Calendar\Periodicity; use FireflyIII\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Interval;
/** /**
* @group unit-test * @group unit-test
@@ -41,7 +40,7 @@ use FireflyIII\Support\Calendar\Periodicity\Interval;
*/ */
final class MonthlyTest extends IntervalTestCase final class MonthlyTest extends IntervalTestCase
{ {
public static function factory(): Interval public static function factory(): Monthly
{ {
return new Monthly(); return new Monthly();
} }

View File

@@ -27,7 +27,6 @@ namespace Tests\unit\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Quarterly; use FireflyIII\Support\Calendar\Periodicity\Quarterly;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Support\Calendar\Periodicity; use FireflyIII\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Interval;
/** /**
* @group unit-test * @group unit-test
@@ -41,7 +40,7 @@ use FireflyIII\Support\Calendar\Periodicity\Interval;
*/ */
final class QuarterlyTest extends IntervalTestCase final class QuarterlyTest extends IntervalTestCase
{ {
public static function factory(): Interval public static function factory(): Quarterly
{ {
return new Quarterly(); return new Quarterly();
} }

View File

@@ -27,7 +27,6 @@ namespace Tests\unit\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Weekly; use FireflyIII\Support\Calendar\Periodicity\Weekly;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Support\Calendar\Periodicity; use FireflyIII\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Interval;
/** /**
* @group unit-test * @group unit-test
@@ -41,7 +40,7 @@ use FireflyIII\Support\Calendar\Periodicity\Interval;
*/ */
final class WeeklyTest extends IntervalTestCase final class WeeklyTest extends IntervalTestCase
{ {
public static function factory(): Interval public static function factory(): Weekly
{ {
return new Weekly(); return new Weekly();
} }

View File

@@ -27,7 +27,6 @@ namespace Tests\unit\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Yearly; use FireflyIII\Support\Calendar\Periodicity\Yearly;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Support\Calendar\Periodicity; use FireflyIII\Support\Calendar\Periodicity;
use FireflyIII\Support\Calendar\Periodicity\Interval;
/** /**
* @group unit-test * @group unit-test
@@ -41,7 +40,7 @@ use FireflyIII\Support\Calendar\Periodicity\Interval;
*/ */
final class YearlyTest extends IntervalTestCase final class YearlyTest extends IntervalTestCase
{ {
public static function factory(): Interval public static function factory(): Yearly
{ {
return new Yearly(); return new Yearly();
} }