mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-22 20:16:22 +00:00
Compare commits
397 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
98ba392016 | ||
|
d49ee83748 | ||
|
88cdb1811f | ||
|
94c190668c | ||
|
eef0f4bd4e | ||
|
dad58fa362 | ||
|
40585469f2 | ||
|
d06035071a | ||
|
e81565d36a | ||
|
f66dd259f0 | ||
|
e003dcd596 | ||
|
d4ecf44b08 | ||
|
f4426eb830 | ||
|
7c86ce3977 | ||
|
1665335525 | ||
|
14bce014a3 | ||
|
75e5115aa3 | ||
|
de7638c502 | ||
|
126e378399 | ||
|
45e9c999b8 | ||
|
62bba0d33b | ||
|
0b220f3288 | ||
|
7dbdf0c4ff | ||
|
417b7c3f86 | ||
|
724a16944a | ||
|
c3bc1af7b5 | ||
|
38b7daf3b6 | ||
|
7bf7bb529e | ||
|
6b5774a66d | ||
|
0e3ebb9f1a | ||
|
1c41b6753d | ||
|
549f3c038a | ||
|
edbac66576 | ||
|
c788395508 | ||
|
35b0c20f88 | ||
|
518712d9e8 | ||
|
241ad25e2f | ||
|
7cf7c5fcef | ||
|
fbb9de64c3 | ||
|
88c145ac3e | ||
|
4aba842624 | ||
|
936c2b8888 | ||
|
c3e971c419 | ||
|
19fee6a8fb | ||
|
477eebdbe7 | ||
|
093bff750c | ||
|
92e679a9ea | ||
|
43232ae45c | ||
|
1fb13d8697 | ||
|
9ac28b93ca | ||
|
067c01ca06 | ||
|
82040c2a5d | ||
|
62502c746c | ||
|
6ab79a87fe | ||
|
04ee3b4dc1 | ||
|
9c9af79ad5 | ||
|
dd794e409f | ||
|
67d29b8416 | ||
|
5ee80dd046 | ||
|
f62e93b487 | ||
|
a7cc70b975 | ||
|
60f0d8074a | ||
|
ed1fdf9382 | ||
|
9ea3c4224e | ||
|
71325de44e | ||
|
cdb041e647 | ||
|
b9d750bf59 | ||
|
461249737e | ||
|
1aeaa8b77d | ||
|
a59d7ccdc2 | ||
|
2c1ca428db | ||
|
224970f3bd | ||
|
742d934ddb | ||
|
1699513023 | ||
|
488a8a7e86 | ||
|
dd571d6221 | ||
|
4cc5128b4c | ||
|
2636a6557a | ||
|
0bf97ccf22 | ||
|
592fc71b4e | ||
|
0e7712d3b8 | ||
|
80f21d2a4f | ||
|
5513ec068e | ||
|
14a46a6197 | ||
|
b93ee5efd8 | ||
|
cdd4dc6065 | ||
|
0d8b2ae799 | ||
|
77dc79b638 | ||
|
f48723db40 | ||
|
ebf91078c5 | ||
|
90d0d85dd6 | ||
|
0c5b4f7f64 | ||
|
9c4bb08ed1 | ||
|
1d3bbde4b0 | ||
|
b6faee033d | ||
|
05e0f88d11 | ||
|
ae9a151140 | ||
|
da633e3c62 | ||
|
8cb384d3cf | ||
|
de2a34c3ec | ||
|
b7c65446a8 | ||
|
bc648b187c | ||
|
4de0828b5d | ||
|
b2364d26ec | ||
|
83d94cb792 | ||
|
66cc3f48bc | ||
|
63297c43b7 | ||
|
5b0637558f | ||
|
e9a8e104be | ||
|
0f524e7800 | ||
|
969e0bccc9 | ||
|
ba3e026927 | ||
|
0c6868d477 | ||
|
7f70cf47ec | ||
|
fa4492287d | ||
|
60809c688e | ||
|
2404f5299c | ||
|
21a394eaf5 | ||
|
419d7846c9 | ||
|
0827accc39 | ||
|
2e53f7d0b7 | ||
|
bdfcf8ec95 | ||
|
6a20170e00 | ||
|
0c974f1ff7 | ||
|
9c098d45c5 | ||
|
cfdf9aa8dc | ||
|
2ea74542e6 | ||
|
7fcaa2b5fb | ||
|
e9e905e495 | ||
|
f67ff98d78 | ||
|
e3c4dde4ff | ||
|
9787561000 | ||
|
cd041b4c75 | ||
|
60ee70c926 | ||
|
00de78b6f1 | ||
|
33a841b831 | ||
|
df66dcf102 | ||
|
086a7a0b1e | ||
|
ec0ba3d212 | ||
|
b0ab06b7eb | ||
|
965acd6d45 | ||
|
4d156870ef | ||
|
499720df46 | ||
|
610bc108e7 | ||
|
53f1b0218c | ||
|
0a7a099796 | ||
|
ed90ebc896 | ||
|
87fe518d45 | ||
|
5cb0891a27 | ||
|
b4bd66bd58 | ||
|
64d95fe845 | ||
|
a2d6d7a92c | ||
|
1d8a784586 | ||
|
3c8bfae8ff | ||
|
f65eccfe4c | ||
|
7ce6dc9f16 | ||
|
4a73caf4c3 | ||
|
1b9d8dd3c3 | ||
|
b11bfb0aae | ||
|
024e16bf4b | ||
|
daf753d76e | ||
|
4c90f66578 | ||
|
db94f18d46 | ||
|
a9bd0f551d | ||
|
e1ba2d9ad9 | ||
|
939c636a74 | ||
|
2b829cb645 | ||
|
4bbc898639 | ||
|
27d07d5807 | ||
|
f010ffefc1 | ||
|
fc0fee161e | ||
|
72c99d3834 | ||
|
a2984f299b | ||
|
3925077223 | ||
|
deb51bd8de | ||
|
03f39f53d8 | ||
|
e72314778c | ||
|
ced3e9387a | ||
|
02c906afe6 | ||
|
7a2d4c9bd2 | ||
|
dffddfda18 | ||
|
9bb62c865a | ||
|
a97ebf2b97 | ||
|
9a62a6c514 | ||
|
04dc162270 | ||
|
75d5a50328 | ||
|
eadb7d5dcb | ||
|
8dc07f1148 | ||
|
217ce85a9b | ||
|
ef88b25dbd | ||
|
4c2e2a3a5a | ||
|
1e8e1c6e51 | ||
|
a92944786c | ||
|
8ce760a0bf | ||
|
8d8e047d2c | ||
|
06a923db94 | ||
|
551408b801 | ||
|
e1915e365a | ||
|
e8c4eec536 | ||
|
e3f4e75561 | ||
|
fd640f9698 | ||
|
ffd8aef35f | ||
|
46412bdc66 | ||
|
d73c3476c8 | ||
|
ff737ae05e | ||
|
171ec0c630 | ||
|
b4a6c6fcbe | ||
|
4886084296 | ||
|
1a3dfbdef6 | ||
|
0c087f33c2 | ||
|
5f9f621fa6 | ||
|
cd3de7b545 | ||
|
8aeb513d54 | ||
|
bfc5c5d154 | ||
|
7c9f7f04b7 | ||
|
3352c2cf3c | ||
|
e61a433999 | ||
|
3517452ea1 | ||
|
8a1190b9ee | ||
|
fc78c9a1d6 | ||
|
8d55f7f2e5 | ||
|
8162b22d43 | ||
|
8504d55f17 | ||
|
75ae1bbde1 | ||
|
a20668e91b | ||
|
eb559bbb03 | ||
|
2eae96a895 | ||
|
4bbf35bca4 | ||
|
f1b5e45488 | ||
|
57ed1581ec | ||
|
c668381ab0 | ||
|
44f99991fc | ||
|
696c76102b | ||
|
fe4e00dc5c | ||
|
1a1b0ee27d | ||
|
298c4ec654 | ||
|
c6e3fa2cc6 | ||
|
61484dcfee | ||
|
99009cff88 | ||
|
673f68b07c | ||
|
d1232192ce | ||
|
b2084a94e5 | ||
|
ddcb246955 | ||
|
8796168580 | ||
|
dde7bcfc4c | ||
|
a6503fda39 | ||
|
455e311661 | ||
|
a4a919d7b7 | ||
|
a90ce3c944 | ||
|
a6d179b883 | ||
|
1b29e5e628 | ||
|
e8fd496bca | ||
|
3d61e27a47 | ||
|
f9a55ce3d8 | ||
|
c432757942 | ||
|
da740ccbef | ||
|
f1173263b6 | ||
|
68da1a7039 | ||
|
64414edf58 | ||
|
6b136d2c8c | ||
|
752a877b91 | ||
|
d11c36e476 | ||
|
b13232f06b | ||
|
cf6ed5af32 | ||
|
be531d777e | ||
|
190508fa54 | ||
|
2c2dddc071 | ||
|
c60858de5c | ||
|
6ab332e4fb | ||
|
9df43cc710 | ||
|
79d1b15d86 | ||
|
923debb299 | ||
|
f5fef8c036 | ||
|
982134c077 | ||
|
07aeb6cd20 | ||
|
30cca355ba | ||
|
d17cc15037 | ||
|
efade857bb | ||
|
15ac6a1195 | ||
|
a45a050e7d | ||
|
e435ff8b1c | ||
|
788dae1477 | ||
|
2bb4cc7954 | ||
|
ecead8a27b | ||
|
4a2681df14 | ||
|
5761d82635 | ||
|
36fce9db4e | ||
|
1227574bc1 | ||
|
47c2a66e1d | ||
|
c59e52bbbf | ||
|
81961fd632 | ||
|
b557805eeb | ||
|
e58da3c41d | ||
|
f43b539470 | ||
|
ab3dbf9218 | ||
|
d943a5ae9b | ||
|
449058dad7 | ||
|
b9cf8b3ef2 | ||
|
27037c2fbb | ||
|
10646099a0 | ||
|
43ad63fac6 | ||
|
221c59437c | ||
|
1a94ec5bbe | ||
|
f57c554c56 | ||
|
334aec58a4 | ||
|
7035da4d75 | ||
|
29a40ce8dd | ||
|
c6c98c4df5 | ||
|
277d7e6650 | ||
|
130c539006 | ||
|
2bdb2e12f0 | ||
|
25779206a1 | ||
|
92f72a5ad7 | ||
|
4e041248ac | ||
|
8cc5aa8aba | ||
|
4ba712b24e | ||
|
7af9169763 | ||
|
775504acb6 | ||
|
7840e37e1a | ||
|
720fff4595 | ||
|
551c1f4cda | ||
|
7f0db0de04 | ||
|
6ac3cc384b | ||
|
563879c218 | ||
|
dbb7ed3d5d | ||
|
4e3c2ba72c | ||
|
8e911491f6 | ||
|
03c5f3cc2d | ||
|
484565d600 | ||
|
163a979227 | ||
|
ed105fee1d | ||
|
3b82cfa486 | ||
|
834e52eb2e | ||
|
7eb938fe23 | ||
|
8db7a4c47d | ||
|
b055a5d6af | ||
|
ad0a1b9a24 | ||
|
05d190659a | ||
|
9c6eaffba6 | ||
|
3ee5e9aa04 | ||
|
93a544fe53 | ||
|
3bc98bee20 | ||
|
f6302bc29b | ||
|
43aa1704a9 | ||
|
14fe82e361 | ||
|
33317c15a2 | ||
|
ff1b56c5ef | ||
|
25e2063d70 | ||
|
1d36c74934 | ||
|
aebe7908f0 | ||
|
3e2b881296 | ||
|
c670a6991d | ||
|
f76a7d59e0 | ||
|
3d8bf3ec9b | ||
|
55e4479454 | ||
|
436fe9fea4 | ||
|
63a7a4b03b | ||
|
0cab974048 | ||
|
5fdcf37d06 | ||
|
4663fb2f12 | ||
|
e844ab592d | ||
|
3dcb35710b | ||
|
8d87abde64 | ||
|
2b78485a61 | ||
|
9d057b853f | ||
|
bd269eaadf | ||
|
7096c65f50 | ||
|
1462b0de69 | ||
|
86a1f170c4 | ||
|
40389fb6d5 | ||
|
36021d84cf | ||
|
1278f92355 | ||
|
573f9adb49 | ||
|
431c99c27b | ||
|
77cc558931 | ||
|
42043de34f | ||
|
f2b2c2109f | ||
|
7fe29ad983 | ||
|
07d9bcfb9d | ||
|
fdd235e4cb | ||
|
2646acadb8 | ||
|
5ef646b810 | ||
|
e8bdb5ef38 | ||
|
7a851c2cc6 | ||
|
624784e54e | ||
|
20eb2ebe58 | ||
|
25f8acb417 | ||
|
f75e6430b1 | ||
|
e72a483c49 | ||
|
68934858ce | ||
|
c08b5177d9 | ||
|
fe8635f1ce | ||
|
e96d28b981 | ||
|
784cc3d52d | ||
|
2ab3fb3a71 | ||
|
ff765d4687 | ||
|
ed36604050 |
@@ -301,7 +301,6 @@ PUSHER_ID=
|
||||
DEMO_USERNAME=
|
||||
DEMO_PASSWORD=
|
||||
USE_ENCRYPTION=false
|
||||
IS_HEROKU=false
|
||||
FIREFLY_III_LAYOUT=v1
|
||||
|
||||
#
|
||||
|
1
.ci/php-cs-fixer/.gitignore
vendored
1
.ci/php-cs-fixer/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
vendor
|
||||
.php-cs-fixer.cache
|
||||
|
387
.ci/php-cs-fixer/composer.lock
generated
387
.ci/php-cs-fixer/composer.lock
generated
@@ -79,16 +79,16 @@
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "3.3.2",
|
||||
"version": "3.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/semver.git",
|
||||
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
|
||||
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
|
||||
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
|
||||
"reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -138,9 +138,9 @@
|
||||
"versioning"
|
||||
],
|
||||
"support": {
|
||||
"irc": "irc://irc.freenode.org/composer",
|
||||
"irc": "ircs://irc.libera.chat:6697/composer",
|
||||
"issues": "https://github.com/composer/semver/issues",
|
||||
"source": "https://github.com/composer/semver/tree/3.3.2"
|
||||
"source": "https://github.com/composer/semver/tree/3.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -156,7 +156,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-04-01T19:23:25+00:00"
|
||||
"time": "2023-08-31T09:50:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/xdebug-handler",
|
||||
@@ -224,178 +224,23 @@
|
||||
],
|
||||
"time": "2022-02-25T21:32:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/annotations.git",
|
||||
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
|
||||
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/lexer": "^2 || ^3",
|
||||
"ext-tokenizer": "*",
|
||||
"php": "^7.2 || ^8.0",
|
||||
"psr/cache": "^1 || ^2 || ^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/cache": "^2.0",
|
||||
"doctrine/coding-standard": "^10",
|
||||
"phpstan/phpstan": "^1.8.0",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"symfony/cache": "^5.4 || ^6",
|
||||
"vimeo/psalm": "^4.10"
|
||||
},
|
||||
"suggest": {
|
||||
"php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Docblock Annotations Parser",
|
||||
"homepage": "https://www.doctrine-project.org/projects/annotations.html",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"docblock",
|
||||
"parser"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/annotations/issues",
|
||||
"source": "https://github.com/doctrine/annotations/tree/2.0.1"
|
||||
},
|
||||
"time": "2023-02-02T22:02:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/lexer.git",
|
||||
"reference": "84a527db05647743d50373e0ec53a152f2cde568"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568",
|
||||
"reference": "84a527db05647743d50373e0ec53a152f2cde568",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^10",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/plugin-phpunit": "^0.18.3",
|
||||
"vimeo/psalm": "^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Lexer\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
|
||||
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"docblock",
|
||||
"lexer",
|
||||
"parser",
|
||||
"php"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/lexer/issues",
|
||||
"source": "https://github.com/doctrine/lexer/tree/3.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpdoctrine",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-15T16:57:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.17.0",
|
||||
"version": "v3.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "3f0ed862f22386c55a767461ef5083bddceeed79"
|
||||
"reference": "113e09fea3d2306319ffaa2423fe3de768b28cff"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/3f0ed862f22386c55a767461ef5083bddceeed79",
|
||||
"reference": "3f0ed862f22386c55a767461ef5083bddceeed79",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/113e09fea3d2306319ffaa2423fe3de768b28cff",
|
||||
"reference": "113e09fea3d2306319ffaa2423fe3de768b28cff",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/semver": "^3.3",
|
||||
"composer/xdebug-handler": "^3.0.3",
|
||||
"doctrine/annotations": "^2",
|
||||
"doctrine/lexer": "^2 || ^3",
|
||||
"ext-json": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"php": "^7.4 || ^8.0",
|
||||
@@ -412,6 +257,7 @@
|
||||
"symfony/stopwatch": "^5.4 || ^6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"facile-it/paraunit": "^1.3 || ^2.0",
|
||||
"justinrainbow/json-schema": "^5.2",
|
||||
"keradus/cli-executor": "^2.0",
|
||||
"mikey179/vfsstream": "^1.6.11",
|
||||
@@ -463,7 +309,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.17.0"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -471,56 +317,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-22T19:59:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/cache.git",
|
||||
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
|
||||
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Cache\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for caching libraries",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"psr",
|
||||
"psr-6"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/cache/tree/3.0.0"
|
||||
},
|
||||
"time": "2021-02-03T23:26:27+00:00"
|
||||
"time": "2023-09-22T20:43:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
@@ -744,16 +541,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v6.3.0",
|
||||
"version": "v6.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7"
|
||||
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
|
||||
"reference": "8788808b07cf0bdd6e4b7fdd23d8ddb1470c83b7",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6",
|
||||
"reference": "eca495f2ee845130855ddf1cf18460c38966c8b6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -814,7 +611,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v6.3.0"
|
||||
"source": "https://github.com/symfony/console/tree/v6.3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -830,7 +627,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-29T12:49:39+00:00"
|
||||
"time": "2023-08-16T10:10:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
@@ -901,16 +698,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v6.3.0",
|
||||
"version": "v6.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa"
|
||||
"reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa",
|
||||
"reference": "3af8ac1a3f98f6dbc55e10ae59c9e44bfc38dfaa",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/adb01fe097a4ee930db9258a3cc906b5beb5cf2e",
|
||||
"reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -961,7 +758,7 @@
|
||||
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/event-dispatcher/tree/v6.3.0"
|
||||
"source": "https://github.com/symfony/event-dispatcher/tree/v6.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -977,7 +774,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-04-21T14:41:17+00:00"
|
||||
"time": "2023-07-06T06:56:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher-contracts",
|
||||
@@ -1057,16 +854,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v6.3.0",
|
||||
"version": "v6.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "97b698e1d77d356304def77a8d0cd73090b359ea"
|
||||
"reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/97b698e1d77d356304def77a8d0cd73090b359ea",
|
||||
"reference": "97b698e1d77d356304def77a8d0cd73090b359ea",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae",
|
||||
"reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1100,7 +897,7 @@
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v6.3.0"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v6.3.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1116,20 +913,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-30T17:12:32+00:00"
|
||||
"time": "2023-06-01T08:30:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v6.3.0",
|
||||
"version": "v6.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "d9b01ba073c44cef617c7907ce2419f8d00d75e2"
|
||||
"reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/d9b01ba073c44cef617c7907ce2419f8d00d75e2",
|
||||
"reference": "d9b01ba073c44cef617c7907ce2419f8d00d75e2",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/9915db259f67d21eefee768c1abcf1cc61b1fc9e",
|
||||
"reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1164,7 +961,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v6.3.0"
|
||||
"source": "https://github.com/symfony/finder/tree/v6.3.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1180,7 +977,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-04-02T01:25:41+00:00"
|
||||
"time": "2023-07-31T08:31:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
@@ -1251,16 +1048,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
|
||||
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
|
||||
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
|
||||
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1275,7 +1072,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1313,7 +1110,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1329,20 +1126,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
"reference": "511a08c03c1960e08a883f4cffcacd219b758354"
|
||||
"reference": "875e90aeea2777b6f135677f618529449334a612"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
|
||||
"reference": "511a08c03c1960e08a883f4cffcacd219b758354",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
|
||||
"reference": "875e90aeea2777b6f135677f618529449334a612",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1354,7 +1151,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1394,7 +1191,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1410,20 +1207,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
|
||||
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
|
||||
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
|
||||
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1435,7 +1232,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1478,7 +1275,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1494,20 +1291,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
|
||||
"reference": "42292d99c55abe617799667f454222c54c60e229",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1522,7 +1319,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1561,7 +1358,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1577,20 +1374,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-07-28T09:04:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
|
||||
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
|
||||
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
|
||||
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1599,7 +1396,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1644,7 +1441,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1660,20 +1457,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.27.0",
|
||||
"version": "v1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a"
|
||||
"reference": "7581cd600fa9fd681b797d00b02f068e2f13263b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a",
|
||||
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b",
|
||||
"reference": "7581cd600fa9fd681b797d00b02f068e2f13263b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1682,7 +1479,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
"dev-main": "1.28-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1723,7 +1520,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1739,20 +1536,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
"time": "2023-01-26T09:26:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v6.3.0",
|
||||
"version": "v6.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "8741e3ed7fe2e91ec099e02446fb86667a0f1628"
|
||||
"reference": "0b5c29118f2e980d455d2e34a5659f4579847c54"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/8741e3ed7fe2e91ec099e02446fb86667a0f1628",
|
||||
"reference": "8741e3ed7fe2e91ec099e02446fb86667a0f1628",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/0b5c29118f2e980d455d2e34a5659f4579847c54",
|
||||
"reference": "0b5c29118f2e980d455d2e34a5659f4579847c54",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1784,7 +1581,7 @@
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v6.3.0"
|
||||
"source": "https://github.com/symfony/process/tree/v6.3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1800,7 +1597,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-19T08:06:44+00:00"
|
||||
"time": "2023-08-07T10:39:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
@@ -1948,16 +1745,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v6.3.0",
|
||||
"version": "v6.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f"
|
||||
"reference": "53d1a83225002635bca3482fcbf963001313fb68"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/f2e190ee75ff0f5eced645ec0be5c66fac81f51f",
|
||||
"reference": "f2e190ee75ff0f5eced645ec0be5c66fac81f51f",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68",
|
||||
"reference": "53d1a83225002635bca3482fcbf963001313fb68",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2014,7 +1811,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v6.3.0"
|
||||
"source": "https://github.com/symfony/string/tree/v6.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2030,7 +1827,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-21T21:06:29+00:00"
|
||||
"time": "2023-07-05T08:41:27+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
@@ -30,12 +30,9 @@ SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
# clean up php code
|
||||
cd $SCRIPT_DIR/php-cs-fixer
|
||||
composer update
|
||||
composer update --quiet
|
||||
rm -f .php-cs-fixer.cache
|
||||
echo 'Removed cache...'
|
||||
echo 'Running...'
|
||||
PHP_CS_FIXER_IGNORE_ENV=true ./vendor/bin/php-cs-fixer fix --config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php --allow-risky=yes
|
||||
echo 'Done!'
|
||||
cd $SCRIPT_DIR/..
|
||||
|
||||
exit 0
|
||||
|
37
.ci/phpmd.sh
Normal file
37
.ci/phpmd.sh
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# phpmd.sh
|
||||
# Copyright (c) 2023 james@firefly-iii.org
|
||||
#
|
||||
# This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
|
||||
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
|
||||
cd $SCRIPT_DIR/phpmd
|
||||
composer update --quiet
|
||||
./vendor/bin/phpmd \
|
||||
$SCRIPT_DIR/../app text phpmd.xml \
|
||||
--exclude $SCRIPT_DIR/../app/resources/** \
|
||||
--exclude $SCRIPT_DIR/../app/frontend/** \
|
||||
--exclude $SCRIPT_DIR/../app/public/** \
|
||||
--exclude $SCRIPT_DIR/../app/vendor/** \
|
||||
|
||||
cd $SCRIPT_DIR/..
|
||||
|
||||
exit 0
|
1
.ci/phpmd/.gitignore
vendored
Normal file
1
.ci/phpmd/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
vendor
|
5
.ci/phpmd/composer.json
Normal file
5
.ci/phpmd/composer.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"require-dev": {
|
||||
"phpmd/phpmd": "^2.13"
|
||||
}
|
||||
}
|
1012
.ci/phpmd/composer.lock
generated
Normal file
1012
.ci/phpmd/composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
72
.ci/phpmd/phpmd.xml
Normal file
72
.ci/phpmd/phpmd.xml
Normal file
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ phpmd.xml
|
||||
~ Copyright (c) 2023 james@firefly-iii.org
|
||||
~
|
||||
~ This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU Affero General Public License as
|
||||
~ published by the Free Software Foundation, either version 3 of the
|
||||
~ License, or (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU Affero General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU Affero General Public License
|
||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<ruleset name="pcsg-generated-ruleset"
|
||||
xmlns="http://pmd.sf.net/ruleset/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
|
||||
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
|
||||
<description>Bla bla</description>
|
||||
|
||||
<!--
|
||||
Commando vanuit firefly directory:
|
||||
phpmd database,app,tests html /gdrive-all/development/phpmd/phpmd.xml > public/report.html
|
||||
-->
|
||||
|
||||
<!-- Import the entire controversial code rule set -->
|
||||
<rule ref="rulesets/controversial.xml">
|
||||
<exclude name="CamelCasePropertyName" />
|
||||
</rule>
|
||||
|
||||
<!-- clean code -->
|
||||
<rule ref="rulesets/codesize.xml" />
|
||||
<rule ref="rulesets/design.xml" />
|
||||
<rule ref="rulesets/naming.xml" />
|
||||
<rule ref="rulesets/unusedcode.xml" />
|
||||
|
||||
<rule ref="rulesets/codesize.xml/CyclomaticComplexity">
|
||||
<properties>
|
||||
<property name="reportLevel" value="5"/>
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="rulesets/codesize.xml/NPathComplexity">
|
||||
<properties>
|
||||
<property name="minimum" value="128"/>
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="rulesets/codesize.xml/ExcessiveMethodLength">
|
||||
<properties>
|
||||
<property name="minimum" value="40"/>
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="rulesets/codesize.xml/ExcessiveParameterList">
|
||||
<properties>
|
||||
<property name="minimum" value="5"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<!-- include clean code manually -->
|
||||
<rule ref="rulesets/cleancode.xml/BooleanArgumentFlag" />
|
||||
<rule ref="rulesets/cleancode.xml/ElseExpression" />
|
||||
|
||||
<!-- no this one -->
|
||||
<!--<rule ref="rulesets/cleancode.xml/StaticAccess" />-->
|
||||
</ruleset>
|
@@ -59,3 +59,5 @@ fi
|
||||
|
||||
# restore .env file
|
||||
mv $SCRIPT_DIR/../.env.backup $SCRIPT_DIR/../.env
|
||||
|
||||
cd $SCRIPT_DIR/..
|
||||
|
@@ -1,321 +0,0 @@
|
||||
# You can leave this on "local". If you change it to production most console commands will ask for extra confirmation.
|
||||
# Never set it to "testing".
|
||||
APP_ENV=heroku
|
||||
|
||||
# Set to true if you want to see debug information in error screens.
|
||||
APP_DEBUG=false
|
||||
|
||||
# This should be your email address.
|
||||
# If you use Docker or similar, you can set this variable from a file by using SITE_OWNER_FILE
|
||||
SITE_OWNER=heroku@example.com
|
||||
|
||||
# The encryption key for your sessions. Keep this very secure.
|
||||
# If you generate a new one all existing attachments must be considered LOST.
|
||||
# Change it to a string of exactly 32 chars or use something like `php artisan key:generate` to generate it.
|
||||
# If you use Docker or similar, you can set this variable from a file by using APP_KEY_FILE
|
||||
APP_KEY=7ahyYVPVsmxjdhsweWCauGeJfwc92NP2
|
||||
|
||||
#
|
||||
# Firefly III will launch using this language (for new users and unauthenticated visitors)
|
||||
# For a list of available languages: https://github.com/firefly-iii/firefly-iii/tree/main/resources/lang
|
||||
#
|
||||
# If text is still in English, remember that not everything may have been translated.
|
||||
DEFAULT_LANGUAGE=en_US
|
||||
|
||||
# The locale defines how numbers are formatted.
|
||||
# by default this value is the same as whatever the language is.
|
||||
DEFAULT_LOCALE=equal
|
||||
|
||||
# Change this value to your preferred time zone.
|
||||
# Example: Europe/Amsterdam
|
||||
# For a list of supported time zones, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
TZ=UTC
|
||||
|
||||
# TRUSTED_PROXIES is a useful variable when using Docker and/or a reverse proxy.
|
||||
# Set it to ** and reverse proxies work just fine.
|
||||
TRUSTED_PROXIES=**
|
||||
|
||||
# The log channel defines where your log entries go to.
|
||||
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
|
||||
# Also available are 'syslog', 'errorlog' and 'stdout' which will log to the system itself.
|
||||
# A rotating log option is 'daily', creates 5 files that (surprise) rotate.
|
||||
# Default setting 'stack' will log to 'daily' and to 'stdout' at the same time.
|
||||
|
||||
# - Docker + versions <= 4.8.1.8 and before: use "stdout"
|
||||
# - Docker + versions > 4.8.1.8 : use "docker_out"
|
||||
# - Docker + versions >= 5.1.1 : use "stack"
|
||||
# - For everything else (als not Docker) : use 'stack'
|
||||
|
||||
LOG_CHANNEL=stdout
|
||||
|
||||
# Log level. You can set this from least severe to most severe:
|
||||
# debug, info, notice, warning, error, critical, alert, emergency
|
||||
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
|
||||
# nothing will get logged, ever.
|
||||
APP_LOG_LEVEL=notice
|
||||
|
||||
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
|
||||
# For other database types, please see the FAQ: https://docs.firefly-iii.org/support/faq
|
||||
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
|
||||
# Use "pgsql" for PostgreSQL
|
||||
# Use "mysql" for MySQL and MariaDB.
|
||||
# Use "sqlite" for SQLite.
|
||||
DB_CONNECTION=pgsql
|
||||
|
||||
|
||||
# MySQL supports SSL. You can configure it here.
|
||||
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
|
||||
MYSQL_USE_SSL=false
|
||||
MYSQL_SSL_VERIFY_SERVER_CERT=true
|
||||
# You need to set at least of these options
|
||||
MYSQL_SSL_CAPATH=/etc/ssl/certs/
|
||||
MYSQL_SSL_CA=
|
||||
MYSQL_SSL_CERT=
|
||||
MYSQL_SSL_KEY=
|
||||
MYSQL_SSL_CIPHER=
|
||||
|
||||
# PostgreSQL supports SSL. You can configure it here.
|
||||
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
|
||||
PGSQL_SSL_MODE=prefer
|
||||
PGSQL_SSL_ROOT_CERT=null
|
||||
PGSQL_SSL_CERT=null
|
||||
PGSQL_SSL_KEY=null
|
||||
PGSQL_SSL_CRL_FILE=null
|
||||
|
||||
# If you're looking for performance improvements, you could install memcached.
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
# If you set either of these to 'redis', you might want to update these settings too
|
||||
# If you use Docker or similar, you can set REDIS_HOST_FILE, REDIS_PASSWORD_FILE or
|
||||
# REDIS_PORT_FILE to set the value from a file instead of from an environment variable
|
||||
|
||||
# can be tcp, unix or http
|
||||
REDIS_SCHEME=tcp
|
||||
|
||||
# use only when using 'unix' for REDIS_SCHEME. Leave empty otherwise.
|
||||
REDIS_PATH=
|
||||
|
||||
# use only when using 'tcp' or 'http' for REDIS_SCHEME. Leave empty otherwise.
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PORT=6379
|
||||
|
||||
REDIS_PASSWORD=null
|
||||
# always use quotes and make sure redis db "0" and "1" exists. Otherwise change accordingly.
|
||||
REDIS_DB="0"
|
||||
REDIS_CACHE_DB="1"
|
||||
|
||||
# Cookie settings. Should not be necessary to change these.
|
||||
# If you use Docker or similar, you can set COOKIE_DOMAIN_FILE to set
|
||||
# the value from a file instead of from an environment variable
|
||||
COOKIE_PATH="/"
|
||||
COOKIE_DOMAIN=
|
||||
COOKIE_SECURE=false
|
||||
|
||||
# If you want Firefly III to mail you, update these settings
|
||||
# For instructions, see: https://docs.firefly-iii.org/advanced-installation/email
|
||||
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
|
||||
MAIL_MAILER=log
|
||||
MAIL_HOST=null
|
||||
MAIL_PORT=2525
|
||||
MAIL_FROM=changeme@example.com
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
|
||||
# Other mail drivers:
|
||||
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
|
||||
MAILGUN_DOMAIN=
|
||||
MAILGUN_SECRET=
|
||||
|
||||
|
||||
# If you are on EU region in mailgun, use api.eu.mailgun.net, otherwise use api.mailgun.net
|
||||
# If you use Docker or similar, you can set this variable from a file by appending it with _FILE
|
||||
MAILGUN_ENDPOINT=api.mailgun.net
|
||||
|
||||
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
|
||||
MANDRILL_SECRET=
|
||||
SPARKPOST_SECRET=
|
||||
|
||||
|
||||
# Firefly III can send you the following messages
|
||||
SEND_REGISTRATION_MAIL=true
|
||||
SEND_ERROR_MESSAGE=true
|
||||
|
||||
# These messages contain (sensitive) transaction information:
|
||||
SEND_REPORT_JOURNALS=true
|
||||
|
||||
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
|
||||
# If you use Docker or similar, you can set this variable from a file by appending it with _FILE
|
||||
MAPBOX_API_KEY=
|
||||
|
||||
# The map will default to this location:
|
||||
MAP_DEFAULT_LAT=51.983333
|
||||
MAP_DEFAULT_LONG=5.916667
|
||||
MAP_DEFAULT_ZOOM=6
|
||||
|
||||
# Firefly III currently supports two provider for live Currency Exchange Rates:
|
||||
# "fixer", and "ratesapi".
|
||||
# RatesApi.IO (see https://ratesapi.io) is a FREE and OPEN SOURCE live currency exchange rates,
|
||||
# built compatible with Fixer.IO, based on data published by European Central Bank, and doesn't require API key.
|
||||
CER_PROVIDER=ratesapi
|
||||
|
||||
# If you have select "fixer" as default currency exchange rates,
|
||||
# set a Fixer IO API key here (see https://fixer.io) to enable live currency exchange rates.
|
||||
# Please note that this WILL ONLY WORK FOR PAID fixer.io accounts because they severely limited
|
||||
# the free API up to the point where you might as well offer nothing.
|
||||
# If you use Docker or similar, you can set this variable from a file by appending it with _FILE
|
||||
FIXER_API_KEY=
|
||||
|
||||
# Firefly III has two options for user authentication. "eloquent" is the default,
|
||||
# and "ldap" for LDAP servers.
|
||||
# For full instructions on these settings please visit:
|
||||
# https://docs.firefly-iii.org/advanced-installation/authentication
|
||||
# If you use Docker or similar, you can set this variable from a file by appending it with _FILE
|
||||
LOGIN_PROVIDER=eloquent
|
||||
|
||||
#
|
||||
# It's also possible to change the way users are authenticated. You could use Authelia for example.
|
||||
# Authentication via the REMOTE_USER header is supported. Change the value below to "remote_user_guard".
|
||||
#
|
||||
# If you do this please read the documentation for instructions and warnings:
|
||||
# https://docs.firefly-iii.org/advanced-installation/authentication
|
||||
#
|
||||
# This function is available in Firefly III v5.3.0 and higher.
|
||||
AUTHENTICATION_GUARD=web
|
||||
|
||||
#
|
||||
# Likewise, it's impossible to log out users who's authentication is handled by an external system.
|
||||
# Enter a custom URL here that will force a logout (your authentication provider can tell you).
|
||||
# Setting this variable only works when AUTHENTICATION_GUARD != web
|
||||
#
|
||||
CUSTOM_LOGOUT_URL=
|
||||
|
||||
# LDAP connection configuration
|
||||
# OpenLDAP, FreeIPA or ActiveDirectory
|
||||
# # If you use Docker or similar, you can set this variable from a file by appending it with _FILE
|
||||
ADLDAP_CONNECTION_SCHEME=OpenLDAP
|
||||
ADLDAP_AUTO_CONNECT=true
|
||||
|
||||
# LDAP connection settings
|
||||
# You can set the following variables from a file by appending them with _FILE:
|
||||
# ADLDAP_CONTROLLERS, ADLDAP_PORT, ADLDAP_BASEDN
|
||||
ADLDAP_CONTROLLERS=
|
||||
ADLDAP_PORT=389
|
||||
ADLDAP_TIMEOUT=5
|
||||
ADLDAP_BASEDN=""
|
||||
ADLDAP_FOLLOW_REFFERALS=false
|
||||
|
||||
# SSL/TLS settings
|
||||
ADLDAP_USE_SSL=false
|
||||
ADLDAP_USE_TLS=false
|
||||
ADLDAP_SSL_CACERTDIR=
|
||||
ADLDAP_SSL_CACERTFILE=
|
||||
ADLDAP_SSL_CERTFILE=
|
||||
ADLDAP_SSL_KEYFILE=
|
||||
ADLDAP_SSL_CIPHER_SUITE=
|
||||
ADLDAP_SSL_REQUIRE_CERT=
|
||||
|
||||
# You can set the following variables from a file by appending them with _FILE:
|
||||
ADLDAP_ADMIN_USERNAME=
|
||||
ADLDAP_ADMIN_PASSWORD=
|
||||
|
||||
# You can set the following variables from a file by appending them with _FILE:
|
||||
ADLDAP_ACCOUNT_PREFIX=
|
||||
ADLDAP_ACCOUNT_SUFFIX=
|
||||
|
||||
|
||||
# LDAP authentication settings.
|
||||
ADLDAP_PASSWORD_SYNC=false
|
||||
ADLDAP_LOGIN_FALLBACK=false
|
||||
|
||||
ADLDAP_DISCOVER_FIELD=distinguishedname
|
||||
ADLDAP_AUTH_FIELD=distinguishedname
|
||||
|
||||
# Will allow SSO if your server provides an AUTH_USER field.
|
||||
# You can set the following variables from a file by appending them with _FILE:
|
||||
WINDOWS_SSO_ENABLED=false
|
||||
WINDOWS_SSO_DISCOVER=samaccountname
|
||||
WINDOWS_SSO_KEY=AUTH_USER
|
||||
|
||||
# field to sync as local username.
|
||||
# You can set the following variable from a file by appending it with _FILE:
|
||||
ADLDAP_SYNC_FIELD=userprincipalname
|
||||
|
||||
# You can disable the X-Frame-Options header if it interferes with tools like
|
||||
# Organizr. This is at your own risk. Applications running in frames run the risk
|
||||
# of leaking information to their parent frame.
|
||||
DISABLE_FRAME_HEADER=false
|
||||
|
||||
# You can disable the Content Security Policy header when you're using an ancient browser
|
||||
# or any version of Microsoft Edge / Internet Explorer (which amounts to the same thing really)
|
||||
# This leaves you with the risk of not being able to stop XSS bugs should they ever surface.
|
||||
# This is at your own risk.
|
||||
DISABLE_CSP_HEADER=false
|
||||
|
||||
# If you wish to track your own behavior over Firefly III, set valid analytics tracker information here.
|
||||
# Nobody uses this except for me on the demo site. But hey, feel free to use this if you want to.
|
||||
# Do not prepend the TRACKER_URL with http:// or https://
|
||||
# The only tracker supported is Matomo.
|
||||
# You can set the following variables from a file by appending them with _FILE:
|
||||
TRACKER_SITE_ID=
|
||||
TRACKER_URL=
|
||||
|
||||
# You can fine tune the start-up of a Docker container by editing these environment variables.
|
||||
# Use this at your own risk. Disabling certain checks and features may result in lost of inconsistent data.
|
||||
# However if you know what you're doing you can significantly speed up container start times.
|
||||
# Set each value to true to enable, or false to disable.
|
||||
|
||||
# Check if the SQLite database exists. Can be skipped if you're not using SQLite.
|
||||
# Won't significantly speed up things.
|
||||
DKR_CHECK_SQLITE=true
|
||||
|
||||
# Run database creation and migration commands. Disable this only if you're 100% sure the DB exists
|
||||
# and is up to date.
|
||||
DKR_RUN_MIGRATION=true
|
||||
|
||||
# Run database upgrade commands. Disable this only when you're 100% sure your DB is up-to-date
|
||||
# with the latest fixes (outside of migrations!)
|
||||
DKR_RUN_UPGRADE=true
|
||||
|
||||
# Verify database integrity. Includes all data checks and verifications.
|
||||
# Disabling this makes Firefly III assume your DB is intact.
|
||||
DKR_RUN_VERIFY=true
|
||||
|
||||
# Run database reporting commands. When disabled, Firefly III won't go over your data to report current state.
|
||||
# Disabling this should have no impact on data integrity or safety but it won't warn you of possible issues.
|
||||
DKR_RUN_REPORT=true
|
||||
|
||||
# Generate OAuth2 keys.
|
||||
# When disabled, Firefly III won't attempt to generate OAuth2 Passport keys. This won't be an issue, IFF (if and only if)
|
||||
# you had previously generated keys already and they're stored in your database for restoration.
|
||||
DKR_RUN_PASSPORT_INSTALL=true
|
||||
|
||||
# Leave the following configuration vars as is.
|
||||
# Unless you like to tinker and know what you're doing.
|
||||
APP_NAME=FireflyIII
|
||||
ADLDAP_CONNECTION=default
|
||||
BROADCAST_DRIVER=log
|
||||
QUEUE_DRIVER=sync
|
||||
CACHE_PREFIX=firefly
|
||||
SEARCH_RESULT_LIMIT=50
|
||||
PUSHER_KEY=
|
||||
PUSHER_SECRET=
|
||||
PUSHER_ID=
|
||||
DEMO_USERNAME=
|
||||
DEMO_PASSWORD=
|
||||
USE_ENCRYPTION=false
|
||||
IS_HEROKU=false
|
||||
FIREFLY_III_LAYOUT=v1
|
||||
|
||||
#
|
||||
# If you have trouble configuring your Firefly III installation, DON'T BOTHER setting this variable.
|
||||
# It won't work. It doesn't do ANYTHING. Don't believe the lies you read online. I'm not joking.
|
||||
# This configuration value WILL NOT HELP.
|
||||
#
|
||||
# This variable is ONLY used in some of the emails Firefly III sends around. Nowhere else.
|
||||
# So when configuring anything WEB related this variable doesn't do anything. Nothing
|
||||
#
|
||||
# If you're stuck I understand you get desperate but look SOMEWHERE ELSE.
|
||||
#
|
||||
APP_URL=http://localhost
|
@@ -1,31 +0,0 @@
|
||||
bg_BG
|
||||
ca_ES
|
||||
cs_CZ
|
||||
da_DK
|
||||
de_DE
|
||||
el_GR
|
||||
en_GB
|
||||
en_US
|
||||
es_ES
|
||||
fi_FI
|
||||
fr_FR
|
||||
hu_HU
|
||||
id_ID
|
||||
it_IT
|
||||
ja_JP
|
||||
ko_KR
|
||||
nb_NO
|
||||
nl_NL
|
||||
pl_PL
|
||||
pt_BR
|
||||
pt_PT
|
||||
ro_RO
|
||||
ru_RU
|
||||
sk_SK
|
||||
sl_SI
|
||||
sv_SE
|
||||
tr_TR
|
||||
uk_UA
|
||||
vi_VN
|
||||
zh-hans_CN
|
||||
zh-hant_CN
|
18
.editorconfig
Normal file
18
.editorconfig
Normal file
@@ -0,0 +1,18 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[docker-compose.yml]
|
||||
indent_size = 4
|
36
.env.example
36
.env.example
@@ -45,12 +45,6 @@ TRUSTED_PROXIES=
|
||||
# Default setting 'stack' will log to 'daily' and to 'stdout' at the same time.
|
||||
LOG_CHANNEL=stack
|
||||
|
||||
#
|
||||
# Used when logging to papertrail:
|
||||
#
|
||||
PAPERTRAIL_HOST=
|
||||
PAPERTRAIL_PORT=
|
||||
|
||||
# Log level. You can set this from least severe to most severe:
|
||||
# debug, info, notice, warning, error, critical, alert, emergency
|
||||
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
|
||||
@@ -58,8 +52,30 @@ PAPERTRAIL_PORT=
|
||||
APP_LOG_LEVEL=notice
|
||||
|
||||
# Audit log level.
|
||||
# Set this to "emergency" if you dont want to store audit logs, leave on info otherwise.
|
||||
AUDIT_LOG_LEVEL=info
|
||||
# The audit log is used to log notable Firefly III events on a separate channel.
|
||||
# These log entries may contain sensitive financial information.
|
||||
# The audit log is disabled by default.
|
||||
#
|
||||
# To enable it, set AUDIT_LOG_LEVEL to "info"
|
||||
# To disable it, set AUDIT_LOG_LEVEL to "emergency"
|
||||
AUDIT_LOG_LEVEL=emergency
|
||||
|
||||
#
|
||||
# If you want, you can redirect the audit logs to another channel.
|
||||
# Set 'audit_stdout', 'audit_syslog', 'audit_errorlog' to log to the system itself.
|
||||
# Use audit_daily to log to a rotating file.
|
||||
# Use audit_papertrail to log to papertrail.
|
||||
#
|
||||
# If you do this, the audit logs may be mixed with normal logs because the settings for these channels
|
||||
# are often the same as the settings for the normal logs.
|
||||
AUDIT_LOG_CHANNEL=
|
||||
|
||||
#
|
||||
# Used when logging to papertrail:
|
||||
# Also used when audit logs log to papertrail:
|
||||
#
|
||||
PAPERTRAIL_HOST=
|
||||
PAPERTRAIL_PORT=
|
||||
|
||||
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
|
||||
# For other database types, please see the FAQ: https://docs.firefly-iii.org/firefly-iii/faq/self-hosted/#i-want-to-use-sqlite
|
||||
@@ -143,6 +159,7 @@ MAIL_FROM=changeme@example.com
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_SENDMAIL_COMMAND=
|
||||
|
||||
# Other mail drivers:
|
||||
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
|
||||
@@ -240,7 +257,7 @@ ALLOW_WEBHOOKS=false
|
||||
#
|
||||
# The static cron job token can be useful when you use Docker and wish to manage cron jobs.
|
||||
# 1. Set this token to any 32-character value (this is important!).
|
||||
# 2. Use this token in the cron URL instead of a user's command line token.
|
||||
# 2. Use this token in the cron URL instead of a user's command line token that you can find in /profile
|
||||
#
|
||||
# For more info: https://docs.firefly-iii.org/firefly-iii/advanced-installation/cron/
|
||||
#
|
||||
@@ -297,7 +314,6 @@ PUSHER_SECRET=
|
||||
PUSHER_ID=
|
||||
DEMO_USERNAME=
|
||||
DEMO_PASSWORD=
|
||||
IS_HEROKU=false
|
||||
FIREFLY_III_LAYOUT=v1
|
||||
|
||||
#
|
||||
|
17
.gitattributes
vendored
17
.gitattributes
vendored
@@ -1,8 +1,11 @@
|
||||
* text=auto
|
||||
*.css linguist-vendored
|
||||
*.scss linguist-vendored
|
||||
*.js linguist-vendored
|
||||
* text=auto eol=lf
|
||||
|
||||
*.blade.php diff=html
|
||||
*.css diff=css
|
||||
*.html diff=html
|
||||
*.md diff=markdown
|
||||
*.php diff=php
|
||||
|
||||
/.github export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
/tests export-ignore
|
||||
/phpunit.xml export-ignore
|
||||
/.ci export-ignore
|
||||
.styleci.yml export-ignore
|
||||
|
29
.github/code_of_conduct.md
vendored
29
.github/code_of_conduct.md
vendored
@@ -2,7 +2,10 @@
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making
|
||||
participation in our project and our community a harassment-free experience for everyone, regardless of age, body size,
|
||||
disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race,
|
||||
religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
@@ -24,23 +27,35 @@ Examples of unacceptable behavior by participants include:
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take
|
||||
appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits,
|
||||
issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any
|
||||
contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the
|
||||
project or its community. Examples of representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed representative at an online or offline
|
||||
event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at james@firefly-iii.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at
|
||||
james@firefly-iii.org. The project team will review and investigate all complaints, and will respond in a way that it
|
||||
deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the
|
||||
reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent
|
||||
repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available
|
||||
at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
|
10
.github/its_you_not_me.md
vendored
10
.github/its_you_not_me.md
vendored
@@ -2,9 +2,11 @@
|
||||
|
||||
Sometimes bugs reported to Firefly III are configuration and system problems on the user's side.
|
||||
|
||||
If you run into any of the following problems, there's a good chance it's not a Firefly III issue, but a configuration issue.
|
||||
If you run into any of the following problems, there's a good chance it's not a Firefly III issue, but a configuration
|
||||
issue.
|
||||
|
||||
- ⚠️ Firefly III can't connect to the database when starting or the password is wrong, even though you're sure it's correct.
|
||||
- ⚠️ Firefly III can't connect to the database when starting or the password is wrong, even though you're sure it's
|
||||
correct.
|
||||
- ⚠️ Errors about a missing `APP_KEY` or other encryption/hash problems
|
||||
- ⚠️ You can't login due to `419` errors (page expired)
|
||||
- ⚠️ Any `500` error when starting Firefly III
|
||||
@@ -13,4 +15,6 @@ If you run into any of the following problems, there's a good chance it's not a
|
||||
- ⚠️ Firefly III does not work behind your reverse proxy
|
||||
- ⚠️ You can't connect to the Data Importer due to 404's or authentication issues.
|
||||
|
||||
If you run into an issue like this, please start a [discussion](https://github.com/firefly-iii/firefly-iii/discussions) or chat on [Gitter.im](https://gitter.im/firefly-iii/firefly-iii). There's a good chance it's not a bug but something we can fix rather quickly :+1:
|
||||
If you run into an issue like this, please start a [discussion](https://github.com/firefly-iii/firefly-iii/discussions)
|
||||
or chat on [Gitter.im](https://gitter.im/firefly-iii/firefly-iii). There's a good chance it's not a bug but something we
|
||||
can fix rather quickly :+1:
|
||||
|
6
.github/support.md
vendored
6
.github/support.md
vendored
@@ -9,7 +9,8 @@ First of all: thank you for reporting a bug instead of ditching the tool altoget
|
||||
1. Open bugs will have open issues, so search for one first.
|
||||
2. If your feature request is already there, vote on it with :+1: or :-1: reactions.
|
||||
3. Do NOT hijack old issues with the bug you found, open your own issue.
|
||||
4. If relevant, take the time and see if the [demo site](https://demo.firefly-iii.org/) is also suffering from your issue.
|
||||
4. If relevant, take the time and see if the [demo site](https://demo.firefly-iii.org/) is also suffering from your
|
||||
issue.
|
||||
5. If relevant, read the [documentation](https://docs.firefly-iii.org/).
|
||||
|
||||
Please follow these guidelines when opening new issues:
|
||||
@@ -25,7 +26,8 @@ Only then [create a new issue](https://github.com/firefly-iii/firefly-iii/issues
|
||||
## Issue closure and abandonment policy
|
||||
|
||||
- Issues can be converted into discussions if it's not a bug or feature request.
|
||||
- Features that won't be implemented will be labelled "wontfix". [This isn't personal](https://docs.firefly-iii.org/firefly-iii/about-firefly-iii/what-its-not/).
|
||||
- Features that won't be implemented will be labelled "
|
||||
wontfix". [This isn't personal](https://docs.firefly-iii.org/firefly-iii/about-firefly-iii/what-its-not/).
|
||||
- Issues can be closed if they're duplicates of other issues.
|
||||
- Issues can be closed if the answer is in the FAQ.
|
||||
- Issues will be closed automatically after 14 days.
|
||||
|
11
.github/workflows/closed-issues.yml
vendored
11
.github/workflows/closed-issues.yml
vendored
@@ -7,17 +7,18 @@ jobs:
|
||||
auto_comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
uses: aws-actions/closed-issue-message@v1
|
||||
- uses: aws-actions/closed-issue-message@v1
|
||||
with:
|
||||
message: |
|
||||
Hi there! This is an automatic reply. `Share and enjoy`
|
||||
|
||||
This issue is now 🔒 closed. Please be aware that closed issues are **not** watched.
|
||||
This issue is now 🔒 closed. Please be aware that closed issues are not monitored by the developer of Firefly III.
|
||||
|
||||
- If the original bug is not actually fixed, please feel free to open [a new issue](https://github.com/firefly-iii/firefly-iii/issues/new/choose). Please refer to this issue for clarity.
|
||||
- If the original bug is not actually fixed, please open [a new issue](https://github.com/firefly-iii/firefly-iii/issues/new/choose). Refer to this issue for clarity.
|
||||
- Follow-up questions must be posted in a new [discussion](https://github.com/firefly-iii/firefly-iii/discussions/)
|
||||
- Further replies to this issue will get **no response**.
|
||||
- Further replies to this issue may get no response.
|
||||
|
||||
If there is more to discuss, please open [a new issue](https://github.com/firefly-iii/firefly-iii/issues/new/choose) or [discussion](https://github.com/firefly-iii/firefly-iii/discussions/).
|
||||
|
||||
Thank you for your contributions.
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
28
.github/workflows/sonarcloud.yml
vendored
28
.github/workflows/sonarcloud.yml
vendored
@@ -1,5 +1,6 @@
|
||||
name: Sonarcloud
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
@@ -12,6 +13,33 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup PHP with Xdebug
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.2'
|
||||
coverage: xdebug
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --prefer-dist --no-interaction --no-progress --no-scripts
|
||||
|
||||
- name: Copy environment file
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Generate app key
|
||||
run: php artisan key:generate
|
||||
|
||||
- name: "Run tests with coverage"
|
||||
run: composer coverage
|
||||
|
||||
- name: Fix code coverage paths
|
||||
run: sed -i 's@'$GITHUB_WORKSPACE'@/github/workspace/@g' coverage.xml
|
||||
|
||||
- name: SonarCloud Scan
|
||||
uses: SonarSource/sonarcloud-github-action@master
|
||||
env:
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,4 +7,4 @@ npm-debug.log
|
||||
yarn-error.log
|
||||
.env
|
||||
/.ci/php-cs-fixer/vendor
|
||||
/.ci/coverage
|
||||
coverage.xml
|
||||
|
@@ -8,7 +8,5 @@
|
||||
# To hide directory listing
|
||||
Options All -Indexes
|
||||
|
||||
# To prevent access to .env and other files
|
||||
<Files .*>
|
||||
# To prevent access any file
|
||||
Deny from all
|
||||
</Files>
|
||||
|
65
app.json
65
app.json
@@ -1,65 +0,0 @@
|
||||
{
|
||||
"name": "Firefly III",
|
||||
"description": "A free and open source personal finances manager",
|
||||
"repository": "https://github.com/firefly-iii/firefly-iii",
|
||||
"website": "https://firefly-iii.org/",
|
||||
"logo": "https://raw.githubusercontent.com/firefly-iii/firefly-iii/main/public/mstile-150x150.png",
|
||||
"keywords": [
|
||||
"finance",
|
||||
"finances",
|
||||
"manager",
|
||||
"management",
|
||||
"euro",
|
||||
"dollar",
|
||||
"laravel",
|
||||
"money",
|
||||
"currency",
|
||||
"financials",
|
||||
"financial",
|
||||
"budgets",
|
||||
"administration",
|
||||
"tool",
|
||||
"tooling",
|
||||
"help",
|
||||
"helper",
|
||||
"assistant",
|
||||
"planning",
|
||||
"organizing",
|
||||
"bills",
|
||||
"personal finance",
|
||||
"budgets",
|
||||
"budgeting",
|
||||
"budgeting tool",
|
||||
"budgeting application",
|
||||
"transactions",
|
||||
"self hosted",
|
||||
"self-hosted",
|
||||
"transfers",
|
||||
"management"
|
||||
],
|
||||
"addons": [
|
||||
{
|
||||
"plan": "heroku-postgresql",
|
||||
"options": {
|
||||
"version": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
"scripts": {
|
||||
"postdeploy": "php artisan migrate:refresh --seed;php artisan firefly:instructions install"
|
||||
},
|
||||
"buildpacks": [
|
||||
{
|
||||
"url": "heroku/php"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/heroku/heroku-buildpack-locale"
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"APP_KEY": {
|
||||
"description": "This key is used to create app cookies en secure attachments.",
|
||||
"value": "base64:If1gJN4pyycXTq+WS5TjneDympKuu+8SKvTl6RZnhJg="
|
||||
}
|
||||
}
|
||||
}
|
@@ -105,7 +105,7 @@ class AccountController extends Controller
|
||||
'name' => $account->name,
|
||||
'name_with_balance' => $nameWithBalance,
|
||||
'type' => $account->accountType->type,
|
||||
'currency_id' => $currency->id,
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_name' => $currency->name,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
|
@@ -74,6 +74,111 @@ abstract class Controller extends BaseController
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to grab all parameters from the URL.
|
||||
*
|
||||
* @return ParameterBag
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
private function getParameters(): ParameterBag
|
||||
{
|
||||
$bag = new ParameterBag();
|
||||
$page = (int)request()->get('page');
|
||||
if ($page < 1) {
|
||||
$page = 1;
|
||||
}
|
||||
if ($page > pow(2, 16)) {
|
||||
$page = pow(2, 16);
|
||||
}
|
||||
$bag->set('page', $page);
|
||||
|
||||
// some date fields:
|
||||
$dates = ['start', 'end', 'date'];
|
||||
foreach ($dates as $field) {
|
||||
$date = null;
|
||||
try {
|
||||
$date = request()->query->get($field);
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field));
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$value = null;
|
||||
}
|
||||
$obj = null;
|
||||
if (null !== $date) {
|
||||
try {
|
||||
$obj = Carbon::parse($date);
|
||||
} catch (InvalidDateException | InvalidFormatException $e) {
|
||||
// don't care
|
||||
app('log')->warning(
|
||||
sprintf(
|
||||
'Ignored invalid date "%s" in API controller parameter check: %s',
|
||||
substr($date, 0, 20),
|
||||
$e->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
$bag->set($field, $obj);
|
||||
}
|
||||
|
||||
// integer fields:
|
||||
$integers = ['limit'];
|
||||
foreach ($integers as $integer) {
|
||||
try {
|
||||
$value = request()->query->get($integer);
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $integer));
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$value = null;
|
||||
}
|
||||
if (null !== $value) {
|
||||
$bag->set($integer, (int)$value);
|
||||
}
|
||||
}
|
||||
|
||||
// sort fields:
|
||||
return $this->getSortParameters($bag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ParameterBag $bag
|
||||
*
|
||||
* @return ParameterBag
|
||||
*/
|
||||
private function getSortParameters(ParameterBag $bag): ParameterBag
|
||||
{
|
||||
$sortParameters = [];
|
||||
try {
|
||||
$param = (string)request()->query->get('sort');
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error('Request field "sort" contains a non-scalar value. Value set to NULL.');
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$param = '';
|
||||
}
|
||||
if ('' === $param) {
|
||||
return $bag;
|
||||
}
|
||||
$parts = explode(',', $param);
|
||||
foreach ($parts as $part) {
|
||||
$part = trim($part);
|
||||
$direction = 'asc';
|
||||
if ('-' === $part[0]) {
|
||||
$part = substr($part, 1);
|
||||
$direction = 'desc';
|
||||
}
|
||||
if (in_array($part, $this->allowedSort, true)) {
|
||||
$sortParameters[] = [$part, $direction];
|
||||
}
|
||||
}
|
||||
$bag->set('sort', $sortParameters);
|
||||
|
||||
return $bag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to help build URL's.
|
||||
*
|
||||
@@ -109,106 +214,4 @@ abstract class Controller extends BaseController
|
||||
|
||||
return $manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to grab all parameters from the URL.
|
||||
*
|
||||
* @return ParameterBag
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
private function getParameters(): ParameterBag
|
||||
{
|
||||
$bag = new ParameterBag();
|
||||
$page = (int)request()->get('page');
|
||||
if ($page < 1) {
|
||||
$page = 1;
|
||||
}
|
||||
if ($page > pow(2, 16)) {
|
||||
$page = pow(2, 16);
|
||||
}
|
||||
$bag->set('page', $page);
|
||||
|
||||
// some date fields:
|
||||
$dates = ['start', 'end', 'date'];
|
||||
foreach ($dates as $field) {
|
||||
$date = null;
|
||||
try {
|
||||
$date = request()->query->get($field);
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field));
|
||||
Log::error($e->getMessage());
|
||||
$value = null;
|
||||
}
|
||||
$obj = null;
|
||||
if (null !== $date) {
|
||||
try {
|
||||
$obj = Carbon::parse($date);
|
||||
} catch (InvalidDateException|InvalidFormatException $e) {
|
||||
// don't care
|
||||
app('log')->warning(
|
||||
sprintf(
|
||||
'Ignored invalid date "%s" in API controller parameter check: %s',
|
||||
substr($date, 0, 20),
|
||||
$e->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
$bag->set($field, $obj);
|
||||
}
|
||||
|
||||
// integer fields:
|
||||
$integers = ['limit'];
|
||||
foreach ($integers as $integer) {
|
||||
try {
|
||||
$value = request()->query->get($integer);
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $integer));
|
||||
Log::error($e->getMessage());
|
||||
$value = null;
|
||||
}
|
||||
if (null !== $value) {
|
||||
$bag->set($integer, (int)$value);
|
||||
}
|
||||
}
|
||||
|
||||
// sort fields:
|
||||
return $this->getSortParameters($bag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ParameterBag $bag
|
||||
*
|
||||
* @return ParameterBag
|
||||
*/
|
||||
private function getSortParameters(ParameterBag $bag): ParameterBag
|
||||
{
|
||||
$sortParameters = [];
|
||||
try {
|
||||
$param = (string)request()->query->get('sort');
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error('Request field "sort" contains a non-scalar value. Value set to NULL.');
|
||||
Log::error($e->getMessage());
|
||||
$param = '';
|
||||
}
|
||||
if ('' === $param) {
|
||||
return $bag;
|
||||
}
|
||||
$parts = explode(',', $param);
|
||||
foreach ($parts as $part) {
|
||||
$part = trim($part);
|
||||
$direction = 'asc';
|
||||
if ('-' === $part[0]) {
|
||||
$part = substr($part, 1);
|
||||
$direction = 'desc';
|
||||
}
|
||||
if (in_array($part, $this->allowedSort, true)) {
|
||||
$sortParameters[] = [$part, $direction];
|
||||
}
|
||||
}
|
||||
$bag->set('sort', $sortParameters);
|
||||
|
||||
return $bag;
|
||||
}
|
||||
}
|
||||
|
@@ -201,6 +201,94 @@ class DestroyController extends Controller
|
||||
return response()->json([], 204);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyBudgets(): void
|
||||
{
|
||||
/** @var AvailableBudgetRepositoryInterface $abRepository */
|
||||
$abRepository = app(AvailableBudgetRepositoryInterface::class);
|
||||
$abRepository->destroyAll();
|
||||
|
||||
/** @var BudgetLimitRepositoryInterface $blRepository */
|
||||
$blRepository = app(BudgetLimitRepositoryInterface::class);
|
||||
$blRepository->destroyAll();
|
||||
|
||||
/** @var BudgetRepositoryInterface $budgetRepository */
|
||||
$budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$budgetRepository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyBills(): void
|
||||
{
|
||||
/** @var BillRepositoryInterface $repository */
|
||||
$repository = app(BillRepositoryInterface::class);
|
||||
$repository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyPiggyBanks(): void
|
||||
{
|
||||
/** @var PiggyBankRepositoryInterface $repository */
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyRules(): void
|
||||
{
|
||||
/** @var RuleGroupRepositoryInterface $repository */
|
||||
$repository = app(RuleGroupRepositoryInterface::class);
|
||||
$repository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyRecurringTransactions(): void
|
||||
{
|
||||
/** @var RecurringRepositoryInterface $repository */
|
||||
$repository = app(RecurringRepositoryInterface::class);
|
||||
$repository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyCategories(): void
|
||||
{
|
||||
/** @var CategoryRepositoryInterface $categoryRepos */
|
||||
$categoryRepos = app(CategoryRepositoryInterface::class);
|
||||
$categoryRepos->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyTags(): void
|
||||
{
|
||||
/** @var TagRepositoryInterface $tagRepository */
|
||||
$tagRepository = app(TagRepositoryInterface::class);
|
||||
$tagRepository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function destroyObjectGroups(): void
|
||||
{
|
||||
/** @var ObjectGroupRepositoryInterface $repository */
|
||||
$repository = app(ObjectGroupRepositoryInterface::class);
|
||||
$repository->deleteAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*/
|
||||
@@ -226,91 +314,6 @@ class DestroyController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyBills(): void
|
||||
{
|
||||
/** @var BillRepositoryInterface $repository */
|
||||
$repository = app(BillRepositoryInterface::class);
|
||||
$repository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyBudgets(): void
|
||||
{
|
||||
/** @var AvailableBudgetRepositoryInterface $abRepository */
|
||||
$abRepository = app(AvailableBudgetRepositoryInterface::class);
|
||||
$abRepository->destroyAll();
|
||||
|
||||
/** @var BudgetLimitRepositoryInterface $blRepository */
|
||||
$blRepository = app(BudgetLimitRepositoryInterface::class);
|
||||
$blRepository->destroyAll();
|
||||
|
||||
/** @var BudgetRepositoryInterface $budgetRepository */
|
||||
$budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$budgetRepository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyCategories(): void
|
||||
{
|
||||
/** @var CategoryRepositoryInterface $categoryRepos */
|
||||
$categoryRepos = app(CategoryRepositoryInterface::class);
|
||||
$categoryRepos->destroyAll();
|
||||
}
|
||||
|
||||
private function destroyObjectGroups(): void
|
||||
{
|
||||
/** @var ObjectGroupRepositoryInterface $repository */
|
||||
$repository = app(ObjectGroupRepositoryInterface::class);
|
||||
$repository->deleteAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyPiggyBanks(): void
|
||||
{
|
||||
/** @var PiggyBankRepositoryInterface $repository */
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyRecurringTransactions(): void
|
||||
{
|
||||
/** @var RecurringRepositoryInterface $repository */
|
||||
$repository = app(RecurringRepositoryInterface::class);
|
||||
$repository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyRules(): void
|
||||
{
|
||||
/** @var RuleGroupRepositoryInterface $repository */
|
||||
$repository = app(RuleGroupRepositoryInterface::class);
|
||||
$repository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function destroyTags(): void
|
||||
{
|
||||
/** @var TagRepositoryInterface $tagRepository */
|
||||
$tagRepository = app(TagRepositoryInterface::class);
|
||||
$tagRepository->destroyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*/
|
||||
|
@@ -29,6 +29,8 @@ use FireflyIII\Api\V1\Requests\Data\Export\ExportRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Support\Export\ExportDataGenerator;
|
||||
use Illuminate\Http\Response as LaravelResponse;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
/**
|
||||
* Class ExportController
|
||||
@@ -69,6 +71,36 @@ class ExportController extends Controller
|
||||
return $this->returnExport('accounts');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return LaravelResponse
|
||||
* @throws FireflyException
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
private function returnExport(string $key): LaravelResponse
|
||||
{
|
||||
$date = date('Y-m-d-H-i-s');
|
||||
$fileName = sprintf('%s-export-%s.csv', $date, $key);
|
||||
$data = $this->exporter->export();
|
||||
|
||||
/** @var LaravelResponse $response */
|
||||
$response = response($data[$key]);
|
||||
$response
|
||||
->header('Content-Description', 'File Transfer')
|
||||
->header('Content-Type', 'application/octet-stream')
|
||||
->header('Content-Disposition', 'attachment; filename=' . $fileName)
|
||||
->header('Content-Transfer-Encoding', 'binary')
|
||||
->header('Connection', 'Keep-Alive')
|
||||
->header('Expires', '0')
|
||||
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
||||
->header('Pragma', 'public')
|
||||
->header('Content-Length', (string)strlen($data[$key]));
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportBills
|
||||
@@ -200,32 +232,4 @@ class ExportController extends Controller
|
||||
|
||||
return $this->returnExport('transactions');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return LaravelResponse
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function returnExport(string $key): LaravelResponse
|
||||
{
|
||||
$date = date('Y-m-d-H-i-s');
|
||||
$fileName = sprintf('%s-export-%s.csv', $date, $key);
|
||||
$data = $this->exporter->export();
|
||||
|
||||
/** @var LaravelResponse $response */
|
||||
$response = response($data[$key]);
|
||||
$response
|
||||
->header('Content-Description', 'File Transfer')
|
||||
->header('Content-Type', 'application/octet-stream')
|
||||
->header('Content-Disposition', 'attachment; filename='.$fileName)
|
||||
->header('Content-Transfer-Encoding', 'binary')
|
||||
->header('Connection', 'Keep-Alive')
|
||||
->header('Expires', '0')
|
||||
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
||||
->header('Pragma', 'public')
|
||||
->header('Content-Length', (string)strlen($data[$key]));
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@@ -37,6 +37,9 @@ use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class PurgeController
|
||||
*/
|
||||
class PurgeController extends Controller
|
||||
{
|
||||
/**
|
||||
|
@@ -96,6 +96,7 @@ class TriggerController extends Controller
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
|
||||
}
|
||||
|
||||
|
||||
// file the rule(s)
|
||||
$transactions = $ruleEngine->find();
|
||||
$count = $transactions->count();
|
||||
@@ -149,6 +150,7 @@ class TriggerController extends Controller
|
||||
$ruleEngine->addOperator(['type' => 'account_id', 'value' => implode(',', $parameters['accounts'])]);
|
||||
}
|
||||
|
||||
|
||||
// fire the rule(s)
|
||||
$ruleEngine->fire();
|
||||
|
||||
|
@@ -80,7 +80,7 @@ class ShowController extends Controller
|
||||
->setPage($this->parameters->get('page'))
|
||||
// set types of transactions to return.
|
||||
->setTypes($types);
|
||||
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
|
||||
if (null !== $this->parameters->get('start') || null !== $this->parameters->get('end')) {
|
||||
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
|
||||
}
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
@@ -97,6 +97,21 @@ class ShowController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/transactions/getTransactionByJournal
|
||||
*
|
||||
* Show a single transaction, by transaction journal.
|
||||
*
|
||||
* @param TransactionJournal $transactionJournal
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function showJournal(TransactionJournal $transactionJournal): JsonResponse
|
||||
{
|
||||
return $this->show($transactionJournal->transactionGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/transactions/getTransaction
|
||||
@@ -133,19 +148,4 @@ class ShowController extends Controller
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/transactions/getTransactionByJournal
|
||||
*
|
||||
* Show a single transaction, by transaction journal.
|
||||
*
|
||||
* @param TransactionJournal $transactionJournal
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function showJournal(TransactionJournal $transactionJournal): JsonResponse
|
||||
{
|
||||
return $this->show($transactionJournal->transactionGroup);
|
||||
}
|
||||
}
|
||||
|
@@ -79,6 +79,7 @@ class UpdateController extends Controller
|
||||
{
|
||||
Log::debug('Now in update routine for transaction group!');
|
||||
$data = $request->getAll();
|
||||
|
||||
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
|
@@ -97,35 +97,6 @@ class UpdateController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/enableCurrency
|
||||
*
|
||||
* Enable a currency.
|
||||
*
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws FireflyException
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function enable(TransactionCurrency $currency): JsonResponse
|
||||
{
|
||||
$this->repository->enable($currency);
|
||||
$manager = $this->getManager();
|
||||
|
||||
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
|
||||
$this->parameters->set('defaultCurrency', $defaultCurrency);
|
||||
|
||||
/** @var CurrencyTransformer $transformer */
|
||||
$transformer = app(CurrencyTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($currency, $transformer, 'currencies');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/defaultCurrency
|
||||
@@ -157,6 +128,35 @@ class UpdateController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/enableCurrency
|
||||
*
|
||||
* Enable a currency.
|
||||
*
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws FireflyException
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function enable(TransactionCurrency $currency): JsonResponse
|
||||
{
|
||||
$this->repository->enable($currency);
|
||||
$manager = $this->getManager();
|
||||
|
||||
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
|
||||
$this->parameters->set('defaultCurrency', $defaultCurrency);
|
||||
|
||||
/** @var CurrencyTransformer $transformer */
|
||||
$transformer = app(CurrencyTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($currency, $transformer, 'currencies');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/updateCurrency
|
||||
|
@@ -30,6 +30,9 @@ use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class DestroyController
|
||||
*/
|
||||
class DestroyController extends Controller
|
||||
{
|
||||
private LinkTypeRepositoryInterface $repository;
|
||||
|
@@ -37,6 +37,9 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
/**
|
||||
* Class ShowController
|
||||
*/
|
||||
class ShowController extends Controller
|
||||
{
|
||||
private LinkTypeRepositoryInterface $repository;
|
||||
|
@@ -35,6 +35,9 @@ use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
/**
|
||||
* Class StoreController
|
||||
*/
|
||||
class StoreController extends Controller
|
||||
{
|
||||
use TransactionFilter;
|
||||
|
@@ -34,6 +34,9 @@ use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
/**
|
||||
* Class UpdateController
|
||||
*/
|
||||
class UpdateController extends Controller
|
||||
{
|
||||
private JournalRepositoryInterface $journalRepository;
|
||||
|
@@ -33,7 +33,6 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use JsonException;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
|
||||
|
@@ -121,30 +121,6 @@ class BasicController extends Controller
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if date is outside session range.
|
||||
*
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function notInDateRange(Carbon $date, Carbon $start, Carbon $end): bool // Validate a preference
|
||||
{
|
||||
$result = false;
|
||||
if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
|
||||
$result = true;
|
||||
}
|
||||
// start and end in the past? use $end
|
||||
if ($start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date)) {
|
||||
$result = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
@@ -214,7 +190,7 @@ class BasicController extends Controller
|
||||
'key' => sprintf('balance-in-%s', $currency->code),
|
||||
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
|
||||
'monetary_value' => $sums[$currencyId] ?? '0',
|
||||
'currency_id' => $currency->id,
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
@@ -227,7 +203,7 @@ class BasicController extends Controller
|
||||
'key' => sprintf('spent-in-%s', $currency->code),
|
||||
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
|
||||
'monetary_value' => $expenses[$currencyId] ?? '0',
|
||||
'currency_id' => $currency->id,
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
@@ -239,7 +215,7 @@ class BasicController extends Controller
|
||||
'key' => sprintf('earned-in-%s', $currency->code),
|
||||
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
|
||||
'monetary_value' => $incomes[$currencyId] ?? '0',
|
||||
'currency_id' => $currency->id,
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
@@ -277,7 +253,7 @@ class BasicController extends Controller
|
||||
'key' => sprintf('bills-paid-in-%s', $info['code']),
|
||||
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]),
|
||||
'monetary_value' => $amount,
|
||||
'currency_id' => $info['id'],
|
||||
'currency_id' => (string)$info['id'],
|
||||
'currency_code' => $info['code'],
|
||||
'currency_symbol' => $info['symbol'],
|
||||
'currency_decimal_places' => $info['decimal_places'],
|
||||
@@ -296,7 +272,7 @@ class BasicController extends Controller
|
||||
'key' => sprintf('bills-unpaid-in-%s', $info['code']),
|
||||
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]),
|
||||
'monetary_value' => $amount,
|
||||
'currency_id' => $info['id'],
|
||||
'currency_id' => (string)$info['id'],
|
||||
'currency_code' => $info['code'],
|
||||
'currency_symbol' => $info['symbol'],
|
||||
'currency_decimal_places' => $info['decimal_places'],
|
||||
@@ -326,7 +302,7 @@ class BasicController extends Controller
|
||||
|
||||
foreach ($spent as $row) {
|
||||
// either an amount was budgeted or 0 is available.
|
||||
$amount = $available[$row['currency_id']] ?? '0';
|
||||
$amount = (string)($available[$row['currency_id']] ?? '0');
|
||||
$spentInCurrency = $row['sum'];
|
||||
$leftToSpend = bcadd($amount, $spentInCurrency);
|
||||
|
||||
@@ -340,23 +316,18 @@ class BasicController extends Controller
|
||||
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
|
||||
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]),
|
||||
'monetary_value' => $leftToSpend,
|
||||
'currency_id' => $row['currency_id'],
|
||||
'currency_id' => (string)$row['currency_id'],
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_symbol' => $row['currency_symbol'],
|
||||
'currency_decimal_places' => $row['currency_decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $leftToSpend, false),
|
||||
'local_icon' => 'money',
|
||||
'sub_title' => (string)trans(
|
||||
'firefly.box_spend_per_day',
|
||||
[
|
||||
'amount' => app('amount')->formatFlat(
|
||||
'sub_title' => app('amount')->formatFlat(
|
||||
$row['currency_symbol'],
|
||||
$row['currency_decimal_places'],
|
||||
$perDay,
|
||||
false
|
||||
),
|
||||
]
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -410,7 +381,7 @@ class BasicController extends Controller
|
||||
'key' => sprintf('net-worth-in-%s', $currency->code),
|
||||
'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $currency->symbol]),
|
||||
'monetary_value' => $amount,
|
||||
'currency_id' => $currency->id,
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
@@ -422,4 +393,28 @@ class BasicController extends Controller
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if date is outside session range.
|
||||
*
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function notInDateRange(Carbon $date, Carbon $start, Carbon $end): bool // Validate a preference
|
||||
{
|
||||
$result = false;
|
||||
if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
|
||||
$result = true;
|
||||
}
|
||||
// start and end in the past? use $end
|
||||
if ($start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date)) {
|
||||
$result = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@@ -94,6 +94,42 @@ class ConfigurationController extends Controller
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all config values.
|
||||
*
|
||||
* @return array
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
private function getDynamicConfiguration(): array
|
||||
{
|
||||
$isDemoSite = app('fireflyconfig')->get('is_demo_site');
|
||||
$updateCheck = app('fireflyconfig')->get('permission_update_check');
|
||||
$lastCheck = app('fireflyconfig')->get('last_update_check');
|
||||
$singleUser = app('fireflyconfig')->get('single_user_mode');
|
||||
|
||||
return [
|
||||
'is_demo_site' => $isDemoSite?->data,
|
||||
'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data,
|
||||
'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data,
|
||||
'single_user_mode' => $singleUser?->data,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getStaticConfiguration(): array
|
||||
{
|
||||
$list = EitherConfigKey::$static;
|
||||
$return = [];
|
||||
foreach ($list as $key) {
|
||||
$return[$key] = config($key);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/configuration/getSingleConfiguration
|
||||
@@ -102,7 +138,6 @@ class ConfigurationController extends Controller
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws FireflyException
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
public function show(string $configKey): JsonResponse
|
||||
@@ -164,40 +199,4 @@ class ConfigurationController extends Controller
|
||||
|
||||
return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all config values.
|
||||
*
|
||||
* @return array
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
private function getDynamicConfiguration(): array
|
||||
{
|
||||
$isDemoSite = app('fireflyconfig')->get('is_demo_site');
|
||||
$updateCheck = app('fireflyconfig')->get('permission_update_check');
|
||||
$lastCheck = app('fireflyconfig')->get('last_update_check');
|
||||
$singleUser = app('fireflyconfig')->get('single_user_mode');
|
||||
|
||||
return [
|
||||
'is_demo_site' => $isDemoSite?->data,
|
||||
'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data,
|
||||
'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data,
|
||||
'single_user_mode' => $singleUser?->data,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getStaticConfiguration(): array
|
||||
{
|
||||
$list = EitherConfigKey::$static;
|
||||
$return = [];
|
||||
foreach ($list as $key) {
|
||||
$return[$key] = config($key);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
@@ -28,6 +28,8 @@ use FireflyIII\Api\V1\Requests\System\CronRequest;
|
||||
use FireflyIII\Support\Http\Controllers\CronRunner;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
/**
|
||||
* Class CronController
|
||||
@@ -44,6 +46,8 @@ class CronController extends Controller
|
||||
* @param string $token
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
public function cron(CronRequest $request, string $token): JsonResponse
|
||||
{
|
||||
@@ -54,7 +58,7 @@ class CronController extends Controller
|
||||
$return = [];
|
||||
$return['recurring_transactions'] = $this->runRecurring($config['force'], $config['date']);
|
||||
$return['auto_budgets'] = $this->runAutoBudget($config['force'], $config['date']);
|
||||
if (true === config('cer.enabled')) {
|
||||
if (true === config('cer.download_enabled')) {
|
||||
$return['exchange_rates'] = $this->exchangeRatesCronJob($config['force'], $config['date']);
|
||||
}
|
||||
$return['bill_warnings'] = $this->billWarningCronJob($config['force'], $config['date']);
|
||||
|
@@ -35,6 +35,9 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
/**
|
||||
* Class MessageController
|
||||
*/
|
||||
class MessageController extends Controller
|
||||
{
|
||||
public const RESOURCE_KEY = 'webhook_messages';
|
||||
|
@@ -127,6 +127,7 @@ class ShowController extends Controller
|
||||
*/
|
||||
public function triggerTransaction(Webhook $webhook, TransactionGroup $group): JsonResponse
|
||||
{
|
||||
app('log')->debug(sprintf('Now in triggerTransaction(%d, %d)', $webhook->id, $group->id));
|
||||
/** @var MessageGeneratorInterface $engine */
|
||||
$engine = app(MessageGeneratorInterface::class);
|
||||
$engine->setUser(auth()->user());
|
||||
@@ -141,6 +142,7 @@ class ShowController extends Controller
|
||||
$engine->generateMessages();
|
||||
|
||||
// trigger event to send them:
|
||||
app('log')->debug('send event RequestedSendWebhookMessages');
|
||||
event(new RequestedSendWebhookMessages());
|
||||
|
||||
return response()->json([], 204);
|
||||
|
@@ -38,6 +38,9 @@ class ExportRequest extends FormRequest
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$result = [
|
||||
|
@@ -82,6 +82,28 @@ class GenericRequest extends FormRequest
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function parseAccounts(): void
|
||||
{
|
||||
if (0 !== $this->accounts->count()) {
|
||||
return;
|
||||
}
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
$array = $this->get('accounts');
|
||||
if (is_array($array)) {
|
||||
foreach ($array as $accountId) {
|
||||
$accountId = (int)$accountId;
|
||||
$account = $repository->find($accountId);
|
||||
if (null !== $account) {
|
||||
$this->accounts->push($account);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
@@ -92,6 +114,28 @@ class GenericRequest extends FormRequest
|
||||
return $this->bills;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function parseBills(): void
|
||||
{
|
||||
if (0 !== $this->bills->count()) {
|
||||
return;
|
||||
}
|
||||
$repository = app(BillRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
$array = $this->get('bills');
|
||||
if (is_array($array)) {
|
||||
foreach ($array as $billId) {
|
||||
$billId = (int)$billId;
|
||||
$bill = $repository->find($billId);
|
||||
if (null !== $bill) {
|
||||
$this->bills->push($bill);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
@@ -102,6 +146,28 @@ class GenericRequest extends FormRequest
|
||||
return $this->budgets;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function parseBudgets(): void
|
||||
{
|
||||
if (0 !== $this->budgets->count()) {
|
||||
return;
|
||||
}
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
$array = $this->get('budgets');
|
||||
if (is_array($array)) {
|
||||
foreach ($array as $budgetId) {
|
||||
$budgetId = (int)$budgetId;
|
||||
$budget = $repository->find($budgetId);
|
||||
if (null !== $budget) {
|
||||
$this->budgets->push($budget);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
@@ -112,6 +178,28 @@ class GenericRequest extends FormRequest
|
||||
return $this->categories;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function parseCategories(): void
|
||||
{
|
||||
if (0 !== $this->categories->count()) {
|
||||
return;
|
||||
}
|
||||
$repository = app(CategoryRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
$array = $this->get('categories');
|
||||
if (is_array($array)) {
|
||||
foreach ($array as $categoryId) {
|
||||
$categoryId = (int)$categoryId;
|
||||
$category = $repository->find($categoryId);
|
||||
if (null !== $category) {
|
||||
$this->categories->push($category);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Carbon
|
||||
*/
|
||||
@@ -180,114 +268,6 @@ class GenericRequest extends FormRequest
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
// this is cheating, but it works to initialize the collections.
|
||||
$this->accounts = new Collection();
|
||||
$this->budgets = new Collection();
|
||||
$this->categories = new Collection();
|
||||
$this->bills = new Collection();
|
||||
$this->tags = new Collection();
|
||||
|
||||
return [
|
||||
'start' => 'required|date',
|
||||
'end' => 'required|date|after_or_equal:start',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function parseAccounts(): void
|
||||
{
|
||||
if (0 !== $this->accounts->count()) {
|
||||
return;
|
||||
}
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
$array = $this->get('accounts');
|
||||
if (is_array($array)) {
|
||||
foreach ($array as $accountId) {
|
||||
$accountId = (int)$accountId;
|
||||
$account = $repository->find($accountId);
|
||||
if (null !== $account) {
|
||||
$this->accounts->push($account);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function parseBills(): void
|
||||
{
|
||||
if (0 !== $this->bills->count()) {
|
||||
return;
|
||||
}
|
||||
$repository = app(BillRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
$array = $this->get('bills');
|
||||
if (is_array($array)) {
|
||||
foreach ($array as $billId) {
|
||||
$billId = (int)$billId;
|
||||
$bill = $repository->find($billId);
|
||||
if (null !== $bill) {
|
||||
$this->bills->push($bill);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function parseBudgets(): void
|
||||
{
|
||||
if (0 !== $this->budgets->count()) {
|
||||
return;
|
||||
}
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
$array = $this->get('budgets');
|
||||
if (is_array($array)) {
|
||||
foreach ($array as $budgetId) {
|
||||
$budgetId = (int)$budgetId;
|
||||
$budget = $repository->find($budgetId);
|
||||
if (null !== $budget) {
|
||||
$this->budgets->push($budget);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function parseCategories(): void
|
||||
{
|
||||
if (0 !== $this->categories->count()) {
|
||||
return;
|
||||
}
|
||||
$repository = app(CategoryRepositoryInterface::class);
|
||||
$repository->setUser(auth()->user());
|
||||
$array = $this->get('categories');
|
||||
if (is_array($array)) {
|
||||
foreach ($array as $categoryId) {
|
||||
$categoryId = (int)$categoryId;
|
||||
$category = $repository->find($categoryId);
|
||||
if (null !== $category) {
|
||||
$this->categories->push($category);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -309,4 +289,24 @@ class GenericRequest extends FormRequest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
// this is cheating, but it works to initialize the collections.
|
||||
$this->accounts = new Collection();
|
||||
$this->budgets = new Collection();
|
||||
$this->categories = new Collection();
|
||||
$this->bills = new Collection();
|
||||
$this->tags = new Collection();
|
||||
|
||||
return [
|
||||
'start' => 'required|date',
|
||||
'end' => 'required|date|after_or_equal:start',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -73,6 +73,65 @@ class StoreRequest extends FormRequest
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
|
||||
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTransactionData(): array
|
||||
{
|
||||
$return = [];
|
||||
// transaction data:
|
||||
/** @var array|null $transactions */
|
||||
$transactions = $this->get('transactions');
|
||||
if (null === $transactions) {
|
||||
return [];
|
||||
}
|
||||
/** @var array $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$return[] = $this->getSingleTransactionData($transaction);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the repetition data as it is found in the submitted data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getRepetitionData(): array
|
||||
{
|
||||
$return = [];
|
||||
// repetition data:
|
||||
/** @var array|null $repetitions */
|
||||
$repetitions = $this->get('repetitions');
|
||||
if (null === $repetitions) {
|
||||
return [];
|
||||
}
|
||||
/** @var array $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
$current = [];
|
||||
if (array_key_exists('type', $repetition)) {
|
||||
$current['type'] = $repetition['type'];
|
||||
}
|
||||
if (array_key_exists('moment', $repetition)) {
|
||||
$current['moment'] = $repetition['moment'];
|
||||
}
|
||||
if (array_key_exists('skip', $repetition)) {
|
||||
$current['skip'] = (int)$repetition['skip'];
|
||||
}
|
||||
if (array_key_exists('weekend', $repetition)) {
|
||||
$current['weekend'] = (int)$repetition['weekend'];
|
||||
}
|
||||
|
||||
$return[] = $current;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
@@ -139,63 +198,4 @@ class StoreRequest extends FormRequest
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the repetition data as it is found in the submitted data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getRepetitionData(): array
|
||||
{
|
||||
$return = [];
|
||||
// repetition data:
|
||||
/** @var array|null $repetitions */
|
||||
$repetitions = $this->get('repetitions');
|
||||
if (null === $repetitions) {
|
||||
return [];
|
||||
}
|
||||
/** @var array $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
$current = [];
|
||||
if (array_key_exists('type', $repetition)) {
|
||||
$current['type'] = $repetition['type'];
|
||||
}
|
||||
if (array_key_exists('moment', $repetition)) {
|
||||
$current['moment'] = $repetition['moment'];
|
||||
}
|
||||
if (array_key_exists('skip', $repetition)) {
|
||||
$current['skip'] = (int)$repetition['skip'];
|
||||
}
|
||||
if (array_key_exists('weekend', $repetition)) {
|
||||
$current['weekend'] = (int)$repetition['weekend'];
|
||||
}
|
||||
|
||||
$return[] = $current;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
|
||||
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTransactionData(): array
|
||||
{
|
||||
$return = [];
|
||||
// transaction data:
|
||||
/** @var array|null $transactions */
|
||||
$transactions = $this->get('transactions');
|
||||
if (null === $transactions) {
|
||||
return [];
|
||||
}
|
||||
/** @var array $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$return[] = $this->getSingleTransactionData($transaction);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
@@ -80,6 +80,70 @@ class UpdateRequest extends FormRequest
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the repetition data as it is found in the submitted data.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function getRepetitionData(): ?array
|
||||
{
|
||||
$return = [];
|
||||
// repetition data:
|
||||
/** @var array|null $repetitions */
|
||||
$repetitions = $this->get('repetitions');
|
||||
if (null === $repetitions) {
|
||||
return null;
|
||||
}
|
||||
/** @var array $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
$current = [];
|
||||
if (array_key_exists('type', $repetition)) {
|
||||
$current['type'] = $repetition['type'];
|
||||
}
|
||||
|
||||
if (array_key_exists('moment', $repetition)) {
|
||||
$current['moment'] = (string)$repetition['moment'];
|
||||
}
|
||||
|
||||
if (array_key_exists('skip', $repetition)) {
|
||||
$current['skip'] = (int)$repetition['skip'];
|
||||
}
|
||||
|
||||
if (array_key_exists('weekend', $repetition)) {
|
||||
$current['weekend'] = (int)$repetition['weekend'];
|
||||
}
|
||||
$return[] = $current;
|
||||
}
|
||||
if (0 === count($return)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
|
||||
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function getTransactionData(): ?array
|
||||
{
|
||||
$return = [];
|
||||
// transaction data:
|
||||
/** @var array|null $transactions */
|
||||
$transactions = $this->get('transactions');
|
||||
if (null === $transactions) {
|
||||
return null;
|
||||
}
|
||||
/** @var array $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$return[] = $this->getSingleTransactionData($transaction);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
@@ -154,68 +218,4 @@ class UpdateRequest extends FormRequest
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the repetition data as it is found in the submitted data.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function getRepetitionData(): ?array
|
||||
{
|
||||
$return = [];
|
||||
// repetition data:
|
||||
/** @var array|null $repetitions */
|
||||
$repetitions = $this->get('repetitions');
|
||||
if (null === $repetitions) {
|
||||
return null;
|
||||
}
|
||||
/** @var array $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
$current = [];
|
||||
if (array_key_exists('type', $repetition)) {
|
||||
$current['type'] = $repetition['type'];
|
||||
}
|
||||
|
||||
if (array_key_exists('moment', $repetition)) {
|
||||
$current['moment'] = (string)$repetition['moment'];
|
||||
}
|
||||
|
||||
if (array_key_exists('skip', $repetition)) {
|
||||
$current['skip'] = (int)$repetition['skip'];
|
||||
}
|
||||
|
||||
if (array_key_exists('weekend', $repetition)) {
|
||||
$current['weekend'] = (int)$repetition['weekend'];
|
||||
}
|
||||
$return[] = $current;
|
||||
}
|
||||
if (0 === count($return)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
|
||||
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function getTransactionData(): ?array
|
||||
{
|
||||
$return = [];
|
||||
// transaction data:
|
||||
/** @var array|null $transactions */
|
||||
$transactions = $this->get('transactions');
|
||||
if (null === $transactions) {
|
||||
return null;
|
||||
}
|
||||
/** @var array $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$return[] = $this->getSingleTransactionData($transaction);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -67,6 +67,48 @@ class StoreRequest extends FormRequest
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getRuleTriggers(): array
|
||||
{
|
||||
$triggers = $this->get('triggers');
|
||||
$return = [];
|
||||
if (is_array($triggers)) {
|
||||
foreach ($triggers as $trigger) {
|
||||
$return[] = [
|
||||
'type' => $trigger['type'],
|
||||
'value' => $trigger['value'],
|
||||
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'true')),
|
||||
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getRuleActions(): array
|
||||
{
|
||||
$actions = $this->get('actions');
|
||||
$return = [];
|
||||
if (is_array($actions)) {
|
||||
foreach ($actions as $action) {
|
||||
$return[] = [
|
||||
'type' => $action['type'],
|
||||
'value' => $action['value'],
|
||||
'active' => $this->convertBoolean((string)($action['active'] ?? 'true')),
|
||||
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
@@ -120,6 +162,21 @@ class StoreRequest extends FormRequest
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when there are no triggers in the array of data.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
protected function atLeastOneTrigger(Validator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$triggers = $data['triggers'] ?? [];
|
||||
// need at least one trigger
|
||||
if (!is_countable($triggers) || 0 === count($triggers)) {
|
||||
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when there are no repetitions in the array of data.
|
||||
*
|
||||
@@ -135,35 +192,6 @@ class StoreRequest extends FormRequest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when there are no ACTIVE actions in the array of data.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
protected function atLeastOneActiveAction(Validator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$actions = $data['actions'] ?? [];
|
||||
// need at least one trigger
|
||||
if (!is_countable($actions) || 0 === count($actions)) {
|
||||
return;
|
||||
}
|
||||
$allInactive = true;
|
||||
$inactiveIndex = 0;
|
||||
foreach ($actions as $index => $action) {
|
||||
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
|
||||
if (true === $active) {
|
||||
$allInactive = false;
|
||||
}
|
||||
if (false === $active) {
|
||||
$inactiveIndex = $index;
|
||||
}
|
||||
}
|
||||
if (true === $allInactive) {
|
||||
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when there are no ACTIVE triggers in the array of data.
|
||||
*
|
||||
@@ -194,59 +222,31 @@ class StoreRequest extends FormRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when there are no triggers in the array of data.
|
||||
* Adds an error to the validator when there are no ACTIVE actions in the array of data.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
protected function atLeastOneTrigger(Validator $validator): void
|
||||
protected function atLeastOneActiveAction(Validator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$triggers = $data['triggers'] ?? [];
|
||||
$actions = $data['actions'] ?? [];
|
||||
// need at least one trigger
|
||||
if (!is_countable($triggers) || 0 === count($triggers)) {
|
||||
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger'));
|
||||
if (!is_countable($actions) || 0 === count($actions)) {
|
||||
return;
|
||||
}
|
||||
$allInactive = true;
|
||||
$inactiveIndex = 0;
|
||||
foreach ($actions as $index => $action) {
|
||||
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
|
||||
if (true === $active) {
|
||||
$allInactive = false;
|
||||
}
|
||||
if (false === $active) {
|
||||
$inactiveIndex = $index;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getRuleActions(): array
|
||||
{
|
||||
$actions = $this->get('actions');
|
||||
$return = [];
|
||||
if (is_array($actions)) {
|
||||
foreach ($actions as $action) {
|
||||
$return[] = [
|
||||
'type' => $action['type'],
|
||||
'value' => $action['value'],
|
||||
'active' => $this->convertBoolean((string)($action['active'] ?? 'true')),
|
||||
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
|
||||
];
|
||||
if (true === $allInactive) {
|
||||
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getRuleTriggers(): array
|
||||
{
|
||||
$triggers = $this->get('triggers');
|
||||
$return = [];
|
||||
if (is_array($triggers)) {
|
||||
foreach ($triggers as $trigger) {
|
||||
$return[] = [
|
||||
'type' => $trigger['type'],
|
||||
'value' => $trigger['value'],
|
||||
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'true')),
|
||||
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
@@ -52,24 +52,11 @@ class TestRequest extends FormRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @return int
|
||||
*/
|
||||
public function rules(): array
|
||||
private function getPage(): int
|
||||
{
|
||||
return [
|
||||
'start' => 'date',
|
||||
'end' => 'date|after_or_equal:start',
|
||||
'accounts' => '',
|
||||
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getAccounts(): array
|
||||
{
|
||||
return $this->get('accounts');
|
||||
return 0 === (int)$this->query('page') ? 1 : (int)$this->query('page');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,10 +70,23 @@ class TestRequest extends FormRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @return array
|
||||
*/
|
||||
private function getPage(): int
|
||||
private function getAccounts(): array
|
||||
{
|
||||
return 0 === (int)$this->query('page') ? 1 : (int)$this->query('page');
|
||||
return $this->get('accounts');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'start' => 'date',
|
||||
'end' => 'date|after_or_equal:start',
|
||||
'accounts' => '',
|
||||
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -50,16 +50,13 @@ class TriggerRequest extends FormRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @param string $field
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function rules(): array
|
||||
private function getDate(string $field): ?Carbon
|
||||
{
|
||||
return [
|
||||
'start' => 'date',
|
||||
'end' => 'date|after_or_equal:start',
|
||||
'accounts' => '',
|
||||
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
|
||||
];
|
||||
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($this->query($field), 0, 10));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,12 +68,15 @@ class TriggerRequest extends FormRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return Carbon|null
|
||||
* @return array
|
||||
*/
|
||||
private function getDate(string $field): ?Carbon
|
||||
public function rules(): array
|
||||
{
|
||||
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($this->query($field), 0, 10));
|
||||
return [
|
||||
'start' => 'date',
|
||||
'end' => 'date|after_or_equal:start',
|
||||
'accounts' => '',
|
||||
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -73,6 +73,56 @@ class UpdateRequest extends FormRequest
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
private function getRuleTriggers(): ?array
|
||||
{
|
||||
if (!$this->has('triggers')) {
|
||||
return null;
|
||||
}
|
||||
$triggers = $this->get('triggers');
|
||||
$return = [];
|
||||
if (is_array($triggers)) {
|
||||
foreach ($triggers as $trigger) {
|
||||
$active = array_key_exists('active', $trigger) ? $trigger['active'] : true;
|
||||
$stopProcessing = array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false;
|
||||
$return[] = [
|
||||
'type' => $trigger['type'],
|
||||
'value' => $trigger['value'],
|
||||
'active' => $active,
|
||||
'stop_processing' => $stopProcessing,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
private function getRuleActions(): ?array
|
||||
{
|
||||
if (!$this->has('actions')) {
|
||||
return null;
|
||||
}
|
||||
$actions = $this->get('actions');
|
||||
$return = [];
|
||||
if (is_array($actions)) {
|
||||
foreach ($actions as $action) {
|
||||
$return[] = [
|
||||
'type' => $action['type'],
|
||||
'value' => $action['value'],
|
||||
'active' => $this->convertBoolean((string)($action['active'] ?? 'false')),
|
||||
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
@@ -130,21 +180,6 @@ class UpdateRequest extends FormRequest
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when there are no repetitions in the array of data.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
protected function atLeastOneAction(Validator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$actions = $data['actions'] ?? null;
|
||||
// need at least one action
|
||||
if (is_array($actions) && 0 === count($actions)) {
|
||||
$validator->errors()->add('title', (string)trans('validation.at_least_one_action'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when there are no repetitions in the array of data.
|
||||
*
|
||||
@@ -160,36 +195,6 @@ class UpdateRequest extends FormRequest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when there are no repetitions in the array of data.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
protected function atLeastOneValidAction(Validator $validator): void
|
||||
{
|
||||
$data = $validator->getData();
|
||||
$actions = $data['actions'] ?? [];
|
||||
$allInactive = true;
|
||||
$inactiveIndex = 0;
|
||||
// need at least one action
|
||||
if (is_array($actions) && 0 === count($actions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($actions as $index => $action) {
|
||||
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
|
||||
if (true === $active) {
|
||||
$allInactive = false;
|
||||
}
|
||||
if (false === $active) {
|
||||
$inactiveIndex = $index;
|
||||
}
|
||||
}
|
||||
if (true === $allInactive) {
|
||||
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the validator when there are no repetitions in the array of data.
|
||||
*
|
||||
@@ -220,52 +225,47 @@ class UpdateRequest extends FormRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
* Adds an error to the validator when there are no repetitions in the array of data.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
private function getRuleActions(): ?array
|
||||
protected function atLeastOneAction(Validator $validator): void
|
||||
{
|
||||
if (!$this->has('actions')) {
|
||||
return null;
|
||||
$data = $validator->getData();
|
||||
$actions = $data['actions'] ?? null;
|
||||
// need at least one action
|
||||
if (is_array($actions) && 0 === count($actions)) {
|
||||
$validator->errors()->add('title', (string)trans('validation.at_least_one_action'));
|
||||
}
|
||||
$actions = $this->get('actions');
|
||||
$return = [];
|
||||
if (is_array($actions)) {
|
||||
foreach ($actions as $action) {
|
||||
$return[] = [
|
||||
'type' => $action['type'],
|
||||
'value' => $action['value'],
|
||||
'active' => $this->convertBoolean((string)($action['active'] ?? 'false')),
|
||||
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
* Adds an error to the validator when there are no repetitions in the array of data.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*/
|
||||
private function getRuleTriggers(): ?array
|
||||
protected function atLeastOneValidAction(Validator $validator): void
|
||||
{
|
||||
if (!$this->has('triggers')) {
|
||||
return null;
|
||||
}
|
||||
$triggers = $this->get('triggers');
|
||||
$return = [];
|
||||
if (is_array($triggers)) {
|
||||
foreach ($triggers as $trigger) {
|
||||
$active = array_key_exists('active', $trigger) ? $trigger['active'] : true;
|
||||
$stopProcessing = array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false;
|
||||
$return[] = [
|
||||
'type' => $trigger['type'],
|
||||
'value' => $trigger['value'],
|
||||
'active' => $active,
|
||||
'stop_processing' => $stopProcessing,
|
||||
];
|
||||
}
|
||||
$data = $validator->getData();
|
||||
$actions = $data['actions'] ?? [];
|
||||
$allInactive = true;
|
||||
$inactiveIndex = 0;
|
||||
// need at least one action
|
||||
if (is_array($actions) && 0 === count($actions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $return;
|
||||
foreach ($actions as $index => $action) {
|
||||
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
|
||||
if (true === $active) {
|
||||
$allInactive = false;
|
||||
}
|
||||
if (false === $active) {
|
||||
$inactiveIndex = $index;
|
||||
}
|
||||
}
|
||||
if (true === $allInactive) {
|
||||
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -50,16 +50,13 @@ class TestRequest extends FormRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @param string $field
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function rules(): array
|
||||
private function getDate(string $field): ?Carbon
|
||||
{
|
||||
return [
|
||||
'start' => 'date',
|
||||
'end' => 'date|after_or_equal:start',
|
||||
'accounts' => '',
|
||||
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
|
||||
];
|
||||
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,12 +68,15 @@ class TestRequest extends FormRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return Carbon|null
|
||||
* @return array
|
||||
*/
|
||||
private function getDate(string $field): ?Carbon
|
||||
public function rules(): array
|
||||
{
|
||||
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
|
||||
return [
|
||||
'start' => 'date',
|
||||
'end' => 'date|after_or_equal:start',
|
||||
'accounts' => '',
|
||||
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -50,14 +50,13 @@ class TriggerRequest extends FormRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @param string $field
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function rules(): array
|
||||
private function getDate(string $field): ?Carbon
|
||||
{
|
||||
return [
|
||||
'start' => 'date',
|
||||
'end' => 'date|after_or_equal:start',
|
||||
];
|
||||
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,12 +68,13 @@ class TriggerRequest extends FormRequest
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return Carbon|null
|
||||
* @return array
|
||||
*/
|
||||
private function getDate(string $field): ?Carbon
|
||||
public function rules(): array
|
||||
{
|
||||
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
|
||||
return [
|
||||
'start' => 'date',
|
||||
'end' => 'date|after_or_equal:start',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -69,6 +69,103 @@ class StoreRequest extends FormRequest
|
||||
// TODO include location and ability to process it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transaction data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTransactionData(): array
|
||||
{
|
||||
$return = [];
|
||||
/**
|
||||
* @var array $transaction
|
||||
*/
|
||||
foreach ($this->get('transactions') as $transaction) {
|
||||
$object = new NullArrayObject($transaction);
|
||||
$return[] = [
|
||||
'type' => $this->clearString($object['type'], false),
|
||||
'date' => $this->dateFromValue($object['date']),
|
||||
'order' => $this->integerFromValue((string)$object['order']),
|
||||
|
||||
'currency_id' => $this->integerFromValue((string)$object['currency_id']),
|
||||
'currency_code' => $this->clearString((string)$object['currency_code'], false),
|
||||
|
||||
// foreign currency info:
|
||||
'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']),
|
||||
'foreign_currency_code' => $this->clearString((string)$object['foreign_currency_code'], false),
|
||||
|
||||
// amount and foreign amount. Cannot be 0.
|
||||
'amount' => $this->clearString((string)$object['amount'], false),
|
||||
'foreign_amount' => $this->clearString((string)$object['foreign_amount'], false),
|
||||
|
||||
// description.
|
||||
'description' => $this->clearString($object['description'], false),
|
||||
|
||||
// source of transaction. If everything is null, assume cash account.
|
||||
'source_id' => $this->integerFromValue((string)$object['source_id']),
|
||||
'source_name' => $this->clearString((string)$object['source_name'], false),
|
||||
'source_iban' => $this->clearString((string)$object['source_iban'], false),
|
||||
'source_number' => $this->clearString((string)$object['source_number'], false),
|
||||
'source_bic' => $this->clearString((string)$object['source_bic'], false),
|
||||
|
||||
// destination of transaction. If everything is null, assume cash account.
|
||||
'destination_id' => $this->integerFromValue((string)$object['destination_id']),
|
||||
'destination_name' => $this->clearString((string)$object['destination_name'], false),
|
||||
'destination_iban' => $this->clearString((string)$object['destination_iban'], false),
|
||||
'destination_number' => $this->clearString((string)$object['destination_number'], false),
|
||||
'destination_bic' => $this->clearString((string)$object['destination_bic'], false),
|
||||
|
||||
// budget info
|
||||
'budget_id' => $this->integerFromValue((string)$object['budget_id']),
|
||||
'budget_name' => $this->clearString((string)$object['budget_name'], false),
|
||||
|
||||
// category info
|
||||
'category_id' => $this->integerFromValue((string)$object['category_id']),
|
||||
'category_name' => $this->clearString((string)$object['category_name'], false),
|
||||
|
||||
// journal bill reference. Optional. Will only work for withdrawals
|
||||
'bill_id' => $this->integerFromValue((string)$object['bill_id']),
|
||||
'bill_name' => $this->clearString((string)$object['bill_name'], false),
|
||||
|
||||
// piggy bank reference. Optional. Will only work for transfers
|
||||
'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']),
|
||||
'piggy_bank_name' => $this->clearString((string)$object['piggy_bank_name'], false),
|
||||
|
||||
// some other interesting properties
|
||||
'reconciled' => $this->convertBoolean((string)$object['reconciled']),
|
||||
'notes' => $this->clearString((string)$object['notes']),
|
||||
'tags' => $this->arrayFromValue($object['tags']),
|
||||
|
||||
// all custom fields:
|
||||
'internal_reference' => $this->clearString((string)$object['internal_reference'], false),
|
||||
'external_id' => $this->clearString((string)$object['external_id'], false),
|
||||
'original_source' => sprintf('ff3-v%s|api-v%s', config('firefly.version'), config('firefly.api_version')),
|
||||
'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
|
||||
'bunq_payment_id' => $this->clearString((string)$object['bunq_payment_id'], false),
|
||||
'external_url' => $this->clearString((string)$object['external_url'], false),
|
||||
|
||||
'sepa_cc' => $this->clearString((string)$object['sepa_cc'], false),
|
||||
'sepa_ct_op' => $this->clearString((string)$object['sepa_ct_op'], false),
|
||||
'sepa_ct_id' => $this->clearString((string)$object['sepa_ct_id'], false),
|
||||
'sepa_db' => $this->clearString((string)$object['sepa_db'], false),
|
||||
'sepa_country' => $this->clearString((string)$object['sepa_country'], false),
|
||||
'sepa_ep' => $this->clearString((string)$object['sepa_ep'], false),
|
||||
'sepa_ci' => $this->clearString((string)$object['sepa_ci'], false),
|
||||
'sepa_batch_id' => $this->clearString((string)$object['sepa_batch_id'], false),
|
||||
// custom date fields. Must be Carbon objects. Presence is optional.
|
||||
'interest_date' => $this->dateFromValue($object['interest_date']),
|
||||
'book_date' => $this->dateFromValue($object['book_date']),
|
||||
'process_date' => $this->dateFromValue($object['process_date']),
|
||||
'due_date' => $this->dateFromValue($object['due_date']),
|
||||
'payment_date' => $this->dateFromValue($object['payment_date']),
|
||||
'invoice_date' => $this->dateFromValue($object['invoice_date']),
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
@@ -197,101 +294,4 @@ class StoreRequest extends FormRequest
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transaction data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTransactionData(): array
|
||||
{
|
||||
$return = [];
|
||||
/**
|
||||
* @var array $transaction
|
||||
*/
|
||||
foreach ($this->get('transactions') as $transaction) {
|
||||
$object = new NullArrayObject($transaction);
|
||||
$return[] = [
|
||||
'type' => $this->clearString($object['type'], false),
|
||||
'date' => $this->dateFromValue($object['date']),
|
||||
'order' => $this->integerFromValue((string)$object['order']),
|
||||
|
||||
'currency_id' => $this->integerFromValue((string)$object['currency_id']),
|
||||
'currency_code' => $this->clearString((string)$object['currency_code'], false),
|
||||
|
||||
// foreign currency info:
|
||||
'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']),
|
||||
'foreign_currency_code' => $this->clearString((string)$object['foreign_currency_code'], false),
|
||||
|
||||
// amount and foreign amount. Cannot be 0.
|
||||
'amount' => $this->clearString((string)$object['amount'], false),
|
||||
'foreign_amount' => $this->clearString((string)$object['foreign_amount'], false),
|
||||
|
||||
// description.
|
||||
'description' => $this->clearString($object['description'], false),
|
||||
|
||||
// source of transaction. If everything is null, assume cash account.
|
||||
'source_id' => $this->integerFromValue((string)$object['source_id']),
|
||||
'source_name' => $this->clearString((string)$object['source_name'], false),
|
||||
'source_iban' => $this->clearString((string)$object['source_iban'], false),
|
||||
'source_number' => $this->clearString((string)$object['source_number'], false),
|
||||
'source_bic' => $this->clearString((string)$object['source_bic'], false),
|
||||
|
||||
// destination of transaction. If everything is null, assume cash account.
|
||||
'destination_id' => $this->integerFromValue((string)$object['destination_id']),
|
||||
'destination_name' => $this->clearString((string)$object['destination_name'], false),
|
||||
'destination_iban' => $this->clearString((string)$object['destination_iban'], false),
|
||||
'destination_number' => $this->clearString((string)$object['destination_number'], false),
|
||||
'destination_bic' => $this->clearString((string)$object['destination_bic'], false),
|
||||
|
||||
// budget info
|
||||
'budget_id' => $this->integerFromValue((string)$object['budget_id']),
|
||||
'budget_name' => $this->clearString((string)$object['budget_name'], false),
|
||||
|
||||
// category info
|
||||
'category_id' => $this->integerFromValue((string)$object['category_id']),
|
||||
'category_name' => $this->clearString((string)$object['category_name'], false),
|
||||
|
||||
// journal bill reference. Optional. Will only work for withdrawals
|
||||
'bill_id' => $this->integerFromValue((string)$object['bill_id']),
|
||||
'bill_name' => $this->clearString((string)$object['bill_name'], false),
|
||||
|
||||
// piggy bank reference. Optional. Will only work for transfers
|
||||
'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']),
|
||||
'piggy_bank_name' => $this->clearString((string)$object['piggy_bank_name'], false),
|
||||
|
||||
// some other interesting properties
|
||||
'reconciled' => $this->convertBoolean((string)$object['reconciled']),
|
||||
'notes' => $this->clearString((string)$object['notes']),
|
||||
'tags' => $this->arrayFromValue($object['tags']),
|
||||
|
||||
// all custom fields:
|
||||
'internal_reference' => $this->clearString((string)$object['internal_reference'], false),
|
||||
'external_id' => $this->clearString((string)$object['external_id'], false),
|
||||
'original_source' => sprintf('ff3-v%s|api-v%s', config('firefly.version'), config('firefly.api_version')),
|
||||
'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
|
||||
'bunq_payment_id' => $this->clearString((string)$object['bunq_payment_id'], false),
|
||||
'external_url' => $this->clearString((string)$object['external_url'], false),
|
||||
|
||||
'sepa_cc' => $this->clearString((string)$object['sepa_cc'], false),
|
||||
'sepa_ct_op' => $this->clearString((string)$object['sepa_ct_op'], false),
|
||||
'sepa_ct_id' => $this->clearString((string)$object['sepa_ct_id'], false),
|
||||
'sepa_db' => $this->clearString((string)$object['sepa_db'], false),
|
||||
'sepa_country' => $this->clearString((string)$object['sepa_country'], false),
|
||||
'sepa_ep' => $this->clearString((string)$object['sepa_ep'], false),
|
||||
'sepa_ci' => $this->clearString((string)$object['sepa_ci'], false),
|
||||
'sepa_batch_id' => $this->clearString((string)$object['sepa_batch_id'], false),
|
||||
// custom date fields. Must be Carbon objects. Presence is optional.
|
||||
'interest_date' => $this->dateFromValue($object['interest_date']),
|
||||
'book_date' => $this->dateFromValue($object['book_date']),
|
||||
'process_date' => $this->dateFromValue($object['process_date']),
|
||||
'due_date' => $this->dateFromValue($object['due_date']),
|
||||
'payment_date' => $this->dateFromValue($object['payment_date']),
|
||||
'invoice_date' => $this->dateFromValue($object['invoice_date']),
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
@@ -59,6 +59,7 @@ class UpdateRequest extends FormRequest
|
||||
* Get all data. Is pretty complex because of all the ??-statements.
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
@@ -152,6 +153,7 @@ class UpdateRequest extends FormRequest
|
||||
* Get transaction data.
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getTransactionData(): array
|
||||
{
|
||||
@@ -322,7 +324,7 @@ class UpdateRequest extends FormRequest
|
||||
|
||||
return [
|
||||
// basic fields for group:
|
||||
'group_title' => 'between:1,1000',
|
||||
'group_title' => 'between:1,1000|nullable',
|
||||
'apply_rules' => [new IsBoolean()],
|
||||
|
||||
// transaction rules (in array for splits):
|
||||
@@ -335,8 +337,8 @@ class UpdateRequest extends FormRequest
|
||||
|
||||
|
||||
// currency info
|
||||
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
'transactions.*.currency_code' => 'min:3|max:51|exists:transaction_currencies,code',
|
||||
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id|nullable',
|
||||
'transactions.*.currency_code' => 'min:3|max:51|exists:transaction_currencies,code|nullable',
|
||||
'transactions.*.foreign_currency_id' => 'nullable|numeric|exists:transaction_currencies,id',
|
||||
'transactions.*.foreign_currency_code' => 'nullable|min:3|max:51|exists:transaction_currencies,code',
|
||||
|
||||
@@ -356,9 +358,9 @@ class UpdateRequest extends FormRequest
|
||||
'transactions.*.destination_name' => 'between:1,255|nullable',
|
||||
|
||||
// budget, category, bill and piggy
|
||||
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUser()],
|
||||
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUser(), 'nullable'],
|
||||
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUser()],
|
||||
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUser()],
|
||||
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUser(), 'nullable'],
|
||||
'transactions.*.category_name' => 'between:1,255|nullable',
|
||||
'transactions.*.bill_id' => ['numeric', 'nullable', 'mustExist:bills,id', new BelongsUser()],
|
||||
'transactions.*.bill_name' => ['between:1,255', 'nullable', new BelongsUser()],
|
||||
@@ -366,7 +368,7 @@ class UpdateRequest extends FormRequest
|
||||
// other interesting fields
|
||||
'transactions.*.reconciled' => [new IsBoolean()],
|
||||
'transactions.*.notes' => 'min:1|max:50000|nullable',
|
||||
'transactions.*.tags' => 'between:0,255',
|
||||
'transactions.*.tags' => 'between:0,255|nullable',
|
||||
|
||||
// meta info fields
|
||||
'transactions.*.internal_reference' => 'min:1|max:255|nullable',
|
||||
|
@@ -27,6 +27,9 @@ use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Class PreferenceStoreRequest
|
||||
*/
|
||||
class PreferenceStoreRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
|
@@ -28,6 +28,9 @@ use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Class PreferenceUpdateRequest
|
||||
*/
|
||||
class PreferenceUpdateRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
|
@@ -30,11 +30,10 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Administration\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\AccountFilter;
|
||||
use FireflyIII\User;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use JsonException;
|
||||
|
||||
/**
|
||||
* Class AccountController
|
||||
@@ -42,6 +41,7 @@ use JsonException;
|
||||
class AccountController extends Controller
|
||||
{
|
||||
use AccountFilter;
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
private AdminAccountRepositoryInterface $adminRepository;
|
||||
private array $balanceTypes;
|
||||
@@ -58,6 +58,11 @@ class AccountController extends Controller
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
$this->adminRepository = app(AdminAccountRepositoryInterface::class);
|
||||
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->adminRepository->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
@@ -66,12 +71,16 @@ class AccountController extends Controller
|
||||
|
||||
/**
|
||||
* Documentation for this endpoint:
|
||||
* TODO endpoint is not documented.
|
||||
* TODO list of checks
|
||||
* 1. use dates from ParameterBag
|
||||
* 2. Request validates dates
|
||||
* 3. Request includes user_group_id
|
||||
* 4. Endpoint is documented.
|
||||
* 5. Collector uses user_group_id
|
||||
*
|
||||
* @param AutocompleteRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws JsonException
|
||||
* @throws FireflyException
|
||||
* @throws FireflyException
|
||||
*/
|
||||
@@ -80,8 +89,7 @@ class AccountController extends Controller
|
||||
$data = $request->getData();
|
||||
$types = $data['types'];
|
||||
$query = $data['query'];
|
||||
$date = $data['date'] ?? today(config('app.timezone'));
|
||||
$this->adminRepository->setAdministrationId($data['administration_id']);
|
||||
$date = $this->parameters->get('date') ?? today(config('app.timezone'));
|
||||
|
||||
$return = [];
|
||||
$result = $this->adminRepository->searchAccount((string)$query, $types, $data['limit']);
|
||||
@@ -102,7 +110,7 @@ class AccountController extends Controller
|
||||
'name' => $account->name,
|
||||
'name_with_balance' => $nameWithBalance,
|
||||
'type' => $account->accountType->type,
|
||||
'currency_id' => $currency->id,
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_name' => $currency->name,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
|
@@ -27,10 +27,13 @@ namespace FireflyIII\Api\V2\Controllers\Chart;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Generic\DateRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ConvertsExchangeRates;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\CleansChartData;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
@@ -40,7 +43,8 @@ use Psr\Container\NotFoundExceptionInterface;
|
||||
*/
|
||||
class AccountController extends Controller
|
||||
{
|
||||
use ConvertsExchangeRates;
|
||||
use CleansChartData;
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
private AccountRepositoryInterface $repository;
|
||||
|
||||
@@ -53,6 +57,10 @@ class AccountController extends Controller
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->repository->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
@@ -63,24 +71,32 @@ class AccountController extends Controller
|
||||
* This endpoint is documented at
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/charts/getChartAccountOverview
|
||||
*
|
||||
* The native currency is the preferred currency on the page /currencies.
|
||||
*
|
||||
* If a transaction has foreign currency = native currency, the foreign amount will be used, no conversion
|
||||
* will take place.
|
||||
*
|
||||
* TODO validate and set user_group_id from request
|
||||
*
|
||||
* @param DateRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function dashboard(DateRequest $request): JsonResponse
|
||||
{
|
||||
// parameters for chart:
|
||||
$dates = $request->getAll();
|
||||
/** @var Carbon $start */
|
||||
$start = $dates['start'];
|
||||
$start = $this->parameters->get('start');
|
||||
/** @var Carbon $end */
|
||||
$end = $dates['end'];
|
||||
$end = $this->parameters->get('end');
|
||||
$end->endOfDay();
|
||||
|
||||
// user's preferences
|
||||
$defaultSet = $this->repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT])->pluck('id')->toArray();
|
||||
$frontPage = app('preferences')->get('frontPageAccounts', $defaultSet);
|
||||
/** @var TransactionCurrency $default */
|
||||
$default = app('amount')->getDefaultCurrency();
|
||||
$accounts = $this->repository->getAccountsById($frontPage->data);
|
||||
$chartData = [];
|
||||
@@ -89,7 +105,6 @@ class AccountController extends Controller
|
||||
$frontPage->data = $defaultSet;
|
||||
$frontPage->save();
|
||||
}
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$currency = $this->repository->getAccountCurrency($account);
|
||||
@@ -98,38 +113,45 @@ class AccountController extends Controller
|
||||
}
|
||||
$currentSet = [
|
||||
'label' => $account->name,
|
||||
// the currency that belongs to the account.
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'native_id' => null,
|
||||
'native_code' => null,
|
||||
'native_symbol' => null,
|
||||
'native_decimal_places' => null,
|
||||
'start_date' => $start->toAtomString(),
|
||||
'end_date' => $end->toAtomString(),
|
||||
'type' => 'line', // line, area or bar
|
||||
'yAxisID' => 0, // 0, 1, 2
|
||||
|
||||
// the default currency of the user (could be the same!)
|
||||
'native_id' => (string)$default->id,
|
||||
'native_code' => $default->code,
|
||||
'native_symbol' => $default->symbol,
|
||||
'native_decimal_places' => (int)$default->decimal_places,
|
||||
'start' => $start->toAtomString(),
|
||||
'end' => $end->toAtomString(),
|
||||
'period' => '1D',
|
||||
'entries' => [],
|
||||
'native_entries' => [],
|
||||
];
|
||||
$currentStart = clone $start;
|
||||
$range = app('steam')->balanceInRange($account, $start, clone $end);
|
||||
|
||||
// 2022-10-11: this method no longer converts to floats
|
||||
$range = app('steam')->balanceInRange($account, $start, clone $end, $currency);
|
||||
$rangeConverted = app('steam')->balanceInRangeConverted($account, $start, clone $end, $default);
|
||||
|
||||
$previous = array_values($range)[0];
|
||||
$previousConverted = array_values($rangeConverted)[0];
|
||||
while ($currentStart <= $end) {
|
||||
$format = $currentStart->format('Y-m-d');
|
||||
$label = $currentStart->toAtomString();
|
||||
$balance = array_key_exists($format, $range) ? $range[$format] : $previous;
|
||||
$balanceConverted = array_key_exists($format, $rangeConverted) ? $rangeConverted[$format] : $previousConverted;
|
||||
$previous = $balance;
|
||||
$previousConverted = $balanceConverted;
|
||||
|
||||
$currentStart->addDay();
|
||||
$currentSet['entries'][$label] = $balance;
|
||||
$currentSet['native_entries'][$label] = $balanceConverted;
|
||||
}
|
||||
$currentSet = $this->cerChartSet($currentSet);
|
||||
$chartData[] = $currentSet;
|
||||
}
|
||||
|
||||
return response()->json($chartData);
|
||||
return response()->json($this->clean($chartData));
|
||||
}
|
||||
|
||||
}
|
||||
|
262
app/Api/V2/Controllers/Chart/BalanceController.php
Normal file
262
app/Api/V2/Controllers/Chart/BalanceController.php
Normal file
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* BalanceController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\Chart;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Chart\BalanceChartRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\CleansChartData;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class BalanceController
|
||||
*/
|
||||
class BalanceController extends Controller
|
||||
{
|
||||
use CleansChartData;
|
||||
|
||||
private AccountRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The code is practically a duplicate of ReportController::operations.
|
||||
*
|
||||
* Currency is up to the account/transactions in question, but conversion to the default
|
||||
* currency is possible.
|
||||
*
|
||||
* If the transaction being processed is already in native currency OR if the
|
||||
* foreign amount is in the native currency, the amount will not be converted.
|
||||
*
|
||||
* TODO validate and set user_group_id
|
||||
* TODO collector set group, not user
|
||||
*
|
||||
* @param BalanceChartRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function balance(BalanceChartRequest $request): JsonResponse
|
||||
{
|
||||
$params = $request->getAll();
|
||||
/** @var Carbon $start */
|
||||
$start = $this->parameters->get('start');
|
||||
/** @var Carbon $end */
|
||||
$end = $this->parameters->get('end');
|
||||
$end->endOfDay();
|
||||
/** @var Collection $accounts */
|
||||
$accounts = $params['accounts'];
|
||||
$preferredRange = $params['period'];
|
||||
|
||||
// set some formats, based on input parameters.
|
||||
$format = app('navigation')->preferredCarbonFormatByPeriod($preferredRange);
|
||||
|
||||
// prepare for currency conversion and data collection:
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
/** @var TransactionCurrency $default */
|
||||
$default = app('amount')->getDefaultCurrency();
|
||||
$converter = new ExchangeRateConverter();
|
||||
$currencies = [(int)$default->id => $default,]; // currency cache
|
||||
$data = [];
|
||||
$chartData = [];
|
||||
|
||||
// get journals for entire period:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setRange($start, $end)->withAccountInformation();
|
||||
$collector->setXorAccounts($accounts);
|
||||
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::RECONCILIATION, TransactionType::TRANSFER]);
|
||||
$journals = $collector->getExtractedJournals();
|
||||
|
||||
// set array for default currency (even if unused later on)
|
||||
$defaultCurrencyId = (int)$default->id;
|
||||
$data[$defaultCurrencyId] = [
|
||||
'currency_id' => (string)$defaultCurrencyId,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_code' => $default->code,
|
||||
'currency_name' => $default->name,
|
||||
'currency_decimal_places' => (int)$default->decimal_places,
|
||||
'native_id' => (string)$defaultCurrencyId,
|
||||
'native_symbol' => $default->symbol,
|
||||
'native_code' => $default->code,
|
||||
'native_name' => $default->name,
|
||||
'native_decimal_places' => (int)$default->decimal_places,
|
||||
];
|
||||
|
||||
|
||||
// loop. group by currency and by period.
|
||||
/** @var array $journal */
|
||||
foreach ($journals as $journal) {
|
||||
// format the date according to the period
|
||||
$period = $journal['date']->format($format);
|
||||
|
||||
// collect (and cache) currency information for this journal.
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
$currency = $currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
|
||||
$currencies[$currencyId] = $currency; // may just re-assign itself, don't mind.
|
||||
|
||||
// set the array with monetary info, if it does not exist.
|
||||
$data[$currencyId] = $data[$currencyId] ?? [
|
||||
'currency_id' => (string)$currencyId,
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
'currency_name' => $journal['currency_name'],
|
||||
'currency_decimal_places' => $journal['currency_decimal_places'],
|
||||
// native currency info (could be the same)
|
||||
'native_id' => (string)$default->id,
|
||||
'native_code' => $default->code,
|
||||
'native_symbol' => $default->symbol,
|
||||
'native_decimal_places' => (int)$default->decimal_places,
|
||||
];
|
||||
|
||||
// set the array (in monetary info) with spent/earned in this $period, if it does not exist.
|
||||
$data[$currencyId][$period] = $data[$currencyId][$period] ?? [
|
||||
'period' => $period,
|
||||
'spent' => '0',
|
||||
'earned' => '0',
|
||||
'native_spent' => '0',
|
||||
'native_earned' => '0',
|
||||
];
|
||||
// is this journal's amount in- our outgoing?
|
||||
$key = 'spent';
|
||||
$amount = app('steam')->negative($journal['amount']);
|
||||
// deposit = incoming
|
||||
// transfer or reconcile or opening balance, and these accounts are the destination.
|
||||
if (
|
||||
TransactionType::DEPOSIT === $journal['transaction_type_type']
|
||||
||
|
||||
|
||||
(
|
||||
(
|
||||
TransactionType::TRANSFER === $journal['transaction_type_type']
|
||||
|| TransactionType::RECONCILIATION === $journal['transaction_type_type']
|
||||
|| TransactionType::OPENING_BALANCE === $journal['transaction_type_type']
|
||||
)
|
||||
&& in_array($journal['destination_account_id'], $ids, true)
|
||||
)
|
||||
) {
|
||||
$key = 'earned';
|
||||
$amount = app('steam')->positive($journal['amount']);
|
||||
}
|
||||
// get conversion rate
|
||||
$rate = $converter->getCurrencyRate($currency, $default, $journal['date']);
|
||||
$amountConverted = bcmul($amount, $rate);
|
||||
|
||||
// perhaps transaction already has the foreign amount in the native currency.
|
||||
if ((int)$journal['foreign_currency_id'] === (int)$default->id) {
|
||||
$amountConverted = $journal['foreign_amount'] ?? '0';
|
||||
$amountConverted = 'earned' === $key ? app('steam')->positive($amountConverted) : app('steam')->negative($amountConverted);
|
||||
}
|
||||
|
||||
// add normal entry
|
||||
$data[$currencyId][$period][$key] = bcadd($data[$currencyId][$period][$key], $amount);
|
||||
|
||||
// add converted entry
|
||||
$convertedKey = sprintf('native_%s', $key);
|
||||
$data[$currencyId][$period][$convertedKey] = bcadd($data[$currencyId][$period][$convertedKey], $amountConverted);
|
||||
}
|
||||
|
||||
// loop this data, make chart bars for each currency:
|
||||
/** @var array $currency */
|
||||
foreach ($data as $currency) {
|
||||
// income and expense array prepped:
|
||||
$income = [
|
||||
'label' => 'earned',
|
||||
'currency_id' => (string)$currency['currency_id'],
|
||||
'currency_symbol' => $currency['currency_symbol'],
|
||||
'currency_code' => $currency['currency_code'],
|
||||
'currency_decimal_places' => $currency['currency_decimal_places'],
|
||||
'native_id' => (string)$currency['native_id'],
|
||||
'native_symbol' => $currency['native_symbol'],
|
||||
'native_code' => $currency['native_code'],
|
||||
'native_decimal_places' => $currency['native_decimal_places'],
|
||||
'start' => $start->toAtomString(),
|
||||
'end' => $end->toAtomString(),
|
||||
'period' => $preferredRange,
|
||||
'entries' => [],
|
||||
'native_entries' => [],
|
||||
];
|
||||
$expense = [
|
||||
'label' => 'spent',
|
||||
'currency_id' => (string)$currency['currency_id'],
|
||||
'currency_symbol' => $currency['currency_symbol'],
|
||||
'currency_code' => $currency['currency_code'],
|
||||
'currency_decimal_places' => $currency['currency_decimal_places'],
|
||||
'native_id' => (string)$currency['native_id'],
|
||||
'native_symbol' => $currency['native_symbol'],
|
||||
'native_code' => $currency['native_code'],
|
||||
'native_decimal_places' => $currency['native_decimal_places'],
|
||||
'start' => $start->toAtomString(),
|
||||
'end' => $end->toAtomString(),
|
||||
'period' => $preferredRange,
|
||||
'entries' => [],
|
||||
'native_entries' => [],
|
||||
|
||||
];
|
||||
// loop all possible periods between $start and $end, and add them to the correct dataset.
|
||||
$currentStart = clone $start;
|
||||
while ($currentStart <= $end) {
|
||||
$key = $currentStart->format($format);
|
||||
$label = $currentStart->toAtomString();
|
||||
// normal entries
|
||||
$income['entries'][$label] = app('steam')->bcround(($currency[$key]['earned'] ?? '0'), $currency['currency_decimal_places']);
|
||||
$expense['entries'][$label] = app('steam')->bcround(($currency[$key]['spent'] ?? '0'), $currency['currency_decimal_places']);
|
||||
|
||||
// converted entries
|
||||
$income['native_entries'][$label] = app('steam')->bcround(($currency[$key]['native_earned'] ?? '0'), $currency['native_decimal_places']);
|
||||
$expense['native_entries'][$label] = app('steam')->bcround(($currency[$key]['native_spent'] ?? '0'), $currency['native_decimal_places']);
|
||||
|
||||
// next loop
|
||||
$currentStart = app('navigation')->addPeriod($currentStart, $preferredRange, 0);
|
||||
}
|
||||
|
||||
$chartData[] = $income;
|
||||
$chartData[] = $expense;
|
||||
}
|
||||
return response()->json($this->clean($chartData));
|
||||
}
|
||||
|
||||
}
|
316
app/Api/V2/Controllers/Chart/BudgetController.php
Normal file
316
app/Api/V2/Controllers/Chart/BudgetController.php
Normal file
@@ -0,0 +1,316 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* BudgetController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\Chart;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Generic\DateRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\UserGroups\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroups\Budget\OperationsRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\CleansChartData;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class BudgetController
|
||||
*/
|
||||
class BudgetController extends Controller
|
||||
{
|
||||
use CleansChartData;
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
protected OperationsRepositoryInterface $opsRepository;
|
||||
private BudgetLimitRepositoryInterface $blRepository;
|
||||
private array $currencies = [];
|
||||
private TransactionCurrency $currency;
|
||||
private BudgetRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
|
||||
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$this->currency = app('amount')->getDefaultCurrency();
|
||||
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->repository->setUserGroup($userGroup);
|
||||
$this->opsRepository->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateRequest $request
|
||||
*
|
||||
* TODO see autocomplete/accountcontroller
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function dashboard(DateRequest $request): JsonResponse
|
||||
{
|
||||
$params = $request->getAll();
|
||||
/** @var Carbon $start */
|
||||
$start = $params['start'];
|
||||
/** @var Carbon $end */
|
||||
$end = $params['end'];
|
||||
|
||||
// code from FrontpageChartGenerator, but not in separate class
|
||||
$budgets = $this->repository->getActiveBudgets();
|
||||
$data = [];
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
// could return multiple arrays, so merge.
|
||||
$data = array_merge($data, $this->processBudget($budget, $start, $end));
|
||||
}
|
||||
return response()->json($this->clean($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function processBudget(Budget $budget, Carbon $start, Carbon $end): array
|
||||
{
|
||||
// get all limits:
|
||||
$limits = $this->blRepository->getBudgetLimits($budget, $start, $end);
|
||||
$rows = [];
|
||||
|
||||
// if no limits
|
||||
if (0 === $limits->count()) {
|
||||
// return as a single item in an array
|
||||
$rows = $this->noBudgetLimits($budget, $start, $end);
|
||||
}
|
||||
if ($limits->count() > 0) {
|
||||
$rows = $this->budgetLimits($budget, $limits);
|
||||
}
|
||||
// is always an array
|
||||
$return = [];
|
||||
foreach ($rows as $row) {
|
||||
$current = [
|
||||
'label' => $budget->name,
|
||||
'currency_id' => (string)$row['currency_id'],
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_name' => $row['currency_name'],
|
||||
'currency_decimal_places' => $row['currency_decimal_places'],
|
||||
'native_id' => (string)$row['native_id'],
|
||||
'native_code' => $row['native_code'],
|
||||
'native_name' => $row['native_name'],
|
||||
'native_decimal_places' => $row['native_decimal_places'],
|
||||
'period' => null,
|
||||
'start' => $row['start'],
|
||||
'end' => $row['end'],
|
||||
'entries' => [
|
||||
'spent' => $row['spent'],
|
||||
'left' => $row['left'],
|
||||
'overspent' => $row['overspent'],
|
||||
],
|
||||
'native_entries' => [
|
||||
'spent' => $row['native_spent'],
|
||||
'left' => $row['native_left'],
|
||||
'overspent' => $row['native_overspent'],
|
||||
],
|
||||
];
|
||||
$return[] = $current;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* When no budget limits are present, the expenses of the whole period are collected and grouped.
|
||||
* This is grouped per currency. Because there is no limit set, "left to spend" and "overspent" are empty.
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function noBudgetLimits(Budget $budget, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$budgetId = (int)$budget->id;
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, null, new Collection([$budget]));
|
||||
return $this->processExpenses($budgetId, $spent, $start, $end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared between the "noBudgetLimits" function and "processLimit".
|
||||
*
|
||||
* Will take a single set of expenses and return its info.
|
||||
*
|
||||
* @param int $budgetId
|
||||
* @param array $array
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function processExpenses(int $budgetId, array $array, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$converter = new ExchangeRateConverter();
|
||||
$return = [];
|
||||
|
||||
/**
|
||||
* This array contains the expenses in this budget. Grouped per currency.
|
||||
* The grouping is on the main currency only.
|
||||
*
|
||||
* @var int $currencyId
|
||||
* @var array $block
|
||||
*/
|
||||
foreach ($array as $currencyId => $block) {
|
||||
$this->currencies[$currencyId] = $this->currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
|
||||
$return[$currencyId] = $return[$currencyId] ?? [
|
||||
'currency_id' => (string)$currencyId,
|
||||
'currency_code' => $block['currency_code'],
|
||||
'currency_name' => $block['currency_name'],
|
||||
'currency_symbol' => $block['currency_symbol'],
|
||||
'currency_decimal_places' => (int)$block['currency_decimal_places'],
|
||||
'native_id' => (string)$this->currency->id,
|
||||
'native_code' => $this->currency->code,
|
||||
'native_name' => $this->currency->name,
|
||||
'native_symbol' => $this->currency->symbol,
|
||||
'native_decimal_places' => (int)$this->currency->decimal_places,
|
||||
'start' => $start->toAtomString(),
|
||||
'end' => $end->toAtomString(),
|
||||
'spent' => '0',
|
||||
'native_spent' => '0',
|
||||
'left' => '0',
|
||||
'native_left' => '0',
|
||||
'overspent' => '0',
|
||||
'native_overspent' => '0',
|
||||
|
||||
];
|
||||
$currentBudgetArray = $block['budgets'][$budgetId];
|
||||
//var_dump($return);
|
||||
/** @var array $journal */
|
||||
foreach ($currentBudgetArray['transaction_journals'] as $journal) {
|
||||
|
||||
// convert the amount to the native currency.
|
||||
$rate = $converter->getCurrencyRate($this->currencies[$currencyId], $this->currency, $journal['date']);
|
||||
$convertedAmount = bcmul($journal['amount'], $rate);
|
||||
if ($journal['foreign_currency_id'] === $this->currency->id) {
|
||||
$convertedAmount = $journal['foreign_amount'];
|
||||
}
|
||||
|
||||
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], $journal['amount']);
|
||||
$return[$currencyId]['native_spent'] = bcadd($return[$currencyId]['native_spent'], $convertedAmount);
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that processes each budget limit (per budget).
|
||||
*
|
||||
* If you have a budget limit in EUR, only transactions in EUR will be considered.
|
||||
* If you have a budget limit in GBP, only transactions in GBP will be considered.
|
||||
*
|
||||
* If you have a budget limit in EUR, and a transaction in GBP, it will not be considered for the EUR budget limit.
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param Collection $limits
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function budgetLimits(Budget $budget, Collection $limits): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in budgetLimits(#%d)', $budget->id));
|
||||
$data = [];
|
||||
/** @var BudgetLimit $limit */
|
||||
foreach ($limits as $limit) {
|
||||
$data = array_merge($data, $this->processLimit($budget, $limit));
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param BudgetLimit $limit
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function processLimit(Budget $budget, BudgetLimit $limit): array
|
||||
{
|
||||
$budgetId = (int)$budget->id;
|
||||
$end = clone $limit->end_date;
|
||||
$end->endOfDay();
|
||||
$spent = $this->opsRepository->listExpenses($limit->start_date, $end, null, new Collection([$budget]));
|
||||
$limitCurrencyId = (int)$limit->transaction_currency_id;
|
||||
$limitCurrency = $limit->transactionCurrency;
|
||||
$converter = new ExchangeRateConverter();
|
||||
$filtered = [];
|
||||
$rate = $converter->getCurrencyRate($limitCurrency, $this->currency, $limit->start_date);
|
||||
$convertedLimitAmount = bcmul($limit->amount, $rate);
|
||||
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($spent as $currencyId => $entry) {
|
||||
// only spent the entry where the entry's currency matches the budget limit's currency
|
||||
// so $filtered will only have 1 or 0 entries
|
||||
if ($entry['currency_id'] === $limitCurrencyId) {
|
||||
$filtered[$currencyId] = $entry;
|
||||
}
|
||||
}
|
||||
$result = $this->processExpenses($budgetId, $filtered, $limit->start_date, $end);
|
||||
if (1 === count($result)) {
|
||||
$compare = bccomp((string)$limit->amount, app('steam')->positive($result[$limitCurrencyId]['spent']));
|
||||
if (1 === $compare) {
|
||||
// convert this amount into the native currency:
|
||||
$result[$limitCurrencyId]['left'] = bcadd($limit->amount, $result[$limitCurrencyId]['spent']);
|
||||
$result[$limitCurrencyId]['native_left'] = bcadd($convertedLimitAmount, $result[$limitCurrencyId]['native_spent']);
|
||||
}
|
||||
if ($compare <= 0) {
|
||||
$result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, $result[$limitCurrencyId]['spent']));
|
||||
$result[$limitCurrencyId]['native_overspent'] = app('steam')->positive(bcadd($convertedLimitAmount, $result[$limitCurrencyId]['native_spent']));
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
}
|
144
app/Api/V2/Controllers/Chart/CategoryController.php
Normal file
144
app/Api/V2/Controllers/Chart/CategoryController.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* CategoryController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\Chart;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Generic\DateRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\CleansChartData;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class BudgetController
|
||||
*/
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
use CleansChartData;
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
private AccountRepositoryInterface $accountRepos;
|
||||
private CurrencyRepositoryInterface $currencyRepos;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->accountRepos = app(AccountRepositoryInterface::class);
|
||||
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->accountRepos->setUserGroup($userGroup);
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO may be worth to move to a handler but the data is simple enough.
|
||||
* TODO see autoComplete/account controller
|
||||
*
|
||||
* @param DateRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function dashboard(DateRequest $request): JsonResponse
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = $this->parameters->get('start');
|
||||
/** @var Carbon $end */
|
||||
$end = $this->parameters->get('end');
|
||||
$accounts = $this->accountRepos->getAccountsByType([AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::ASSET, AccountType::DEFAULT]);
|
||||
$default = app('amount')->getDefaultCurrency();
|
||||
$converter = new ExchangeRateConverter();
|
||||
$currencies = [];
|
||||
$return = [];
|
||||
|
||||
// get journals for entire period:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setRange($start, $end)->withAccountInformation();
|
||||
$collector->setXorAccounts($accounts)->withCategoryInformation();
|
||||
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::RECONCILIATION]);
|
||||
$journals = $collector->getExtractedJournals();
|
||||
|
||||
/** @var array $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
|
||||
$currencies[$currencyId] = $currency;
|
||||
$categoryName = null === $journal['category_name'] ? (string)trans('firefly.no_category') : $journal['category_name'];
|
||||
$amount = app('steam')->positive($journal['amount']);
|
||||
$nativeAmount = $converter->convert($default, $currency, $journal['date'], $amount);
|
||||
$key = sprintf('%s-%s', $categoryName, $currency->code);
|
||||
if ((int)$journal['foreign_currency_id'] === (int)$default->id) {
|
||||
$nativeAmount = app('steam')->positive($journal['foreign_amount']);
|
||||
}
|
||||
// create arrays
|
||||
$return[$key] = $return[$key] ?? [
|
||||
'label' => $categoryName,
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_name' => $currency->name,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => (int)$currency->decimal_places,
|
||||
'native_id' => (string)$default->id,
|
||||
'native_code' => $default->code,
|
||||
'native_name' => $default->name,
|
||||
'native_symbol' => $default->symbol,
|
||||
'native_decimal_places' => (int)$default->decimal_places,
|
||||
'period' => null,
|
||||
'start' => $start->toAtomString(),
|
||||
'end' => $end->toAtomString(),
|
||||
'amount' => '0',
|
||||
'native_amount' => '0',
|
||||
];
|
||||
|
||||
|
||||
// add monies
|
||||
$return[$key]['amount'] = bcadd($return[$key]['amount'], $amount);
|
||||
$return[$key]['native_amount'] = bcadd($return[$key]['native_amount'], $nativeAmount);
|
||||
}
|
||||
$return = array_values($return);
|
||||
|
||||
// order by native amount
|
||||
usort($return, function (array $a, array $b) {
|
||||
return (float)$a['native_amount'] < (float)$b['native_amount'] ? 1 : -1;
|
||||
});
|
||||
return response()->json($this->clean($return));
|
||||
}
|
||||
|
||||
}
|
@@ -64,54 +64,6 @@ class Controller extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param LengthAwarePaginator $paginator
|
||||
* @param AbstractTransformer $transformer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
final protected function jsonApiList(string $key, LengthAwarePaginator $paginator, AbstractTransformer $transformer): array
|
||||
{
|
||||
$manager = new Manager();
|
||||
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
$objects = $paginator->getCollection();
|
||||
|
||||
// the transformer, at this point, needs to collect information that ALL items in the collection
|
||||
// require, like meta data and stuff like that, and save it for later.
|
||||
$transformer->collectMetaData($objects);
|
||||
|
||||
$resource = new FractalCollection($objects, $transformer, $key);
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return $manager->createData($resource)->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON API object and returns it.
|
||||
*
|
||||
* @param string $key
|
||||
* @param Model $object
|
||||
* @param AbstractTransformer $transformer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
final protected function jsonApiObject(string $key, Model $object, AbstractTransformer $transformer): array
|
||||
{
|
||||
// create some objects:
|
||||
$manager = new Manager();
|
||||
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
$transformer->collectMetaData(new Collection([$object]));
|
||||
|
||||
$resource = new Item($object, $transformer, $key);
|
||||
|
||||
return $manager->createData($resource)->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO duplicate from V1 controller
|
||||
* Method to grab all parameters from the URL.
|
||||
@@ -141,21 +93,26 @@ class Controller extends BaseController
|
||||
// some date fields:
|
||||
foreach ($dates as $field) {
|
||||
$date = null;
|
||||
$obj = null;
|
||||
try {
|
||||
$date = request()->query->get($field);
|
||||
} catch (BadRequestException $e) {
|
||||
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field));
|
||||
Log::error($e->getMessage());
|
||||
$value = null;
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
$obj = null;
|
||||
if (null !== $date) {
|
||||
try {
|
||||
$obj = Carbon::parse($date);
|
||||
$obj = Carbon::parse($date, config('app.timezone'));
|
||||
} catch (InvalidDateException | InvalidFormatException $e) {
|
||||
// don't care
|
||||
app('log')->warning(sprintf('Ignored invalid date "%s" in API v2 controller parameter check: %s', substr($date, 0, 20), $e->getMessage()));
|
||||
}
|
||||
// out of range? set to null.
|
||||
if (null !== $obj && ($obj->year <= 1900 || $obj->year > 2099)) {
|
||||
app('log')->warning(sprintf('Refuse to use date "%s" in API v2 controller parameter check: %s', $field, $obj->toAtomString()));
|
||||
$obj = null;
|
||||
}
|
||||
}
|
||||
$bag->set($field, $obj);
|
||||
}
|
||||
@@ -179,4 +136,52 @@ class Controller extends BaseController
|
||||
|
||||
return $bag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param LengthAwarePaginator $paginator
|
||||
* @param AbstractTransformer $transformer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
final protected function jsonApiList(string $key, LengthAwarePaginator $paginator, AbstractTransformer $transformer): array
|
||||
{
|
||||
$manager = new Manager();
|
||||
$baseUrl = request()->getSchemeAndHttpHost() . '/api/v2';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
$objects = $paginator->getCollection();
|
||||
|
||||
// the transformer, at this point, needs to collect information that ALL items in the collection
|
||||
// require, like meta-data and stuff like that, and save it for later.
|
||||
$transformer->collectMetaData($objects);
|
||||
|
||||
$resource = new FractalCollection($objects, $transformer, $key);
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return $manager->createData($resource)->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON API object and returns it.
|
||||
*
|
||||
* @param string $key
|
||||
* @param Model $object
|
||||
* @param AbstractTransformer $transformer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
final protected function jsonApiObject(string $key, array | Model $object, AbstractTransformer $transformer): array
|
||||
{
|
||||
// create some objects:
|
||||
$manager = new Manager();
|
||||
$baseUrl = request()->getSchemeAndHttpHost() . '/api/v2';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
$transformer->collectMetaData(new Collection([$object]));
|
||||
|
||||
$resource = new Item($object, $transformer, $key);
|
||||
|
||||
return $manager->createData($resource)->toArray();
|
||||
}
|
||||
}
|
||||
|
101
app/Api/V2/Controllers/Model/Bill/ShowController.php
Normal file
101
app/Api/V2/Controllers/Model/Bill/ShowController.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* ShowController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\Model\Bill;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Repositories\UserGroups\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use FireflyIII\Transformers\V2\AccountTransformer;
|
||||
use FireflyIII\Transformers\V2\BillTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* Class ShowController
|
||||
*/
|
||||
class ShowController extends Controller
|
||||
{
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
private BillRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(BillRepositoryInterface::class);
|
||||
|
||||
// new way of user group validation
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->repository->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* TODO see autocomplete/accountcontroller for list.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$this->repository->correctOrder();
|
||||
$bills = $this->repository->getBills();
|
||||
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
|
||||
$count = $bills->count();
|
||||
$bills = $bills->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
$paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page'));
|
||||
$transformer = new BillTransformer();
|
||||
$transformer->setParameters($this->parameters); // give params to transformer
|
||||
|
||||
return response()
|
||||
->json($this->jsonApiList('subscriptions', $paginator, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO this endpoint is not documented
|
||||
*/
|
||||
public function show(Request $request, Bill $bill): JsonResponse
|
||||
{
|
||||
$transformer = new BillTransformer();
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
return response()
|
||||
->api($this->jsonApiObject('subscriptions', $bill, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
}
|
@@ -26,8 +26,9 @@ namespace FireflyIII\Api\V2\Controllers\Model\Bill;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Generic\DateRequest;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ConvertsExchangeRates;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\UserGroups\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
@@ -35,7 +36,7 @@ use Illuminate\Http\JsonResponse;
|
||||
*/
|
||||
class SumController extends Controller
|
||||
{
|
||||
use ConvertsExchangeRates;
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
private BillRepositoryInterface $repository;
|
||||
|
||||
@@ -49,6 +50,12 @@ class SumController extends Controller
|
||||
function ($request, $next) {
|
||||
$this->repository = app(BillRepositoryInterface::class);
|
||||
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->repository->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
@@ -58,35 +65,35 @@ class SumController extends Controller
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/transactions-sum/getBillsPaidTrSum
|
||||
*
|
||||
* TODO see autocomplete/accountcontroller for list.
|
||||
*
|
||||
* @param DateRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function paid(DateRequest $request): JsonResponse
|
||||
{
|
||||
$dates = $request->getAll();
|
||||
$result = $this->repository->sumPaidInRange($dates['start'], $dates['end']);
|
||||
$converted = $this->cerSum($result);
|
||||
$result = $this->repository->sumPaidInRange($this->parameters->get('start'), $this->parameters->get('end'));
|
||||
|
||||
// convert to JSON response:
|
||||
return response()->api($converted);
|
||||
return response()->api(array_values($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/transactions-sum/getBillsUnpaidTrSum
|
||||
*
|
||||
* TODO see autocomplete/accountcontroller for list.
|
||||
*
|
||||
* @param DateRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function unpaid(DateRequest $request): JsonResponse
|
||||
{
|
||||
$dates = $request->getAll();
|
||||
$result = $this->repository->sumUnpaidInRange($dates['start'], $dates['end']);
|
||||
$converted = $this->cerSum($result);
|
||||
$result = $this->repository->sumUnpaidInRange($this->parameters->get('start'), $this->parameters->get('end'));
|
||||
|
||||
// convert to JSON response:
|
||||
return response()->api($converted);
|
||||
return response()->api(array_values($result));
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,9 @@ use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* Class ListController
|
||||
*/
|
||||
class ListController extends Controller
|
||||
{
|
||||
private BudgetRepositoryInterface $repository;
|
||||
@@ -57,6 +60,8 @@ class ListController extends Controller
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
echo 'this needs move to Administration';
|
||||
exit;
|
||||
$collection = $this->repository->getActiveBudgets();
|
||||
$total = $collection->count();
|
||||
$collection->slice($this->pageSize * $this->parameters->get('page'), $this->pageSize);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* ShowController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
@@ -21,10 +21,13 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\Model\Budget;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Generic\DateRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ConvertsExchangeRates;
|
||||
@@ -32,6 +35,7 @@ use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class ShowController
|
||||
* TODO lots of deprecated code here.
|
||||
*/
|
||||
class ShowController extends Controller
|
||||
{
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V2\Controllers\Model\Budget;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Generic\DateRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ConvertsExchangeRates;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
@@ -32,6 +32,9 @@ use FireflyIII\Transformers\V2\BudgetLimitTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* Class ListController
|
||||
*/
|
||||
class ListController extends Controller
|
||||
{
|
||||
private BudgetLimitRepositoryInterface $repository;
|
||||
|
84
app/Api/V2/Controllers/Model/PiggyBank/ShowController.php
Normal file
84
app/Api/V2/Controllers/Model/PiggyBank/ShowController.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* ShowController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\Model\PiggyBank;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\UserGroups\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use FireflyIII\Transformers\V2\PiggyBankTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* Class ShowController
|
||||
*/
|
||||
class ShowController extends Controller
|
||||
{
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
private PiggyBankRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(PiggyBankRepositoryInterface::class);
|
||||
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->repository->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* TODO see autocomplete/accountcontroller for list.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$piggies = $this->repository->getPiggyBanks();
|
||||
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
|
||||
$count = $piggies->count();
|
||||
$piggies = $piggies->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
$paginator = new LengthAwarePaginator($piggies, $count, $pageSize, $this->parameters->get('page'));
|
||||
$transformer = new PiggyBankTransformer();
|
||||
$transformer->setParameters($this->parameters); // give params to transformer
|
||||
|
||||
return response()
|
||||
->json($this->jsonApiList('piggy-banks', $paginator, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
}
|
128
app/Api/V2/Controllers/Model/Transaction/StoreController.php
Normal file
128
app/Api/V2/Controllers/Model/Transaction/StoreController.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* StoreController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\Model\Transaction;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Model\Transaction\StoreRequest;
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
|
||||
use FireflyIII\Rules\IsDuplicateTransaction;
|
||||
use FireflyIII\Transformers\V2\TransactionGroupTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
/**
|
||||
* Class StoreController
|
||||
*/
|
||||
class StoreController extends Controller
|
||||
{
|
||||
private TransactionGroupRepositoryInterface $groupRepository;
|
||||
|
||||
/**
|
||||
* TransactionController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->groupRepository = app(TransactionGroupRepositoryInterface::class);
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO this method is practically the same as the V1 method and borrows as much code as possible.
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws FireflyException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function post(StoreRequest $request): JsonResponse
|
||||
{
|
||||
|
||||
app('log')->debug('Now in API v2 StoreController::store()');
|
||||
$data = $request->getAll();
|
||||
$userGroup = $request->getUserGroup();
|
||||
$data['user_group'] = $userGroup;
|
||||
|
||||
// overrule user group and see where we end up.
|
||||
// what happens when we refer to a budget that is not in this user group?
|
||||
|
||||
app('log')->channel('audit')->info('Store new transaction over API.', $data);
|
||||
|
||||
try {
|
||||
$transactionGroup = $this->groupRepository->store($data);
|
||||
} catch (DuplicateTransactionException $e) {
|
||||
app('log')->warning('Caught a duplicate transaction. Return error message.');
|
||||
$validator = Validator::make(
|
||||
['transactions' => [['description' => $e->getMessage()]]],
|
||||
['transactions.0.description' => new IsDuplicateTransaction()]
|
||||
);
|
||||
throw new ValidationException($validator, 0, $e);
|
||||
} catch (FireflyException $e) {
|
||||
app('log')->warning('Caught an exception. Return error message.');
|
||||
app('log')->error($e->getMessage());
|
||||
$message = sprintf('Internal exception: %s', $e->getMessage());
|
||||
$validator = Validator::make(['transactions' => [['description' => $message]]], ['transactions.0.description' => new IsDuplicateTransaction()]);
|
||||
throw new ValidationException($validator, 0, $e);
|
||||
}
|
||||
app('preferences')->mark();
|
||||
$applyRules = $data['apply_rules'] ?? true;
|
||||
$fireWebhooks = $data['fire_webhooks'] ?? true;
|
||||
event(new StoredTransactionGroup($transactionGroup, $applyRules, $fireWebhooks));
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setUser($admin)
|
||||
// filter on transaction group.
|
||||
->setTransactionGroup($transactionGroup);
|
||||
|
||||
$selectedGroup = $collector->getGroups()->first();
|
||||
if (null === $selectedGroup) {
|
||||
throw new FireflyException('200032: Cannot find transaction. Possibly, a rule deleted this transaction after its creation.');
|
||||
}
|
||||
|
||||
$transformer = new TransactionGroupTransformer();
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
return response()
|
||||
->api($this->jsonApiObject('transactions', $selectedGroup, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
|
||||
}
|
555
app/Api/V2/Controllers/Summary/BasicController.php
Normal file
555
app/Api/V2/Controllers/Summary/BasicController.php
Normal file
@@ -0,0 +1,555 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* SummaryController.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 FireflyIII\Api\V2\Controllers\Summary;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Generic\DateRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Helpers\Report\NetWorthInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroups\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroups\Budget\AvailableBudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroups\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroups\Budget\OperationsRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class BasicController
|
||||
*/
|
||||
class BasicController extends Controller
|
||||
{
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
private AvailableBudgetRepositoryInterface $abRepository;
|
||||
private AccountRepositoryInterface $accountRepository;
|
||||
private BillRepositoryInterface $billRepository;
|
||||
private BudgetRepositoryInterface $budgetRepository;
|
||||
private CurrencyRepositoryInterface $currencyRepos;
|
||||
private OperationsRepositoryInterface $opsRepository;
|
||||
|
||||
/**
|
||||
* BasicController constructor.
|
||||
*
|
||||
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->abRepository = app(AvailableBudgetRepositoryInterface::class);
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
$this->billRepository = app(BillRepositoryInterface::class);
|
||||
$this->budgetRepository = app(BudgetRepositoryInterface::class);
|
||||
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
||||
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->abRepository->setUserGroup($userGroup);
|
||||
$this->accountRepository->setUserGroup($userGroup);
|
||||
$this->billRepository->setUserGroup($userGroup);
|
||||
$this->budgetRepository->setUserGroup($userGroup);
|
||||
$this->opsRepository->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/summary/getBasicSummary
|
||||
*
|
||||
* @param DateRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function basic(DateRequest $request): JsonResponse
|
||||
{
|
||||
// parameters for boxes:
|
||||
$start = $this->parameters->get('start');
|
||||
$end = $this->parameters->get('end');
|
||||
|
||||
// balance information:
|
||||
$balanceData = $this->getBalanceInformation($start, $end);
|
||||
$billData = $this->getBillInformation($start, $end);
|
||||
$spentData = $this->getLeftToSpendInfo($start, $end);
|
||||
$netWorthData = $this->getNetWorthInfo($start, $end);
|
||||
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
|
||||
return response()->json($total);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getBalanceInformation(Carbon $start, Carbon $end): array
|
||||
{
|
||||
// prep some arrays:
|
||||
$incomes = [
|
||||
'native' => '0',
|
||||
];
|
||||
$expenses = [
|
||||
'native' => '0',
|
||||
];
|
||||
$sums = [
|
||||
'native' => '0',
|
||||
];
|
||||
$return = [];
|
||||
$currencies = [];
|
||||
$converter = new ExchangeRateConverter();
|
||||
$default = app('amount')->getDefaultCurrency();
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
// collect income of user using the new group collector.
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setRange($start, $end)
|
||||
->setUserGroup($user->userGroup)
|
||||
// set page to retrieve
|
||||
->setPage($this->parameters->get('page'))
|
||||
// set types of transactions to return.
|
||||
->setTypes([TransactionType::DEPOSIT])
|
||||
->setRange($start, $end);
|
||||
|
||||
$set = $collector->getExtractedJournals();
|
||||
/** @var array $transactionJournal */
|
||||
foreach ($set as $transactionJournal) {
|
||||
// transaction info:
|
||||
$currencyId = (int)$transactionJournal['currency_id'];
|
||||
$amount = bcmul($transactionJournal['amount'], '-1');
|
||||
$currency = $currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
|
||||
$currencies[$currencyId] = $currency;
|
||||
$nativeAmount = $converter->convert($currency, $default, $transactionJournal['date'], $amount);
|
||||
if ((int)$transactionJournal['foreign_currency_id'] === (int)$default->id) {
|
||||
// use foreign amount instead
|
||||
$nativeAmount = $transactionJournal['foreign_amount'];
|
||||
}
|
||||
// prep the arrays
|
||||
$incomes[$currencyId] = $incomes[$currencyId] ?? '0';
|
||||
$incomes['native'] = $incomes['native'] ?? '0';
|
||||
$sums[$currencyId] = $sums[$currencyId] ?? '0';
|
||||
$sums['native'] = $sums['native'] ?? '0';
|
||||
|
||||
// add values:
|
||||
$incomes[$currencyId] = bcadd($incomes[$currencyId], $amount);
|
||||
$sums[$currencyId] = bcadd($sums[$currencyId], $amount);
|
||||
$incomes['native'] = bcadd($incomes['native'], $nativeAmount);
|
||||
$sums['native'] = bcadd($sums['native'], $nativeAmount);
|
||||
}
|
||||
|
||||
// collect expenses of user using the new group collector.
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setRange($start, $end)
|
||||
->setUserGroup($user->userGroup)
|
||||
// set page to retrieve
|
||||
->setPage($this->parameters->get('page'))
|
||||
// set types of transactions to return.
|
||||
->setTypes([TransactionType::WITHDRAWAL])
|
||||
->setRange($start, $end);
|
||||
$set = $collector->getExtractedJournals();
|
||||
|
||||
/** @var array $transactionJournal */
|
||||
foreach ($set as $transactionJournal) {
|
||||
// transaction info
|
||||
$currencyId = (int)$transactionJournal['currency_id'];
|
||||
$amount = $transactionJournal['amount'];
|
||||
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
|
||||
$currencies[$currencyId] = $currency;
|
||||
$nativeAmount = $converter->convert($currency, $default, $transactionJournal['date'], $amount);
|
||||
if ((int)$transactionJournal['foreign_currency_id'] === (int)$default->id) {
|
||||
// use foreign amount instead
|
||||
$nativeAmount = $transactionJournal['foreign_amount'];
|
||||
}
|
||||
|
||||
// prep arrays
|
||||
$expenses[$currencyId] = $expenses[$currencyId] ?? '0';
|
||||
$expenses['native'] = $expenses['native'] ?? '0';
|
||||
$sums[$currencyId] = $sums[$currencyId] ?? '0';
|
||||
$sums['native'] = $sums['native'] ?? '0';
|
||||
|
||||
// add values
|
||||
$expenses[$currencyId] = bcadd($expenses[$currencyId], $amount);
|
||||
$sums[$currencyId] = bcadd($sums[$currencyId], $amount);
|
||||
$expenses['native'] = bcadd($expenses['native'], $nativeAmount);
|
||||
$sums['native'] = bcadd($sums['native'], $nativeAmount);
|
||||
}
|
||||
|
||||
// create special array for native currency:
|
||||
$return[] = [
|
||||
'key' => 'balance-in-native',
|
||||
'value' => $sums['native'],
|
||||
'currency_id' => (string)$default->id,
|
||||
'currency_code' => $default->code,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_decimal_places' => $default->decimal_places,
|
||||
];
|
||||
$return[] = [
|
||||
'key' => 'spent-in-native',
|
||||
'value' => $expenses['native'],
|
||||
'currency_id' => (string)$default->id,
|
||||
'currency_code' => $default->code,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_decimal_places' => $default->decimal_places,
|
||||
];
|
||||
$return[] = [
|
||||
'key' => 'earned-in-native',
|
||||
'value' => $incomes['native'],
|
||||
'currency_id' => (string)$default->id,
|
||||
'currency_code' => $default->code,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_decimal_places' => $default->decimal_places,
|
||||
];
|
||||
|
||||
// format amounts:
|
||||
$keys = array_keys($sums);
|
||||
foreach ($keys as $currencyId) {
|
||||
if ('native' === $currencyId) {
|
||||
// skip native entries.
|
||||
continue;
|
||||
}
|
||||
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
|
||||
$currencies[$currencyId] = $currency;
|
||||
// create objects for big array.
|
||||
$return[] = [
|
||||
'key' => sprintf('balance-in-%s', $currency->code),
|
||||
'value' => $sums[$currencyId] ?? '0',
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
];
|
||||
$return[] = [
|
||||
'key' => sprintf('spent-in-%s', $currency->code),
|
||||
'value' => $expenses[$currencyId] ?? '0',
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
];
|
||||
$return[] = [
|
||||
'key' => sprintf('earned-in-%s', $currency->code),
|
||||
'value' => $incomes[$currencyId] ?? '0',
|
||||
'currency_id' => (string)$currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getBillInformation(Carbon $start, Carbon $end): array
|
||||
{
|
||||
/*
|
||||
* Since both this method and the chart use the exact same data, we can suffice
|
||||
* with calling the one method in the bill repository that will get this amount.
|
||||
*/
|
||||
$paidAmount = $this->billRepository->sumPaidInRange($start, $end);
|
||||
$unpaidAmount = $this->billRepository->sumUnpaidInRange($start, $end);
|
||||
|
||||
$return = [];
|
||||
/**
|
||||
* @var array $info
|
||||
*/
|
||||
foreach ($paidAmount as $info) {
|
||||
$amount = bcmul($info['sum'], '-1');
|
||||
$nativeAmount = bcmul($info['native_sum'], '-1');
|
||||
$return[] = [
|
||||
'key' => sprintf('bills-paid-in-%s', $info['currency_code']),
|
||||
'value' => $amount,
|
||||
'currency_id' => (string)$info['currency_id'],
|
||||
'currency_code' => $info['currency_code'],
|
||||
'currency_symbol' => $info['currency_symbol'],
|
||||
'currency_decimal_places' => $info['currency_decimal_places'],
|
||||
];
|
||||
$return[] = [
|
||||
'key' => 'bills-paid-in-native',
|
||||
'value' => $nativeAmount,
|
||||
'currency_id' => (string)$info['native_id'],
|
||||
'currency_code' => $info['native_code'],
|
||||
'currency_symbol' => $info['native_symbol'],
|
||||
'currency_decimal_places' => $info['native_decimal_places'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array $info
|
||||
*/
|
||||
foreach ($unpaidAmount as $info) {
|
||||
$amount = bcmul($info['sum'], '-1');
|
||||
$nativeAmount = bcmul($info['native_sum'], '-1');
|
||||
$return[] = [
|
||||
'key' => sprintf('bills-unpaid-in-%s', $info['currency_code']),
|
||||
'value' => $amount,
|
||||
'currency_id' => (string)$info['currency_id'],
|
||||
'currency_code' => $info['currency_code'],
|
||||
'currency_symbol' => $info['currency_symbol'],
|
||||
'currency_decimal_places' => $info['currency_decimal_places'],
|
||||
];
|
||||
$return[] = [
|
||||
'key' => 'bills-unpaid-in-native',
|
||||
'value' => $nativeAmount,
|
||||
'currency_id' => (string)$info['native_id'],
|
||||
'currency_code' => $info['native_code'],
|
||||
'currency_symbol' => $info['native_symbol'],
|
||||
'currency_decimal_places' => $info['native_decimal_places'],
|
||||
];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getLeftToSpendInfo(Carbon $start, Carbon $end): array
|
||||
{
|
||||
app('log')->debug('Now in getLeftToSpendInfo');
|
||||
$return = [];
|
||||
$today = today(config('app.timezone'));
|
||||
$available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
|
||||
$budgets = $this->budgetRepository->getActiveBudgets();
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, null, $budgets);
|
||||
$default = app('amount')->getDefaultCurrency();
|
||||
$currencies = [];
|
||||
$converter = new ExchangeRateConverter();
|
||||
|
||||
// native info:
|
||||
$nativeLeft = [
|
||||
'key' => 'left-to-spend-in-native',
|
||||
'value' => '0',
|
||||
'currency_id' => (string)$default->id,
|
||||
'currency_code' => $default->code,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_decimal_places' => (int)$default->decimal_places,
|
||||
];
|
||||
$nativePerDay = [
|
||||
'key' => 'left-per-day-to-spend-in-native',
|
||||
'value' => '0',
|
||||
'currency_id' => (string)$default->id,
|
||||
'currency_code' => $default->code,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_decimal_places' => (int)$default->decimal_places,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var int $currencyId
|
||||
* @var array $row
|
||||
*/
|
||||
foreach ($spent as $currencyId => $row) {
|
||||
app('log')->debug(sprintf('Processing spent array in currency #%d', $currencyId));
|
||||
$currencyId = (int)$currencyId;
|
||||
$spent = '0';
|
||||
$spentNative = '0';
|
||||
// get the sum from the array of transactions (double loop but who cares)
|
||||
/** @var array $budget */
|
||||
foreach ($row['budgets'] as $budget) {
|
||||
app('log')->debug(sprintf('Processing expenses in budget "%s".', $budget['name']));
|
||||
/** @var array $journal */
|
||||
foreach ($budget['transaction_journals'] as $journal) {
|
||||
$journalCurrencyId = $journal['currency_id'];
|
||||
$currency = $currencies[$journalCurrencyId] ?? $this->currencyRepos->find($journalCurrencyId);
|
||||
$currencies[$currencyId] = $currency;
|
||||
$amount = app('steam')->negative($journal['amount']);
|
||||
$amountNative = $converter->convert($default, $currency, $start, $amount);
|
||||
if ((int)$journal['foreign_currency_id'] === (int)$default->id) {
|
||||
$amountNative = $journal['foreign_amount'];
|
||||
}
|
||||
$spent = bcadd($spent, $amount);
|
||||
$spentNative = bcadd($spentNative, $amountNative);
|
||||
}
|
||||
app('log')->debug(sprintf('Total spent in budget "%s" is %s', $budget['name'], $spent));
|
||||
}
|
||||
|
||||
// either an amount was budgeted or 0 is available.
|
||||
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
|
||||
$currencies[$currencyId] = $currency;
|
||||
$amount = $available[$currencyId]['amount'] ?? '0';
|
||||
$amountNative = $available[$currencyId]['native_amount'] ?? '0';
|
||||
$left = bcadd($amount, $spent);
|
||||
$leftNative = bcadd($amountNative, $spentNative);
|
||||
app('log')->debug(sprintf('Available amount is %s', $amount));
|
||||
app('log')->debug(sprintf('Amount left is %s', $left));
|
||||
|
||||
// how much left per day?
|
||||
$days = $today->diffInDays($end) + 1;
|
||||
$perDay = '0';
|
||||
$perDayNative = '0';
|
||||
if (0 !== $days && bccomp($left, '0') > -1) {
|
||||
$perDay = bcdiv($left, (string)$days);
|
||||
}
|
||||
if (0 !== $days && bccomp($leftNative, '0') > -1) {
|
||||
$perDayNative = bcdiv($leftNative, (string)$days);
|
||||
}
|
||||
|
||||
// left
|
||||
$return[] = [
|
||||
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
|
||||
'value' => $left,
|
||||
'currency_id' => (string)$row['currency_id'],
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_symbol' => $row['currency_symbol'],
|
||||
'currency_decimal_places' => (int)$row['currency_decimal_places'],
|
||||
];
|
||||
// left (native)
|
||||
$nativeLeft['value'] = $leftNative;
|
||||
|
||||
// left per day:
|
||||
$return[] = [
|
||||
'key' => sprintf('left-per-day-to-spend-in-%s', $row['currency_code']),
|
||||
'value' => $perDay,
|
||||
'currency_id' => (string)$row['currency_id'],
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_symbol' => $row['currency_symbol'],
|
||||
'currency_decimal_places' => (int)$row['currency_decimal_places'],
|
||||
];
|
||||
|
||||
// left per day (native)
|
||||
$nativePerDay['value'] = $perDayNative;
|
||||
}
|
||||
$return[] = $nativeLeft;
|
||||
$return[] = $nativePerDay;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getNetWorthInfo(Carbon $start, Carbon $end): array
|
||||
{
|
||||
/** @var UserGroup $userGroup */
|
||||
$userGroup = auth()->user()->userGroup;
|
||||
$date = today(config('app.timezone'))->startOfDay();
|
||||
// start and end in the future? use $end
|
||||
if ($this->notInDateRange($date, $start, $end)) {
|
||||
/** @var Carbon $date */
|
||||
$date = session('end', today(config('app.timezone'))->endOfMonth());
|
||||
}
|
||||
|
||||
/** @var NetWorthInterface $netWorthHelper */
|
||||
$netWorthHelper = app(NetWorthInterface::class);
|
||||
$netWorthHelper->setUserGroup($userGroup);
|
||||
$allAccounts = $this->accountRepository->getActiveAccountsByType(
|
||||
[AccountType::ASSET, AccountType::DEFAULT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::DEBT]
|
||||
);
|
||||
|
||||
// filter list on preference of being included.
|
||||
$filtered = $allAccounts->filter(
|
||||
function (Account $account) {
|
||||
$includeNetWorth = $this->accountRepository->getMetaValue($account, 'include_net_worth');
|
||||
|
||||
return null === $includeNetWorth || '1' === $includeNetWorth;
|
||||
}
|
||||
);
|
||||
|
||||
$netWorthSet = $netWorthHelper->byAccounts($filtered, $date);
|
||||
$return = [];
|
||||
// in native amount
|
||||
$return[] = [
|
||||
'key' => 'net-worth-in-native',
|
||||
'value' => $netWorthSet['native']['balance'],
|
||||
'currency_id' => (string)$netWorthSet['native']['currency_id'],
|
||||
'currency_code' => $netWorthSet['native']['currency_code'],
|
||||
'currency_symbol' => $netWorthSet['native']['currency_symbol'],
|
||||
'currency_decimal_places' => $netWorthSet['native']['currency_decimal_places'],
|
||||
];
|
||||
foreach ($netWorthSet as $key => $data) {
|
||||
if ('native' === $key) {
|
||||
continue;
|
||||
}
|
||||
$return[] = [
|
||||
'key' => sprintf('net-worth-in-%s', $data['currency_code']),
|
||||
'value' => $data['balance'],
|
||||
'currency_id' => (string)$data['currency_id'],
|
||||
'currency_code' => $data['currency_code'],
|
||||
'currency_symbol' => $data['currency_symbol'],
|
||||
'currency_decimal_places' => $data['currency_decimal_places'],
|
||||
];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if date is outside session range.
|
||||
*
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function notInDateRange(Carbon $date, Carbon $start, Carbon $end): bool // Validate a preference
|
||||
{
|
||||
$result = false;
|
||||
if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
|
||||
$result = true;
|
||||
}
|
||||
// start and end in the past? use $end
|
||||
if ($start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date)) {
|
||||
$result = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
* NetWorthController.php
|
||||
* Copyright (c) 2022 james@firefly-iii.org
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -22,11 +22,13 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers;
|
||||
namespace FireflyIII\Api\V2\Controllers\Summary;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Generic\SingleDateRequest;
|
||||
use FireflyIII\Helpers\Report\NetWorthInterface;
|
||||
use FireflyIII\Support\Http\Api\ConvertsExchangeRates;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
@@ -34,6 +36,7 @@ use Illuminate\Http\JsonResponse;
|
||||
*/
|
||||
class NetWorthController extends Controller
|
||||
{
|
||||
use ValidatesUserGroupTrait;
|
||||
use ConvertsExchangeRates;
|
||||
|
||||
private NetWorthInterface $netWorth;
|
||||
@@ -47,7 +50,12 @@ class NetWorthController extends Controller
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->netWorth = app(NetWorthInterface::class);
|
||||
$this->netWorth->setUser(auth()->user());
|
||||
|
||||
// new way of user group validation
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->netWorth->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
@@ -24,6 +24,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\System;
|
||||
|
||||
/**
|
||||
* Class ConfigurationController
|
||||
*/
|
||||
class ConfigurationController
|
||||
{
|
||||
}
|
||||
|
@@ -26,6 +26,9 @@ namespace FireflyIII\Api\V2\Controllers\System;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
|
||||
/**
|
||||
* Class DebugController
|
||||
*/
|
||||
class DebugController extends Controller
|
||||
{
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
* VersionUpdateController.php
|
||||
* Copyright (c) 2022 james@firefly-iii.org
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -22,7 +22,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers;
|
||||
namespace FireflyIII\Api\V2\Controllers\System;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
|
||||
/**
|
||||
* Class VersionUpdateController
|
@@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
* AccountController.php
|
||||
* Copyright (c) 2022 james@firefly-iii.org
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -25,7 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V2\Controllers\Transaction\List;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Transaction\ListRequest;
|
||||
use FireflyIII\Api\V2\Request\Model\Transaction\ListRequest;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
@@ -49,19 +49,17 @@ class AccountController extends Controller
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function listTransactions(ListRequest $request, Account $account): JsonResponse
|
||||
public function list(ListRequest $request, Account $account): JsonResponse
|
||||
{
|
||||
// collect transactions:
|
||||
$type = $request->get('type') ?? 'default';
|
||||
$limit = (int)$request->get('limit');
|
||||
$page = (int)$request->get('page');
|
||||
$limit = $request->getLimit();
|
||||
$page = $request->getPage();
|
||||
$page = max($page, 1);
|
||||
|
||||
if ($limit > 0 && $limit <= $this->pageSize) {
|
||||
$this->pageSize = $limit;
|
||||
}
|
||||
|
||||
$types = $this->mapTransactionTypes($type);
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
@@ -69,15 +67,25 @@ class AccountController extends Controller
|
||||
->withAPIInformation()
|
||||
->setLimit($this->pageSize)
|
||||
->setPage($page)
|
||||
->setTypes($types);
|
||||
->setTypes($request->getTransactionTypes());
|
||||
|
||||
// TODO date filter
|
||||
//if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
|
||||
// $collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
|
||||
//}
|
||||
$start = $request->getStartDate();
|
||||
$end = $request->getEndDate();
|
||||
if (null !== $start) {
|
||||
$collector->setStart($start);
|
||||
}
|
||||
if (null !== $end) {
|
||||
$collector->setEnd($start);
|
||||
}
|
||||
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
$paginator->setPath(route('api.v2.accounts.transactions', [$account->id])); // TODO . $this->buildParams()
|
||||
$paginator->setPath(
|
||||
sprintf(
|
||||
'%s?%s',
|
||||
route('api.v2.accounts.transactions', [$account->id]),
|
||||
$request->buildParams()
|
||||
)
|
||||
);
|
||||
|
||||
return response()
|
||||
->json($this->jsonApiList('transactions', $paginator, new TransactionGroupTransformer()))
|
||||
|
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/*
|
||||
* TransactionController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\Transaction\List;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Model\Transaction\ListRequest;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Transformers\V2\TransactionGroupTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class TransactionController
|
||||
*/
|
||||
class TransactionController extends Controller
|
||||
{
|
||||
/**
|
||||
* @param ListRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function list(ListRequest $request): JsonResponse
|
||||
{
|
||||
// collect transactions:
|
||||
$limit = $request->getLimit();
|
||||
$page = $request->getPage();
|
||||
$page = max($page, 1);
|
||||
|
||||
if ($limit > 0 && $limit <= $this->pageSize) {
|
||||
$this->pageSize = $limit;
|
||||
}
|
||||
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUserGroup(auth()->user()->userGroup)
|
||||
->withAPIInformation()
|
||||
->setLimit($this->pageSize)
|
||||
->setPage($page)
|
||||
->setTypes($request->getTransactionTypes());
|
||||
|
||||
$start = $this->parameters->get('start');
|
||||
$end = $this->parameters->get('end');
|
||||
if (null !== $start) {
|
||||
$collector->setStart($start);
|
||||
}
|
||||
if (null !== $end) {
|
||||
$collector->setEnd($end);
|
||||
}
|
||||
|
||||
// $collector->dumpQuery();
|
||||
// exit;
|
||||
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
$paginator->setPath(
|
||||
sprintf(
|
||||
'%s?%s',
|
||||
route('api.v2.transactions.list'),
|
||||
$request->buildParams()
|
||||
)
|
||||
);
|
||||
|
||||
return response()
|
||||
->json($this->jsonApiList('transactions', $paginator, new TransactionGroupTransformer()))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
* BillController.php
|
||||
* Copyright (c) 2022 james@firefly-iii.org
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
|
77
app/Api/V2/Controllers/UserGroup/DestroyController.php
Normal file
77
app/Api/V2/Controllers/UserGroup/DestroyController.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* DestroyController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\UserGroup;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Class DestroyController
|
||||
*/
|
||||
class DestroyController extends Controller
|
||||
{
|
||||
private UserGroupRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(UserGroupRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param UserGroup $userGroup
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function destroy(Request $request, UserGroup $userGroup): JsonResponse
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
// need owner role or system owner role to delete user group.
|
||||
$access = $user->hasRoleInGroup($userGroup, UserRoleEnum::OWNER, false, true);
|
||||
if (false === $access) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
$this->repository->destroy($userGroup);
|
||||
return response()->json([], 204);
|
||||
}
|
||||
}
|
101
app/Api/V2/Controllers/UserGroup/ShowController.php
Normal file
101
app/Api/V2/Controllers/UserGroup/ShowController.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* ShowController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\UserGroup;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
|
||||
use FireflyIII\Transformers\V2\UserGroupTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class ShowController
|
||||
*/
|
||||
class ShowController extends Controller
|
||||
{
|
||||
private UserGroupRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(UserGroupRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$collection = new Collection();
|
||||
// if the user has the system owner role, get all. Otherwise, get only the users' groups.
|
||||
if (!auth()->user()->hasRole('owner')) {
|
||||
$collection = $this->repository->get();
|
||||
}
|
||||
if (auth()->user()->hasRole('owner')) {
|
||||
$collection = $this->repository->getAll();
|
||||
}
|
||||
$count = $collection->count();
|
||||
$userGroups = $collection->slice(($this->parameters->get('page') - 1) * $this->pageSize, $this->pageSize);
|
||||
|
||||
$paginator = new LengthAwarePaginator($userGroups, $count, $this->pageSize, $this->parameters->get('page'));
|
||||
$transformer = new UserGroupTransformer();
|
||||
$transformer->setParameters($this->parameters); // give params to transformer
|
||||
|
||||
return response()
|
||||
->json($this->jsonApiList('user-groups', $paginator, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param UserGroup $userGroup
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function show(Request $request, UserGroup $userGroup): JsonResponse
|
||||
{
|
||||
$transformer = new UserGroupTransformer();
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
return response()
|
||||
->api($this->jsonApiObject('user-groups', $userGroup, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
}
|
73
app/Api/V2/Controllers/UserGroup/StoreController.php
Normal file
73
app/Api/V2/Controllers/UserGroup/StoreController.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* StoreController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\UserGroup;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\UserGroup\StoreRequest;
|
||||
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
|
||||
use FireflyIII\Transformers\V2\UserGroupTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class StoreController
|
||||
*/
|
||||
class StoreController extends Controller
|
||||
{
|
||||
private UserGroupRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(UserGroupRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StoreRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function store(StoreRequest $request): JsonResponse
|
||||
{
|
||||
$all = $request->getAll();
|
||||
$userGroup = $this->repository->store($all);
|
||||
$transformer = new UserGroupTransformer();
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
return response()
|
||||
->api($this->jsonApiObject('user-groups', $userGroup, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
}
|
96
app/Api/V2/Controllers/UserGroup/UpdateController.php
Normal file
96
app/Api/V2/Controllers/UserGroup/UpdateController.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* UpdateController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Controllers\UserGroup;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\UserGroup\UpdateMembershipRequest;
|
||||
use FireflyIII\Api\V2\Request\UserGroup\UpdateRequest;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
|
||||
use FireflyIII\Transformers\V2\UserGroupTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class UpdateController
|
||||
*/
|
||||
class UpdateController extends Controller
|
||||
{
|
||||
// basic update van group
|
||||
// add user, add rights, remove user, remove rights.
|
||||
|
||||
private UserGroupRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(UserGroupRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UpdateRequest $request
|
||||
* @param UserGroup $userGroup
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function update(UpdateRequest $request, UserGroup $userGroup): JsonResponse
|
||||
{
|
||||
$all = $request->getAll();
|
||||
$userGroup = $this->repository->update($userGroup, $all);
|
||||
$transformer = new UserGroupTransformer();
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
return response()
|
||||
->api($this->jsonApiObject('user-groups', $userGroup, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UpdateMembershipRequest $request
|
||||
* @param UserGroup $userGroup
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function updateMembership(UpdateMembershipRequest $request, UserGroup $userGroup): JsonResponse
|
||||
{
|
||||
$all = $request->getAll();
|
||||
$userGroup = $this->repository->updateMembership($userGroup, $all);
|
||||
$transformer = new UserGroupTransformer();
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
return response()
|
||||
->api($this->jsonApiObject('user-groups', $userGroup, $transformer))
|
||||
->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
}
|
@@ -23,13 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Request\Autocomplete;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\UserRole;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use FireflyIII\User;
|
||||
use FireflyIII\Validation\Administration\ValidatesAdministrationAccess;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
@@ -40,11 +38,10 @@ class AutocompleteRequest extends FormRequest
|
||||
{
|
||||
use ConvertsDataTypes;
|
||||
use ChecksLogin;
|
||||
use ValidatesAdministrationAccess;
|
||||
protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS];
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getData(): array
|
||||
{
|
||||
@@ -66,7 +63,6 @@ class AutocompleteRequest extends FormRequest
|
||||
'query' => $this->convertString('query'),
|
||||
'date' => $this->getCarbonDate('date'),
|
||||
'limit' => $limit,
|
||||
'administration_id' => (int)($this->get('administration_id', null) ?? $user->getAdministrationId()),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -92,7 +88,7 @@ class AutocompleteRequest extends FormRequest
|
||||
$validator->after(
|
||||
function (Validator $validator) {
|
||||
// validate if the account can access this administration
|
||||
$this->validateAdministration($validator, [UserRole::CHANGE_TRANSACTIONS]);
|
||||
$this->validateAdministration($validator, [UserRoleEnum::MANAGE_TRANSACTIONS]);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
92
app/Api/V2/Request/Chart/BalanceChartRequest.php
Normal file
92
app/Api/V2/Request/Chart/BalanceChartRequest.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* BalanceChartRequest.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Request\Chart;
|
||||
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Class BalanceChartRequest
|
||||
*/
|
||||
class BalanceChartRequest extends FormRequest
|
||||
{
|
||||
use ConvertsDataTypes;
|
||||
use ChecksLogin;
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
/**
|
||||
* Get all data from the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return [
|
||||
'accounts' => $this->getAccountList(),
|
||||
'period' => $this->convertString('period'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'start' => 'required|date|after:1900-01-01|before:2099-12-31',
|
||||
'end' => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01',
|
||||
'accounts.*' => 'required|exists:accounts,id',
|
||||
'period' => sprintf('required|in:%s', join(',', config('firefly.valid_view_ranges'))),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Validator $validator
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(
|
||||
function (Validator $validator) {
|
||||
// validate transaction query data.
|
||||
$data = $validator->getData();
|
||||
if (!array_key_exists('accounts', $data)) {
|
||||
$validator->errors()->add('accounts', trans('validation.filled', ['attribute' => 'accounts']));
|
||||
return;
|
||||
}
|
||||
if (!is_array($data['accounts'])) {
|
||||
$validator->errors()->add('accounts', trans('validation.filled', ['attribute' => 'accounts']));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@@ -47,7 +47,7 @@ class DateRequest extends FormRequest
|
||||
{
|
||||
return [
|
||||
'start' => $this->getCarbonDate('start'),
|
||||
'end' => $this->getCarbonDate('end'),
|
||||
'end' => $this->getCarbonDate('end')->endOfDay(),
|
||||
];
|
||||
}
|
||||
|
||||
|
116
app/Api/V2/Request/Model/Transaction/ListRequest.php
Normal file
116
app/Api/V2/Request/Model/Transaction/ListRequest.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* ListRequest.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Request\Model\Transaction;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Class ListRequest
|
||||
* Used specifically to list transactions.
|
||||
*/
|
||||
class ListRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
use TransactionFilter;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function buildParams(): string
|
||||
{
|
||||
$array = [
|
||||
'page' => $this->getPage(),
|
||||
];
|
||||
|
||||
$start = $this->getStartDate();
|
||||
$end = $this->getEndDate();
|
||||
if (null !== $start && null !== $end) {
|
||||
$array['start'] = $start->format('Y-m-d');
|
||||
$array['end'] = $end->format('Y-m-d');
|
||||
}
|
||||
if (0 !== $this->getLimit()) {
|
||||
$array['limit'] = $this->getLimit();
|
||||
}
|
||||
return http_build_query($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getPage(): int
|
||||
{
|
||||
$page = $this->convertInteger('page');
|
||||
return 0 === $page || $page > 65536 ? 1 : $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function getStartDate(): ?Carbon
|
||||
{
|
||||
return $this->getCarbonDate('start');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Carbon|null
|
||||
*/
|
||||
public function getEndDate(): ?Carbon
|
||||
{
|
||||
return $this->getCarbonDate('end');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLimit(): int
|
||||
{
|
||||
return $this->convertInteger('limit');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getTransactionTypes(): array
|
||||
{
|
||||
$type = (string)$this->get('type', 'default');
|
||||
return $this->mapTransactionTypes($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'start' => 'date',
|
||||
'end' => 'date|after:start',
|
||||
];
|
||||
}
|
||||
}
|
317
app/Api/V2/Request/Model/Transaction/StoreRequest.php
Normal file
317
app/Api/V2/Request/Model/Transaction/StoreRequest.php
Normal file
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
/*
|
||||
* StoreRequest.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Request\Model\Transaction;
|
||||
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Rules\BelongsUserGroup;
|
||||
use FireflyIII\Rules\IsBoolean;
|
||||
use FireflyIII\Rules\IsDateOrTime;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use FireflyIII\Support\Request\AppendsLocationData;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use FireflyIII\User;
|
||||
use FireflyIII\Validation\CurrencyValidation;
|
||||
use FireflyIII\Validation\GroupValidation;
|
||||
use FireflyIII\Validation\TransactionValidation;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Class StoreRequest
|
||||
*
|
||||
* TODO this class is basically the same as the v1 request. However, it does not accept
|
||||
* TODO models, objects and references that are NOT part of the designated user group (aka administration).
|
||||
* TODO this distinction is already made in the CheckLogin trait, where there is also a convenient function
|
||||
* TODO to grab the current UserGroup. This code is slightly different from other v2 apis that use
|
||||
* TODO the "administration_id", those will have to be updated later on.
|
||||
*/
|
||||
class StoreRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
|
||||
use TransactionValidation;
|
||||
use GroupValidation;
|
||||
use CurrencyValidation;
|
||||
use AppendsLocationData;
|
||||
protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS];
|
||||
|
||||
/**
|
||||
* Get all data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
app('log')->debug('V2: Get all data in TransactionStoreRequest');
|
||||
|
||||
return [
|
||||
'group_title' => $this->convertString('group_title'),
|
||||
'error_if_duplicate_hash' => $this->boolean('error_if_duplicate_hash'),
|
||||
'apply_rules' => $this->boolean('apply_rules', true),
|
||||
'fire_webhooks' => $this->boolean('fire_webhooks', true),
|
||||
'transactions' => $this->getTransactionData(),
|
||||
];
|
||||
// TODO include location and ability to process it.
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transaction data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getTransactionData(): array
|
||||
{
|
||||
$return = [];
|
||||
/**
|
||||
* @var array $transaction
|
||||
*/
|
||||
foreach ($this->get('transactions') as $transaction) {
|
||||
$object = new NullArrayObject($transaction);
|
||||
$return[] = [
|
||||
'type' => $this->clearString($object['type'], false),
|
||||
'date' => $this->dateFromValue($object['date']),
|
||||
'order' => $this->integerFromValue((string)$object['order']),
|
||||
|
||||
'currency_id' => $this->integerFromValue((string)$object['currency_id']),
|
||||
'currency_code' => $this->clearString((string)$object['currency_code'], false),
|
||||
|
||||
// foreign currency info:
|
||||
'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']),
|
||||
'foreign_currency_code' => $this->clearString((string)$object['foreign_currency_code'], false),
|
||||
|
||||
// amount and foreign amount. Cannot be 0.
|
||||
'amount' => $this->clearString((string)$object['amount'], false),
|
||||
'foreign_amount' => $this->clearString((string)$object['foreign_amount'], false),
|
||||
|
||||
// description.
|
||||
'description' => $this->clearString($object['description'], false),
|
||||
|
||||
// source of transaction. If everything is null, assume cash account.
|
||||
'source_id' => $this->integerFromValue((string)$object['source_id']),
|
||||
'source_name' => $this->clearString((string)$object['source_name'], false),
|
||||
'source_iban' => $this->clearString((string)$object['source_iban'], false),
|
||||
'source_number' => $this->clearString((string)$object['source_number'], false),
|
||||
'source_bic' => $this->clearString((string)$object['source_bic'], false),
|
||||
|
||||
// destination of transaction. If everything is null, assume cash account.
|
||||
'destination_id' => $this->integerFromValue((string)$object['destination_id']),
|
||||
'destination_name' => $this->clearString((string)$object['destination_name'], false),
|
||||
'destination_iban' => $this->clearString((string)$object['destination_iban'], false),
|
||||
'destination_number' => $this->clearString((string)$object['destination_number'], false),
|
||||
'destination_bic' => $this->clearString((string)$object['destination_bic'], false),
|
||||
|
||||
// budget info
|
||||
'budget_id' => $this->integerFromValue((string)$object['budget_id']),
|
||||
'budget_name' => $this->clearString((string)$object['budget_name'], false),
|
||||
|
||||
// category info
|
||||
'category_id' => $this->integerFromValue((string)$object['category_id']),
|
||||
'category_name' => $this->clearString((string)$object['category_name'], false),
|
||||
|
||||
// journal bill reference. Optional. Will only work for withdrawals
|
||||
'bill_id' => $this->integerFromValue((string)$object['bill_id']),
|
||||
'bill_name' => $this->clearString((string)$object['bill_name'], false),
|
||||
|
||||
// piggy bank reference. Optional. Will only work for transfers
|
||||
'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']),
|
||||
'piggy_bank_name' => $this->clearString((string)$object['piggy_bank_name'], false),
|
||||
|
||||
// some other interesting properties
|
||||
'reconciled' => $this->convertBoolean((string)$object['reconciled']),
|
||||
'notes' => $this->clearString((string)$object['notes']),
|
||||
'tags' => $this->arrayFromValue($object['tags']),
|
||||
|
||||
// all custom fields:
|
||||
'internal_reference' => $this->clearString((string)$object['internal_reference'], false),
|
||||
'external_id' => $this->clearString((string)$object['external_id'], false),
|
||||
'original_source' => sprintf('ff3-v%s|api-v%s', config('firefly.version'), config('firefly.api_version')),
|
||||
'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
|
||||
'bunq_payment_id' => $this->clearString((string)$object['bunq_payment_id'], false),
|
||||
'external_url' => $this->clearString((string)$object['external_url'], false),
|
||||
|
||||
'sepa_cc' => $this->clearString((string)$object['sepa_cc'], false),
|
||||
'sepa_ct_op' => $this->clearString((string)$object['sepa_ct_op'], false),
|
||||
'sepa_ct_id' => $this->clearString((string)$object['sepa_ct_id'], false),
|
||||
'sepa_db' => $this->clearString((string)$object['sepa_db'], false),
|
||||
'sepa_country' => $this->clearString((string)$object['sepa_country'], false),
|
||||
'sepa_ep' => $this->clearString((string)$object['sepa_ep'], false),
|
||||
'sepa_ci' => $this->clearString((string)$object['sepa_ci'], false),
|
||||
'sepa_batch_id' => $this->clearString((string)$object['sepa_batch_id'], false),
|
||||
// custom date fields. Must be Carbon objects. Presence is optional.
|
||||
'interest_date' => $this->dateFromValue($object['interest_date']),
|
||||
'book_date' => $this->dateFromValue($object['book_date']),
|
||||
'process_date' => $this->dateFromValue($object['process_date']),
|
||||
'due_date' => $this->dateFromValue($object['due_date']),
|
||||
'payment_date' => $this->dateFromValue($object['payment_date']),
|
||||
'invoice_date' => $this->dateFromValue($object['invoice_date']),
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
app('log')->debug('V2: Collect rules of TransactionStoreRequest');
|
||||
|
||||
// at this point the userGroup can't be NULL because the
|
||||
// authorize() method will complain. Loudly.
|
||||
/** @var UserGroup $userGroup */
|
||||
$userGroup = $this->getUserGroup();
|
||||
|
||||
return [
|
||||
// basic fields for group:
|
||||
'group_title' => 'between:1,1000|nullable',
|
||||
'error_if_duplicate_hash' => [new IsBoolean()],
|
||||
'apply_rules' => [new IsBoolean()],
|
||||
|
||||
// transaction rules (in array for splits):
|
||||
'transactions.*.type' => 'required|in:withdrawal,deposit,transfer,opening-balance,reconciliation',
|
||||
'transactions.*.date' => ['required', new IsDateOrTime()],
|
||||
'transactions.*.order' => 'numeric|min:0',
|
||||
|
||||
// currency info
|
||||
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id|nullable',
|
||||
'transactions.*.currency_code' => 'min:3|max:51|exists:transaction_currencies,code|nullable',
|
||||
'transactions.*.foreign_currency_id' => 'numeric|exists:transaction_currencies,id|nullable',
|
||||
'transactions.*.foreign_currency_code' => 'min:3|max:51|exists:transaction_currencies,code|nullable',
|
||||
|
||||
// amount
|
||||
'transactions.*.amount' => 'required|numeric|gt:0',
|
||||
'transactions.*.foreign_amount' => 'numeric',
|
||||
|
||||
// description
|
||||
'transactions.*.description' => 'nullable|between:1,1000',
|
||||
|
||||
// source of transaction
|
||||
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUserGroup($userGroup)],
|
||||
'transactions.*.source_name' => 'between:1,255|nullable',
|
||||
'transactions.*.source_iban' => 'between:1,255|nullable|iban',
|
||||
'transactions.*.source_number' => 'between:1,255|nullable',
|
||||
'transactions.*.source_bic' => 'between:1,255|nullable|bic',
|
||||
|
||||
// destination of transaction
|
||||
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUserGroup($userGroup)],
|
||||
'transactions.*.destination_name' => 'between:1,255|nullable',
|
||||
'transactions.*.destination_iban' => 'between:1,255|nullable|iban',
|
||||
'transactions.*.destination_number' => 'between:1,255|nullable',
|
||||
'transactions.*.destination_bic' => 'between:1,255|nullable|bic',
|
||||
|
||||
// budget, category, bill and piggy
|
||||
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUserGroup($userGroup)],
|
||||
'transactions.*.budget_name' => ['between:1,255', 'nullable', new BelongsUserGroup($userGroup)],
|
||||
'transactions.*.category_id' => ['mustExist:categories,id', new BelongsUserGroup($userGroup), 'nullable'],
|
||||
'transactions.*.category_name' => 'between:1,255|nullable',
|
||||
'transactions.*.bill_id' => ['numeric', 'nullable', 'mustExist:bills,id', new BelongsUserGroup($userGroup)],
|
||||
'transactions.*.bill_name' => ['between:1,255', 'nullable', new BelongsUserGroup($userGroup)],
|
||||
'transactions.*.piggy_bank_id' => ['numeric', 'nullable', 'mustExist:piggy_banks,id', new BelongsUserGroup($userGroup)],
|
||||
'transactions.*.piggy_bank_name' => ['between:1,255', 'nullable', new BelongsUserGroup($userGroup)],
|
||||
|
||||
// other interesting fields
|
||||
'transactions.*.reconciled' => [new IsBoolean()],
|
||||
'transactions.*.notes' => 'min:1|max:50000|nullable',
|
||||
'transactions.*.tags' => 'between:0,255',
|
||||
|
||||
// meta info fields
|
||||
'transactions.*.internal_reference' => 'min:1|max:255|nullable',
|
||||
'transactions.*.external_id' => 'min:1|max:255|nullable',
|
||||
'transactions.*.recurrence_id' => 'min:1|max:255|nullable',
|
||||
'transactions.*.bunq_payment_id' => 'min:1|max:255|nullable',
|
||||
'transactions.*.external_url' => 'min:1|max:255|nullable|url',
|
||||
|
||||
// SEPA fields:
|
||||
'transactions.*.sepa_cc' => 'min:1|max:255|nullable',
|
||||
'transactions.*.sepa_ct_op' => 'min:1|max:255|nullable',
|
||||
'transactions.*.sepa_ct_id' => 'min:1|max:255|nullable',
|
||||
'transactions.*.sepa_db' => 'min:1|max:255|nullable',
|
||||
'transactions.*.sepa_country' => 'min:1|max:255|nullable',
|
||||
'transactions.*.sepa_ep' => 'min:1|max:255|nullable',
|
||||
'transactions.*.sepa_ci' => 'min:1|max:255|nullable',
|
||||
'transactions.*.sepa_batch_id' => 'min:1|max:255|nullable',
|
||||
|
||||
// dates
|
||||
'transactions.*.interest_date' => 'date|nullable',
|
||||
'transactions.*.book_date' => 'date|nullable',
|
||||
'transactions.*.process_date' => 'date|nullable',
|
||||
'transactions.*.due_date' => 'date|nullable',
|
||||
'transactions.*.payment_date' => 'date|nullable',
|
||||
'transactions.*.invoice_date' => 'date|nullable',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the validator instance.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
/** @var UserGroup $userGroup */
|
||||
$userGroup = $this->getUserGroup();
|
||||
$validator->after(
|
||||
function (Validator $validator) use ($user, $userGroup) {
|
||||
// must be valid array.
|
||||
$this->validateTransactionArray($validator); // does not need group validation.
|
||||
|
||||
// must submit at least one transaction.
|
||||
app('log')->debug('Now going to validateOneTransaction');
|
||||
$this->validateOneTransaction($validator); // does not need group validation.
|
||||
app('log')->debug('Now done with validateOneTransaction');
|
||||
|
||||
// all journals must have a description
|
||||
$this->validateDescriptions($validator); // does not need group validation.
|
||||
|
||||
// all transaction types must be equal:
|
||||
$this->validateTransactionTypes($validator); // does not need group validation.
|
||||
|
||||
// validate foreign currency info
|
||||
$this->validateForeignCurrencyInformation($validator); // does not need group validation.
|
||||
|
||||
// validate all account info
|
||||
$this->validateAccountInformation($validator, $user, $userGroup);
|
||||
|
||||
// validate source/destination is equal, depending on the transaction journal type.
|
||||
$this->validateEqualAccounts($validator);
|
||||
|
||||
// the group must have a description if > 1 journal.
|
||||
$this->validateGroupDescription($validator);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
61
app/Api/V2/Request/UserGroup/StoreRequest.php
Normal file
61
app/Api/V2/Request/UserGroup/StoreRequest.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* StoreRequest.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Request\UserGroup;
|
||||
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Class StoreRequest
|
||||
*/
|
||||
class StoreRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER, UserRoleEnum::FULL];
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->convertString('title'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'title' => 'unique:user_groups,title|required|min:2|max:255',
|
||||
];
|
||||
}
|
||||
}
|
69
app/Api/V2/Request/UserGroup/UpdateMembershipRequest.php
Normal file
69
app/Api/V2/Request/UserGroup/UpdateMembershipRequest.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* StoreRequest.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Request\UserGroup;
|
||||
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Class StoreRequest
|
||||
*/
|
||||
class UpdateMembershipRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER, UserRoleEnum::FULL];
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->convertInteger('id'),
|
||||
'email' => $this->convertString('email'),
|
||||
'roles' => $this->get('roles') ?? [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$validRoles = [];
|
||||
foreach (UserRoleEnum::cases() as $role) {
|
||||
$validRoles[] = $role->value;
|
||||
}
|
||||
return [
|
||||
'id' => 'exists:users,id|required_without:email',
|
||||
'email' => 'exists:users,email|required_without:id',
|
||||
'roles.*' => 'required|in:' . join(',', $validRoles),
|
||||
];
|
||||
}
|
||||
}
|
64
app/Api/V2/Request/UserGroup/UpdateRequest.php
Normal file
64
app/Api/V2/Request/UserGroup/UpdateRequest.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
* StoreRequest.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V2\Request\UserGroup;
|
||||
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Class StoreRequest
|
||||
*/
|
||||
class UpdateRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER, UserRoleEnum::FULL];
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->convertString('title'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
/** @var UserGroup $userGroup */
|
||||
$userGroup = $this->route()->parameter('userGroup');
|
||||
return [
|
||||
'title' => sprintf('required|min:2|max:255|unique:user_groups,title,%d', $userGroup->id),
|
||||
];
|
||||
}
|
||||
}
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Models\AutoBudget;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
use FireflyIII\Models\Bill;
|
||||
@@ -33,12 +34,15 @@ use FireflyIII\Models\PiggyBankRepetition;
|
||||
use FireflyIII\Models\RecurrenceTransaction;
|
||||
use FireflyIII\Models\RuleTrigger;
|
||||
use Illuminate\Console\Command;
|
||||
use ValueError;
|
||||
|
||||
/**
|
||||
* Class ReportSkeleton
|
||||
*/
|
||||
class CorrectAmounts extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
protected $description = 'This command makes sure positive and negative amounts are recorded correctly.';
|
||||
protected $signature = 'firefly-iii:fix-amount-pos-neg';
|
||||
|
||||
@@ -78,7 +82,7 @@ class CorrectAmounts extends Command
|
||||
$set = AutoBudget::where('amount', '<', 0)->get();
|
||||
$count = $set->count();
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: All auto budget amounts are positive.');
|
||||
$this->friendlyPositive('All auto budget amounts are positive.');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -87,7 +91,7 @@ class CorrectAmounts extends Command
|
||||
$item->amount = app('steam')->positive((string)$item->amount);
|
||||
$item->save();
|
||||
}
|
||||
$this->line(sprintf('Corrected %d auto budget amount(s).', $count));
|
||||
$this->friendlyInfo(sprintf('Corrected %d auto budget amount(s).', $count));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,7 +102,7 @@ class CorrectAmounts extends Command
|
||||
$set = AvailableBudget::where('amount', '<', 0)->get();
|
||||
$count = $set->count();
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: All available budget amounts are positive.');
|
||||
$this->friendlyPositive('All available budget amounts are positive.');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -107,7 +111,7 @@ class CorrectAmounts extends Command
|
||||
$item->amount = app('steam')->positive((string)$item->amount);
|
||||
$item->save();
|
||||
}
|
||||
$this->line(sprintf('Corrected %d available budget amount(s).', $count));
|
||||
$this->friendlyInfo(sprintf('Corrected %d available budget amount(s).', $count));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,7 +122,7 @@ class CorrectAmounts extends Command
|
||||
$set = Bill::where('amount_min', '<', 0)->orWhere('amount_max', '<', 0)->get();
|
||||
$count = $set->count();
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: All bill amounts are positive.');
|
||||
$this->friendlyPositive('All bill amounts are positive.');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -128,6 +132,7 @@ class CorrectAmounts extends Command
|
||||
$item->amount_max = app('steam')->positive((string)$item->amount_max);
|
||||
$item->save();
|
||||
}
|
||||
$this->friendlyInfo(sprintf('Corrected %d bill amount(s).', $count));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +143,7 @@ class CorrectAmounts extends Command
|
||||
$set = BudgetLimit::where('amount', '<', 0)->get();
|
||||
$count = $set->count();
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: All budget limit amounts are positive.');
|
||||
$this->friendlyPositive('All budget limit amounts are positive.');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -147,7 +152,7 @@ class CorrectAmounts extends Command
|
||||
$item->amount = app('steam')->positive((string)$item->amount);
|
||||
$item->save();
|
||||
}
|
||||
$this->line(sprintf('Corrected %d budget limit amount(s).', $count));
|
||||
$this->friendlyInfo(sprintf('Corrected %d budget limit amount(s).', $count));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,7 +163,7 @@ class CorrectAmounts extends Command
|
||||
$set = CurrencyExchangeRate::where('rate', '<', 0)->get();
|
||||
$count = $set->count();
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: All currency exchange rates are positive.');
|
||||
$this->friendlyPositive('All currency exchange rates are positive.');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -167,7 +172,27 @@ class CorrectAmounts extends Command
|
||||
$item->rate = app('steam')->positive((string)$item->rate);
|
||||
$item->save();
|
||||
}
|
||||
$this->line(sprintf('Corrected %d currency exchange rate(s).', $count));
|
||||
$this->friendlyInfo(sprintf('Corrected %d currency exchange rate(s).', $count));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function fixRepetitions(): void
|
||||
{
|
||||
$set = PiggyBankRepetition::where('currentamount', '<', 0)->get();
|
||||
$count = $set->count();
|
||||
if (0 === $count) {
|
||||
$this->friendlyPositive('All piggy bank repetition amounts are positive.');
|
||||
|
||||
return;
|
||||
}
|
||||
/** @var PiggyBankRepetition $item */
|
||||
foreach ($set as $item) {
|
||||
$item->currentamount = app('steam')->positive((string)$item->currentamount);
|
||||
$item->save();
|
||||
}
|
||||
$this->friendlyInfo(sprintf('Corrected %d piggy bank repetition amount(s).', $count));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +203,7 @@ class CorrectAmounts extends Command
|
||||
$set = PiggyBank::where('targetamount', '<', 0)->get();
|
||||
$count = $set->count();
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: All piggy bank amounts are positive.');
|
||||
$this->friendlyPositive('All piggy bank amounts are positive.');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -187,7 +212,7 @@ class CorrectAmounts extends Command
|
||||
$item->targetamount = app('steam')->positive((string)$item->targetamount);
|
||||
$item->save();
|
||||
}
|
||||
$this->line(sprintf('Corrected %d piggy bank amount(s).', $count));
|
||||
$this->friendlyInfo(sprintf('Corrected %d piggy bank amount(s).', $count));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,7 +225,7 @@ class CorrectAmounts extends Command
|
||||
->get();
|
||||
$count = $set->count();
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: All recurring transaction amounts are positive.');
|
||||
$this->friendlyPositive('All recurring transaction amounts are positive.');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -210,27 +235,7 @@ class CorrectAmounts extends Command
|
||||
$item->foreign_amount = app('steam')->positive((string)$item->foreign_amount);
|
||||
$item->save();
|
||||
}
|
||||
$this->line(sprintf('Corrected %d recurring transaction amount(s).', $count));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function fixRepetitions(): void
|
||||
{
|
||||
$set = PiggyBankRepetition::where('currentamount', '<', 0)->get();
|
||||
$count = $set->count();
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: All piggy bank repetition amounts are positive.');
|
||||
|
||||
return;
|
||||
}
|
||||
/** @var PiggyBankRepetition $item */
|
||||
foreach ($set as $item) {
|
||||
$item->currentamount = app('steam')->positive((string)$item->currentamount);
|
||||
$item->save();
|
||||
}
|
||||
$this->line(sprintf('Corrected %d piggy bank repetition amount(s).', $count));
|
||||
$this->friendlyInfo(sprintf('Corrected %d recurring transaction amount(s).', $count));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,18 +248,27 @@ class CorrectAmounts extends Command
|
||||
/** @var RuleTrigger $item */
|
||||
foreach ($set as $item) {
|
||||
// basic check:
|
||||
if (-1 === bccomp((string)$item->trigger_value, '0')) {
|
||||
$check = 0;
|
||||
try {
|
||||
$check = bccomp((string)$item->trigger_value, '0');
|
||||
} catch (ValueError $e) {
|
||||
$this->friendlyError(sprintf('Rule #%d contained invalid %s-trigger "%s". The trigger has been removed, and the rule is disabled.', $item->rule_id, $item->trigger_type, $item->trigger_value));
|
||||
$item->rule->active = false;
|
||||
$item->rule->save();
|
||||
$item->forceDelete();
|
||||
}
|
||||
if (-1 === $check) {
|
||||
$fixed++;
|
||||
$item->trigger_value = app('steam')->positive((string)$item->trigger_value);
|
||||
$item->save();
|
||||
}
|
||||
}
|
||||
if (0 === $fixed) {
|
||||
$this->info('Correct: All rule trigger amounts are positive.');
|
||||
$this->friendlyPositive('All rule trigger amounts are positive.');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->line(sprintf('Corrected %d rule trigger amount(s).', $fixed));
|
||||
$this->friendlyInfo(sprintf('Corrected %d rule trigger amount(s).', $fixed));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use Artisan;
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use Illuminate\Console\Command;
|
||||
use Schema;
|
||||
|
||||
@@ -34,6 +35,8 @@ use Schema;
|
||||
*/
|
||||
class CorrectDatabase extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
protected $description = 'Will correct the integrity of your database, if necessary.';
|
||||
protected $signature = 'firefly-iii:correct-database';
|
||||
|
||||
@@ -44,7 +47,7 @@ class CorrectDatabase extends Command
|
||||
{
|
||||
// if table does not exist, return false
|
||||
if (!Schema::hasTable('users')) {
|
||||
$this->error('No "users"-table, will not continue.');
|
||||
$this->friendlyError('No "users"-table, will not continue.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -76,7 +79,7 @@ class CorrectDatabase extends Command
|
||||
'firefly-iii:trigger-credit-recalculation',
|
||||
];
|
||||
foreach ($commands as $command) {
|
||||
$this->line(sprintf('Now executing command "%s"', $command));
|
||||
$this->friendlyLine(sprintf('Now executing command "%s"', $command));
|
||||
$this->call($command);
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Transaction;
|
||||
@@ -39,6 +40,8 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
class CorrectOpeningBalanceCurrencies extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
protected $description = 'Will make sure that opening balance transaction currencies match the account they\'re for.';
|
||||
protected $signature = 'firefly-iii:fix-ob-currencies';
|
||||
|
||||
@@ -58,16 +61,27 @@ class CorrectOpeningBalanceCurrencies extends Command
|
||||
|
||||
if ($count > 0) {
|
||||
$message = sprintf('Corrected %d opening balance transaction(s).', $count);
|
||||
$this->line($message);
|
||||
$this->friendlyInfo($message);
|
||||
}
|
||||
if (0 === $count) {
|
||||
$message = 'Correct: There was nothing to fix in the opening balance transactions.';
|
||||
$this->info($message);
|
||||
$message = 'There was nothing to fix in the opening balance transactions.';
|
||||
$this->friendlyPositive($message);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getJournals(): Collection
|
||||
{
|
||||
/** @var Collection */
|
||||
return TransactionJournal::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->whereNull('transaction_journals.deleted_at')
|
||||
->where('transaction_types.type', TransactionType::OPENING_BALANCE)->get(['transaction_journals.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
@@ -80,7 +94,7 @@ class CorrectOpeningBalanceCurrencies extends Command
|
||||
if (null === $account) {
|
||||
$message = sprintf('Transaction journal #%d has no valid account. Can\'t fix this line.', $journal->id);
|
||||
app('log')->warning($message);
|
||||
$this->warn($message);
|
||||
$this->friendlyError($message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -109,34 +123,10 @@ class CorrectOpeningBalanceCurrencies extends Command
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
private function getCurrency(Account $account): TransactionCurrency
|
||||
{
|
||||
/** @var AccountRepositoryInterface $repos */
|
||||
$repos = app(AccountRepositoryInterface::class);
|
||||
$repos->setUser($account->user);
|
||||
|
||||
return $repos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUser($account->user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getJournals(): Collection
|
||||
{
|
||||
/** @var Collection */
|
||||
return TransactionJournal::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->whereNull('transaction_journals.deleted_at')
|
||||
->where('transaction_types.type', TransactionType::OPENING_BALANCE)->get(['transaction_journals.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function setCorrectCurrency(Account $account, TransactionJournal $journal): int
|
||||
@@ -160,4 +150,18 @@ class CorrectOpeningBalanceCurrencies extends Command
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
private function getCurrency(Account $account): TransactionCurrency
|
||||
{
|
||||
/** @var AccountRepositoryInterface $repos */
|
||||
$repos = app(AccountRepositoryInterface::class);
|
||||
$repos->setUser($account->user);
|
||||
|
||||
return $repos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUser($account->user);
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Console\Command;
|
||||
@@ -33,6 +34,8 @@ use Illuminate\Console\Command;
|
||||
*/
|
||||
class CreateAccessTokens extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
@@ -66,12 +69,12 @@ class CreateAccessTokens extends Command
|
||||
if (null === $pref) {
|
||||
$token = $user->generateAccessToken();
|
||||
app('preferences')->setForUser($user, 'access_token', $token);
|
||||
$this->line(sprintf('Generated access token for user %s', $user->email));
|
||||
$this->friendlyInfo(sprintf('Generated access token for user %s', $user->email));
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: Verified access tokens.');
|
||||
$this->friendlyPositive('Verified access tokens.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Models\LinkType;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
@@ -31,6 +32,8 @@ use Illuminate\Console\Command;
|
||||
*/
|
||||
class CreateLinkTypes extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
@@ -67,13 +70,13 @@ class CreateLinkTypes extends Command
|
||||
$link->inward = $values[1];
|
||||
$link->outward = $values[0];
|
||||
++$count;
|
||||
$this->line(sprintf('Created missing link type "%s"', $name));
|
||||
$this->friendlyInfo(sprintf('Created missing link type "%s"', $name));
|
||||
}
|
||||
$link->editable = false;
|
||||
$link->save();
|
||||
}
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: all link types are OK');
|
||||
$this->friendlyPositive('All link types are OK');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
@@ -32,6 +33,8 @@ use Illuminate\Console\Command;
|
||||
*/
|
||||
class DeleteEmptyGroups extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
protected $description = 'Delete empty transaction groups.';
|
||||
protected $signature = 'firefly-iii:delete-empty-groups';
|
||||
|
||||
@@ -50,7 +53,7 @@ class DeleteEmptyGroups extends Command
|
||||
|
||||
$total = count($groupIds);
|
||||
if ($total > 0) {
|
||||
$this->info(sprintf('Deleted %d empty transaction group(s).', $total));
|
||||
$this->friendlyInfo(sprintf('Deleted %d empty transaction group(s).', $total));
|
||||
|
||||
// again, chunks for SQLite.
|
||||
$chunks = array_chunk($groupIds, 500);
|
||||
@@ -59,7 +62,7 @@ class DeleteEmptyGroups extends Command
|
||||
}
|
||||
}
|
||||
if (0 === $total) {
|
||||
$this->info('Correct: verified empty groups.');
|
||||
$this->friendlyInfo('Verified there are no empty groups.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Console\Command;
|
||||
@@ -35,6 +36,8 @@ use Illuminate\Support\Facades\Log;
|
||||
*/
|
||||
class DeleteEmptyJournals extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
@@ -61,30 +64,6 @@ class DeleteEmptyJournals extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function deleteEmptyJournals(): void
|
||||
{
|
||||
$count = 0;
|
||||
$set = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->groupBy('transaction_journals.id')
|
||||
->whereNull('transactions.transaction_journal_id')
|
||||
->get(['transaction_journals.id']);
|
||||
|
||||
foreach ($set as $entry) {
|
||||
try {
|
||||
TransactionJournal::find($entry->id)->delete();
|
||||
} catch (QueryException $e) {
|
||||
Log::info(sprintf('Could not delete entry: %s', $e->getMessage()));
|
||||
}
|
||||
|
||||
|
||||
$this->info(sprintf('Deleted empty transaction journal #%d', $entry->id));
|
||||
++$count;
|
||||
}
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: no empty transaction journals.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete transactions and their journals if they have an uneven number of transactions.
|
||||
*/
|
||||
@@ -103,16 +82,47 @@ class DeleteEmptyJournals extends Command
|
||||
TransactionJournal::find((int)$row->transaction_journal_id)->delete();
|
||||
} catch (QueryException $e) {
|
||||
Log::info(sprintf('Could not delete journal: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
|
||||
Transaction::where('transaction_journal_id', (int)$row->transaction_journal_id)->delete();
|
||||
$this->info(sprintf('Deleted transaction journal #%d because it had an uneven number of transactions.', $row->transaction_journal_id));
|
||||
$this->friendlyWarning(
|
||||
sprintf('Deleted transaction journal #%d because it had an uneven number of transactions.', $row->transaction_journal_id)
|
||||
);
|
||||
$total++;
|
||||
}
|
||||
}
|
||||
if (0 === $total) {
|
||||
$this->info('Correct: no uneven transaction journals.');
|
||||
$this->friendlyPositive('No uneven transaction journals.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function deleteEmptyJournals(): void
|
||||
{
|
||||
$count = 0;
|
||||
$set = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->groupBy('transaction_journals.id')
|
||||
->whereNull('transactions.transaction_journal_id')
|
||||
->get(['transaction_journals.id']);
|
||||
|
||||
foreach ($set as $entry) {
|
||||
try {
|
||||
TransactionJournal::find($entry->id)->delete();
|
||||
} catch (QueryException $e) {
|
||||
Log::info(sprintf('Could not delete entry: %s', $e->getMessage()));
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
|
||||
$this->friendlyInfo(sprintf('Deleted empty transaction journal #%d', $entry->id));
|
||||
++$count;
|
||||
}
|
||||
if (0 === $count) {
|
||||
$this->friendlyPositive('No empty transaction journals.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Console\Command;
|
||||
@@ -34,6 +35,8 @@ use stdClass;
|
||||
*/
|
||||
class DeleteOrphanedTransactions extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
@@ -63,37 +66,8 @@ class DeleteOrphanedTransactions extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function deleteFromOrphanedAccounts(): void
|
||||
{
|
||||
$set
|
||||
= Transaction::leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
|
||||
->whereNotNull('accounts.deleted_at')
|
||||
->get(['transactions.*']);
|
||||
$count = 0;
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
// delete journals
|
||||
$journal = TransactionJournal::find((int)$transaction->transaction_journal_id);
|
||||
if ($journal) {
|
||||
$journal->delete();
|
||||
}
|
||||
Transaction::where('transaction_journal_id', (int)$transaction->transaction_journal_id)->delete();
|
||||
$this->line(
|
||||
sprintf(
|
||||
'Deleted transaction journal #%d because account #%d was already deleted.',
|
||||
$transaction->transaction_journal_id,
|
||||
$transaction->account_id
|
||||
)
|
||||
);
|
||||
$count++;
|
||||
}
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: no orphaned accounts.');
|
||||
}
|
||||
}
|
||||
|
||||
private function deleteOrphanedJournals(): void
|
||||
{
|
||||
$set = TransactionJournal::leftJoin('transaction_groups', 'transaction_journals.transaction_group_id', 'transaction_groups.id')
|
||||
@@ -102,15 +76,15 @@ class DeleteOrphanedTransactions extends Command
|
||||
->get(['transaction_journals.id', 'transaction_journals.transaction_group_id']);
|
||||
$count = $set->count();
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: no orphaned journals.');
|
||||
$this->friendlyPositive('No orphaned journals.');
|
||||
return;
|
||||
}
|
||||
if ($count > 0) {
|
||||
$this->info(sprintf('Found %d orphaned journal(s).', $count));
|
||||
$this->friendlyInfo(sprintf('Found %d orphaned journal(s).', $count));
|
||||
foreach ($set as $entry) {
|
||||
$journal = TransactionJournal::withTrashed()->find((int)$entry->id);
|
||||
if (null !== $journal) {
|
||||
$journal->delete();
|
||||
$this->info(
|
||||
$this->friendlyWarning(
|
||||
sprintf(
|
||||
'Journal #%d (part of deleted transaction group #%d) has been deleted as well.',
|
||||
$entry->id,
|
||||
@@ -120,7 +94,6 @@ class DeleteOrphanedTransactions extends Command
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
@@ -143,7 +116,7 @@ class DeleteOrphanedTransactions extends Command
|
||||
$transaction = Transaction::find((int)$entry->transaction_id);
|
||||
if (null !== $transaction) {
|
||||
$transaction->delete();
|
||||
$this->info(
|
||||
$this->friendlyWarning(
|
||||
sprintf(
|
||||
'Transaction #%d (part of deleted transaction journal #%d) has been deleted as well.',
|
||||
$entry->transaction_id,
|
||||
@@ -154,7 +127,39 @@ class DeleteOrphanedTransactions extends Command
|
||||
}
|
||||
}
|
||||
if (0 === $count) {
|
||||
$this->info('Correct: no orphaned transactions.');
|
||||
$this->friendlyPositive('No orphaned transactions.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function deleteFromOrphanedAccounts(): void
|
||||
{
|
||||
$set
|
||||
= Transaction::leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
|
||||
->whereNotNull('accounts.deleted_at')
|
||||
->get(['transactions.*']);
|
||||
$count = 0;
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
// delete journals
|
||||
$journal = TransactionJournal::find((int)$transaction->transaction_journal_id);
|
||||
if ($journal) {
|
||||
$journal->delete();
|
||||
}
|
||||
Transaction::where('transaction_journal_id', (int)$transaction->transaction_journal_id)->delete();
|
||||
$this->friendlyWarning(
|
||||
sprintf(
|
||||
'Deleted transaction journal #%d because account #%d was already deleted.',
|
||||
$transaction->transaction_journal_id,
|
||||
$transaction->account_id
|
||||
)
|
||||
);
|
||||
$count++;
|
||||
}
|
||||
if (0 === $count) {
|
||||
$this->friendlyPositive('No orphaned accounts.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Console\Command;
|
||||
@@ -32,6 +33,8 @@ use Illuminate\Console\Command;
|
||||
*/
|
||||
class DeleteZeroAmount extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
@@ -57,13 +60,13 @@ class DeleteZeroAmount extends Command
|
||||
$journals = TransactionJournal::whereIn('id', $set)->get();
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$this->info(sprintf('Deleted transaction journal #%d because the amount is zero (0.00).', $journal->id));
|
||||
$this->friendlyWarning(sprintf('Deleted transaction journal #%d because the amount is zero (0.00).', $journal->id));
|
||||
$journal->delete();
|
||||
|
||||
Transaction::where('transaction_journal_id', $journal->id)->delete();
|
||||
}
|
||||
if (0 === $journals->count()) {
|
||||
$this->info('Correct: no zero-amount transaction journals.');
|
||||
$this->friendlyPositive('No zero-amount transaction journals.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\Transaction;
|
||||
@@ -30,13 +31,14 @@ use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class EnableCurrencies
|
||||
*/
|
||||
class EnableCurrencies extends Command
|
||||
{
|
||||
use ShowsFriendlyMessages;
|
||||
|
||||
protected $description = 'Enables all currencies in use.';
|
||||
protected $signature = 'firefly-iii:enable-currencies';
|
||||
|
||||
@@ -85,10 +87,10 @@ class EnableCurrencies extends Command
|
||||
);
|
||||
$disabled = TransactionCurrency::whereIn('id', $found)->where('enabled', false)->count();
|
||||
if ($disabled > 0) {
|
||||
$this->info(sprintf('%d were (was) still disabled. This has been corrected.', $disabled));
|
||||
$this->friendlyInfo(sprintf('%d currencies were (was) disabled while in use by transactions. This has been corrected.', $disabled));
|
||||
}
|
||||
if (0 === $disabled) {
|
||||
$this->info('Correct: All currencies are correctly enabled or disabled.');
|
||||
$this->friendlyPositive('All currencies are correctly enabled or disabled.');
|
||||
}
|
||||
TransactionCurrency::whereIn('id', $found)->update(['enabled' => true]);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user