mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-08-24 14:04:06 +00:00
Compare commits
87 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
67d29b8416 | ||
|
f62e93b487 | ||
|
a7cc70b975 | ||
|
60f0d8074a | ||
|
ed1fdf9382 | ||
|
9ea3c4224e | ||
|
71325de44e | ||
|
cdb041e647 | ||
|
b9d750bf59 | ||
|
461249737e | ||
|
1aeaa8b77d | ||
|
a59d7ccdc2 | ||
|
2c1ca428db | ||
|
224970f3bd | ||
|
742d934ddb | ||
|
1699513023 | ||
|
488a8a7e86 | ||
|
dd571d6221 | ||
|
4cc5128b4c | ||
|
2636a6557a | ||
|
0bf97ccf22 | ||
|
592fc71b4e | ||
|
0e7712d3b8 | ||
|
80f21d2a4f | ||
|
5513ec068e | ||
|
14a46a6197 | ||
|
b93ee5efd8 | ||
|
cdd4dc6065 | ||
|
0d8b2ae799 | ||
|
77dc79b638 | ||
|
f48723db40 | ||
|
ebf91078c5 | ||
|
90d0d85dd6 | ||
|
0c5b4f7f64 | ||
|
9c4bb08ed1 | ||
|
1d3bbde4b0 | ||
|
b6faee033d | ||
|
05e0f88d11 | ||
|
ae9a151140 | ||
|
da633e3c62 | ||
|
8cb384d3cf | ||
|
de2a34c3ec | ||
|
b7c65446a8 | ||
|
bc648b187c | ||
|
4de0828b5d | ||
|
b2364d26ec | ||
|
83d94cb792 | ||
|
66cc3f48bc | ||
|
63297c43b7 | ||
|
5b0637558f | ||
|
e9a8e104be | ||
|
0f524e7800 | ||
|
969e0bccc9 | ||
|
ba3e026927 | ||
|
0c6868d477 | ||
|
7f70cf47ec | ||
|
fa4492287d | ||
|
60809c688e | ||
|
2404f5299c | ||
|
21a394eaf5 | ||
|
419d7846c9 | ||
|
0827accc39 | ||
|
2e53f7d0b7 | ||
|
bdfcf8ec95 | ||
|
6a20170e00 | ||
|
0c974f1ff7 | ||
|
9c098d45c5 | ||
|
cfdf9aa8dc | ||
|
2ea74542e6 | ||
|
7fcaa2b5fb | ||
|
e9e905e495 | ||
|
f67ff98d78 | ||
|
e3c4dde4ff | ||
|
9787561000 | ||
|
cd041b4c75 | ||
|
60ee70c926 | ||
|
00de78b6f1 | ||
|
33a841b831 | ||
|
df66dcf102 | ||
|
086a7a0b1e | ||
|
ec0ba3d212 | ||
|
b0ab06b7eb | ||
|
965acd6d45 | ||
|
4d156870ef | ||
|
499720df46 | ||
|
610bc108e7 | ||
|
53f1b0218c |
338
.ci/php-cs-fixer/composer.lock
generated
338
.ci/php-cs-fixer/composer.lock
generated
@@ -79,16 +79,16 @@
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "3.3.2",
|
||||
"version": "3.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/semver.git",
|
||||
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
|
||||
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
|
||||
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
|
||||
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -138,9 +138,9 @@
|
||||
"versioning"
|
||||
],
|
||||
"support": {
|
||||
"irc": "irc://irc.freenode.org/composer",
|
||||
"irc": "ircs://irc.libera.chat:6697/composer",
|
||||
"issues": "https://github.com/composer/semver/issues",
|
||||
"source": "https://github.com/composer/semver/tree/3.3.2"
|
||||
"source": "https://github.com/composer/semver/tree/3.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -156,7 +156,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-04-01T19:23:25+00:00"
|
||||
"time": "2023-08-31T09:50:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/xdebug-handler",
|
||||
@@ -224,178 +224,23 @@
|
||||
],
|
||||
"time": "2022-02-25T21:32:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/annotations.git",
|
||||
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
|
||||
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/lexer": "^2 || ^3",
|
||||
"ext-tokenizer": "*",
|
||||
"php": "^7.2 || ^8.0",
|
||||
"psr/cache": "^1 || ^2 || ^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/cache": "^2.0",
|
||||
"doctrine/coding-standard": "^10",
|
||||
"phpstan/phpstan": "^1.8.0",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"symfony/cache": "^5.4 || ^6",
|
||||
"vimeo/psalm": "^4.10"
|
||||
},
|
||||
"suggest": {
|
||||
"php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Docblock Annotations Parser",
|
||||
"homepage": "https://www.doctrine-project.org/projects/annotations.html",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"docblock",
|
||||
"parser"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/annotations/issues",
|
||||
"source": "https://github.com/doctrine/annotations/tree/2.0.1"
|
||||
},
|
||||
"time": "2023-02-02T22:02:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/lexer.git",
|
||||
"reference": "84a527db05647743d50373e0ec53a152f2cde568"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568",
|
||||
"reference": "84a527db05647743d50373e0ec53a152f2cde568",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^10",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/plugin-phpunit": "^0.18.3",
|
||||
"vimeo/psalm": "^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Lexer\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
|
||||
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"docblock",
|
||||
"lexer",
|
||||
"parser",
|
||||
"php"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/lexer/issues",
|
||||
"source": "https://github.com/doctrine/lexer/tree/3.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpdoctrine",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-15T16:57:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.22.0",
|
||||
"version": "v3.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "92b019f6c8d79aa26349d0db7671d37440dc0ff3"
|
||||
"reference": "9025b7d2b6e1d90a63d0ac0905018ce5d03ec88d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/92b019f6c8d79aa26349d0db7671d37440dc0ff3",
|
||||
"reference": "92b019f6c8d79aa26349d0db7671d37440dc0ff3",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/9025b7d2b6e1d90a63d0ac0905018ce5d03ec88d",
|
||||
"reference": "9025b7d2b6e1d90a63d0ac0905018ce5d03ec88d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/semver": "^3.3",
|
||||
"composer/xdebug-handler": "^3.0.3",
|
||||
"doctrine/annotations": "^2",
|
||||
"doctrine/lexer": "^2 || ^3",
|
||||
"ext-json": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"php": "^7.4 || ^8.0",
|
||||
@@ -464,7 +309,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.22.0"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.25.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -472,56 +317,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-16T23:08:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/cache.git",
|
||||
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
|
||||
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Cache\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for caching libraries",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"psr",
|
||||
"psr-6"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/cache/tree/3.0.0"
|
||||
},
|
||||
"time": "2021-02-03T23:26:27+00:00"
|
||||
"time": "2023-08-31T21:27:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
@@ -745,16 +541,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v6.3.2",
|
||||
"version": "v6.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898"
|
||||
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/aa5d64ad3f63f2e48964fc81ee45cb318a723898",
|
||||
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6",
|
||||
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -815,7 +611,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v6.3.2"
|
||||
"source": "https://github.com/symfony/console/tree/v6.3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -831,7 +627,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-19T20:17:28+00:00"
|
||||
"time": "2023-08-16T10:10:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
@@ -1252,16 +1048,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
|
||||
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
|
||||
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
|
||||
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1276,7 +1072,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1314,7 +1110,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1330,20 +1126,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
"reference": "511a08c03c1960e08a883f4cffcacd219b758354"
|
||||
"reference": "875e90aeea2777b6f135677f618529449334a612"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
|
||||
"reference": "511a08c03c1960e08a883f4cffcacd219b758354",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
|
||||
"reference": "875e90aeea2777b6f135677f618529449334a612",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1355,7 +1151,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1395,7 +1191,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1411,20 +1207,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
|
||||
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
|
||||
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
|
||||
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1436,7 +1232,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1479,7 +1275,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1495,20 +1291,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1523,7 +1319,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1562,7 +1358,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1578,20 +1374,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-07-28T09:04:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
|
||||
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
|
||||
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
|
||||
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1600,7 +1396,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1645,7 +1441,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1661,20 +1457,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a"
|
||||
"reference": "7581cd600fa9fd681b797d00b02f068e2f13263b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a",
|
||||
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b",
|
||||
"reference": "7581cd600fa9fd681b797d00b02f068e2f13263b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1683,7 +1479,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1724,7 +1520,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1740,20 +1536,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v6.3.2",
|
||||
"version": "v6.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "c5ce962db0d9b6e80247ca5eb9af6472bd4d7b5d"
|
||||
"reference": "0b5c29118f2e980d455d2e34a5659f4579847c54"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/c5ce962db0d9b6e80247ca5eb9af6472bd4d7b5d",
|
||||
"reference": "c5ce962db0d9b6e80247ca5eb9af6472bd4d7b5d",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/0b5c29118f2e980d455d2e34a5659f4579847c54",
|
||||
"reference": "0b5c29118f2e980d455d2e34a5659f4579847c54",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1785,7 +1581,7 @@
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v6.3.2"
|
||||
"source": "https://github.com/symfony/process/tree/v6.3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1801,7 +1597,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-12T16:00:22+00:00"
|
||||
"time": "2023-08-07T10:39:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
|
32
.env.example
32
.env.example
@@ -45,12 +45,6 @@ TRUSTED_PROXIES=
|
||||
# Default setting 'stack' will log to 'daily' and to 'stdout' at the same time.
|
||||
LOG_CHANNEL=stack
|
||||
|
||||
#
|
||||
# Used when logging to papertrail:
|
||||
#
|
||||
PAPERTRAIL_HOST=
|
||||
PAPERTRAIL_PORT=
|
||||
|
||||
# Log level. You can set this from least severe to most severe:
|
||||
# debug, info, notice, warning, error, critical, alert, emergency
|
||||
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
|
||||
@@ -58,8 +52,30 @@ PAPERTRAIL_PORT=
|
||||
APP_LOG_LEVEL=notice
|
||||
|
||||
# Audit log level.
|
||||
# Set this to "emergency" if you dont want to store audit logs, leave on info otherwise.
|
||||
AUDIT_LOG_LEVEL=info
|
||||
# The audit log is used to log notable Firefly III events on a separate channel.
|
||||
# These log entries may contain sensitive financial information.
|
||||
# The audit log is disabled by default.
|
||||
#
|
||||
# To enable it, set AUDIT_LOG_LEVEL to "info"
|
||||
# To disable it, set AUDIT_LOG_LEVEL to "emergency"
|
||||
AUDIT_LOG_LEVEL=emergency
|
||||
|
||||
#
|
||||
# If you want, you can redirect the audit logs to another channel.
|
||||
# Set 'audit_stdout', 'audit_syslog', 'audit_errorlog' to log to the system itself.
|
||||
# Use audit_daily to log to a rotating file.
|
||||
# Use audit_papertrail to log to papertrail.
|
||||
#
|
||||
# If you do this, the audit logs may be mixed with normal logs because the settings for these channels
|
||||
# are often the same as the settings for the normal logs.
|
||||
AUDIT_LOG_CHANNEL=
|
||||
|
||||
#
|
||||
# Used when logging to papertrail:
|
||||
# Also used when audit logs log to papertrail:
|
||||
#
|
||||
PAPERTRAIL_HOST=
|
||||
PAPERTRAIL_PORT=
|
||||
|
||||
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
|
||||
# For other database types, please see the FAQ: https://docs.firefly-iii.org/firefly-iii/faq/self-hosted/#i-want-to-use-sqlite
|
||||
|
@@ -102,6 +102,7 @@ abstract class Controller extends BaseController
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field));
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$value = null;
|
||||
}
|
||||
$obj = null;
|
||||
@@ -130,6 +131,7 @@ abstract class Controller extends BaseController
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $integer));
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$value = null;
|
||||
}
|
||||
if (null !== $value) {
|
||||
@@ -154,6 +156,7 @@ abstract class Controller extends BaseController
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error('Request field "sort" contains a non-scalar value. Value set to NULL.');
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$param = '';
|
||||
}
|
||||
if ('' === $param) {
|
||||
|
@@ -99,6 +99,7 @@ class Controller extends BaseController
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field));
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
if (null !== $date) {
|
||||
try {
|
||||
|
@@ -24,7 +24,9 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V2\Controllers\Model\Bill;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Repositories\Administration\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Transformers\V2\AccountTransformer;
|
||||
use FireflyIII\Transformers\V2\BillTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -71,4 +73,17 @@ class ShowController extends Controller
|
||||
->json($this->jsonApiList('subscriptions', $paginator, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO this endpoint is not documented
|
||||
*/
|
||||
public function show(Request $request, Bill $bill): JsonResponse
|
||||
{
|
||||
$transformer = new BillTransformer();
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
return response()
|
||||
->api($this->jsonApiObject('subscriptions', $bill, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
}
|
||||
|
45
app/Api/V2/Controllers/Model/Transaction/StoreController.php
Normal file
45
app/Api/V2/Controllers/Model/Transaction/StoreController.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* StoreController.php
|
||||
* Copyright (c) 2023 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\Api\V2\Controllers\Model\Transaction;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class StoreController
|
||||
*/
|
||||
class StoreController extends Controller
|
||||
{
|
||||
/**
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function post(): JsonResponse
|
||||
{
|
||||
|
||||
return response()->json([]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -105,10 +105,6 @@ class BasicController extends Controller
|
||||
$end = $this->parameters->get('end');
|
||||
|
||||
// balance information:
|
||||
$balanceData = [];
|
||||
$billData = [];
|
||||
$spentData = [];
|
||||
$netWorthData = [];
|
||||
$balanceData = $this->getBalanceInformation($start, $end);
|
||||
$billData = $this->getBillInformation($start, $end);
|
||||
$spentData = $this->getLeftToSpendInfo($start, $end);
|
||||
@@ -127,9 +123,15 @@ class BasicController extends Controller
|
||||
private function getBalanceInformation(Carbon $start, Carbon $end): array
|
||||
{
|
||||
// prep some arrays:
|
||||
$incomes = [];
|
||||
$expenses = [];
|
||||
$sums = [];
|
||||
$incomes = [
|
||||
'native' => '0',
|
||||
];
|
||||
$expenses = [
|
||||
'native' => '0',
|
||||
];
|
||||
$sums = [
|
||||
'native' => '0',
|
||||
];
|
||||
$return = [];
|
||||
$currencies = [];
|
||||
$converter = new ExchangeRateConverter();
|
||||
@@ -354,6 +356,7 @@ class BasicController extends Controller
|
||||
*/
|
||||
private function getLeftToSpendInfo(Carbon $start, Carbon $end): array
|
||||
{
|
||||
app('log')->debug('Now in getLeftToSpendInfo');
|
||||
$return = [];
|
||||
$today = today(config('app.timezone'));
|
||||
$available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
|
||||
@@ -367,7 +370,7 @@ class BasicController extends Controller
|
||||
$nativeLeft = [
|
||||
'key' => 'left-to-spend-in-native',
|
||||
'value' => '0',
|
||||
'currency_id' => (int)$default->id,
|
||||
'currency_id' => (string)$default->id,
|
||||
'currency_code' => $default->code,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_decimal_places' => (int)$default->decimal_places,
|
||||
@@ -375,7 +378,7 @@ class BasicController extends Controller
|
||||
$nativePerDay = [
|
||||
'key' => 'left-per-day-to-spend-in-native',
|
||||
'value' => '0',
|
||||
'currency_id' => (int)$default->id,
|
||||
'currency_id' => (string)$default->id,
|
||||
'currency_code' => $default->code,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_decimal_places' => (int)$default->decimal_places,
|
||||
@@ -386,17 +389,20 @@ class BasicController extends Controller
|
||||
* @var array $row
|
||||
*/
|
||||
foreach ($spent as $currencyId => $row) {
|
||||
app('log')->debug(sprintf('Processing spent array in currency #%d', $currencyId));
|
||||
$currencyId = (int)$currencyId;
|
||||
$spent = '0';
|
||||
$spentNative = '0';
|
||||
// get the sum from the array of transactions (double loop but who cares)
|
||||
/** @var array $budget */
|
||||
foreach ($row['budgets'] as $budget) {
|
||||
app('log')->debug(sprintf('Processing expenses in budget "%s".', $budget['name']));
|
||||
/** @var array $journal */
|
||||
foreach ($budget['transaction_journals'] as $journal) {
|
||||
$journalCurrencyId = $journal['currency_id'];
|
||||
$currency = $currencies[$journalCurrencyId] ?? $this->currencyRepos->find($journalCurrencyId);
|
||||
$currencies[$currencyId] = $currency;
|
||||
$amount = bcmul($journal['amount'], '-1');
|
||||
$amount = app('steam')->negative($journal['amount']);
|
||||
$amountNative = $converter->convert($default, $currency, $start, $amount);
|
||||
if ((int)$journal['foreign_currency_id'] === (int)$default->id) {
|
||||
$amountNative = $journal['foreign_amount'];
|
||||
@@ -404,15 +410,18 @@ class BasicController extends Controller
|
||||
$spent = bcadd($spent, $amount);
|
||||
$spentNative = bcadd($spentNative, $amountNative);
|
||||
}
|
||||
app('log')->debug(sprintf('Total spent in budget "%s" is %s', $budget['name'], $spent));
|
||||
}
|
||||
|
||||
// either an amount was budgeted or 0 is available.
|
||||
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
|
||||
$currencies[$currencyId] = $currency;
|
||||
$amount = $available[$currencyId]['amount'] ?? '0';
|
||||
$amountNative = $converter->convert($default, $currency, $start, $amount);
|
||||
$amountNative = $available[$currencyId]['native_amount'] ?? '0';
|
||||
$left = bcadd($amount, $spent);
|
||||
$leftNative = bcadd($amountNative, $spentNative);
|
||||
app('log')->debug(sprintf('Available amount is %s', $amount));
|
||||
app('log')->debug(sprintf('Amount left is %s', $left));
|
||||
|
||||
// how much left per day?
|
||||
$days = $today->diffInDays($end) + 1;
|
||||
@@ -429,10 +438,10 @@ class BasicController extends Controller
|
||||
$return[] = [
|
||||
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
|
||||
'value' => $left,
|
||||
'currency_id' => $row['currency_id'],
|
||||
'currency_id' => (string)$row['currency_id'],
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_symbol' => $row['currency_symbol'],
|
||||
'currency_decimal_places' => $row['currency_decimal_places'],
|
||||
'currency_decimal_places' => (int)$row['currency_decimal_places'],
|
||||
];
|
||||
// left (native)
|
||||
$nativeLeft['value'] = $leftNative;
|
||||
@@ -441,10 +450,10 @@ class BasicController extends Controller
|
||||
$return[] = [
|
||||
'key' => sprintf('left-per-day-to-spend-in-%s', $row['currency_code']),
|
||||
'value' => $perDay,
|
||||
'currency_id' => $row['currency_id'],
|
||||
'currency_id' => (string)$row['currency_id'],
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_symbol' => $row['currency_symbol'],
|
||||
'currency_decimal_places' => $row['currency_decimal_places'],
|
||||
'currency_decimal_places' => (int)$row['currency_decimal_places'],
|
||||
];
|
||||
|
||||
// left per day (native)
|
||||
|
@@ -42,7 +42,7 @@ class BalanceChartRequest extends FormRequest
|
||||
{
|
||||
return [
|
||||
'accounts' => $this->getAccountList(),
|
||||
'period' => $this->string('period'),
|
||||
'period' => $this->convertString('period'),
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -34,6 +34,7 @@ use FireflyIII\Models\PiggyBankRepetition;
|
||||
use FireflyIII\Models\RecurrenceTransaction;
|
||||
use FireflyIII\Models\RuleTrigger;
|
||||
use Illuminate\Console\Command;
|
||||
use ValueError;
|
||||
|
||||
/**
|
||||
* Class ReportSkeleton
|
||||
@@ -247,7 +248,16 @@ class CorrectAmounts extends Command
|
||||
/** @var RuleTrigger $item */
|
||||
foreach ($set as $item) {
|
||||
// basic check:
|
||||
if (-1 === bccomp((string)$item->trigger_value, '0')) {
|
||||
$check = 0;
|
||||
try {
|
||||
$check = bccomp((string)$item->trigger_value, '0');
|
||||
} catch (ValueError $e) {
|
||||
$this->friendlyError(sprintf('Rule #%d contained invalid %s-trigger "%s". The trigger has been removed, and the rule is disabled.', $item->rule_id, $item->trigger_type, $item->trigger_value));
|
||||
$item->rule->active = false;
|
||||
$item->rule->save();
|
||||
$item->forceDelete();
|
||||
}
|
||||
if (-1 === $check) {
|
||||
$fixed++;
|
||||
$item->trigger_value = app('steam')->positive((string)$item->trigger_value);
|
||||
$item->save();
|
||||
|
@@ -82,6 +82,7 @@ class DeleteEmptyJournals extends Command
|
||||
TransactionJournal::find((int)$row->transaction_journal_id)->delete();
|
||||
} catch (QueryException $e) {
|
||||
Log::info(sprintf('Could not delete journal: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +114,7 @@ class DeleteEmptyJournals extends Command
|
||||
TransactionJournal::find($entry->id)->delete();
|
||||
} catch (QueryException $e) {
|
||||
Log::info(sprintf('Could not delete entry: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
|
||||
|
52
app/Events/Model/Rule/RuleActionFailedOnArray.php
Normal file
52
app/Events/Model/Rule/RuleActionFailedOnArray.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* RuleActionFailedOnArray.php
|
||||
* Copyright (c) 2023 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\Rule;
|
||||
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class RuleActionFailedOnArray
|
||||
*/
|
||||
class RuleActionFailedOnArray
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public string $error;
|
||||
public array $journal;
|
||||
public RuleAction $ruleAction;
|
||||
|
||||
/**
|
||||
* @param RuleAction $ruleAction
|
||||
* @param array $journal
|
||||
* @param string $error
|
||||
*/
|
||||
public function __construct(RuleAction $ruleAction, array $journal, string $error)
|
||||
{
|
||||
app('log')->debug('Created new RuleActionFailedOnArray');
|
||||
$this->ruleAction = $ruleAction;
|
||||
$this->journal = $journal;
|
||||
$this->error = $error;
|
||||
}
|
||||
}
|
53
app/Events/Model/Rule/RuleActionFailedOnObject.php
Normal file
53
app/Events/Model/Rule/RuleActionFailedOnObject.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* RuleActionFailedOnArray.php
|
||||
* Copyright (c) 2023 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\Rule;
|
||||
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class RuleActionFailedOnObject
|
||||
*/
|
||||
class RuleActionFailedOnObject
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public string $error;
|
||||
public TransactionJournal $journal;
|
||||
public RuleAction $ruleAction;
|
||||
|
||||
/**
|
||||
* @param RuleAction $ruleAction
|
||||
* @param TransactionJournal $journal
|
||||
* @param string $error
|
||||
*/
|
||||
public function __construct(RuleAction $ruleAction, TransactionJournal $journal, string $error)
|
||||
{
|
||||
app('log')->debug('Created new RuleActionFailedOnObject');
|
||||
$this->ruleAction = $ruleAction;
|
||||
$this->journal = $journal;
|
||||
$this->error = $error;
|
||||
}
|
||||
}
|
@@ -218,6 +218,7 @@ class AccountFactory
|
||||
}
|
||||
// create account!
|
||||
$account = Account::create($databaseData);
|
||||
Log::channel('audit')->info(sprintf('Account #%d ("%s") has been created.', $account->id, $account->name));
|
||||
|
||||
// update meta data:
|
||||
$data = $this->cleanMetaDataArray($account, $data);
|
||||
@@ -228,6 +229,7 @@ class AccountFactory
|
||||
$this->storeOpeningBalance($account, $data);
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
// create credit liability data (only liabilities)
|
||||
@@ -235,6 +237,7 @@ class AccountFactory
|
||||
$this->storeCreditLiability($account, $data);
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
// create notes
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class AccountMetaFactory
|
||||
|
@@ -77,6 +77,7 @@ class CategoryFactory
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('400003: Could not store new category.', 0, $e);
|
||||
}
|
||||
}
|
||||
|
@@ -130,6 +130,7 @@ class RecurrenceFactory
|
||||
$this->createTransactions($recurrence, $data['transactions'] ?? []);
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$recurrence->forceDelete();
|
||||
$message = sprintf('Could not create recurring transaction: %s', $e->getMessage());
|
||||
$this->errors->add('store', $message);
|
||||
|
@@ -69,6 +69,7 @@ class TransactionCurrencyFactory
|
||||
} catch (QueryException $e) {
|
||||
$result = null;
|
||||
Log::error(sprintf('Could not create new currency: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('400004: Could not store new currency.', 0, $e);
|
||||
}
|
||||
|
||||
|
@@ -110,7 +110,7 @@ class TransactionFactory
|
||||
Log::error(sprintf('Could not create transaction: %s', $e->getMessage()), $data);
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('Query exception when creating transaction.', 0, $e);
|
||||
throw new FireflyException(sprintf('Query exception when creating transaction: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
if (null === $result) {
|
||||
throw new FireflyException('Transaction is NULL.');
|
||||
|
@@ -75,6 +75,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
||||
->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Cannot render reports.account.report: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = sprintf('Could not render report view: %s', $e->getMessage());
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -77,6 +77,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
||||
->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Cannot render reports.category.month: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = sprintf('Could not render report view: %s', $e->getMessage());
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -59,6 +59,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
||||
return view('reports.default.month', compact('accountIds', 'reportType'))->with('start', $this->start)->with('end', $this->end)->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Cannot render reports.default.month: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = 'Could not render report view.';
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -63,6 +63,7 @@ class MultiYearReportGenerator implements ReportGeneratorInterface
|
||||
)->with('start', $this->start)->with('end', $this->end)->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Cannot render reports.default.multi-year: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = sprintf('Could not render report view: %s', $e->getMessage());
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -63,6 +63,7 @@ class YearReportGenerator implements ReportGeneratorInterface
|
||||
)->with('start', $this->start)->with('end', $this->end)->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Cannot render reports.account.report: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = 'Could not render report view.';
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -71,6 +71,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
||||
)->with('start', $this->start)->with('end', $this->end)->with('tags', $this->tags)->with('accounts', $this->accounts)->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Cannot render reports.tag.month: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = sprintf('Could not render report view: %s', $e->getMessage());
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -174,6 +174,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface
|
||||
Log::error(
|
||||
sprintf('The transformer could not include the requested transaction group for webhook #%d: %s', $webhook->id, $e->getMessage())
|
||||
);
|
||||
Log::error($e->getTraceAsString());
|
||||
|
||||
return;
|
||||
}
|
||||
|
@@ -166,7 +166,7 @@ class BudgetLimitHandler
|
||||
$availableBudget->end_date->format('Y-m-d')
|
||||
)
|
||||
);
|
||||
// have to recalc everything just in case.
|
||||
// have to recalculate everything just in case.
|
||||
$set = $repository->getAllBudgetLimitsByCurrency($availableBudget->transactionCurrency, $availableBudget->start_date, $availableBudget->end_date);
|
||||
Log::debug(sprintf('Found %d interesting budget limit(s).', $set->count()));
|
||||
/** @var BudgetLimit $budgetLimit */
|
||||
@@ -186,15 +186,18 @@ class BudgetLimitHandler
|
||||
precision : Precision::DAY(),
|
||||
boundaries: Boundaries::EXCLUDE_NONE()
|
||||
);
|
||||
// if both equal eachother, amount from this BL must be added to the AB
|
||||
// if both equal each other, amount from this BL must be added to the AB
|
||||
if ($limitPeriod->equals($abPeriod)) {
|
||||
app('log')->debug('This budget limit is equal to the available budget period.');
|
||||
$newAmount = bcadd($newAmount, $budgetLimit->amount);
|
||||
}
|
||||
// if budget limit period inside AB period, can be added in full.
|
||||
// if budget limit period is inside AB period, it can be added in full.
|
||||
if (!$limitPeriod->equals($abPeriod) && $abPeriod->contains($limitPeriod)) {
|
||||
app('log')->debug('This budget limit is smaller than the available budget period.');
|
||||
$newAmount = bcadd($newAmount, $budgetLimit->amount);
|
||||
}
|
||||
if (!$limitPeriod->equals($abPeriod) && $abPeriod->overlapsWith($limitPeriod)) {
|
||||
if (!$limitPeriod->equals($abPeriod) && !$abPeriod->contains($limitPeriod) && $abPeriod->overlapsWith($limitPeriod)) {
|
||||
app('log')->debug('This budget limit is something else entirely!');
|
||||
$overlap = $abPeriod->overlap($limitPeriod);
|
||||
if (null !== $overlap) {
|
||||
$length = $overlap->length();
|
||||
@@ -209,7 +212,7 @@ class BudgetLimitHandler
|
||||
return;
|
||||
}
|
||||
Log::debug(sprintf('Concluded new amount for this AB must be %s', $newAmount));
|
||||
$availableBudget->amount = $newAmount;
|
||||
$availableBudget->amount = app('steam')->bcround($newAmount, $availableBudget->transactionCurrency->decimal_places);
|
||||
$availableBudget->save();
|
||||
}
|
||||
|
||||
|
95
app/Handlers/Events/Model/RuleHandler.php
Normal file
95
app/Handlers/Events/Model/RuleHandler.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* RuleHandler.php
|
||||
* Copyright (c) 2023 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\Handlers\Events\Model;
|
||||
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
|
||||
use FireflyIII\Notifications\User\RuleActionFailed;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
/**
|
||||
* Class RuleHandler
|
||||
*/
|
||||
class RuleHandler
|
||||
{
|
||||
/**
|
||||
* @param RuleActionFailedOnArray $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ruleActionFailedOnArray(RuleActionFailedOnArray $event): void
|
||||
{
|
||||
$ruleAction = $event->ruleAction;
|
||||
$rule = $ruleAction->rule;
|
||||
$preference = Preferences::getForUser($rule->user, 'notification_rule_action_failures', true)->data;
|
||||
if (false === $preference) {
|
||||
return;
|
||||
}
|
||||
app('log')->debug('Now in ruleActionFailedOnArray');
|
||||
$journal = $event->journal;
|
||||
$error = $event->error;
|
||||
$user = $ruleAction->rule->user;
|
||||
|
||||
$mainMessage = trans('rules.main_message', ['rule' => $rule->title, 'action' => $ruleAction->action_type, 'group' => $journal['transaction_group_id'], 'error' => $error]);
|
||||
$groupTitle = $journal['description'] ?? '';
|
||||
$groupLink = route('transactions.show', [$journal['transaction_group_id']]);
|
||||
$ruleTitle = $rule->title;
|
||||
$ruleLink = route('rules.edit', [$rule->id]);
|
||||
$params = [$mainMessage, $groupTitle, $groupLink, $ruleTitle, $ruleLink];
|
||||
|
||||
|
||||
Notification::send($user, new RuleActionFailed($params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RuleActionFailedOnObject $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ruleActionFailedOnObject(RuleActionFailedOnObject $event): void
|
||||
{
|
||||
$ruleAction = $event->ruleAction;
|
||||
$rule = $ruleAction->rule;
|
||||
$preference = Preferences::getForUser($rule->user, 'notification_rule_action_failures', true)->data;
|
||||
if (false === $preference) {
|
||||
return;
|
||||
}
|
||||
app('log')->debug('Now in ruleActionFailedOnObject');
|
||||
$journal = $event->journal;
|
||||
$error = $event->error;
|
||||
$user = $ruleAction->rule->user;
|
||||
|
||||
$mainMessage = trans('rules.main_message', ['rule' => $rule->title, 'action' => $ruleAction->action_type, 'group' => $journal->transaction_group_id, 'error' => $error]);
|
||||
$groupTitle = $journal->description ?? '';
|
||||
$groupLink = route('transactions.show', [$journal->transaction_group_id]);
|
||||
$ruleTitle = $rule->title;
|
||||
$ruleLink = route('rules.edit', [$rule->id]);
|
||||
$params = [$mainMessage, $groupTitle, $groupLink, $ruleTitle, $ruleLink];
|
||||
|
||||
|
||||
Notification::send($user, new RuleActionFailed($params));
|
||||
}
|
||||
|
||||
}
|
@@ -275,6 +275,7 @@ class UserEventHandler
|
||||
Mail::to($newEmail)->send(new ConfirmEmailChangeMail($newEmail, $oldEmail, $url));
|
||||
} catch (Exception $e) { // intentional generic exception
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
@@ -299,6 +300,7 @@ class UserEventHandler
|
||||
Mail::to($oldEmail)->send(new UndoEmailChangeMail($newEmail, $oldEmail, $url));
|
||||
} catch (Exception $e) { // intentional generic exception
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
@@ -342,6 +344,7 @@ class UserEventHandler
|
||||
Mail::to($invitee)->send(new InvitationMail($invitee, $admin, $url));
|
||||
} catch (Exception $e) { // intentional generic exception
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
|
@@ -57,7 +57,7 @@ class VersionCheckEventHandler
|
||||
$permission = app('fireflyconfig')->get('permission_update_check', -1);
|
||||
$value = (int)$permission->data;
|
||||
if (1 !== $value) {
|
||||
Log::info('Update check is not enabled.');
|
||||
Log::debug('Update check is not enabled.');
|
||||
$this->warnToCheckForUpdates($event);
|
||||
|
||||
return;
|
||||
|
@@ -871,7 +871,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
public function setLimit(int $limit): GroupCollectorInterface
|
||||
{
|
||||
$this->limit = $limit;
|
||||
app('log')->debug(sprintf('GroupCollector: The limit is now %d', $limit));
|
||||
//app('log')->debug(sprintf('GroupCollector: The limit is now %d', $limit));
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -976,7 +976,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
{
|
||||
$page = 0 === $page ? 1 : $page;
|
||||
$this->page = $page;
|
||||
app('log')->debug(sprintf('GroupCollector: page is now %d', $page));
|
||||
//app('log')->debug(sprintf('GroupCollector: page is now %d', $page));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ use FireflyIII\Events\AdminRequestedTestMessage;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use FireflyIII\Support\Notifications\UrlValidator;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
@@ -99,7 +100,7 @@ class HomeController extends Controller
|
||||
if ('' === $url) {
|
||||
FireflyConfig::delete('slack_webhook_url');
|
||||
}
|
||||
if (str_starts_with($url, 'https://hooks.slack.com/services/')) {
|
||||
if (UrlValidator::isValidWebhookURL($url)) {
|
||||
FireflyConfig::set('slack_webhook_url', $url);
|
||||
}
|
||||
|
||||
|
@@ -146,7 +146,7 @@ class IndexController extends Controller
|
||||
private function getSums(array $bills): array
|
||||
{
|
||||
$sums = [];
|
||||
$range = app('navigation')->getViewRange(false);
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
|
||||
/** @var array $group */
|
||||
foreach ($bills as $groupOrder => $group) {
|
||||
@@ -177,7 +177,6 @@ class IndexController extends Controller
|
||||
$sums[$groupOrder][$currencyId]['per_period'] = bcadd($sums[$groupOrder][$currencyId]['per_period'], $this->amountPerPeriod($bill, $range));
|
||||
}
|
||||
}
|
||||
|
||||
return $sums;
|
||||
}
|
||||
|
||||
|
@@ -101,6 +101,7 @@ class IndexController extends Controller
|
||||
*/
|
||||
public function index(Request $request, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
$this->abRepository->cleanup();
|
||||
Log::debug(sprintf('Start of IndexController::index("%s", "%s")', $start?->format('Y-m-d'), $end?->format('Y-m-d')));
|
||||
|
||||
// collect some basic vars:
|
||||
@@ -226,6 +227,7 @@ class IndexController extends Controller
|
||||
Log::debug(sprintf('Working on budget #%d ("%s")', $current->id, $current->name));
|
||||
$array = $current->toArray();
|
||||
$array['spent'] = [];
|
||||
$array['spent_total'] = [];
|
||||
$array['budgeted'] = [];
|
||||
$array['attachments'] = $this->repository->getAttachments($current);
|
||||
$array['auto_budget'] = $this->repository->getAutoBudget($current);
|
||||
@@ -234,9 +236,10 @@ class IndexController extends Controller
|
||||
foreach ($budgetLimits as $limit) {
|
||||
Log::debug(sprintf('Working on budget limit #%d', $limit->id));
|
||||
$currency = $limit->transactionCurrency ?? $defaultCurrency;
|
||||
$amount = app('steam')->bcround($limit->amount, $currency->decimal_places);
|
||||
$array['budgeted'][] = [
|
||||
'id' => $limit->id,
|
||||
'amount' => app('steam')->bcround($limit->amount, $currency->decimal_places),
|
||||
'amount' => $amount,
|
||||
'start_date' => $limit->start_date->isoFormat($this->monthAndDayFormat),
|
||||
'end_date' => $limit->end_date->isoFormat($this->monthAndDayFormat),
|
||||
'in_range' => $limit->start_date->isSameDay($start) && $limit->end_date->isSameDay($end),
|
||||
@@ -245,6 +248,7 @@ class IndexController extends Controller
|
||||
'currency_name' => $currency->name,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
];
|
||||
Log::debug(sprintf('The amount budgeted for budget limit #%d is %s %s', $limit->id, $currency->code, $amount));
|
||||
}
|
||||
|
||||
/** @var TransactionCurrency $currency */
|
||||
@@ -337,6 +341,7 @@ class IndexController extends Controller
|
||||
*/
|
||||
public function reorder(Request $request, BudgetRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
$this->abRepository->cleanup();
|
||||
$budgetIds = $request->get('budgetIds');
|
||||
|
||||
foreach ($budgetIds as $index => $budgetId) {
|
||||
|
@@ -28,7 +28,10 @@ use Exception;
|
||||
use FireflyConfig;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Support\Http\Controllers\GetConfigurationData;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -37,6 +40,8 @@ use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\View\View;
|
||||
use Monolog\Handler\RotatingFileHandler;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
/**
|
||||
* Class DebugController
|
||||
@@ -117,86 +122,9 @@ class DebugController extends Controller
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
// basic scope information:
|
||||
$now = now(config('app.timezone'))->format('Y-m-d H:i:s e');
|
||||
$buildNr = '(unknown)';
|
||||
$buildDate = '(unknown)';
|
||||
$baseBuildNr = '(unknown)';
|
||||
$baseBuildDate = '(unknown)';
|
||||
$expectedDBversion = config('firefly.db_version');
|
||||
$foundDBversion = FireflyConfig::get('db_version', 1)->data;
|
||||
try {
|
||||
if (file_exists('/var/www/counter-main.txt')) {
|
||||
$buildNr = trim(file_get_contents('/var/www/counter-main.txt'));
|
||||
}
|
||||
} catch (Exception $e) { // generic catch for open basedir.
|
||||
Log::debug('Could not check counter.');
|
||||
Log::warning($e->getMessage());
|
||||
}
|
||||
try {
|
||||
if (file_exists('/var/www/build-date-main.txt')) {
|
||||
$buildDate = trim(file_get_contents('/var/www/build-date-main.txt'));
|
||||
}
|
||||
} catch (Exception $e) { // generic catch for open basedir.
|
||||
Log::debug('Could not check date.');
|
||||
Log::warning($e->getMessage());
|
||||
}
|
||||
if ('' !== (string)env('BASE_IMAGE_BUILD')) {
|
||||
$baseBuildNr = env('BASE_IMAGE_BUILD');
|
||||
}
|
||||
if ('' !== (string)env('BASE_IMAGE_DATE')) {
|
||||
$baseBuildDate = env('BASE_IMAGE_DATE');
|
||||
}
|
||||
|
||||
$phpVersion = PHP_VERSION;
|
||||
$phpOs = PHP_OS;
|
||||
|
||||
// system information
|
||||
$tz = env('TZ');
|
||||
$appEnv = config('app.env');
|
||||
$appDebug = var_export(config('app.debug'), true);
|
||||
$cacheDriver = config('cache.default');
|
||||
$logChannel = config('logging.default');
|
||||
$appLogLevel = config('logging.level');
|
||||
$maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize'));
|
||||
$maxPostSize = app('steam')->phpBytes(ini_get('post_max_size'));
|
||||
$uploadSize = min($maxFileSize, $maxPostSize);
|
||||
$displayErrors = ini_get('display_errors');
|
||||
$errorReporting = $this->errorReporting((int)ini_get('error_reporting'));
|
||||
$interface = PHP_SAPI;
|
||||
$defaultLanguage = (string)config('firefly.default_language');
|
||||
$defaultLocale = (string)config('firefly.default_locale');
|
||||
$bcscale = bcscale();
|
||||
$drivers = implode(', ', DB::availableDrivers());
|
||||
$currentDriver = DB::getDriverName();
|
||||
$trustedProxies = config('firefly.trusted_proxies');
|
||||
|
||||
// user info
|
||||
$loginProvider = config('auth.providers.users.driver');
|
||||
$userGuard = config('auth.defaults.guard');
|
||||
$remoteHeader = $userGuard === 'remote_user_guard' ? config('auth.guard_header') : 'N/A';
|
||||
$remoteMailHeader = $userGuard === 'remote_user_guard' ? config('auth.guard_email') : 'N/A';
|
||||
$userLanguage = app('steam')->getLanguage();
|
||||
$userLocale = app('steam')->getLocale();
|
||||
$userAgent = $request->header('user-agent');
|
||||
$stateful = join(', ', config('sanctum.stateful'));
|
||||
|
||||
|
||||
// expected + found DB version:
|
||||
|
||||
// some new vars.
|
||||
$isDocker = env('IS_DOCKER', false);
|
||||
|
||||
// set languages, see what happens:
|
||||
$original = setlocale(LC_ALL, 0);
|
||||
$localeAttempts = [];
|
||||
$parts = app('steam')->getLocaleArray(app('steam')->getLocale());
|
||||
foreach ($parts as $code) {
|
||||
$code = trim($code);
|
||||
Log::debug(sprintf('Trying to set %s', $code));
|
||||
$localeAttempts[$code] = var_export(setlocale(LC_ALL, $code), true);
|
||||
}
|
||||
setlocale(LC_ALL, $original);
|
||||
$table = $this->generateTable();
|
||||
$table = str_replace(["\n", "\t", ' '], '', $table);
|
||||
$now = now(config('app.timezone'))->format('Y-m-d H:i:s');
|
||||
|
||||
// get latest log file:
|
||||
$logger = Log::driver();
|
||||
@@ -213,50 +141,190 @@ class DebugController extends Controller
|
||||
}
|
||||
if ('' !== $logContent) {
|
||||
// last few lines
|
||||
$logContent = 'Truncated from this point <----|' . substr($logContent, -8192);
|
||||
$logContent = 'Truncated from this point <----|' . substr($logContent, -16384);
|
||||
}
|
||||
|
||||
return view(
|
||||
'debug',
|
||||
compact(
|
||||
'phpVersion',
|
||||
'localeAttempts',
|
||||
'expectedDBversion',
|
||||
'foundDBversion',
|
||||
'appEnv',
|
||||
'appDebug',
|
||||
'logChannel',
|
||||
'stateful',
|
||||
'tz',
|
||||
'uploadSize',
|
||||
'appLogLevel',
|
||||
'remoteHeader',
|
||||
'remoteMailHeader',
|
||||
'now',
|
||||
'drivers',
|
||||
'currentDriver',
|
||||
'userGuard',
|
||||
'loginProvider',
|
||||
'buildNr',
|
||||
'buildDate',
|
||||
'baseBuildNr',
|
||||
'baseBuildDate',
|
||||
'bcscale',
|
||||
'userAgent',
|
||||
'displayErrors',
|
||||
'errorReporting',
|
||||
'phpOs',
|
||||
'interface',
|
||||
'logContent',
|
||||
'cacheDriver',
|
||||
'trustedProxies',
|
||||
'userLanguage',
|
||||
'userLocale',
|
||||
'defaultLanguage',
|
||||
'defaultLocale',
|
||||
'isDocker'
|
||||
)
|
||||
);
|
||||
return view('debug', compact('table', 'now', 'logContent'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function generateTable(): string
|
||||
{
|
||||
// system information:
|
||||
$system = $this->getSystemInformation();
|
||||
$docker = $this->getBuildInfo();
|
||||
$app = $this->getAppInfo();
|
||||
$user = $this->getuserInfo();
|
||||
|
||||
return (string)view('partials.debug-table', compact('system', 'docker', 'app', 'user'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getSystemInformation(): array
|
||||
{
|
||||
$maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize'));
|
||||
$maxPostSize = app('steam')->phpBytes(ini_get('post_max_size'));
|
||||
$drivers = DB::availableDrivers();
|
||||
$currentDriver = DB::getDriverName();
|
||||
return [
|
||||
'db_version' => app('fireflyconfig')->get('db_version', 1)->data,
|
||||
'php_version' => PHP_VERSION,
|
||||
'php_os' => PHP_OS,
|
||||
'interface' => PHP_SAPI,
|
||||
'bcscale' => bcscale(),
|
||||
'display_errors' => ini_get('display_errors'),
|
||||
'error_reporting' => $this->errorReporting((int)ini_get('error_reporting')),
|
||||
'upload_size' => min($maxFileSize, $maxPostSize),
|
||||
'all_drivers' => $drivers,
|
||||
'current_driver' => $currentDriver,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getBuildInfo(): array
|
||||
{
|
||||
$return = [
|
||||
'is_docker' => env('IS_DOCKER', false),
|
||||
'build' => '(unknown)',
|
||||
'build_date' => '(unknown)',
|
||||
'base_build' => '(unknown)',
|
||||
'base_build_date' => '(unknown)',
|
||||
|
||||
];
|
||||
try {
|
||||
if (file_exists('/var/www/counter-main.txt')) {
|
||||
$return['build'] = trim(file_get_contents('/var/www/counter-main.txt'));
|
||||
}
|
||||
} catch (Exception $e) { // generic catch for open basedir.
|
||||
Log::debug('Could not check build counter, but thats ok.');
|
||||
Log::warning($e->getMessage());
|
||||
}
|
||||
try {
|
||||
if (file_exists('/var/www/build-date-main.txt')) {
|
||||
$return['build_date'] = trim(file_get_contents('/var/www/build-date-main.txt'));
|
||||
}
|
||||
} catch (Exception $e) { // generic catch for open basedir.
|
||||
Log::debug('Could not check build date, but thats ok.');
|
||||
Log::warning($e->getMessage());
|
||||
}
|
||||
if ('' !== (string)env('BASE_IMAGE_BUILD')) {
|
||||
$return['base_build'] = env('BASE_IMAGE_BUILD');
|
||||
}
|
||||
if ('' !== (string)env('BASE_IMAGE_DATE')) {
|
||||
$return['base_build_date'] = env('BASE_IMAGE_DATE');
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getAppInfo(): array
|
||||
{
|
||||
$userGuard = config('auth.defaults.guard');
|
||||
|
||||
return [
|
||||
'tz' => env('TZ'),
|
||||
'debug' => var_export(config('app.debug'), true),
|
||||
'log_channel' => env('LOG_CHANNEL'),
|
||||
'audit_log_channel' => envNonEmpty('AUDIT_LOG_CHANNEL', '(empty)'),
|
||||
'default_language' => (string)config('firefly.default_language'),
|
||||
'default_locale' => (string)config('firefly.default_locale'),
|
||||
'remote_header' => $userGuard === 'remote_user_guard' ? config('auth.guard_header') : 'N/A',
|
||||
'remote_mail_header' => $userGuard === 'remote_user_guard' ? config('auth.guard_email') : 'N/A',
|
||||
'stateful_domains' => join(', ', config('sanctum.stateful')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
private function getuserInfo(): array
|
||||
{
|
||||
$userFlags = $this->getUserFlags();
|
||||
|
||||
// user info
|
||||
$userAgent = request()->header('user-agent');
|
||||
|
||||
// set languages, see what happens:
|
||||
$original = setlocale(LC_ALL, 0);
|
||||
$localeAttempts = [];
|
||||
$parts = app('steam')->getLocaleArray(app('steam')->getLocale());
|
||||
foreach ($parts as $code) {
|
||||
$code = trim($code);
|
||||
Log::debug(sprintf('Trying to set %s', $code));
|
||||
$result = setlocale(LC_ALL, $code);
|
||||
$localeAttempts[$code] = $result === $code;
|
||||
}
|
||||
setlocale(LC_ALL, $original);
|
||||
|
||||
return [
|
||||
'user_id' => auth()->user()->id,
|
||||
'user_count' => User::count(),
|
||||
'user_flags' => $userFlags,
|
||||
'user_agent' => $userAgent,
|
||||
'locale_attempts' => $localeAttempts,
|
||||
'locale' => app('steam')->getLocale(),
|
||||
'language' => app('steam')->getLanguage(),
|
||||
'view_range' => app('preferences')->get('viewRange', '1M')->data,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getUserFlags(): string
|
||||
{
|
||||
$flags = [];
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
// has liabilities
|
||||
if ($user->accounts()->accountTypeIn([AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE])->count() > 0) {
|
||||
$flags[] = ':credit_card:';
|
||||
}
|
||||
|
||||
// has piggies
|
||||
if ($user->piggyBanks()->count() > 0) {
|
||||
$flags[] = ':pig:';
|
||||
}
|
||||
|
||||
// has stored reconciliations
|
||||
$type = TransactionType::whereType(TransactionType::RECONCILIATION)->first();
|
||||
if ($user->transactionJournals()->where('transaction_type_id', $type->id)->count()) {
|
||||
$flags[] = ':ledger:';
|
||||
}
|
||||
|
||||
// has used importer?
|
||||
|
||||
// has rules
|
||||
if ($user->rules()->count() > 0) {
|
||||
$flags[] = ':wrench:';
|
||||
}
|
||||
|
||||
// has recurring transactions
|
||||
if ($user->recurrences()->count() > 0) {
|
||||
$flags[] = ':clock130:';
|
||||
}
|
||||
|
||||
// has groups
|
||||
if ($user->objectGroups()->count() > 0) {
|
||||
$flags[] = ':bookmark_tabs:';
|
||||
}
|
||||
|
||||
// uses bills
|
||||
if ($user->bills()->count() > 0) {
|
||||
$flags[] = ':email:';
|
||||
}
|
||||
return join(' ', $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -275,4 +343,5 @@ class DebugController extends Controller
|
||||
|
||||
return redirect(route('home'));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -138,6 +138,9 @@ class HomeController extends Controller
|
||||
$accounts = $repository->getAccountsById($frontPage->data);
|
||||
$today = today(config('app.timezone'));
|
||||
|
||||
// sort frontpage accounts by order
|
||||
$accounts = $accounts->sortBy('order');
|
||||
|
||||
Log::debug('Frontpage accounts are ', $frontPage->data);
|
||||
|
||||
/** @var BillRepositoryInterface $billRepository */
|
||||
|
@@ -55,10 +55,12 @@ class BoxController extends Controller
|
||||
*/
|
||||
public function available(): JsonResponse
|
||||
{
|
||||
app('log')->debug('Now in available()');
|
||||
/** @var OperationsRepositoryInterface $opsRepository */
|
||||
$opsRepository = app(OperationsRepositoryInterface::class);
|
||||
/** @var AvailableBudgetRepositoryInterface $abRepository */
|
||||
$abRepository = app(AvailableBudgetRepositoryInterface::class);
|
||||
$abRepository->cleanup();
|
||||
/** @var Carbon $start */
|
||||
$start = session('start', today(config('app.timezone'))->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
@@ -73,40 +75,57 @@ class BoxController extends Controller
|
||||
$cache->addProperty($today);
|
||||
$cache->addProperty('box-available');
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get());
|
||||
//return response()->json($cache->get());
|
||||
}
|
||||
$leftPerDayAmount = '0';
|
||||
$leftToSpendAmount = '0';
|
||||
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
$availableBudgets = $abRepository->getAvailableBudgetsByDate($start, $end);
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
app('log')->debug(sprintf('Default currency is %s', $currency->code));
|
||||
$availableBudgets = $abRepository->getAvailableBudgetsByExactDate($start, $end);
|
||||
app('log')->debug(sprintf('Found %d available budget(s)', $availableBudgets->count()));
|
||||
$availableBudgets = $availableBudgets->filter(
|
||||
static function (AvailableBudget $availableBudget) use ($currency) {
|
||||
if ($availableBudget->transaction_currency_id === $currency->id) {
|
||||
app('log')->debug(sprintf(
|
||||
'Will include AB #%d: from %s-%s amount %s',
|
||||
$availableBudget->id,
|
||||
$availableBudget->start_date->format('Y-m-d'),
|
||||
$availableBudget->end_date->format('Y-m-d'),
|
||||
$availableBudget->amount
|
||||
));
|
||||
return $availableBudget;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
app('log')->debug(sprintf('Filtered back to %d available budgets', $availableBudgets->count()));
|
||||
// spent in this period, in budgets, for default currency.
|
||||
// also calculate spent per day.
|
||||
$spent = $opsRepository->sumExpenses($start, $end, null, null, $currency);
|
||||
$spentAmount = $spent[(int)$currency->id]['sum'] ?? '0';
|
||||
app('log')->debug(sprintf('Spent for default currency for all budgets in this period: %s', $spentAmount));
|
||||
|
||||
$days = $today->between($start, $end) ? $today->diffInDays($start) + 1 : $end->diffInDays($start) + 1;
|
||||
$days = $today->between($start, $end) ? $today->diffInDays($start) + 1 : $end->diffInDays($start) + 1;
|
||||
app('log')->debug(sprintf('Number of days left: %d', $days));
|
||||
$spentPerDay = bcdiv($spentAmount, (string)$days);
|
||||
app('log')->debug(sprintf('Available to spend per day: %s', $spentPerDay));
|
||||
if ($availableBudgets->count() > 0) {
|
||||
$display = 0; // assume user overspent
|
||||
$boxTitle = (string)trans('firefly.overspent');
|
||||
$totalAvailableSum = (string)$availableBudgets->sum('amount');
|
||||
app('log')->debug(sprintf('Total available sum is %s', $totalAvailableSum));
|
||||
// calculate with available budget.
|
||||
$leftToSpendAmount = bcadd($totalAvailableSum, $spentAmount);
|
||||
app('log')->debug(sprintf('So left to spend is %s', $leftToSpendAmount));
|
||||
if (1 === bccomp($leftToSpendAmount, '0')) {
|
||||
app('log')->debug(sprintf('Left to spend is positive!'));
|
||||
$boxTitle = (string)trans('firefly.left_to_spend');
|
||||
$days = $today->diffInDays($end) + 1;
|
||||
$display = 1; // not overspent
|
||||
$leftPerDayAmount = bcdiv($leftToSpendAmount, (string)$days);
|
||||
app('log')->debug(sprintf('Left to spend per day is %s', $leftPerDayAmount));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,9 +137,10 @@ class BoxController extends Controller
|
||||
'left_per_day' => app('amount')->formatAnything($currency, $leftPerDayAmount, false),
|
||||
'title' => $boxTitle,
|
||||
];
|
||||
app('log')->debug('Final output', $return);
|
||||
|
||||
$cache->store($return);
|
||||
|
||||
app('log')->debug('Now done with available()');
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
|
@@ -75,6 +75,7 @@ class FrontpageController extends Controller
|
||||
$html = view('json.piggy-banks', compact('info'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Cannot render json.piggy-banks: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$html = 'Could not render view.';
|
||||
throw new FireflyException($html, 0, $e);
|
||||
}
|
||||
|
@@ -157,6 +157,7 @@ class ReconcileController extends Controller
|
||||
)->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('View error: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$view = sprintf('Could not render accounts.reconcile.overview: %s', $e->getMessage());
|
||||
throw new FireflyException($view, 0, $e);
|
||||
}
|
||||
@@ -258,6 +259,7 @@ class ReconcileController extends Controller
|
||||
)->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$html = sprintf('Could not render accounts.reconcile.transactions: %s', $e->getMessage());
|
||||
throw new FireflyException($html, 0, $e);
|
||||
}
|
||||
|
@@ -55,6 +55,7 @@ class RuleController extends Controller
|
||||
$view = view('rules.partials.action', compact('actions', 'count'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Cannot render rules.partials.action: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$view = 'Could not render view.';
|
||||
throw new FireflyException($view, 0, $e);
|
||||
}
|
||||
@@ -86,6 +87,7 @@ class RuleController extends Controller
|
||||
$view = view('rules.partials.trigger', compact('triggers', 'count'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Cannot render rules.partials.trigger: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$view = 'Could not render view.';
|
||||
throw new FireflyException($view, 0, $e);
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Notifications\UrlValidator;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -207,7 +208,7 @@ class PreferencesController extends Controller
|
||||
// slack URL:
|
||||
if (!auth()->user()->hasRole('demo')) {
|
||||
$url = (string)$request->get('slackUrl');
|
||||
if (str_starts_with($url, 'https://hooks.slack.com/services/')) {
|
||||
if (UrlValidator::isValidWebhookURL($url)) {
|
||||
app('preferences')->set('slack_webhook_url', $url);
|
||||
}
|
||||
if ('' === $url) {
|
||||
|
@@ -65,7 +65,8 @@ class AccountController extends Controller
|
||||
try {
|
||||
$result = view('reports.partials.accounts', compact('accountReport'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.accounts: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.accounts: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = 'Could not render view.';
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -141,7 +141,8 @@ class BalanceController extends Controller
|
||||
try {
|
||||
$result = view('reports.partials.balance', compact('report'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.balance: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.balance: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = 'Could not render view.';
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -61,7 +61,8 @@ class BillController extends Controller
|
||||
try {
|
||||
$result = view('reports.partials.bills', compact('report'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.budgets: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.budgets: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = 'Could not render view.';
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -195,8 +195,9 @@ class BudgetController extends Controller
|
||||
try {
|
||||
$result = view('reports.budget.partials.avg-expenses', compact('result'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
$result = sprintf('Could not render view: %s', $e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
||||
@@ -353,7 +354,8 @@ class BudgetController extends Controller
|
||||
try {
|
||||
$result = view('reports.partials.budget-period', compact('report', 'periods'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = 'Could not render view.';
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
@@ -406,7 +408,7 @@ class BudgetController extends Controller
|
||||
try {
|
||||
$result = view('reports.budget.partials.top-expenses', compact('result'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
$result = sprintf('Could not render view: %s', $e->getMessage());
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -315,7 +315,7 @@ class CategoryController extends Controller
|
||||
try {
|
||||
$result = view('reports.category.partials.avg-expenses', compact('result'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
$result = sprintf('Could not render view: %s', $e->getMessage());
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
@@ -368,7 +368,7 @@ class CategoryController extends Controller
|
||||
try {
|
||||
$result = view('reports.category.partials.avg-income', compact('result'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
$result = sprintf('Could not render view: %s', $e->getMessage());
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -115,7 +115,7 @@ class DoubleController extends Controller
|
||||
try {
|
||||
$result = view('reports.double.partials.avg-expenses', compact('result'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
$result = sprintf('Could not render view: %s', $e->getMessage());
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
@@ -168,7 +168,7 @@ class DoubleController extends Controller
|
||||
try {
|
||||
$result = view('reports.double.partials.avg-income', compact('result'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
$result = sprintf('Could not render view: %s', $e->getMessage());
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
@@ -463,7 +463,7 @@ class DoubleController extends Controller
|
||||
try {
|
||||
$result = view('reports.double.partials.top-expenses', compact('result'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
$result = sprintf('Could not render view: %s', $e->getMessage());
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
@@ -514,7 +514,7 @@ class DoubleController extends Controller
|
||||
try {
|
||||
$result = view('reports.double.partials.top-income', compact('result'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
|
||||
$result = sprintf('Could not render view: %s', $e->getMessage());
|
||||
throw new FireflyException($e->getMessage(), 0, $e);
|
||||
}
|
||||
|
@@ -85,7 +85,8 @@ class OperationsController extends Controller
|
||||
try {
|
||||
$result = view('reports.partials.income-expenses', compact('report', 'type'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.income-expense: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.income-expense: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = 'Could not render view.';
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
@@ -121,7 +122,8 @@ class OperationsController extends Controller
|
||||
try {
|
||||
$result = view('reports.partials.income-expenses', compact('report', 'type'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.income-expenses: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.income-expenses: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = 'Could not render view.';
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
@@ -177,7 +179,8 @@ class OperationsController extends Controller
|
||||
try {
|
||||
$result = view('reports.partials.operations', compact('sums'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Could not render reports.partials.operations: %s', $e->getMessage()));
|
||||
Log::error(sprintf('Could not render reports.partials.operations: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$result = 'Could not render view.';
|
||||
throw new FireflyException($result, 0, $e);
|
||||
}
|
||||
|
@@ -128,6 +128,7 @@ class SearchController extends Controller
|
||||
$html = view('search.search', compact('groups', 'hasPages', 'searchTime'))->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Cannot render search.search: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
$html = 'Could not render view.';
|
||||
throw new FireflyException($html, 0, $e);
|
||||
}
|
||||
|
@@ -158,6 +158,7 @@ class ReportFormRequest extends FormRequest
|
||||
} catch (Exception $e) { // intentional generic exception
|
||||
$error = sprintf('"%s" is not a valid date range: %s', $range, $e->getMessage());
|
||||
Log::error($error);
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException($error, 0, $e);
|
||||
}
|
||||
return $date;
|
||||
@@ -192,6 +193,7 @@ class ReportFormRequest extends FormRequest
|
||||
} catch (Exception $e) { // intentional generic exception
|
||||
$error = sprintf('"%s" is not a valid date range: %s', $range, $e->getMessage());
|
||||
Log::error($error);
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException($error, 0, $e);
|
||||
}
|
||||
return $date;
|
||||
@@ -220,19 +222,18 @@ class ReportFormRequest extends FormRequest
|
||||
}
|
||||
if (!is_array($set)) {
|
||||
Log::error(sprintf('Set is not an array! "%s"', $set));
|
||||
return $collection;
|
||||
}
|
||||
if (is_array($set)) {
|
||||
foreach ($set as $tagTag) {
|
||||
Log::debug(sprintf('Now searching for "%s"', $tagTag));
|
||||
$tag = $repository->findByTag($tagTag);
|
||||
if (null !== $tag) {
|
||||
$collection->push($tag);
|
||||
continue;
|
||||
}
|
||||
$tag = $repository->find((int)$tagTag);
|
||||
if (null !== $tag) {
|
||||
$collection->push($tag);
|
||||
}
|
||||
foreach ($set as $tagTag) {
|
||||
Log::debug(sprintf('Now searching for "%s"', $tagTag));
|
||||
$tag = $repository->findByTag($tagTag);
|
||||
if (null !== $tag) {
|
||||
$collection->push($tag);
|
||||
continue;
|
||||
}
|
||||
$tag = $repository->find((int)$tagTag);
|
||||
if (null !== $tag) {
|
||||
$collection->push($tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -61,6 +61,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @method static Builder|ObjectGroup whereTitle($value)
|
||||
* @method static Builder|ObjectGroup whereUpdatedAt($value)
|
||||
* @method static Builder|ObjectGroup whereUserId($value)
|
||||
* @property int|null $user_group_id
|
||||
* @method static Builder|ObjectGroup whereUserGroupId($value)
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class ObjectGroup extends Model
|
||||
|
@@ -76,6 +76,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @method static Builder|Rule withoutTrashed()
|
||||
* @property int|null $user_group_id
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Rule whereUserGroupId($value)
|
||||
* @property-read \FireflyIII\Models\UserGroup|null $userGroup
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class Rule extends Model
|
||||
|
@@ -61,6 +61,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @method static Builder|TransactionGroup withoutTrashed()
|
||||
* @property int|null $user_group_id
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|TransactionGroup whereUserGroupId($value)
|
||||
* @property-read \FireflyIII\Models\UserGroup|null $userGroup
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class TransactionGroup extends Model
|
||||
|
@@ -52,6 +52,16 @@ use Illuminate\Support\Carbon;
|
||||
* @method static Builder|UserGroup whereUpdatedAt($value)
|
||||
* @property-read Collection<int, Account> $accounts
|
||||
* @property-read int|null $accounts_count
|
||||
* @property-read Collection<int, \FireflyIII\Models\AvailableBudget> $availableBudgets
|
||||
* @property-read int|null $available_budgets_count
|
||||
* @property-read Collection<int, \FireflyIII\Models\Bill> $bills
|
||||
* @property-read int|null $bills_count
|
||||
* @property-read Collection<int, \FireflyIII\Models\Budget> $budgets
|
||||
* @property-read int|null $budgets_count
|
||||
* @property-read Collection<int, \FireflyIII\Models\PiggyBank> $piggyBanks
|
||||
* @property-read int|null $piggy_banks_count
|
||||
* @property-read Collection<int, \FireflyIII\Models\TransactionJournal> $transactionJournals
|
||||
* @property-read int|null $transaction_journals_count
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class UserGroup extends Model
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Notifications\Admin;
|
||||
|
||||
use FireflyIII\Support\Notifications\UrlValidator;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
@@ -99,9 +100,9 @@ class TestNotification extends Notification
|
||||
public function via($notifiable)
|
||||
{
|
||||
/** @var User|null $user */
|
||||
$user = auth()->user();
|
||||
$user = auth()->user();
|
||||
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
|
||||
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) {
|
||||
if (UrlValidator::isValidWebhookURL($slackUrl)) {
|
||||
return ['mail', 'slack'];
|
||||
}
|
||||
return ['mail'];
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Notifications\Admin;
|
||||
|
||||
use FireflyIII\Models\InvitedUser;
|
||||
use FireflyIII\Support\Notifications\UrlValidator;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
@@ -102,9 +103,9 @@ class UserInvitation extends Notification
|
||||
public function via($notifiable)
|
||||
{
|
||||
/** @var User|null $user */
|
||||
$user = auth()->user();
|
||||
$user = auth()->user();
|
||||
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
|
||||
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) {
|
||||
if (UrlValidator::isValidWebhookURL($slackUrl)) {
|
||||
return ['mail', 'slack'];
|
||||
}
|
||||
return ['mail'];
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Notifications\Admin;
|
||||
|
||||
use FireflyIII\Support\Notifications\UrlValidator;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
@@ -99,9 +100,9 @@ class UserRegistration extends Notification
|
||||
public function via($notifiable)
|
||||
{
|
||||
/** @var User|null $user */
|
||||
$user = auth()->user();
|
||||
$user = auth()->user();
|
||||
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
|
||||
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) {
|
||||
if (UrlValidator::isValidWebhookURL($slackUrl)) {
|
||||
return ['mail', 'slack'];
|
||||
}
|
||||
return ['mail'];
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Notifications\Admin;
|
||||
|
||||
use FireflyIII\Support\Notifications\UrlValidator;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
@@ -87,21 +88,10 @@ class VersionCheckResult extends Notification
|
||||
*/
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
// return (new SlackMessage())->text($this->message)
|
||||
// ->sectionBlock(function (SectionBlock $block) {
|
||||
// $button = new ButtonElement('Button');
|
||||
// $button->url('https://github.com/firefly-iii/firefly-iii/releases');
|
||||
// $block->accessory($button);
|
||||
// });
|
||||
//// ->attachment(function ($attachment) {
|
||||
//// $attachment->title('Firefly III @ GitHub', 'https://github.com/firefly-iii/firefly-iii/releases');
|
||||
//// });
|
||||
|
||||
|
||||
return (new SlackMessage())->content($this->message)
|
||||
->attachment(function ($attachment) {
|
||||
$attachment->title('Firefly III @ GitHub', 'https://github.com/firefly-iii/firefly-iii/releases');
|
||||
});
|
||||
->attachment(function ($attachment) {
|
||||
$attachment->title('Firefly III @ GitHub', 'https://github.com/firefly-iii/firefly-iii/releases');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,9 +104,9 @@ class VersionCheckResult extends Notification
|
||||
public function via($notifiable)
|
||||
{
|
||||
/** @var User|null $user */
|
||||
$user = auth()->user();
|
||||
$user = auth()->user();
|
||||
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
|
||||
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) {
|
||||
if (UrlValidator::isValidWebhookURL($slackUrl)) {
|
||||
return ['mail', 'slack'];
|
||||
}
|
||||
return ['mail'];
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Notifications\User;
|
||||
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Support\Notifications\UrlValidator;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
@@ -38,8 +39,8 @@ class BillReminder extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private Bill $bill;
|
||||
private int $diff;
|
||||
private Bill $bill;
|
||||
private int $diff;
|
||||
private string $field;
|
||||
|
||||
/**
|
||||
@@ -49,9 +50,9 @@ class BillReminder extends Notification
|
||||
*/
|
||||
public function __construct(Bill $bill, string $field, int $diff)
|
||||
{
|
||||
$this->bill = $bill;
|
||||
$this->bill = $bill;
|
||||
$this->field = $field;
|
||||
$this->diff = $diff;
|
||||
$this->diff = $diff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +102,7 @@ class BillReminder extends Notification
|
||||
$message = (string)trans(sprintf('email.bill_warning_subject_now_%s', $this->field), ['diff' => $this->diff, 'name' => $this->bill->name]);
|
||||
}
|
||||
$bill = $this->bill;
|
||||
$url = route('bills.show', [$bill->id]);
|
||||
$url = route('bills.show', [$bill->id]);
|
||||
return (new SlackMessage())
|
||||
->warning()
|
||||
->attachment(function ($attachment) use ($bill, $url) {
|
||||
@@ -120,9 +121,9 @@ class BillReminder extends Notification
|
||||
public function via($notifiable)
|
||||
{
|
||||
/** @var User|null $user */
|
||||
$user = auth()->user();
|
||||
$user = auth()->user();
|
||||
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
|
||||
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) {
|
||||
if (UrlValidator::isValidWebhookURL($slackUrl)) {
|
||||
return ['mail', 'slack'];
|
||||
}
|
||||
return ['mail'];
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Notifications\User;
|
||||
|
||||
use FireflyIII\Support\Notifications\UrlValidator;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
@@ -96,9 +97,9 @@ class NewAccessToken extends Notification
|
||||
public function via($notifiable)
|
||||
{
|
||||
/** @var User|null $user */
|
||||
$user = auth()->user();
|
||||
$user = auth()->user();
|
||||
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
|
||||
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) {
|
||||
if (UrlValidator::isValidWebhookURL($slackUrl)) {
|
||||
return ['mail', 'slack'];
|
||||
}
|
||||
return ['mail'];
|
||||
|
117
app/Notifications/User/RuleActionFailed.php
Normal file
117
app/Notifications/User/RuleActionFailed.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* NewAccessToken.php
|
||||
* Copyright (c) 2022 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Notifications\User;
|
||||
|
||||
use FireflyIII\Support\Notifications\UrlValidator;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
/**
|
||||
* Class RuleActionFailed
|
||||
*/
|
||||
class RuleActionFailed extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private string $groupLink;
|
||||
private string $groupTitle;
|
||||
private string $message;
|
||||
private string $ruleLink;
|
||||
private string $ruleTitle;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(array $params)
|
||||
{
|
||||
[$mainMessage, $groupTitle, $groupLink, $ruleTitle, $ruleLink] = $params;
|
||||
$this->message = $mainMessage;
|
||||
$this->groupTitle = $groupTitle;
|
||||
$this->groupLink = $groupLink;
|
||||
$this->ruleTitle = $ruleTitle;
|
||||
$this->ruleLink = $ruleLink;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Slack representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
*
|
||||
* @return SlackMessage
|
||||
*/
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
$groupTitle = $this->groupTitle;
|
||||
$groupLink = $this->groupLink;
|
||||
$ruleTitle = $this->ruleTitle;
|
||||
$ruleLink = $this->ruleLink;
|
||||
|
||||
return (new SlackMessage())->content($this->message)->attachment(function ($attachment) use ($groupTitle, $groupLink) {
|
||||
$attachment->title((string)trans('rules.inspect_transaction', ['title' => $groupTitle]), $groupLink);
|
||||
})->attachment(function ($attachment) use ($ruleTitle, $ruleLink) {
|
||||
$attachment->title((string)trans('rules.inspect_rule', ['title' => $ruleTitle]), $ruleLink);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
/** @var User|null $user */
|
||||
$user = auth()->user();
|
||||
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
|
||||
if (UrlValidator::isValidWebhookURL($slackUrl)) {
|
||||
app('log')->debug('Will send ruleActionFailed through Slack!');
|
||||
return ['slack'];
|
||||
}
|
||||
app('log')->debug('Will NOT send ruleActionFailed through Slack');
|
||||
return [];
|
||||
}
|
||||
}
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Notifications\User;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Support\Notifications\UrlValidator;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
@@ -124,9 +125,9 @@ class UserLogin extends Notification
|
||||
public function via($notifiable)
|
||||
{
|
||||
/** @var User|null $user */
|
||||
$user = auth()->user();
|
||||
$user = auth()->user();
|
||||
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
|
||||
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) {
|
||||
if (UrlValidator::isValidWebhookURL($slackUrl)) {
|
||||
return ['mail', 'slack'];
|
||||
}
|
||||
return ['mail'];
|
||||
|
@@ -32,6 +32,8 @@ use FireflyIII\Events\DetectedNewIPAddress;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Created;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Deleted;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Updated;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
|
||||
use FireflyIII\Events\NewVersionAvailable;
|
||||
use FireflyIII\Events\RegisteredUser;
|
||||
use FireflyIII\Events\RequestedNewPassword;
|
||||
@@ -170,6 +172,14 @@ class EventServiceProvider extends ServiceProvider
|
||||
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@deleted',
|
||||
],
|
||||
|
||||
// rule actions
|
||||
RuleActionFailedOnArray::class => [
|
||||
'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnArray',
|
||||
],
|
||||
RuleActionFailedOnObject::class => [
|
||||
'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnObject',
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
|
@@ -39,6 +39,49 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
|
||||
{
|
||||
private User $user;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function cleanup(): void
|
||||
{
|
||||
$exists = [];
|
||||
$availableBudgets = $this->user->availableBudgets()->get();
|
||||
/** @var AvailableBudget $availableBudget */
|
||||
foreach ($availableBudgets as $availableBudget) {
|
||||
$start = $availableBudget->start_date->format('Y-m-d');
|
||||
$end = $availableBudget->end_date->format('Y-m-d');
|
||||
$key = sprintf('%s-%s-%s', $availableBudget->transaction_currency_id, $start, $end);
|
||||
if (array_key_exists($key, $exists)) {
|
||||
app('log')->debug(sprintf('Found duplicate AB: %s %s, %s-%s. Has been deleted', $availableBudget->transaction_currency_id, $availableBudget->amount, $start, $end));
|
||||
$availableBudget->delete();
|
||||
}
|
||||
$exists[$key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all available budgets (in all currencies) (for the selected period).
|
||||
*
|
||||
* @param Carbon|null $start
|
||||
* @param Carbon|null $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get(?Carbon $start = null, ?Carbon $end = null): Collection
|
||||
{
|
||||
$query = $this->user->availableBudgets()->with(['transactionCurrency']);
|
||||
if (null !== $start && null !== $end) {
|
||||
$query->where(
|
||||
static function (Builder $q1) use ($start, $end) {
|
||||
$q1->where('start_date', '=', $start->format('Y-m-d'));
|
||||
$q1->where('end_date', '=', $end->format('Y-m-d'));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return $query->get(['available_budgets.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all available budgets.
|
||||
*/
|
||||
@@ -122,29 +165,6 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all available budgets (in all currencies) (for the selected period).
|
||||
*
|
||||
* @param Carbon|null $start
|
||||
* @param Carbon|null $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function get(?Carbon $start = null, ?Carbon $end = null): Collection
|
||||
{
|
||||
$query = $this->user->availableBudgets()->with(['transactionCurrency']);
|
||||
if (null !== $start && null !== $end) {
|
||||
$query->where(
|
||||
static function (Builder $q1) use ($start, $end) {
|
||||
$q1->where('start_date', '=', $start->format('Y-m-d'));
|
||||
$q1->where('end_date', '=', $end->format('Y-m-d'));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return $query->get(['available_budgets.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available budget objects.
|
||||
*
|
||||
@@ -180,6 +200,23 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available budget objects.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*
|
||||
*/
|
||||
public function getAvailableBudgetsByExactDate(Carbon $start, Carbon $end): Collection
|
||||
{
|
||||
return $this->user->availableBudgets()
|
||||
->where('start_date', '=', $start->format('Y-m-d'))
|
||||
->where('end_date', '=', $end->format('Y-m-d'))
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
@@ -35,6 +35,11 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface AvailableBudgetRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup(): void;
|
||||
|
||||
/**
|
||||
* Delete all available budgets.
|
||||
*/
|
||||
@@ -111,6 +116,14 @@ interface AvailableBudgetRepositoryInterface
|
||||
*/
|
||||
public function getAvailableBudgetsByDate(?Carbon $start, ?Carbon $end): Collection;
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAvailableBudgetsByExactDate(Carbon $start, Carbon $end): Collection;
|
||||
|
||||
/**
|
||||
* Get by transaction currency and date. Should always result in one entry or NULL.
|
||||
*
|
||||
|
58
app/Support/Binder/UserGroupBill.php
Normal file
58
app/Support/Binder/UserGroupBill.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AccountList.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Binder;
|
||||
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Routing\Route;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Class UserGroupBill.
|
||||
*/
|
||||
class UserGroupBill implements BinderInterface
|
||||
{
|
||||
/**
|
||||
* @param string $value
|
||||
* @param Route $route
|
||||
*
|
||||
* @return Bill
|
||||
* @throws NotFoundHttpException
|
||||
*
|
||||
*/
|
||||
public static function routeBinder(string $value, Route $route): Bill
|
||||
{
|
||||
if (auth()->check()) {
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$currency = Bill::where('id', (int)$value)
|
||||
->where('user_group_id', $user->user_group_id)
|
||||
->first();
|
||||
if (null !== $currency) {
|
||||
return $currency;
|
||||
}
|
||||
}
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
}
|
@@ -294,7 +294,7 @@ trait RenderPartialViews
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('Could not render', 0, $e);
|
||||
throw new FireflyException(sprintf('Could not render: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
|
||||
++$index;
|
||||
@@ -349,7 +349,7 @@ trait RenderPartialViews
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('Could not render', 0, $e);
|
||||
throw new FireflyException(sprintf('Could not render: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
|
||||
++$index;
|
||||
|
@@ -62,7 +62,7 @@ trait RuleManagement
|
||||
} catch (Throwable $e) {
|
||||
Log::error(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('Could not render', 0, $e);
|
||||
throw new FireflyException(sprintf('Could not render: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ trait RuleManagement
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('Could not render', 0, $e);
|
||||
throw new FireflyException(sprintf('Could not render: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
@@ -153,7 +153,7 @@ trait RuleManagement
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('Could not render', 0, $e);
|
||||
throw new FireflyException(sprintf('Could not render: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
|
40
app/Support/Notifications/UrlValidator.php
Normal file
40
app/Support/Notifications/UrlValidator.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* UrlValidator.php
|
||||
* Copyright (c) 2023 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\Support\Notifications;
|
||||
|
||||
/**
|
||||
* Class UrlValidator
|
||||
*/
|
||||
class UrlValidator
|
||||
{
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValidWebhookURL(string $url): bool
|
||||
{
|
||||
return str_starts_with($url, 'https://hooks.slack.com/services/') || str_starts_with($url, 'https://discord.com/api/webhooks/');
|
||||
}
|
||||
}
|
@@ -1004,151 +1004,151 @@ class OperatorQuerySearch implements SearchInterface
|
||||
//
|
||||
case '-date_on':
|
||||
case 'date_on':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setExactDateParams($range, $prohibited);
|
||||
return false;
|
||||
case 'date_before':
|
||||
case '-date_after':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setDateBeforeParams($range);
|
||||
return false;
|
||||
case 'date_after':
|
||||
case '-date_before':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setDateAfterParams($range);
|
||||
return false;
|
||||
|
||||
case 'interest_date_on':
|
||||
case '-interest_date_on':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setExactMetaDateParams('interest_date', $range, $prohibited);
|
||||
return false;
|
||||
case 'interest_date_before':
|
||||
case '-interest_date_after':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateBeforeParams('interest_date', $range);
|
||||
return false;
|
||||
case 'interest_date_after':
|
||||
case '-interest_date_before':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateAfterParams('interest_date', $range);
|
||||
return false;
|
||||
|
||||
case 'book_date_on':
|
||||
case '-book_date_on':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setExactMetaDateParams('book_date', $range, $prohibited);
|
||||
return false;
|
||||
case 'book_date_before':
|
||||
case '-book_date_after':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateBeforeParams('book_date', $range);
|
||||
return false;
|
||||
case 'book_date_after':
|
||||
case '-book_date_before':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateAfterParams('book_date', $range);
|
||||
return false;
|
||||
|
||||
case 'process_date_on':
|
||||
case '-process_date_on':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setExactMetaDateParams('process_date', $range, $prohibited);
|
||||
return false;
|
||||
case 'process_date_before':
|
||||
case '-process_date_after':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateBeforeParams('process_date', $range);
|
||||
return false;
|
||||
case 'process_date_after':
|
||||
case '-process_date_before':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateAfterParams('process_date', $range);
|
||||
return false;
|
||||
|
||||
case 'due_date_on':
|
||||
case '-due_date_on':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setExactMetaDateParams('due_date', $range, $prohibited);
|
||||
return false;
|
||||
case 'due_date_before':
|
||||
case '-due_date_after':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateBeforeParams('due_date', $range);
|
||||
return false;
|
||||
case 'due_date_after':
|
||||
case '-due_date_before':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateAfterParams('due_date', $range);
|
||||
return false;
|
||||
|
||||
case 'payment_date_on':
|
||||
case '-payment_date_on':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setExactMetaDateParams('payment_date', $range, $prohibited);
|
||||
return false;
|
||||
case 'payment_date_before':
|
||||
case '-payment_date_after':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateBeforeParams('payment_date', $range);
|
||||
return false;
|
||||
case 'payment_date_after':
|
||||
case '-payment_date_before':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateAfterParams('payment_date', $range);
|
||||
return false;
|
||||
|
||||
case 'invoice_date_on':
|
||||
case '-invoice_date_on':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setExactMetaDateParams('invoice_date', $range, $prohibited);
|
||||
return false;
|
||||
case 'invoice_date_before':
|
||||
case '-invoice_date_after':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateBeforeParams('invoice_date', $range);
|
||||
return false;
|
||||
case 'invoice_date_after':
|
||||
case '-invoice_date_before':
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setMetaDateAfterParams('invoice_date', $range);
|
||||
return false;
|
||||
|
||||
case 'created_at_on':
|
||||
case '-created_at_on':
|
||||
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setExactObjectDateParams('created_at', $range, $prohibited);
|
||||
return false;
|
||||
case 'created_at_before':
|
||||
case '-created_at_after':
|
||||
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setObjectDateBeforeParams('created_at', $range);
|
||||
return false;
|
||||
case 'created_at_after':
|
||||
case '-created_at_before':
|
||||
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setObjectDateAfterParams('created_at', $range);
|
||||
return false;
|
||||
|
||||
case 'updated_at_on':
|
||||
case '-updated_at_on':
|
||||
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setExactObjectDateParams('updated_at', $range, $prohibited);
|
||||
return false;
|
||||
case 'updated_at_before':
|
||||
case '-updated_at_after':
|
||||
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setObjectDateBeforeParams('updated_at', $range);
|
||||
return false;
|
||||
case 'updated_at_after':
|
||||
case '-updated_at_before':
|
||||
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
|
||||
$range = $this->parseDateRange($value);
|
||||
$range = $this->parseDateRange($operator, $value);
|
||||
$this->setObjectDateAfterParams('updated_at', $range);
|
||||
return false;
|
||||
//
|
||||
@@ -1550,13 +1550,22 @@ class OperatorQuerySearch implements SearchInterface
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function parseDateRange(string $value): array
|
||||
private function parseDateRange(string $type, string $value): array
|
||||
{
|
||||
$parser = new ParseDateString();
|
||||
if ($parser->isDateRange($value)) {
|
||||
return $parser->parseRange($value);
|
||||
}
|
||||
$parsedDate = $parser->parseDate($value);
|
||||
try {
|
||||
$parsedDate = $parser->parseDate($value);
|
||||
} catch (FireflyException $e) {
|
||||
Log::debug(sprintf('Could not parse date "%s", will return empty array.', $value));
|
||||
$this->invalidOperators[] = [
|
||||
'type' => $type,
|
||||
'value' => (string)$value,
|
||||
];
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'exact' => $parsedDate,
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Factory\TagFactory;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
@@ -61,7 +62,7 @@ class AddTag implements ActionInterface
|
||||
|
||||
if (null === $tag) {
|
||||
// could not find, could not create tag.
|
||||
Log::error(sprintf('RuleAction AddTag. Could not find or create tag "%s"', $this->action->action_value));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.find_or_create_tag_failed', ['tag' => $this->action->action_value])));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -78,12 +79,12 @@ class AddTag implements ActionInterface
|
||||
|
||||
// event for audit log entry
|
||||
event(new TriggeredAuditLog($this->action->rule, $object, 'add_tag', null, $tag->tag));
|
||||
|
||||
return true;
|
||||
}
|
||||
Log::debug(
|
||||
sprintf('RuleAction AddTag fired but tag %d ("%s") was already added to journal %d.', $tag->id, $tag->tag, $journal['transaction_journal_id'])
|
||||
);
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.tag_already_added', ['tag' => $this->action->action_value])));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
@@ -56,6 +57,7 @@ class AppendDescriptionToNotes implements ActionInterface
|
||||
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
|
||||
if (null === $object) {
|
||||
Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_other_user')));
|
||||
return false;
|
||||
}
|
||||
$note = $object->notes()->first();
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
@@ -60,6 +61,7 @@ class AppendNotesToDescription implements ActionInterface
|
||||
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
|
||||
if (null === $object) {
|
||||
Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_other_user')));
|
||||
return false;
|
||||
}
|
||||
$note = $object->notes()->first();
|
||||
@@ -80,6 +82,7 @@ class AppendNotesToDescription implements ActionInterface
|
||||
|
||||
return true;
|
||||
}
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.new_notes_empty')));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -56,6 +57,7 @@ class ClearBudget implements ActionInterface
|
||||
$budget = $object->budgets()->first();
|
||||
if (null === $budget) {
|
||||
Log::debug(sprintf('RuleAction ClearBudget, no budget in journal #%d.', $journal['transaction_journal_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_already_no_budget')));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -56,6 +57,7 @@ class ClearCategory implements ActionInterface
|
||||
$category = $object->categories()->first();
|
||||
if (null === $category) {
|
||||
Log::debug(sprintf('RuleAction ClearCategory, no category in journal #%d.', $journal['transaction_journal_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_already_no_category')));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -55,6 +56,7 @@ class ClearNotes implements ActionInterface
|
||||
$notes = $object->notes()->first();
|
||||
if (null === $notes) {
|
||||
Log::debug(sprintf('RuleAction ClearNotes, journal #%d has no notes.', $journal['transaction_journal_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_already_no_notes')));
|
||||
return false;
|
||||
}
|
||||
$before = $notes->text;
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\AccountFactory;
|
||||
@@ -65,11 +66,13 @@ class ConvertToDeposit implements ActionInterface
|
||||
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
|
||||
if (null === $object) {
|
||||
Log::error(sprintf('Cannot find journal #%d, cannot convert to deposit.', $journal['transaction_journal_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_not_found')));
|
||||
return false;
|
||||
}
|
||||
$groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count();
|
||||
if ($groupCount > 1) {
|
||||
Log::error(sprintf('Group #%d has more than one transaction in it, cannot convert to deposit.', $journal['transaction_group_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.split_group')));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -77,7 +80,7 @@ class ConvertToDeposit implements ActionInterface
|
||||
$type = $object->transactionType->type;
|
||||
if (TransactionType::DEPOSIT === $type) {
|
||||
Log::error(sprintf('Journal #%d is already a deposit (rule #%d).', $journal['transaction_journal_id'], $this->action->rule_id));
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.is_already_deposit')));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -89,6 +92,7 @@ class ConvertToDeposit implements ActionInterface
|
||||
} catch (JsonException | FireflyException $e) {
|
||||
Log::debug('Could not convert withdrawal to deposit.');
|
||||
Log::error($e->getMessage());
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -104,13 +108,14 @@ class ConvertToDeposit implements ActionInterface
|
||||
} catch (JsonException | FireflyException $e) {
|
||||
Log::debug('Could not convert transfer to deposit.');
|
||||
Log::error($e->getMessage());
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
|
||||
return false;
|
||||
}
|
||||
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::TRANSFER, TransactionType::DEPOSIT));
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.unsupported_transaction_type_deposit', ['type' => $type])));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,8 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
@@ -62,11 +64,13 @@ class ConvertToTransfer implements ActionInterface
|
||||
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
|
||||
if (null === $object) {
|
||||
Log::error(sprintf('Cannot find journal #%d, cannot convert to transfer.', $journal['transaction_journal_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_not_found')));
|
||||
return false;
|
||||
}
|
||||
$groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count();
|
||||
if ($groupCount > 1) {
|
||||
Log::error(sprintf('Group #%d has more than one transaction in it, cannot convert to transfer.', $journal['transaction_group_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.split_group')));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -77,15 +81,19 @@ class ConvertToTransfer implements ActionInterface
|
||||
Log::error(
|
||||
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')));
|
||||
|
||||
return false;
|
||||
}
|
||||
if (TransactionType::DEPOSIT !== $type && TransactionType::WITHDRAWAL !== $type) {
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.unsupported_transaction_type_transfer', ['type' => $type])));
|
||||
return false;
|
||||
}
|
||||
|
||||
// find the asset account in the action value.
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$repository->setUser($user);
|
||||
$opposing = null;
|
||||
$expectedType = null;
|
||||
if (TransactionType::WITHDRAWAL === $type) {
|
||||
$expectedType = $this->getSourceType($journalId);
|
||||
@@ -107,6 +115,7 @@ class ConvertToTransfer implements ActionInterface
|
||||
$this->action->rule_id
|
||||
)
|
||||
);
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_valid_opposing', ['name' => $this->action->action_value])));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -118,9 +127,12 @@ class ConvertToTransfer implements ActionInterface
|
||||
} catch (FireflyException $e) {
|
||||
Log::debug('Could not convert withdrawal to transfer.');
|
||||
Log::error($e->getMessage());
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
|
||||
return false;
|
||||
}
|
||||
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::WITHDRAWAL, TransactionType::TRANSFER));
|
||||
if (false !== $res) {
|
||||
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::WITHDRAWAL, TransactionType::TRANSFER));
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
if (TransactionType::DEPOSIT === $type) {
|
||||
@@ -130,12 +142,15 @@ class ConvertToTransfer implements ActionInterface
|
||||
} catch (FireflyException $e) {
|
||||
Log::debug('Could not convert deposit to transfer.');
|
||||
Log::error($e->getMessage());
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
|
||||
return false;
|
||||
}
|
||||
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::DEPOSIT, TransactionType::TRANSFER));
|
||||
if (false !== $res) {
|
||||
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::DEPOSIT, TransactionType::TRANSFER));
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.unsupported_transaction_type_transfer', ['type' => $type])));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -192,6 +207,7 @@ class ConvertToTransfer implements ActionInterface
|
||||
[$journal->id, $opposing->name, $this->action->rule_id]
|
||||
)
|
||||
);
|
||||
event(new RuleActionFailedOnObject($this->action, $journal, trans('rules.already_has_source_asset', ['name' => $opposing->name])));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -250,6 +266,7 @@ class ConvertToTransfer implements ActionInterface
|
||||
[$journal->id, $opposing->name, $this->action->rule_id]
|
||||
)
|
||||
);
|
||||
event(new RuleActionFailedOnObject($this->action, $journal, trans('rules.already_has_destination_asset', ['name' => $opposing->name])));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\AccountFactory;
|
||||
@@ -65,21 +66,26 @@ class ConvertToWithdrawal implements ActionInterface
|
||||
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
|
||||
if (null === $object) {
|
||||
Log::error(sprintf('Cannot find journal #%d, cannot convert to withdrawal.', $journal['transaction_journal_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_not_found')));
|
||||
return false;
|
||||
}
|
||||
$groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count();
|
||||
if ($groupCount > 1) {
|
||||
Log::error(sprintf('Group #%d has more than one transaction in it, cannot convert to withdrawal.', $journal['transaction_group_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.split_group')));
|
||||
return false;
|
||||
}
|
||||
|
||||
$type = $object->transactionType->type;
|
||||
if (TransactionType::WITHDRAWAL === $type) {
|
||||
Log::error(sprintf('Journal #%d is already a withdrawal (rule #%d).', $journal['transaction_journal_id'], $this->action->rule_id));
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.is_already_withdrawal')));
|
||||
return false;
|
||||
}
|
||||
if (TransactionType::DEPOSIT !== $type && TransactionType::TRANSFER !== $type) {
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.unsupported_transaction_type_withdrawal', ['type' => $type])));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TransactionType::DEPOSIT === $type) {
|
||||
Log::debug('Going to transform a deposit to a withdrawal.');
|
||||
try {
|
||||
@@ -87,6 +93,7 @@ class ConvertToWithdrawal implements ActionInterface
|
||||
} catch (JsonException | FireflyException $e) {
|
||||
Log::debug('Could not convert transfer to deposit.');
|
||||
Log::error($e->getMessage());
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
|
||||
return false;
|
||||
}
|
||||
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::DEPOSIT, TransactionType::WITHDRAWAL));
|
||||
@@ -101,13 +108,14 @@ class ConvertToWithdrawal implements ActionInterface
|
||||
} catch (JsonException | FireflyException $e) {
|
||||
Log::debug('Could not convert transfer to deposit.');
|
||||
Log::error($e->getMessage());
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
|
||||
return false;
|
||||
}
|
||||
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::TRANSFER, TransactionType::WITHDRAWAL));
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.unsupported_transaction_type_withdrawal', ['type' => $type])));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -73,6 +74,7 @@ class LinkToBill implements ActionInterface
|
||||
$billName
|
||||
)
|
||||
);
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.already_linked_to_subscription', ['name' => $billName])));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -97,7 +99,7 @@ class LinkToBill implements ActionInterface
|
||||
$billName
|
||||
)
|
||||
);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_subscription', ['name' => $billName])));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
@@ -57,6 +58,7 @@ class MoveDescriptionToNotes implements ActionInterface
|
||||
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
|
||||
if (null === $object) {
|
||||
Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_other_user')));
|
||||
return false;
|
||||
}
|
||||
$note = $object->notes()->first();
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -63,16 +64,19 @@ class MoveNotesToDescription implements ActionInterface
|
||||
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
|
||||
if (null === $object) {
|
||||
Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_other_user')));
|
||||
return false;
|
||||
}
|
||||
$note = $object->notes()->first();
|
||||
if (null === $note) {
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_notes_to_move')));
|
||||
// nothing to move, return null
|
||||
return false;
|
||||
}
|
||||
if ('' === $note->text) {
|
||||
// nothing to move, return null
|
||||
$note->delete();
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_notes_to_move')));
|
||||
return false;
|
||||
}
|
||||
$before = $object->description;
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -55,6 +56,7 @@ class RemoveAllTags implements ActionInterface
|
||||
$count = DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal['transaction_journal_id'])->count();
|
||||
if (0 === $count) {
|
||||
Log::debug(sprintf('RuleAction RemoveAllTags, journal #%d has no tags.', $journal['transaction_journal_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_tags_to_remove')));
|
||||
return false;
|
||||
}
|
||||
Log::debug(sprintf('RuleAction RemoveAllTags removed all tags from journal %d.', $journal['transaction_journal_id']));
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -61,6 +62,7 @@ class RemoveTag implements ActionInterface
|
||||
Log::debug(
|
||||
sprintf('RuleAction RemoveTag tried to remove tag "%s" from journal #%d but no such tag exists.', $name, $journal['transaction_journal_id'])
|
||||
);
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_tag', ['tag' => $name])));
|
||||
return false;
|
||||
}
|
||||
$count = DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal['transaction_journal_id'])->where('tag_id', $tag->id)->count();
|
||||
@@ -68,6 +70,7 @@ class RemoveTag implements ActionInterface
|
||||
Log::debug(
|
||||
sprintf('RuleAction RemoveTag tried to remove tag "%s" from journal #%d but no such tag is linked.', $name, $journal['transaction_journal_id'])
|
||||
);
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_unlink_tag', ['tag' => $name])));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -65,7 +66,7 @@ class SetBudget implements ActionInterface
|
||||
$search
|
||||
)
|
||||
);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_budget', ['name' => $search])));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -78,7 +79,7 @@ class SetBudget implements ActionInterface
|
||||
$journal['transaction_type_type']
|
||||
)
|
||||
);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_set_budget', ['type' => $journal['transaction_type_type'], 'name' => $search])));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Factory\CategoryFactory;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
@@ -57,7 +58,7 @@ class SetCategory implements ActionInterface
|
||||
$search = $this->action->action_value;
|
||||
if (null === $user) {
|
||||
Log::error(sprintf('Journal has no valid user ID so action SetCategory("%s") cannot be applied', $search), $journal);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_such_journal')));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -73,7 +74,7 @@ class SetCategory implements ActionInterface
|
||||
$search
|
||||
)
|
||||
);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_category', ['name' => $search])));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
@@ -65,7 +66,7 @@ class SetDestinationAccount implements ActionInterface
|
||||
|
||||
if (null === $object) {
|
||||
Log::error('Could not find journal.');
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_such_journal')));
|
||||
return false;
|
||||
}
|
||||
$type = $object->transactionType->type;
|
||||
@@ -81,7 +82,7 @@ class SetDestinationAccount implements ActionInterface
|
||||
$this->action->action_value
|
||||
)
|
||||
);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_asset', ['name' => $this->action->action_value])));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -90,13 +91,13 @@ class SetDestinationAccount implements ActionInterface
|
||||
$source = $object->transactions()->where('amount', '<', 0)->first();
|
||||
if (null === $source) {
|
||||
Log::error('Could not find source transaction.');
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_source_transaction')));
|
||||
return false;
|
||||
}
|
||||
// account must not be deleted (in the meantime):
|
||||
if (null === $source->account) {
|
||||
Log::error('Could not find source transaction account.');
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_source_transaction_account')));
|
||||
return false;
|
||||
}
|
||||
if (null !== $newAccount && (int)$newAccount->id === (int)$source->account_id) {
|
||||
@@ -108,6 +109,7 @@ class SetDestinationAccount implements ActionInterface
|
||||
)
|
||||
);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.already_has_destination', ['name' => $newAccount->name])));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
@@ -64,7 +65,7 @@ class SetSourceAccount implements ActionInterface
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
if (null === $object) {
|
||||
Log::error('Could not find journal.');
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_such_journal')));
|
||||
return false;
|
||||
}
|
||||
$type = $object->transactionType->type;
|
||||
@@ -76,7 +77,7 @@ class SetSourceAccount implements ActionInterface
|
||||
Log::error(
|
||||
sprintf('Cant change source account of journal #%d because no asset account with name "%s" exists.', $object->id, $this->action->action_value)
|
||||
);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_asset', ['name' => $this->action->action_value])));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -85,13 +86,13 @@ class SetSourceAccount implements ActionInterface
|
||||
$destination = $object->transactions()->where('amount', '>', 0)->first();
|
||||
if (null === $destination) {
|
||||
Log::error('Could not find destination transaction.');
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_destination_transaction')));
|
||||
return false;
|
||||
}
|
||||
// account must not be deleted (in the meantime):
|
||||
if (null === $destination->account) {
|
||||
Log::error('Could not find destination transaction account.');
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_destination_transaction_account')));
|
||||
return false;
|
||||
}
|
||||
if (null !== $newAccount && (int)$newAccount->id === (int)$destination->account_id) {
|
||||
@@ -102,12 +103,12 @@ class SetSourceAccount implements ActionInterface
|
||||
$destination->account_id
|
||||
)
|
||||
);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.already_has_source', ['name' => $newAccount->name])));
|
||||
return false;
|
||||
}
|
||||
|
||||
// if this is a deposit, the new source account must be a revenue account and may be created:
|
||||
// or its a liability
|
||||
// or it's a liability
|
||||
if (TransactionType::DEPOSIT === $type) {
|
||||
$newAccount = $this->findDepositSourceAccount();
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\Transaction;
|
||||
@@ -59,18 +60,20 @@ class SwitchAccounts implements ActionInterface
|
||||
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
|
||||
if (null === $object) {
|
||||
Log::error(sprintf('Cannot find journal #%d, cannot switch accounts.', $journal['transaction_journal_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_such_journal')));
|
||||
return false;
|
||||
}
|
||||
$groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count();
|
||||
if ($groupCount > 1) {
|
||||
Log::error(sprintf('Group #%d has more than one transaction in it, cannot switch accounts.', $journal['transaction_group_id']));
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.split_group')));
|
||||
return false;
|
||||
}
|
||||
|
||||
$type = $object->transactionType->type;
|
||||
if (TransactionType::TRANSFER !== $type) {
|
||||
Log::error(sprintf('Journal #%d is NOT a transfer (rule #%d), cannot switch accounts.', $journal['transaction_journal_id'], $this->action->rule_id));
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.is_not_transfer')));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -80,7 +83,7 @@ class SwitchAccounts implements ActionInterface
|
||||
$destTransaction = $object->transactions()->where('amount', '>', 0)->first();
|
||||
if (null === $sourceTransaction || null === $destTransaction) {
|
||||
Log::error(sprintf('Journal #%d has no source or destination transaction (rule #%d), cannot switch accounts.', $journal['transaction_journal_id'], $this->action->rule_id));
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_accounts')));
|
||||
return false;
|
||||
}
|
||||
$sourceAccountId = (int)$sourceTransaction->account_id;
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\TransactionRules\Actions;
|
||||
|
||||
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
|
||||
use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
@@ -61,16 +62,15 @@ class UpdatePiggybank implements ActionInterface
|
||||
// refresh the transaction type.
|
||||
$user = User::find($journal['user_id']);
|
||||
/** @var TransactionJournal $journalObj */
|
||||
$journalObj = $user->transactionJournals()->find($journal['transaction_journal_id']);
|
||||
$type = TransactionType::find((int)$journalObj->transaction_type_id);
|
||||
$journal['transaction_type_type'] = $type->type;
|
||||
$journalObj = $user->transactionJournals()->find($journal['transaction_journal_id']);
|
||||
$type = TransactionType::find((int)$journalObj->transaction_type_id);
|
||||
|
||||
$piggyBank = $this->findPiggyBank($user);
|
||||
if (null === $piggyBank) {
|
||||
Log::info(
|
||||
sprintf('No piggy bank named "%s", cant execute action #%d of rule #%d', $this->action->action_value, $this->action->id, $this->action->rule_id)
|
||||
);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_piggy', ['name' => $this->action->action_value])));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ class UpdatePiggybank implements ActionInterface
|
||||
$destination->account_id
|
||||
)
|
||||
);
|
||||
|
||||
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_link_piggy', ['name' => $this->action->action_value])));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -28,6 +28,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -38,6 +39,7 @@ use Illuminate\Support\Collection;
|
||||
class AccountTransformer extends AbstractTransformer
|
||||
{
|
||||
private array $accountMeta;
|
||||
private array $accountTypes;
|
||||
private array $balances;
|
||||
private array $convertedBalances;
|
||||
private array $currencies;
|
||||
@@ -51,6 +53,7 @@ class AccountTransformer extends AbstractTransformer
|
||||
{
|
||||
$this->currencies = [];
|
||||
$this->accountMeta = [];
|
||||
$this->accountTypes = [];
|
||||
$this->balances = app('steam')->balancesByAccounts($objects, $this->getDate());
|
||||
$this->convertedBalances = app('steam')->balancesByAccountsConverted($objects, $this->getDate());
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
@@ -72,6 +75,15 @@ class AccountTransformer extends AbstractTransformer
|
||||
$id = (int)$entry->account_id;
|
||||
$this->accountMeta[$id][$entry->name] = $entry->data;
|
||||
}
|
||||
// get account types:
|
||||
// select accounts.id, account_types.type from account_types left join accounts on accounts.account_type_id = account_types.id;
|
||||
$accountTypes = AccountType::leftJoin('accounts', 'accounts.account_type_id', '=', 'account_types.id')
|
||||
->whereIn('accounts.id', $accountIds)
|
||||
->get(['accounts.id', 'account_types.type']);
|
||||
/** @var AccountType $row */
|
||||
foreach ($accountTypes as $row) {
|
||||
$this->accountTypes[(int)$row->id] = (string)config(sprintf('firefly.shortNamesByFullName.%s', $row->type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,10 +108,13 @@ class AccountTransformer extends AbstractTransformer
|
||||
*/
|
||||
public function transform(Account $account): array
|
||||
{
|
||||
//$fullType = $account->accountType->type;
|
||||
//$accountType = (string) config(sprintf('firefly.shortNamesByFullName.%s', $fullType));
|
||||
$id = (int)$account->id;
|
||||
|
||||
// various meta
|
||||
$accountRole = $this->accountMeta[$id]['account_role'] ?? null;
|
||||
$accountType = $this->accountTypes[$id];
|
||||
$order = (int)$account->order;
|
||||
|
||||
// no currency? use default
|
||||
$currency = $this->default;
|
||||
if (0 !== (int)$this->accountMeta[$id]['currency_id']) {
|
||||
@@ -109,16 +124,21 @@ class AccountTransformer extends AbstractTransformer
|
||||
$balance = $this->balances[$id] ?? null;
|
||||
$nativeBalance = $this->convertedBalances[$id]['native_balance'] ?? null;
|
||||
|
||||
// no order for some accounts:
|
||||
if (!in_array(strtolower($accountType), ['liability', 'liabilities', 'asset'], true)) {
|
||||
$order = null;
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => (string)$account->id,
|
||||
'created_at' => $account->created_at->toAtomString(),
|
||||
'updated_at' => $account->updated_at->toAtomString(),
|
||||
'active' => $account->active,
|
||||
//'order' => $order,
|
||||
'order' => $order,
|
||||
'name' => $account->name,
|
||||
'iban' => '' === $account->iban ? null : $account->iban,
|
||||
// 'type' => strtolower($accountType),
|
||||
// 'account_role' => $accountRole,
|
||||
'type' => strtolower($accountType),
|
||||
'account_role' => $accountRole,
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
|
@@ -28,9 +28,11 @@ use Carbon\CarbonInterface;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Log;
|
||||
@@ -40,6 +42,7 @@ use Log;
|
||||
*/
|
||||
class BillTransformer extends AbstractTransformer
|
||||
{
|
||||
private ExchangeRateConverter $converter;
|
||||
private array $currencies;
|
||||
private TransactionCurrency $default;
|
||||
private array $groups;
|
||||
@@ -102,21 +105,71 @@ class BillTransformer extends AbstractTransformer
|
||||
];
|
||||
|
||||
}
|
||||
$this->default = app('amount')->getDefaultCurrency();
|
||||
|
||||
$this->default = app('amount')->getDefaultCurrency();
|
||||
$this->converter = new ExchangeRateConverter();
|
||||
// grab all paid dates:
|
||||
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
|
||||
$journals = TransactionJournal::whereIn('bill_id', $bills)
|
||||
->where('date', '>=', $this->parameters->get('start'))
|
||||
->where('date', '<=', $this->parameters->get('end'))
|
||||
->get(['transaction_journals.id', 'transaction_journals.transaction_group_id', 'transaction_journals.date', 'transaction_journals.bill_id']);
|
||||
$journals = TransactionJournal::whereIn('bill_id', $bills)
|
||||
->where('date', '>=', $this->parameters->get('start'))
|
||||
->where('date', '<=', $this->parameters->get('end'))
|
||||
->get(['transaction_journals.id', 'transaction_journals.transaction_group_id', 'transaction_journals.date', 'transaction_journals.bill_id']);
|
||||
$journalIds = $journals->pluck('id')->toArray();
|
||||
|
||||
// grab transactions for amount:
|
||||
$set = Transaction::whereIn('transaction_journal_id', $journalIds)
|
||||
->where('transactions.amount', '<', 0)
|
||||
->get(['transactions.id', 'transactions.transaction_journal_id', 'transactions.amount', 'transactions.foreign_amount', 'transactions.transaction_currency_id', 'transactions.foreign_currency_id']);
|
||||
// convert to array for easy finding:
|
||||
$transactions = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
$journalId = (int)$transaction->transaction_journal_id;
|
||||
$transactions[$journalId] = $transaction->toArray();
|
||||
}
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$billId = (int)$journal->bill_id;
|
||||
$transaction = $transactions[(int)$journal->id] ?? [];
|
||||
$billId = (int)$journal->bill_id;
|
||||
$currencyId = (int)$transaction['transaction_currency_id'] ?? 0;
|
||||
$currencies[$currencyId] = $currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
|
||||
|
||||
// foreign currency
|
||||
$foreignCurrencyId = null;
|
||||
$foreignCurrencyCode = null;
|
||||
$foreignCurrencyName = null;
|
||||
$foreignCurrencySymbol = null;
|
||||
$foreignCurrencyDp = null;
|
||||
if (null !== $transaction['foreign_currency_id']) {
|
||||
$foreignCurrencyId = (int)$transaction['foreign_currency_id'];
|
||||
$currencies[$foreignCurrencyId] = $currencies[$foreignCurrencyId] ?? TransactionCurrency::find($foreignCurrencyId);
|
||||
$foreignCurrencyCode = $currencies[$foreignCurrencyId]->code;
|
||||
$foreignCurrencyName = $currencies[$foreignCurrencyId]->name;
|
||||
$foreignCurrencySymbol = $currencies[$foreignCurrencyId]->symbol;
|
||||
$foreignCurrencyDp = (int)$currencies[$foreignCurrencyId]->decimal_places;
|
||||
}
|
||||
|
||||
$this->paidDates[$billId][] = [
|
||||
'transaction_group_id' => (string)$journal->id,
|
||||
'transaction_journal_id' => (string)$journal->transaction_group_id,
|
||||
'date' => $journal->date->toAtomString(),
|
||||
'transaction_group_id' => (string)$journal->id,
|
||||
'transaction_journal_id' => (string)$journal->transaction_group_id,
|
||||
'date' => $journal->date->toAtomString(),
|
||||
'currency_id' => (int)$currencies[$currencyId]->id,
|
||||
'currency_code' => $currencies[$currencyId]->code,
|
||||
'currency_name' => $currencies[$currencyId]->name,
|
||||
'currency_symbol' => $currencies[$currencyId]->symbol,
|
||||
'currency_decimal_places' => (int)$currencies[$currencyId]->decimal_places,
|
||||
'native_id' => (int)$currencies[$currencyId]->id,
|
||||
'native_code' => $currencies[$currencyId]->code,
|
||||
'native_symbol' => $currencies[$currencyId]->symbol,
|
||||
'native_decimal_places' => (int)$currencies[$currencyId]->decimal_places,
|
||||
'foreign_currency_id' => $foreignCurrencyId,
|
||||
'foreign_currency_code' => $foreignCurrencyCode,
|
||||
'foreign_currency_name' => $foreignCurrencyName,
|
||||
'foreign_currency_symbol' => $foreignCurrencySymbol,
|
||||
'foreign_currency_decimal_places' => $foreignCurrencyDp,
|
||||
'amount' => $transaction['amount'],
|
||||
'foreign_amount' => $transaction['foreign_amount'],
|
||||
'native_amount' => $this->converter->convert($currencies[$currencyId], $this->default, $journal->date, $transaction['amount']),
|
||||
'foreign_native_amount' => null === $transaction['foreign_amount'] ? null : $this->converter->convert($currencies[$foreignCurrencyId], $this->default, $journal->date, $transaction['foreign_amount']),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -131,11 +184,19 @@ class BillTransformer extends AbstractTransformer
|
||||
*/
|
||||
public function transform(Bill $bill): array
|
||||
{
|
||||
$paidData = $this->paidDates[(int)$bill->id] ?? [];
|
||||
$nextExpectedMatch = $this->nextExpectedMatch($bill, $this->paidDates[(int)$bill->id] ?? []);
|
||||
$payDates = $this->payDates($bill);
|
||||
$currency = $this->currencies[(int)$bill->transaction_currency_id];
|
||||
$group = $this->groups[(int)$bill->id] ?? null;
|
||||
$paidData = $this->paidDates[(int)$bill->id] ?? [];
|
||||
$nextExpectedMatch = $this->nextExpectedMatch($bill, $this->paidDates[(int)$bill->id] ?? []);
|
||||
$payDates = $this->payDates($bill);
|
||||
$currency = $this->currencies[(int)$bill->transaction_currency_id];
|
||||
$group = $this->groups[(int)$bill->id] ?? null;
|
||||
|
||||
// date for currency conversion
|
||||
/** @var Carbon|null $startParam */
|
||||
$startParam = $this->parameters->get('start');
|
||||
/** @var Carbon|null $start */
|
||||
$date = null === $startParam ? today() : clone $startParam;
|
||||
|
||||
|
||||
$nextExpectedMatchDiff = $this->getNextExpectedMatchDiff($nextExpectedMatch, $payDates);
|
||||
return [
|
||||
'id' => (int)$bill->id,
|
||||
@@ -144,10 +205,18 @@ class BillTransformer extends AbstractTransformer
|
||||
'name' => $bill->name,
|
||||
'amount_min' => app('steam')->bcround($bill->amount_min, $currency->decimal_places),
|
||||
'amount_max' => app('steam')->bcround($bill->amount_max, $currency->decimal_places),
|
||||
'native_amount_min' => $this->converter->convert($currency, $this->default, $date, $bill->amount_min),
|
||||
'native_amount_max' => $this->converter->convert($currency, $this->default, $date, $bill->amount_max),
|
||||
'currency_id' => (string)$bill->transaction_currency_id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_name' => $currency->name,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => (int)$currency->decimal_places,
|
||||
'native_id' => $this->default->id,
|
||||
'native_code' => $this->default->code,
|
||||
'native_name' => $this->default->name,
|
||||
'native_symbol' => $this->default->symbol,
|
||||
'native_decimal_places' => (int)$this->default->decimal_places,
|
||||
'date' => $bill->date->toAtomString(),
|
||||
'end_date' => $bill->end_date?->toAtomString(),
|
||||
'extension_date' => $bill->extension_date?->toAtomString(),
|
||||
@@ -185,8 +254,11 @@ class BillTransformer extends AbstractTransformer
|
||||
// 2023-07-1 sub one day from the start date to fix a possible bug (see #7704)
|
||||
// 2023-07-18 this particular date is used to search for the last paid date.
|
||||
// 2023-07-18 the cloned $searchDate is used to grab the correct transactions.
|
||||
/** @var Carbon $start */
|
||||
$start = clone $this->parameters->get('start');
|
||||
|
||||
/** @var Carbon|null $startParam */
|
||||
$startParam = $this->parameters->get('start');
|
||||
/** @var Carbon|null $start */
|
||||
$start = null === $startParam ? today() : clone $startParam;
|
||||
$start->subDay();
|
||||
|
||||
$lastPaidDate = $this->lastPaidDate($dates, $start);
|
||||
|
@@ -302,7 +302,7 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
if (null === $string) {
|
||||
return null;
|
||||
}
|
||||
Log::debug(sprintf('Now in date("%s")', $string));
|
||||
// Log::debug(sprintf('Now in date("%s")', $string));
|
||||
if (10 === strlen($string)) {
|
||||
return Carbon::createFromFormat('Y-m-d', $string, config('app.timezone'));
|
||||
}
|
||||
|
@@ -114,7 +114,11 @@ trait DepositValidation
|
||||
|
||||
// source can be any of the following types.
|
||||
$validTypes = array_keys($this->combinations[$this->transactionType]);
|
||||
if (null === $accountId && null === $accountName && false === $this->canCreateTypes($validTypes)) {
|
||||
if (null === $accountId &&
|
||||
null === $accountName &&
|
||||
null === $accountIban &&
|
||||
null === $accountNumber &&
|
||||
false === $this->canCreateTypes($validTypes)) {
|
||||
// if both values are NULL return false,
|
||||
// because the source of a deposit can't be created.
|
||||
// (this never happens).
|
||||
@@ -122,12 +126,12 @@ trait DepositValidation
|
||||
$result = false;
|
||||
}
|
||||
|
||||
// if there is an iban, it can only be in use by a revenue account or we will fail.
|
||||
// if there is an iban, it can only be in use by a revenue account, or we will fail.
|
||||
if (null !== $accountIban && '' !== $accountIban) {
|
||||
app('log')->debug('Check if there is not already an account with this IBAN');
|
||||
$existing = $this->findExistingAccount([AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], ['iban' => $accountIban]);
|
||||
if (null !== $existing) {
|
||||
$this->destError = (string)trans('validation.deposit_src_iban_exists');
|
||||
$this->sourceError = (string)trans('validation.deposit_src_iban_exists');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -265,6 +265,7 @@ class AccountValidator
|
||||
if (null !== $accountId && $accountId > 0) {
|
||||
$first = $this->accountRepository->find($accountId);
|
||||
if ((null !== $first) && in_array($first->accountType->type, $validTypes, true)) {
|
||||
app('log')->debug(sprintf('ID: Found %s account #%d ("%s", IBAN "%s")', $first->accountType->type, $first->id, $first->name, $first->iban ?? 'no iban'));
|
||||
return $first;
|
||||
}
|
||||
}
|
||||
@@ -273,6 +274,7 @@ class AccountValidator
|
||||
if (null !== $accountIban && '' !== (string)$accountIban) {
|
||||
$first = $this->accountRepository->findByIbanNull($accountIban, $validTypes);
|
||||
if ((null !== $first) && in_array($first->accountType->type, $validTypes, true)) {
|
||||
app('log')->debug(sprintf('Iban: Found %s account #%d ("%s", IBAN "%s")', $first->accountType->type, $first->id, $first->name, $first->iban ?? 'no iban'));
|
||||
return $first;
|
||||
}
|
||||
}
|
||||
@@ -281,14 +283,20 @@ class AccountValidator
|
||||
if (null !== $accountNumber && '' !== (string)$accountNumber) {
|
||||
$first = $this->accountRepository->findByAccountNumber($accountNumber, $validTypes);
|
||||
if ((null !== $first) && in_array($first->accountType->type, $validTypes, true)) {
|
||||
app('log')->debug(sprintf('Number: Found %s account #%d ("%s", IBAN "%s")', $first->accountType->type, $first->id, $first->name, $first->iban ?? 'no iban'));
|
||||
return $first;
|
||||
}
|
||||
}
|
||||
|
||||
// find by name:
|
||||
if ('' !== (string)$accountName) {
|
||||
return $this->accountRepository->findByName($accountName, $validTypes);
|
||||
$first = $this->accountRepository->findByName($accountName, $validTypes);
|
||||
if (null !== $first) {
|
||||
app('log')->debug(sprintf('Name: Found %s account #%d ("%s", IBAN "%s")', $first->accountType->type, $first->id, $first->name, $first->iban ?? 'no iban'));
|
||||
return $first;
|
||||
}
|
||||
}
|
||||
app('log')->debug('Found nothing!');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@@ -103,6 +103,7 @@ trait TransactionValidation
|
||||
*/
|
||||
protected function validateSingleAccount(Validator $validator, int $index, string $transactionType, array $transaction): void
|
||||
{
|
||||
app('log')->debug(sprintf('Now in validateSingleAccount(%d)', $index));
|
||||
/** @var AccountValidator $accountValidator */
|
||||
$accountValidator = app(AccountValidator::class);
|
||||
|
||||
@@ -784,8 +785,8 @@ trait TransactionValidation
|
||||
private function compareAccountData(string $type, array $comparison): bool
|
||||
{
|
||||
return match ($type) {
|
||||
default => $this->compareAccountDataWithdrawal($comparison),
|
||||
'deposit' => $this->compareAccountDataDeposit($comparison),
|
||||
default => $this->compareAccountDataWithdrawal($comparison),
|
||||
'deposit' => $this->compareAccountDataDeposit($comparison),
|
||||
'transfer' => $this->compareAccountDataTransfer($comparison),
|
||||
};
|
||||
}
|
||||
|
41
changelog.md
41
changelog.md
@@ -3,6 +3,47 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 6.0.23 - 2023-09-04
|
||||
|
||||
### Changed
|
||||
|
||||
- New debug information tables are in HTML
|
||||
|
||||
### Fixed
|
||||
|
||||
- Remove extra slashes from paths, breaking CSS
|
||||
|
||||
## 6.0.22 - 2023-09-02
|
||||
|
||||
### API
|
||||
|
||||
- [Issue 7917](https://github.com/firefly-iii/firefly-iii/issues/7917) Fixed an API issue where submitting an account name would not be accepted.
|
||||
|
||||
## 6.0.21 - 2023-09-02
|
||||
|
||||
### Added
|
||||
|
||||
- Rules will now report failures if a Slack/Discord notification channel is configured
|
||||
- Notifications can be sent to Discord
|
||||
- Beta layout `v2`, activate with `FIREFLY_III_LAYOUT=v2`
|
||||
|
||||
### Changed
|
||||
|
||||
- Audit log settings are changed, refer to the `.env.example`-file.
|
||||
- Many URLs are new rendered as relative URLs.
|
||||
|
||||
### Fixed
|
||||
|
||||
- [Issue 7853](https://github.com/firefly-iii/firefly-iii/issues/7853) Left to spend on main page shows incorrect value
|
||||
- [Issue 7883](https://github.com/firefly-iii/firefly-iii/issues/7883) Missing translation
|
||||
- [Issue 7910](https://github.com/firefly-iii/firefly-iii/issues/7910) Type format error
|
||||
- Home page respects account order
|
||||
- JS errors for users using Firefly III in a subdir.
|
||||
|
||||
### API
|
||||
|
||||
- Bumped to v2.0.6 but only so the docs match again.
|
||||
|
||||
## 6.0.20 - 2023-08-13
|
||||
|
||||
### Fixed
|
||||
|
@@ -85,7 +85,7 @@
|
||||
"diglactic/laravel-breadcrumbs": "^8.1",
|
||||
"doctrine/dbal": "3.*",
|
||||
"gdbots/query-parser": "^3.0",
|
||||
"guzzlehttp/guzzle": "^7.7",
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"jc5/google2fa-laravel": "^2.0",
|
||||
"jc5/recovery": "^2",
|
||||
"laravel/framework": "^10",
|
||||
@@ -111,7 +111,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-ide-helper": "2.*",
|
||||
"ergebnis/phpstan-rules": "^2.0",
|
||||
"ergebnis/phpstan-rules": "^2.1",
|
||||
"fakerphp/faker": "1.*",
|
||||
"filp/whoops": "2.*",
|
||||
"mockery/mockery": "1.*",
|
||||
|
670
composer.lock
generated
670
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -61,6 +61,7 @@ use FireflyIII\Support\Binder\JournalList;
|
||||
use FireflyIII\Support\Binder\TagList;
|
||||
use FireflyIII\Support\Binder\TagOrId;
|
||||
use FireflyIII\Support\Binder\UserGroupAccount;
|
||||
use FireflyIII\Support\Binder\UserGroupBill;
|
||||
use FireflyIII\TransactionRules\Actions\AddTag;
|
||||
use FireflyIII\TransactionRules\Actions\AppendDescription;
|
||||
use FireflyIII\TransactionRules\Actions\AppendDescriptionToNotes;
|
||||
@@ -110,8 +111,8 @@ return [
|
||||
'handle_debts' => true,
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => '6.0.20',
|
||||
'api_version' => '2.0.6',
|
||||
'version' => '6.0.23',
|
||||
'api_version' => '2.0.7',
|
||||
'db_version' => 20,
|
||||
|
||||
// generic settings
|
||||
@@ -148,7 +149,7 @@ return [
|
||||
'update_minimum_age' => 7,
|
||||
|
||||
// notifications
|
||||
'available_notifications' => ['bill_reminder', 'new_access_token', 'transaction_creation', 'user_login'],
|
||||
'available_notifications' => ['bill_reminder', 'new_access_token', 'transaction_creation', 'user_login', 'rule_action_failures'],
|
||||
'admin_notifications' => ['admin_new_reg', 'user_new_reg', 'new_version', 'invite_created', 'invite_redeemed'],
|
||||
|
||||
// enabled languages
|
||||
@@ -480,6 +481,7 @@ return [
|
||||
|
||||
// V2 API endpoints:
|
||||
'userGroupAccount' => UserGroupAccount::class,
|
||||
'userGroupBill' => UserGroupBill::class,
|
||||
|
||||
|
||||
],
|
||||
|
@@ -24,6 +24,30 @@ declare(strict_types=1);
|
||||
use FireflyIII\Support\Logging\AuditLogger;
|
||||
use Monolog\Handler\SyslogUdpHandler;
|
||||
|
||||
// standard config for both log things:
|
||||
$defaultChannels = ['daily', 'stdout'];
|
||||
$auditChannels = ['audit_daily', 'audit_stdout'];
|
||||
|
||||
|
||||
// validChannels is missing 'stack' because we already check for that one.
|
||||
$validChannels = ['single', 'papertrail', 'stdout', 'daily', 'syslog', 'errorlog'];
|
||||
$validAuditChannels = ['audit_papertrail', 'audit_stdout', 'audit_stdout', 'audit_daily', 'audit_syslog', 'audit_errorlog'];
|
||||
|
||||
// which settings did the user set, if any?
|
||||
$defaultLogChannel = (string)envNonEmpty('LOG_CHANNEL', 'stack');
|
||||
$auditLogChannel = (string)envNonEmpty('AUDIT_LOG_CHANNEL', '');
|
||||
|
||||
if ('stack' === $defaultLogChannel) {
|
||||
$defaultChannels = ['daily', 'stdout'];
|
||||
}
|
||||
if (in_array($defaultLogChannel, $validChannels, true)) {
|
||||
$defaultChannels = [$defaultLogChannel];
|
||||
}
|
||||
|
||||
if (in_array($auditLogChannel, $validAuditChannels, true)) {
|
||||
$auditChannels = [$auditLogChannel];
|
||||
}
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -53,16 +77,27 @@ return [
|
||||
*/
|
||||
|
||||
'channels' => [
|
||||
// default channels for 'stack' and audit logs:
|
||||
'stack' => [
|
||||
/*
|
||||
* 'stack' and 'audit' are the two "generic" channels that
|
||||
* are valid destinations for logs.
|
||||
*/
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => ['daily', 'stdout'],
|
||||
'channels' => $defaultChannels,
|
||||
],
|
||||
'audit' => [
|
||||
'audit' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => ['audit_daily', 'audit_stdout'],
|
||||
'channels' => $auditChannels,
|
||||
],
|
||||
'papertrail' => [
|
||||
/*
|
||||
* There are 6 valid destinations for the normal logs, listed below:
|
||||
*/
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
],
|
||||
'papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
'handler' => SyslogUdpHandler::class,
|
||||
@@ -71,55 +106,65 @@ return [
|
||||
'port' => env('PAPERTRAIL_PORT'),
|
||||
],
|
||||
],
|
||||
|
||||
// single laravel log file:
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
],
|
||||
|
||||
// stdout, used in stack 'stack' by default:
|
||||
'stdout' => [
|
||||
'stdout' => [
|
||||
'driver' => 'single',
|
||||
'path' => 'php://stdout',
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
],
|
||||
|
||||
// daily, used in stack 'stack' by default:
|
||||
'daily' => [
|
||||
'daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/ff3-' . PHP_SAPI . '.log'),
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
'days' => 7,
|
||||
],
|
||||
'syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
],
|
||||
'errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
],
|
||||
|
||||
// the audit log destinations:
|
||||
'audit_daily' => [
|
||||
/*
|
||||
* There are 5 valid destinations for the audit logs, listed below.
|
||||
* The only one missing is "single".
|
||||
*/
|
||||
'audit_papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => envNonEmpty('AUDIT_LOG_LEVEL', 'info'),
|
||||
'handler' => SyslogUdpHandler::class,
|
||||
'tap' => [AuditLogger::class],
|
||||
'handler_with' => [
|
||||
'host' => env('PAPERTRAIL_HOST'),
|
||||
'port' => env('PAPERTRAIL_PORT'),
|
||||
],
|
||||
],
|
||||
'audit_stdout' => [
|
||||
'driver' => 'single',
|
||||
'path' => 'php://stdout',
|
||||
'tap' => [AuditLogger::class],
|
||||
'level' => envNonEmpty('AUDIT_LOG_LEVEL', 'info'),
|
||||
],
|
||||
'audit_daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/ff3-audit.log'),
|
||||
'tap' => [AuditLogger::class],
|
||||
'level' => envNonEmpty('AUDIT_LOG_LEVEL', 'info'),
|
||||
'days' => 90,
|
||||
],
|
||||
'audit_stdout' => [
|
||||
'driver' => 'single',
|
||||
'path' => 'php://stdout',
|
||||
'audit_syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'tap' => [AuditLogger::class],
|
||||
'level' => envNonEmpty('AUDIT_LOG_LEVEL', 'info'),
|
||||
],
|
||||
'audit_errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'tap' => [AuditLogger::class],
|
||||
'level' => envNonEmpty('AUDIT_LOG_LEVEL', 'info'),
|
||||
],
|
||||
|
||||
// syslog destination
|
||||
'syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
],
|
||||
|
||||
// errorlog destination
|
||||
'errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'level' => envNonEmpty('APP_LOG_LEVEL', 'info'),
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user