mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-08-16 10:54:39 +00:00
Compare commits
87 Commits
develop-20
...
v6.1.21
Author | SHA1 | Date | |
---|---|---|---|
|
abcddb09bf | ||
|
cf71a0fc55 | ||
|
78253f9e1e | ||
|
ebd0848c7f | ||
|
c8461eb0b5 | ||
|
a4cbdeaeac | ||
|
3e1ce69d52 | ||
|
08a26b976e | ||
|
5fc55381a2 | ||
|
dbf3d24ae7 | ||
|
cc7c6e02c5 | ||
|
b45aa85853 | ||
|
e7526ac5e3 | ||
|
441ada70b8 | ||
|
dedc06a46b | ||
|
b0adf1b277 | ||
|
28f65e9f44 | ||
|
a013af5f0d | ||
|
9552701662 | ||
|
ef52f0aad1 | ||
|
0b6f04905a | ||
|
cdb36357d4 | ||
|
8938622bd9 | ||
|
b210294aa9 | ||
|
5b02f20775 | ||
|
fac382a5df | ||
|
88d88bebc9 | ||
|
755fb9c29b | ||
|
51a835ab51 | ||
|
c9895ab182 | ||
|
e71d46a4e5 | ||
|
8d1d5f37c1 | ||
|
525a68682d | ||
|
715648d0d8 | ||
|
9452e93f22 | ||
|
a6aa145471 | ||
|
25aa6dcb59 | ||
|
bb2270b274 | ||
|
d7f6b4143e | ||
|
0cf0e26fa8 | ||
|
cc23197d60 | ||
|
bc1721d95e | ||
|
0d19173da6 | ||
|
1983f07d3c | ||
|
aad1b91cc2 | ||
|
8cb1057a33 | ||
|
b178032985 | ||
|
561213e95d | ||
|
44fa7c4306 | ||
|
e2169563e2 | ||
|
845344e003 | ||
|
cdb48453e8 | ||
|
9669cef518 | ||
|
f962f71ed7 | ||
|
94ed4021fb | ||
|
1765855c57 | ||
|
55cf3e7d44 | ||
|
9f1840dc05 | ||
|
78dab2e5f9 | ||
|
103b9d5005 | ||
|
1b75b778d8 | ||
|
7e665dbdfc | ||
|
b6897ec3a9 | ||
|
660260174a | ||
|
78d32865b5 | ||
|
edfa92c1aa | ||
|
63012f269c | ||
|
7d0e7f779f | ||
|
b8e18f80f4 | ||
|
481b01e4f7 | ||
|
edf2030251 | ||
|
bd1cfffb61 | ||
|
629f70d27d | ||
|
57f5ebc0f9 | ||
|
b4f51e7b47 | ||
|
d78d254e86 | ||
|
eb0c113699 | ||
|
23045ebd59 | ||
|
2e5931f304 | ||
|
a620b07c00 | ||
|
cb724145f2 | ||
|
8ef17f6686 | ||
|
debfd9160c | ||
|
f2482e4ace | ||
|
d98d757f8b | ||
|
0c9a41a929 | ||
|
e26f78bf50 |
212
.ci/php-cs-fixer/composer.lock
generated
212
.ci/php-cs-fixer/composer.lock
generated
@@ -72,26 +72,26 @@
|
||||
},
|
||||
{
|
||||
"name": "composer/pcre",
|
||||
"version": "3.2.0",
|
||||
"version": "3.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/pcre.git",
|
||||
"reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90"
|
||||
"reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/ea4ab6f9580a4fd221e0418f2c357cdd39102a90",
|
||||
"reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4",
|
||||
"reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan": "<1.11.8"
|
||||
"phpstan/phpstan": "<1.11.10"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.11.8",
|
||||
"phpstan/phpstan": "^1.11.10",
|
||||
"phpstan/phpstan-strict-rules": "^1.1",
|
||||
"phpunit/phpunit": "^8 || ^9"
|
||||
},
|
||||
@@ -131,7 +131,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/pcre/issues",
|
||||
"source": "https://github.com/composer/pcre/tree/3.2.0"
|
||||
"source": "https://github.com/composer/pcre/tree/3.3.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -147,28 +147,28 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-25T09:36:02+00:00"
|
||||
"time": "2024-08-27T18:44:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "3.4.2",
|
||||
"version": "3.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/semver.git",
|
||||
"reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6"
|
||||
"reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/c51258e759afdb17f1fd1fe83bc12baaef6309d6",
|
||||
"reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
|
||||
"reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"symfony/phpunit-bridge": "^4.2 || ^5"
|
||||
"phpstan/phpstan": "^1.11",
|
||||
"symfony/phpunit-bridge": "^3 || ^7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -212,7 +212,7 @@
|
||||
"support": {
|
||||
"irc": "ircs://irc.libera.chat:6697/composer",
|
||||
"issues": "https://github.com/composer/semver/issues",
|
||||
"source": "https://github.com/composer/semver/tree/3.4.2"
|
||||
"source": "https://github.com/composer/semver/tree/3.4.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -228,7 +228,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-12T11:35:52+00:00"
|
||||
"time": "2024-09-19T14:15:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/xdebug-handler",
|
||||
@@ -345,16 +345,16 @@
|
||||
},
|
||||
{
|
||||
"name": "fidry/cpu-core-counter",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theofidry/cpu-core-counter.git",
|
||||
"reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42"
|
||||
"reference": "8520451a140d3f46ac33042715115e290cf5785f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42",
|
||||
"reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42",
|
||||
"url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f",
|
||||
"reference": "8520451a140d3f46ac33042715115e290cf5785f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -394,7 +394,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/theofidry/cpu-core-counter/issues",
|
||||
"source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0"
|
||||
"source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -402,20 +402,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-02-07T09:43:46+00:00"
|
||||
"time": "2024-08-06T10:04:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.61.1",
|
||||
"version": "v3.64.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "94a87189f55814e6cabca2d9a33b06de384a2ab8"
|
||||
"reference": "58dd9c931c785a79739310aef5178928305ffa67"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/94a87189f55814e6cabca2d9a33b06de384a2ab8",
|
||||
"reference": "94a87189f55814e6cabca2d9a33b06de384a2ab8",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/58dd9c931c785a79739310aef5178928305ffa67",
|
||||
"reference": "58dd9c931c785a79739310aef5178928305ffa67",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -497,7 +497,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.61.1"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.64.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -505,7 +505,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-31T14:33:15+00:00"
|
||||
"time": "2024-08-30T23:09:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
@@ -612,16 +612,16 @@
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
|
||||
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
|
||||
"reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
|
||||
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -656,9 +656,9 @@
|
||||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/log/tree/3.0.0"
|
||||
"source": "https://github.com/php-fig/log/tree/3.0.2"
|
||||
},
|
||||
"time": "2021-07-14T16:46:02+00:00"
|
||||
"time": "2024-09-11T13:17:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/cache",
|
||||
@@ -1259,16 +1259,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v7.1.3",
|
||||
"version": "v7.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9"
|
||||
"reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9",
|
||||
"reference": "cb1dcb30ebc7005c29864ee78adb47b5fb7c3cd9",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/0fa539d12b3ccf068a722bbbffa07ca7079af9ee",
|
||||
"reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1332,7 +1332,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v7.1.3"
|
||||
"source": "https://github.com/symfony/console/tree/v7.1.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1348,7 +1348,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-26T12:41:01+00:00"
|
||||
"time": "2024-09-20T08:28:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
@@ -1575,16 +1575,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v7.1.2",
|
||||
"version": "v7.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "92a91985250c251de9b947a14bb2c9390b1a562c"
|
||||
"reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/92a91985250c251de9b947a14bb2c9390b1a562c",
|
||||
"reference": "92a91985250c251de9b947a14bb2c9390b1a562c",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/61fe0566189bf32e8cfee78335d8776f64a66f5a",
|
||||
"reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1621,7 +1621,7 @@
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v7.1.2"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v7.1.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1637,20 +1637,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-28T10:03:55+00:00"
|
||||
"time": "2024-09-17T09:16:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v7.1.3",
|
||||
"version": "v7.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "717c6329886f32dc65e27461f80f2a465412fdca"
|
||||
"reference": "d95bbf319f7d052082fb7af147e0f835a695e823"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/717c6329886f32dc65e27461f80f2a465412fdca",
|
||||
"reference": "717c6329886f32dc65e27461f80f2a465412fdca",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/d95bbf319f7d052082fb7af147e0f835a695e823",
|
||||
"reference": "d95bbf319f7d052082fb7af147e0f835a695e823",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1685,7 +1685,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v7.1.3"
|
||||
"source": "https://github.com/symfony/finder/tree/v7.1.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1701,7 +1701,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-24T07:08:44+00:00"
|
||||
"time": "2024-08-13T14:28:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
@@ -1772,20 +1772,20 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "0424dff1c58f028c451efff2045f5d92410bd540"
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540",
|
||||
"reference": "0424dff1c58f028c451efff2045f5d92410bd540",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ctype": "*"
|
||||
@@ -1831,7 +1831,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1847,24 +1847,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
"reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a"
|
||||
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a",
|
||||
"reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
|
||||
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
@@ -1909,7 +1909,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1925,24 +1925,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb"
|
||||
"reference": "3833d7255cc303546435cb650316bff708a1c75c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb",
|
||||
"reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
|
||||
"reference": "3833d7255cc303546435cb650316bff708a1c75c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
@@ -1990,7 +1990,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2006,24 +2006,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c"
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c",
|
||||
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-mbstring": "*"
|
||||
@@ -2070,7 +2070,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2086,24 +2086,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-19T12:30:46+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433"
|
||||
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433",
|
||||
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
|
||||
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -2150,7 +2150,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2166,24 +2166,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.30.0",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
"reference": "3fb075789fb91f9ad9af537c4012d523085bd5af"
|
||||
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/3fb075789fb91f9ad9af537c4012d523085bd5af",
|
||||
"reference": "3fb075789fb91f9ad9af537c4012d523085bd5af",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
|
||||
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -2226,7 +2226,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.30.0"
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2242,20 +2242,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-19T12:30:46+00:00"
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v7.1.3",
|
||||
"version": "v7.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca"
|
||||
"reference": "5c03ee6369281177f07f7c68252a280beccba847"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/7f2f542c668ad6c313dc4a5e9c3321f733197eca",
|
||||
"reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/5c03ee6369281177f07f7c68252a280beccba847",
|
||||
"reference": "5c03ee6369281177f07f7c68252a280beccba847",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2287,7 +2287,7 @@
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v7.1.3"
|
||||
"source": "https://github.com/symfony/process/tree/v7.1.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2303,7 +2303,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-26T12:44:47+00:00"
|
||||
"time": "2024-09-19T21:48:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
@@ -2452,16 +2452,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v7.1.3",
|
||||
"version": "v7.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "ea272a882be7f20cad58d5d78c215001617b7f07"
|
||||
"reference": "d66f9c343fa894ec2037cc928381df90a7ad4306"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/ea272a882be7f20cad58d5d78c215001617b7f07",
|
||||
"reference": "ea272a882be7f20cad58d5d78c215001617b7f07",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/d66f9c343fa894ec2037cc928381df90a7ad4306",
|
||||
"reference": "d66f9c343fa894ec2037cc928381df90a7ad4306",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2519,7 +2519,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v7.1.3"
|
||||
"source": "https://github.com/symfony/string/tree/v7.1.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2535,7 +2535,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-22T10:25:37+00:00"
|
||||
"time": "2024-09-20T08:28:38+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
@@ -312,6 +312,12 @@ PUSHER_ID=
|
||||
DEMO_USERNAME=
|
||||
DEMO_PASSWORD=
|
||||
|
||||
#
|
||||
# Disable or enable the running balance column data
|
||||
# Please disable this. It's a very experimental feature.
|
||||
#
|
||||
USE_RUNNING_BALANCE=false
|
||||
|
||||
#
|
||||
# The v2 layout is very experimental. If it breaks you get to keep both parts.
|
||||
# Be wary of data loss.
|
||||
|
@@ -4,6 +4,9 @@ Over time, many people have contributed to Firefly III. Their efforts are not al
|
||||
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
|
||||
|
||||
## 2024
|
||||
- Jhon Pedroza
|
||||
- mzhubail
|
||||
- tasnim
|
||||
- withbest
|
||||
- Steve Wasiura
|
||||
- imlonghao
|
||||
|
@@ -37,6 +37,7 @@ use Illuminate\Support\Arr;
|
||||
use Illuminate\Validation\ValidationException as LaravelValidationException;
|
||||
use Laravel\Passport\Exceptions\OAuthServerException as LaravelOAuthException;
|
||||
use LaravelJsonApi\Core\Exceptions\JsonApiException;
|
||||
use LaravelJsonApi\Exceptions\ExceptionParser;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -67,6 +68,16 @@ class Handler extends ExceptionHandler
|
||||
JsonApiException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Register the exception handling callbacks for the application.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->renderable(
|
||||
ExceptionParser::make()->renderable()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response. It's complex but lucky for us, we never use it because
|
||||
* Firefly III never crashes.
|
||||
@@ -81,15 +92,23 @@ class Handler extends ExceptionHandler
|
||||
public function render($request, \Throwable $e): Response
|
||||
{
|
||||
$expectsJson = $request->expectsJson();
|
||||
// if the user requests anything /api/, assume the user wants to see JSON.
|
||||
if (str_starts_with($request->getRequestUri(), '/api/')) {
|
||||
app('log')->debug('API endpoint, always assume user wants JSON.');
|
||||
$expectsJson = true;
|
||||
}
|
||||
|
||||
app('log')->debug('Now in Handler::render()');
|
||||
|
||||
if ($e instanceof JsonApiException) {
|
||||
// ignore it: controller will handle it.
|
||||
|
||||
app('log')->debug(sprintf(
|
||||
'Return to parent to handle JsonApiException(%d)',
|
||||
$e->getCode()
|
||||
));
|
||||
|
||||
return parent::render($request, $e);
|
||||
}
|
||||
|
||||
if ($e instanceof LaravelValidationException && $expectsJson) {
|
||||
// ignore it: controller will handle it.
|
||||
|
||||
app('log')->debug(sprintf('Return to parent to handle LaravelValidationException(%d)', $e->status));
|
||||
|
||||
return parent::render($request, $e);
|
||||
|
@@ -717,7 +717,7 @@ trait MetaCollection
|
||||
|
||||
$this->joinMetaDataTables();
|
||||
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
||||
$this->query->where('journal_meta.data', '=', $internalReference);
|
||||
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($internalReference)));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@@ -805,7 +805,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
return 'zzz';
|
||||
}
|
||||
|
||||
exit('here we are');
|
||||
exit('here we are 2');
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -99,6 +99,10 @@ class AccountRepository extends AbstractRepository implements QueriesAll, Create
|
||||
return Capabilities\CrudAccount::make();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO piggy banks
|
||||
* TODO transactions
|
||||
*/
|
||||
protected function relations(): CrudRelations
|
||||
{
|
||||
Log::debug(__METHOD__);
|
||||
|
@@ -4,30 +4,55 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\JsonApi\V2\Accounts;
|
||||
|
||||
use FireflyIII\Rules\BelongsUser;
|
||||
use FireflyIII\Rules\Account\IsUniqueAccount;
|
||||
use FireflyIII\Rules\IsBoolean;
|
||||
use FireflyIII\Rules\IsValidPositiveAmount;
|
||||
use FireflyIII\Rules\UniqueAccountNumber;
|
||||
use FireflyIII\Rules\UniqueIban;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use LaravelJsonApi\Laravel\Http\Requests\ResourceRequest;
|
||||
|
||||
class AccountRequest extends ResourceRequest
|
||||
{
|
||||
use ConvertsDataTypes;
|
||||
|
||||
/**
|
||||
* Get the validation rules for the resource.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
Log::debug(__METHOD__);
|
||||
|
||||
exit('am i used');
|
||||
$accountRoles = implode(',', config('firefly.accountRoles'));
|
||||
$ccPaymentTypes = implode(',', array_keys(config('firefly.ccTypes')));
|
||||
$types = implode(',', array_keys(config('firefly.subTitlesByIdentifier')));
|
||||
$type = $this->convertString('type');
|
||||
// var_dump($types);exit;
|
||||
|
||||
return [
|
||||
'type' => [
|
||||
new BelongsUser(),
|
||||
],
|
||||
'name' => [
|
||||
'nullable',
|
||||
'string',
|
||||
'max:255',
|
||||
],
|
||||
'name' => ['required', 'max:1024', 'min:1'], // , new IsUniqueAccount()
|
||||
'account_type' => ['required', 'max:1024', 'min:1', sprintf('in:%s', $types)],
|
||||
// 'iban' => ['iban', 'nullable', new UniqueIban(null, $type)],
|
||||
// 'bic' => 'bic|nullable',
|
||||
// 'account_number' => ['min:1', 'max:255', 'nullable', new UniqueAccountNumber(null, $type)],
|
||||
// 'opening_balance' => 'numeric|required_with:opening_balance_date|nullable',
|
||||
// 'opening_balance_date' => 'date|required_with:opening_balance|nullable',
|
||||
// 'virtual_balance' => 'numeric|nullable',
|
||||
// 'order' => 'numeric|nullable',
|
||||
// 'currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
// 'currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
|
||||
// 'active' => [new IsBoolean()],
|
||||
// 'include_net_worth' => [new IsBoolean()],
|
||||
// 'account_role' => sprintf('nullable|in:%s|required_if:type,asset', $accountRoles),
|
||||
// 'credit_card_type' => sprintf('nullable|in:%s|required_if:account_role,ccAsset', $ccPaymentTypes),
|
||||
// 'monthly_payment_date' => 'nullable|date|required_if:account_role,ccAsset|required_if:credit_card_type,monthlyFull',
|
||||
// 'liability_type' => 'nullable|required_if:type,liability|required_if:type,liabilities|in:loan,debt,mortgage',
|
||||
// 'liability_amount' => ['required_with:liability_start_date', new IsValidPositiveAmount()],
|
||||
// 'liability_start_date' => 'required_with:liability_amount|date',
|
||||
// 'liability_direction' => 'nullable|required_if:type,liability|required_if:type,liabilities|in:credit,debit',
|
||||
// 'interest' => 'min:0|max:100|numeric',
|
||||
// 'interest_period' => sprintf('nullable|in:%s', implode(',', config('firefly.interest_periods'))),
|
||||
// 'notes' => 'min:0|max:32768',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,6 @@ namespace FireflyIII\JsonApi\V2\Accounts;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use LaravelJsonApi\Core\Resources\JsonApiResource;
|
||||
|
||||
/**
|
||||
@@ -38,7 +37,7 @@ class AccountResource extends JsonApiResource
|
||||
'active' => $this->resource->active,
|
||||
'order' => $this->resource->order,
|
||||
'iban' => $this->resource->iban,
|
||||
'type' => $this->resource->account_type_string,
|
||||
'account_type' => $this->resource->account_type_string,
|
||||
'account_role' => $this->resource->account_role,
|
||||
'account_number' => '' === $this->resource->account_number ? null : $this->resource->account_number,
|
||||
|
||||
|
@@ -28,8 +28,6 @@ class AccountSchema extends Schema
|
||||
*/
|
||||
public function fields(): array
|
||||
{
|
||||
Log::debug(__METHOD__);
|
||||
|
||||
return [
|
||||
ID::make(),
|
||||
Attribute::make('created_at'),
|
||||
@@ -40,7 +38,7 @@ class AccountSchema extends Schema
|
||||
Attribute::make('active')->sortable(),
|
||||
Attribute::make('order')->sortable(),
|
||||
Attribute::make('iban')->sortable(),
|
||||
Attribute::make('type'),
|
||||
Attribute::make('account_type'),
|
||||
Attribute::make('account_role'),
|
||||
Attribute::make('account_number')->sortable(),
|
||||
|
||||
@@ -60,7 +58,9 @@ class AccountSchema extends Schema
|
||||
Attribute::make('liability_direction'),
|
||||
Attribute::make('interest'),
|
||||
Attribute::make('interest_period'),
|
||||
Attribute::make('current_debt')->sortable(),
|
||||
// Attribute::make('current_debt')->sortable(),
|
||||
|
||||
// TODO credit card fields.
|
||||
|
||||
// dynamic data
|
||||
Attribute::make('last_activity')->sortable(),
|
||||
|
@@ -53,6 +53,8 @@ class CrudAccount extends CrudResource
|
||||
|
||||
public function create(array $validatedData): Account
|
||||
{
|
||||
exit('here we are');
|
||||
var_dump($validatedData);
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
@@ -37,6 +37,11 @@ class AccountPolicy
|
||||
return auth()->check() && $user->id === $account->user_id;
|
||||
}
|
||||
|
||||
public function create(): bool
|
||||
{
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Everybody can do this, but selection should limit to user.
|
||||
*
|
||||
|
201
app/Rules/Account/IsUniqueAccount.php
Normal file
201
app/Rules/Account/IsUniqueAccount.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
/*
|
||||
* IsUniqueAccount.php
|
||||
* Copyright (c) 2024 james@firefly-iii.org.
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Rules\Account;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\Validation\DataAwareRule;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
|
||||
/**
|
||||
* @method fail(string $string)
|
||||
*/
|
||||
class IsUniqueAccount implements ValidationRule, DataAwareRule
|
||||
{
|
||||
protected \Closure $fail;
|
||||
protected array $data = [];
|
||||
|
||||
#[\Override]
|
||||
public function validate(string $attribute, mixed $value, \Closure $fail): void
|
||||
{
|
||||
return;
|
||||
$this->fail = $fail;
|
||||
// because a user does not have to be logged in (tests and what-not).
|
||||
if (!auth()->check()) {
|
||||
app('log')->debug('validateUniqueAccountForUser::anon');
|
||||
$fail('validation.nog_logged_in')->translate();
|
||||
|
||||
return;
|
||||
}
|
||||
if (array_key_exists('type', $this->data)) {
|
||||
app('log')->debug('validateUniqueAccountForUser::typeString');
|
||||
|
||||
$this->validateByAccountTypeString($value, $parameters, (string) $this->data['type']);
|
||||
}
|
||||
if (array_key_exists('account_type_id', $this->data)) {
|
||||
app('log')->debug('validateUniqueAccountForUser::typeId');
|
||||
|
||||
$this->validateByAccountTypeId($value, $parameters);
|
||||
}
|
||||
$parameterId = $parameters[0] ?? null;
|
||||
if (null !== $parameterId) {
|
||||
app('log')->debug('validateUniqueAccountForUser::paramId');
|
||||
|
||||
$this->validateByParameterId((int) $parameterId, $value);
|
||||
}
|
||||
if (array_key_exists('id', $this->data)) {
|
||||
app('log')->debug('validateUniqueAccountForUser::accountId');
|
||||
|
||||
$this->validateByAccountId($value);
|
||||
}
|
||||
|
||||
// without type, just try to validate the name.
|
||||
app('log')->debug('validateUniqueAccountForUser::accountName');
|
||||
|
||||
$this->validateByAccountName($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO duplicate from old validation class.
|
||||
*/
|
||||
private function validateByAccountTypeString(string $value, array $parameters, string $type): bool
|
||||
{
|
||||
/** @var null|array $search */
|
||||
$search = config('firefly.accountTypeByIdentifier.%s', $type);
|
||||
|
||||
if (null === $search) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$accountTypes = AccountType::whereIn('type', $search)->get();
|
||||
$ignore = (int) ($parameters[0] ?? 0.0);
|
||||
$accountTypeIds = $accountTypes->pluck('id')->toArray();
|
||||
|
||||
/** @var null|Account $result */
|
||||
$result = auth()->user()->accounts()->whereIn('account_type_id', $accountTypeIds)->where('id', '!=', $ignore)
|
||||
->where('name', $value)
|
||||
->first()
|
||||
;
|
||||
|
||||
return null === $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO duplicate from old validation class.
|
||||
*/
|
||||
private function validateAccountAnonymously(): void
|
||||
{
|
||||
if (!array_key_exists('user_id', $this->data)) {
|
||||
$this->fail('No user ID provided.');
|
||||
}
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::find($this->data['user_id']);
|
||||
$type = AccountType::find($this->data['account_type_id'])->first();
|
||||
$value = $this->data['name'];
|
||||
|
||||
/** @var null|Account $result */
|
||||
$result = $user->accounts()->where('account_type_id', $type->id)->where('name', $value)->first();
|
||||
|
||||
return null === $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Duplicate from old validation class.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param mixed $parameters
|
||||
*/
|
||||
private function validateByAccountTypeId($value, $parameters): bool
|
||||
{
|
||||
$type = AccountType::find($this->data['account_type_id'])->first();
|
||||
$ignore = (int) ($parameters[0] ?? 0.0);
|
||||
|
||||
/** @var null|Account $result */
|
||||
$result = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)
|
||||
->where('name', $value)
|
||||
->first()
|
||||
;
|
||||
|
||||
return null === $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Duplicate from old validation class.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
private function validateByParameterId(int $accountId, $value): bool
|
||||
{
|
||||
/** @var Account $existingAccount */
|
||||
$existingAccount = Account::find($accountId);
|
||||
|
||||
$type = $existingAccount->accountType;
|
||||
$ignore = $existingAccount->id;
|
||||
|
||||
$entry = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)
|
||||
->where('name', $value)
|
||||
->first()
|
||||
;
|
||||
|
||||
return null === $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Duplicate from old validation class.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
private function validateByAccountId($value): bool
|
||||
{
|
||||
/** @var Account $existingAccount */
|
||||
$existingAccount = Account::find($this->data['id']);
|
||||
|
||||
$type = $existingAccount->accountType;
|
||||
$ignore = $existingAccount->id;
|
||||
|
||||
$entry = auth()->user()->accounts()->where('account_type_id', $type->id)->where('id', '!=', $ignore)
|
||||
->where('name', $value)
|
||||
->first()
|
||||
;
|
||||
|
||||
return null === $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO is duplicate
|
||||
* TODO does not take group into account. Must be made group aware.
|
||||
*/
|
||||
private function validateByAccountName(string $value): bool
|
||||
{
|
||||
return 0 === auth()->user()->accounts()->where('name', $value)->count();
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function setData(array $data): void
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
}
|
@@ -41,9 +41,8 @@ trait DateCalculation
|
||||
{
|
||||
$difference = (int)($start->diffInDays($end, true) + 1);
|
||||
$today = today(config('app.timezone'))->startOfDay();
|
||||
|
||||
if ($start->lte($today) && $end->gte($today)) {
|
||||
$difference = $today->diffInDays($end);
|
||||
$difference = $today->diffInDays($end) + 1;
|
||||
}
|
||||
|
||||
return (int)(0 === $difference ? 1 : $difference);
|
||||
|
@@ -130,6 +130,7 @@ trait GetConfigurationData
|
||||
|
||||
/** @var Carbon $todayEnd */
|
||||
$todayEnd = app('navigation')->endOfPeriod($todayStart, $viewRange);
|
||||
|
||||
if ($todayStart->ne($start) || $todayEnd->ne($end)) {
|
||||
$ranges[ucfirst((string)trans('firefly.today'))] = [$todayStart, $todayEnd];
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountBalance;
|
||||
@@ -74,7 +75,35 @@ class AccountBalanceCalculator
|
||||
foreach ($transactionJournal->transactions as $transaction) {
|
||||
$accounts->push($transaction->account);
|
||||
}
|
||||
$object->optimizedCalculation($accounts);
|
||||
$object->optimizedCalculation($accounts, $transactionJournal->date);
|
||||
}
|
||||
|
||||
private function getLatestBalance(int $accountId, int $currencyId, ?Carbon $notBefore): string
|
||||
{
|
||||
if (null === $notBefore) {
|
||||
return '0';
|
||||
}
|
||||
Log::debug(sprintf('getLatestBalance: notBefore date is "%s", calculating', $notBefore->format('Y-m-d')));
|
||||
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->whereNull('transactions.deleted_at')
|
||||
->where('transaction_journals.transaction_currency_id', $currencyId)
|
||||
->whereNull('transaction_journals.deleted_at')
|
||||
// this order is the same as GroupCollector
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->orderBy('transaction_journals.description', 'DESC')
|
||||
->orderBy('transactions.amount', 'DESC')
|
||||
->where('transactions.account_id', $accountId)
|
||||
;
|
||||
$notBefore->startOfDay();
|
||||
$query->where('transaction_journals.date', '<', $notBefore);
|
||||
|
||||
$first = $query->first(['transactions.id', 'transactions.balance_dirty', 'transactions.transaction_currency_id', 'transaction_journals.date', 'transactions.account_id', 'transactions.amount', 'transactions.balance_after']);
|
||||
$balance = $first->balance_after ?? '0';
|
||||
Log::debug(sprintf('getLatestBalance: found balance: %s in transaction #%d', $balance, $first->id ?? 0));
|
||||
|
||||
return $balance;
|
||||
}
|
||||
|
||||
private function getAccountBalanceByAccount(int $account, int $currency): AccountBalance
|
||||
@@ -98,9 +127,15 @@ class AccountBalanceCalculator
|
||||
return $entry;
|
||||
}
|
||||
|
||||
private function optimizedCalculation(Collection $accounts): void
|
||||
private function optimizedCalculation(Collection $accounts, ?Carbon $notBefore = null): void
|
||||
{
|
||||
Log::debug('start of optimizedCalculation');
|
||||
if (false === config('firefly.feature_flags.running_balance_column')) {
|
||||
Log::debug('optimizedCalculation is disabled, return.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($accounts->count() > 0) {
|
||||
Log::debug(sprintf('Limited to %d account(s)', $accounts->count()));
|
||||
}
|
||||
@@ -120,6 +155,10 @@ class AccountBalanceCalculator
|
||||
if ($accounts->count() > 0) {
|
||||
$query->whereIn('transactions.account_id', $accounts->pluck('id')->toArray());
|
||||
}
|
||||
if (null !== $notBefore) {
|
||||
$notBefore->startOfDay();
|
||||
$query->where('transaction_journals.date', '>=', $notBefore);
|
||||
}
|
||||
|
||||
$set = $query->get(['transactions.id', 'transactions.balance_dirty', 'transactions.transaction_currency_id', 'transaction_journals.date', 'transactions.account_id', 'transactions.amount']);
|
||||
|
||||
@@ -127,7 +166,7 @@ class AccountBalanceCalculator
|
||||
foreach ($set as $entry) {
|
||||
// start with empty array:
|
||||
$balances[$entry->account_id] ??= [];
|
||||
$balances[$entry->account_id][$entry->transaction_currency_id] ??= '0';
|
||||
$balances[$entry->account_id][$entry->transaction_currency_id] ??= $this->getLatestBalance($entry->account_id, $entry->transaction_currency_id, $notBefore);
|
||||
|
||||
// before and after are easy:
|
||||
$before = $balances[$entry->account_id][$entry->transaction_currency_id];
|
||||
@@ -306,7 +345,7 @@ class AccountBalanceCalculator
|
||||
|
||||
private function getStartAmounts(Account $account, TransactionJournal $journal): array
|
||||
{
|
||||
exit('here we are');
|
||||
exit('here we are 1');
|
||||
|
||||
return [];
|
||||
}
|
||||
|
@@ -177,6 +177,7 @@ class Navigation
|
||||
'year' => 'startOfYear',
|
||||
'yearly' => 'startOfYear',
|
||||
'1Y' => 'startOfYear',
|
||||
'MTD' => 'startOfMonth',
|
||||
];
|
||||
|
||||
$parameterMap = [
|
||||
@@ -274,13 +275,21 @@ class Navigation
|
||||
|
||||
/** @var Carbon $tEnd */
|
||||
$tEnd = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$diffInDays = (int)$tStart->diffInDays($tEnd, true);
|
||||
$diffInDays = (int) $tStart->diffInDays($tEnd, true);
|
||||
}
|
||||
Log::debug(sprintf('Diff in days is %d', $diffInDays));
|
||||
$currentEnd->addDays($diffInDays);
|
||||
|
||||
return $currentEnd;
|
||||
}
|
||||
if ('MTD' === $repeatFreq) {
|
||||
$today = today();
|
||||
if ($today->isSameMonth($end)) {
|
||||
return $today->endOfDay();
|
||||
}
|
||||
|
||||
return $end->endOfMonth();
|
||||
}
|
||||
|
||||
$result = match ($repeatFreq) {
|
||||
'last7' => $currentEnd->addDays(7)->startOfDay(),
|
||||
@@ -327,7 +336,7 @@ class Navigation
|
||||
{
|
||||
$endOfMonth = $date->copy()->endOfMonth();
|
||||
|
||||
return (int)$date->diffInDays($endOfMonth, true);
|
||||
return (int) $date->diffInDays($endOfMonth, true);
|
||||
}
|
||||
|
||||
public function diffInPeriods(string $period, int $skip, Carbon $beginning, Carbon $end): int
|
||||
@@ -382,7 +391,7 @@ class Navigation
|
||||
));
|
||||
}
|
||||
|
||||
return (int)$diff;
|
||||
return (int) $diff;
|
||||
}
|
||||
|
||||
public function endOfX(Carbon $theCurrentEnd, string $repeatFreq, ?Carbon $maxDate): Carbon
|
||||
@@ -428,7 +437,7 @@ class Navigation
|
||||
if (is_array($range)) {
|
||||
$range = '1M';
|
||||
}
|
||||
$range = (string)$range;
|
||||
$range = (string) $range;
|
||||
if (!$correct) {
|
||||
return $range;
|
||||
}
|
||||
@@ -463,18 +472,18 @@ class Navigation
|
||||
// define period to increment
|
||||
$increment = 'addDay';
|
||||
$format = $this->preferredCarbonFormat($start, $end);
|
||||
$displayFormat = (string)trans('config.month_and_day_js', [], $locale);
|
||||
$displayFormat = (string) trans('config.month_and_day_js', [], $locale);
|
||||
$diff = $start->diffInMonths($end, true);
|
||||
// increment by month (for year)
|
||||
if ($diff >= 1.0001) {
|
||||
$increment = 'addMonth';
|
||||
$displayFormat = (string)trans('config.month_js');
|
||||
$displayFormat = (string) trans('config.month_js');
|
||||
}
|
||||
|
||||
// increment by year (for multi-year)
|
||||
if ($diff >= 12.0001) {
|
||||
$increment = 'addYear';
|
||||
$displayFormat = (string)trans('config.year_js');
|
||||
$displayFormat = (string) trans('config.year_js');
|
||||
}
|
||||
$begin = clone $start;
|
||||
$entries = [];
|
||||
@@ -514,19 +523,19 @@ class Navigation
|
||||
{
|
||||
$date = clone $theDate;
|
||||
$formatMap = [
|
||||
'1D' => (string)trans('config.specific_day_js'),
|
||||
'daily' => (string)trans('config.specific_day_js'),
|
||||
'custom' => (string)trans('config.specific_day_js'),
|
||||
'1W' => (string)trans('config.week_in_year_js'),
|
||||
'week' => (string)trans('config.week_in_year_js'),
|
||||
'weekly' => (string)trans('config.week_in_year_js'),
|
||||
'1M' => (string)trans('config.month_js'),
|
||||
'month' => (string)trans('config.month_js'),
|
||||
'monthly' => (string)trans('config.month_js'),
|
||||
'1Y' => (string)trans('config.year_js'),
|
||||
'year' => (string)trans('config.year_js'),
|
||||
'yearly' => (string)trans('config.year_js'),
|
||||
'6M' => (string)trans('config.half_year_js'),
|
||||
'1D' => (string) trans('config.specific_day_js'),
|
||||
'daily' => (string) trans('config.specific_day_js'),
|
||||
'custom' => (string) trans('config.specific_day_js'),
|
||||
'1W' => (string) trans('config.week_in_year_js'),
|
||||
'week' => (string) trans('config.week_in_year_js'),
|
||||
'weekly' => (string) trans('config.week_in_year_js'),
|
||||
'1M' => (string) trans('config.month_js'),
|
||||
'month' => (string) trans('config.month_js'),
|
||||
'monthly' => (string) trans('config.month_js'),
|
||||
'1Y' => (string) trans('config.year_js'),
|
||||
'year' => (string) trans('config.year_js'),
|
||||
'yearly' => (string) trans('config.year_js'),
|
||||
'6M' => (string) trans('config.half_year_js'),
|
||||
];
|
||||
|
||||
if (array_key_exists($repeatFrequency, $formatMap)) {
|
||||
@@ -567,13 +576,13 @@ class Navigation
|
||||
public function preferredCarbonLocalizedFormat(Carbon $start, Carbon $end): string
|
||||
{
|
||||
$locale = app('steam')->getLocale();
|
||||
$format = (string)trans('config.month_and_day_js', [], $locale);
|
||||
$format = (string) trans('config.month_and_day_js', [], $locale);
|
||||
if ($start->diffInMonths($end, true) > 1) {
|
||||
$format = (string)trans('config.month_js', [], $locale);
|
||||
$format = (string) trans('config.month_js', [], $locale);
|
||||
}
|
||||
|
||||
if ($start->diffInMonths($end, true) > 12) {
|
||||
$format = (string)trans('config.year_js', [], $locale);
|
||||
$format = (string) trans('config.year_js', [], $locale);
|
||||
}
|
||||
|
||||
return $format;
|
||||
@@ -586,11 +595,11 @@ class Navigation
|
||||
public function preferredEndOfPeriod(Carbon $start, Carbon $end): string
|
||||
{
|
||||
$format = 'endOfDay';
|
||||
if ((int)$start->diffInMonths($end, true) > 1) {
|
||||
if ((int) $start->diffInMonths($end, true) > 1) {
|
||||
$format = 'endOfMonth';
|
||||
}
|
||||
|
||||
if ((int)$start->diffInMonths($end, true) > 12) {
|
||||
if ((int) $start->diffInMonths($end, true) > 12) {
|
||||
$format = 'endOfYear';
|
||||
}
|
||||
|
||||
@@ -604,11 +613,11 @@ class Navigation
|
||||
public function preferredRangeFormat(Carbon $start, Carbon $end): string
|
||||
{
|
||||
$format = '1D';
|
||||
if ((int)$start->diffInMonths($end, true) > 1) {
|
||||
if ((int) $start->diffInMonths($end, true) > 1) {
|
||||
$format = '1M';
|
||||
}
|
||||
|
||||
if ((int)$start->diffInMonths($end, true) > 12) {
|
||||
if ((int) $start->diffInMonths($end, true) > 12) {
|
||||
$format = '1Y';
|
||||
}
|
||||
|
||||
@@ -622,11 +631,11 @@ class Navigation
|
||||
public function preferredSqlFormat(Carbon $start, Carbon $end): string
|
||||
{
|
||||
$format = '%Y-%m-%d';
|
||||
if ((int)$start->diffInMonths($end, true) > 1) {
|
||||
if ((int) $start->diffInMonths($end, true) > 1) {
|
||||
$format = '%Y-%m';
|
||||
}
|
||||
|
||||
if ((int)$start->diffInMonths($end, true) > 12) {
|
||||
if ((int) $start->diffInMonths($end, true) > 12) {
|
||||
$format = '%Y';
|
||||
}
|
||||
|
||||
@@ -682,7 +691,7 @@ class Navigation
|
||||
|
||||
/** @var Carbon $tEnd */
|
||||
$tEnd = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$diffInDays = (int)$tStart->diffInDays($tEnd, true);
|
||||
$diffInDays = (int) $tStart->diffInDays($tEnd, true);
|
||||
$date->subDays($diffInDays * $subtract);
|
||||
|
||||
return $date;
|
||||
|
@@ -44,8 +44,7 @@ class Steam
|
||||
*/
|
||||
public function balanceIgnoreVirtual(Account $account, Carbon $date): string
|
||||
{
|
||||
Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
|
||||
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$repository->setUser($account->user);
|
||||
@@ -96,7 +95,7 @@ class Steam
|
||||
*/
|
||||
public function balanceInRange(Account $account, Carbon $start, Carbon $end, ?TransactionCurrency $currency = null): array
|
||||
{
|
||||
Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($account->id);
|
||||
$cache->addProperty('balance-in-range');
|
||||
@@ -221,7 +220,7 @@ class Steam
|
||||
*/
|
||||
public function balance(Account $account, Carbon $date, ?TransactionCurrency $currency = null): string
|
||||
{
|
||||
Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
// abuse chart properties:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($account->id);
|
||||
@@ -270,7 +269,7 @@ class Steam
|
||||
*/
|
||||
public function balanceInRangeConverted(Account $account, Carbon $start, Carbon $end, TransactionCurrency $native): array
|
||||
{
|
||||
Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($account->id);
|
||||
$cache->addProperty('balance-in-range-converted');
|
||||
@@ -396,7 +395,7 @@ class Steam
|
||||
*/
|
||||
public function balanceConverted(Account $account, Carbon $date, TransactionCurrency $native): string
|
||||
{
|
||||
Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
Log::debug(sprintf('Now in balanceConverted (%s) for account #%d, converting to %s', $date->format('Y-m-d'), $account->id, $native->code));
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($account->id);
|
||||
@@ -542,7 +541,7 @@ class Steam
|
||||
*/
|
||||
public function balancesByAccounts(Collection $accounts, Carbon $date): array
|
||||
{
|
||||
Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
// cache this property.
|
||||
$cache = new CacheProperties();
|
||||
@@ -573,7 +572,7 @@ class Steam
|
||||
*/
|
||||
public function balancesByAccountsConverted(Collection $accounts, Carbon $date): array
|
||||
{
|
||||
Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
// cache this property.
|
||||
$cache = new CacheProperties();
|
||||
@@ -607,7 +606,7 @@ class Steam
|
||||
*/
|
||||
public function balancesPerCurrencyByAccounts(Collection $accounts, Carbon $date): array
|
||||
{
|
||||
Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
// cache this property.
|
||||
$cache = new CacheProperties();
|
||||
@@ -633,7 +632,7 @@ class Steam
|
||||
|
||||
public function balancePerCurrency(Account $account, Carbon $date): array
|
||||
{
|
||||
Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
// Log::warning(sprintf('Deprecated method %s, do not use.', __METHOD__));
|
||||
// abuse chart properties:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($account->id);
|
||||
|
@@ -29,7 +29,6 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Support\Search\OperatorQuerySearch;
|
||||
use League\CommonMark\GithubFlavoredMarkdownConverter;
|
||||
use Route;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
use Twig\TwigFunction;
|
||||
@@ -63,12 +62,29 @@ class General extends AbstractExtension
|
||||
}
|
||||
|
||||
/** @var Carbon $date */
|
||||
$date = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$info = app('steam')->balanceByTransactions($account, $date, null);
|
||||
$date = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$runningBalance = config('firefly.feature_flags.running_balance_column');
|
||||
$info = [];
|
||||
if (true === $runningBalance) {
|
||||
$info = app('steam')->balanceByTransactions($account, $date, null);
|
||||
}
|
||||
if (false === $runningBalance) {
|
||||
$info[] = app('steam')->balance($account, $date);
|
||||
}
|
||||
|
||||
$strings = [];
|
||||
$strings = [];
|
||||
foreach ($info as $currencyId => $balance) {
|
||||
$strings[] = app('amount')->formatByCurrencyId($currencyId, $balance, false);
|
||||
$balance = (string) $balance;
|
||||
if (0 === $currencyId) {
|
||||
// not good code but OK
|
||||
/** @var AccountRepositoryInterface $accountRepos */
|
||||
$accountRepos = app(AccountRepositoryInterface::class);
|
||||
$currency = $accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
|
||||
$strings[] = app('amount')->formatAnything($currency, $balance, false);
|
||||
}
|
||||
if (0 !== $currencyId) {
|
||||
$strings[] = app('amount')->formatByCurrencyId($currencyId, $balance, false);
|
||||
}
|
||||
}
|
||||
|
||||
return implode(', ', $strings);
|
||||
@@ -198,7 +214,7 @@ class General extends AbstractExtension
|
||||
]
|
||||
);
|
||||
|
||||
return (string)$converter->convert($text);
|
||||
return (string) $converter->convert($text);
|
||||
},
|
||||
['is_safe' => ['html']]
|
||||
);
|
||||
@@ -212,8 +228,8 @@ class General extends AbstractExtension
|
||||
return new TwigFilter(
|
||||
'phphost',
|
||||
static function (string $string): string {
|
||||
$proto = (string)parse_url($string, PHP_URL_SCHEME);
|
||||
$host = (string)parse_url($string, PHP_URL_HOST);
|
||||
$proto = (string) parse_url($string, PHP_URL_SCHEME);
|
||||
$host = (string) parse_url($string, PHP_URL_HOST);
|
||||
|
||||
return e(sprintf('%s://%s', $proto, $host));
|
||||
}
|
||||
|
63
changelog.md
63
changelog.md
@@ -3,6 +3,69 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 6.1.21 - 2024-09-30
|
||||
|
||||
### Added
|
||||
|
||||
- Enabled the expression engine built by @michaelhthomas. Read more about it in [the documentation](https://docs.firefly-iii.org/references/firefly-iii/rule-expressions/).
|
||||
- Add running balance data, see if it can be used in the layout in the future.
|
||||
- [PR 9160](https://github.com/firefly-iii/firefly-iii/pull/9160) (add test cases for api/v1/autocomplete/CategoryController) reported by @tasnim0tantawi
|
||||
- [PR 9178](https://github.com/firefly-iii/firefly-iii/pull/9178) (Add test cases for Api\V1\Controllers\Autocomplete\BillController & BudgetController) reported by @tasnim0tantawi
|
||||
- [PR 9171](https://github.com/firefly-iii/firefly-iii/pull/9171) (Add about test) reported by @mzhubail
|
||||
|
||||
### Changed
|
||||
|
||||
- [PR 9096](https://github.com/firefly-iii/firefly-iii/pull/9096) (chore: fix some comments) reported by @withbest
|
||||
|
||||
### Fixed
|
||||
|
||||
- [Issue 9078](https://github.com/firefly-iii/firefly-iii/issues/9078) (bcadd exception while using POST transactions) reported by @dbtdsilva
|
||||
- [Discussion 9080](https://github.com/orgs/firefly-iii/discussions/9080) (Incorrect sorting on expense accounts) started by @pc-zookeeper
|
||||
- [Issue 9084](https://github.com/firefly-iii/firefly-iii/issues/9084) (API Call for bills/nextExpectedMatch does not update) reported by @marcelweikum
|
||||
- [Issue 9103](https://github.com/firefly-iii/firefly-iii/issues/9103) (Default Currency does not apply to Accounts.) reported by @chrisgriff1512
|
||||
- [Issue 9140](https://github.com/firefly-iii/firefly-iii/issues/9140) (Dashboard 'Today' option chooses 1st of month (not current date)) reported by @PAS-BC
|
||||
- [PR 9179](https://github.com/firefly-iii/firefly-iii/pull/9179) (fix Navigation.php MTD logic to make tests pass.) reported by @tasnim0tantawi
|
||||
- [PR 9239](https://github.com/firefly-iii/firefly-iii/pull/9239) (Fix webhook index page when Firefly is not served at root) reported by @jfpedroza
|
||||
- [Issue 9168](https://github.com/firefly-iii/firefly-iii/issues/9168) (Custom logout URL doesn't work.) reported by @JC5
|
||||
- [Issue 9155](https://github.com/firefly-iii/firefly-iii/issues/9155) (internal_reference_is does not correctly match numeric internal references) reported by @Lrns123
|
||||
- [Issue 9275](https://github.com/firefly-iii/firefly-iii/issues/9275) (Long wait when editing a transaction) reported by @JC5
|
||||
- [Issue 9278](https://github.com/firefly-iii/firefly-iii/issues/9278) (Update to v6.1.20 changed Balance of Account) reported by @JeuJeus
|
||||
- [Issue 9281](https://github.com/firefly-iii/firefly-iii/issues/9281) (Update to v6.1.20 leads to a type error) reported by @krakonos1602
|
||||
|
||||
### API
|
||||
|
||||
- Expand v2 API
|
||||
|
||||
## 6.1.20 - 2024-09-29
|
||||
|
||||
### Added
|
||||
|
||||
- Enabled the expression engine built by @michaelhthomas. Read more about it in [the documentation](https://docs.firefly-iii.org/references/firefly-iii/rule-expressions/).
|
||||
- Add running balance data, see if it can be used in the layout in the future.
|
||||
- [PR 9160](https://github.com/firefly-iii/firefly-iii/pull/9160) (add test cases for api/v1/autocomplete/CategoryController) reported by @tasnim0tantawi
|
||||
- [PR 9178](https://github.com/firefly-iii/firefly-iii/pull/9178) (Add test cases for Api\V1\Controllers\Autocomplete\BillController & BudgetController) reported by @tasnim0tantawi
|
||||
- [PR 9171](https://github.com/firefly-iii/firefly-iii/pull/9171) (Add about test) reported by @mzhubail
|
||||
|
||||
### Changed
|
||||
|
||||
- [PR 9096](https://github.com/firefly-iii/firefly-iii/pull/9096) (chore: fix some comments) reported by @withbest
|
||||
|
||||
### Fixed
|
||||
|
||||
- [Issue 9078](https://github.com/firefly-iii/firefly-iii/issues/9078) (bcadd exception while using POST transactions) reported by @dbtdsilva
|
||||
- [Discussion 9080](https://github.com/orgs/firefly-iii/discussions/9080) (Incorrect sorting on expense accounts) started by @pc-zookeeper
|
||||
- [Issue 9084](https://github.com/firefly-iii/firefly-iii/issues/9084) (API Call for bills/nextExpectedMatch does not update) reported by @marcelweikum
|
||||
- [Issue 9103](https://github.com/firefly-iii/firefly-iii/issues/9103) (Default Currency does not apply to Accounts.) reported by @chrisgriff1512
|
||||
- [Issue 9140](https://github.com/firefly-iii/firefly-iii/issues/9140) (Dashboard 'Today' option chooses 1st of month (not current date)) reported by @PAS-BC
|
||||
- [PR 9179](https://github.com/firefly-iii/firefly-iii/pull/9179) (fix Navigation.php MTD logic to make tests pass.) reported by @tasnim0tantawi
|
||||
- [PR 9239](https://github.com/firefly-iii/firefly-iii/pull/9239) (Fix webhook index page when Firefly is not served at root) reported by @jfpedroza
|
||||
- [Issue 9168](https://github.com/firefly-iii/firefly-iii/issues/9168) (Custom logout URL doesn't work.) reported by @JC5
|
||||
- [Issue 9155](https://github.com/firefly-iii/firefly-iii/issues/9155) (internal_reference_is does not correctly match numeric internal references) reported by @Lrns123
|
||||
|
||||
### API
|
||||
|
||||
- Expand v2 API
|
||||
|
||||
## 6.1.19 - 2024-07-20
|
||||
|
||||
### Fixed
|
||||
|
@@ -93,7 +93,7 @@
|
||||
"laravel/framework": "^11",
|
||||
"laravel/passport": "^12",
|
||||
"laravel/sanctum": "^4",
|
||||
"laravel/slack-notification-channel": "^3.0",
|
||||
"laravel/slack-notification-channel": "^3.3",
|
||||
"laravel/ui": "^4.2",
|
||||
"league/commonmark": "2.*",
|
||||
"league/csv": "^9.10",
|
||||
@@ -120,10 +120,10 @@
|
||||
"larastan/larastan": "^2",
|
||||
"laravel-json-api/testing": "^3.0",
|
||||
"mockery/mockery": "1.*",
|
||||
"phpstan/extension-installer": "^1.3",
|
||||
"phpstan/extension-installer": "^1.4",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.4",
|
||||
"phpstan/phpstan-strict-rules": "^1.6",
|
||||
"phpunit/phpunit": "^10",
|
||||
"thecodingmachine/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
|
965
composer.lock
generated
965
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -65,10 +65,6 @@ use FireflyIII\Support\Binder\UserGroupAccount;
|
||||
use FireflyIII\Support\Binder\UserGroupBill;
|
||||
use FireflyIII\Support\Binder\UserGroupTransaction;
|
||||
use FireflyIII\TransactionRules\Actions\AddTag;
|
||||
use FireflyIII\TransactionRules\Actions\AppendDescription;
|
||||
use FireflyIII\TransactionRules\Actions\AppendDescriptionToNotes;
|
||||
use FireflyIII\TransactionRules\Actions\AppendNotes;
|
||||
use FireflyIII\TransactionRules\Actions\AppendNotesToDescription;
|
||||
use FireflyIII\TransactionRules\Actions\ClearBudget;
|
||||
use FireflyIII\TransactionRules\Actions\ClearCategory;
|
||||
use FireflyIII\TransactionRules\Actions\ClearNotes;
|
||||
@@ -77,10 +73,6 @@ use FireflyIII\TransactionRules\Actions\ConvertToTransfer;
|
||||
use FireflyIII\TransactionRules\Actions\ConvertToWithdrawal;
|
||||
use FireflyIII\TransactionRules\Actions\DeleteTransaction;
|
||||
use FireflyIII\TransactionRules\Actions\LinkToBill;
|
||||
use FireflyIII\TransactionRules\Actions\MoveDescriptionToNotes;
|
||||
use FireflyIII\TransactionRules\Actions\MoveNotesToDescription;
|
||||
use FireflyIII\TransactionRules\Actions\PrependDescription;
|
||||
use FireflyIII\TransactionRules\Actions\PrependNotes;
|
||||
use FireflyIII\TransactionRules\Actions\RemoveAllTags;
|
||||
use FireflyIII\TransactionRules\Actions\RemoveTag;
|
||||
use FireflyIII\TransactionRules\Actions\SetAmount;
|
||||
@@ -110,14 +102,15 @@ return [
|
||||
],
|
||||
// some feature flags:
|
||||
'feature_flags' => [
|
||||
'export' => true,
|
||||
'telemetry' => false,
|
||||
'webhooks' => true,
|
||||
'handle_debts' => true,
|
||||
'expression_engine' => true,
|
||||
'export' => true,
|
||||
'telemetry' => false,
|
||||
'webhooks' => true,
|
||||
'handle_debts' => true,
|
||||
'expression_engine' => true,
|
||||
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => 'develop/2024-08-05',
|
||||
'version' => '6.1.21',
|
||||
'api_version' => '2.1.0',
|
||||
'db_version' => 24,
|
||||
|
||||
|
898
package-lock.json
generated
898
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,5 +5,8 @@
|
||||
"workspaces": [
|
||||
"resources/assets/v1",
|
||||
"resources/assets/v2"
|
||||
]
|
||||
],
|
||||
"devDependencies": {
|
||||
"postcss": "^8.4.47"
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,10 @@
|
||||
diff --git a/node_modules/admin-lte/src/scss/_app-sidebar.scss b/node_modules/admin-lte/src/scss/_app-sidebar.scss
|
||||
index 437946b..040bf5d 100644
|
||||
old mode 100644
|
||||
new mode 100755
|
||||
index 69dfc16..dc341eb
|
||||
--- a/node_modules/admin-lte/src/scss/_app-sidebar.scss
|
||||
+++ b/node_modules/admin-lte/src/scss/_app-sidebar.scss
|
||||
@@ -582,7 +582,6 @@ body:not(.app-loaded) {
|
||||
@@ -577,7 +577,6 @@ body:not(.app-loaded) {
|
||||
|
||||
@if $enable-dark-mode {
|
||||
@include color-mode(dark) {
|
@@ -73,6 +73,7 @@ function formatLabel(str, maxwidth) {
|
||||
}
|
||||
|
||||
var defaultChartOptions = {
|
||||
|
||||
elements: {
|
||||
line: {
|
||||
cubicInterpolationMode: 'monotone'
|
||||
@@ -158,4 +159,4 @@ var neutralDefaultPieOptions = {
|
||||
},
|
||||
maintainAspectRatio: true,
|
||||
responsive: true
|
||||
};
|
||||
};
|
||||
|
@@ -173,6 +173,8 @@ Over time, [many people have contributed to Firefly III](https://github.com/fire
|
||||
|
||||
The Firefly III logo is made by the excellent Cherie Woo.
|
||||
|
||||
<a href="https://hellogithub.com/repository/a8c64f04cb3643c2a4423c4ad924dec9" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=a8c64f04cb3643c2a4423c4ad924dec9&claim_uid=1bPi7O2rTGREZXN&theme=small" alt="Featured|HelloGitHub" /></a>
|
||||
|
||||
[packagist-shield]: https://img.shields.io/packagist/v/grumpydictator/firefly-iii.svg?style=flat-square
|
||||
[packagist-url]: https://packagist.org/packages/grumpydictator/firefly-iii
|
||||
[license-shield]: https://img.shields.io/github/license/firefly-iii/firefly-iii.svg?style=flat-square
|
||||
|
@@ -10,19 +10,19 @@
|
||||
"prod": "mix --production"
|
||||
},
|
||||
"dependencies": {
|
||||
"date-fns": "^3.6.0",
|
||||
"date-fns": "^4.0.0",
|
||||
"stream-browserify": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@johmun/vue-tags-input": "^2",
|
||||
"@vue/compiler-sfc": "^3.4.34",
|
||||
"axios": "^1.3",
|
||||
"@vue/compiler-sfc": "^3.5.3",
|
||||
"axios": "^1.7",
|
||||
"bootstrap-sass": "^3",
|
||||
"cross-env": "^7.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"jquery": "^3",
|
||||
"laravel-mix": "^6.0",
|
||||
"postcss": "^8.4",
|
||||
"postcss": "^8.4.47",
|
||||
"uiv": "^1.4",
|
||||
"vue": "^2.7",
|
||||
"vue-i18n": "^8",
|
||||
|
@@ -887,6 +887,7 @@ export default {
|
||||
|
||||
deleteTransaction: function (index, event) {
|
||||
event.preventDefault();
|
||||
console.log('Remove transaction.');
|
||||
this.transactions.splice(index, 1);
|
||||
},
|
||||
limitSourceType: function (type) {
|
||||
|
@@ -540,6 +540,7 @@ export default {
|
||||
// }
|
||||
},
|
||||
convertData: function () {
|
||||
console.log('start of convertData');
|
||||
let data = {
|
||||
'apply_rules': this.applyRules,
|
||||
'fire_webhooks': this.fireWebhooks,
|
||||
@@ -585,7 +586,7 @@ export default {
|
||||
}
|
||||
}
|
||||
//console.log(data);
|
||||
|
||||
console.log('end of convertData');
|
||||
return data;
|
||||
},
|
||||
convertDataRow(row, index, transactionType, currencyId) {
|
||||
@@ -741,8 +742,8 @@ export default {
|
||||
return currentArray;
|
||||
},
|
||||
submit: function (e) {
|
||||
|
||||
let button = $('#submitButton');
|
||||
console.log('Submit!');
|
||||
let button = $(e.currentTarget);
|
||||
button.prop("disabled", true);
|
||||
|
||||
const page = window.location.href.split('/');
|
||||
@@ -750,23 +751,26 @@ export default {
|
||||
let uri = './api/v1/transactions/' + groupId + '?_token=' + document.head.querySelector('meta[name="csrf-token"]').content;
|
||||
let method = 'PUT';
|
||||
if (this.storeAsNew) {
|
||||
console.log('storeAsNew');
|
||||
// other links.
|
||||
uri = './api/v1/transactions?_token=' + document.head.querySelector('meta[name="csrf-token"]').content;
|
||||
method = 'POST';
|
||||
}
|
||||
const data = this.convertData();
|
||||
|
||||
//axios.put(uri, data)
|
||||
console.log('POST!');
|
||||
axios({
|
||||
method: method,
|
||||
url: uri,
|
||||
data: data,
|
||||
}).then(response => {
|
||||
console.log('Response!');
|
||||
if (0 === this.collectAttachmentData(response)) {
|
||||
const title = response.data.data.attributes.group_title ?? response.data.data.attributes.transactions[0].description;
|
||||
this.redirectUser(response.data.data.id, title);
|
||||
}
|
||||
button.removeAttr('disabled');
|
||||
}).catch(error => {
|
||||
console.log('Error :(');
|
||||
// give user errors things back.
|
||||
// something something render errors.
|
||||
this.parseErrors(error.response.data);
|
||||
@@ -775,10 +779,11 @@ export default {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
button.removeAttr('disabled');
|
||||
console.log('DONE with method.');
|
||||
},
|
||||
|
||||
redirectUser(groupId, title) {
|
||||
console.log('Now in redirectUser');
|
||||
if (this.returnAfter) {
|
||||
this.setDefaultErrors();
|
||||
// do message if update or new:
|
||||
@@ -796,10 +801,11 @@ export default {
|
||||
window.location.href = window.previousUrl + '?transaction_group_id=' + groupId + '&message=updated';
|
||||
}
|
||||
}
|
||||
console.log('End of redirectUser');
|
||||
},
|
||||
|
||||
collectAttachmentData(response) {
|
||||
// console.log('Now incollectAttachmentData()');
|
||||
console.log('Now incollectAttachmentData()');
|
||||
let groupId = response.data.data.id;
|
||||
|
||||
// array of all files to be uploaded:
|
||||
@@ -831,7 +837,7 @@ export default {
|
||||
}
|
||||
}
|
||||
let count = toBeUploaded.length;
|
||||
// console.log('Found ' + toBeUploaded.length + ' attachments.');
|
||||
console.log('Found ' + toBeUploaded.length + ' attachments.');
|
||||
|
||||
// loop all uploads.
|
||||
for (const key in toBeUploaded) {
|
||||
@@ -857,6 +863,7 @@ export default {
|
||||
})(toBeUploaded[key], key, this);
|
||||
}
|
||||
}
|
||||
console.log('Done with collectAttachmentData()');
|
||||
return count;
|
||||
},
|
||||
|
||||
|
@@ -122,7 +122,7 @@ export default {
|
||||
webhook.show_secret = !webhook.show_secret;
|
||||
},
|
||||
downloadWebhooks: function (page) {
|
||||
axios.get("/api/v1/webhooks?page=" + page).then((response) => {
|
||||
axios.get("./api/v1/webhooks?page=" + page).then((response) => {
|
||||
for (let i in response.data.data) {
|
||||
if (response.data.data.hasOwnProperty(i)) {
|
||||
let current = response.data.data[i];
|
||||
|
@@ -5,10 +5,10 @@
|
||||
"flash_warning": "\uacbd\uace0!",
|
||||
"flash_success": "\uc131\uacf5!",
|
||||
"close": "\ub2eb\uae30",
|
||||
"select_dest_account": "Please select or type a valid destination account name",
|
||||
"select_source_account": "Please select or type a valid source account name",
|
||||
"select_dest_account": "\uc720\ud6a8\ud55c \ub300\uc0c1 \uacc4\uc815 \ub0b4\uc5ed\uc744 \uc120\ud0dd \ub610\ub294 \ud0c0\uc785\uc744 \uc120\ud0dd\ud558\uc2ed\uc2dc\uc624.",
|
||||
"select_source_account": "\uc720\ud6a8\ud55c \uc18c\uc2a4 \uacc4\uc815 \ub0b4\uc5ed\uc744 \uc120\ud0dd \ub610\ub294 \ud0c0\uc785\uc744 \uc120\ud0dd\ud558\uc2ed\uc2dc\uc624.",
|
||||
"split_transaction_title": "\ubd84\ud560 \uac70\ub798\uc5d0 \ub300\ud55c \uc124\uba85",
|
||||
"errors_submission": "There was something wrong with your submission. Please check out the errors below.",
|
||||
"errors_submission": "\uc81c\ucd9c\ud55c \ub0b4\uc6a9\uc5d0 \ubb38\uc81c\uac00 \uc788\uc2b5\ub2c8\ub2e4. \uc544\ub798 \uc624\ub958\ub97c \ud655\uc778\ud574 \uc8fc\uc138\uc694.",
|
||||
"split": "\ub098\ub204\uae30",
|
||||
"single_split": "\ub098\ub204\uae30",
|
||||
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\uac70\ub798 #{ID} (\"{title}\")<\/a>\uac00 \uc800\uc7a5\ub418\uc5c8\uc2b5\ub2c8\ub2e4.",
|
||||
@@ -33,7 +33,7 @@
|
||||
"submit": "\uc81c\ucd9c",
|
||||
"amount": "\uae08\uc561",
|
||||
"date": "\ub0a0\uc9dc",
|
||||
"is_reconciled_fields_dropped": "Because this transaction is reconciled, you will not be able to update the accounts, nor the amount(s).",
|
||||
"is_reconciled_fields_dropped": "\uc774 \uac70\ub798\uac00 \uc218\uc815\ub418\uc5c8\uae30 \ub54c\ubb38\uc5d0, \uacc4\uc88c\ub098 \uae08\uc561\uc744 \uc5c5\ub370\uc774\ud2b8 \ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.",
|
||||
"tags": "\ud0dc\uadf8",
|
||||
"no_budget": "(\uc608\uc0b0 \uc5c6\uc74c)",
|
||||
"no_bill": "(\uccad\uad6c\uc11c \uc5c6\uc74c)",
|
||||
|
@@ -5,8 +5,8 @@
|
||||
"flash_warning": "Aviso!",
|
||||
"flash_success": "Sucesso!",
|
||||
"close": "Fechar",
|
||||
"select_dest_account": "Please select or type a valid destination account name",
|
||||
"select_source_account": "Please select or type a valid source account name",
|
||||
"select_dest_account": "Por favor, selecione ou digite um nome de conta destinat\u00e1ria v\u00e1lida",
|
||||
"select_source_account": "Por favor, selecione ou digite um nome de conta v\u00e1lido",
|
||||
"split_transaction_title": "Descri\u00e7\u00e3o da transa\u00e7\u00e3o dividida",
|
||||
"errors_submission": "Algo correu mal com o envio dos dados. Por favor verifique e corrija os erros abaixo.",
|
||||
"split": "Dividir",
|
||||
|
@@ -5,60 +5,60 @@
|
||||
"flash_warning": "\u0423\u0432\u0430\u0433\u0430!",
|
||||
"flash_success": "\u0423\u0441\u043f\u0456\u0448\u043d\u043e!",
|
||||
"close": "\u0417\u0430\u043a\u0440\u0438\u0442\u0438",
|
||||
"select_dest_account": "Please select or type a valid destination account name",
|
||||
"select_source_account": "Please select or type a valid source account name",
|
||||
"split_transaction_title": "Description of the split transaction",
|
||||
"errors_submission": "There was something wrong with your submission. Please check out the errors below.",
|
||||
"select_dest_account": "\u0411\u0443\u0434\u044c \u043b\u0430\u0441\u043a\u0430, \u0432\u0438\u0431\u0435\u0440\u0456\u0442\u044c \u0430\u0431\u043e \u0432\u0432\u0435\u0434\u0456\u0442\u044c \u0434\u0456\u0439\u0441\u043d\u0435 \u0456\u043c'\u044f \u043e\u0431\u043b\u0456\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0438\u0441\u0443 \u043f\u0440\u0438\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f",
|
||||
"select_source_account": "\u0411\u0443\u0434\u044c \u043b\u0430\u0441\u043a\u0430, \u0432\u0438\u0431\u0435\u0440\u0456\u0442\u044c \u0430\u0431\u043e \u0432\u0432\u0435\u0434\u0456\u0442\u044c \u0434\u0456\u0439\u0441\u043d\u0435 \u0456\u043c'\u044f \u0432\u0438\u0445\u0456\u0434\u043d\u043e\u0433\u043e \u043e\u0431\u043b\u0456\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0438\u0441\u0443",
|
||||
"split_transaction_title": "\u041e\u043f\u0438\u0441 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u0457 \u0440\u043e\u0437\u0434\u0456\u043b\u0435\u043d\u043d\u044f",
|
||||
"errors_submission": "\u0429\u043e\u0441\u044c \u043d\u0435 \u0442\u0430\u043a \u0437 \u0432\u0430\u0448\u043e\u044e \u043f\u0440\u043e\u043f\u043e\u0437\u0438\u0446\u0456\u0454\u044e. \u0411\u0443\u0434\u044c \u043b\u0430\u0441\u043a\u0430, \u043f\u0435\u0440\u0435\u0432\u0456\u0440\u0442\u0435 \u043f\u043e\u043c\u0438\u043b\u043a\u0438 \u043d\u0438\u0436\u0447\u0435.",
|
||||
"split": "\u0420\u043e\u0437\u0434\u0456\u043b\u0438\u0442\u0438",
|
||||
"single_split": "\u0420\u043e\u0437\u0434\u0456\u043b\u0438\u0442\u0438",
|
||||
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> has been stored.",
|
||||
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u044f #{ID} (\"{title}\")<\/a> \u0431\u0443\u043b\u0430 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u0430.",
|
||||
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">\u0412\u0435\u0431\u0445\u0443\u043a #{ID} (\"{title}\")<\/a> \u0431\u0443\u0432 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u0438\u0439.",
|
||||
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">\u0412\u0435\u0431\u0445\u0443\u043a #{ID}<\/a> (\"{title}\") \u0431\u0443\u0432 \u043e\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439.",
|
||||
"transaction_updated_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID}<\/a> (\"{title}\") has been updated.",
|
||||
"transaction_new_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID}<\/a> has been stored.",
|
||||
"transaction_journal_information": "Transaction information",
|
||||
"submission_options": "Submission options",
|
||||
"transaction_updated_link": "<a href=\"transactions\/show\/{ID}\">\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u044f #{ID}<\/a> (\"{title}\") \u0431\u0443\u043b\u0430 \u043e\u043d\u043e\u0432\u043b\u0435\u043d\u0430.",
|
||||
"transaction_new_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u044f #{ID}<\/a> \u0431\u0443\u043b\u0430 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u0430.",
|
||||
"transaction_journal_information": "\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u044f \u043f\u0440\u043e \u043f\u043b\u0430\u0442\u0456\u0436",
|
||||
"submission_options": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438 \u0441\u0430\u0431\u043c\u0456\u0442\u0443",
|
||||
"apply_rules_checkbox": "\u0417\u0430\u0441\u0442\u043e\u0441\u0443\u0432\u0430\u0442\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430",
|
||||
"fire_webhooks_checkbox": "Fire webhooks",
|
||||
"fire_webhooks_checkbox": "\u041f\u043e\u0436\u0435\u0436\u043d\u0456 \u0432\u0435\u0431\u0433\u0430\u043a\u0438",
|
||||
"no_budget_pointer": "\u0417\u0434\u0430\u0454\u0442\u044c\u0441\u044f, \u043d\u0435 \u0441\u0442\u0432\u043e\u0440\u0438\u043b\u0438 \u0436\u043e\u0434\u043d\u043e\u0433\u043e \u0431\u044e\u0434\u0436\u0435\u0442\u0443. \u0421\u0442\u0432\u043e\u0440\u0456\u0442\u044c \u043e\u0434\u0438\u043d \u043d\u0430 \u0441\u0442\u043e\u0440\u0456\u043d\u0446\u0456 <a href=\"budgets\">\u0431\u044e\u0434\u0436\u0435\u0442\u0456\u0432<\/a>. \u0411\u044e\u0434\u0436\u0435\u0442\u0438 \u043c\u043e\u0436\u0443\u0442\u044c \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0442\u0438 \u0432\u0430\u043c \u0441\u0442\u0435\u0436\u0438\u0442\u0438 \u0437\u0430 \u0432\u0438\u0442\u0440\u0430\u0442\u0430\u043c\u0438.",
|
||||
"no_bill_pointer": "\u0423 \u0432\u0430\u0441, \u0437\u0434\u0430\u0454\u0442\u044c\u0441\u044f, \u0449\u0435 \u043d\u0435\u043c\u0430\u0454 \u0440\u0430\u0445\u0443\u043d\u043a\u0456\u0432 \u0434\u043e \u0441\u043f\u043b\u0430\u0442\u0438. \u0421\u0442\u0432\u043e\u0440\u0456\u0442\u044c \u043a\u0456\u043b\u044c\u043a\u0430 \u043d\u0430 \u0441\u0442\u043e\u0440\u0456\u043d\u0446\u0456 <a href=\"bills\">\u0440\u0430\u0445\u0443\u043d\u043a\u0456\u0432<\/a>. \u0420\u0430\u0445\u0443\u043d\u043a\u0438 \u043c\u043e\u0436\u0443\u0442\u044c \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0442\u0438 \u0432\u0430\u043c \u0441\u0442\u0435\u0436\u0438\u0442\u0438 \u0437\u0430 \u0432\u0438\u0442\u0440\u0430\u0442\u0430\u043c\u0438.",
|
||||
"source_account": "\u0412\u0438\u0445\u0456\u0434\u043d\u0438\u0439 \u0440\u0430\u0445\u0443\u043d\u043e\u043a",
|
||||
"hidden_fields_preferences": "You can enable more transaction options in your <a href=\"preferences\">preferences<\/a>.",
|
||||
"hidden_fields_preferences": "\u0412\u0438 \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0432\u0456\u043c\u043a\u043d\u0443\u0442\u0438 \u0431\u0456\u043b\u044c\u0448\u0435 \u043e\u043f\u0446\u0456\u0439 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u0457 \u0443 \u0432\u0430\u0448\u043e\u043c\u0443 <a href=\"preferences\">\u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f<\/a>.",
|
||||
"destination_account": "\u0420\u0430\u0445\u0443\u043d\u043e\u043a \u043f\u0440\u0438\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f",
|
||||
"add_another_split": "Add another split",
|
||||
"submission": "Submission",
|
||||
"stored_journal": "Successfully created new transaction \":description\"",
|
||||
"create_another": "After storing, return here to create another one.",
|
||||
"reset_after": "Reset form after submission",
|
||||
"add_another_split": "\u0414\u043e\u0434\u0430\u0442\u0438 \u0449\u0435 \u0447\u0430\u0441\u0442\u0438\u043d\u0443",
|
||||
"submission": "\u041f\u043e\u0434\u0430\u043d\u043d\u044f",
|
||||
"stored_journal": "\u0423\u0441\u043f\u0456\u0448\u043d\u043e \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u043e \u043d\u043e\u0432\u0443 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u044e \":description\"",
|
||||
"create_another": "\u041f\u0456\u0441\u043b\u044f \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u043d\u044f, \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u0438\u0441\u044f \u0441\u044e\u0434\u0438.",
|
||||
"reset_after": "\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u0438 \u0444\u043e\u0440\u043c\u0443 \u043f\u0456\u0441\u043b\u044f \u0443\u0445\u0432\u0430\u043b\u0435\u043d\u043d\u044f",
|
||||
"submit": "\u041f\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0438",
|
||||
"amount": "\u0421\u0443\u043c\u0430",
|
||||
"date": "\u0414\u0430\u0442\u0430",
|
||||
"is_reconciled_fields_dropped": "Because this transaction is reconciled, you will not be able to update the accounts, nor the amount(s).",
|
||||
"is_reconciled_fields_dropped": "\u0427\u0435\u0440\u0435\u0437 \u0442\u0435, \u0449\u043e \u0446\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u044f \u0431\u0443\u043b\u0430 \u0432\u0438\u043a\u043e\u043d\u0430\u043d\u0430, \u0432\u0438 \u043d\u0435 \u0437\u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u043d\u043e\u0432\u0438\u0442\u0438 \u043e\u0431\u043b\u0456\u043a\u043e\u0432\u0456 \u0437\u0430\u043f\u0438\u0441\u0438, \u0430 \u0442\u0430\u043a\u043e\u0436 \u0441\u0443\u043c\u0438(\u0457).",
|
||||
"tags": "\u0422\u0435\u0433\u0438",
|
||||
"no_budget": "(\u043f\u043e\u0437\u0430 \u0431\u044e\u0434\u0436\u0435\u0442\u043e\u043c)",
|
||||
"no_bill": "(no bill)",
|
||||
"category": "Category",
|
||||
"no_bill": "(\u043d\u0435\u043c\u0430\u0454 \u0440\u0430\u0445\u0443\u043d\u043a\u0443)",
|
||||
"category": "\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0456\u044f",
|
||||
"attachments": "\u0412\u043a\u043b\u0430\u0434\u0435\u043d\u043d\u044f",
|
||||
"notes": "Notes",
|
||||
"notes": "\u041f\u0440\u0438\u043c\u0456\u0442\u043a\u0438",
|
||||
"external_url": "\u0417\u043e\u0432\u043d\u0456\u0448\u043d\u0456\u0439 URL",
|
||||
"update_transaction": "Update transaction",
|
||||
"after_update_create_another": "After updating, return here to continue editing.",
|
||||
"store_as_new": "Store as a new transaction instead of updating.",
|
||||
"split_title_help": "If you create a split transaction, there must be a global description for all splits of the transaction.",
|
||||
"update_transaction": "\u041e\u043d\u043e\u0432\u0438\u0442\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0456\u044e",
|
||||
"after_update_create_another": "\u041f\u0456\u0441\u043b\u044f \u043e\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044f \u043f\u043e\u0432\u0435\u0440\u043d\u0456\u0442\u044c\u0441\u044f \u0441\u044e\u0434\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u043e\u0432\u0436\u0435\u043d\u043d\u044f \u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u043d\u043d\u044f.",
|
||||
"store_as_new": "\u0417\u0431\u0435\u0440\u0456\u0433\u0430\u0442\u0438 \u0432 \u044f\u043a\u043e\u0441\u0442\u0456 \u043d\u043e\u0432\u043e\u0457 \u043e\u043f\u0435\u0440\u0430\u0446\u0456\u0457, \u0430 \u043d\u0435 \u043e\u043d\u043e\u0432\u043b\u044e\u0432\u0430\u0442\u0438.",
|
||||
"split_title_help": "\u042f\u043a\u0449\u043e \u0432\u0438 \u0441\u0442\u0432\u043e\u0440\u0438\u0442\u0435 \u0440\u043e\u0437\u043f\u043e\u0434\u0456\u043b\u0435\u043d\u0443 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u044e, \u0442\u043e \u043f\u043e\u0432\u0438\u043d\u043d\u0456 \u0431\u0443\u0442\u0438 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0456 \u043e\u043f\u0438\u0441\u0438 \u0434\u043b\u044f \u0432\u0441\u0456\u0445 \u0440\u043e\u0437\u0434\u0456\u043b\u0435\u043d\u0438\u0445 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u0439.",
|
||||
"none_in_select_list": "(\u043d\u0435\u043c\u0430\u0454)",
|
||||
"no_piggy_bank": "(\u043d\u0435\u043c\u0430\u0454 \u0441\u043a\u0430\u0440\u0431\u043d\u0438\u0447\u043a\u0438)",
|
||||
"description": "\u041e\u043f\u0438\u0441",
|
||||
"split_transaction_title_help": "If you create a split transaction, there must be a global description for all splits of the transaction.",
|
||||
"split_transaction_title_help": "\u042f\u043a\u0449\u043e \u0432\u0438 \u0441\u0442\u0432\u043e\u0440\u0438\u0442\u0435 \u0440\u043e\u0437\u043f\u043e\u0434\u0456\u043b\u0435\u043d\u0443 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u044e, \u0442\u043e \u043f\u043e\u0432\u0438\u043d\u043d\u0456 \u0431\u0443\u0442\u0438 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0456 \u043e\u043f\u0438\u0441\u0438 \u0434\u043b\u044f \u0432\u0441\u0456\u0445 \u0440\u043e\u0437\u0434\u0456\u043b\u0435\u043d\u0438\u0445 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0456\u0439.",
|
||||
"destination_account_reconciliation": "\u0412\u0438 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0456\u0457 \u043f\u043e\u0433\u043e\u0434\u0436\u0435\u043d\u043d\u044f, \u0440\u0430\u0445\u0443\u043d\u043a\u0443 \u043f\u0440\u0438\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f.",
|
||||
"source_account_reconciliation": "\u0412\u0438 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0456\u0457 \u0437\u0432\u0456\u0440\u043a\u0438, \u0440\u0430\u0445\u0443\u043d\u043a\u0430 \u0434\u0436\u0435\u0440\u0435\u043b\u0430.",
|
||||
"budget": "Budget",
|
||||
"budget": "\u0411\u044e\u0434\u0436\u0435\u0442",
|
||||
"bill": "\u0420\u0430\u0445\u0443\u043d\u043e\u043a",
|
||||
"you_create_withdrawal": "You're creating a withdrawal.",
|
||||
"you_create_transfer": "You're creating a transfer.",
|
||||
"you_create_deposit": "You're creating a deposit.",
|
||||
"you_create_withdrawal": "\u0412\u0438 \u0441\u0442\u0432\u043e\u0440\u044e\u0454\u0442\u0435 \u0432\u0456\u0434\u043a\u043b\u0438\u043a\u0430\u043d\u043d\u044f.",
|
||||
"you_create_transfer": "\u0412\u0438 \u0441\u0442\u0432\u043e\u0440\u044e\u0454\u0442\u0435 \u043f\u0435\u0440\u0435\u043a\u0430\u0437.",
|
||||
"you_create_deposit": "\u0412\u0438 \u0441\u0442\u0432\u043e\u0440\u044e\u0454\u0442\u0435 \u0434\u0435\u043f\u043e\u0437\u0438\u0442.",
|
||||
"edit": "\u0420\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438",
|
||||
"delete": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438",
|
||||
"name": "Name",
|
||||
"name": "\u041d\u0430\u0437\u0432\u0430",
|
||||
"profile_whoops": "\u041b\u0438\u0448\u0435\u043d\u044c\u043a\u043e!",
|
||||
"profile_something_wrong": "\u0429\u043e\u0441\u044c \u043f\u0456\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a!",
|
||||
"profile_try_again": "\u0429\u043e\u0441\u044c \u043f\u0456\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a. \u0411\u0443\u0434\u044c \u043b\u0430\u0441\u043a\u0430, \u0441\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0449\u0435 \u0440\u0430\u0437.",
|
||||
@@ -107,7 +107,7 @@
|
||||
"actions": "\u0414\u0456\u0457",
|
||||
"meta_data": "\u041c\u0435\u0442\u0430-\u0434\u0430\u043d\u0456",
|
||||
"webhook_messages": "\u041f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u043d\u044f \u0432\u0435\u0431-\u0445\u0443\u043a\u0430",
|
||||
"inactive": "Inactive",
|
||||
"inactive": "\u041d\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u0438\u0439",
|
||||
"no_webhook_messages": "\u041f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u043d\u044f \u0432\u0456\u0434\u0441\u0443\u0442\u043d\u0456",
|
||||
"inspect": "\u0414\u043e\u0441\u043b\u0456\u0434\u0438\u0442\u0438",
|
||||
"create_new_webhook": "\u0421\u0442\u0432\u043e\u0440\u0438\u0442\u0438 \u043d\u043e\u0432\u0438\u0439 \u0432\u0435\u0431-\u0445\u0443\u043a",
|
||||
|
@@ -8,10 +8,10 @@
|
||||
"postinstall": "patch-package --error-on-fail"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^1.6.8",
|
||||
"axios": "^1.7.4",
|
||||
"laravel-vite-plugin": "^1.0.5",
|
||||
"patch-package": "^8.0.0",
|
||||
"sass": "^1.77.8",
|
||||
"sass": "^1.78.0",
|
||||
"vite": "^5",
|
||||
"vite-plugin-manifest-sri": "^0.2.0"
|
||||
},
|
||||
@@ -30,7 +30,7 @@
|
||||
"chart.js": "^4.4.0",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"chartjs-chart-sankey": "^0.12.1",
|
||||
"date-fns": "^3.6.0",
|
||||
"date-fns": "^4.0.0",
|
||||
"i18next": "^23.11.2",
|
||||
"i18next-chained-backend": "^4.6.2",
|
||||
"i18next-http-backend": "^2.4.2",
|
||||
|
@@ -28,6 +28,7 @@ return [
|
||||
'filter_must_be_in' => 'Filter ":filter" must be one of: :values',
|
||||
'filter_not_string' => 'Filter ":filter" is expected to be a string of text',
|
||||
'bad_api_filter' => 'This API endpoint does not support ":filter" as a filter.',
|
||||
'nog_logged_in' => 'You are not logged in.',
|
||||
'bad_type_source' => 'Firefly III can\'t determine the transaction type based on this source account.',
|
||||
'bad_type_destination' => 'Firefly III can\'t determine the transaction type based on this destination account.',
|
||||
'missing_where' => 'Array is missing "where"-clause',
|
||||
|
@@ -85,12 +85,12 @@
|
||||
</a>
|
||||
</li>
|
||||
{% if true == featuringWebhooks %}
|
||||
<li class="{{ activeRoutePartial('webhooks') }}">
|
||||
<a href="{{ route('webhooks.index') }}">
|
||||
<span class="fa fa-angle-right fa-fw"></span>
|
||||
<span>{{ 'webhooks'|_ }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="{{ activeRoutePartial('webhooks') }}">
|
||||
<a href="{{ route('webhooks.index') }}">
|
||||
<span class="fa fa-angle-right fa-fw"></span>
|
||||
<span>{{ 'webhooks'|_ }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="">
|
||||
<a href="#">
|
||||
@@ -230,10 +230,18 @@
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
{% if 'remote_user_guard' != authGuard or '' != logoutUri %}
|
||||
{% if 'web' == authGuard %}
|
||||
<li>
|
||||
<a href="{{ route('logout') }}" class="logout-link">
|
||||
<em class="fa fa-sign-out fa-fw"></em>
|
||||
<span>{{ 'logout'|_ }}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if 'remote_user_guard' == authGuard and '' != logoutUrl %}
|
||||
<li>
|
||||
<a href="{{ logoutUrl }}">
|
||||
<em class="fa fa-sign-out fa-fw"></em>
|
||||
<span>{{ 'logout'|_ }}</span>
|
||||
</a>
|
||||
|
@@ -243,10 +243,11 @@ Route::group(
|
||||
JsonApiRoute::server('v2')->prefix('v2')
|
||||
->resources(function (ResourceRegistrar $server): void {
|
||||
// ACCOUNTS
|
||||
$server->resource('accounts', AccountController::class)->relationships(function (Relationships $relations): void {
|
||||
$relations->hasOne('user')->readOnly();
|
||||
});
|
||||
// $server->resource('accounts', AccountController::class)->readOnly();
|
||||
$server->resource('accounts', AccountController::class)
|
||||
->relationships(function (Relationships $relations): void {
|
||||
$relations->hasOne('user')->readOnly();
|
||||
})
|
||||
;
|
||||
|
||||
// USERS
|
||||
$server->resource('users', JsonApiController::class)->readOnly()->relationships(function (Relationships $relations): void {
|
||||
|
79
tests/integration/Api/About/AboutControllerTest.php
Normal file
79
tests/integration/Api/About/AboutControllerTest.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/*
|
||||
* AboutControllerTest.php
|
||||
* Copyright (c) 2021 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\integration\Api\About;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
use Tests\integration\TestCase;
|
||||
|
||||
/**
|
||||
* Class AboutControllerTest
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
final class AboutControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
private $user;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!isset($this->user)) {
|
||||
$this->user = $this->createAuthenticatedUser();
|
||||
}
|
||||
$this->actingAs($this->user);
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestReturnsSystemInformation(): void
|
||||
{
|
||||
$response = $this->getJson(route('api.v1.about.index'));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonStructure([
|
||||
'data' => [
|
||||
'version',
|
||||
'api_version',
|
||||
'php_version',
|
||||
'os',
|
||||
'driver',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestReturnsUserInformation(): void
|
||||
{
|
||||
$response = $this->getJson(route('api.v1.about.user'));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJson(
|
||||
fn (AssertableJson $json) => $json
|
||||
->where('data.attributes.email', $this->user->email)
|
||||
->where('data.attributes.role', $this->user->role)
|
||||
);
|
||||
}
|
||||
}
|
159
tests/integration/Api/Autocomplete/BillControllerTest.php
Normal file
159
tests/integration/Api/Autocomplete/BillControllerTest.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/*
|
||||
* BillControllerTest.php
|
||||
* Copyright (c) 2024 tasnim0tantawi
|
||||
*
|
||||
* 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 Tests\integration\Api\Autocomplete;
|
||||
|
||||
use FireflyIII\Models\Bill;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\integration\TestCase;
|
||||
use FireflyIII\User;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
|
||||
/**
|
||||
* Class BillControllerTest
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
final class BillControllerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \FireflyIII\Api\V1\Controllers\Autocomplete\BillController
|
||||
*/
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function createAuthenticatedUser(): User
|
||||
{
|
||||
$userGroup = UserGroup::create(['title' => 'Test Group']);
|
||||
|
||||
return User::create([
|
||||
'email' => 'test@email.com',
|
||||
'password' => 'password',
|
||||
'user_group_id' => $userGroup->id,
|
||||
]);
|
||||
}
|
||||
|
||||
private function createTestBills(int $count, User $user): void
|
||||
{
|
||||
for ($i = 1; $i <= $count; ++$i) {
|
||||
$bill = Bill::create([
|
||||
'user_id' => $user->id,
|
||||
'name' => 'Bill '.$i,
|
||||
'user_group_id' => $user->user_group_id,
|
||||
'amount_min' => rand(1, 100), // random amount
|
||||
'amount_max' => rand(101, 200), // random amount
|
||||
'match' => 'MIGRATED_TO_RULES',
|
||||
'date' => '2024-01-01',
|
||||
'repeat_freq' => 'monthly',
|
||||
'automatch' => 1,
|
||||
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function testGivenAnUnauthenticatedRequestWhenCallingTheBillsEndpointThenReturns401HttpCode(): void
|
||||
{
|
||||
// test API
|
||||
$response = $this->get(route('api.v1.autocomplete.bills'), ['Accept' => 'application/json']);
|
||||
$response->assertStatus(401);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
$response->assertContent('{"message":"Unauthenticated","exception":"AuthenticationException"}');
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheBillsEndpointThenReturns200HttpCode(): void
|
||||
{
|
||||
// act as a user
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->get(route('api.v1.autocomplete.bills'), ['Accept' => 'application/json']);
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheBillsEndpointThenReturnsBills(): void
|
||||
{
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->createTestBills(5, $user);
|
||||
$response = $this->get(route('api.v1.autocomplete.bills'), ['Accept' => 'application/json']);
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
$response->assertJsonCount(5);
|
||||
$response->assertJsonFragment(['name' => 'Bill 1']);
|
||||
$response->assertJsonStructure([
|
||||
'*' => [
|
||||
'id',
|
||||
'name',
|
||||
'active',
|
||||
],
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheBillsEndpointWithQueryThenReturnsBillsWithLimit(): void
|
||||
{
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->createTestBills(5, $user);
|
||||
$response = $this->get(route('api.v1.autocomplete.bills', [
|
||||
'query' => 'Bill',
|
||||
'limit' => 3,
|
||||
]), ['Accept' => 'application/json']);
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
$response->assertJsonCount(3);
|
||||
$response->assertJsonFragment(['name' => 'Bill 1']);
|
||||
$response->assertJsonStructure([
|
||||
'*' => [
|
||||
'id',
|
||||
'name',
|
||||
'active',
|
||||
],
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheBillsEndpointWithQueryThenReturnsBillsThatMatchQuery(): void
|
||||
{
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->createTestBills(20, $user);
|
||||
$response = $this->get(route('api.v1.autocomplete.bills', [
|
||||
'query' => 'Bill 1',
|
||||
'limit' => 20,
|
||||
]), ['Accept' => 'application/json']);
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
// Bill 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11)
|
||||
$response->assertJsonCount(11);
|
||||
$response->assertJsonMissing(['name' => 'Bill 2']);
|
||||
}
|
||||
}
|
142
tests/integration/Api/Autocomplete/BudgetControllerTest.php
Normal file
142
tests/integration/Api/Autocomplete/BudgetControllerTest.php
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
/*
|
||||
* BudgetControllerTest.php
|
||||
* Copyright (c) 2024 tasnim0tantawi
|
||||
*
|
||||
* 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 Tests\integration\Api\Autocomplete;
|
||||
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\integration\TestCase;
|
||||
use FireflyIII\User;
|
||||
|
||||
/**
|
||||
* Class BudgetControllerTest
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
final class BudgetControllerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \FireflyIII\Api\V1\Controllers\Autocomplete\BudgetController
|
||||
*/
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function createAuthenticatedUser(): User
|
||||
{
|
||||
$userGroup = UserGroup::create(['title' => 'Test Group']);
|
||||
|
||||
return User::create([
|
||||
'email' => 'test@email.com',
|
||||
'password' => 'password',
|
||||
'user_group_id' => $userGroup->id,
|
||||
]);
|
||||
}
|
||||
|
||||
private function createTestBudgets(int $count, User $user): void
|
||||
{
|
||||
for ($i = 1; $i <= $count; ++$i) {
|
||||
$budget = Budget::create([
|
||||
'user_id' => $user->id,
|
||||
'name' => 'Budget '.$i,
|
||||
'user_group_id' => $user->user_group_id,
|
||||
'active' => 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function testGivenAnUnauthenticatedRequestWhenCallingTheBudgetsEndpointThenReturns401HttpCode(): void
|
||||
{
|
||||
// test API
|
||||
$response = $this->get(route('api.v1.autocomplete.budgets'), ['Accept' => 'application/json']);
|
||||
$response->assertStatus(401);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
$response->assertContent('{"message":"Unauthenticated","exception":"AuthenticationException"}');
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheBudgetsEndpointThenReturns200HttpCode(): void
|
||||
{
|
||||
// act as a user
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->get(route('api.v1.autocomplete.budgets'), ['Accept' => 'application/json']);
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheBudgetsEndpointThenReturnsBudgets(): void
|
||||
{
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->createTestBudgets(5, $user);
|
||||
$response = $this->get(route('api.v1.autocomplete.budgets'), ['Accept' => 'application/json']);
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
$response->assertJsonCount(5);
|
||||
$response->assertJsonFragment(['name' => 'Budget 1']);
|
||||
$response->assertJsonStructure([
|
||||
'*' => [
|
||||
'id',
|
||||
'name',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheBudgetsEndpointWithQueryThenReturnsBudgetsWithLimit(): void
|
||||
{
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->createTestBudgets(5, $user);
|
||||
$response = $this->get(route('api.v1.autocomplete.budgets', [
|
||||
'query' => 'Budget',
|
||||
'limit' => 3,
|
||||
]), ['Accept' => 'application/json']);
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
$response->assertJsonCount(3);
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheBudgetsEndpointWithQueryThenReturnsBudgetsThatMatchQuery(): void
|
||||
{
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->createTestBudgets(20, $user);
|
||||
$response = $this->get(route('api.v1.autocomplete.budgets', [
|
||||
'query' => 'Budget 1',
|
||||
'limit' => 20,
|
||||
]), ['Accept' => 'application/json']);
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
// Budget 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11)
|
||||
$response->assertJsonCount(11);
|
||||
$response->assertJsonMissing(['name' => 'Budget 2']);
|
||||
}
|
||||
}
|
137
tests/integration/Api/Autocomplete/CategoryControllerTest.php
Normal file
137
tests/integration/Api/Autocomplete/CategoryControllerTest.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/*
|
||||
* CategoryControllerTest.php
|
||||
* Copyright (c) 2024 tasnim0tantawi
|
||||
*
|
||||
* 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 Tests\integration\Api\Autocomplete;
|
||||
|
||||
use FireflyIII\Models\Category;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\integration\TestCase;
|
||||
use FireflyIII\User;
|
||||
|
||||
/**
|
||||
* Class CategoryControllerTest
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
final class CategoryControllerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \FireflyIII\Api\V1\Controllers\Autocomplete\CategoryController
|
||||
*/
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function createAuthenticatedUser(): User
|
||||
{
|
||||
return User::create([
|
||||
'email' => 'test@email.com',
|
||||
'password' => 'password',
|
||||
]);
|
||||
}
|
||||
|
||||
private function createTestCategories(int $count, User $user): void
|
||||
{
|
||||
for ($i = 1; $i <= $count; ++$i) {
|
||||
$category = Category::create([
|
||||
'user_id' => $user->id,
|
||||
'name' => 'Category '.$i,
|
||||
'user_group_id' => $user->user_group_id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function testGivenAnUnauthenticatedRequestWhenCallingTheCategoriesEndpointThenReturns401HttpCode(): void
|
||||
{
|
||||
// test API
|
||||
$response = $this->get(route('api.v1.autocomplete.categories'), ['Accept' => 'application/json']);
|
||||
$response->assertStatus(401);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
$response->assertContent('{"message":"Unauthenticated","exception":"AuthenticationException"}');
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheCategoriesEndpointThenReturns200HttpCode(): void
|
||||
{
|
||||
// act as a user
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->get(route('api.v1.autocomplete.categories'), ['Accept' => 'application/json']);
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheCategoriesEndpointThenReturnsCategories(): void
|
||||
{
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->createTestCategories(5, $user);
|
||||
$response = $this->get(route('api.v1.autocomplete.categories'), ['Accept' => 'application/json']);
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
$response->assertJsonCount(5);
|
||||
$response->assertJsonFragment(['name' => 'Category 1']);
|
||||
$response->assertJsonStructure([
|
||||
'*' => [
|
||||
'id',
|
||||
'name',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheCategoriesEndpointWithQueryThenReturnsCategoriesWithLimit(): void
|
||||
{
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->createTestCategories(5, $user);
|
||||
$response = $this->get(route('api.v1.autocomplete.categories', [
|
||||
'query' => 'Category',
|
||||
'limit' => 3,
|
||||
]), ['Accept' => 'application/json']);
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
$response->assertJsonCount(3);
|
||||
}
|
||||
|
||||
public function testGivenAuthenticatedRequestWhenCallingTheCategoriesEndpointWithQueryThenReturnsCategoriesThatMatchQuery(): void
|
||||
{
|
||||
$user = $this->createAuthenticatedUser();
|
||||
$this->actingAs($user);
|
||||
|
||||
$this->createTestCategories(20, $user);
|
||||
$response = $this->get(route('api.v1.autocomplete.categories', [
|
||||
'query' => 'Category 1',
|
||||
'limit' => 20,
|
||||
]), ['Accept' => 'application/json']);
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/json');
|
||||
// Category 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11)
|
||||
$response->assertJsonCount(11);
|
||||
$response->assertJsonMissing(['name' => 'Category 2']);
|
||||
}
|
||||
}
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Tests\integration;
|
||||
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
use Tests\integration\Traits\CollectsValues;
|
||||
|
||||
@@ -48,4 +49,12 @@ abstract class TestCase extends BaseTestCase
|
||||
'custom range' => ['custom'],
|
||||
];
|
||||
}
|
||||
|
||||
protected function createAuthenticatedUser(): User
|
||||
{
|
||||
return User::create([
|
||||
'email' => 'test@email.com',
|
||||
'password' => 'password',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -70,9 +70,10 @@ final class NavigationEndOfPeriodTest extends TestCase
|
||||
'last30' => ['frequency' => 'last30', 'from' => Carbon::now(), 'expected' => Carbon::now()->addDays(30)->endOfDay()],
|
||||
'last90' => ['frequency' => 'last90', 'from' => Carbon::now(), 'expected' => Carbon::now()->addDays(90)->endOfDay()],
|
||||
'last365' => ['frequency' => 'last365', 'from' => Carbon::now(), 'expected' => Carbon::now()->addDays(365)->endOfDay()],
|
||||
'MTD' => ['frequency' => 'MTD', 'from' => Carbon::now(), 'expected' => Carbon::now()->startOfMonth()->startOfDay()],
|
||||
'MTD' => ['frequency' => 'MTD', 'from' => Carbon::now(),
|
||||
'expected' => Carbon::now()->isSameMonth(Carbon::now()) ? Carbon::now()->endOfDay() : Carbon::now()->endOfMonth()],
|
||||
'QTD' => ['frequency' => 'QTD', 'from' => Carbon::now(), 'expected' => Carbon::now()->firstOfQuarter()->startOfDay()],
|
||||
'YTD' => ['frequency' => 'YTD', 'from' => Carbon::now(), 'expected' => Carbon::now()->startOfYear()->startOfDay()],
|
||||
'YTD' => ['frequency' => 'YTD', 'from' => Carbon::now(), 'expected' => Carbon::now()->firstOfYear()->startOfDay()],
|
||||
'week 2023-08-05 to 2023-08-11' => ['frequency' => '1W', 'from' => Carbon::parse('2023-08-05'), 'expected' => Carbon::parse('2023-08-11')->endOfDay()],
|
||||
];
|
||||
}
|
||||
|
Reference in New Issue
Block a user