mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-19 09:41:22 +00:00
Compare commits
400 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad1e9c27e9 | ||
|
|
ab761696bf | ||
|
|
0713273a99 | ||
|
|
5668a3271b | ||
|
|
1eca105a91 | ||
|
|
3883b99c24 | ||
|
|
d6adbc697a | ||
|
|
a5789b1085 | ||
|
|
a6ccbcb795 | ||
|
|
1a6067f7ae | ||
|
|
cb735b18a9 | ||
|
|
909bd11147 | ||
|
|
1a76c606ed | ||
|
|
8c9b6796a1 | ||
|
|
844ab608d4 | ||
|
|
dc39094975 | ||
|
|
b32184d525 | ||
|
|
d95ae53ce2 | ||
|
|
5e3147ddeb | ||
|
|
9e594c6075 | ||
|
|
c0058c51ea | ||
|
|
b0b68d4243 | ||
|
|
22eb90212d | ||
|
|
94e264b6ce | ||
|
|
7ea15761a6 | ||
|
|
1ced4a089d | ||
|
|
648e63628c | ||
|
|
2847e2aff5 | ||
|
|
9dfaabb5d0 | ||
|
|
6a21f98ea4 | ||
|
|
4d5f4cc1c0 | ||
|
|
970ce6cb0d | ||
|
|
31cad5de00 | ||
|
|
e06db9e620 | ||
|
|
f57ac64dc2 | ||
|
|
57d7c1623f | ||
|
|
c86aa9cb3f | ||
|
|
48209d0d22 | ||
|
|
8f6a271cc0 | ||
|
|
a9b610f367 | ||
|
|
1046930f29 | ||
|
|
1b16e5e216 | ||
|
|
e16ba9ac70 | ||
|
|
71ac676b83 | ||
|
|
1b6c0d5d86 | ||
|
|
14db016e98 | ||
|
|
7e2e1626ac | ||
|
|
bce4e7e2bf | ||
|
|
ede327f3d3 | ||
|
|
82718a74dc | ||
|
|
eefd6141a1 | ||
|
|
7894f1871e | ||
|
|
0ef9b5b462 | ||
|
|
9ca75d134e | ||
|
|
b78776e1f7 | ||
|
|
f2f9f8fbab | ||
|
|
5b5acba816 | ||
|
|
9f2729d0ff | ||
|
|
afe98cda9f | ||
|
|
9c4d2e8791 | ||
|
|
cea170359f | ||
|
|
70bb8fbc89 | ||
|
|
82cd0adca6 | ||
|
|
e821f5b2b6 | ||
|
|
4cade467c6 | ||
|
|
b6c9639948 | ||
|
|
ca9319db34 | ||
|
|
beaec9a4c1 | ||
|
|
cbc44e8200 | ||
|
|
017b1a481a | ||
|
|
e15932fe4a | ||
|
|
08c044fe52 | ||
|
|
0e11245cb4 | ||
|
|
cde494d3ef | ||
|
|
9a15decdff | ||
|
|
186b986e02 | ||
|
|
cdbf5653ac | ||
|
|
c403dd7490 | ||
|
|
d15d9fdf2a | ||
|
|
0b618de44c | ||
|
|
875f19f728 | ||
|
|
7bb549732c | ||
|
|
b9baa93ae4 | ||
|
|
315479fcd3 | ||
|
|
1f1334a1fc | ||
|
|
bf0744e03a | ||
|
|
8fb9577660 | ||
|
|
90d58c5c39 | ||
|
|
b6aa79bb38 | ||
|
|
14a0de6b6a | ||
|
|
13e56b7249 | ||
|
|
3753901e38 | ||
|
|
e76075e29f | ||
|
|
284db7f90b | ||
|
|
cabdf4e380 | ||
|
|
9859052c4d | ||
|
|
0feeac9160 | ||
|
|
54b33a0b69 | ||
|
|
e08e7b2c9b | ||
|
|
782e2add88 | ||
|
|
f18a5a6f1b | ||
|
|
6fc971c4cb | ||
|
|
3250c4830d | ||
|
|
9e1a69217d | ||
|
|
46c26a64d8 | ||
|
|
2f12a70647 | ||
|
|
be190d1fa0 | ||
|
|
1e4888209b | ||
|
|
8aa2961c19 | ||
|
|
304cdabc96 | ||
|
|
c60e272eb3 | ||
|
|
c074f55cb2 | ||
|
|
e6af29646e | ||
|
|
b4213328fe | ||
|
|
8a7628c9dc | ||
|
|
d52c146e12 | ||
|
|
1910a4bd4b | ||
|
|
bd0c552f54 | ||
|
|
b29ea98de4 | ||
|
|
dd1db87806 | ||
|
|
6f9e446577 | ||
|
|
664230dca8 | ||
|
|
1a24e7e0aa | ||
|
|
9239815ce6 | ||
|
|
116e19ec06 | ||
|
|
fc0ad622eb | ||
|
|
2c5cdb8780 | ||
|
|
9a309f32fa | ||
|
|
e2e54d342a | ||
|
|
42f7529495 | ||
|
|
f172151252 | ||
|
|
e2ad38d3e0 | ||
|
|
40cc32fc5a | ||
|
|
436c034fdd | ||
|
|
286b1848d9 | ||
|
|
7fffebf6df | ||
|
|
b1764478ec | ||
|
|
6b6a799206 | ||
|
|
0a82ed901e | ||
|
|
d733c9ed14 | ||
|
|
a752ea489c | ||
|
|
876a24586f | ||
|
|
ea2779cf9a | ||
|
|
77aa36163d | ||
|
|
b581d8ecb7 | ||
|
|
83b404d01e | ||
|
|
8deb92c3e5 | ||
|
|
20a6e0170c | ||
|
|
944a78807c | ||
|
|
0b02d294f4 | ||
|
|
a5d86536c3 | ||
|
|
71c08cfe0c | ||
|
|
8ab0d5fc48 | ||
|
|
57f81ee4c8 | ||
|
|
5c28adf266 | ||
|
|
5a57398f81 | ||
|
|
8121a384ef | ||
|
|
8666197e05 | ||
|
|
1ea2b8bbcb | ||
|
|
a71cedd8a9 | ||
|
|
04c5f583f6 | ||
|
|
7716ff4e8c | ||
|
|
6b51a116d1 | ||
|
|
b2f14dc177 | ||
|
|
da1d3b82f9 | ||
|
|
6282d8c828 | ||
|
|
73129b0ce5 | ||
|
|
f71e7a2f28 | ||
|
|
341da327e3 | ||
|
|
3d8adfa7e4 | ||
|
|
279d7769f5 | ||
|
|
b7d3b40353 | ||
|
|
7ecd691ee2 | ||
|
|
f3398c7dec | ||
|
|
90644e662d | ||
|
|
f5c5cb7fb9 | ||
|
|
312e79921a | ||
|
|
b83d346a86 | ||
|
|
3eed67f108 | ||
|
|
15f0bc63b2 | ||
|
|
0a4b0ec929 | ||
|
|
560f6cbf24 | ||
|
|
9165e0238f | ||
|
|
97d6be6809 | ||
|
|
4de14eba0c | ||
|
|
6c64023bf7 | ||
|
|
a923c288e6 | ||
|
|
4c1d8e8e85 | ||
|
|
02f2def88b | ||
|
|
4bcacc5d68 | ||
|
|
913dbe6b1a | ||
|
|
ce8164dd87 | ||
|
|
a5b412f546 | ||
|
|
82bb352624 | ||
|
|
ebbf2659b1 | ||
|
|
d0084becea | ||
|
|
6af2b37ac2 | ||
|
|
814fc6eabd | ||
|
|
50278a679a | ||
|
|
d42e9c75ef | ||
|
|
00b3dced2c | ||
|
|
5c0c00188f | ||
|
|
2ec56626f3 | ||
|
|
e87456b2f8 | ||
|
|
3609b515e5 | ||
|
|
a1609542c3 | ||
|
|
4c4625583a | ||
|
|
7b479316ea | ||
|
|
b021c7690f | ||
|
|
2be060796e | ||
|
|
1b4d55cca4 | ||
|
|
a8cea4119d | ||
|
|
e247aace8d | ||
|
|
41553e9b86 | ||
|
|
e875587260 | ||
|
|
5377483345 | ||
|
|
4112acfb8d | ||
|
|
f3bc02e11c | ||
|
|
8e411a898b | ||
|
|
915edbecc9 | ||
|
|
975a6c34bf | ||
|
|
cdd988b4de | ||
|
|
b58bc97422 | ||
|
|
482688ac3c | ||
|
|
aea31b5e28 | ||
|
|
d7cbc53b4b | ||
|
|
f74c6c2d19 | ||
|
|
3080d2ddc4 | ||
|
|
4ad5881760 | ||
|
|
7e55d1a4fd | ||
|
|
7ef5eed6e2 | ||
|
|
10aa41a7ea | ||
|
|
1f9b362b6f | ||
|
|
4bf9bfb521 | ||
|
|
1d7119114d | ||
|
|
e1b6df6fb1 | ||
|
|
7cf38bb01e | ||
|
|
e34ec22845 | ||
|
|
46506abeb8 | ||
|
|
95654cc4d4 | ||
|
|
47aded820d | ||
|
|
24444ebf08 | ||
|
|
bdc0df8350 | ||
|
|
b2c9a2973c | ||
|
|
da2a347511 | ||
|
|
6fbc3ba060 | ||
|
|
02eff06cd3 | ||
|
|
7586d4b494 | ||
|
|
9059f0fee6 | ||
|
|
c2af9e3d20 | ||
|
|
0b51366526 | ||
|
|
e40260bd9c | ||
|
|
cf2842840d | ||
|
|
17fa8fcb2c | ||
|
|
0d2f9864e2 | ||
|
|
89cbd91204 | ||
|
|
f4d9b57887 | ||
|
|
4b2e4afca5 | ||
|
|
dd1ba30c48 | ||
|
|
3ba4570691 | ||
|
|
848cfabcba | ||
|
|
1bbd10b909 | ||
|
|
a16a4f813d | ||
|
|
91cfa963b2 | ||
|
|
a35557eb62 | ||
|
|
aad4e47b6a | ||
|
|
1b177723ae | ||
|
|
99dba92bd3 | ||
|
|
e13ccff056 | ||
|
|
46528dd29d | ||
|
|
4f611ad810 | ||
|
|
af41985a64 | ||
|
|
d0864e06b5 | ||
|
|
6f0366e146 | ||
|
|
e0cdbcb28c | ||
|
|
f19b99194c | ||
|
|
43a55e2e35 | ||
|
|
b2743825ca | ||
|
|
d4f6cce56e | ||
|
|
6092d206b6 | ||
|
|
c8ad83cc91 | ||
|
|
7d31071ff8 | ||
|
|
c975ef15f1 | ||
|
|
f855011d34 | ||
|
|
fbcf0929d8 | ||
|
|
d89e75cbe8 | ||
|
|
ccaa42ad74 | ||
|
|
56d8dce622 | ||
|
|
c79baf98cf | ||
|
|
d1cab9f68c | ||
|
|
69c5c93353 | ||
|
|
28ebd683e4 | ||
|
|
d752edd625 | ||
|
|
1dab45d493 | ||
|
|
b99982d02b | ||
|
|
fff17ac6c1 | ||
|
|
4086257983 | ||
|
|
bd9e0ac281 | ||
|
|
b075d6db5e | ||
|
|
befd79cf14 | ||
|
|
07f68d2b14 | ||
|
|
d14889bd27 | ||
|
|
91e40c14f9 | ||
|
|
b7b2206262 | ||
|
|
f344d0319c | ||
|
|
0c8a1682b6 | ||
|
|
39866be3f1 | ||
|
|
947e82fa0f | ||
|
|
0335a64a21 | ||
|
|
a9e57e1c34 | ||
|
|
8a8279f97a | ||
|
|
b968889552 | ||
|
|
4068df5e50 | ||
|
|
dc42370322 | ||
|
|
8c24f14ee5 | ||
|
|
494d1743a2 | ||
|
|
4a30d9f6bb | ||
|
|
ed6d25067c | ||
|
|
445ae7e10e | ||
|
|
6f45609161 | ||
|
|
f1230e47f7 | ||
|
|
7e0ef6d43e | ||
|
|
14f9da544a | ||
|
|
5a84036e16 | ||
|
|
4dccf7b7b5 | ||
|
|
66060dbed4 | ||
|
|
cfb824588f | ||
|
|
d2b4316d7a | ||
|
|
3af69b433d | ||
|
|
a6733fa255 | ||
|
|
4277c54009 | ||
|
|
66baa7554a | ||
|
|
ffca4b0543 | ||
|
|
3e3c48314f | ||
|
|
06ff450d31 | ||
|
|
07c57cc640 | ||
|
|
a67f10c99e | ||
|
|
2882bcbf7b | ||
|
|
67cc5b0280 | ||
|
|
b42b178b71 | ||
|
|
7de05cd173 | ||
|
|
3db43743d9 | ||
|
|
14638e4ed8 | ||
|
|
e756b93810 | ||
|
|
358d83dcfc | ||
|
|
331c231a94 | ||
|
|
4403b65bae | ||
|
|
a27d80d765 | ||
|
|
04272fff81 | ||
|
|
e963708c54 | ||
|
|
08c4542847 | ||
|
|
553e9270e5 | ||
|
|
8a7297e131 | ||
|
|
0f260da8e6 | ||
|
|
77560ab3a8 | ||
|
|
e3b2f2d9a8 | ||
|
|
74e01a52b9 | ||
|
|
dc28ba42ef | ||
|
|
406150620a | ||
|
|
43f59a1135 | ||
|
|
5c02eaa66c | ||
|
|
b4eac84097 | ||
|
|
ec3b356f86 | ||
|
|
bf99d5c299 | ||
|
|
a297131440 | ||
|
|
bae2161ee3 | ||
|
|
0fe0de1a7f | ||
|
|
e7845115f6 | ||
|
|
bc11c3fab2 | ||
|
|
1b7546f3f9 | ||
|
|
663be30117 | ||
|
|
cf34713518 | ||
|
|
3f56a8ec53 | ||
|
|
35d105588b | ||
|
|
122d988ed2 | ||
|
|
9fcc5e7a67 | ||
|
|
9a492c3731 | ||
|
|
4f752031f3 | ||
|
|
19be8bb891 | ||
|
|
693e1b08c7 | ||
|
|
9aad380518 | ||
|
|
8c518c8d58 | ||
|
|
9af89a19db | ||
|
|
939b18b86c | ||
|
|
108e775a15 | ||
|
|
653692ade0 | ||
|
|
72c6bfee7e | ||
|
|
ac92939429 | ||
|
|
052957bbd0 | ||
|
|
97e6afe3dc | ||
|
|
1fd028dfb8 | ||
|
|
c73866f47c | ||
|
|
b0e120abee | ||
|
|
b2da38d401 | ||
|
|
cabe2579fa | ||
|
|
18a845ac55 | ||
|
|
a4d14f8259 | ||
|
|
9d084e62f7 | ||
|
|
0393fcd704 | ||
|
|
edb5b2ed5e |
@@ -38,9 +38,14 @@ SEND_REGISTRATION_MAIL=true
|
|||||||
SEND_ERROR_MESSAGE=true
|
SEND_ERROR_MESSAGE=true
|
||||||
SHOW_INCOMPLETE_TRANSLATIONS=false
|
SHOW_INCOMPLETE_TRANSLATIONS=false
|
||||||
|
|
||||||
|
CACHE_PREFIX=firefly
|
||||||
|
|
||||||
ANALYTICS_ID=
|
ANALYTICS_ID=
|
||||||
SITE_OWNER=mail@example.com
|
SITE_OWNER=mail@example.com
|
||||||
|
|
||||||
PUSHER_KEY=
|
PUSHER_KEY=
|
||||||
PUSHER_SECRET=
|
PUSHER_SECRET=
|
||||||
PUSHER_APP_ID=
|
PUSHER_APP_ID=
|
||||||
|
|
||||||
|
DEMO_USERNAME=
|
||||||
|
DEMO_PASSWORD=
|
||||||
@@ -5,14 +5,13 @@ php:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
- phpenv config-rm xdebug.ini
|
- phpenv config-rm xdebug.ini
|
||||||
- composer selfupdate
|
|
||||||
- rm composer.lock
|
- rm composer.lock
|
||||||
- composer update --no-scripts
|
- composer update --no-scripts
|
||||||
- php artisan clear-compiled
|
- php artisan clear-compiled
|
||||||
- php artisan optimize
|
- php artisan optimize
|
||||||
- php artisan env
|
- php artisan env
|
||||||
- ./test.sh -r
|
- cp .env.testing .env
|
||||||
- php artisan env
|
- mv storage/database/databasecopy.sqlite storage/database/database.sqlite
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- phpunit
|
- phpunit
|
||||||
36
CHANGELOG.md
36
CHANGELOG.md
@@ -2,7 +2,41 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
## [4.2.1] - 2015-05-25
|
|
||||||
|
## [4.3.0] - 2015-12-26
|
||||||
|
### Added
|
||||||
|
- New method of keeping track of available budget, see issue #489
|
||||||
|
- Support for Spanish
|
||||||
|
- Firefly III now has an extended demo mode. Will expand further in the future.
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- New favicon
|
||||||
|
- Import routine no longer gives transactions a description #483
|
||||||
|
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- All test data generation code.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Removed import accounts from search results #478
|
||||||
|
- Redirect after delete will no longer go back to deleted item #477
|
||||||
|
- Cannot math #482
|
||||||
|
- Fixed bug in virtual balance field #479
|
||||||
|
|
||||||
|
## [4.2.2] - 2016-12-18
|
||||||
|
### Added
|
||||||
|
- New budget report (still a bit of a beta)
|
||||||
|
- Can now edit user
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- New config for specific events. Still need to build Notifications.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Various bugs
|
||||||
|
- Issue #472 thanks to @zjean
|
||||||
|
|
||||||
|
## [4.2.1] - 2016-12-09
|
||||||
### Added
|
### Added
|
||||||
- BIC support (see #430)
|
- BIC support (see #430)
|
||||||
- New category report section and chart (see the general financial report)
|
- New category report section and chart (see the general financial report)
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -1,15 +1,21 @@
|
|||||||
# Firefly III [](https://secure.php.net/downloads.php#v7.0.4) [](https://packagist.org/packages/grumpydictator/firefly-iii) [](https://scrutinizer-ci.com/g/JC5/firefly-iii/?branch=master)
|
# Firefly III: A personal finances manager
|
||||||
|
|
||||||
[](https://travis-ci.org/JC5/firefly-iii)
|
[](https://secure.php.net/downloads.php#v7.0.4) [](https://packagist.org/packages/grumpydictator/firefly-iii) [](https://scrutinizer-ci.com/g/JC5/firefly-iii/?branch=master)
|
||||||
|
|
||||||
## A personal finances manager
|
[](https://travis-ci.org/JC5/firefly-iii) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA)
|
||||||
|
|
||||||
[](https://i.nder.be/hhfv03hp) [](https://i.nder.be/hhmwmqw9)
|
[](https://i.nder.be/h2b37243) [](https://i.nder.be/hv70pbwc)
|
||||||
|
|
||||||
[](https://i.nder.be/g63q05m0) [](https://i.nder.be/c2g30ngg)
|
[](https://i.nder.be/ccn0u2mp) [](https://i.nder.be/gm8hbh7z)
|
||||||
|
|
||||||
|
_(You can click on the images for a better view)_
|
||||||
|
|
||||||
"Firefly III" is a financial manager. It can help you keep track of expenses, income, budgets and everything in between. It even supports credit cards, shared household accounts and savings accounts! It's pretty fancy. You should use it to save and organise money.
|
"Firefly III" is a financial manager. It can help you keep track of expenses, income, budgets and everything in between. It even supports credit cards, shared household accounts and savings accounts! It's pretty fancy. You should use it to save and organise money.
|
||||||
|
|
||||||
|
## Try it out!
|
||||||
|
|
||||||
|
Try out Firefly III on the [demo site](https://firefly-iii.nder.be/).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
To install Firefly III, you'll need a web server (preferrably on Linux) and access to the command line. Then, please read the [installation guide](https://firefly-iii.github.io/installation-guide/).
|
To install Firefly III, you'll need a web server (preferrably on Linux) and access to the command line. Then, please read the [installation guide](https://firefly-iii.github.io/installation-guide/).
|
||||||
@@ -29,4 +35,6 @@ Firefly works on the principle that if you know where you're money is going, you
|
|||||||
|
|
||||||
Firefly is pretty awesome. [You can read more about Firefly III, and its features, on the Github Pages](https://firefly-iii.github.io/).
|
Firefly is pretty awesome. [You can read more about Firefly III, and its features, on the Github Pages](https://firefly-iii.github.io/).
|
||||||
|
|
||||||
|
If you like Firefly and if it helps you save lots of money, why not send me [a dime for every dollar saved](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA) (this is a joke, although the Paypal form works just fine, try it!)
|
||||||
|
|
||||||
If you want to contact me, please open an issue or [email me](mailto:thegrumpydictator@gmail.com).
|
If you want to contact me, please open an issue or [email me](mailto:thegrumpydictator@gmail.com).
|
||||||
|
|||||||
@@ -50,11 +50,10 @@ class CreateImport extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @SuppressWarnings(PHPMD.ExcessiveMethodLength) // cannot be helped
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
// find the file
|
|
||||||
/** @var UserRepositoryInterface $userRepository */
|
/** @var UserRepositoryInterface $userRepository */
|
||||||
$userRepository = app(UserRepositoryInterface::class);
|
$userRepository = app(UserRepositoryInterface::class);
|
||||||
$file = $this->argument('file');
|
$file = $this->argument('file');
|
||||||
@@ -67,7 +66,6 @@ class CreateImport extends Command
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to parse configuration data:
|
|
||||||
$configurationData = json_decode(file_get_contents($configuration));
|
$configurationData = json_decode(file_get_contents($configuration));
|
||||||
if (is_null($configurationData)) {
|
if (is_null($configurationData)) {
|
||||||
$this->error(sprintf('Firefly III cannot read the contents of configuration file "%s" (working directory: "%s").', $configuration, $cwd));
|
$this->error(sprintf('Firefly III cannot read the contents of configuration file "%s" (working directory: "%s").', $configuration, $cwd));
|
||||||
@@ -82,21 +80,17 @@ class CreateImport extends Command
|
|||||||
|
|
||||||
/** @var ImportJobRepositoryInterface $jobRepository */
|
/** @var ImportJobRepositoryInterface $jobRepository */
|
||||||
$jobRepository = app(ImportJobRepositoryInterface::class, [$user]);
|
$jobRepository = app(ImportJobRepositoryInterface::class, [$user]);
|
||||||
|
|
||||||
$job = $jobRepository->create($type);
|
$job = $jobRepository->create($type);
|
||||||
$this->line(sprintf('Created job "%s"...', $job->key));
|
$this->line(sprintf('Created job "%s"...', $job->key));
|
||||||
|
|
||||||
// put the file in the proper place:
|
|
||||||
Artisan::call('firefly:encrypt', ['file' => $file, 'key' => $job->key]);
|
Artisan::call('firefly:encrypt', ['file' => $file, 'key' => $job->key]);
|
||||||
$this->line('Stored import data...');
|
$this->line('Stored import data...');
|
||||||
|
|
||||||
// store the configuration in the job:
|
|
||||||
$job->configuration = $configurationData;
|
$job->configuration = $configurationData;
|
||||||
$job->status = 'settings_complete';
|
$job->status = 'settings_complete';
|
||||||
$job->save();
|
$job->save();
|
||||||
$this->line('Stored configuration...');
|
$this->line('Stored configuration...');
|
||||||
|
|
||||||
// if user wants to run it, do!
|
|
||||||
if ($this->option('start') === true) {
|
if ($this->option('start') === true) {
|
||||||
$this->line('The import will start in a moment. This process is not visible...');
|
$this->line('The import will start in a moment. This process is not visible...');
|
||||||
Log::debug('Go for import!');
|
Log::debug('Go for import!');
|
||||||
@@ -109,10 +103,10 @@ class CreateImport extends Command
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five exactly.
|
||||||
*/
|
*/
|
||||||
private function validArguments(): bool
|
private function validArguments(): bool
|
||||||
{
|
{
|
||||||
// find the file
|
|
||||||
/** @var UserRepositoryInterface $userRepository */
|
/** @var UserRepositoryInterface $userRepository */
|
||||||
$userRepository = app(UserRepositoryInterface::class);
|
$userRepository = app(UserRepositoryInterface::class);
|
||||||
$file = $this->argument('file');
|
$file = $this->argument('file');
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use FireflyIII\Import\Logging\CommandHandler;
|
|||||||
use FireflyIII\Models\ImportJob;
|
use FireflyIII\Models\ImportJob;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Log;
|
use Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,32 +70,15 @@ class Import extends Command
|
|||||||
$monolog = Log::getMonolog();
|
$monolog = Log::getMonolog();
|
||||||
$handler = new CommandHandler($this);
|
$handler = new CommandHandler($this);
|
||||||
$monolog->pushHandler($handler);
|
$monolog->pushHandler($handler);
|
||||||
|
$importProcedure = new ImportProcedure;
|
||||||
|
$result = $importProcedure->runImport($job);
|
||||||
|
|
||||||
$result = ImportProcedure::runImport($job);
|
// display result to user:
|
||||||
|
$this->presentResults($result);
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int $index
|
|
||||||
* @var TransactionJournal $journal
|
|
||||||
*/
|
|
||||||
foreach ($result as $index => $journal) {
|
|
||||||
if (!is_null($journal->id)) {
|
|
||||||
$this->line(sprintf('Line #%d has been imported as transaction #%d.', $index, $journal->id));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$this->error(sprintf('Could not store line #%d', $index));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->line('The import has completed.');
|
$this->line('The import has completed.');
|
||||||
|
|
||||||
// get any errors from the importer:
|
// get any errors from the importer:
|
||||||
$extendedStatus = $job->extended_status;
|
$this->presentErrors($job);
|
||||||
if (isset($extendedStatus['errors']) && count($extendedStatus['errors']) > 0) {
|
|
||||||
$this->line(sprintf('The following %d error(s) occured during the import:', count($extendedStatus['errors'])));
|
|
||||||
foreach ($extendedStatus['errors'] as $error) {
|
|
||||||
$this->error($error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -120,4 +104,36 @@ class Import extends Command
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ImportJob $job
|
||||||
|
*/
|
||||||
|
private function presentErrors(ImportJob $job)
|
||||||
|
{
|
||||||
|
$extendedStatus = $job->extended_status;
|
||||||
|
if (isset($extendedStatus['errors']) && count($extendedStatus['errors']) > 0) {
|
||||||
|
$this->line(sprintf('The following %d error(s) occured during the import:', count($extendedStatus['errors'])));
|
||||||
|
foreach ($extendedStatus['errors'] as $error) {
|
||||||
|
$this->error($error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $result
|
||||||
|
*/
|
||||||
|
private function presentResults(Collection $result)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int $index
|
||||||
|
* @var TransactionJournal $journal
|
||||||
|
*/
|
||||||
|
foreach ($result as $index => $journal) {
|
||||||
|
if (!is_null($journal->id)) {
|
||||||
|
$this->line(sprintf('Line #%d has been imported as transaction #%d.', $index, $journal->id));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->error(sprintf('Could not store line #%d', $index));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,42 +60,26 @@ class ScanAttachments extends Command
|
|||||||
/** @var Attachment $attachment */
|
/** @var Attachment $attachment */
|
||||||
foreach ($attachments as $attachment) {
|
foreach ($attachments as $attachment) {
|
||||||
$fileName = $attachment->fileName();
|
$fileName = $attachment->fileName();
|
||||||
|
|
||||||
// try to grab file content:
|
|
||||||
try {
|
try {
|
||||||
$content = $disk->get($fileName);
|
$content = $disk->get($fileName);
|
||||||
} catch (FileNotFoundException $e) {
|
} catch (FileNotFoundException $e) {
|
||||||
$this->error(sprintf('Could not find data for attachment #%d', $attachment->id));
|
$this->error(sprintf('Could not find data for attachment #%d', $attachment->id));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// try to decrypt content.
|
|
||||||
try {
|
try {
|
||||||
$decrypted = Crypt::decrypt($content);
|
$decrypted = Crypt::decrypt($content);
|
||||||
} catch (DecryptException $e) {
|
} catch (DecryptException $e) {
|
||||||
$this->error(sprintf('Could not decrypt data of attachment #%d', $attachment->id));
|
$this->error(sprintf('Could not decrypt data of attachment #%d', $attachment->id));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make temp file:
|
|
||||||
$tmpfname = tempnam(sys_get_temp_dir(), 'FireflyIII');
|
$tmpfname = tempnam(sys_get_temp_dir(), 'FireflyIII');
|
||||||
|
|
||||||
// store content in temp file:
|
|
||||||
file_put_contents($tmpfname, $decrypted);
|
file_put_contents($tmpfname, $decrypted);
|
||||||
|
|
||||||
// get md5 and mime
|
|
||||||
$md5 = md5_file($tmpfname);
|
$md5 = md5_file($tmpfname);
|
||||||
$mime = mime_content_type($tmpfname);
|
$mime = mime_content_type($tmpfname);
|
||||||
|
|
||||||
// update attachment:
|
|
||||||
$attachment->md5 = $md5;
|
$attachment->md5 = $md5;
|
||||||
$attachment->mime = $mime;
|
$attachment->mime = $mime;
|
||||||
$attachment->save();
|
$attachment->save();
|
||||||
|
|
||||||
|
|
||||||
$this->line(sprintf('Fixed attachment #%d', $attachment->id));
|
$this->line(sprintf('Fixed attachment #%d', $attachment->id));
|
||||||
|
|
||||||
// find file:
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ use Crypt;
|
|||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\Category;
|
|
||||||
use FireflyIII\Models\Tag;
|
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
@@ -126,16 +124,16 @@ class VerifyDatabase extends Command
|
|||||||
{
|
{
|
||||||
$set = Budget::leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
|
$set = Budget::leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
|
||||||
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
|
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
|
||||||
->groupBy(['budgets.id', 'budgets.name', 'budgets.user_id', 'users.email'])
|
->groupBy(['budgets.id', 'budgets.name', 'budgets.encrypted', 'budgets.user_id', 'users.email'])
|
||||||
->whereNull('budget_limits.id')
|
->whereNull('budget_limits.id')
|
||||||
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'users.email']);
|
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'budgets.encrypted', 'users.email']);
|
||||||
|
|
||||||
/** @var stdClass $entry */
|
/** @var Budget $entry */
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
|
$name = $entry->encrypted ? Crypt::decrypt($entry->name) : $entry->name;
|
||||||
$line = sprintf(
|
$line = sprintf(
|
||||||
'Notice: User #%d (%s) has budget #%d ("%s") which has no budget limits.',
|
'Notice: User #%d (%s) has budget #%d ("%s") which has no budget limits.',
|
||||||
$entry->user_id, $entry->email, $entry->id, Crypt::decrypt($entry->name)
|
$entry->user_id, $entry->email, $entry->id, $name
|
||||||
);
|
);
|
||||||
$this->line($line);
|
$this->line($line);
|
||||||
}
|
}
|
||||||
@@ -192,7 +190,10 @@ class VerifyDatabase extends Command
|
|||||||
->where('transaction_types.type', $transactionType)
|
->where('transaction_types.type', $transactionType)
|
||||||
->whereIn('account_types.type', $accountTypes)
|
->whereIn('account_types.type', $accountTypes)
|
||||||
->whereNull('transaction_journals.deleted_at')
|
->whereNull('transaction_journals.deleted_at')
|
||||||
->get(['transaction_journals.id', 'transaction_journals.user_id', 'users.email', 'account_types.type as a_type', 'transaction_types.type']);
|
->get(
|
||||||
|
['transaction_journals.id', 'transaction_journals.user_id', 'users.email', 'account_types.type as a_type',
|
||||||
|
'transaction_types.type']
|
||||||
|
);
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
$this->error(
|
$this->error(
|
||||||
sprintf(
|
sprintf(
|
||||||
|
|||||||
0
app/Console/Kernel.php
Executable file → Normal file
0
app/Console/Kernel.php
Executable file → Normal file
41
app/Events/BlockedBadLogin.php
Normal file
41
app/Events/BlockedBadLogin.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BlockedBadLogin.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class LockedOutUser
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class BlockedBadLogin extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $email;
|
||||||
|
public $ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance. This event is triggered when a user gets themselves locked out.
|
||||||
|
*
|
||||||
|
* @param string $email
|
||||||
|
* @param string $ipAddress
|
||||||
|
*/
|
||||||
|
public function __construct(string $email, string $ipAddress)
|
||||||
|
{
|
||||||
|
$this->email = $email;
|
||||||
|
$this->ipAddress = $ipAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
app/Events/BlockedUseOfDomain.php
Normal file
42
app/Events/BlockedUseOfDomain.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BlockedUseOfDomain.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BlockedUseOfDomain
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class BlockedUseOfDomain extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $email;
|
||||||
|
public $ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance. This event is triggered when a user tries to register with a banned domain (on blocked domain list).
|
||||||
|
*
|
||||||
|
* @param string $email
|
||||||
|
* @param string $ipAddress
|
||||||
|
*/
|
||||||
|
public function __construct(string $email, string $ipAddress)
|
||||||
|
{
|
||||||
|
$this->email = $email;
|
||||||
|
$this->ipAddress = $ipAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
app/Events/BlockedUseOfEmail.php
Normal file
42
app/Events/BlockedUseOfEmail.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BlockedUseOfEmail.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BlockedUseOfEmail
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class BlockedUseOfEmail extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $email;
|
||||||
|
public $ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance. This event is triggered when a user tries to register with a banned email address (already used before).
|
||||||
|
*
|
||||||
|
* @param string $email
|
||||||
|
* @param string $ipAddress
|
||||||
|
*/
|
||||||
|
public function __construct(string $email, string $ipAddress)
|
||||||
|
{
|
||||||
|
$this->email = $email;
|
||||||
|
$this->ipAddress = $ipAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
app/Events/BlockedUserLogin.php
Normal file
42
app/Events/BlockedUserLogin.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BlockedUserLogin.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BlockedUserLogin
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class BlockedUserLogin extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $ipAddress;
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance. This event is triggered when a blocked user logs in.
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
* @param string $ipAddress
|
||||||
|
*/
|
||||||
|
public function __construct(User $user, string $ipAddress)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->ipAddress = $ipAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
app/Events/DeletedUser.php
Normal file
38
app/Events/DeletedUser.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* DeletedUser.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class DeletedUser
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class DeletedUser extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance. This event is triggered when a user deletes themselves.
|
||||||
|
*
|
||||||
|
* @param string $email
|
||||||
|
*/
|
||||||
|
public function __construct(string $email)
|
||||||
|
{
|
||||||
|
$this->email = $email;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
app/Events/LockedOutUser.php
Normal file
41
app/Events/LockedOutUser.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* LockedOutUser.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class LockedOutUser
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class LockedOutUser extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $email;
|
||||||
|
public $ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance. This event is triggered when a user gets themselves locked out.
|
||||||
|
*
|
||||||
|
* @param string $email
|
||||||
|
* @param string $ipAddress
|
||||||
|
*/
|
||||||
|
public function __construct(string $email, string $ipAddress)
|
||||||
|
{
|
||||||
|
$this->email = $email;
|
||||||
|
$this->ipAddress = $ipAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
app/Exceptions/Handler.php
Executable file → Normal file
0
app/Exceptions/Handler.php
Executable file → Normal file
@@ -30,7 +30,7 @@ use ZipArchive;
|
|||||||
*
|
*
|
||||||
* @package FireflyIII\Export
|
* @package FireflyIII\Export
|
||||||
*/
|
*/
|
||||||
class Processor
|
class Processor implements ProcessorInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
/** @var Collection */
|
/** @var Collection */
|
||||||
|
|||||||
67
app/Export/ProcessorInterface.php
Normal file
67
app/Export/ProcessorInterface.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ProcessorInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface ProcessorInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export
|
||||||
|
*/
|
||||||
|
interface ProcessorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processor constructor.
|
||||||
|
*
|
||||||
|
* @param array $settings
|
||||||
|
*/
|
||||||
|
public function __construct(array $settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function collectAttachments(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function collectJournals(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function collectOldUploads(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function convertJournals(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function createZipFile(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function exportJournals(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getFiles(): Collection;
|
||||||
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* AccountChartGeneratorInterface.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
|
|
||||||
namespace FireflyIII\Generator\Chart\Account;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use FireflyIII\Models\Account;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface AccountChartGeneratorInterface
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\Account
|
|
||||||
*/
|
|
||||||
interface AccountChartGeneratorInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $values
|
|
||||||
* @param array $names
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function pieChart(array $values, array $names): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $accounts
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $accounts
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function frontpage(Collection $accounts, Carbon $start, Carbon $end): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $accounts
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function revenueAccounts(Collection $accounts, Carbon $start, Carbon $end): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Account $account
|
|
||||||
* @param array $labels
|
|
||||||
* @param array $dataSet
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function single(Account $account, array $labels, array $dataSet): array;
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ChartJsAccountChartGenerator.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
namespace FireflyIII\Generator\Chart\Account;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use FireflyIII\Models\Account;
|
|
||||||
use FireflyIII\Support\ChartColour;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ChartJsAccountChartGenerator
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\Account
|
|
||||||
*/
|
|
||||||
class ChartJsAccountChartGenerator implements AccountChartGeneratorInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $accounts
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'count' => 1,
|
|
||||||
'labels' => [], 'datasets' => [[
|
|
||||||
'label' => trans('firefly.spent'),
|
|
||||||
'data' => []]]];
|
|
||||||
foreach ($accounts as $account) {
|
|
||||||
if ($account->difference > 0) {
|
|
||||||
$data['labels'][] = $account->name;
|
|
||||||
$data['datasets'][0]['data'][] = $account->difference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $accounts
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function frontpage(Collection $accounts, Carbon $start, Carbon $end): array
|
|
||||||
{
|
|
||||||
// language:
|
|
||||||
$format = (string)trans('config.month_and_day');
|
|
||||||
$data = ['count' => 0, 'labels' => [], 'datasets' => [],];
|
|
||||||
$current = clone $start;
|
|
||||||
while ($current <= $end) {
|
|
||||||
$data['labels'][] = $current->formatLocalized($format);
|
|
||||||
$current->addDay();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($accounts as $account) {
|
|
||||||
$data['datasets'][] = [
|
|
||||||
'label' => $account->name,
|
|
||||||
'fillColor' => 'rgba(220,220,220,0.2)',
|
|
||||||
'strokeColor' => 'rgba(220,220,220,1)',
|
|
||||||
'pointColor' => 'rgba(220,220,220,1)',
|
|
||||||
'pointStrokeColor' => '#fff',
|
|
||||||
'pointHighlightFill' => '#fff',
|
|
||||||
'pointHighlightStroke' => 'rgba(220,220,220,1)',
|
|
||||||
'data' => $account->balances,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
$data['count'] = count($data['datasets']);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $values
|
|
||||||
* @param array $names
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function pieChart(array $values, array $names): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'datasets' => [
|
|
||||||
0 => [],
|
|
||||||
],
|
|
||||||
'labels' => [],
|
|
||||||
];
|
|
||||||
$index = 0;
|
|
||||||
foreach ($values as $categoryId => $value) {
|
|
||||||
|
|
||||||
// make larger than 0
|
|
||||||
if (bccomp($value, '0') === -1) {
|
|
||||||
$value = bcmul($value, '-1');
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['datasets'][0]['data'][] = round($value, 2);
|
|
||||||
$data['datasets'][0]['backgroundColor'][] = ChartColour::getColour($index);
|
|
||||||
$data['labels'][] = $names[$categoryId];
|
|
||||||
$index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $accounts
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function revenueAccounts(Collection $accounts, Carbon $start, Carbon $end): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'count' => 1,
|
|
||||||
'labels' => [], 'datasets' => [[
|
|
||||||
'label' => trans('firefly.earned'),
|
|
||||||
'data' => []]]];
|
|
||||||
foreach ($accounts as $account) {
|
|
||||||
if ($account->difference > 0) {
|
|
||||||
$data['labels'][] = $account->name;
|
|
||||||
$data['datasets'][0]['data'][] = $account->difference;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Account $account
|
|
||||||
* @param array $labels
|
|
||||||
* @param array $dataSet
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function single(Account $account, array $labels, array $dataSet): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'count' => 1,
|
|
||||||
'labels' => $labels,
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'label' => $account->name,
|
|
||||||
'data' => $dataSet,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
149
app/Generator/Chart/Basic/ChartJsGenerator.php
Normal file
149
app/Generator/Chart/Basic/ChartJsGenerator.php
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ChartJsGenerator.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Chart\Basic;
|
||||||
|
|
||||||
|
use FireflyIII\Support\ChartColour;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ChartJsGenerator
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Basic
|
||||||
|
*/
|
||||||
|
class ChartJsGenerator implements GeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will generate a Chart JS compatible array from the given input. Expects this format
|
||||||
|
*
|
||||||
|
* Will take labels for all from first set.
|
||||||
|
*
|
||||||
|
* 0: [
|
||||||
|
* 'label' => 'label of set',
|
||||||
|
* 'type' => bar or line, optional
|
||||||
|
* 'yAxisID' => ID of yAxis, optional, will not be included when unused.
|
||||||
|
* 'fill' => if to fill a line? optional, will not be included when unused.
|
||||||
|
* 'entries' =>
|
||||||
|
* [
|
||||||
|
* 'label-of-entry' => 'value'
|
||||||
|
* ]
|
||||||
|
* ]
|
||||||
|
* 1: [
|
||||||
|
* 'label' => 'label of another set',
|
||||||
|
* 'type' => bar or line, optional
|
||||||
|
* 'yAxisID' => ID of yAxis, optional, will not be included when unused.
|
||||||
|
* 'fill' => if to fill a line? optional, will not be included when unused.
|
||||||
|
* 'entries' =>
|
||||||
|
* [
|
||||||
|
* 'label-of-entry' => 'value'
|
||||||
|
* ]
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiSet(array $data): array
|
||||||
|
{
|
||||||
|
reset($data);
|
||||||
|
$first = current($data);
|
||||||
|
$labels = array_keys($first['entries']);
|
||||||
|
|
||||||
|
$chartData = [
|
||||||
|
'count' => count($data),
|
||||||
|
'labels' => $labels, // take ALL labels from the first set.
|
||||||
|
'datasets' => [],
|
||||||
|
];
|
||||||
|
unset($first, $labels);
|
||||||
|
|
||||||
|
foreach ($data as $set) {
|
||||||
|
$currentSet = [
|
||||||
|
'label' => $set['label'],
|
||||||
|
'type' => $set['type'] ?? 'line',
|
||||||
|
'data' => array_values($set['entries']),
|
||||||
|
];
|
||||||
|
if (isset($set['yAxisID'])) {
|
||||||
|
$currentSet['yAxisID'] = $set['yAxisID'];
|
||||||
|
}
|
||||||
|
if (isset($set['fill'])) {
|
||||||
|
$currentSet['fill'] = $set['fill'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$chartData['datasets'][] = $currentSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $chartData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expects data as:
|
||||||
|
*
|
||||||
|
* key => value
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function pieChart(array $data): array
|
||||||
|
{
|
||||||
|
$chartData = [
|
||||||
|
'datasets' => [
|
||||||
|
0 => [],
|
||||||
|
],
|
||||||
|
'labels' => [],
|
||||||
|
];
|
||||||
|
$index = 0;
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
|
||||||
|
// make larger than 0
|
||||||
|
if (bccomp($value, '0') === -1) {
|
||||||
|
$value = bcmul($value, '-1');
|
||||||
|
}
|
||||||
|
|
||||||
|
$chartData['datasets'][0]['data'][] = round($value, 2);
|
||||||
|
$chartData['datasets'][0]['backgroundColor'][] = ChartColour::getColour($index);
|
||||||
|
$chartData['labels'][] = $key;
|
||||||
|
$index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $chartData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will generate a (ChartJS) compatible array from the given input. Expects this format:
|
||||||
|
*
|
||||||
|
* 'label-of-entry' => value
|
||||||
|
* 'label-of-entry' => value
|
||||||
|
*
|
||||||
|
* @param string $setLabel
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function singleSet(string $setLabel, array $data): array
|
||||||
|
{
|
||||||
|
$chartData = [
|
||||||
|
'count' => 1,
|
||||||
|
'labels' => array_keys($data), // take ALL labels from the first set.
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => $setLabel,
|
||||||
|
'data' => array_values($data),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return $chartData;
|
||||||
|
}
|
||||||
|
}
|
||||||
73
app/Generator/Chart/Basic/GeneratorInterface.php
Normal file
73
app/Generator/Chart/Basic/GeneratorInterface.php
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* GeneratorInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Chart\Basic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface GeneratorInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Basic
|
||||||
|
*/
|
||||||
|
interface GeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will generate a (ChartJS) compatible array from the given input. Expects this format:
|
||||||
|
*
|
||||||
|
* 0: [
|
||||||
|
* 'label' => 'label of set',
|
||||||
|
* 'entries' =>
|
||||||
|
* [
|
||||||
|
* 'label-of-entry' => 'value'
|
||||||
|
* ]
|
||||||
|
* ]
|
||||||
|
* 1: [
|
||||||
|
* 'label' => 'label of another set',
|
||||||
|
* 'entries' =>
|
||||||
|
* [
|
||||||
|
* 'label-of-entry' => 'value'
|
||||||
|
* ]
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiSet(array $data): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expects data as:
|
||||||
|
*
|
||||||
|
* key => value
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function pieChart(array $data): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will generate a (ChartJS) compatible array from the given input. Expects this format:
|
||||||
|
*
|
||||||
|
* 'label-of-entry' => value
|
||||||
|
* 'label-of-entry' => value
|
||||||
|
*
|
||||||
|
* @param string $setLabel
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function singleSet(string $setLabel, array $data): array;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* BillChartGeneratorInterface.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
|
|
||||||
namespace FireflyIII\Generator\Chart\Bill;
|
|
||||||
|
|
||||||
|
|
||||||
use FireflyIII\Models\Bill;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface BillChartGeneratorInterface
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\Bill
|
|
||||||
*/
|
|
||||||
interface BillChartGeneratorInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $paid
|
|
||||||
* @param string $unpaid
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function frontpage(string $paid, string $unpaid): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Bill $bill
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function single(Bill $bill, Collection $entries): array;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ChartJsBillChartGenerator.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
|
|
||||||
namespace FireflyIII\Generator\Chart\Bill;
|
|
||||||
|
|
||||||
use FireflyIII\Models\Bill;
|
|
||||||
use FireflyIII\Models\Transaction;
|
|
||||||
use FireflyIII\Support\ChartColour;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ChartJsBillChartGenerator
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\Bill
|
|
||||||
*/
|
|
||||||
class ChartJsBillChartGenerator implements BillChartGeneratorInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $paid
|
|
||||||
* @param string $unpaid
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function frontpage(string $paid, string $unpaid): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'data' => [round($unpaid, 2), round(bcmul($paid, '-1'), 2)],
|
|
||||||
'backgroundColor' => [ChartColour::getColour(0), ChartColour::getColour(1)],
|
|
||||||
],
|
|
||||||
|
|
||||||
],
|
|
||||||
'labels' => [strval(trans('firefly.unpaid')), strval(trans('firefly.paid'))],
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Bill $bill
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function single(Bill $bill, Collection $entries): array
|
|
||||||
{
|
|
||||||
$format = (string)trans('config.month');
|
|
||||||
$data = ['count' => 3, 'labels' => [], 'datasets' => [],];
|
|
||||||
$minAmount = [];
|
|
||||||
$maxAmount = [];
|
|
||||||
$actualAmount = [];
|
|
||||||
/** @var Transaction $entry */
|
|
||||||
foreach ($entries as $entry) {
|
|
||||||
$data['labels'][] = $entry->date->formatLocalized($format);
|
|
||||||
$minAmount[] = round($bill->amount_min, 2);
|
|
||||||
$maxAmount[] = round($bill->amount_max, 2);
|
|
||||||
// journalAmount has been collected in BillRepository::getJournals
|
|
||||||
$actualAmount[] = bcmul($entry->transaction_amount, '-1');
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['datasets'][] = [
|
|
||||||
'type' => 'bar',
|
|
||||||
'label' => trans('firefly.minAmount'),
|
|
||||||
'data' => $minAmount,
|
|
||||||
];
|
|
||||||
$data['datasets'][] = [
|
|
||||||
'type' => 'line',
|
|
||||||
'label' => trans('firefly.billEntry'),
|
|
||||||
'data' => $actualAmount,
|
|
||||||
];
|
|
||||||
$data['datasets'][] = [
|
|
||||||
'type' => 'bar',
|
|
||||||
'label' => trans('firefly.maxAmount'),
|
|
||||||
'data' => $maxAmount,
|
|
||||||
];
|
|
||||||
|
|
||||||
$data['count'] = count($data['datasets']);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* BudgetChartGeneratorInterface.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
|
|
||||||
namespace FireflyIII\Generator\Chart\Budget;
|
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface BudgetChartGeneratorInterface
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\Budget
|
|
||||||
*/
|
|
||||||
interface BudgetChartGeneratorInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
* @param string $dateFormat
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function budgetLimit(Collection $entries, string $dateFormat): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function frontpage(Collection $entries): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function period(array $entries): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function periodNoBudget(array $entries): array;
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ChartJsBudgetChartGenerator.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
namespace FireflyIII\Generator\Chart\Budget;
|
|
||||||
|
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ChartJsBudgetChartGenerator
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\Budget
|
|
||||||
*/
|
|
||||||
class ChartJsBudgetChartGenerator implements BudgetChartGeneratorInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param Collection $entries
|
|
||||||
* @param string $dateFormat
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function budgetLimit(Collection $entries, string $dateFormat = 'month_and_day'): array
|
|
||||||
{
|
|
||||||
$format = strval(trans('config.' . $dateFormat));
|
|
||||||
$data = [
|
|
||||||
'labels' => [],
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'label' => 'Amount',
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
/** @var array $entry */
|
|
||||||
foreach ($entries as $entry) {
|
|
||||||
$data['labels'][] = $entry[0]->formatLocalized($format);
|
|
||||||
$data['datasets'][0]['data'][] = $entry[1];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['count'] = count($data['datasets']);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function frontpage(Collection $entries): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'count' => 0,
|
|
||||||
'labels' => [],
|
|
||||||
'datasets' => [],
|
|
||||||
];
|
|
||||||
$left = [];
|
|
||||||
$spent = [];
|
|
||||||
$overspent = [];
|
|
||||||
$filtered = $entries->filter(
|
|
||||||
function ($entry) {
|
|
||||||
return ($entry[1] != 0 || $entry[2] != 0 || $entry[3] != 0);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
foreach ($filtered as $entry) {
|
|
||||||
$data['labels'][] = $entry[0];
|
|
||||||
$left[] = round($entry[1], 2);
|
|
||||||
$spent[] = round(bcmul($entry[2], '-1'), 2); // spent is coming in negative, must be positive
|
|
||||||
$overspent[] = round(bcmul($entry[3], '-1'), 2); // same
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['datasets'][] = [
|
|
||||||
'label' => trans('firefly.overspent'),
|
|
||||||
'data' => $overspent,
|
|
||||||
];
|
|
||||||
$data['datasets'][] = [
|
|
||||||
'label' => trans('firefly.left'),
|
|
||||||
'data' => $left,
|
|
||||||
];
|
|
||||||
$data['datasets'][] = [
|
|
||||||
'label' => trans('firefly.spent'),
|
|
||||||
'data' => $spent,
|
|
||||||
];
|
|
||||||
|
|
||||||
$data['count'] = 3;
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function period(array $entries): array
|
|
||||||
{
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'labels' => array_keys($entries),
|
|
||||||
'datasets' => [
|
|
||||||
0 => [
|
|
||||||
'label' => trans('firefly.budgeted'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
1 => [
|
|
||||||
'label' => trans('firefly.spent'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'count' => 2,
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($entries as $label => $entry) {
|
|
||||||
// data set 0 is budgeted
|
|
||||||
// data set 1 is spent:
|
|
||||||
$data['datasets'][0]['data'][] = $entry['budgeted'];
|
|
||||||
$data['datasets'][1]['data'][] = round(($entry['spent'] * -1), 2);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function periodNoBudget(array $entries): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'labels' => array_keys($entries),
|
|
||||||
'datasets' => [
|
|
||||||
0 => [
|
|
||||||
'label' => trans('firefly.spent'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'count' => 1,
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($entries as $label => $entry) {
|
|
||||||
// data set 0 is budgeted
|
|
||||||
// data set 1 is spent:
|
|
||||||
$data['datasets'][0]['data'][] = round(($entry['spent'] * -1), 2);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* CategoryChartGeneratorInterface.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
|
|
||||||
namespace FireflyIII\Generator\Chart\Category;
|
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface CategoryChartGeneratorInterface
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\Category
|
|
||||||
*/
|
|
||||||
interface CategoryChartGeneratorInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function all(Collection $entries): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function frontpage(Collection $entries): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function mainReportChart(array $entries): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function period(Collection $entries): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $data
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function pieChart(array $data): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function reportPeriod(array $entries): array;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ChartJsCategoryChartGenerator.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
namespace FireflyIII\Generator\Chart\Category;
|
|
||||||
|
|
||||||
use FireflyIII\Support\ChartColour;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ChartJsCategoryChartGenerator
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\Category
|
|
||||||
*/
|
|
||||||
class ChartJsCategoryChartGenerator implements CategoryChartGeneratorInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function all(Collection $entries): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'count' => 2,
|
|
||||||
'labels' => [],
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.spent'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.earned'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($entries as $entry) {
|
|
||||||
$data['labels'][] = $entry[1];
|
|
||||||
$spent = $entry[2];
|
|
||||||
$earned = $entry[3];
|
|
||||||
|
|
||||||
$data['datasets'][0]['data'][] = bccomp($spent, '0') === 0 ? null : round(bcmul($spent, '-1'), 4);
|
|
||||||
$data['datasets'][1]['data'][] = bccomp($earned, '0') === 0 ? null : round($earned, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function frontpage(Collection $entries): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'count' => 1,
|
|
||||||
'labels' => [],
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.spent'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
foreach ($entries as $entry) {
|
|
||||||
if ($entry->spent != 0) {
|
|
||||||
$data['labels'][] = $entry->name;
|
|
||||||
$data['datasets'][0]['data'][] = round(bcmul($entry->spent, '-1'), 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function mainReportChart(array $entries): array
|
|
||||||
{
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'count' => 0,
|
|
||||||
'labels' => array_keys($entries),
|
|
||||||
'datasets' => [],
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
foreach ($entries as $row) {
|
|
||||||
foreach ($row['in'] as $categoryId => $amount) {
|
|
||||||
// get in:
|
|
||||||
$data['datasets'][$categoryId . 'in']['data'][] = round($amount, 2);
|
|
||||||
|
|
||||||
// get out:
|
|
||||||
$opposite = $row['out'][$categoryId];
|
|
||||||
$data['datasets'][$categoryId . 'out']['data'][] = round($opposite, 2);
|
|
||||||
|
|
||||||
// set name:
|
|
||||||
$data['datasets'][$categoryId . 'out']['label'] = $row['name'][$categoryId] . ' (' . strtolower(strval(trans('firefly.expenses'))) . ')';
|
|
||||||
$data['datasets'][$categoryId . 'in']['label'] = $row['name'][$categoryId] . ' (' . strtolower(strval(trans('firefly.income'))) . ')';
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove empty rows:
|
|
||||||
foreach ($data['datasets'] as $key => $content) {
|
|
||||||
if (array_sum($content['data']) === 0.0) {
|
|
||||||
unset($data['datasets'][$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// re-key the datasets array:
|
|
||||||
$data['datasets'] = array_values($data['datasets']);
|
|
||||||
$data['count'] = count($data['datasets']);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function period(Collection $entries): array
|
|
||||||
{
|
|
||||||
return $this->all($entries);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function reportPeriod(array $entries): array
|
|
||||||
{
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'labels' => array_keys($entries),
|
|
||||||
'datasets' => [
|
|
||||||
0 => [
|
|
||||||
'label' => trans('firefly.earned'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
1 => [
|
|
||||||
'label' => trans('firefly.spent'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'count' => 2,
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($entries as $label => $entry) {
|
|
||||||
// data set 0 is budgeted
|
|
||||||
// data set 1 is spent:
|
|
||||||
$data['datasets'][0]['data'][] = round($entry['earned'], 2);
|
|
||||||
$data['datasets'][1]['data'][] = round(bcmul($entry['spent'], '-1'), 2);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function pieChart(array $entries): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'datasets' => [
|
|
||||||
0 => [],
|
|
||||||
],
|
|
||||||
'labels' => [],
|
|
||||||
];
|
|
||||||
$index = 0;
|
|
||||||
foreach ($entries as $entry) {
|
|
||||||
|
|
||||||
if (bccomp($entry['amount'], '0') === -1) {
|
|
||||||
$entry['amount'] = bcmul($entry['amount'], '-1');
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['datasets'][0]['data'][] = round($entry['amount'], 2);
|
|
||||||
$data['datasets'][0]['backgroundColor'][] = ChartColour::getColour($index);
|
|
||||||
$data['labels'][] = $entry['name'];
|
|
||||||
$index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ChartJsPiggyBankChartGenerator.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
namespace FireflyIII\Generator\Chart\PiggyBank;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ChartJsPiggyBankChartGenerator
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\PiggyBank
|
|
||||||
*/
|
|
||||||
class ChartJsPiggyBankChartGenerator implements PiggyBankChartGeneratorInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $set
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function history(Collection $set): array
|
|
||||||
{
|
|
||||||
|
|
||||||
// language:
|
|
||||||
$format = (string)trans('config.month_and_day');
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'count' => 1,
|
|
||||||
'labels' => [],
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'label' => 'Diff',
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
$sum = '0';
|
|
||||||
foreach ($set as $key => $value) {
|
|
||||||
$date = new Carbon($key);
|
|
||||||
$sum = bcadd($sum, $value);
|
|
||||||
$data['labels'][] = $date->formatLocalized($format);
|
|
||||||
$data['datasets'][0]['data'][] = round($sum, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ChartJsReportChartGenerator.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
namespace FireflyIII\Generator\Chart\Report;
|
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ChartJsReportChartGenerator
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\Report
|
|
||||||
*/
|
|
||||||
class ChartJsReportChartGenerator implements ReportChartGeneratorInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as above but other translations.
|
|
||||||
*
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function multiYearOperations(Collection $entries): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'count' => 2,
|
|
||||||
'labels' => [],
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.income'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.expenses'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($entries as $entry) {
|
|
||||||
$data['labels'][] = $entry[0]->formatLocalized('%Y');
|
|
||||||
$data['datasets'][0]['data'][] = round($entry[1], 2);
|
|
||||||
$data['datasets'][1]['data'][] = round($entry[2], 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $income
|
|
||||||
* @param string $expense
|
|
||||||
* @param int $count
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function multiYearSum(string $income, string $expense, int $count): array
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'count' => 2,
|
|
||||||
'labels' => [trans('firefly.sum_of_years'), trans('firefly.average_of_years')],
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.income'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.expenses'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
$data['datasets'][0]['data'][] = round($income, 2);
|
|
||||||
$data['datasets'][1]['data'][] = round($expense, 2);
|
|
||||||
$data['datasets'][0]['data'][] = round(($income / $count), 2);
|
|
||||||
$data['datasets'][1]['data'][] = round(($expense / $count), 2);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function netWorth(Collection $entries) : array
|
|
||||||
{
|
|
||||||
$format = (string)trans('config.month_and_day');
|
|
||||||
$data = [
|
|
||||||
'count' => 1,
|
|
||||||
'labels' => [],
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.net_worth'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
foreach ($entries as $entry) {
|
|
||||||
$data['labels'][] = trim($entry['date']->formatLocalized($format));
|
|
||||||
$data['datasets'][0]['data'][] = round($entry['net-worth'], 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function yearOperations(Collection $entries): array
|
|
||||||
{
|
|
||||||
// language:
|
|
||||||
$format = (string)trans('config.month');
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'count' => 2,
|
|
||||||
'labels' => [],
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.income'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.expenses'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($entries as $entry) {
|
|
||||||
$data['labels'][] = $entry[0]->formatLocalized($format);
|
|
||||||
$data['datasets'][0]['data'][] = round($entry[1], 2);
|
|
||||||
$data['datasets'][1]['data'][] = round($entry[2], 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $income
|
|
||||||
* @param string $expense
|
|
||||||
* @param int $count
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function yearSum(string $income, string $expense, int $count): array
|
|
||||||
{
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'count' => 2,
|
|
||||||
'labels' => [trans('firefly.sum_of_year'), trans('firefly.average_of_year')],
|
|
||||||
'datasets' => [
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.income'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'label' => trans('firefly.expenses'),
|
|
||||||
'data' => [],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
$data['datasets'][0]['data'][] = round($income, 2);
|
|
||||||
$data['datasets'][1]['data'][] = round($expense, 2);
|
|
||||||
$data['datasets'][0]['data'][] = round(($income / $count), 2);
|
|
||||||
$data['datasets'][1]['data'][] = round(($expense / $count), 2);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* ReportChartGeneratorInterface.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms of the
|
|
||||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
|
||||||
*
|
|
||||||
* See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types = 1);
|
|
||||||
|
|
||||||
namespace FireflyIII\Generator\Chart\Report;
|
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface ReportChartGeneratorInterface
|
|
||||||
*
|
|
||||||
* @package FireflyIII\Generator\Chart\Report
|
|
||||||
*/
|
|
||||||
interface ReportChartGeneratorInterface
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function multiYearOperations(Collection $entries): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $income
|
|
||||||
* @param string $expense
|
|
||||||
* @param int $count
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function multiYearSum(string $income, string $expense, int $count): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function netWorth(Collection $entries) : array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $entries
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function yearOperations(Collection $entries): array;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $income
|
|
||||||
* @param string $expense
|
|
||||||
* @param int $count
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function yearSum(string $income, string $expense, int $count): array;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -25,7 +25,7 @@ use Steam;
|
|||||||
/**
|
/**
|
||||||
* Class MonthReportGenerator
|
* Class MonthReportGenerator
|
||||||
*
|
*
|
||||||
* @package FireflyIII\Generator\Report\Standard
|
* @package FireflyIII\Generator\Report\Audit
|
||||||
*/
|
*/
|
||||||
class MonthReportGenerator implements ReportGeneratorInterface
|
class MonthReportGenerator implements ReportGeneratorInterface
|
||||||
{
|
{
|
||||||
@@ -110,6 +110,16 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setBudgets(Collection $budgets): ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $categories
|
* @param Collection $categories
|
||||||
*
|
*
|
||||||
|
|||||||
247
app/Generator/Report/Budget/MonthReportGenerator.php
Normal file
247
app/Generator/Report/Budget/MonthReportGenerator.php
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* MonthReportGenerator.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Report\Budget;
|
||||||
|
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Generator\Report\ReportGeneratorInterface;
|
||||||
|
use FireflyIII\Generator\Report\Support;
|
||||||
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
|
use FireflyIII\Models\Transaction;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class MonthReportGenerator
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Report\Budget
|
||||||
|
*/
|
||||||
|
class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
/** @var Collection */
|
||||||
|
private $accounts;
|
||||||
|
/** @var Collection */
|
||||||
|
private $budgets;
|
||||||
|
/** @var Carbon */
|
||||||
|
private $end;
|
||||||
|
/** @var Collection */
|
||||||
|
private $expenses;
|
||||||
|
/** @var Collection */
|
||||||
|
private $income;
|
||||||
|
/** @var Carbon */
|
||||||
|
private $start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MonthReportGenerator constructor.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->income = new Collection;
|
||||||
|
$this->expenses = new Collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function generate(): string
|
||||||
|
{
|
||||||
|
$accountIds = join(',', $this->accounts->pluck('id')->toArray());
|
||||||
|
$budgetIds = join(',', $this->budgets->pluck('id')->toArray());
|
||||||
|
$expenses = $this->getExpenses();
|
||||||
|
$accountSummary = $this->summarizeByAccount($expenses);
|
||||||
|
$budgetSummary = $this->summarizeByBudget($expenses);
|
||||||
|
$averageExpenses = $this->getAverages($expenses, SORT_ASC);
|
||||||
|
$topExpenses = $this->getTopExpenses();
|
||||||
|
|
||||||
|
// render!
|
||||||
|
return view('reports.budget.month', compact('accountIds', 'budgetIds', 'accountSummary', 'budgetSummary', 'averageExpenses', 'topExpenses'))
|
||||||
|
->with('start', $this->start)->with('end', $this->end)
|
||||||
|
->with('budgets', $this->budgets)
|
||||||
|
->with('accounts', $this->accounts)
|
||||||
|
->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setAccounts(Collection $accounts): ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
$this->accounts = $accounts;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setBudgets(Collection $budgets): ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
$this->budgets = $budgets;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $categories
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setCategories(Collection $categories): ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setEndDate(Carbon $date): ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
$this->end = $date;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setStartDate(Carbon $date): ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
$this->start = $date;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $collection
|
||||||
|
* @param int $sortFlag
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getAverages(Collection $collection, int $sortFlag): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($collection as $transaction) {
|
||||||
|
// opposing name and ID:
|
||||||
|
$opposingId = $transaction->opposing_account_id;
|
||||||
|
|
||||||
|
// is not set?
|
||||||
|
if (!isset($result[$opposingId])) {
|
||||||
|
$name = $transaction->opposing_account_name;
|
||||||
|
$result[$opposingId] = [
|
||||||
|
'name' => $name,
|
||||||
|
'count' => 1,
|
||||||
|
'id' => $opposingId,
|
||||||
|
'average' => $transaction->transaction_amount,
|
||||||
|
'sum' => $transaction->transaction_amount,
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$result[$opposingId]['count']++;
|
||||||
|
$result[$opposingId]['sum'] = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
|
||||||
|
$result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort result by average:
|
||||||
|
$average = [];
|
||||||
|
foreach ($result as $key => $row) {
|
||||||
|
$average[$key] = floatval($row['average']);
|
||||||
|
}
|
||||||
|
|
||||||
|
array_multisort($average, $sortFlag, $result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function getExpenses(): Collection
|
||||||
|
{
|
||||||
|
if ($this->expenses->count() > 0) {
|
||||||
|
Log::debug('Return previous set of expenses.');
|
||||||
|
|
||||||
|
return $this->expenses;
|
||||||
|
}
|
||||||
|
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
|
||||||
|
->setTypes([TransactionType::WITHDRAWAL])
|
||||||
|
->setBudgets($this->budgets)->withOpposingAccount()->disableFilter();
|
||||||
|
|
||||||
|
$accountIds = $this->accounts->pluck('id')->toArray();
|
||||||
|
$transactions = $collector->getJournals();
|
||||||
|
$transactions = self::filterExpenses($transactions, $accountIds);
|
||||||
|
$this->expenses = $transactions;
|
||||||
|
|
||||||
|
return $transactions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function getTopExpenses(): Collection
|
||||||
|
{
|
||||||
|
$transactions = $this->getExpenses()->sortBy('transaction_amount');
|
||||||
|
|
||||||
|
return $transactions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $collection
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function summarizeByAccount(Collection $collection): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($collection as $transaction) {
|
||||||
|
$accountId = $transaction->account_id;
|
||||||
|
$result[$accountId] = $result[$accountId] ?? '0';
|
||||||
|
$result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $collection
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function summarizeByBudget(Collection $collection): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($collection as $transaction) {
|
||||||
|
$jrnlBudId = intval($transaction->transaction_journal_budget_id);
|
||||||
|
$transBudId = intval($transaction->transaction_budget_id);
|
||||||
|
$budgetId = max($jrnlBudId, $transBudId);
|
||||||
|
$result[$budgetId] = $result[$budgetId] ?? '0';
|
||||||
|
$result[$budgetId] = bcadd($transaction->transaction_amount, $result[$budgetId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
app/Generator/Report/Budget/MultiYearReportGenerator.php
Normal file
27
app/Generator/Report/Budget/MultiYearReportGenerator.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* MultiYearReportGenerator.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Report\Budget;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class MultiYearReportGenerator
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Report\Budget
|
||||||
|
*/
|
||||||
|
class MultiYearReportGenerator extends MonthReportGenerator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Doesn't do anything different.
|
||||||
|
*/
|
||||||
|
}
|
||||||
28
app/Generator/Report/Budget/YearReportGenerator.php
Normal file
28
app/Generator/Report/Budget/YearReportGenerator.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* YearReportGenerator.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Report\Budget;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class YearReportGenerator
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Report\Budget
|
||||||
|
*/
|
||||||
|
class YearReportGenerator extends MonthReportGenerator
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Doesn't do anything different.
|
||||||
|
*/
|
||||||
|
}
|
||||||
@@ -15,8 +15,8 @@ namespace FireflyIII\Generator\Report\Category;
|
|||||||
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Crypt;
|
|
||||||
use FireflyIII\Generator\Report\ReportGeneratorInterface;
|
use FireflyIII\Generator\Report\ReportGeneratorInterface;
|
||||||
|
use FireflyIII\Generator\Report\Support;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollector;
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
@@ -95,6 +95,16 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setBudgets(Collection $budgets): ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $categories
|
* @param Collection $categories
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -36,6 +36,13 @@ interface ReportGeneratorInterface
|
|||||||
*/
|
*/
|
||||||
public function setAccounts(Collection $accounts): ReportGeneratorInterface;
|
public function setAccounts(Collection $accounts): ReportGeneratorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setBudgets(Collection $budgets): ReportGeneratorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $categories
|
* @param Collection $categories
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -63,6 +63,16 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setBudgets(Collection $budgets): ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $categories
|
* @param Collection $categories
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -60,6 +60,16 @@ class MultiYearReportGenerator implements ReportGeneratorInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setBudgets(Collection $budgets): ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $categories
|
* @param Collection $categories
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -60,6 +60,16 @@ class YearReportGenerator implements ReportGeneratorInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
*
|
||||||
|
* @return ReportGeneratorInterface
|
||||||
|
*/
|
||||||
|
public function setBudgets(Collection $budgets): ReportGeneratorInterface
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $categories
|
* @param Collection $categories
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types = 1);
|
||||||
|
|
||||||
namespace FireflyIII\Generator\Report\Category;
|
namespace FireflyIII\Generator\Report;
|
||||||
|
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -15,10 +15,17 @@ namespace FireflyIII\Handlers\Events;
|
|||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use FireflyConfig;
|
use FireflyConfig;
|
||||||
|
use FireflyIII\Events\BlockedBadLogin;
|
||||||
|
use FireflyIII\Events\BlockedUseOfDomain;
|
||||||
|
use FireflyIII\Events\BlockedUseOfEmail;
|
||||||
|
use FireflyIII\Events\BlockedUserLogin;
|
||||||
use FireflyIII\Events\ConfirmedUser;
|
use FireflyIII\Events\ConfirmedUser;
|
||||||
|
use FireflyIII\Events\DeletedUser;
|
||||||
|
use FireflyIII\Events\LockedOutUser;
|
||||||
use FireflyIII\Events\RegisteredUser;
|
use FireflyIII\Events\RegisteredUser;
|
||||||
use FireflyIII\Events\RequestedNewPassword;
|
use FireflyIII\Events\RequestedNewPassword;
|
||||||
use FireflyIII\Events\ResentConfirmation;
|
use FireflyIII\Events\ResentConfirmation;
|
||||||
|
use FireflyIII\Models\Configuration;
|
||||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Mail\Message;
|
use Illuminate\Mail\Message;
|
||||||
@@ -75,6 +82,210 @@ class UserEventHandler
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BlockedBadLogin $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function reportBadLogin(BlockedBadLogin $event)
|
||||||
|
{
|
||||||
|
$email = $event->email;
|
||||||
|
$owner = env('SITE_OWNER');
|
||||||
|
$ipAddress = $event->ipAddress;
|
||||||
|
/** @var Configuration $sendmail */
|
||||||
|
$sendmail = FireflyConfig::get('mail_for_bad_login', config('firefly.configuration.mail_for_bad_login'));
|
||||||
|
Log::debug(sprintf('Now in reportBadLogin for email address %s', $email));
|
||||||
|
Log::error(sprintf('User %s tried to login with bad credentials.', $email));
|
||||||
|
if (is_null($sendmail) || (!is_null($sendmail) && $sendmail->data === false)) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Mail::send(
|
||||||
|
['emails.blocked-bad-creds-html', 'emails.blocked-bad-creds-text'], ['email' => $email, 'ip' => $ipAddress],
|
||||||
|
function (Message $message) use ($owner) {
|
||||||
|
$message->to($owner, $owner)->subject('Blocked login attempt with bad credentials');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (Swift_TransportException $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BlockedUserLogin $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function reportBlockedUser(BlockedUserLogin $event): bool
|
||||||
|
{
|
||||||
|
$user = $event->user;
|
||||||
|
$owner = env('SITE_OWNER');
|
||||||
|
$email = $user->email;
|
||||||
|
$ipAddress = $event->ipAddress;
|
||||||
|
/** @var Configuration $sendmail */
|
||||||
|
$sendmail = FireflyConfig::get('mail_for_blocked_login', config('firefly.configuration.mail_for_blocked_login'));
|
||||||
|
Log::debug(sprintf('Now in reportBlockedUser for email address %s', $email));
|
||||||
|
Log::error(sprintf('User #%d (%s) has their accout blocked (blocked_code is "%s") but tried to login.', $user->id, $email, $user->blocked_code));
|
||||||
|
if (is_null($sendmail) || (!is_null($sendmail) && $sendmail->data === false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send email message:
|
||||||
|
try {
|
||||||
|
Mail::send(
|
||||||
|
['emails.blocked-login-html', 'emails.blocked-login-text'],
|
||||||
|
[
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'user_address' => $email,
|
||||||
|
'ip' => $ipAddress,
|
||||||
|
'code' => $user->blocked_code,
|
||||||
|
], function (Message $message) use ($owner, $user) {
|
||||||
|
$message->to($owner, $owner)->subject('Blocked login attempt of blocked user');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (Swift_TransportException $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param LockedOutUser $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function reportLockout(LockedOutUser $event): bool
|
||||||
|
{
|
||||||
|
$email = $event->email;
|
||||||
|
$owner = env('SITE_OWNER');
|
||||||
|
$ipAddress = $event->ipAddress;
|
||||||
|
/** @var Configuration $sendmail */
|
||||||
|
$sendmail = FireflyConfig::get('mail_for_lockout', config('firefly.configuration.mail_for_lockout'));
|
||||||
|
Log::debug(sprintf('Now in respondToLockout for email address %s', $email));
|
||||||
|
Log::error(sprintf('User %s was locked out after too many invalid login attempts.', $email));
|
||||||
|
if (is_null($sendmail) || (!is_null($sendmail) && $sendmail->data === false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send email message:
|
||||||
|
try {
|
||||||
|
Mail::send(
|
||||||
|
['emails.locked-out-html', 'emails.locked-out-text'], ['email' => $email, 'ip' => $ipAddress], function (Message $message) use ($owner) {
|
||||||
|
$message->to($owner, $owner)->subject('User was locked out');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (Swift_TransportException $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BlockedUseOfDomain $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function reportUseBlockedDomain(BlockedUseOfDomain $event): bool
|
||||||
|
{
|
||||||
|
$email = $event->email;
|
||||||
|
$owner = env('SITE_OWNER');
|
||||||
|
$ipAddress = $event->ipAddress;
|
||||||
|
$parts = explode('@', $email);
|
||||||
|
/** @var Configuration $sendmail */
|
||||||
|
$sendmail = FireflyConfig::get('mail_for_blocked_domain', config('firefly.configuration.mail_for_blocked_domain'));
|
||||||
|
Log::debug(sprintf('Now in reportUseBlockedDomain for email address %s', $email));
|
||||||
|
Log::error(sprintf('Somebody tried to register using an email address (%s) connected to a banned domain (%s).', $email, $parts[1]));
|
||||||
|
if (is_null($sendmail) || (!is_null($sendmail) && $sendmail->data === false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send email message:
|
||||||
|
try {
|
||||||
|
Mail::send(
|
||||||
|
['emails.blocked-registration-html', 'emails.blocked-registration-text'],
|
||||||
|
[
|
||||||
|
'email_address' => $email,
|
||||||
|
'blocked_domain' => $parts[1],
|
||||||
|
'ip' => $ipAddress,
|
||||||
|
], function (Message $message) use ($owner) {
|
||||||
|
$message->to($owner, $owner)->subject('Blocked registration attempt with blocked domain');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (Swift_TransportException $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BlockedUseOfEmail $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function reportUseOfBlockedEmail(BlockedUseOfEmail $event): bool
|
||||||
|
{
|
||||||
|
$email = $event->email;
|
||||||
|
$owner = env('SITE_OWNER');
|
||||||
|
$ipAddress = $event->ipAddress;
|
||||||
|
/** @var Configuration $sendmail */
|
||||||
|
$sendmail = FireflyConfig::get('mail_for_blocked_email', config('firefly.configuration.mail_for_blocked_email'));
|
||||||
|
Log::debug(sprintf('Now in reportUseOfBlockedEmail for email address %s', $email));
|
||||||
|
Log::error(sprintf('Somebody tried to register using email address %s which is blocked (SHA2 hash).', $email));
|
||||||
|
if (is_null($sendmail) || (!is_null($sendmail) && $sendmail->data === false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send email message:
|
||||||
|
try {
|
||||||
|
Mail::send(
|
||||||
|
['emails.blocked-email-html', 'emails.blocked-email-text'],
|
||||||
|
[
|
||||||
|
'user_address' => $email,
|
||||||
|
'ip' => $ipAddress,
|
||||||
|
], function (Message $message) use ($owner) {
|
||||||
|
$message->to($owner, $owner)->subject('Blocked registration attempt with blocked email address');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (Swift_TransportException $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DeletedUser $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function saveEmailAddress(DeletedUser $event): bool
|
||||||
|
{
|
||||||
|
Preferences::mark();
|
||||||
|
$email = hash('sha256', $event->email);
|
||||||
|
Log::debug(sprintf('Hash of email is %s', $email));
|
||||||
|
/** @var Configuration $configuration */
|
||||||
|
$configuration = FireflyConfig::get('deleted_users', []);
|
||||||
|
$content = $configuration->data;
|
||||||
|
if (!is_array($content)) {
|
||||||
|
$content = [];
|
||||||
|
}
|
||||||
|
$content[] = $email;
|
||||||
|
$configuration->data = $content;
|
||||||
|
Log::debug('New content of deleted_users is ', $content);
|
||||||
|
FireflyConfig::set('deleted_users', $content);
|
||||||
|
|
||||||
|
Preferences::mark();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method will send a newly registered user a confirmation message, urging him or her to activate their account.
|
* This method will send a newly registered user a confirmation message, urging him or her to activate their account.
|
||||||
*
|
*
|
||||||
@@ -194,7 +405,6 @@ class UserEventHandler
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @param string $ipAddress
|
* @param string $ipAddress
|
||||||
|
|||||||
@@ -79,6 +79,22 @@ class BillLine
|
|||||||
$this->bill = $bill;
|
$this->bill = $bill;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function getLastHitDate(): Carbon
|
||||||
|
{
|
||||||
|
return $this->lastHitDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $lastHitDate
|
||||||
|
*/
|
||||||
|
public function setLastHitDate(Carbon $lastHitDate)
|
||||||
|
{
|
||||||
|
$this->lastHitDate = $lastHitDate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@@ -151,21 +167,5 @@ class BillLine
|
|||||||
$this->hit = $hit;
|
$this->hit = $hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Carbon $lastHitDate
|
|
||||||
*/
|
|
||||||
public function setLastHitDate(Carbon $lastHitDate)
|
|
||||||
{
|
|
||||||
$this->lastHitDate = $lastHitDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Carbon
|
|
||||||
*/
|
|
||||||
public function getLastHitDate(): Carbon
|
|
||||||
{
|
|
||||||
return $this->lastHitDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
'transaction_types.type as transaction_type_type',
|
'transaction_types.type as transaction_type_type',
|
||||||
'transaction_journals.bill_id',
|
'transaction_journals.bill_id',
|
||||||
'bills.name as bill_name',
|
'bills.name as bill_name',
|
||||||
|
'bills.name_encrypted as bill_name_encrypted',
|
||||||
'transactions.id as id',
|
'transactions.id as id',
|
||||||
'transactions.amount as transaction_amount',
|
'transactions.amount as transaction_amount',
|
||||||
'transactions.description as transaction_description',
|
'transactions.description as transaction_description',
|
||||||
@@ -180,10 +181,12 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
$set->each(
|
$set->each(
|
||||||
function (Transaction $transaction) {
|
function (Transaction $transaction) {
|
||||||
$transaction->date = new Carbon($transaction->date);
|
$transaction->date = new Carbon($transaction->date);
|
||||||
$transaction->description = intval($transaction->encrypted) === 1 ? Crypt::decrypt($transaction->description) : $transaction->description;
|
$transaction->description = $transaction->encrypted ? Crypt::decrypt($transaction->description) : $transaction->description;
|
||||||
$transaction->bill_name = !is_null($transaction->bill_name) ? Crypt::decrypt($transaction->bill_name) : '';
|
|
||||||
|
if (!is_null($transaction->bill_name)) {
|
||||||
|
$transaction->bill_name = $transaction->bill_name_encrypted ? Crypt::decrypt($transaction->bill_name) : $transaction->bill_name;
|
||||||
|
}
|
||||||
|
|
||||||
// optionally decrypted:
|
|
||||||
try {
|
try {
|
||||||
$transaction->opposing_account_name = Crypt::decrypt($transaction->opposing_account_name);
|
$transaction->opposing_account_name = Crypt::decrypt($transaction->opposing_account_name);
|
||||||
} catch (DecryptException $e) {
|
} catch (DecryptException $e) {
|
||||||
@@ -709,7 +712,7 @@ class JournalCollector implements JournalCollectorInterface
|
|||||||
*/
|
*/
|
||||||
private function startQuery(): EloquentBuilder
|
private function startQuery(): EloquentBuilder
|
||||||
{
|
{
|
||||||
|
/** @var EloquentBuilder $query */
|
||||||
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
|
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
|
||||||
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
|
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ use FireflyIII\Models\TransactionType;
|
|||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use Illuminate\Database\Query\JoinClause;
|
use Illuminate\Database\Query\JoinClause;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BalanceReportHelper
|
* Class BalanceReportHelper
|
||||||
@@ -59,19 +60,23 @@ class BalanceReportHelper implements BalanceReportHelperInterface
|
|||||||
*/
|
*/
|
||||||
public function getBalanceReport(Collection $accounts, Carbon $start, Carbon $end): Balance
|
public function getBalanceReport(Collection $accounts, Carbon $start, Carbon $end): Balance
|
||||||
{
|
{
|
||||||
|
Log::debug('Start of balance report');
|
||||||
$balance = new Balance;
|
$balance = new Balance;
|
||||||
$header = new BalanceHeader;
|
$header = new BalanceHeader;
|
||||||
$limitRepetitions = $this->budgetRepository->getAllBudgetLimitRepetitions($start, $end);
|
$limitRepetitions = $this->budgetRepository->getAllBudgetLimitRepetitions($start, $end);
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
|
Log::debug(sprintf('Add account %s to headers.', $account->name));
|
||||||
$header->addAccount($account);
|
$header->addAccount($account);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var LimitRepetition $repetition */
|
/** @var LimitRepetition $repetition */
|
||||||
foreach ($limitRepetitions as $repetition) {
|
foreach ($limitRepetitions as $repetition) {
|
||||||
$budget = $this->budgetRepository->find($repetition->budget_id);
|
$budget = $this->budgetRepository->find($repetition->budget_id);
|
||||||
|
Log::debug(sprintf('Create balance line for budget #%d ("%s") and repetition #%d', $budget->id, $budget->name, $repetition->id));
|
||||||
$line = $this->createBalanceLine($budget, $repetition, $accounts);
|
$line = $this->createBalanceLine($budget, $repetition, $accounts);
|
||||||
$balance->addBalanceLine($line);
|
$balance->addBalanceLine($line);
|
||||||
}
|
}
|
||||||
|
Log::debug('Create rest of the things.');
|
||||||
$noBudgetLine = $this->createNoBudgetLine($accounts, $start, $end);
|
$noBudgetLine = $this->createNoBudgetLine($accounts, $start, $end);
|
||||||
$coveredByTagLine = $this->createTagsBalanceLine($accounts, $start, $end);
|
$coveredByTagLine = $this->createTagsBalanceLine($accounts, $start, $end);
|
||||||
$leftUnbalancedLine = $this->createLeftUnbalancedLine($noBudgetLine, $coveredByTagLine);
|
$leftUnbalancedLine = $this->createLeftUnbalancedLine($noBudgetLine, $coveredByTagLine);
|
||||||
@@ -81,9 +86,12 @@ class BalanceReportHelper implements BalanceReportHelperInterface
|
|||||||
$balance->addBalanceLine($leftUnbalancedLine);
|
$balance->addBalanceLine($leftUnbalancedLine);
|
||||||
$balance->setBalanceHeader($header);
|
$balance->setBalanceHeader($header);
|
||||||
|
|
||||||
|
Log::debug('Clear unused budgets.');
|
||||||
// remove budgets without expenses from balance lines:
|
// remove budgets without expenses from balance lines:
|
||||||
$balance = $this->removeUnusedBudgets($balance);
|
$balance = $this->removeUnusedBudgets($balance);
|
||||||
|
|
||||||
|
Log::debug('Return report.');
|
||||||
|
|
||||||
return $balance;
|
return $balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ class AccountController extends Controller
|
|||||||
$type = $account->accountType->type;
|
$type = $account->accountType->type;
|
||||||
$typeName = config('firefly.shortNamesByFullName.' . $type);
|
$typeName = config('firefly.shortNamesByFullName.' . $type);
|
||||||
$name = $account->name;
|
$name = $account->name;
|
||||||
|
$accountId = $account->id;
|
||||||
$moveTo = $repository->find(intval(Input::get('move_account_before_delete')));
|
$moveTo = $repository->find(intval(Input::get('move_account_before_delete')));
|
||||||
|
|
||||||
$repository->destroy($account, $moveTo);
|
$repository->destroy($account, $moveTo);
|
||||||
@@ -134,7 +135,13 @@ class AccountController extends Controller
|
|||||||
Session::flash('success', strval(trans('firefly.' . $typeName . '_deleted', ['name' => $name])));
|
Session::flash('success', strval(trans('firefly.' . $typeName . '_deleted', ['name' => $name])));
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
return redirect(session('accounts.delete.url'));
|
$uri = session('accounts.delete.url');
|
||||||
|
if (!(strpos($uri, sprintf('accounts/show/%s', $accountId)) === false)) {
|
||||||
|
// uri would point back to account
|
||||||
|
$uri = route('accounts.index', [$typeName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect($uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -193,7 +200,6 @@ class AccountController extends Controller
|
|||||||
public function index(ARI $repository, string $what)
|
public function index(ARI $repository, string $what)
|
||||||
{
|
{
|
||||||
$what = $what ?? 'asset';
|
$what = $what ?? 'asset';
|
||||||
|
|
||||||
$subTitle = trans('firefly.' . $what . '_accounts');
|
$subTitle = trans('firefly.' . $what . '_accounts');
|
||||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||||
$types = config('firefly.accountTypesByIdentifier.' . $what);
|
$types = config('firefly.accountTypesByIdentifier.' . $what);
|
||||||
@@ -214,6 +220,7 @@ class AccountController extends Controller
|
|||||||
$account->lastActivityDate = $this->isInArray($activities, $account->id);
|
$account->lastActivityDate = $this->isInArray($activities, $account->id);
|
||||||
$account->startBalance = $this->isInArray($startBalances, $account->id);
|
$account->startBalance = $this->isInArray($startBalances, $account->id);
|
||||||
$account->endBalance = $this->isInArray($endBalances, $account->id);
|
$account->endBalance = $this->isInArray($endBalances, $account->id);
|
||||||
|
$account->difference = bcsub($account->endBalance, $account->startBalance);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -239,6 +246,7 @@ class AccountController extends Controller
|
|||||||
$end = session('end', Navigation::endOfPeriod(new Carbon, $range));
|
$end = session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||||
$page = intval(Input::get('page')) === 0 ? 1 : intval(Input::get('page'));
|
$page = intval(Input::get('page')) === 0 ? 1 : intval(Input::get('page'));
|
||||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||||
|
$chartUri = route('chart.account.single', [$account->id]);
|
||||||
|
|
||||||
// grab those journals:
|
// grab those journals:
|
||||||
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->setLimit($pageSize)->setPage($page);
|
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->setLimit($pageSize)->setPage($page);
|
||||||
@@ -248,7 +256,7 @@ class AccountController extends Controller
|
|||||||
// generate entries for each period (and cache those)
|
// generate entries for each period (and cache those)
|
||||||
$entries = $this->periodEntries($account);
|
$entries = $this->periodEntries($account);
|
||||||
|
|
||||||
return view('accounts.show', compact('account', 'what', 'entries', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end'));
|
return view('accounts.show', compact('account', 'entries', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -262,6 +270,7 @@ class AccountController extends Controller
|
|||||||
$subTitle = sprintf('%s (%s)', $account->name, strtolower(trans('firefly.everything')));
|
$subTitle = sprintf('%s (%s)', $account->name, strtolower(trans('firefly.everything')));
|
||||||
$page = intval(Input::get('page')) === 0 ? 1 : intval(Input::get('page'));
|
$page = intval(Input::get('page')) === 0 ? 1 : intval(Input::get('page'));
|
||||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||||
|
$chartUri = route('chart.account.all', [$account->id]);
|
||||||
|
|
||||||
// replace with journal collector:
|
// replace with journal collector:
|
||||||
$collector = new JournalCollector(auth()->user());
|
$collector = new JournalCollector(auth()->user());
|
||||||
@@ -273,7 +282,8 @@ class AccountController extends Controller
|
|||||||
$start = $repository->oldestJournalDate($account);
|
$start = $repository->oldestJournalDate($account);
|
||||||
$end = $repository->newestJournalDate($account);
|
$end = $repository->newestJournalDate($account);
|
||||||
|
|
||||||
return view('accounts.show_with_date', compact('account', 'journals', 'subTitle', 'start', 'end'));
|
// same call, except "entries".
|
||||||
|
return view('accounts.show', compact('account', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -291,6 +301,7 @@ class AccountController extends Controller
|
|||||||
$subTitle = $account->name . ' (' . Navigation::periodShow($start, $range) . ')';
|
$subTitle = $account->name . ' (' . Navigation::periodShow($start, $range) . ')';
|
||||||
$page = intval(Input::get('page')) === 0 ? 1 : intval(Input::get('page'));
|
$page = intval(Input::get('page')) === 0 ? 1 : intval(Input::get('page'));
|
||||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||||
|
$chartUri = route('chart.account.period', [$account->id, $carbon->format('Y-m-d')]);
|
||||||
|
|
||||||
// replace with journal collector:
|
// replace with journal collector:
|
||||||
$collector = new JournalCollector(auth()->user());
|
$collector = new JournalCollector(auth()->user());
|
||||||
@@ -298,7 +309,8 @@ class AccountController extends Controller
|
|||||||
$journals = $collector->getPaginatedJournals();
|
$journals = $collector->getPaginatedJournals();
|
||||||
$journals->setPath('accounts/show/' . $account->id . '/' . $date);
|
$journals->setPath('accounts/show/' . $account->id . '/' . $date);
|
||||||
|
|
||||||
return view('accounts.show-by-date', compact('category', 'date', 'account', 'journals', 'subTitle', 'carbon', 'start', 'end'));
|
// same call, except "entries".
|
||||||
|
return view('accounts.show', compact('account', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -374,7 +386,7 @@ class AccountController extends Controller
|
|||||||
return $array[$entryId];
|
return $array[$entryId];
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -61,8 +61,21 @@ class ConfigurationController extends Controller
|
|||||||
$singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
$singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
||||||
$mustConfirmAccount = FireflyConfig::get('must_confirm_account', config('firefly.configuration.must_confirm_account'))->data;
|
$mustConfirmAccount = FireflyConfig::get('must_confirm_account', config('firefly.configuration.must_confirm_account'))->data;
|
||||||
$isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data;
|
$isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data;
|
||||||
|
$siteOwner = env('SITE_OWNER');
|
||||||
|
|
||||||
return view('admin.configuration.index', compact('subTitle', 'subTitleIcon', 'singleUserMode', 'mustConfirmAccount', 'isDemoSite'));
|
// email settings:
|
||||||
|
$sendErrorMessage = [
|
||||||
|
'mail_for_lockout' => FireflyConfig::get('mail_for_lockout', config('firefly.configuration.mail_for_lockout'))->data,
|
||||||
|
'mail_for_blocked_domain' => FireflyConfig::get('mail_for_blocked_domain', config('firefly.configuration.mail_for_blocked_domain'))->data,
|
||||||
|
'mail_for_blocked_email' => FireflyConfig::get('mail_for_blocked_email', config('firefly.configuration.mail_for_blocked_email'))->data,
|
||||||
|
'mail_for_bad_login' => FireflyConfig::get('mail_for_bad_login', config('firefly.configuration.mail_for_bad_login'))->data,
|
||||||
|
'mail_for_blocked_login' => FireflyConfig::get('mail_for_blocked_login', config('firefly.configuration.mail_for_blocked_login'))->data,
|
||||||
|
];
|
||||||
|
|
||||||
|
return view(
|
||||||
|
'admin.configuration.index',
|
||||||
|
compact('subTitle', 'subTitleIcon', 'singleUserMode', 'mustConfirmAccount', 'isDemoSite', 'sendErrorMessage', 'siteOwner')
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +94,13 @@ class ConfigurationController extends Controller
|
|||||||
FireflyConfig::set('must_confirm_account', $data['must_confirm_account']);
|
FireflyConfig::set('must_confirm_account', $data['must_confirm_account']);
|
||||||
FireflyConfig::set('is_demo_site', $data['is_demo_site']);
|
FireflyConfig::set('is_demo_site', $data['is_demo_site']);
|
||||||
|
|
||||||
|
// email settings
|
||||||
|
FireflyConfig::set('mail_for_lockout', $data['mail_for_lockout']);
|
||||||
|
FireflyConfig::set('mail_for_blocked_domain', $data['mail_for_blocked_domain']);
|
||||||
|
FireflyConfig::set('mail_for_blocked_email', $data['mail_for_blocked_email']);
|
||||||
|
FireflyConfig::set('mail_for_bad_login', $data['mail_for_bad_login']);
|
||||||
|
FireflyConfig::set('mail_for_blocked_login', $data['mail_for_blocked_login']);
|
||||||
|
|
||||||
// flash message
|
// flash message
|
||||||
Session::flash('success', strval(trans('firefly.configuration_updated')));
|
Session::flash('success', strval(trans('firefly.configuration_updated')));
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|||||||
@@ -16,9 +16,13 @@ namespace FireflyIII\Http\Controllers\Admin;
|
|||||||
|
|
||||||
use FireflyConfig;
|
use FireflyConfig;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
|
use FireflyIII\Http\Requests\UserFormRequest;
|
||||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Preferences;
|
use Preferences;
|
||||||
|
use Session;
|
||||||
|
use URL;
|
||||||
|
use View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class UserController
|
* Class UserController
|
||||||
@@ -27,28 +31,56 @@ use Preferences;
|
|||||||
*/
|
*/
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
|
||||||
|
$this->middleware(
|
||||||
|
function ($request, $next) {
|
||||||
|
View::share('title', strval(trans('firefly.administration')));
|
||||||
|
View::share('mainTitleIcon', 'fa-hand-spock-o');
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param User $user
|
* @param User $user
|
||||||
*
|
*
|
||||||
* @return int
|
* @return View
|
||||||
*/
|
*/
|
||||||
public function edit(User $user)
|
public function edit(User $user)
|
||||||
{
|
{
|
||||||
return $user->id;
|
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||||
|
if (session('users.edit.fromUpdate') !== true) {
|
||||||
|
Session::put('users.edit.url', URL::previous());
|
||||||
|
}
|
||||||
|
Session::forget('users.edit.fromUpdate');
|
||||||
|
|
||||||
|
$subTitle = strval(trans('firefly.edit_user', ['email' => $user->email]));
|
||||||
|
$subTitleIcon = 'fa-user-o';
|
||||||
|
$codes = [
|
||||||
|
'' => strval(trans('firefly.no_block_code')),
|
||||||
|
'bounced' => strval(trans('firefly.block_code_bounced')),
|
||||||
|
'expired' => strval(trans('firefly.block_code_expired')),
|
||||||
|
];
|
||||||
|
|
||||||
|
return view('admin.users.edit', compact('user', 'subTitle', 'subTitleIcon', 'codes'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param UserRepositoryInterface $repository
|
* @param UserRepositoryInterface $repository
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
* @return View
|
||||||
*/
|
*/
|
||||||
public function index(UserRepositoryInterface $repository)
|
public function index(UserRepositoryInterface $repository)
|
||||||
{
|
{
|
||||||
$title = strval(trans('firefly.administration'));
|
|
||||||
$mainTitleIcon = 'fa-hand-spock-o';
|
|
||||||
$subTitle = strval(trans('firefly.user_administration'));
|
$subTitle = strval(trans('firefly.user_administration'));
|
||||||
$subTitleIcon = 'fa-users';
|
$subTitleIcon = 'fa-users';
|
||||||
$mustConfirmAccount = FireflyConfig::get('must_confirm_account', config('firefly.configuration.must_confirm_account'))->data;
|
$mustConfirmAccount = FireflyConfig::get('must_confirm_account', config('firefly.configuration.must_confirm_account'))->data;
|
||||||
@@ -77,7 +109,7 @@ class UserController extends Controller
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return view('admin.users.index', compact('title', 'mainTitleIcon', 'subTitle', 'subTitleIcon', 'users'));
|
return view('admin.users.index', compact('subTitle', 'subTitleIcon', 'users'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,5 +160,41 @@ class UserController extends Controller
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param UserFormRequest $request
|
||||||
|
* @param User $user
|
||||||
|
*
|
||||||
|
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
|
*/
|
||||||
|
public function update(UserFormRequest $request, User $user)
|
||||||
|
{
|
||||||
|
$data = $request->getUserData();
|
||||||
|
|
||||||
|
// update password
|
||||||
|
if (strlen($data['password']) > 0) {
|
||||||
|
$user->password = bcrypt($data['password']);
|
||||||
|
$user->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// change blocked status and code:
|
||||||
|
$user->blocked = $data['blocked'];
|
||||||
|
$user->blocked_code = $data['blocked_code'];
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
Session::flash('success', strval(trans('firefly.updated_user', ['email' => $user->email])));
|
||||||
|
Preferences::mark();
|
||||||
|
|
||||||
|
if (intval($request->get('return_to_edit')) === 1) {
|
||||||
|
// set value so edit routine will not overwrite URL:
|
||||||
|
Session::put('users.edit.fromUpdate', true);
|
||||||
|
|
||||||
|
return redirect(route('admin.users.edit', [$user->id]))->withInput(['return_to_edit' => 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// redirect to previous URL.
|
||||||
|
return redirect(session('users.edit.url'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,16 +95,12 @@ class AttachmentController extends Controller
|
|||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function download(Attachment $attachment)
|
public function download(AttachmentRepositoryInterface $repository, Attachment $attachment)
|
||||||
{
|
{
|
||||||
// create a disk.
|
if ($repository->exists($attachment)) {
|
||||||
$disk = Storage::disk('upload');
|
$content = $repository->getContent($attachment);
|
||||||
$file = $attachment->fileName();
|
|
||||||
|
|
||||||
if ($disk->exists($file)) {
|
|
||||||
|
|
||||||
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
|
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
|
||||||
$content = Crypt::decrypt($disk->get($file));
|
|
||||||
|
|
||||||
Log::debug('Send file to user', ['file' => $quoted, 'size' => strlen($content)]);
|
Log::debug('Send file to user', ['file' => $quoted, 'size' => strlen($content)]);
|
||||||
|
|
||||||
@@ -118,8 +114,8 @@ class AttachmentController extends Controller
|
|||||||
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
||||||
->header('Pragma', 'public')
|
->header('Pragma', 'public')
|
||||||
->header('Content-Length', strlen($content));
|
->header('Content-Length', strlen($content));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new FireflyException('Could not find the indicated attachment. The file is no longer there.');
|
throw new FireflyException('Could not find the indicated attachment. The file is no longer there.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
37
app/Http/Controllers/Auth/ForgotPasswordController.php
Executable file → Normal file
37
app/Http/Controllers/Auth/ForgotPasswordController.php
Executable file → Normal file
@@ -13,7 +13,9 @@ declare(strict_types = 1);
|
|||||||
namespace FireflyIII\Http\Controllers\Auth;
|
namespace FireflyIII\Http\Controllers\Auth;
|
||||||
|
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
|
use FireflyIII\User;
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ForgotPasswordController
|
* Class ForgotPasswordController
|
||||||
@@ -33,4 +35,39 @@ class ForgotPasswordController extends Controller
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->middleware('guest');
|
$this->middleware('guest');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a reset link to the given user.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function sendResetLinkEmail(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, ['email' => 'required|email']);
|
||||||
|
|
||||||
|
// verify if the user is not a demo user. If so, we give him back an error.
|
||||||
|
$user = User::where('email', $request->get('email'))->first();
|
||||||
|
if (!is_null($user) && $user->hasRole('demo')) {
|
||||||
|
return back()->withErrors(
|
||||||
|
['email' => trans('firefly.cannot_reset_demo_user')]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->broker()->sendResetLink(
|
||||||
|
$request->only('email')
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($response === Password::RESET_LINK_SENT) {
|
||||||
|
return back()->with('status', trans($response));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an error was returned by the password broker, we will get this message
|
||||||
|
// translated so we can notify a user of the problem. We'll redirect back
|
||||||
|
// to where the users came from so they can attempt this process again.
|
||||||
|
return back()->withErrors(
|
||||||
|
['email' => trans($response)]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
70
app/Http/Controllers/Auth/LoginController.php
Executable file → Normal file
70
app/Http/Controllers/Auth/LoginController.php
Executable file → Normal file
@@ -14,15 +14,14 @@ namespace FireflyIII\Http\Controllers\Auth;
|
|||||||
|
|
||||||
use Config;
|
use Config;
|
||||||
use FireflyConfig;
|
use FireflyConfig;
|
||||||
|
use FireflyIII\Events\BlockedBadLogin;
|
||||||
|
use FireflyIII\Events\BlockedUserLogin;
|
||||||
|
use FireflyIII\Events\LockedOutUser;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Mail\Message;
|
|
||||||
use Lang;
|
use Lang;
|
||||||
use Log;
|
|
||||||
use Mail;
|
|
||||||
use Swift_TransportException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class LoginController
|
* Class LoginController
|
||||||
@@ -31,16 +30,6 @@ use Swift_TransportException;
|
|||||||
*/
|
*/
|
||||||
class LoginController extends Controller
|
class LoginController extends Controller
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Login Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This controller handles authenticating users for the application and
|
|
||||||
| redirecting them to your home screen. The controller uses a trait
|
|
||||||
| to conveniently provide its functionality to your applications.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
use AuthenticatesUsers;
|
use AuthenticatesUsers;
|
||||||
|
|
||||||
@@ -49,7 +38,7 @@ class LoginController extends Controller
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = '/home';
|
protected $redirectTo = '/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new controller instance.
|
* Create a new controller instance.
|
||||||
@@ -64,26 +53,24 @@ class LoginController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Handle a login request to the application.
|
* Handle a login request to the application.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param Request $request
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function login(Request $request)
|
public function login(Request $request)
|
||||||
{
|
{
|
||||||
$this->validateLogin($request);
|
$this->validateLogin($request);
|
||||||
|
|
||||||
// If the class is using the ThrottlesLogins trait, we can automatically throttle
|
|
||||||
// the login attempts for this application. We'll key this by the username and
|
|
||||||
// the IP address of the client making these requests into this application.
|
|
||||||
$lockedOut = $this->hasTooManyLoginAttempts($request);
|
$lockedOut = $this->hasTooManyLoginAttempts($request);
|
||||||
if ($lockedOut) {
|
if ($lockedOut) {
|
||||||
$this->fireLockoutEvent($request);
|
$this->fireLockoutEvent($request);
|
||||||
|
|
||||||
|
event(new LockedOutUser($request->get('email'), $request->ip()));
|
||||||
|
|
||||||
return $this->sendLockoutResponse($request);
|
return $this->sendLockoutResponse($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
$credentials = $this->credentials($request);
|
$credentials = $this->credentials($request);
|
||||||
$credentials['blocked'] = 0; // most not be blocked.
|
$credentials['blocked'] = 0; // must not be blocked.
|
||||||
|
|
||||||
if ($this->guard()->attempt($credentials, $request->has('remember'))) {
|
if ($this->guard()->attempt($credentials, $request->has('remember'))) {
|
||||||
return $this->sendLoginResponse($request);
|
return $this->sendLoginResponse($request);
|
||||||
@@ -94,10 +81,15 @@ class LoginController extends Controller
|
|||||||
/** @var User $foundUser */
|
/** @var User $foundUser */
|
||||||
$foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first();
|
$foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first();
|
||||||
if (!is_null($foundUser)) {
|
if (!is_null($foundUser)) {
|
||||||
// if it exists, show message:
|
// user exists, but is blocked:
|
||||||
$code = strlen(strval($foundUser->blocked_code)) > 0 ? $foundUser->blocked_code : 'general_blocked';
|
$code = strlen(strval($foundUser->blocked_code)) > 0 ? $foundUser->blocked_code : 'general_blocked';
|
||||||
$errorMessage = strval(trans('firefly.' . $code . '_error', ['email' => $credentials['email']]));
|
$errorMessage = strval(trans('firefly.' . $code . '_error', ['email' => $credentials['email']]));
|
||||||
$this->reportBlockedUserLoginAttempt($foundUser, $code, $request->ip());
|
event(new BlockedUserLogin($foundUser, $request->ip()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// simply a bad login.
|
||||||
|
if (is_null($foundUser)) {
|
||||||
|
event(new BlockedBadLogin($credentials['email'], $request->ip()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the login attempt was unsuccessful we will increment the number of attempts
|
// If the login attempt was unsuccessful we will increment the number of attempts
|
||||||
@@ -167,34 +159,4 @@ class LoginController extends Controller
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a message home about the blocked attempt to login.
|
|
||||||
* Perhaps in a later stage, simply log these messages.
|
|
||||||
*
|
|
||||||
* @param User $user
|
|
||||||
* @param string $code
|
|
||||||
* @param string $ipAddress
|
|
||||||
*/
|
|
||||||
private function reportBlockedUserLoginAttempt(User $user, string $code, string $ipAddress)
|
|
||||||
{
|
|
||||||
|
|
||||||
try {
|
|
||||||
$email = env('SITE_OWNER', false);
|
|
||||||
$fields = [
|
|
||||||
'user_id' => $user->id,
|
|
||||||
'user_address' => $user->email,
|
|
||||||
'code' => $code,
|
|
||||||
'ip' => $ipAddress,
|
|
||||||
];
|
|
||||||
|
|
||||||
Mail::send(
|
|
||||||
['emails.blocked-login-html', 'emails.blocked-login-text'], $fields, function (Message $message) use ($email, $user) {
|
|
||||||
$message->to($email, $email)->subject('Blocked a login attempt from ' . trim($user->email) . '.');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (Swift_TransportException $e) {
|
|
||||||
Log::error($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,21 +26,11 @@ use Illuminate\Support\Facades\Password;
|
|||||||
*
|
*
|
||||||
* @package FireflyIII\Http\Controllers\Auth
|
* @package FireflyIII\Http\Controllers\Auth
|
||||||
* @method getEmailSubject()
|
* @method getEmailSubject()
|
||||||
* @method getSendResetLinkEmailSuccessResponse()
|
* @method getSendResetLinkEmailSuccessResponse(string $response)
|
||||||
* @method getSendResetLinkEmailFailureResponse()
|
* @method getSendResetLinkEmailFailureResponse(string $response)
|
||||||
*/
|
*/
|
||||||
class PasswordController extends Controller
|
class PasswordController extends Controller
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Password Reset Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This controller is responsible for handling password reset requests
|
|
||||||
| and uses a simple trait to include this behavior. You're free to
|
|
||||||
| explore this trait and override any methods you wish to tweak.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
use ResetsPasswords;
|
use ResetsPasswords;
|
||||||
|
|
||||||
|
|||||||
57
app/Http/Controllers/Auth/RegisterController.php
Executable file → Normal file
57
app/Http/Controllers/Auth/RegisterController.php
Executable file → Normal file
@@ -14,17 +14,16 @@ namespace FireflyIII\Http\Controllers\Auth;
|
|||||||
|
|
||||||
use Auth;
|
use Auth;
|
||||||
use Config;
|
use Config;
|
||||||
|
use FireflyConfig;
|
||||||
|
use FireflyIII\Events\BlockedUseOfDomain;
|
||||||
|
use FireflyIII\Events\BlockedUseOfEmail;
|
||||||
use FireflyIII\Events\RegisteredUser;
|
use FireflyIII\Events\RegisteredUser;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Support\Facades\FireflyConfig;
|
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Mail\Message;
|
|
||||||
use Log;
|
use Log;
|
||||||
use Mail;
|
|
||||||
use Session;
|
use Session;
|
||||||
use Swift_TransportException;
|
|
||||||
use Validator;
|
use Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,16 +33,6 @@ use Validator;
|
|||||||
*/
|
*/
|
||||||
class RegisterController extends Controller
|
class RegisterController extends Controller
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Register Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This controller handles the registration of new users as well as their
|
|
||||||
| validation and creation. By default this controller uses a trait to
|
|
||||||
| provide this functionality without requiring any additional code.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
use RegistersUsers;
|
use RegistersUsers;
|
||||||
|
|
||||||
@@ -93,8 +82,19 @@ class RegisterController extends Controller
|
|||||||
if ($this->isBlockedDomain($data['email'])) {
|
if ($this->isBlockedDomain($data['email'])) {
|
||||||
$validator->getMessageBag()->add('email', (string)trans('validation.invalid_domain'));
|
$validator->getMessageBag()->add('email', (string)trans('validation.invalid_domain'));
|
||||||
|
|
||||||
$this->reportBlockedDomainRegistrationAttempt($data['email'], $request->ip());
|
event(new BlockedUseOfDomain($data['email'], $request->ip()));
|
||||||
|
$this->throwValidationException($request, $validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
// is user a deleted user?
|
||||||
|
$hash = hash('sha256', $data['email']);
|
||||||
|
$configuration = FireflyConfig::get('deleted_users', []);
|
||||||
|
$set = $configuration->data;
|
||||||
|
Log::debug(sprintf('Hash of email is %s', $hash));
|
||||||
|
Log::debug('Hashes of deleted users: ', $set);
|
||||||
|
if (in_array($hash, $set)) {
|
||||||
|
$validator->getMessageBag()->add('email', (string)trans('validation.deleted_user'));
|
||||||
|
event(new BlockedUseOfEmail($data['email'], $request->ip()));
|
||||||
$this->throwValidationException($request, $validator);
|
$this->throwValidationException($request, $validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,31 +202,4 @@ class RegisterController extends Controller
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a message home about a blocked domain and the address attempted to register.
|
|
||||||
*
|
|
||||||
* @param string $registrationMail
|
|
||||||
* @param string $ipAddress
|
|
||||||
*/
|
|
||||||
private function reportBlockedDomainRegistrationAttempt(string $registrationMail, string $ipAddress)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$email = env('SITE_OWNER', false);
|
|
||||||
$parts = explode('@', $registrationMail);
|
|
||||||
$domain = $parts[1];
|
|
||||||
$fields = [
|
|
||||||
'email_address' => $registrationMail,
|
|
||||||
'blocked_domain' => $domain,
|
|
||||||
'ip' => $ipAddress,
|
|
||||||
];
|
|
||||||
|
|
||||||
Mail::send(
|
|
||||||
['emails.blocked-registration-html', 'emails.blocked-registration-text'], $fields, function (Message $message) use ($email, $domain) {
|
|
||||||
$message->to($email, $email)->subject('Blocked a registration attempt with domain ' . $domain . '.');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (Swift_TransportException $e) {
|
|
||||||
Log::error($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
10
app/Http/Controllers/Auth/ResetPasswordController.php
Executable file → Normal file
10
app/Http/Controllers/Auth/ResetPasswordController.php
Executable file → Normal file
@@ -22,16 +22,6 @@ use Illuminate\Foundation\Auth\ResetsPasswords;
|
|||||||
*/
|
*/
|
||||||
class ResetPasswordController extends Controller
|
class ResetPasswordController extends Controller
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Password Reset Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This controller is responsible for handling password reset requests
|
|
||||||
| and uses a simple trait to include this behavior. You're free to
|
|
||||||
| explore this trait and override any methods you wish to tweak.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
use ResetsPasswords;
|
use ResetsPasswords;
|
||||||
|
|
||||||
|
|||||||
@@ -100,12 +100,19 @@ class BillController extends Controller
|
|||||||
public function destroy(BillRepositoryInterface $repository, Bill $bill)
|
public function destroy(BillRepositoryInterface $repository, Bill $bill)
|
||||||
{
|
{
|
||||||
$name = $bill->name;
|
$name = $bill->name;
|
||||||
|
$billId = $bill->id;
|
||||||
$repository->destroy($bill);
|
$repository->destroy($bill);
|
||||||
|
|
||||||
Session::flash('success', strval(trans('firefly.deleted_bill', ['name' => $name])));
|
Session::flash('success', strval(trans('firefly.deleted_bill', ['name' => $name])));
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
return redirect(session('bills.delete.url'));
|
$uri = session('bills.delete.url');
|
||||||
|
if (!(strpos($uri, sprintf('bills/show/%s', $billId)) === false)) {
|
||||||
|
// uri would point back to bill
|
||||||
|
$uri = route('bills.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect($uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ namespace FireflyIII\Http\Controllers;
|
|||||||
|
|
||||||
use Amount;
|
use Amount;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Config;
|
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollector;
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
use FireflyIII\Http\Requests\BudgetFormRequest;
|
use FireflyIII\Http\Requests\BudgetFormRequest;
|
||||||
|
use FireflyIII\Http\Requests\BudgetIncomeRequest;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\LimitRepetition;
|
use FireflyIII\Models\LimitRepetition;
|
||||||
@@ -26,8 +26,6 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
|||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Input;
|
use Input;
|
||||||
use Log;
|
|
||||||
use Navigation;
|
|
||||||
use Preferences;
|
use Preferences;
|
||||||
use Response;
|
use Response;
|
||||||
use Session;
|
use Session;
|
||||||
@@ -42,6 +40,9 @@ use View;
|
|||||||
class BudgetController extends Controller
|
class BudgetController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** @var BudgetRepositoryInterface */
|
||||||
|
private $repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -55,6 +56,7 @@ class BudgetController extends Controller
|
|||||||
function ($request, $next) {
|
function ($request, $next) {
|
||||||
View::share('title', trans('firefly.budgets'));
|
View::share('title', trans('firefly.budgets'));
|
||||||
View::share('mainTitleIcon', 'fa-tasks');
|
View::share('mainTitleIcon', 'fa-tasks');
|
||||||
|
$this->repository = app(BudgetRepositoryInterface::class);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
@@ -75,19 +77,13 @@ class BudgetController extends Controller
|
|||||||
/** @var Carbon $end */
|
/** @var Carbon $end */
|
||||||
$end = session('end', Carbon::now()->endOfMonth());
|
$end = session('end', Carbon::now()->endOfMonth());
|
||||||
$viewRange = Preferences::get('viewRange', '1M')->data;
|
$viewRange = Preferences::get('viewRange', '1M')->data;
|
||||||
|
|
||||||
// is custom view range?
|
|
||||||
if (session('is_custom_range') === true) {
|
|
||||||
$viewRange = 'custom';
|
|
||||||
}
|
|
||||||
|
|
||||||
$limitRepetition = $repository->updateLimitAmount($budget, $start, $end, $viewRange, $amount);
|
$limitRepetition = $repository->updateLimitAmount($budget, $start, $end, $viewRange, $amount);
|
||||||
if ($amount == 0) {
|
if ($amount == 0) {
|
||||||
$limitRepetition = null;
|
$limitRepetition = null;
|
||||||
}
|
}
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0]);
|
return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0, 'amount' => $amount]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,14 +131,20 @@ class BudgetController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
$name = $budget->name;
|
$name = $budget->name;
|
||||||
|
$budgetId = $budget->id;
|
||||||
$repository->destroy($budget);
|
$repository->destroy($budget);
|
||||||
|
|
||||||
|
|
||||||
Session::flash('success', strval(trans('firefly.deleted_budget', ['name' => e($name)])));
|
Session::flash('success', strval(trans('firefly.deleted_budget', ['name' => e($name)])));
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
|
$uri = session('budgets.delete.url');
|
||||||
|
if (!(strpos($uri, sprintf('budgets/show/%s', $budgetId)) === false)) {
|
||||||
|
// uri would point back to budget
|
||||||
|
$uri = route('budgets.index');
|
||||||
|
}
|
||||||
|
|
||||||
return redirect(session('budgets.delete.url'));
|
return redirect($uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,82 +169,27 @@ class BudgetController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param BudgetRepositoryInterface $repository
|
|
||||||
* @param AccountRepositoryInterface $accountRepository
|
|
||||||
*
|
|
||||||
* @return View
|
* @return View
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public function index(BudgetRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
public function index()
|
||||||
{
|
{
|
||||||
$repository->cleanupBudgets();
|
$this->repository->cleanupBudgets();
|
||||||
|
|
||||||
$budgets = $repository->getActiveBudgets();
|
$budgets = $this->repository->getActiveBudgets();
|
||||||
$inactive = $repository->getInactiveBudgets();
|
$inactive = $this->repository->getInactiveBudgets();
|
||||||
$spent = '0';
|
|
||||||
$budgeted = '0';
|
|
||||||
$range = Preferences::get('viewRange', '1M')->data;
|
|
||||||
$repeatFreq = Config::get('firefly.range_to_repeat_freq.' . $range);
|
|
||||||
|
|
||||||
if (session('is_custom_range') === true) {
|
|
||||||
$repeatFreq = 'custom';
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var Carbon $start */
|
|
||||||
$start = session('start', new Carbon);
|
$start = session('start', new Carbon);
|
||||||
/** @var Carbon $end */
|
|
||||||
$end = session('end', new Carbon);
|
$end = session('end', new Carbon);
|
||||||
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
|
|
||||||
$budgetIncomeTotal = Preferences::get($key, 1000)->data;
|
|
||||||
$period = Navigation::periodShow($start, $range);
|
|
||||||
$periodStart = $start->formatLocalized($this->monthAndDayFormat);
|
$periodStart = $start->formatLocalized($this->monthAndDayFormat);
|
||||||
$periodEnd = $end->formatLocalized($this->monthAndDayFormat);
|
$periodEnd = $end->formatLocalized($this->monthAndDayFormat);
|
||||||
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH]);
|
$budgetInformation = $this->collectBudgetInformation($budgets, $start, $end);
|
||||||
$startAsString = $start->format('Y-m-d');
|
|
||||||
$endAsString = $end->format('Y-m-d');
|
|
||||||
Log::debug('Now at /budgets');
|
|
||||||
|
|
||||||
// loop the budgets:
|
|
||||||
/** @var Budget $budget */
|
|
||||||
foreach ($budgets as $budget) {
|
|
||||||
Log::debug(sprintf('Now at budget #%d ("%s")', $budget->id, $budget->name));
|
|
||||||
$budget->spent = $repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end);
|
|
||||||
$allRepetitions = $repository->getAllBudgetLimitRepetitions($start, $end);
|
|
||||||
$otherRepetitions = new Collection;
|
|
||||||
|
|
||||||
/** @var LimitRepetition $repetition */
|
|
||||||
foreach ($allRepetitions as $repetition) {
|
|
||||||
if ($repetition->budget_id == $budget->id) {
|
|
||||||
if ($repetition->budgetLimit->repeat_freq == $repeatFreq
|
|
||||||
&& $repetition->startdate->format('Y-m-d') == $startAsString
|
|
||||||
&& $repetition->enddate->format('Y-m-d') == $endAsString
|
|
||||||
) {
|
|
||||||
// do something
|
|
||||||
$budget->currentRep = $repetition;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$otherRepetitions->push($repetition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$budget->otherRepetitions = $otherRepetitions;
|
|
||||||
|
|
||||||
if (!is_null($budget->currentRep) && !is_null($budget->currentRep->id)) {
|
|
||||||
$budgeted = bcadd($budgeted, $budget->currentRep->amount);
|
|
||||||
}
|
|
||||||
$spent = bcadd($spent, $budget->spent);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$defaultCurrency = Amount::getDefaultCurrency();
|
$defaultCurrency = Amount::getDefaultCurrency();
|
||||||
|
$available = $this->repository->getAvailableBudget($defaultCurrency, $start, $end);
|
||||||
|
$spent = array_sum(array_column($budgetInformation, 'spent'));
|
||||||
|
$budgeted = array_sum(array_column($budgetInformation, 'budgeted'));
|
||||||
|
|
||||||
return view(
|
return view(
|
||||||
'budgets.index', compact(
|
'budgets.index',
|
||||||
'periodStart', 'periodEnd',
|
compact('available', 'periodStart', 'periodEnd', 'budgetInformation', 'defaultCurrency', 'inactive', 'budgets', 'spent', 'budgeted')
|
||||||
'period', 'range', 'budgetIncomeTotal',
|
|
||||||
'defaultCurrency', 'inactive', 'budgets',
|
|
||||||
'spent', 'budgeted'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,16 +221,14 @@ class BudgetController extends Controller
|
|||||||
/**
|
/**
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function postUpdateIncome()
|
public function postUpdateIncome(BudgetIncomeRequest $request)
|
||||||
{
|
{
|
||||||
$range = Preferences::get('viewRange', '1M')->data;
|
$start = session('start', new Carbon);
|
||||||
/** @var Carbon $date */
|
$end = session('end', new Carbon);
|
||||||
$date = session('start', new Carbon);
|
$defaultCurrency = Amount::getDefaultCurrency();
|
||||||
$start = Navigation::startOfPeriod($date, $range);
|
$amount = $request->get('amount');
|
||||||
$end = Navigation::endOfPeriod($start, $range);
|
|
||||||
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
|
|
||||||
|
|
||||||
Preferences::set($key, intval(Input::get('amount')));
|
$this->repository->setAvailableBudget($defaultCurrency, $start, $end, $amount);
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
return redirect(route('budgets.index'));
|
return redirect(route('budgets.index'));
|
||||||
@@ -304,7 +249,7 @@ class BudgetController extends Controller
|
|||||||
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
|
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
|
||||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||||
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH]);
|
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH]);
|
||||||
|
$repetition = null;
|
||||||
// collector:
|
// collector:
|
||||||
$collector = new JournalCollector(auth()->user());
|
$collector = new JournalCollector(auth()->user());
|
||||||
$collector->setAllAssetAccounts()->setRange($start, $end)->setBudget($budget)->setLimit($pageSize)->setPage($page);
|
$collector->setAllAssetAccounts()->setRange($start, $end)->setBudget($budget)->setLimit($pageSize)->setPage($page);
|
||||||
@@ -424,19 +369,57 @@ class BudgetController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function updateIncome()
|
public function updateIncome()
|
||||||
{
|
{
|
||||||
$range = Preferences::get('viewRange', '1M')->data;
|
$start = session('start', new Carbon);
|
||||||
$format = strval(trans('config.month_and_day'));
|
$end = session('end', new Carbon);
|
||||||
|
$defaultCurrency = Amount::getDefaultCurrency();
|
||||||
|
$available = $this->repository->getAvailableBudget($defaultCurrency, $start, $end);
|
||||||
|
|
||||||
/** @var Carbon $date */
|
|
||||||
$date = session('start', new Carbon);
|
|
||||||
$start = Navigation::startOfPeriod($date, $range);
|
|
||||||
$end = Navigation::endOfPeriod($start, $range);
|
|
||||||
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
|
|
||||||
$amount = Preferences::get($key, 1000);
|
|
||||||
$displayStart = $start->formatLocalized($format);
|
|
||||||
$displayEnd = $end->formatLocalized($format);
|
|
||||||
|
|
||||||
return view('budgets.income', compact('amount', 'displayStart', 'displayEnd'));
|
return view('budgets.income', compact('available', 'start', 'end'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function collectBudgetInformation(Collection $budgets, Carbon $start, Carbon $end): array
|
||||||
|
{
|
||||||
|
// get account information
|
||||||
|
$accountRepository = app(AccountRepositoryInterface::class);
|
||||||
|
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH]);
|
||||||
|
$return = [];
|
||||||
|
/** @var Budget $budget */
|
||||||
|
foreach ($budgets as $budget) {
|
||||||
|
$budgetId = $budget->id;
|
||||||
|
$return[$budgetId] = [
|
||||||
|
'spent' => $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end),
|
||||||
|
'budgeted' => '0',
|
||||||
|
'currentRep' => false,
|
||||||
|
];
|
||||||
|
$allRepetitions = $this->repository->getAllBudgetLimitRepetitions($start, $end);
|
||||||
|
$otherRepetitions = new Collection;
|
||||||
|
|
||||||
|
// get all the limit repetitions relevant between start and end and examine them:
|
||||||
|
/** @var LimitRepetition $repetition */
|
||||||
|
foreach ($allRepetitions as $repetition) {
|
||||||
|
if ($repetition->budget_id == $budget->id) {
|
||||||
|
if ($repetition->startdate->isSameDay($start) && $repetition->enddate->isSameDay($end)
|
||||||
|
) {
|
||||||
|
$return[$budgetId]['currentRep'] = $repetition;
|
||||||
|
$return[$budgetId]['budgeted'] = $repetition->amount;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// otherwise it's just one of the many relevant repetitions:
|
||||||
|
$otherRepetitions->push($repetition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$return[$budgetId]['otherRepetitions'] = $otherRepetitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace FireflyIII\Http\Controllers;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollector;
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
|
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||||
use FireflyIII\Http\Requests\CategoryFormRequest;
|
use FireflyIII\Http\Requests\CategoryFormRequest;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Models\Category;
|
use FireflyIII\Models\Category;
|
||||||
@@ -60,7 +61,6 @@ class CategoryController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
// put previous url in session if not redirect from store (not "create another").
|
|
||||||
if (session('categories.create.fromStore') !== true) {
|
if (session('categories.create.fromStore') !== true) {
|
||||||
Session::put('categories.create.url', URL::previous());
|
Session::put('categories.create.url', URL::previous());
|
||||||
}
|
}
|
||||||
@@ -99,12 +99,19 @@ class CategoryController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
$name = $category->name;
|
$name = $category->name;
|
||||||
|
$categoryId = $category->id;
|
||||||
$repository->destroy($category);
|
$repository->destroy($category);
|
||||||
|
|
||||||
Session::flash('success', strval(trans('firefly.deleted_category', ['name' => e($name)])));
|
Session::flash('success', strval(trans('firefly.deleted_category', ['name' => e($name)])));
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
return redirect(session('categories.delete.url'));
|
$uri = session('categories.delete.url');
|
||||||
|
if (!(strpos($uri, sprintf('categories/show/%s', $categoryId)) === false)) {
|
||||||
|
// uri would point back to category
|
||||||
|
$uri = route('categories.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect($uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -190,7 +197,7 @@ class CategoryController extends Controller
|
|||||||
$subTitleIcon = 'fa-bar-chart';
|
$subTitleIcon = 'fa-bar-chart';
|
||||||
|
|
||||||
// use journal collector
|
// use journal collector
|
||||||
$collector = new JournalCollector(auth()->user());
|
$collector = app(JournalCollectorInterface::class);
|
||||||
$collector->setPage($page)->setLimit($pageSize)->setAllAssetAccounts()->setRange($start, $end)->setCategory($category);
|
$collector->setPage($page)->setLimit($pageSize)->setAllAssetAccounts()->setRange($start, $end)->setCategory($category);
|
||||||
$journals = $collector->getPaginatedJournals();
|
$journals = $collector->getPaginatedJournals();
|
||||||
$journals->setPath('categories/show/' . $category->id);
|
$journals->setPath('categories/show/' . $category->id);
|
||||||
@@ -257,12 +264,11 @@ class CategoryController extends Controller
|
|||||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||||
|
|
||||||
// new collector:
|
// new collector:
|
||||||
$collector = new JournalCollector(auth()->user());
|
$collector = app(JournalCollectorInterface::class);
|
||||||
$collector->setPage($page)->setLimit($pageSize)->setAllAssetAccounts()->setRange($start, $end)->setCategory($category);
|
$collector->setPage($page)->setLimit($pageSize)->setAllAssetAccounts()->setRange($start, $end)->setCategory($category);
|
||||||
$journals = $collector->getPaginatedJournals();
|
$journals = $collector->getPaginatedJournals();
|
||||||
$journals->setPath('categories/show/' . $category->id . '/' . $date);
|
$journals->setPath('categories/show/' . $category->id . '/' . $date);
|
||||||
|
|
||||||
|
|
||||||
return view('categories.show-by-date', compact('category', 'journals', 'hideCategory', 'subTitle', 'carbon'));
|
return view('categories.show-by-date', compact('category', 'journals', 'hideCategory', 'subTitle', 'carbon'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace FireflyIII\Http\Controllers\Chart;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Exception;
|
use Exception;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Generator\Chart\Account\AccountChartGeneratorInterface;
|
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
@@ -42,7 +42,7 @@ use Steam;
|
|||||||
class AccountController extends Controller
|
class AccountController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
/** @var \FireflyIII\Generator\Chart\Account\AccountChartGeneratorInterface */
|
/** @var GeneratorInterface */
|
||||||
protected $generator;
|
protected $generator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,8 +51,49 @@ class AccountController extends Controller
|
|||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
// create chart generator:
|
$this->generator = app(GeneratorInterface::class);
|
||||||
$this->generator = app(AccountChartGeneratorInterface::class);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function all(Account $account)
|
||||||
|
{
|
||||||
|
$cache = new CacheProperties();
|
||||||
|
$cache->addProperty('chart.account.all');
|
||||||
|
$cache->addProperty($account->id);
|
||||||
|
if ($cache->has()) {
|
||||||
|
Log::debug('Return chart.account.all from cache.');
|
||||||
|
|
||||||
|
return Response::json($cache->get());
|
||||||
|
}
|
||||||
|
Log::debug('Regenerate chart.account.all from scratch.');
|
||||||
|
|
||||||
|
/** @var AccountRepositoryInterface $repository */
|
||||||
|
$repository = app(AccountRepositoryInterface::class);
|
||||||
|
$start = $repository->oldestJournalDate($account);
|
||||||
|
$end = new Carbon;
|
||||||
|
$format = (string)trans('config.month_and_day');
|
||||||
|
$range = Steam::balanceInRange($account, $start, $end);
|
||||||
|
$current = clone $start;
|
||||||
|
$previous = array_values($range)[0];
|
||||||
|
$chartData = [];
|
||||||
|
|
||||||
|
while ($end >= $current) {
|
||||||
|
$theDate = $current->format('Y-m-d');
|
||||||
|
$balance = $range[$theDate] ?? $previous;
|
||||||
|
$label = $current->formatLocalized($format);
|
||||||
|
$chartData[$label] = $balance;
|
||||||
|
$previous = $balance;
|
||||||
|
$current->addDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->singleSet($account->name, $chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,36 +110,29 @@ class AccountController extends Controller
|
|||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('expenseAccounts');
|
$cache->addProperty('chart.account.expense-accounts');
|
||||||
$cache->addProperty('accounts');
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
$accounts = $repository->getAccountsByType([AccountType::EXPENSE, AccountType::BENEFICIARY]);
|
|
||||||
|
|
||||||
$start->subDay();
|
$start->subDay();
|
||||||
|
|
||||||
|
$accounts = $repository->getAccountsByType([AccountType::EXPENSE, AccountType::BENEFICIARY]);
|
||||||
$ids = $accounts->pluck('id')->toArray();
|
$ids = $accounts->pluck('id')->toArray();
|
||||||
$startBalances = Steam::balancesById($ids, $start);
|
$startBalances = Steam::balancesById($ids, $start);
|
||||||
$endBalances = Steam::balancesById($ids, $end);
|
$endBalances = Steam::balancesById($ids, $end);
|
||||||
|
$chartData = [];
|
||||||
|
|
||||||
$accounts->each(
|
foreach ($accounts as $account) {
|
||||||
function (Account $account) use ($startBalances, $endBalances) {
|
|
||||||
$id = $account->id;
|
$id = $account->id;
|
||||||
$startBalance = $startBalances[$id] ?? '0';
|
$startBalance = $startBalances[$id] ?? '0';
|
||||||
$endBalance = $endBalances[$id] ?? '0';
|
$endBalance = $endBalances[$id] ?? '0';
|
||||||
$diff = bcsub($endBalance, $startBalance);
|
$diff = bcsub($endBalance, $startBalance);
|
||||||
$account->difference = round($diff, 2);
|
if (bccomp($diff, '0') !== 0) {
|
||||||
|
$chartData[$account->name] = round($diff, 2);
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
$accounts = $accounts->sortByDesc(
|
|
||||||
function (Account $account) {
|
|
||||||
return $account->difference;
|
|
||||||
}
|
}
|
||||||
);
|
arsort($chartData);
|
||||||
|
$data = $this->generator->singleSet(strval(trans('firefly.spent')), $chartData);
|
||||||
$data = $this->generator->expenseAccounts($accounts, $start, $end);
|
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -118,28 +152,33 @@ class AccountController extends Controller
|
|||||||
$cache->addProperty($account->id);
|
$cache->addProperty($account->id);
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('expenseByBudget');
|
$cache->addProperty('chart.account.expense-budget');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
|
$collector->setAccounts(new Collection([$account]))
|
||||||
|
->setRange($start, $end)
|
||||||
// grab all journals:
|
->withBudgetInformation()
|
||||||
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->withBudgetInformation()->setTypes([TransactionType::WITHDRAWAL]);
|
->setTypes([TransactionType::WITHDRAWAL]);
|
||||||
$transactions = $collector->getJournals();
|
$transactions = $collector->getJournals();
|
||||||
|
$chartData = [];
|
||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
/** @var Transaction $transaction */
|
/** @var Transaction $transaction */
|
||||||
foreach ($transactions as $transaction) {
|
foreach ($transactions as $transaction) {
|
||||||
$jrnlBudgetId = intval($transaction->transaction_journal_budget_id);
|
$jrnlBudgetId = intval($transaction->transaction_journal_budget_id);
|
||||||
$transBudgetId = intval($transaction->transaction_budget_id);
|
$transBudgetId = intval($transaction->transaction_budget_id);
|
||||||
$budgetId = max($jrnlBudgetId, $transBudgetId);
|
$budgetId = max($jrnlBudgetId, $transBudgetId);
|
||||||
|
|
||||||
$result[$budgetId] = $result[$budgetId] ?? '0';
|
$result[$budgetId] = $result[$budgetId] ?? '0';
|
||||||
$result[$budgetId] = bcadd($transaction->transaction_amount, $result[$budgetId]);
|
$result[$budgetId] = bcadd($transaction->transaction_amount, $result[$budgetId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$names = $this->getBudgetNames(array_keys($result));
|
$names = $this->getBudgetNames(array_keys($result));
|
||||||
$data = $this->generator->pieChart($result, $names);
|
foreach ($result as $budgetId => $amount) {
|
||||||
|
$chartData[$names[$budgetId]] = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -159,26 +198,30 @@ class AccountController extends Controller
|
|||||||
$cache->addProperty($account->id);
|
$cache->addProperty($account->id);
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('expenseByCategory');
|
$cache->addProperty('chart.account.expense-category');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// grab all journals:
|
|
||||||
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->withCategoryInformation()->setTypes([TransactionType::WITHDRAWAL]);
|
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->withCategoryInformation()->setTypes([TransactionType::WITHDRAWAL]);
|
||||||
$transactions = $collector->getJournals();
|
$transactions = $collector->getJournals();
|
||||||
$result = [];
|
$result = [];
|
||||||
|
$chartData = [];
|
||||||
/** @var Transaction $transaction */
|
/** @var Transaction $transaction */
|
||||||
foreach ($transactions as $transaction) {
|
foreach ($transactions as $transaction) {
|
||||||
$jrnlCatId = intval($transaction->transaction_journal_category_id);
|
$jrnlCatId = intval($transaction->transaction_journal_category_id);
|
||||||
$transCatId = intval($transaction->transaction_category_id);
|
$transCatId = intval($transaction->transaction_category_id);
|
||||||
$categoryId = max($jrnlCatId, $transCatId);
|
$categoryId = max($jrnlCatId, $transCatId);
|
||||||
|
|
||||||
$result[$categoryId] = $result[$categoryId] ?? '0';
|
$result[$categoryId] = $result[$categoryId] ?? '0';
|
||||||
$result[$categoryId] = bcadd($transaction->transaction_amount, $result[$categoryId]);
|
$result[$categoryId] = bcadd($transaction->transaction_amount, $result[$categoryId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$names = $this->getCategoryNames(array_keys($result));
|
$names = $this->getCategoryNames(array_keys($result));
|
||||||
$data = $this->generator->pieChart($result, $names);
|
foreach ($result as $categoryId => $amount) {
|
||||||
|
$chartData[$names[$categoryId]] = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -196,7 +239,15 @@ class AccountController extends Controller
|
|||||||
{
|
{
|
||||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||||
$frontPage = Preferences::get('frontPageAccounts', $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])->pluck('id')->toArray());
|
$defaultSet = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])->pluck('id')->toArray();
|
||||||
|
Log::debug('Default set is ', $defaultSet);
|
||||||
|
$frontPage = Preferences::get('frontPageAccounts', $defaultSet);
|
||||||
|
Log::debug('Frontpage preference set is ', $frontPage->data);
|
||||||
|
if (count($frontPage->data) === 0) {
|
||||||
|
$frontPage->data = $defaultSet;
|
||||||
|
Log::debug('frontpage set is empty!');
|
||||||
|
$frontPage->save();
|
||||||
|
}
|
||||||
$accounts = $repository->getAccountsById($frontPage->data);
|
$accounts = $repository->getAccountsById($frontPage->data);
|
||||||
|
|
||||||
return Response::json($this->accountBalanceChart($accounts, $start, $end));
|
return Response::json($this->accountBalanceChart($accounts, $start, $end));
|
||||||
@@ -216,7 +267,7 @@ class AccountController extends Controller
|
|||||||
$cache->addProperty($account->id);
|
$cache->addProperty($account->id);
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('incomeByCategory');
|
$cache->addProperty('chart.account.income-category');
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
@@ -225,23 +276,74 @@ class AccountController extends Controller
|
|||||||
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->withCategoryInformation()->setTypes([TransactionType::DEPOSIT]);
|
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->withCategoryInformation()->setTypes([TransactionType::DEPOSIT]);
|
||||||
$transactions = $collector->getJournals();
|
$transactions = $collector->getJournals();
|
||||||
$result = [];
|
$result = [];
|
||||||
|
$chartData = [];
|
||||||
/** @var Transaction $transaction */
|
/** @var Transaction $transaction */
|
||||||
foreach ($transactions as $transaction) {
|
foreach ($transactions as $transaction) {
|
||||||
$jrnlCatId = intval($transaction->transaction_journal_category_id);
|
$jrnlCatId = intval($transaction->transaction_journal_category_id);
|
||||||
$transCatId = intval($transaction->transaction_category_id);
|
$transCatId = intval($transaction->transaction_category_id);
|
||||||
$categoryId = max($jrnlCatId, $transCatId);
|
$categoryId = max($jrnlCatId, $transCatId);
|
||||||
|
|
||||||
$result[$categoryId] = $result[$categoryId] ?? '0';
|
$result[$categoryId] = $result[$categoryId] ?? '0';
|
||||||
$result[$categoryId] = bcadd($transaction->transaction_amount, $result[$categoryId]);
|
$result[$categoryId] = bcadd($transaction->transaction_amount, $result[$categoryId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$names = $this->getCategoryNames(array_keys($result));
|
$names = $this->getCategoryNames(array_keys($result));
|
||||||
$data = $this->generator->pieChart($result, $names);
|
foreach ($result as $categoryId => $amount) {
|
||||||
|
$chartData[$names[$categoryId]] = $amount;
|
||||||
|
}
|
||||||
|
$data = $this->generator->pieChart($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param string $date
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
* @throws FireflyException
|
||||||
|
*/
|
||||||
|
public function period(Account $account, string $date)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$start = new Carbon($date);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
throw new FireflyException('"' . e($date) . '" does not seem to be a valid date. Should be in the format YYYY-MM-DD');
|
||||||
|
}
|
||||||
|
$range = Preferences::get('viewRange', '1M')->data;
|
||||||
|
$end = Navigation::endOfPeriod($start, $range);
|
||||||
|
$cache = new CacheProperties();
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty('chart.account.period');
|
||||||
|
$cache->addProperty($account->id);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
$format = (string)trans('config.month_and_day');
|
||||||
|
$range = Steam::balanceInRange($account, $start, $end);
|
||||||
|
$current = clone $start;
|
||||||
|
$previous = array_values($range)[0];
|
||||||
|
$chartData = [];
|
||||||
|
|
||||||
|
while ($end >= $current) {
|
||||||
|
$theDate = $current->format('Y-m-d');
|
||||||
|
$balance = $range[$theDate] ?? $previous;
|
||||||
|
$label = $current->formatLocalized($format);
|
||||||
|
$chartData[$label] = $balance;
|
||||||
|
$previous = $balance;
|
||||||
|
$current->addDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->singleSet($account->name, $chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
|
return Response::json($data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the balances for a given set of dates and accounts.
|
* Shows the balances for a given set of dates and accounts.
|
||||||
*
|
*
|
||||||
@@ -267,11 +369,11 @@ class AccountController extends Controller
|
|||||||
{
|
{
|
||||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||||
|
$chartData = [];
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('revenueAccounts');
|
$cache->addProperty('chart.account.revenue-accounts');
|
||||||
$cache->addProperty('accounts');
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
@@ -282,25 +384,19 @@ class AccountController extends Controller
|
|||||||
$startBalances = Steam::balancesById($ids, $start);
|
$startBalances = Steam::balancesById($ids, $start);
|
||||||
$endBalances = Steam::balancesById($ids, $end);
|
$endBalances = Steam::balancesById($ids, $end);
|
||||||
|
|
||||||
$accounts->each(
|
foreach ($accounts as $account) {
|
||||||
function (Account $account) use ($startBalances, $endBalances) {
|
|
||||||
$id = $account->id;
|
$id = $account->id;
|
||||||
$startBalance = $startBalances[$id] ?? '0';
|
$startBalance = $startBalances[$id] ?? '0';
|
||||||
$endBalance = $endBalances[$id] ?? '0';
|
$endBalance = $endBalances[$id] ?? '0';
|
||||||
$diff = bcsub($endBalance, $startBalance);
|
$diff = bcsub($endBalance, $startBalance);
|
||||||
$diff = bcmul($diff, '-1');
|
$diff = bcmul($diff, '-1');
|
||||||
$account->difference = round($diff, 2);
|
if (bccomp($diff, '0') !== 0) {
|
||||||
|
$chartData[$account->name] = round($diff, 2);
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
$accounts = $accounts->sortByDesc(
|
|
||||||
function (Account $account) {
|
|
||||||
return $account->difference;
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
$data = $this->generator->revenueAccounts($accounts, $start, $end);
|
arsort($chartData);
|
||||||
|
$data = $this->generator->singleSet(strval(trans('firefly.spent')), $chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -322,8 +418,7 @@ class AccountController extends Controller
|
|||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('frontpage');
|
$cache->addProperty('chart.account.single');
|
||||||
$cache->addProperty('single');
|
|
||||||
$cache->addProperty($account->id);
|
$cache->addProperty($account->id);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
@@ -333,73 +428,18 @@ class AccountController extends Controller
|
|||||||
$range = Steam::balanceInRange($account, $start, $end);
|
$range = Steam::balanceInRange($account, $start, $end);
|
||||||
$current = clone $start;
|
$current = clone $start;
|
||||||
$previous = array_values($range)[0];
|
$previous = array_values($range)[0];
|
||||||
$labels = [];
|
|
||||||
$chartData = [];
|
$chartData = [];
|
||||||
|
|
||||||
while ($end >= $current) {
|
while ($end >= $current) {
|
||||||
$theDate = $current->format('Y-m-d');
|
$theDate = $current->format('Y-m-d');
|
||||||
$balance = $range[$theDate] ?? $previous;
|
$balance = $range[$theDate] ?? $previous;
|
||||||
|
$label = $current->formatLocalized($format);
|
||||||
$labels[] = $current->formatLocalized($format);
|
$chartData[$label] = $balance;
|
||||||
$chartData[] = $balance;
|
|
||||||
$previous = $balance;
|
$previous = $balance;
|
||||||
$current->addDay();
|
$current->addDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->singleSet($account->name, $chartData);
|
||||||
$data = $this->generator->single($account, $labels, $chartData);
|
|
||||||
$cache->store($data);
|
|
||||||
|
|
||||||
return Response::json($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Account $account
|
|
||||||
* @param string $date
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws FireflyException
|
|
||||||
*/
|
|
||||||
public function specificPeriod(Account $account, string $date)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$start = new Carbon($date);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Log::error($e->getMessage());
|
|
||||||
throw new FireflyException('"' . e($date) . '" does not seem to be a valid date. Should be in the format YYYY-MM-DD');
|
|
||||||
}
|
|
||||||
$range = Preferences::get('viewRange', '1M')->data;
|
|
||||||
$end = Navigation::endOfPeriod($start, $range);
|
|
||||||
// chart properties for cache:
|
|
||||||
$cache = new CacheProperties();
|
|
||||||
$cache->addProperty($start);
|
|
||||||
$cache->addProperty($end);
|
|
||||||
$cache->addProperty('frontpage');
|
|
||||||
$cache->addProperty('specificPeriod');
|
|
||||||
$cache->addProperty($account->id);
|
|
||||||
if ($cache->has()) {
|
|
||||||
return Response::json($cache->get());
|
|
||||||
}
|
|
||||||
|
|
||||||
$format = (string)trans('config.month_and_day');
|
|
||||||
$range = Steam::balanceInRange($account, $start, $end);
|
|
||||||
$current = clone $start;
|
|
||||||
$previous = array_values($range)[0];
|
|
||||||
$labels = [];
|
|
||||||
$chartData = [];
|
|
||||||
|
|
||||||
while ($end >= $current) {
|
|
||||||
$theDate = $current->format('Y-m-d');
|
|
||||||
$balance = $range[$theDate] ?? $previous;
|
|
||||||
|
|
||||||
$labels[] = $current->formatLocalized($format);
|
|
||||||
$chartData[] = $balance;
|
|
||||||
$previous = $balance;
|
|
||||||
$current->addDay();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$data = $this->generator->single($account, $labels, $chartData);
|
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -418,27 +458,35 @@ class AccountController extends Controller
|
|||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('account-balance-chart');
|
$cache->addProperty('chart.account.account-balance-chart');
|
||||||
$cache->addProperty($accounts);
|
$cache->addProperty($accounts);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
|
Log::debug('Return chart.account.account-balance-chart from cache.');
|
||||||
|
|
||||||
return $cache->get();
|
return $cache->get();
|
||||||
}
|
}
|
||||||
|
Log::debug('Regenerate chart.account.account-balance-chart from scratch.');
|
||||||
|
|
||||||
|
$chartData = [];
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
$balances = [];
|
$currentSet = [
|
||||||
$current = clone $start;
|
'label' => $account->name,
|
||||||
|
'entries' => [],
|
||||||
|
];
|
||||||
|
$currentStart = clone $start;
|
||||||
$range = Steam::balanceInRange($account, $start, clone $end);
|
$range = Steam::balanceInRange($account, $start, clone $end);
|
||||||
$previous = round(array_values($range)[0], 2);
|
$previous = round(array_values($range)[0], 2);
|
||||||
while ($current <= $end) {
|
while ($currentStart <= $end) {
|
||||||
$format = $current->format('Y-m-d');
|
$format = $currentStart->format('Y-m-d');
|
||||||
|
$label = $currentStart->formatLocalized(strval(trans('config.month_and_day')));
|
||||||
$balance = isset($range[$format]) ? round($range[$format], 2) : $previous;
|
$balance = isset($range[$format]) ? round($range[$format], 2) : $previous;
|
||||||
$previous = $balance;
|
$previous = $balance;
|
||||||
$balances[] = $balance;
|
$currentStart->addDay();
|
||||||
$current->addDay();
|
$currentSet['entries'][$label] = $balance;
|
||||||
}
|
}
|
||||||
$account->balances = $balances;
|
$chartData[] = $currentSet;
|
||||||
}
|
}
|
||||||
$data = $this->generator->frontpage($accounts, $start, $end);
|
$data = $this->generator->multiSet($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ declare(strict_types = 1);
|
|||||||
namespace FireflyIII\Http\Controllers\Chart;
|
namespace FireflyIII\Http\Controllers\Chart;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Generator\Chart\Bill\BillChartGeneratorInterface;
|
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollector;
|
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\Bill;
|
use FireflyIII\Models\Bill;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
@@ -32,7 +32,7 @@ use Response;
|
|||||||
class BillController extends Controller
|
class BillController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
/** @var \FireflyIII\Generator\Chart\Bill\BillChartGeneratorInterface */
|
/** @var GeneratorInterface */
|
||||||
protected $generator;
|
protected $generator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,8 +41,7 @@ class BillController extends Controller
|
|||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
// create chart generator:
|
$this->generator = app(GeneratorInterface::class);
|
||||||
$this->generator = app(BillChartGeneratorInterface::class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,43 +55,79 @@ class BillController extends Controller
|
|||||||
{
|
{
|
||||||
$start = session('start', Carbon::now()->startOfMonth());
|
$start = session('start', Carbon::now()->startOfMonth());
|
||||||
$end = session('end', Carbon::now()->endOfMonth());
|
$end = session('end', Carbon::now()->endOfMonth());
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty('chart.bill.frontpage');
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get());
|
||||||
|
}
|
||||||
|
|
||||||
$paid = $repository->getBillsPaidInRange($start, $end); // will be a negative amount.
|
$paid = $repository->getBillsPaidInRange($start, $end); // will be a negative amount.
|
||||||
$unpaid = $repository->getBillsUnpaidInRange($start, $end); // will be a positive amount.
|
$unpaid = $repository->getBillsUnpaidInRange($start, $end); // will be a positive amount.
|
||||||
$data = $this->generator->frontpage($paid, $unpaid);
|
$chartData = [
|
||||||
|
strval(trans('firefly.unpaid')) => $unpaid,
|
||||||
|
strval(trans('firefly.paid')) => $paid,
|
||||||
|
];
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the overview for a bill. The min/max amount and matched journals.
|
* @param JournalCollectorInterface $collector
|
||||||
*
|
|
||||||
* @param Bill $bill
|
* @param Bill $bill
|
||||||
*
|
*
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function single(Bill $bill)
|
public function single(JournalCollectorInterface $collector, Bill $bill)
|
||||||
{
|
{
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty('single');
|
$cache->addProperty('chart.bill.single');
|
||||||
$cache->addProperty('bill');
|
|
||||||
$cache->addProperty($bill->id);
|
$cache->addProperty($bill->id);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// get first transaction or today for start:
|
$results = $collector->setAllAssetAccounts()->setBills(new Collection([$bill]))->getJournals();
|
||||||
$collector = new JournalCollector(auth()->user());
|
|
||||||
$collector->setAllAssetAccounts()->setBills(new Collection([$bill]));
|
|
||||||
$results = $collector->getJournals();
|
|
||||||
|
|
||||||
// resort:
|
|
||||||
$results = $results->sortBy(
|
$results = $results->sortBy(
|
||||||
function (Transaction $transaction) {
|
function (Transaction $transaction) {
|
||||||
return $transaction->date->format('U');
|
return $transaction->date->format('U');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
$data = $this->generator->single($bill, $results);
|
$chartData = [
|
||||||
|
[
|
||||||
|
'type' => 'bar',
|
||||||
|
'label' => trans('firefly.min-amount'),
|
||||||
|
'entries' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'type' => 'bar',
|
||||||
|
'label' => trans('firefly.max-amount'),
|
||||||
|
'entries' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'type' => 'line',
|
||||||
|
'label' => trans('firefly.journal-amount'),
|
||||||
|
'entries' => [],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var Transaction $entry */
|
||||||
|
foreach ($results as $entry) {
|
||||||
|
$date = $entry->date->formatLocalized(strval(trans('config.month_and_day')));
|
||||||
|
// minimum amount of bill:
|
||||||
|
$chartData[0]['entries'][$date] = $bill->amount_min;
|
||||||
|
// maximum amount of bill:
|
||||||
|
$chartData[1]['entries'][$date] = $bill->amount_max;
|
||||||
|
// amount of journal:
|
||||||
|
$chartData[2]['entries'][$date] = bcmul($entry->transaction_amount, '-1');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->multiSet($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ declare(strict_types = 1);
|
|||||||
namespace FireflyIII\Http\Controllers\Chart;
|
namespace FireflyIII\Http\Controllers\Chart;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Generator\Chart\Budget\BudgetChartGeneratorInterface;
|
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollector;
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
@@ -36,7 +36,7 @@ use Response;
|
|||||||
class BudgetController extends Controller
|
class BudgetController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
/** @var BudgetChartGeneratorInterface */
|
/** @var GeneratorInterface */
|
||||||
protected $generator;
|
protected $generator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,8 +45,7 @@ class BudgetController extends Controller
|
|||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
// create chart generator:
|
$this->generator = app(GeneratorInterface::class);
|
||||||
$this->generator = app(BudgetChartGeneratorInterface::class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,7 +65,7 @@ class BudgetController extends Controller
|
|||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($first);
|
$cache->addProperty($first);
|
||||||
$cache->addProperty($last);
|
$cache->addProperty($last);
|
||||||
$cache->addProperty('budget');
|
$cache->addProperty('chart.budget.budget');
|
||||||
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
@@ -77,7 +76,7 @@ class BudgetController extends Controller
|
|||||||
|
|
||||||
$budgetCollection = new Collection([$budget]);
|
$budgetCollection = new Collection([$budget]);
|
||||||
$last = Navigation::endOfX($last, $range, $final); // not to overshoot.
|
$last = Navigation::endOfX($last, $range, $final); // not to overshoot.
|
||||||
$entries = new Collection;
|
$entries = [];
|
||||||
while ($first < $last) {
|
while ($first < $last) {
|
||||||
|
|
||||||
// periodspecific dates:
|
// periodspecific dates:
|
||||||
@@ -86,12 +85,13 @@ class BudgetController extends Controller
|
|||||||
// sub another day because reasons.
|
// sub another day because reasons.
|
||||||
$currentEnd->subDay();
|
$currentEnd->subDay();
|
||||||
$spent = $repository->spentInPeriod($budgetCollection, new Collection, $currentStart, $currentEnd);
|
$spent = $repository->spentInPeriod($budgetCollection, new Collection, $currentStart, $currentEnd);
|
||||||
$entry = [$first, ($spent * -1)];
|
$format = Navigation::periodShow($first, $range);
|
||||||
$entries->push($entry);
|
$entries[$format] = bcmul($spent, '-1');
|
||||||
$first = Navigation::addPeriod($first, $range, 0);
|
$first = Navigation::addPeriod($first, $range, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->budgetLimit($entries, 'month');
|
$data = $this->generator->singleSet(strval(trans('firefly.spent')), $entries);
|
||||||
|
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -113,25 +113,25 @@ class BudgetController extends Controller
|
|||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('budget-limit');
|
$cache->addProperty('chart.budget.budget.limit');
|
||||||
$cache->addProperty($budget->id);
|
|
||||||
$cache->addProperty($repetition->id);
|
$cache->addProperty($repetition->id);
|
||||||
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
$entries = new Collection;
|
$entries = [];
|
||||||
$amount = $repetition->amount;
|
$amount = $repetition->amount;
|
||||||
$budgetCollection = new Collection([$budget]);
|
$budgetCollection = new Collection([$budget]);
|
||||||
while ($start <= $end) {
|
while ($start <= $end) {
|
||||||
$spent = $repository->spentInPeriod($budgetCollection, new Collection, $start, $start);
|
$spent = $repository->spentInPeriod($budgetCollection, new Collection, $start, $start);
|
||||||
$amount = bcadd($amount, $spent);
|
$amount = bcadd($amount, $spent);
|
||||||
$entries->push([clone $start, round($amount, 2)]);
|
$format = $start->formatLocalized(strval(trans('config.month_and_day')));
|
||||||
|
$entries[$format] = $amount;
|
||||||
|
|
||||||
$start->addDay();
|
$start->addDay();
|
||||||
}
|
}
|
||||||
$data = $this->generator->budgetLimit($entries, 'month_and_day');
|
$data = $this->generator->singleSet(strval(trans('firefly.left')), $entries);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -152,14 +152,30 @@ class BudgetController extends Controller
|
|||||||
$cache = new CacheProperties();
|
$cache = new CacheProperties();
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('budget');
|
$cache->addProperty('chart.budget.frontpage');
|
||||||
$cache->addProperty('all');
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
$budgets = $repository->getActiveBudgets();
|
$budgets = $repository->getActiveBudgets();
|
||||||
$repetitions = $repository->getAllBudgetLimitRepetitions($start, $end);
|
$repetitions = $repository->getAllBudgetLimitRepetitions($start, $end);
|
||||||
$allEntries = new Collection;
|
$chartData = [
|
||||||
|
[
|
||||||
|
'label' => strval(trans('firefly.spent_in_budget')),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => strval(trans('firefly.left_to_spend')),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => strval(trans('firefly.overspent')),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
/** @var Budget $budget */
|
/** @var Budget $budget */
|
||||||
foreach ($budgets as $budget) {
|
foreach ($budgets as $budget) {
|
||||||
@@ -167,17 +183,34 @@ class BudgetController extends Controller
|
|||||||
$reps = $this->filterRepetitions($repetitions, $budget, $start, $end);
|
$reps = $this->filterRepetitions($repetitions, $budget, $start, $end);
|
||||||
|
|
||||||
if ($reps->count() === 0) {
|
if ($reps->count() === 0) {
|
||||||
$collection = $this->spentInPeriodSingle($repository, $budget, $start, $end);
|
$row = $this->spentInPeriodSingle($repository, $budget, $start, $end);
|
||||||
$allEntries = $allEntries->merge($collection);
|
if (bccomp($row['spent'], '0') !== 0 || bccomp($row['repetition_left'], '0') !== 0) {
|
||||||
|
$chartData[0]['entries'][$row['name']] = bcmul($row['spent'], '-1');
|
||||||
|
$chartData[1]['entries'][$row['name']] = $row['repetition_left'];
|
||||||
|
$chartData[2]['entries'][$row['name']] = bcmul($row['repetition_overspent'], '-1');
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$collection = $this->spentInPeriodMulti($repository, $budget, $reps);
|
$rows = $this->spentInPeriodMulti($repository, $budget, $reps);
|
||||||
$allEntries = $allEntries->merge($collection);
|
foreach ($rows as $row) {
|
||||||
|
if (bccomp($row['spent'], '0') !== 0 || bccomp($row['repetition_left'], '0') !== 0) {
|
||||||
|
$chartData[0]['entries'][$row['name']] = bcmul($row['spent'], '-1');
|
||||||
|
$chartData[1]['entries'][$row['name']] = $row['repetition_left'];
|
||||||
|
$chartData[2]['entries'][$row['name']] = bcmul($row['repetition_overspent'], '-1');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($rows, $row);
|
||||||
|
|
||||||
}
|
}
|
||||||
$entry = $this->spentInPeriodWithout($start, $end);
|
// for no budget:
|
||||||
$allEntries->push($entry);
|
$row = $this->spentInPeriodWithout($start, $end);
|
||||||
$data = $this->generator->frontpage($allEntries);
|
if (bccomp($row['repetition_overspent'], '0') !== 0) {
|
||||||
|
$chartData[0]['entries'][$row['name']] = bcmul($row['spent'], '-1');
|
||||||
|
$chartData[1]['entries'][$row['name']] = $row['repetition_left'];
|
||||||
|
$chartData[2]['entries'][$row['name']] = bcmul($row['repetition_overspent'], '-1');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->multiSet($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -201,20 +234,19 @@ class BudgetController extends Controller
|
|||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty($accounts);
|
$cache->addProperty($accounts);
|
||||||
$cache->addProperty($budget->id);
|
$cache->addProperty($budget->id);
|
||||||
$cache->addProperty('budget');
|
$cache->addProperty('chart.budget.period');
|
||||||
$cache->addProperty('period');
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// the expenses:
|
// get the expenses
|
||||||
$periods = Navigation::listOfPeriods($start, $end);
|
|
||||||
$entries = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end, false);
|
|
||||||
$budgeted = [];
|
$budgeted = [];
|
||||||
|
$periods = Navigation::listOfPeriods($start, $end);
|
||||||
|
$entries = $repository->getBudgetPeriodReport(new Collection([$budget]), $accounts, $start, $end);
|
||||||
$key = Navigation::preferredCarbonFormat($start, $end);
|
$key = Navigation::preferredCarbonFormat($start, $end);
|
||||||
$range = Navigation::preferredRangeFormat($start, $end);
|
$range = Navigation::preferredRangeFormat($start, $end);
|
||||||
|
|
||||||
// get budgeted:
|
// get the budget limits (if any)
|
||||||
$repetitions = $repository->getAllBudgetLimitRepetitions($start, $end);
|
$repetitions = $repository->getAllBudgetLimitRepetitions($start, $end);
|
||||||
$current = clone $start;
|
$current = clone $start;
|
||||||
while ($current < $end) {
|
while ($current < $end) {
|
||||||
@@ -235,18 +267,29 @@ class BudgetController extends Controller
|
|||||||
$current = clone $currentEnd;
|
$current = clone $currentEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// join them:
|
// join them into one set of data:
|
||||||
$result = [];
|
$chartData = [
|
||||||
foreach (array_keys($periods) as $period) {
|
[
|
||||||
$nice = $periods[$period];
|
'label' => strval(trans('firefly.spent')),
|
||||||
$result[$nice] = [
|
'type' => 'bar',
|
||||||
'spent' => isset($entries[$budget->id]['entries'][$period]) ? $entries[$budget->id]['entries'][$period] : '0',
|
'entries' => [],
|
||||||
'budgeted' => isset($entries[$period]) ? $budgeted[$period] : 0,
|
],
|
||||||
|
[
|
||||||
|
'label' => strval(trans('firefly.budgeted')),
|
||||||
|
'type' => 'bar',
|
||||||
|
'entries' => [],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
foreach (array_keys($periods) as $period) {
|
||||||
|
$label = $periods[$period];
|
||||||
|
$spent = isset($entries[$budget->id]['entries'][$period]) ? $entries[$budget->id]['entries'][$period] : '0';
|
||||||
|
$limit = isset($budgeted[$period]) ? $budgeted[$period] : 0;
|
||||||
|
$chartData[0]['entries'][$label] = round(bcmul($spent, '-1'), 2);
|
||||||
|
$chartData[1]['entries'][$label] = $limit;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
$data = $this->generator->multiSet($chartData);
|
||||||
$data = $this->generator->period($result);
|
|
||||||
|
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -267,8 +310,7 @@ class BudgetController extends Controller
|
|||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty($accounts);
|
$cache->addProperty($accounts);
|
||||||
$cache->addProperty('no-budget');
|
$cache->addProperty('chart.budget.no-budget');
|
||||||
$cache->addProperty('period');
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
@@ -276,18 +318,15 @@ class BudgetController extends Controller
|
|||||||
// the expenses:
|
// the expenses:
|
||||||
$periods = Navigation::listOfPeriods($start, $end);
|
$periods = Navigation::listOfPeriods($start, $end);
|
||||||
$entries = $repository->getNoBudgetPeriodReport($accounts, $start, $end);
|
$entries = $repository->getNoBudgetPeriodReport($accounts, $start, $end);
|
||||||
|
$chartData = [];
|
||||||
|
|
||||||
// join them:
|
// join them:
|
||||||
$result = [];
|
|
||||||
foreach (array_keys($periods) as $period) {
|
foreach (array_keys($periods) as $period) {
|
||||||
$nice = $periods[$period];
|
$label = $periods[$period];
|
||||||
$result[$nice] = [
|
$spent = isset($entries['entries'][$period]) ? $entries['entries'][$period] : '0';
|
||||||
'spent' => isset($entries['entries'][$period]) ? $entries['entries'][$period] : '0',
|
$chartData[$label] = bcmul($spent, '-1');
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
$data = $this->generator->singleSet(strval(trans('firefly.spent')), $chartData);
|
||||||
$data = $this->generator->periodNoBudget($result);
|
|
||||||
|
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -316,16 +355,24 @@ class BudgetController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns an array with the following values:
|
||||||
|
* 0 =>
|
||||||
|
* 'name' => name of budget + repetition
|
||||||
|
* 'repetition_left' => left in budget repetition (always zero)
|
||||||
|
* 'repetition_overspent' => spent more than budget repetition? (always zero)
|
||||||
|
* 'spent' => actually spent in period for budget
|
||||||
|
* 1 => (etc)
|
||||||
|
*
|
||||||
* @param BudgetRepositoryInterface $repository
|
* @param BudgetRepositoryInterface $repository
|
||||||
* @param Budget $budget
|
* @param Budget $budget
|
||||||
* @param Collection $repetitions
|
* @param Collection $repetitions
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function spentInPeriodMulti(BudgetRepositoryInterface $repository, Budget $budget, Collection $repetitions): Collection
|
private function spentInPeriodMulti(BudgetRepositoryInterface $repository, Budget $budget, Collection $repetitions): array
|
||||||
{
|
{
|
||||||
|
$return = [];
|
||||||
$format = strval(trans('config.month_and_day'));
|
$format = strval(trans('config.month_and_day'));
|
||||||
$collection = new Collection;
|
|
||||||
$name = $budget->name;
|
$name = $budget->name;
|
||||||
/** @var LimitRepetition $repetition */
|
/** @var LimitRepetition $repetition */
|
||||||
foreach ($repetitions as $repetition) {
|
foreach ($repetitions as $repetition) {
|
||||||
@@ -339,37 +386,54 @@ class BudgetController extends Controller
|
|||||||
}
|
}
|
||||||
$amount = $repetition->amount;
|
$amount = $repetition->amount;
|
||||||
$left = bccomp(bcadd($amount, $expenses), '0') < 1 ? '0' : bcadd($amount, $expenses);
|
$left = bccomp(bcadd($amount, $expenses), '0') < 1 ? '0' : bcadd($amount, $expenses);
|
||||||
$spent = bccomp(bcadd($amount, $expenses), '0') < 1 ? bcmul($amount, '-1') : $expenses;
|
$spent = $expenses;
|
||||||
$overspent = bccomp(bcadd($amount, $expenses), '0') < 1 ? bcadd($amount, $expenses) : '0';
|
$overspent = bccomp(bcadd($amount, $expenses), '0') < 1 ? bcadd($amount, $expenses) : '0';
|
||||||
$array = [$name, $left, $spent, $overspent, $amount, $spent];
|
$return[] = [
|
||||||
$collection->push($array);
|
'name' => $name,
|
||||||
|
'repetition_left' => $left,
|
||||||
|
'repetition_overspent' => $overspent,
|
||||||
|
'spent' => $spent,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $collection;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns an array with the following values:
|
||||||
|
* 'name' => name of budget
|
||||||
|
* 'repetition_left' => left in budget repetition (always zero)
|
||||||
|
* 'repetition_overspent' => spent more than budget repetition? (always zero)
|
||||||
|
* 'spent' => actually spent in period for budget
|
||||||
|
*
|
||||||
|
*
|
||||||
* @param BudgetRepositoryInterface $repository
|
* @param BudgetRepositoryInterface $repository
|
||||||
* @param Budget $budget
|
* @param Budget $budget
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function spentInPeriodSingle(BudgetRepositoryInterface $repository, Budget $budget, Carbon $start, Carbon $end): Collection
|
private function spentInPeriodSingle(BudgetRepositoryInterface $repository, Budget $budget, Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
$collection = new Collection;
|
|
||||||
$amount = '0';
|
|
||||||
$left = '0';
|
|
||||||
$spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end);
|
$spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end);
|
||||||
$overspent = '0';
|
$array = [
|
||||||
$array = [$budget->name, $left, $spent, $overspent, $amount, $spent];
|
'name' => $budget->name,
|
||||||
$collection->push($array);
|
'repetition_left' => '0',
|
||||||
|
'repetition_overspent' => '0',
|
||||||
|
'spent' => $spent,
|
||||||
|
];
|
||||||
|
|
||||||
return $collection;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Returns an array with the following values:
|
||||||
|
* 'name' => "no budget" in local language
|
||||||
|
* 'repetition_left' => left in budget repetition (always zero)
|
||||||
|
* 'repetition_overspent' => spent more than budget repetition? (always zero)
|
||||||
|
* 'spent' => actually spent in period for budget
|
||||||
|
*
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
*
|
*
|
||||||
@@ -387,7 +451,13 @@ class BudgetController extends Controller
|
|||||||
foreach ($journals as $entry) {
|
foreach ($journals as $entry) {
|
||||||
$sum = bcadd($entry->transaction_amount, $sum);
|
$sum = bcadd($entry->transaction_amount, $sum);
|
||||||
}
|
}
|
||||||
|
$array = [
|
||||||
|
'name' => strval(trans('firefly.no_budget')),
|
||||||
|
'repetition_left' => '0',
|
||||||
|
'repetition_overspent' => $sum,
|
||||||
|
'spent' => '0',
|
||||||
|
];
|
||||||
|
|
||||||
return [trans('firefly.no_budget'), '0', '0', $sum, '0', '0'];
|
return $array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
364
app/Http/Controllers/Chart/BudgetReportController.php
Normal file
364
app/Http/Controllers/Chart/BudgetReportController.php
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BudgetReportController.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Http\Controllers\Chart;
|
||||||
|
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
||||||
|
use FireflyIII\Generator\Report\Category\MonthReportGenerator;
|
||||||
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
|
use FireflyIII\Models\Budget;
|
||||||
|
use FireflyIII\Models\LimitRepetition;
|
||||||
|
use FireflyIII\Models\Transaction;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
|
use FireflyIII\Support\CacheProperties;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Log;
|
||||||
|
use Navigation;
|
||||||
|
use Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Separate controller because many helper functions are shared.
|
||||||
|
*
|
||||||
|
* Class BudgetReportController
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Http\Controllers\Chart
|
||||||
|
*/
|
||||||
|
class BudgetReportController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var AccountRepositoryInterface */
|
||||||
|
private $accountRepository;
|
||||||
|
/** @var BudgetRepositoryInterface */
|
||||||
|
private $budgetRepository;
|
||||||
|
/** @var GeneratorInterface */
|
||||||
|
private $generator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->middleware(
|
||||||
|
function ($request, $next) {
|
||||||
|
$this->generator = app(GeneratorInterface::class);
|
||||||
|
$this->budgetRepository = app(BudgetRepositoryInterface::class);
|
||||||
|
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $budgets
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param string $others
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function accountExpense(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end, string $others)
|
||||||
|
{
|
||||||
|
/** @var bool $others */
|
||||||
|
$others = intval($others) === 1;
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('chart.budget.report.account-expense');
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($budgets);
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($others);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
$names = [];
|
||||||
|
$set = $this->getExpenses($accounts, $budgets, $start, $end);
|
||||||
|
$grouped = $this->groupByOpposingAccount($set);
|
||||||
|
$chartData = [];
|
||||||
|
$total = '0';
|
||||||
|
|
||||||
|
foreach ($grouped as $accountId => $amount) {
|
||||||
|
if (!isset($names[$accountId])) {
|
||||||
|
$account = $this->accountRepository->find(intval($accountId));
|
||||||
|
$names[$accountId] = $account->name;
|
||||||
|
}
|
||||||
|
$amount = bcmul($amount, '-1');
|
||||||
|
$total = bcadd($total, $amount);
|
||||||
|
$chartData[$names[$accountId]] = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// also collect all transactions NOT in these budgets.
|
||||||
|
if ($others) {
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL]);
|
||||||
|
$journals = $collector->getJournals();
|
||||||
|
$sum = strval($journals->sum('transaction_amount'));
|
||||||
|
$sum = bcmul($sum, '-1');
|
||||||
|
$sum = bcsub($sum, $total);
|
||||||
|
$chartData[strval(trans('firefly.everything_else'))] = $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
|
return Response::json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $budgets
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param string $others
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function budgetExpense(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end, string $others)
|
||||||
|
{
|
||||||
|
/** @var bool $others */
|
||||||
|
$others = intval($others) === 1;
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('chart.budget.report.budget-expense');
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($budgets);
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($others);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
$names = [];
|
||||||
|
$set = $this->getExpenses($accounts, $budgets, $start, $end);
|
||||||
|
$grouped = $this->groupByBudget($set);
|
||||||
|
$total = '0';
|
||||||
|
$chartData = [];
|
||||||
|
|
||||||
|
foreach ($grouped as $budgetId => $amount) {
|
||||||
|
if (!isset($names[$budgetId])) {
|
||||||
|
$budget = $this->budgetRepository->find(intval($budgetId));
|
||||||
|
$names[$budgetId] = $budget->name;
|
||||||
|
}
|
||||||
|
$amount = bcmul($amount, '-1');
|
||||||
|
$total = bcadd($total, $amount);
|
||||||
|
$chartData[$names[$budgetId]] = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// also collect all transactions NOT in these budgets.
|
||||||
|
if ($others) {
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL]);
|
||||||
|
$journals = $collector->getJournals();
|
||||||
|
$sum = strval($journals->sum('transaction_amount'));
|
||||||
|
$sum = bcmul($sum, '-1');
|
||||||
|
$sum = bcsub($sum, $total);
|
||||||
|
$chartData[strval(trans('firefly.everything_else'))] = $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->pieChart($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
|
return Response::json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $budgets
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function mainChart(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('chart.budget.report.main');
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($budgets);
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get());
|
||||||
|
}
|
||||||
|
/** @var BudgetRepositoryInterface $repository */
|
||||||
|
$repository = app(BudgetRepositoryInterface::class);
|
||||||
|
$format = Navigation::preferredCarbonLocalizedFormat($start, $end);
|
||||||
|
$function = Navigation::preferredEndOfPeriod($start, $end);
|
||||||
|
$chartData = [];
|
||||||
|
$currentStart = clone $start;
|
||||||
|
$limits = $repository->getAllBudgetLimitRepetitions($start, $end); // also for ALL budgets.
|
||||||
|
|
||||||
|
// prep chart data:
|
||||||
|
foreach ($budgets as $budget) {
|
||||||
|
$chartData[$budget->id] = [
|
||||||
|
'label' => strval(trans('firefly.spent_in_specific_budget', ['budget' => $budget->name])),
|
||||||
|
'type' => 'bar',
|
||||||
|
'yAxisID' => 'y-axis-0',
|
||||||
|
'entries' => [],
|
||||||
|
];
|
||||||
|
$chartData[$budget->id . '-sum'] = [
|
||||||
|
'label' => strval(trans('firefly.sum_of_expenses_in_budget', ['budget' => $budget->name])),
|
||||||
|
'type' => 'line',
|
||||||
|
'fill' => false,
|
||||||
|
'yAxisID' => 'y-axis-1',
|
||||||
|
'entries' => [],
|
||||||
|
];
|
||||||
|
$chartData[$budget->id . '-left'] = [
|
||||||
|
'label' => strval(trans('firefly.left_in_budget_limit', ['budget' => $budget->name])),
|
||||||
|
'type' => 'bar',
|
||||||
|
'fill' => false,
|
||||||
|
'yAxisID' => 'y-axis-0',
|
||||||
|
'entries' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$sumOfExpenses = [];
|
||||||
|
$leftOfLimits = [];
|
||||||
|
while ($currentStart < $end) {
|
||||||
|
$currentEnd = clone $currentStart;
|
||||||
|
$currentEnd = $currentEnd->$function();
|
||||||
|
$expenses = $this->groupByBudget($this->getExpenses($accounts, $budgets, $currentStart, $currentEnd));
|
||||||
|
$label = $currentStart->formatLocalized($format);
|
||||||
|
|
||||||
|
/** @var Budget $budget */
|
||||||
|
foreach ($budgets as $budget) {
|
||||||
|
$currentExpenses = $expenses[$budget->id] ?? '0';
|
||||||
|
$sumOfExpenses[$budget->id] = $sumOfExpenses[$budget->id] ?? '0';
|
||||||
|
$sumOfExpenses[$budget->id] = bcadd($currentExpenses, $sumOfExpenses[$budget->id]);
|
||||||
|
$chartData[$budget->id]['entries'][$label] = round(bcmul($currentExpenses, '-1'), 2);
|
||||||
|
$chartData[$budget->id . '-sum']['entries'][$label] = round(bcmul($sumOfExpenses[$budget->id], '-1'), 2);
|
||||||
|
|
||||||
|
$limit = $this->filterLimits($limits, $budget, $currentStart);
|
||||||
|
if (!is_null($limit->id)) {
|
||||||
|
$leftOfLimits[$limit->id] = $leftOfLimits[$limit->id] ?? strval($limit->amount);
|
||||||
|
$leftOfLimits[$limit->id] = bcadd($leftOfLimits[$limit->id], $currentExpenses);
|
||||||
|
$chartData[$budget->id . '-left']['entries'][$label] = round($leftOfLimits[$limit->id], 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
$currentStart = clone $currentEnd;
|
||||||
|
$currentStart->addDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->generator->multiSet($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
|
return Response::json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $limits
|
||||||
|
* @param $budget
|
||||||
|
* @param $currentStart
|
||||||
|
*
|
||||||
|
* @return LimitRepetition
|
||||||
|
*/
|
||||||
|
private function filterLimits(Collection $limits, Budget $budget, Carbon $date): LimitRepetition
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('Start of filterLimits with %d limits.', $limits->count()));
|
||||||
|
$filtered = $limits->filter(
|
||||||
|
function (LimitRepetition $limit) use ($budget, $date) {
|
||||||
|
if ($limit->budget_id !== $budget->id) {
|
||||||
|
Log::debug(sprintf('LimitRepetition has budget #%d but expecting #%d', $limit->budget_id, $budget->id));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($date < $limit->startdate || $date > $limit->enddate) {
|
||||||
|
Log::debug(
|
||||||
|
sprintf(
|
||||||
|
'Date %s is not between %s and %s',
|
||||||
|
$date->format('Y-m-d'), $limit->startdate->format('Y-m-d'), $limit->enddate->format('Y-m-d')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $limit;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if ($filtered->count() === 1) {
|
||||||
|
return $filtered->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LimitRepetition;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $budgets
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function getExpenses(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end): Collection
|
||||||
|
{
|
||||||
|
$collector = new JournalCollector(auth()->user());
|
||||||
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
||||||
|
->setBudgets($budgets)->withOpposingAccount()->disableFilter();
|
||||||
|
$accountIds = $accounts->pluck('id')->toArray();
|
||||||
|
$transactions = $collector->getJournals();
|
||||||
|
$set = MonthReportGenerator::filterExpenses($transactions, $accountIds);
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $set
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function groupByBudget(Collection $set): array
|
||||||
|
{
|
||||||
|
// group by category ID:
|
||||||
|
$grouped = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$jrnlBudId = intval($transaction->transaction_journal_budget_id);
|
||||||
|
$transBudId = intval($transaction->transaction_budget_id);
|
||||||
|
$budgetId = max($jrnlBudId, $transBudId);
|
||||||
|
$grouped[$budgetId] = $grouped[$budgetId] ?? '0';
|
||||||
|
$grouped[$budgetId] = bcadd($transaction->transaction_amount, $grouped[$budgetId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $grouped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $set
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function groupByOpposingAccount(Collection $set): array
|
||||||
|
{
|
||||||
|
$grouped = [];
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$accountId = $transaction->opposing_account_id;
|
||||||
|
$grouped[$accountId] = $grouped[$accountId] ?? '0';
|
||||||
|
$grouped[$accountId] = bcadd($transaction->transaction_amount, $grouped[$accountId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $grouped;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ namespace FireflyIII\Http\Controllers\Chart;
|
|||||||
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Generator\Chart\Category\CategoryChartGeneratorInterface;
|
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Models\Category;
|
use FireflyIII\Models\Category;
|
||||||
@@ -26,7 +26,6 @@ use Illuminate\Support\Collection;
|
|||||||
use Navigation;
|
use Navigation;
|
||||||
use Preferences;
|
use Preferences;
|
||||||
use Response;
|
use Response;
|
||||||
use stdClass;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class CategoryController
|
* Class CategoryController
|
||||||
@@ -35,7 +34,7 @@ use stdClass;
|
|||||||
*/
|
*/
|
||||||
class CategoryController extends Controller
|
class CategoryController extends Controller
|
||||||
{
|
{
|
||||||
/** @var CategoryChartGeneratorInterface */
|
/** @var GeneratorInterface */
|
||||||
protected $generator;
|
protected $generator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +44,7 @@ class CategoryController extends Controller
|
|||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
// create chart generator:
|
// create chart generator:
|
||||||
$this->generator = app(CategoryChartGeneratorInterface::class);
|
$this->generator = app(GeneratorInterface::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,34 +58,42 @@ class CategoryController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function all(CRI $repository, AccountRepositoryInterface $accountRepository, Category $category)
|
public function all(CRI $repository, AccountRepositoryInterface $accountRepository, Category $category)
|
||||||
{
|
{
|
||||||
$start = $repository->firstUseDate($category);
|
|
||||||
$range = Preferences::get('viewRange', '1M')->data;
|
|
||||||
$start = Navigation::startOfPeriod($start, $range);
|
|
||||||
$categoryCollection = new Collection([$category]);
|
|
||||||
$end = new Carbon;
|
|
||||||
$entries = new Collection;
|
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
$cache->addProperty('chart.category.all');
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($category->id);
|
||||||
$cache->addProperty($end);
|
|
||||||
$cache->addProperty('all');
|
|
||||||
$cache->addProperty('categories');
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$start = $repository->firstUseDate($category);
|
||||||
|
$range = Preferences::get('viewRange', '1M')->data;
|
||||||
|
$start = Navigation::startOfPeriod($start, $range);
|
||||||
|
$end = new Carbon;
|
||||||
|
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||||
|
$chartData = [
|
||||||
|
[
|
||||||
|
'label' => strval(trans('firefly.spent')),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => strval(trans('firefly.earned')),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
while ($start <= $end) {
|
while ($start <= $end) {
|
||||||
$currentEnd = Navigation::endOfPeriod($start, $range);
|
$currentEnd = Navigation::endOfPeriod($start, $range);
|
||||||
$spent = $repository->spentInPeriod($categoryCollection, $accounts, $start, $currentEnd);
|
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $currentEnd);
|
||||||
$earned = $repository->earnedInPeriod($categoryCollection, $accounts, $start, $currentEnd);
|
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $start, $currentEnd);
|
||||||
$date = Navigation::periodShow($start, $range);
|
$label = Navigation::periodShow($start, $range);
|
||||||
$entries->push([clone $start, $date, $spent, $earned]);
|
$chartData[0]['entries'][$label] = bcmul($spent, '-1');
|
||||||
|
$chartData[1]['entries'][$label] = $earned;
|
||||||
$start = Navigation::addPeriod($start, $range, 0);
|
$start = Navigation::addPeriod($start, $range, 0);
|
||||||
}
|
}
|
||||||
$entries = $entries->reverse();
|
|
||||||
$entries = $entries->slice(0, 48);
|
$data = $this->generator->multiSet($chartData);
|
||||||
$entries = $entries->reverse();
|
|
||||||
$data = $this->generator->all($entries);
|
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -122,34 +129,29 @@ class CategoryController extends Controller
|
|||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('category');
|
$cache->addProperty('chart.category.frontpage');
|
||||||
$cache->addProperty('frontpage');
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
|
$chartData = [];
|
||||||
$categories = $repository->getCategories();
|
$categories = $repository->getCategories();
|
||||||
$accounts = $accountRepository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]);
|
$accounts = $accountRepository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]);
|
||||||
$set = new Collection;
|
|
||||||
/** @var Category $category */
|
/** @var Category $category */
|
||||||
foreach ($categories as $category) {
|
foreach ($categories as $category) {
|
||||||
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $end);
|
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $end);
|
||||||
if (bccomp($spent, '0') === -1) {
|
if (bccomp($spent, '0') === -1) {
|
||||||
$category->spent = $spent;
|
$chartData[$category->name] = bcmul($spent, '-1');
|
||||||
$set->push($category);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// this is a "fake" entry for the "no category" entry.
|
$chartData[strval(trans('firefly.no_category'))] = bcmul($repository->spentInPeriodWithoutCategory(new Collection, $start, $end), '-1');
|
||||||
$entry = new stdClass;
|
|
||||||
$entry->name = trans('firefly.no_category');
|
|
||||||
$entry->spent = $repository->spentInPeriodWithoutCategory(new Collection, $start, $end);
|
|
||||||
$set->push($entry);
|
|
||||||
|
|
||||||
$set = $set->sortBy('spent');
|
// sort
|
||||||
$data = $this->generator->frontpage($set);
|
arsort($chartData);
|
||||||
|
|
||||||
|
$data = $this->generator->singleSet(strval(trans('firefly.spent')), $chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -166,35 +168,43 @@ class CategoryController extends Controller
|
|||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('category-period-chart');
|
$cache->addProperty('chart.category.period');
|
||||||
$cache->addProperty($accounts->pluck('id')->toArray());
|
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||||
$cache->addProperty($category);
|
$cache->addProperty($category);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
|
|
||||||
return $cache->get();
|
return $cache->get();
|
||||||
}
|
}
|
||||||
$expenses = $repository->periodExpenses(new Collection([$category]), $accounts, $start, $end);
|
$expenses = $repository->periodExpenses(new Collection([$category]), $accounts, $start, $end);
|
||||||
$income = $repository->periodIncome(new Collection([$category]), $accounts, $start, $end);
|
$income = $repository->periodIncome(new Collection([$category]), $accounts, $start, $end);
|
||||||
$periods = Navigation::listOfPeriods($start, $end);
|
$periods = Navigation::listOfPeriods($start, $end);
|
||||||
|
$chartData = [
|
||||||
|
[
|
||||||
// join them:
|
'label' => strval(trans('firefly.spent')),
|
||||||
$result = [];
|
'entries' => [],
|
||||||
foreach (array_keys($periods) as $period) {
|
'type' => 'bar',
|
||||||
$nice = $periods[$period];
|
],
|
||||||
$result[$nice] = [
|
[
|
||||||
'earned' => $income[$category->id]['entries'][$period] ?? '0',
|
'label' => strval(trans('firefly.earned')),
|
||||||
'spent' => $expenses[$category->id]['entries'][$period] ?? '0',
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
foreach (array_keys($periods) as $period) {
|
||||||
|
$label = $periods[$period];
|
||||||
|
$spent = $expenses[$category->id]['entries'][$period] ?? '0';
|
||||||
|
$chartData[0]['entries'][$label] = bcmul($spent, '-1');
|
||||||
|
$chartData[1]['entries'][$label] = $income[$category->id]['entries'][$period] ?? '0';
|
||||||
}
|
}
|
||||||
$data = $this->generator->reportPeriod($result);
|
|
||||||
|
$data = $this->generator->multiSet($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param CRI $repository
|
* @param CRI $repository
|
||||||
* @param Category $category
|
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
@@ -206,26 +216,36 @@ class CategoryController extends Controller
|
|||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty('no-category-period-chart');
|
$cache->addProperty('chart.category.period.no-cat');
|
||||||
$cache->addProperty($accounts->pluck('id')->toArray());
|
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
|
|
||||||
return $cache->get();
|
return $cache->get();
|
||||||
}
|
}
|
||||||
$expenses = $repository->periodExpensesNoCategory($accounts, $start, $end);
|
$expenses = $repository->periodExpensesNoCategory($accounts, $start, $end);
|
||||||
$income = $repository->periodIncomeNoCategory($accounts, $start, $end);
|
$income = $repository->periodIncomeNoCategory($accounts, $start, $end);
|
||||||
$periods = Navigation::listOfPeriods($start, $end);
|
$periods = Navigation::listOfPeriods($start, $end);
|
||||||
|
$chartData = [
|
||||||
// join them:
|
[
|
||||||
$result = [];
|
'label' => strval(trans('firefly.spent')),
|
||||||
foreach (array_keys($periods) as $period) {
|
'entries' => [],
|
||||||
$nice = $periods[$period];
|
'type' => 'bar',
|
||||||
$result[$nice] = [
|
],
|
||||||
'earned' => $income['entries'][$period] ?? '0',
|
[
|
||||||
'spent' => $expenses['entries'][$period] ?? '0',
|
'label' => strval(trans('firefly.earned')),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
foreach (array_keys($periods) as $period) {
|
||||||
|
$label = $periods[$period];
|
||||||
|
$spent = $expenses['entries'][$period] ?? '0';
|
||||||
|
$chartData[0]['entries'][$label] = bcmul($spent, '-1');
|
||||||
|
$chartData[1]['entries'][$label] = $income['entries'][$period] ?? '0';
|
||||||
|
|
||||||
}
|
}
|
||||||
$data = $this->generator->reportPeriod($result);
|
$data = $this->generator->multiSet($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
@@ -260,33 +280,47 @@ class CategoryController extends Controller
|
|||||||
*/
|
*/
|
||||||
private function makePeriodChart(CRI $repository, Category $category, Carbon $start, Carbon $end)
|
private function makePeriodChart(CRI $repository, Category $category, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
$categoryCollection = new Collection([$category]);
|
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($category->id);
|
||||||
|
$cache->addProperty('chart.category.period-chart');
|
||||||
|
|
||||||
/** @var AccountRepositoryInterface $accountRepository */
|
/** @var AccountRepositoryInterface $accountRepository */
|
||||||
$accountRepository = app(AccountRepositoryInterface::class);
|
$accountRepository = app(AccountRepositoryInterface::class);
|
||||||
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||||
|
|
||||||
$cache->addProperty($start);
|
|
||||||
$cache->addProperty($end);
|
|
||||||
$cache->addProperty($accounts);
|
|
||||||
$cache->addProperty($category->id);
|
|
||||||
$cache->addProperty('specific-period');
|
|
||||||
|
|
||||||
|
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return $cache->get();
|
return $cache->get();
|
||||||
}
|
}
|
||||||
$entries = new Collection;
|
|
||||||
|
// chart data
|
||||||
|
$chartData = [
|
||||||
|
[
|
||||||
|
'label' => strval(trans('firefly.spent')),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => strval(trans('firefly.earned')),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
while ($start <= $end) {
|
while ($start <= $end) {
|
||||||
$spent = $repository->spentInPeriod($categoryCollection, $accounts, $start, $start);
|
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $start);
|
||||||
$earned = $repository->earnedInPeriod($categoryCollection, $accounts, $start, $start);
|
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $start, $start);
|
||||||
$date = Navigation::periodShow($start, '1D');
|
$label = Navigation::periodShow($start, '1D');
|
||||||
$entries->push([clone $start, $date, $spent, $earned]);
|
|
||||||
|
$chartData[0]['entries'][$label] = bcmul($spent, '-1');
|
||||||
|
$chartData[1]['entries'][$label] = $earned;
|
||||||
|
|
||||||
|
|
||||||
$start->addDay();
|
$start->addDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->period($entries);
|
$data = $this->generator->multiSet($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace FireflyIII\Http\Controllers\Chart;
|
|||||||
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Generator\Chart\Category\CategoryChartGeneratorInterface;
|
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
||||||
use FireflyIII\Generator\Report\Category\MonthReportGenerator;
|
use FireflyIII\Generator\Report\Category\MonthReportGenerator;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollector;
|
use FireflyIII\Helpers\Collector\JournalCollector;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
@@ -24,8 +24,9 @@ use FireflyIII\Models\Transaction;
|
|||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||||
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Log;
|
use Navigation;
|
||||||
use Response;
|
use Response;
|
||||||
|
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ class CategoryReportController extends Controller
|
|||||||
private $accountRepository;
|
private $accountRepository;
|
||||||
/** @var CategoryRepositoryInterface */
|
/** @var CategoryRepositoryInterface */
|
||||||
private $categoryRepository;
|
private $categoryRepository;
|
||||||
/** @var CategoryChartGeneratorInterface */
|
/** @var GeneratorInterface */
|
||||||
private $generator;
|
private $generator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,7 +55,7 @@ class CategoryReportController extends Controller
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->middleware(
|
$this->middleware(
|
||||||
function ($request, $next) {
|
function ($request, $next) {
|
||||||
$this->generator = app(CategoryChartGeneratorInterface::class);
|
$this->generator = app(GeneratorInterface::class);
|
||||||
$this->categoryRepository = app(CategoryRepositoryInterface::class);
|
$this->categoryRepository = app(CategoryRepositoryInterface::class);
|
||||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||||
|
|
||||||
@@ -76,15 +77,23 @@ class CategoryReportController extends Controller
|
|||||||
{
|
{
|
||||||
/** @var bool $others */
|
/** @var bool $others */
|
||||||
$others = intval($others) === 1;
|
$others = intval($others) === 1;
|
||||||
$names = [];
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('chart.category.report.account-expense');
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($categories);
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($others);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get());
|
||||||
|
}
|
||||||
|
|
||||||
// collect journals (just like the category report does):
|
$names = [];
|
||||||
$set = $this->getExpenses($accounts, $categories, $start, $end);
|
$set = $this->getExpenses($accounts, $categories, $start, $end);
|
||||||
$grouped = $this->groupByOpposingAccount($set);
|
$grouped = $this->groupByOpposingAccount($set);
|
||||||
|
$chartData = [];
|
||||||
// show the grouped results:
|
|
||||||
$result = [];
|
|
||||||
$total = '0';
|
$total = '0';
|
||||||
|
|
||||||
foreach ($grouped as $accountId => $amount) {
|
foreach ($grouped as $accountId => $amount) {
|
||||||
if (!isset($names[$accountId])) {
|
if (!isset($names[$accountId])) {
|
||||||
$account = $this->accountRepository->find(intval($accountId));
|
$account = $this->accountRepository->find(intval($accountId));
|
||||||
@@ -92,7 +101,7 @@ class CategoryReportController extends Controller
|
|||||||
}
|
}
|
||||||
$amount = bcmul($amount, '-1');
|
$amount = bcmul($amount, '-1');
|
||||||
$total = bcadd($total, $amount);
|
$total = bcadd($total, $amount);
|
||||||
$result[] = ['name' => $names[$accountId], 'id' => $accountId, 'amount' => $amount];
|
$chartData[$names[$accountId]] = $amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// also collect all transactions NOT in these categories.
|
// also collect all transactions NOT in these categories.
|
||||||
@@ -102,12 +111,12 @@ class CategoryReportController extends Controller
|
|||||||
$journals = $collector->getJournals();
|
$journals = $collector->getJournals();
|
||||||
$sum = strval($journals->sum('transaction_amount'));
|
$sum = strval($journals->sum('transaction_amount'));
|
||||||
$sum = bcmul($sum, '-1');
|
$sum = bcmul($sum, '-1');
|
||||||
Log::debug(sprintf('Sum of others in accountExpense is %f', $sum));
|
|
||||||
$sum = bcsub($sum, $total);
|
$sum = bcsub($sum, $total);
|
||||||
$result[] = ['name' => trans('firefly.everything_else'), 'id' => 0, 'amount' => $sum];
|
$chartData[strval(trans('firefly.everything_else'))] = $sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->pieChart($result);
|
$data = $this->generator->pieChart($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
@@ -125,22 +134,31 @@ class CategoryReportController extends Controller
|
|||||||
{
|
{
|
||||||
/** @var bool $others */
|
/** @var bool $others */
|
||||||
$others = intval($others) === 1;
|
$others = intval($others) === 1;
|
||||||
$names = [];
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('chart.category.report.account-income');
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($categories);
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($others);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get());
|
||||||
|
}
|
||||||
|
|
||||||
// collect journals (just like the category report does):
|
|
||||||
|
$names = [];
|
||||||
$set = $this->getIncome($accounts, $categories, $start, $end);
|
$set = $this->getIncome($accounts, $categories, $start, $end);
|
||||||
$grouped = $this->groupByOpposingAccount($set);
|
$grouped = $this->groupByOpposingAccount($set);
|
||||||
|
$chartData = [];
|
||||||
// loop and show the grouped results:
|
|
||||||
$result = [];
|
|
||||||
$total = '0';
|
$total = '0';
|
||||||
|
|
||||||
foreach ($grouped as $accountId => $amount) {
|
foreach ($grouped as $accountId => $amount) {
|
||||||
if (!isset($names[$accountId])) {
|
if (!isset($names[$accountId])) {
|
||||||
$account = $this->accountRepository->find(intval($accountId));
|
$account = $this->accountRepository->find(intval($accountId));
|
||||||
$names[$accountId] = $account->name;
|
$names[$accountId] = $account->name;
|
||||||
}
|
}
|
||||||
$total = bcadd($total, $amount);
|
$total = bcadd($total, $amount);
|
||||||
$result[] = ['name' => $names[$accountId], 'id' => $accountId, 'amount' => $amount];
|
$chartData[$names[$accountId]] = $amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// also collect others?
|
// also collect others?
|
||||||
@@ -149,12 +167,12 @@ class CategoryReportController extends Controller
|
|||||||
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT]);
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT]);
|
||||||
$journals = $collector->getJournals();
|
$journals = $collector->getJournals();
|
||||||
$sum = strval($journals->sum('transaction_amount'));
|
$sum = strval($journals->sum('transaction_amount'));
|
||||||
Log::debug(sprintf('Sum of others in accountIncome is %f', $sum));
|
|
||||||
$sum = bcsub($sum, $total);
|
$sum = bcsub($sum, $total);
|
||||||
$result[] = ['name' => trans('firefly.everything_else'), 'id' => 0, 'amount' => $sum];
|
$chartData[strval(trans('firefly.everything_else'))] = $sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->pieChart($result);
|
$data = $this->generator->pieChart($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
@@ -172,15 +190,23 @@ class CategoryReportController extends Controller
|
|||||||
{
|
{
|
||||||
/** @var bool $others */
|
/** @var bool $others */
|
||||||
$others = intval($others) === 1;
|
$others = intval($others) === 1;
|
||||||
$names = [];
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('chart.category.report.category-expense');
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($categories);
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($others);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get());
|
||||||
|
}
|
||||||
|
|
||||||
// collect journals (just like the category report does):
|
$names = [];
|
||||||
$set = $this->getExpenses($accounts, $categories, $start, $end);
|
$set = $this->getExpenses($accounts, $categories, $start, $end);
|
||||||
$grouped = $this->groupByCategory($set);
|
$grouped = $this->groupByCategory($set);
|
||||||
|
|
||||||
// show the grouped results:
|
|
||||||
$result = [];
|
|
||||||
$total = '0';
|
$total = '0';
|
||||||
|
$chartData = [];
|
||||||
|
|
||||||
foreach ($grouped as $categoryId => $amount) {
|
foreach ($grouped as $categoryId => $amount) {
|
||||||
if (!isset($names[$categoryId])) {
|
if (!isset($names[$categoryId])) {
|
||||||
$category = $this->categoryRepository->find(intval($categoryId));
|
$category = $this->categoryRepository->find(intval($categoryId));
|
||||||
@@ -188,7 +214,7 @@ class CategoryReportController extends Controller
|
|||||||
}
|
}
|
||||||
$amount = bcmul($amount, '-1');
|
$amount = bcmul($amount, '-1');
|
||||||
$total = bcadd($total, $amount);
|
$total = bcadd($total, $amount);
|
||||||
$result[] = ['name' => $names[$categoryId], 'id' => $categoryId, 'amount' => $amount];
|
$chartData[$names[$categoryId]] = $amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// also collect all transactions NOT in these categories.
|
// also collect all transactions NOT in these categories.
|
||||||
@@ -198,12 +224,12 @@ class CategoryReportController extends Controller
|
|||||||
$journals = $collector->getJournals();
|
$journals = $collector->getJournals();
|
||||||
$sum = strval($journals->sum('transaction_amount'));
|
$sum = strval($journals->sum('transaction_amount'));
|
||||||
$sum = bcmul($sum, '-1');
|
$sum = bcmul($sum, '-1');
|
||||||
Log::debug(sprintf('Sum of others in categoryExpense is %f', $sum));
|
|
||||||
$sum = bcsub($sum, $total);
|
$sum = bcsub($sum, $total);
|
||||||
$result[] = ['name' => trans('firefly.everything_else'), 'id' => 0, 'amount' => $sum];
|
$chartData[strval(trans('firefly.everything_else'))] = $sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->pieChart($result);
|
$data = $this->generator->pieChart($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
@@ -221,36 +247,43 @@ class CategoryReportController extends Controller
|
|||||||
{
|
{
|
||||||
/** @var bool $others */
|
/** @var bool $others */
|
||||||
$others = intval($others) === 1;
|
$others = intval($others) === 1;
|
||||||
$names = [];
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('chart.category.report.category-income');
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($categories);
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($others);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return Response::json($cache->get());
|
||||||
|
}
|
||||||
|
|
||||||
// collect journals (just like the category report does):
|
$names = [];
|
||||||
$set = $this->getIncome($accounts, $categories, $start, $end);
|
$set = $this->getIncome($accounts, $categories, $start, $end);
|
||||||
$grouped = $this->groupByCategory($set);
|
$grouped = $this->groupByCategory($set);
|
||||||
|
|
||||||
// loop and show the grouped results:
|
|
||||||
$result = [];
|
|
||||||
$total = '0';
|
$total = '0';
|
||||||
|
$chartData = [];
|
||||||
|
|
||||||
foreach ($grouped as $categoryId => $amount) {
|
foreach ($grouped as $categoryId => $amount) {
|
||||||
if (!isset($names[$categoryId])) {
|
if (!isset($names[$categoryId])) {
|
||||||
$category = $this->categoryRepository->find(intval($categoryId));
|
$category = $this->categoryRepository->find(intval($categoryId));
|
||||||
$names[$categoryId] = $category->name;
|
$names[$categoryId] = $category->name;
|
||||||
}
|
}
|
||||||
$total = bcadd($total, $amount);
|
$total = bcadd($total, $amount);
|
||||||
$result[] = ['name' => $names[$categoryId], 'id' => $categoryId, 'amount' => $amount];
|
$chartData[$names[$categoryId]] = $amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// also collect others?
|
|
||||||
if ($others) {
|
if ($others) {
|
||||||
$collector = new JournalCollector(auth()->user());
|
$collector = new JournalCollector(auth()->user());
|
||||||
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT]);
|
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT]);
|
||||||
$journals = $collector->getJournals();
|
$journals = $collector->getJournals();
|
||||||
$sum = strval($journals->sum('transaction_amount'));
|
$sum = strval($journals->sum('transaction_amount'));
|
||||||
Log::debug(sprintf('Sum of others in categoryIncome is %f', $sum));
|
|
||||||
$sum = bcsub($sum, $total);
|
$sum = bcsub($sum, $total);
|
||||||
$result[] = ['name' => trans('firefly.everything_else'), 'id' => 0, 'amount' => $sum];
|
$chartData[strval(trans('firefly.everything_else'))] = $sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->pieChart($result);
|
$data = $this->generator->pieChart($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
@@ -265,52 +298,98 @@ class CategoryReportController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function mainChart(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
|
public function mainChart(Collection $accounts, Collection $categories, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
// determin optimal period:
|
$cache = new CacheProperties;
|
||||||
$period = '1D';
|
$cache->addProperty('chart.category.report.main');
|
||||||
$format = 'month_and_day';
|
$cache->addProperty($accounts);
|
||||||
$function = 'endOfDay';
|
$cache->addProperty($categories);
|
||||||
if ($start->diffInMonths($end) > 1) {
|
$cache->addProperty($start);
|
||||||
$period = '1M';
|
$cache->addProperty($end);
|
||||||
$format = 'month';
|
if ($cache->has()) {
|
||||||
$function = 'endOfMonth';
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
if ($start->diffInMonths($end) > 13) {
|
|
||||||
$period = '1Y';
|
$format = Navigation::preferredCarbonLocalizedFormat($start, $end);
|
||||||
$format = 'year';
|
$function = Navigation::preferredEndOfPeriod($start, $end);
|
||||||
$function = 'endOfYear';
|
$chartData = [];
|
||||||
}
|
|
||||||
Log::debug(sprintf('Period is %s', $period));
|
|
||||||
$data = [];
|
|
||||||
$currentStart = clone $start;
|
$currentStart = clone $start;
|
||||||
|
|
||||||
|
// prep chart data:
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
$chartData[$category->id . '-in'] = [
|
||||||
|
'label' => $category->name . ' (' . strtolower(strval(trans('firefly.income'))) . ')',
|
||||||
|
'type' => 'bar',
|
||||||
|
'yAxisID' => 'y-axis-0',
|
||||||
|
'entries' => [],
|
||||||
|
];
|
||||||
|
$chartData[$category->id . '-out'] = [
|
||||||
|
'label' => $category->name . ' (' . strtolower(strval(trans('firefly.expenses'))) . ')',
|
||||||
|
'type' => 'bar',
|
||||||
|
'yAxisID' => 'y-axis-0',
|
||||||
|
'entries' => [],
|
||||||
|
];
|
||||||
|
// total in, total out:
|
||||||
|
$chartData[$category->id . '-total-in'] = [
|
||||||
|
'label' => $category->name . ' (' . strtolower(strval(trans('firefly.sum_of_income'))) . ')',
|
||||||
|
'type' => 'line',
|
||||||
|
'fill' => false,
|
||||||
|
'yAxisID' => 'y-axis-1',
|
||||||
|
'entries' => [],
|
||||||
|
];
|
||||||
|
$chartData[$category->id . '-total-out'] = [
|
||||||
|
'label' => $category->name . ' (' . strtolower(strval(trans('firefly.sum_of_expenses'))) . ')',
|
||||||
|
'type' => 'line',
|
||||||
|
'fill' => false,
|
||||||
|
'yAxisID' => 'y-axis-1',
|
||||||
|
'entries' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$sumOfIncome = [];
|
||||||
|
$sumOfExpense = [];
|
||||||
|
|
||||||
while ($currentStart < $end) {
|
while ($currentStart < $end) {
|
||||||
$currentEnd = clone $currentStart;
|
$currentEnd = clone $currentStart;
|
||||||
Log::debug(sprintf('Function is %s', $function));
|
|
||||||
$currentEnd = $currentEnd->$function();
|
$currentEnd = $currentEnd->$function();
|
||||||
$expenses = $this->groupByCategory($this->getExpenses($accounts, $categories, $currentStart, $currentEnd));
|
$expenses = $this->groupByCategory($this->getExpenses($accounts, $categories, $currentStart, $currentEnd));
|
||||||
$income = $this->groupByCategory($this->getIncome($accounts, $categories, $currentStart, $currentEnd));
|
$income = $this->groupByCategory($this->getIncome($accounts, $categories, $currentStart, $currentEnd));
|
||||||
$label = $currentStart->formatLocalized(strval(trans('config.' . $format)));
|
$label = $currentStart->formatLocalized($format);
|
||||||
|
|
||||||
Log::debug(sprintf('Now grabbing CMC expenses between %s and %s', $currentStart->format('Y-m-d'), $currentEnd->format('Y-m-d')));
|
|
||||||
|
|
||||||
$data[$label] = [
|
|
||||||
'in' => [],
|
|
||||||
'out' => [],
|
|
||||||
];
|
|
||||||
|
|
||||||
/** @var Category $category */
|
/** @var Category $category */
|
||||||
foreach ($categories as $category) {
|
foreach ($categories as $category) {
|
||||||
// get sum, and get label:
|
$labelIn = $category->id . '-in';
|
||||||
$categoryId = $category->id;
|
$labelOut = $category->id . '-out';
|
||||||
$data[$label]['name'][$categoryId] = $category->name;
|
$labelSumIn = $category->id . '-total-in';
|
||||||
$data[$label]['in'][$categoryId] = $income[$categoryId] ?? '0';
|
$labelSumOut = $category->id . '-total-out';
|
||||||
$data[$label]['out'][$categoryId] = $expenses[$categoryId] ?? '0';
|
$currentIncome = $income[$category->id] ?? '0';
|
||||||
}
|
$currentExpense = $expenses[$category->id] ?? '0';
|
||||||
|
|
||||||
|
|
||||||
|
// add to sum:
|
||||||
|
$sumOfIncome[$category->id] = $sumOfIncome[$category->id] ?? '0';
|
||||||
|
$sumOfExpense[$category->id] = $sumOfExpense[$category->id] ?? '0';
|
||||||
|
$sumOfIncome[$category->id] = bcadd($sumOfIncome[$category->id], $currentIncome);
|
||||||
|
$sumOfExpense[$category->id] = bcadd($sumOfExpense[$category->id], $currentExpense);
|
||||||
|
|
||||||
|
// add to chart:
|
||||||
|
$chartData[$labelIn]['entries'][$label] = $currentIncome;
|
||||||
|
$chartData[$labelOut]['entries'][$label] = $currentExpense;
|
||||||
|
$chartData[$labelSumIn]['entries'][$label] = $sumOfIncome[$category->id];
|
||||||
|
$chartData[$labelSumOut]['entries'][$label] = $sumOfExpense[$category->id];
|
||||||
|
}
|
||||||
$currentStart = clone $currentEnd;
|
$currentStart = clone $currentEnd;
|
||||||
$currentStart->addDay();
|
$currentStart->addDay();
|
||||||
}
|
}
|
||||||
|
// remove all empty entries to prevent cluttering:
|
||||||
$data = $this->generator->mainReportChart($data);
|
$newSet = [];
|
||||||
|
foreach ($chartData as $key => $entry) {
|
||||||
|
if (!array_sum($entry['entries']) == 0) {
|
||||||
|
$newSet[$key] = $chartData[$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count($newSet) === 0) {
|
||||||
|
$newSet = $chartData;
|
||||||
|
}
|
||||||
|
$data = $this->generator->multiSet($newSet);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,12 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace FireflyIII\Http\Controllers\Chart;
|
namespace FireflyIII\Http\Controllers\Chart;
|
||||||
|
|
||||||
use FireflyIII\Generator\Chart\PiggyBank\PiggyBankChartGeneratorInterface;
|
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\PiggyBank;
|
use FireflyIII\Models\PiggyBank;
|
||||||
use FireflyIII\Models\PiggyBankEvent;
|
use FireflyIII\Models\PiggyBankEvent;
|
||||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Response;
|
use Response;
|
||||||
|
|
||||||
|
|
||||||
@@ -31,7 +30,7 @@ use Response;
|
|||||||
class PiggyBankController extends Controller
|
class PiggyBankController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
/** @var PiggyBankChartGeneratorInterface */
|
/** @var GeneratorInterface */
|
||||||
protected $generator;
|
protected $generator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,7 +40,7 @@ class PiggyBankController extends Controller
|
|||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
// create chart generator:
|
// create chart generator:
|
||||||
$this->generator = app(PiggyBankChartGeneratorInterface::class);
|
$this->generator = app(GeneratorInterface::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +55,7 @@ class PiggyBankController extends Controller
|
|||||||
{
|
{
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty('piggy-history');
|
$cache->addProperty('chart.piggy-bank.history');
|
||||||
$cache->addProperty($piggyBank->id);
|
$cache->addProperty($piggyBank->id);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
@@ -64,18 +63,16 @@ class PiggyBankController extends Controller
|
|||||||
|
|
||||||
$set = $repository->getEvents($piggyBank);
|
$set = $repository->getEvents($piggyBank);
|
||||||
$set = $set->reverse();
|
$set = $set->reverse();
|
||||||
$collection = [];
|
$chartData = [];
|
||||||
|
$sum = '0';
|
||||||
/** @var PiggyBankEvent $entry */
|
/** @var PiggyBankEvent $entry */
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
$date = $entry->date->format('Y-m-d');
|
$label = $entry->date->formatLocalized(strval(trans('config.month_and_day')));
|
||||||
$amount = $entry->amount;
|
$sum = bcadd($sum, $entry->amount);
|
||||||
if (isset($collection[$date])) {
|
$chartData[$label] = $sum;
|
||||||
$amount = bcadd($amount, $collection[$date]);
|
|
||||||
}
|
|
||||||
$collection[$date] = $amount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->generator->history(new Collection($collection));
|
$data = $this->generator->singleSet($piggyBank->name, $chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace FireflyIII\Http\Controllers\Chart;
|
|||||||
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Generator\Chart\Report\ReportChartGeneratorInterface;
|
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Repositories\Account\AccountTaskerInterface;
|
use FireflyIII\Repositories\Account\AccountTaskerInterface;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
@@ -32,7 +32,7 @@ use Steam;
|
|||||||
class ReportController extends Controller
|
class ReportController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
/** @var ReportChartGeneratorInterface */
|
/** @var GeneratorInterface */
|
||||||
protected $generator;
|
protected $generator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +42,7 @@ class ReportController extends Controller
|
|||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
// create chart generator:
|
// create chart generator:
|
||||||
$this->generator = app(ReportChartGeneratorInterface::class);
|
$this->generator = app(GeneratorInterface::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,13 +52,14 @@ class ReportController extends Controller
|
|||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
|
*
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function netWorth(Collection $accounts, Carbon $start, Carbon $end)
|
public function netWorth(Collection $accounts, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty('netWorth');
|
$cache->addProperty('chart.report.net-worth');
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($accounts);
|
$cache->addProperty($accounts);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
@@ -67,21 +68,16 @@ class ReportController extends Controller
|
|||||||
}
|
}
|
||||||
$ids = $accounts->pluck('id')->toArray();
|
$ids = $accounts->pluck('id')->toArray();
|
||||||
$current = clone $start;
|
$current = clone $start;
|
||||||
$entries = new Collection;
|
$chartData = [];
|
||||||
while ($current < $end) {
|
while ($current < $end) {
|
||||||
$balances = Steam::balancesById($ids, $current);
|
$balances = Steam::balancesById($ids, $current);
|
||||||
$sum = $this->arraySum($balances);
|
$sum = $this->arraySum($balances);
|
||||||
$entries->push(
|
$label = $current->formatLocalized(strval(trans('config.month_and_day')));
|
||||||
[
|
$chartData[$label] = $sum;
|
||||||
'date' => clone $current,
|
|
||||||
'net-worth' => $sum,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
$current->addDays(7);
|
$current->addDays(7);
|
||||||
}
|
}
|
||||||
$data = $this->generator->netWorth($entries);
|
|
||||||
|
|
||||||
|
$data = $this->generator->singleSet(strval(trans('firefly.net_worth')), $chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
@@ -102,35 +98,52 @@ class ReportController extends Controller
|
|||||||
{
|
{
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty('yearInOut');
|
$cache->addProperty('chart.report.operations');
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($accounts);
|
$cache->addProperty($accounts);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
|
$format = Navigation::preferredCarbonLocalizedFormat($start, $end);
|
||||||
|
$source = $this->getChartData($accounts, $start, $end);
|
||||||
|
$chartData = [
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.income'),
|
||||||
|
'type' => 'bar',
|
||||||
|
'entries' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.expenses'),
|
||||||
|
'type' => 'bar',
|
||||||
|
'entries' => [],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
$chartSource = $this->getYearData($accounts, $start, $end);
|
foreach ($source['earned'] as $date => $amount) {
|
||||||
|
$carbon = new Carbon($date);
|
||||||
if ($start->diffInMonths($end) > 12) {
|
$label = $carbon->formatLocalized($format);
|
||||||
// data = method X
|
$earned = $chartData[0]['entries'][$label] ?? '0';
|
||||||
$data = $this->multiYearOperations($chartSource['earned'], $chartSource['spent'], $start, $end);
|
$chartData[0]['entries'][$label] = bcadd($earned, $amount);
|
||||||
$cache->store($data);
|
}
|
||||||
|
foreach ($source['spent'] as $date => $amount) {
|
||||||
return Response::json($data);
|
$carbon = new Carbon($date);
|
||||||
|
$label = $carbon->formatLocalized($format);
|
||||||
|
$spent = $chartData[1]['entries'][$label] ?? '0';
|
||||||
|
$chartData[1]['entries'][$label] = bcadd($spent, $amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// data = method Y
|
|
||||||
$data = $this->singleYearOperations($chartSource['earned'], $chartSource['spent'], $start, $end);
|
$data = $this->generator->multiSet($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows sum income and expense, debet/credit: operations
|
* Shows sum income and expense, debet/credit: operations
|
||||||
|
*
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
@@ -140,162 +153,67 @@ class ReportController extends Controller
|
|||||||
public function sum(Collection $accounts, Carbon $start, Carbon $end)
|
public function sum(Collection $accounts, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// chart properties for cache:
|
// chart properties for cache:
|
||||||
$cache = new CacheProperties;
|
$cache = new CacheProperties;
|
||||||
$cache->addProperty('yearInOutSummarized');
|
$cache->addProperty('chart.report.sum');
|
||||||
$cache->addProperty($start);
|
$cache->addProperty($start);
|
||||||
$cache->addProperty($end);
|
$cache->addProperty($end);
|
||||||
$cache->addProperty($accounts);
|
$cache->addProperty($accounts);
|
||||||
if ($cache->has()) {
|
if ($cache->has()) {
|
||||||
return Response::json($cache->get());
|
return Response::json($cache->get());
|
||||||
}
|
}
|
||||||
$chartSource = $this->getYearData($accounts, $start, $end);
|
$source = $this->getChartData($accounts, $start, $end);
|
||||||
|
$numbers = [
|
||||||
if ($start->diffInMonths($end) > 12) {
|
'sum_earned' => '0',
|
||||||
// per year
|
'avg_earned' => '0',
|
||||||
$data = $this->multiYearSum($chartSource['earned'], $chartSource['spent'], $start, $end);
|
'count_earned' => 0,
|
||||||
$cache->store($data);
|
'sum_spent' => '0',
|
||||||
|
'avg_spent' => '0',
|
||||||
return Response::json($data);
|
'count_spent' => 0,
|
||||||
|
];
|
||||||
|
foreach ($source['earned'] as $amount) {
|
||||||
|
$numbers['sum_earned'] = bcadd($amount, $numbers['sum_earned']);
|
||||||
|
$numbers['count_earned']++;
|
||||||
}
|
}
|
||||||
// per month!
|
if ($numbers['count_earned'] > 0) {
|
||||||
$data = $this->singleYearSum($chartSource['earned'], $chartSource['spent'], $start, $end);
|
$numbers['avg_earned'] = $numbers['sum_earned'] / $numbers['count_earned'];
|
||||||
|
}
|
||||||
|
foreach ($source['spent'] as $amount) {
|
||||||
|
$numbers['sum_spent'] = bcadd($amount, $numbers['sum_spent']);
|
||||||
|
$numbers['count_spent']++;
|
||||||
|
}
|
||||||
|
if ($numbers['count_spent'] > 0) {
|
||||||
|
$numbers['avg_spent'] = $numbers['sum_spent'] / $numbers['count_spent'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$chartData = [
|
||||||
|
[
|
||||||
|
'label' => strval(trans('firefly.income')),
|
||||||
|
'type' => 'bar',
|
||||||
|
'entries' => [
|
||||||
|
strval(trans('firefly.sum_of_period')) => $numbers['sum_earned'],
|
||||||
|
strval(trans('firefly.average_in_period')) => $numbers['avg_earned'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.expenses'),
|
||||||
|
'type' => 'bar',
|
||||||
|
'entries' => [
|
||||||
|
strval(trans('firefly.sum_of_period')) => $numbers['sum_spent'],
|
||||||
|
strval(trans('firefly.average_in_period')) => $numbers['avg_spent'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$data = $this->generator->multiSet($chartData);
|
||||||
$cache->store($data);
|
$cache->store($data);
|
||||||
|
|
||||||
return Response::json($data);
|
return Response::json($data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $earned
|
|
||||||
* @param array $spent
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function multiYearOperations(array $earned, array $spent, Carbon $start, Carbon $end)
|
|
||||||
{
|
|
||||||
$entries = new Collection;
|
|
||||||
while ($start < $end) {
|
|
||||||
|
|
||||||
$incomeSum = $this->pluckFromArray($start->year, $earned);
|
|
||||||
$expenseSum = $this->pluckFromArray($start->year, $spent);
|
|
||||||
|
|
||||||
$entries->push([clone $start, $incomeSum, $expenseSum]);
|
|
||||||
$start->addYear();
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->generator->multiYearOperations($entries);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $earned
|
|
||||||
* @param array $spent
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function multiYearSum(array $earned, array $spent, Carbon $start, Carbon $end)
|
|
||||||
{
|
|
||||||
$income = '0';
|
|
||||||
$expense = '0';
|
|
||||||
$count = 0;
|
|
||||||
while ($start < $end) {
|
|
||||||
|
|
||||||
$currentIncome = $this->pluckFromArray($start->year, $earned);
|
|
||||||
$currentExpense = $this->pluckFromArray($start->year, $spent);
|
|
||||||
$income = bcadd($income, $currentIncome);
|
|
||||||
$expense = bcadd($expense, $currentExpense);
|
|
||||||
|
|
||||||
$count++;
|
|
||||||
$start->addYear();
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->generator->multiYearSum($income, $expense, $count);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $year
|
|
||||||
* @param array $set
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function pluckFromArray($year, array $set)
|
|
||||||
{
|
|
||||||
$sum = '0';
|
|
||||||
foreach ($set as $date => $amount) {
|
|
||||||
if (substr($date, 0, 4) == $year) {
|
|
||||||
$sum = bcadd($sum, $amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sum;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $earned
|
|
||||||
* @param array $spent
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function singleYearOperations(array $earned, array $spent, Carbon $start, Carbon $end)
|
|
||||||
{
|
|
||||||
// per month? simply use each month.
|
|
||||||
|
|
||||||
$entries = new Collection;
|
|
||||||
while ($start < $end) {
|
|
||||||
// total income and total expenses:
|
|
||||||
$date = $start->format('Y-m');
|
|
||||||
$incomeSum = isset($earned[$date]) ? $earned[$date] : 0;
|
|
||||||
$expenseSum = isset($spent[$date]) ? $spent[$date] : 0;
|
|
||||||
|
|
||||||
$entries->push([clone $start, $incomeSum, $expenseSum]);
|
|
||||||
$start->addMonth();
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->generator->yearOperations($entries);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $earned
|
|
||||||
* @param array $spent
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function singleYearSum(array $earned, array $spent, Carbon $start, Carbon $end)
|
|
||||||
{
|
|
||||||
$income = '0';
|
|
||||||
$expense = '0';
|
|
||||||
$count = 0;
|
|
||||||
while ($start < $end) {
|
|
||||||
$date = $start->format('Y-m');
|
|
||||||
$currentIncome = isset($earned[$date]) ? $earned[$date] : 0;
|
|
||||||
$currentExpense = isset($spent[$date]) ? $spent[$date] : 0;
|
|
||||||
$income = bcadd($income, $currentIncome);
|
|
||||||
$expense = bcadd($expense, $currentExpense);
|
|
||||||
|
|
||||||
$count++;
|
|
||||||
$start->addMonth();
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->generator->yearSum($income, $expense, $count);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $array
|
* @param $array
|
||||||
*
|
*
|
||||||
@@ -312,31 +230,45 @@ class ReportController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Collects the incomes and expenses for the given periods, grouped per month. Will cache its results
|
||||||
|
*
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function getYearData(Collection $accounts, Carbon $start, Carbon $end): array
|
private function getChartData(Collection $accounts, Carbon $start, Carbon $end): array
|
||||||
{
|
{
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('chart.report.get-chart-data');
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$tasker = app(AccountTaskerInterface::class);
|
$tasker = app(AccountTaskerInterface::class);
|
||||||
$currentStart = clone $start;
|
$currentStart = clone $start;
|
||||||
$spentArray = [];
|
$spentArray = [];
|
||||||
$earnedArray = [];
|
$earnedArray = [];
|
||||||
while ($currentStart <= $end) {
|
while ($currentStart <= $end) {
|
||||||
$currentEnd = Navigation::endOfPeriod($currentStart, '1M');
|
$currentEnd = Navigation::endOfPeriod($currentStart, '1M');
|
||||||
$date = $currentStart->format('Y-m');
|
$label = $currentStart->format('Y-m') . '-01';
|
||||||
$spent = $tasker->amountOutInPeriod($accounts, $accounts, $currentStart, $currentEnd);
|
$spent = $tasker->amountOutInPeriod($accounts, $accounts, $currentStart, $currentEnd);
|
||||||
$earned = $tasker->amountInInPeriod($accounts, $accounts, $currentStart, $currentEnd);
|
$earned = $tasker->amountInInPeriod($accounts, $accounts, $currentStart, $currentEnd);
|
||||||
$spentArray[$date] = bcmul($spent, '-1');
|
$spentArray[$label] = bcmul($spent, '-1');
|
||||||
$earnedArray[$date] = $earned;
|
$earnedArray[$label] = $earned;
|
||||||
$currentStart = Navigation::addPeriod($currentStart, '1M', 0);
|
$currentStart = Navigation::addPeriod($currentStart, '1M', 0);
|
||||||
}
|
}
|
||||||
|
$result = [
|
||||||
return [
|
|
||||||
'spent' => $spentArray,
|
'spent' => $spentArray,
|
||||||
'earned' => $earnedArray,
|
'earned' => $earnedArray,
|
||||||
];
|
];
|
||||||
|
$cache->store($result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
app/Http/Controllers/Controller.php
Executable file → Normal file
6
app/Http/Controllers/Controller.php
Executable file → Normal file
@@ -23,6 +23,7 @@ use Illuminate\Foundation\Validation\ValidatesRequests;
|
|||||||
use Illuminate\Routing\Controller as BaseController;
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
use Session;
|
use Session;
|
||||||
use View;
|
use View;
|
||||||
|
use FireflyConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Controller
|
* Class Controller
|
||||||
@@ -49,7 +50,10 @@ class Controller extends BaseController
|
|||||||
View::share('hideCategories', false);
|
View::share('hideCategories', false);
|
||||||
View::share('hideBills', false);
|
View::share('hideBills', false);
|
||||||
View::share('hideTags', false);
|
View::share('hideTags', false);
|
||||||
|
$isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data;
|
||||||
|
View::share('IS_DEMO_SITE', $isDemoSite);
|
||||||
|
View::share('DEMO_USERNAME', env('DEMO_USERNAME',''));
|
||||||
|
View::share('DEMO_PASSWORD', env('DEMO_PASSWORD',''));
|
||||||
|
|
||||||
// translations:
|
// translations:
|
||||||
|
|
||||||
|
|||||||
@@ -89,14 +89,16 @@ class CurrencyController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param CurrencyRepositoryInterface $repository
|
||||||
* @param TransactionCurrency $currency
|
* @param TransactionCurrency $currency
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\RedirectResponse|View
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||||
*/
|
*/
|
||||||
public function delete(TransactionCurrency $currency)
|
public function delete(CurrencyRepositoryInterface $repository, TransactionCurrency $currency)
|
||||||
{
|
{
|
||||||
if (!$this->canDeleteCurrency($currency)) {
|
if (!$repository->canDeleteCurrency($currency)) {
|
||||||
Session::flash('error', trans('firefly.cannot_delete_currency', ['name' => $currency->name]));
|
Session::flash('error', trans('firefly.cannot_delete_currency', ['name' => $currency->name]));
|
||||||
|
|
||||||
return redirect(route('currencies.index'));
|
return redirect(route('currencies.index'));
|
||||||
@@ -114,23 +116,21 @@ class CurrencyController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param CurrencyRepositoryInterface $repository
|
||||||
* @param TransactionCurrency $currency
|
* @param TransactionCurrency $currency
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
* @throws \Exception
|
|
||||||
*/
|
*/
|
||||||
public function destroy(TransactionCurrency $currency)
|
public function destroy(CurrencyRepositoryInterface $repository, TransactionCurrency $currency)
|
||||||
{
|
{
|
||||||
if (!$this->canDeleteCurrency($currency)) {
|
if (!$repository->canDeleteCurrency($currency)) {
|
||||||
Session::flash('error', trans('firefly.cannot_delete_currency', ['name' => $currency->name]));
|
Session::flash('error', trans('firefly.cannot_delete_currency', ['name' => $currency->name]));
|
||||||
|
|
||||||
return redirect(route('currencies.index'));
|
return redirect(route('currencies.index'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$repository->destroy($currency);
|
||||||
Session::flash('success', trans('firefly.deleted_currency', ['name' => $currency->name]));
|
Session::flash('success', trans('firefly.deleted_currency', ['name' => $currency->name]));
|
||||||
if (auth()->user()->hasRole('owner')) {
|
|
||||||
$currency->forceDelete();
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect(session('currencies.delete.url'));
|
return redirect(session('currencies.delete.url'));
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,7 @@ class CurrencyController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
if (!auth()->user()->hasRole('owner')) {
|
if (!auth()->user()->hasRole('owner')) {
|
||||||
Session::flash('warning', trans('firefly.ask_site_owner', ['owner' => env('SITE_OWNER')]));
|
Session::flash('warning', trans('firefly.ask_site_owner', ['site_owner' => env('SITE_OWNER')]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -235,40 +235,4 @@ class CurrencyController extends Controller
|
|||||||
return redirect(session('currencies.edit.url'));
|
return redirect(session('currencies.edit.url'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param TransactionCurrency $currency
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function canDeleteCurrency(TransactionCurrency $currency): bool
|
|
||||||
{
|
|
||||||
$repository = app(CurrencyRepositoryInterface::class);
|
|
||||||
|
|
||||||
// has transactions still
|
|
||||||
if ($repository->countJournals($currency) > 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// is the only currency left
|
|
||||||
if ($repository->get()->count() === 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// is the default currency for the user or the system
|
|
||||||
$defaultCode = Preferences::get('currencyPreference', config('firefly.default_currency', 'EUR'))->data;
|
|
||||||
if ($currency->code === $defaultCode) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// is the default currency for the system
|
|
||||||
$defaultSystemCode = config('firefly.default_currency', 'EUR');
|
|
||||||
if ($currency->code === $defaultSystemCode) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// can be deleted
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,12 @@ namespace FireflyIII\Http\Controllers;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use ExpandedForm;
|
use ExpandedForm;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Export\Processor;
|
use FireflyIII\Export\ProcessorInterface;
|
||||||
use FireflyIII\Http\Requests\ExportFormRequest;
|
use FireflyIII\Http\Requests\ExportFormRequest;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Models\ExportJob;
|
use FireflyIII\Models\ExportJob;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\ExportJob\ExportJobRepositoryInterface;
|
||||||
use FireflyIII\Repositories\ExportJob\ExportJobRepositoryInterface as EJRI;
|
use FireflyIII\Repositories\ExportJob\ExportJobRepositoryInterface as EJRI;
|
||||||
use Preferences;
|
use Preferences;
|
||||||
use Response;
|
use Response;
|
||||||
@@ -59,22 +60,22 @@ class ExportController extends Controller
|
|||||||
* @return \Symfony\Component\HttpFoundation\Response|\Illuminate\Contracts\Routing\ResponseFactory
|
* @return \Symfony\Component\HttpFoundation\Response|\Illuminate\Contracts\Routing\ResponseFactory
|
||||||
* @throws FireflyException
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
public function download(ExportJob $job)
|
public function download(ExportJobRepositoryInterface $repository, ExportJob $job)
|
||||||
{
|
{
|
||||||
$disk = Storage::disk('export');
|
|
||||||
$file = $job->key . '.zip';
|
$file = $job->key . '.zip';
|
||||||
$date = date('Y-m-d \a\t H-i-s');
|
$date = date('Y-m-d \a\t H-i-s');
|
||||||
$name = 'Export job on ' . $date . '.zip';
|
$name = 'Export job on ' . $date . '.zip';
|
||||||
$quoted = sprintf('"%s"', addcslashes($name, '"\\'));
|
$quoted = sprintf('"%s"', addcslashes($name, '"\\'));
|
||||||
|
|
||||||
if (!$disk->exists($file)) {
|
if (!$repository->exists($job)) {
|
||||||
throw new FireflyException('Against all expectations, zip file "' . $file . '" does not exist.');
|
throw new FireflyException('Against all expectations, zip file "' . $file . '" does not exist.');
|
||||||
}
|
}
|
||||||
|
$content = $repository->getContent($job);
|
||||||
|
|
||||||
|
|
||||||
$job->change('export_downloaded');
|
$job->change('export_downloaded');
|
||||||
|
|
||||||
return response($disk->get($file), 200)
|
return response($content, 200)
|
||||||
->header('Content-Description', 'File Transfer')
|
->header('Content-Description', 'File Transfer')
|
||||||
->header('Content-Type', 'application/octet-stream')
|
->header('Content-Type', 'application/octet-stream')
|
||||||
->header('Content-Disposition', 'attachment; filename=' . $quoted)
|
->header('Content-Disposition', 'attachment; filename=' . $quoted)
|
||||||
@@ -83,7 +84,7 @@ class ExportController extends Controller
|
|||||||
->header('Expires', '0')
|
->header('Expires', '0')
|
||||||
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
|
||||||
->header('Pragma', 'public')
|
->header('Pragma', 'public')
|
||||||
->header('Content-Length', $disk->size($file));
|
->header('Content-Length', strlen($content));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +134,6 @@ class ExportController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function postIndex(ExportFormRequest $request, AccountRepositoryInterface $repository, EJRI $jobs)
|
public function postIndex(ExportFormRequest $request, AccountRepositoryInterface $repository, EJRI $jobs)
|
||||||
{
|
{
|
||||||
set_time_limit(0);
|
|
||||||
$job = $jobs->findByKey($request->get('job'));
|
$job = $jobs->findByKey($request->get('job'));
|
||||||
$settings = [
|
$settings = [
|
||||||
'accounts' => $repository->getAccountsById($request->get('accounts')),
|
'accounts' => $repository->getAccountsById($request->get('accounts')),
|
||||||
@@ -146,7 +146,9 @@ class ExportController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
$job->change('export_status_make_exporter');
|
$job->change('export_status_make_exporter');
|
||||||
$processor = new Processor($settings);
|
|
||||||
|
/** @var ProcessorInterface $processor */
|
||||||
|
$processor = app(ProcessorInterface::class, [$settings]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Collect journals:
|
* Collect journals:
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class HomeController extends Controller
|
|||||||
// a possible problem with the budgets.
|
// a possible problem with the budgets.
|
||||||
if ($label === strval(trans('firefly.everything')) || $label === strval(trans('firefly.customRange'))) {
|
if ($label === strval(trans('firefly.everything')) || $label === strval(trans('firefly.customRange'))) {
|
||||||
$isCustomRange = true;
|
$isCustomRange = true;
|
||||||
|
//Preferences::set('viewRange', 'custom');
|
||||||
Log::debug('Range is now marked as "custom".');
|
Log::debug('Range is now marked as "custom".');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +108,7 @@ class HomeController extends Controller
|
|||||||
$journal->save();
|
$journal->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Session::forget(['start', 'end', 'viewRange', 'range', 'is_custom_range']);
|
||||||
|
|
||||||
Session::clear();
|
Session::clear();
|
||||||
Artisan::call('cache:clear');
|
Artisan::call('cache:clear');
|
||||||
@@ -166,9 +167,51 @@ class HomeController extends Controller
|
|||||||
public function routes()
|
public function routes()
|
||||||
{
|
{
|
||||||
// these routes are not relevant for the help pages:
|
// these routes are not relevant for the help pages:
|
||||||
$ignore = ['login', 'registe', 'logout', 'two-fac', 'lost-two', 'confirm', 'resend', 'do_confirm', 'testFla', 'json.', 'piggy-banks.add',
|
$ignore = [
|
||||||
'piggy-banks.remove', 'preferences.', 'rules.rule.up', 'rules.rule.down', 'rules.rule-group.up', 'rules.rule-group.down', 'popup.report',
|
// login and two-factor routes:
|
||||||
'admin.users.domains.block-', 'import.json', 'help.',
|
'login',
|
||||||
|
'registe',
|
||||||
|
'password.rese',
|
||||||
|
'logout',
|
||||||
|
'two-fac',
|
||||||
|
'lost-two',
|
||||||
|
'confirm',
|
||||||
|
'resend',
|
||||||
|
'do_confirm',
|
||||||
|
// test troutes
|
||||||
|
'test-flash',
|
||||||
|
'all-routes',
|
||||||
|
// json routes
|
||||||
|
'json.',
|
||||||
|
// routes that point to modals or that redirect immediately.
|
||||||
|
'piggy-banks.add',
|
||||||
|
'piggy-banks.remove',
|
||||||
|
'rules.rule.up',
|
||||||
|
'attachments.download',
|
||||||
|
'bills.rescan',
|
||||||
|
'rules.rule.down',
|
||||||
|
'rules.rule-group.up',
|
||||||
|
'rules.rule-group.down',
|
||||||
|
'popup.',
|
||||||
|
'error',
|
||||||
|
'flush',
|
||||||
|
//'preferences.',
|
||||||
|
'admin.users.domains.block-',
|
||||||
|
'help.',
|
||||||
|
// ajax routes:
|
||||||
|
'import.json',
|
||||||
|
// charts:
|
||||||
|
'chart.',
|
||||||
|
// report data:
|
||||||
|
'report-data.',
|
||||||
|
|
||||||
|
// others:
|
||||||
|
'debugbar',
|
||||||
|
'attachments.preview',
|
||||||
|
'budgets.income',
|
||||||
|
'currencies.default',
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
$routes = Route::getRoutes();
|
$routes = Route::getRoutes();
|
||||||
$return = '<pre>';
|
$return = '<pre>';
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace FireflyIII\Http\Controllers;
|
|||||||
use Crypt;
|
use Crypt;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Http\Requests\ImportUploadRequest;
|
use FireflyIII\Http\Requests\ImportUploadRequest;
|
||||||
use FireflyIII\Import\ImportProcedure;
|
use FireflyIII\Import\ImportProcedureInterface;
|
||||||
use FireflyIII\Import\Setup\SetupInterface;
|
use FireflyIII\Import\Setup\SetupInterface;
|
||||||
use FireflyIII\Models\ImportJob;
|
use FireflyIII\Models\ImportJob;
|
||||||
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
|
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
|
||||||
@@ -145,10 +145,13 @@ class ImportController extends Controller
|
|||||||
return $this->redirectToCorrectStep($job);
|
return $this->redirectToCorrectStep($job);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if there is a tag (there might not be), we can link to it:
|
||||||
|
$tagId = $job->extended_status['importTag'] ?? 0;
|
||||||
|
|
||||||
$subTitle = trans('firefly.import_finished');
|
$subTitle = trans('firefly.import_finished');
|
||||||
$subTitleIcon = 'fa-star';
|
$subTitleIcon = 'fa-star';
|
||||||
|
|
||||||
return view('import.finished', compact('job', 'subTitle', 'subTitleIcon'));
|
return view('import.finished', compact('job', 'subTitle', 'subTitleIcon', 'tagId'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -312,13 +315,14 @@ class ImportController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param ImportProcedureInterface $importProcedure
|
||||||
* @param ImportJob $job
|
* @param ImportJob $job
|
||||||
*/
|
*/
|
||||||
public function start(ImportJob $job)
|
public function start(ImportProcedureInterface $importProcedure, ImportJob $job)
|
||||||
{
|
{
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
if ($job->status == 'settings_complete') {
|
if ($job->status == 'settings_complete') {
|
||||||
ImportProcedure::runImport($job);
|
$importProcedure->runImport($job);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +334,7 @@ class ImportController extends Controller
|
|||||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
|
||||||
*/
|
*/
|
||||||
public function status(ImportJob $job)
|
public function status(ImportJob $job)
|
||||||
{
|
{ //
|
||||||
Log::debug('Now in status()', ['job' => $job->key]);
|
Log::debug('Now in status()', ['job' => $job->key]);
|
||||||
if (!$this->jobInCorrectStep($job, 'status')) {
|
if (!$this->jobInCorrectStep($job, 'status')) {
|
||||||
return $this->redirectToCorrectStep($job);
|
return $this->redirectToCorrectStep($job);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ use Illuminate\Support\Collection;
|
|||||||
use Input;
|
use Input;
|
||||||
use Log;
|
use Log;
|
||||||
use Preferences;
|
use Preferences;
|
||||||
|
use Response;
|
||||||
use Session;
|
use Session;
|
||||||
use Steam;
|
use Steam;
|
||||||
use URL;
|
use URL;
|
||||||
@@ -149,13 +150,18 @@ class PiggyBankController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy(PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
|
public function destroy(PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
Session::flash('success', strval(trans('firefly.deleted_piggy_bank', ['name' => e($piggyBank->name)])));
|
Session::flash('success', strval(trans('firefly.deleted_piggy_bank', ['name' => e($piggyBank->name)])));
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
$piggyBankId = $piggyBank->id;
|
||||||
$repository->destroy($piggyBank);
|
$repository->destroy($piggyBank);
|
||||||
|
|
||||||
return redirect(session('piggy-banks.delete.url'));
|
$uri = session('piggy-banks.delete.url');
|
||||||
|
if (!(strpos($uri, sprintf('piggy-banks/show/%s', $piggyBankId)) === false)) {
|
||||||
|
// uri would point back to piggy bank
|
||||||
|
$uri = route('piggy-banks.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect($uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,6 +249,8 @@ class PiggyBankController extends Controller
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param PiggyBankRepositoryInterface $repository
|
* @param PiggyBankRepositoryInterface $repository
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function order(PiggyBankRepositoryInterface $repository)
|
public function order(PiggyBankRepositoryInterface $repository)
|
||||||
{
|
{
|
||||||
@@ -257,6 +265,8 @@ class PiggyBankController extends Controller
|
|||||||
$repository->setOrder(intval($id), ($order + 1));
|
$repository->setOrder(intval($id), ($order + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Response::json(['result' => 'ok']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -133,8 +133,8 @@ class ReportController extends Controller
|
|||||||
|
|
||||||
$budget->name = strval(trans('firefly.leftUnbalanced'));
|
$budget->name = strval(trans('firefly.leftUnbalanced'));
|
||||||
$journals = $journals->filter(
|
$journals = $journals->filter(
|
||||||
function (TransactionJournal $journal) {
|
function (Transaction $transaction) {
|
||||||
$tags = $journal->tags()->where('tagMode', 'balancingAct')->count();
|
$tags = $transaction->transactionJournal->tags()->where('tagMode', 'balancingAct')->count();
|
||||||
if ($tags === 0) {
|
if ($tags === 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ class PreferencesController extends Controller
|
|||||||
|
|
||||||
// custom fiscal year
|
// custom fiscal year
|
||||||
$customFiscalYear = intval($request->get('customFiscalYear')) === 1;
|
$customFiscalYear = intval($request->get('customFiscalYear')) === 1;
|
||||||
$fiscalYearStart = date('m-d', strtotime($request->get('fiscalYearStart')));
|
$fiscalYearStart = date('m-d', strtotime(strval($request->get('fiscalYearStart'))));
|
||||||
Preferences::set('customFiscalYear', $customFiscalYear);
|
Preferences::set('customFiscalYear', $customFiscalYear);
|
||||||
Preferences::set('fiscalYearStart', $fiscalYearStart);
|
Preferences::set('fiscalYearStart', $fiscalYearStart);
|
||||||
|
|
||||||
@@ -166,6 +166,9 @@ class PreferencesController extends Controller
|
|||||||
Preferences::set('transactionPageSize', 50);
|
Preferences::set('transactionPageSize', 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$twoFactorAuthEnabled = false;
|
||||||
|
$hasTwoFactorAuthSecret = false;
|
||||||
|
if (!auth()->user()->hasRole('demo')) {
|
||||||
// two factor auth
|
// two factor auth
|
||||||
$twoFactorAuthEnabled = intval($request->get('twoFactorAuthEnabled'));
|
$twoFactorAuthEnabled = intval($request->get('twoFactorAuthEnabled'));
|
||||||
$hasTwoFactorAuthSecret = !is_null(Preferences::get('twoFactorAuthSecret'));
|
$hasTwoFactorAuthSecret = !is_null(Preferences::get('twoFactorAuthSecret'));
|
||||||
@@ -174,6 +177,7 @@ class PreferencesController extends Controller
|
|||||||
if ($hasTwoFactorAuthSecret) {
|
if ($hasTwoFactorAuthSecret) {
|
||||||
Preferences::set('twoFactorAuthEnabled', $twoFactorAuthEnabled);
|
Preferences::set('twoFactorAuthEnabled', $twoFactorAuthEnabled);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// language:
|
// language:
|
||||||
$lang = $request->get('language');
|
$lang = $request->get('language');
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ namespace FireflyIII\Http\Controllers;
|
|||||||
|
|
||||||
use FireflyIII\Http\Requests\DeleteAccountFormRequest;
|
use FireflyIII\Http\Requests\DeleteAccountFormRequest;
|
||||||
use FireflyIII\Http\Requests\ProfileFormRequest;
|
use FireflyIII\Http\Requests\ProfileFormRequest;
|
||||||
use FireflyIII\User;
|
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||||
use Hash;
|
use Hash;
|
||||||
use Preferences;
|
use Log;
|
||||||
use Session;
|
use Session;
|
||||||
use View;
|
use View;
|
||||||
|
|
||||||
@@ -51,6 +51,12 @@ class ProfileController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function changePassword()
|
public function changePassword()
|
||||||
{
|
{
|
||||||
|
if (auth()->user()->hasRole('demo')) {
|
||||||
|
Session::flash('info', strval(trans('firefly.cannot_change_demo')));
|
||||||
|
|
||||||
|
return redirect(route('profile.index'));
|
||||||
|
}
|
||||||
|
|
||||||
$title = auth()->user()->email;
|
$title = auth()->user()->email;
|
||||||
$subTitle = strval(trans('firefly.change_your_password'));
|
$subTitle = strval(trans('firefly.change_your_password'));
|
||||||
$subTitleIcon = 'fa-key';
|
$subTitleIcon = 'fa-key';
|
||||||
@@ -63,6 +69,12 @@ class ProfileController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function deleteAccount()
|
public function deleteAccount()
|
||||||
{
|
{
|
||||||
|
if (auth()->user()->hasRole('demo')) {
|
||||||
|
Session::flash('info', strval(trans('firefly.cannot_delete_demo')));
|
||||||
|
|
||||||
|
return redirect(route('profile.index'));
|
||||||
|
}
|
||||||
|
|
||||||
$title = auth()->user()->email;
|
$title = auth()->user()->email;
|
||||||
$subTitle = strval(trans('firefly.delete_account'));
|
$subTitle = strval(trans('firefly.delete_account'));
|
||||||
$subTitleIcon = 'fa-trash';
|
$subTitleIcon = 'fa-trash';
|
||||||
@@ -84,11 +96,18 @@ class ProfileController extends Controller
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ProfileFormRequest $request
|
* @param ProfileFormRequest $request
|
||||||
|
* @param UserRepositoryInterface $repository
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
*/
|
*/
|
||||||
public function postChangePassword(ProfileFormRequest $request)
|
public function postChangePassword(ProfileFormRequest $request, UserRepositoryInterface $repository)
|
||||||
{
|
{
|
||||||
|
if (auth()->user()->hasRole('demo')) {
|
||||||
|
Session::flash('info', strval(trans('firefly.cannot_change_demo')));
|
||||||
|
|
||||||
|
return redirect(route('profile.index'));
|
||||||
|
}
|
||||||
|
|
||||||
// old, new1, new2
|
// old, new1, new2
|
||||||
if (!Hash::check($request->get('current_password'), auth()->user()->password)) {
|
if (!Hash::check($request->get('current_password'), auth()->user()->password)) {
|
||||||
Session::flash('error', strval(trans('firefly.invalid_current_password')));
|
Session::flash('error', strval(trans('firefly.invalid_current_password')));
|
||||||
@@ -103,56 +122,42 @@ class ProfileController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update the user with the new password.
|
// update the user with the new password.
|
||||||
auth()->user()->password = bcrypt($request->get('new_password'));
|
$repository->changePassword(auth()->user(), $request->get('new_password'));
|
||||||
auth()->user()->save();
|
|
||||||
|
|
||||||
Session::flash('success', strval(trans('firefly.password_changed')));
|
Session::flash('success', strval(trans('firefly.password_changed')));
|
||||||
|
|
||||||
return redirect(route('profile.index'));
|
return redirect(route('profile.index'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param UserRepositoryInterface $repository
|
||||||
* @param DeleteAccountFormRequest $request
|
* @param DeleteAccountFormRequest $request
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
* @throws \Exception
|
|
||||||
*/
|
*/
|
||||||
public function postDeleteAccount(DeleteAccountFormRequest $request)
|
public function postDeleteAccount(UserRepositoryInterface $repository, DeleteAccountFormRequest $request)
|
||||||
{
|
{
|
||||||
|
if (auth()->user()->hasRole('demo')) {
|
||||||
|
Session::flash('info', strval(trans('firefly.cannot_delete_demo')));
|
||||||
|
|
||||||
|
return redirect(route('profile.index'));
|
||||||
|
}
|
||||||
|
|
||||||
// old, new1, new2
|
// old, new1, new2
|
||||||
if (!Hash::check($request->get('password'), auth()->user()->password)) {
|
if (!Hash::check($request->get('password'), auth()->user()->password)) {
|
||||||
Session::flash('error', strval(trans('firefly.invalid_password')));
|
Session::flash('error', strval(trans('firefly.invalid_password')));
|
||||||
|
|
||||||
return redirect(route('profile.delete-account'));
|
return redirect(route('profile.delete-account'));
|
||||||
}
|
}
|
||||||
|
$user = auth()->user();
|
||||||
// store some stuff for the future:
|
Log::info(sprintf('User #%d has opted to delete their account', auth()->user()->id));
|
||||||
$registration = Preferences::get('registration_ip_address')->data;
|
// make repository delete user:
|
||||||
$confirmation = Preferences::get('confirmation_ip_address')->data;
|
auth()->logout();
|
||||||
|
|
||||||
// DELETE!
|
|
||||||
$email = auth()->user()->email;
|
|
||||||
auth()->user()->delete();
|
|
||||||
Session::flush();
|
Session::flush();
|
||||||
|
$repository->destroy($user);
|
||||||
|
|
||||||
Session::flash('gaEventCategory', 'user');
|
Session::flash('gaEventCategory', 'user');
|
||||||
Session::flash('gaEventAction', 'delete-account');
|
Session::flash('gaEventAction', 'delete-account');
|
||||||
|
|
||||||
// create a new user with the same email address so re-registration is blocked.
|
|
||||||
$newUser = User::create(
|
|
||||||
[
|
|
||||||
'email' => $email,
|
|
||||||
'password' => 'deleted',
|
|
||||||
'blocked' => 1,
|
|
||||||
'blocked_code' => 'deleted',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
if (strlen($registration) > 0) {
|
|
||||||
Preferences::setForUser($newUser, 'registration_ip_address', $registration);
|
|
||||||
|
|
||||||
}
|
|
||||||
if (strlen($confirmation) > 0) {
|
|
||||||
Preferences::setForUser($newUser, 'confirmation_ip_address', $confirmation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect(route('index'));
|
return redirect(route('index'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ namespace FireflyIII\Http\Controllers\Report;
|
|||||||
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\Category;
|
use FireflyIII\Models\Category;
|
||||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||||
@@ -99,12 +98,12 @@ class CategoryController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ReportHelperInterface $helper
|
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
*
|
*
|
||||||
* @return mixed|string
|
* @return mixed|string
|
||||||
|
* @internal param ReportHelperInterface $helper
|
||||||
*/
|
*/
|
||||||
public function operations(Collection $accounts, Carbon $start, Carbon $end)
|
public function operations(Collection $accounts, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ namespace FireflyIII\Http\Controllers\Report;
|
|||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
|
||||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
@@ -57,6 +56,33 @@ class OperationsController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function income(Collection $accounts, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
// chart properties for cache:
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty('income-report');
|
||||||
|
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get();
|
||||||
|
}
|
||||||
|
$income = $this->getIncomeReport($start, $end, $accounts);
|
||||||
|
|
||||||
|
$result = view('reports.partials.income', compact('income'))->render();
|
||||||
|
$cache->store($result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
@@ -101,33 +127,6 @@ class OperationsController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection $accounts
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function income(Collection $accounts, Carbon $start, Carbon $end)
|
|
||||||
{
|
|
||||||
// chart properties for cache:
|
|
||||||
$cache = new CacheProperties;
|
|
||||||
$cache->addProperty($start);
|
|
||||||
$cache->addProperty($end);
|
|
||||||
$cache->addProperty('income-report');
|
|
||||||
$cache->addProperty($accounts->pluck('id')->toArray());
|
|
||||||
if ($cache->has()) {
|
|
||||||
//return $cache->get();
|
|
||||||
}
|
|
||||||
$income = $this->getIncomeReport($start, $end, $accounts);
|
|
||||||
|
|
||||||
$result = view('reports.partials.income', compact('income'))->render();
|
|
||||||
$cache->store($result);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Carbon $start
|
* @param Carbon $start
|
||||||
* @param Carbon $end
|
* @param Carbon $end
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use FireflyIII\Helpers\Report\ReportHelperInterface;
|
|||||||
use FireflyIII\Http\Requests\ReportFormRequest;
|
use FireflyIII\Http\Requests\ReportFormRequest;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -95,6 +96,42 @@ class ReportController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Collection $budgets
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function budgetReport(Collection $accounts, Collection $budgets, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
if ($end < $start) {
|
||||||
|
return view('error')->with('message', trans('firefly.end_after_start_date'));
|
||||||
|
}
|
||||||
|
if ($start < session('first')) {
|
||||||
|
$start = session('first');
|
||||||
|
}
|
||||||
|
|
||||||
|
View::share(
|
||||||
|
'subTitle', trans(
|
||||||
|
'firefly.report_budget',
|
||||||
|
[
|
||||||
|
'start' => $start->formatLocalized($this->monthFormat),
|
||||||
|
'end' => $end->formatLocalized($this->monthFormat),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$generator = ReportGeneratorFactory::reportGenerator('Budget', $start, $end);
|
||||||
|
$generator->setAccounts($accounts);
|
||||||
|
$generator->setBudgets($budgets);
|
||||||
|
$result = $generator->generate();
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection $accounts
|
* @param Collection $accounts
|
||||||
* @param Collection $categories
|
* @param Collection $categories
|
||||||
@@ -198,6 +235,9 @@ class ReportController extends Controller
|
|||||||
case 'category':
|
case 'category':
|
||||||
$result = $this->categoryReportOptions();
|
$result = $this->categoryReportOptions();
|
||||||
break;
|
break;
|
||||||
|
case 'budget':
|
||||||
|
$result = $this->budgetReportOptions();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response::json(['html' => $result]);
|
return Response::json(['html' => $result]);
|
||||||
@@ -217,6 +257,7 @@ class ReportController extends Controller
|
|||||||
$end = $request->getEndDate()->format('Ymd');
|
$end = $request->getEndDate()->format('Ymd');
|
||||||
$accounts = join(',', $request->getAccountList()->pluck('id')->toArray());
|
$accounts = join(',', $request->getAccountList()->pluck('id')->toArray());
|
||||||
$categories = join(',', $request->getCategoryList()->pluck('id')->toArray());
|
$categories = join(',', $request->getCategoryList()->pluck('id')->toArray());
|
||||||
|
$budgets = join(',', $request->getBudgetList()->pluck('id')->toArray());
|
||||||
|
|
||||||
if ($request->getAccountList()->count() === 0) {
|
if ($request->getAccountList()->count() === 0) {
|
||||||
Session::flash('error', trans('firefly.select_more_than_one_account'));
|
Session::flash('error', trans('firefly.select_more_than_one_account'));
|
||||||
@@ -230,6 +271,12 @@ class ReportController extends Controller
|
|||||||
return redirect(route('reports.index'));
|
return redirect(route('reports.index'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->getBudgetList()->count() === 0 && $reportType === 'budget') {
|
||||||
|
Session::flash('error', trans('firefly.select_more_than_one_budget'));
|
||||||
|
|
||||||
|
return redirect(route('reports.index'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($end < $start) {
|
if ($end < $start) {
|
||||||
return view('error')->with('message', trans('firefly.end_after_start_date'));
|
return view('error')->with('message', trans('firefly.end_after_start_date'));
|
||||||
}
|
}
|
||||||
@@ -251,11 +298,28 @@ class ReportController extends Controller
|
|||||||
case 'audit':
|
case 'audit':
|
||||||
$uri = route('reports.report.audit', [$accounts, $start, $end]);
|
$uri = route('reports.report.audit', [$accounts, $start, $end]);
|
||||||
break;
|
break;
|
||||||
|
case 'budget':
|
||||||
|
$uri = route('reports.report.budget', [$accounts, $budgets, $start, $end]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect($uri);
|
return redirect($uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function budgetReportOptions(): string
|
||||||
|
{
|
||||||
|
/** @var BudgetRepositoryInterface $repository */
|
||||||
|
$repository = app(BudgetRepositoryInterface::class);
|
||||||
|
$budgets = $repository->getBudgets();
|
||||||
|
$result = view('reports.options.budget', compact('budgets'))->render();
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ use FireflyIII\Models\RuleTrigger;
|
|||||||
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
||||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||||
use FireflyIII\Rules\TransactionMatcher;
|
use FireflyIII\Rules\TransactionMatcher;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Input;
|
use Input;
|
||||||
use Preferences;
|
use Preferences;
|
||||||
use Response;
|
use Response;
|
||||||
@@ -86,10 +87,10 @@ class RuleController extends Controller
|
|||||||
$subTitle = trans('firefly.make_new_rule', ['title' => $ruleGroup->title]);
|
$subTitle = trans('firefly.make_new_rule', ['title' => $ruleGroup->title]);
|
||||||
|
|
||||||
// put previous url in session if not redirect from store (not "create another").
|
// put previous url in session if not redirect from store (not "create another").
|
||||||
if (session('rules.rule.create.fromStore') !== true) {
|
if (session('rules.create.fromStore') !== true) {
|
||||||
Session::put('rules.rule.create.url', URL::previous());
|
Session::put('rules.create.url', URL::previous());
|
||||||
}
|
}
|
||||||
Session::forget('rules.rule.create.fromStore');
|
Session::forget('rules.create.fromStore');
|
||||||
Session::flash('gaEventCategory', 'rules');
|
Session::flash('gaEventCategory', 'rules');
|
||||||
Session::flash('gaEventAction', 'create-rule');
|
Session::flash('gaEventAction', 'create-rule');
|
||||||
|
|
||||||
@@ -110,7 +111,7 @@ class RuleController extends Controller
|
|||||||
$subTitle = trans('firefly.delete_rule', ['title' => $rule->title]);
|
$subTitle = trans('firefly.delete_rule', ['title' => $rule->title]);
|
||||||
|
|
||||||
// put previous url in session
|
// put previous url in session
|
||||||
Session::put('rules.rule.delete.url', URL::previous());
|
Session::put('rules.delete.url', URL::previous());
|
||||||
Session::flash('gaEventCategory', 'rules');
|
Session::flash('gaEventCategory', 'rules');
|
||||||
Session::flash('gaEventAction', 'delete-rule');
|
Session::flash('gaEventAction', 'delete-rule');
|
||||||
|
|
||||||
@@ -135,7 +136,7 @@ class RuleController extends Controller
|
|||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
|
|
||||||
return redirect(session('rules.rule.delete.url'));
|
return redirect(session('rules.delete.url'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,10 +179,10 @@ class RuleController extends Controller
|
|||||||
$subTitle = trans('firefly.edit_rule', ['title' => $rule->title]);
|
$subTitle = trans('firefly.edit_rule', ['title' => $rule->title]);
|
||||||
|
|
||||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||||
if (session('rules.rule.edit.fromUpdate') !== true) {
|
if (session('rules.edit.fromUpdate') !== true) {
|
||||||
Session::put('rules.rule.edit.url', URL::previous());
|
Session::put('rules.edit.url', URL::previous());
|
||||||
}
|
}
|
||||||
Session::forget('rules.rule.edit.fromUpdate');
|
Session::forget('rules.edit.fromUpdate');
|
||||||
Session::flash('gaEventCategory', 'rules');
|
Session::flash('gaEventCategory', 'rules');
|
||||||
Session::flash('gaEventAction', 'edit-rule');
|
Session::flash('gaEventAction', 'edit-rule');
|
||||||
|
|
||||||
@@ -203,14 +204,15 @@ class RuleController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param Request $request
|
||||||
* @param RuleRepositoryInterface $repository
|
* @param RuleRepositoryInterface $repository
|
||||||
* @param Rule $rule
|
* @param Rule $rule
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function reorderRuleActions(RuleRepositoryInterface $repository, Rule $rule)
|
public function reorderRuleActions(Request $request, RuleRepositoryInterface $repository, Rule $rule)
|
||||||
{
|
{
|
||||||
$ids = Input::get('actions');
|
$ids = $request->get('actions');
|
||||||
if (is_array($ids)) {
|
if (is_array($ids)) {
|
||||||
$repository->reorderRuleActions($rule, $ids);
|
$repository->reorderRuleActions($rule, $ids);
|
||||||
}
|
}
|
||||||
@@ -220,14 +222,15 @@ class RuleController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param Request $request
|
||||||
* @param RuleRepositoryInterface $repository
|
* @param RuleRepositoryInterface $repository
|
||||||
* @param Rule $rule
|
* @param Rule $rule
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
public function reorderRuleTriggers(RuleRepositoryInterface $repository, Rule $rule)
|
public function reorderRuleTriggers(Request $request, RuleRepositoryInterface $repository, Rule $rule)
|
||||||
{
|
{
|
||||||
$ids = Input::get('triggers');
|
$ids = $request->get('triggers');
|
||||||
if (is_array($ids)) {
|
if (is_array($ids)) {
|
||||||
$repository->reorderRuleTriggers($rule, $ids);
|
$repository->reorderRuleTriggers($rule, $ids);
|
||||||
}
|
}
|
||||||
@@ -254,13 +257,13 @@ class RuleController extends Controller
|
|||||||
|
|
||||||
if (intval(Input::get('create_another')) === 1) {
|
if (intval(Input::get('create_another')) === 1) {
|
||||||
// set value so create routine will not overwrite URL:
|
// set value so create routine will not overwrite URL:
|
||||||
Session::put('rules.rule.create.fromStore', true);
|
Session::put('rules.create.fromStore', true);
|
||||||
|
|
||||||
return redirect(route('rules.rule.create', [$ruleGroup]))->withInput();
|
return redirect(route('rules.create', [$ruleGroup]))->withInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
// redirect to previous URL.
|
// redirect to previous URL.
|
||||||
return redirect(session('rules.rule.create.url'));
|
return redirect(session('rules.create.url'));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,13 +344,13 @@ class RuleController extends Controller
|
|||||||
|
|
||||||
if (intval(Input::get('return_to_edit')) === 1) {
|
if (intval(Input::get('return_to_edit')) === 1) {
|
||||||
// set value so edit routine will not overwrite URL:
|
// set value so edit routine will not overwrite URL:
|
||||||
Session::put('rules.rule.edit.fromUpdate', true);
|
Session::put('rules.edit.fromUpdate', true);
|
||||||
|
|
||||||
return redirect(route('rules.rule.edit', [$rule->id]))->withInput(['return_to_edit' => 1]);
|
return redirect(route('rules.edit', [$rule->id]))->withInput(['return_to_edit' => 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// redirect to previous URL.
|
// redirect to previous URL.
|
||||||
return redirect(session('rules.rule.edit.url'));
|
return redirect(session('rules.edit.url'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createDefaultRule()
|
private function createDefaultRule()
|
||||||
|
|||||||
@@ -62,10 +62,10 @@ class RuleGroupController extends Controller
|
|||||||
$subTitle = trans('firefly.make_new_rule_group');
|
$subTitle = trans('firefly.make_new_rule_group');
|
||||||
|
|
||||||
// put previous url in session if not redirect from store (not "create another").
|
// put previous url in session if not redirect from store (not "create another").
|
||||||
if (session('rules.rule-group.create.fromStore') !== true) {
|
if (session('rule-groups.create.fromStore') !== true) {
|
||||||
Session::put('rules.rule-group.create.url', URL::previous());
|
Session::put('rule-groups.create.url', URL::previous());
|
||||||
}
|
}
|
||||||
Session::forget('rules.rule-group.create.fromStore');
|
Session::forget('rule-groups.create.fromStore');
|
||||||
Session::flash('gaEventCategory', 'rules');
|
Session::flash('gaEventCategory', 'rules');
|
||||||
Session::flash('gaEventAction', 'create-rule-group');
|
Session::flash('gaEventAction', 'create-rule-group');
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ class RuleGroupController extends Controller
|
|||||||
unset($ruleGroupList[$ruleGroup->id]);
|
unset($ruleGroupList[$ruleGroup->id]);
|
||||||
|
|
||||||
// put previous url in session
|
// put previous url in session
|
||||||
Session::put('rules.rule-group.delete.url', URL::previous());
|
Session::put('rule-groups.delete.url', URL::previous());
|
||||||
Session::flash('gaEventCategory', 'rules');
|
Session::flash('gaEventCategory', 'rules');
|
||||||
Session::flash('gaEventAction', 'delete-rule-group');
|
Session::flash('gaEventAction', 'delete-rule-group');
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ class RuleGroupController extends Controller
|
|||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
|
|
||||||
return redirect(session('rules.rule-group.delete.url'));
|
return redirect(session('rule-groups.delete.url'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,10 +140,10 @@ class RuleGroupController extends Controller
|
|||||||
$subTitle = trans('firefly.edit_rule_group', ['title' => $ruleGroup->title]);
|
$subTitle = trans('firefly.edit_rule_group', ['title' => $ruleGroup->title]);
|
||||||
|
|
||||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||||
if (session('rules.rule-group.edit.fromUpdate') !== true) {
|
if (session('rule-groups.edit.fromUpdate') !== true) {
|
||||||
Session::put('rules.rule-group.edit.url', URL::previous());
|
Session::put('rule-groups.edit.url', URL::previous());
|
||||||
}
|
}
|
||||||
Session::forget('rules.rule-group.edit.fromUpdate');
|
Session::forget('rule-groups.edit.fromUpdate');
|
||||||
Session::flash('gaEventCategory', 'rules');
|
Session::flash('gaEventCategory', 'rules');
|
||||||
Session::flash('gaEventAction', 'edit-rule-group');
|
Session::flash('gaEventAction', 'edit-rule-group');
|
||||||
|
|
||||||
@@ -220,13 +220,13 @@ class RuleGroupController extends Controller
|
|||||||
|
|
||||||
if (intval(Input::get('create_another')) === 1) {
|
if (intval(Input::get('create_another')) === 1) {
|
||||||
// set value so create routine will not overwrite URL:
|
// set value so create routine will not overwrite URL:
|
||||||
Session::put('rules.rule-group.create.fromStore', true);
|
Session::put('rule-groups.create.fromStore', true);
|
||||||
|
|
||||||
return redirect(route('rules.rule-group.create'))->withInput();
|
return redirect(route('rule-groups.create'))->withInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
// redirect to previous URL.
|
// redirect to previous URL.
|
||||||
return redirect(session('rules.rule-group.create.url'));
|
return redirect(session('rule-groups.create.url'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -265,13 +265,13 @@ class RuleGroupController extends Controller
|
|||||||
|
|
||||||
if (intval(Input::get('return_to_edit')) === 1) {
|
if (intval(Input::get('return_to_edit')) === 1) {
|
||||||
// set value so edit routine will not overwrite URL:
|
// set value so edit routine will not overwrite URL:
|
||||||
Session::put('rules.rule-group.edit.fromUpdate', true);
|
Session::put('rule-groups.edit.fromUpdate', true);
|
||||||
|
|
||||||
return redirect(route('rules.rule-group.edit', [$ruleGroup->id]))->withInput(['return_to_edit' => 1]);
|
return redirect(route('rule-groups.edit', [$ruleGroup->id]))->withInput(['return_to_edit' => 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// redirect to previous URL.
|
// redirect to previous URL.
|
||||||
return redirect(session('rules.rule-group.edit.url'));
|
return redirect(session('rule-groups.edit.url'));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,14 +172,14 @@ class ConvertController extends Controller
|
|||||||
switch ($joined) {
|
switch ($joined) {
|
||||||
default:
|
default:
|
||||||
throw new FireflyException('Cannot handle ' . $joined);
|
throw new FireflyException('Cannot handle ' . $joined);
|
||||||
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT: # one
|
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT: // one
|
||||||
$destination = $sourceAccount;
|
$destination = $sourceAccount;
|
||||||
break;
|
break;
|
||||||
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER: # two
|
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER: // two
|
||||||
$destination = $accountRepository->find(intval($data['destination_account_asset']));
|
$destination = $accountRepository->find(intval($data['destination_account_asset']));
|
||||||
break;
|
break;
|
||||||
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL: # three
|
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL: // three
|
||||||
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL: #five
|
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL: // five
|
||||||
$data = [
|
$data = [
|
||||||
'name' => $data['destination_account_expense'],
|
'name' => $data['destination_account_expense'],
|
||||||
'accountType' => 'expense',
|
'accountType' => 'expense',
|
||||||
@@ -189,8 +189,8 @@ class ConvertController extends Controller
|
|||||||
];
|
];
|
||||||
$destination = $accountRepository->store($data);
|
$destination = $accountRepository->store($data);
|
||||||
break;
|
break;
|
||||||
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER: # four
|
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER: // four
|
||||||
case TransactionType::TRANSFER . '-' . TransactionType::DEPOSIT: #six
|
case TransactionType::TRANSFER . '-' . TransactionType::DEPOSIT: // six
|
||||||
$destination = $destinationAccount;
|
$destination = $destinationAccount;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class MassController extends Controller
|
|||||||
*
|
*
|
||||||
* @return View
|
* @return View
|
||||||
*/
|
*/
|
||||||
public function massDelete(Collection $journals)
|
public function delete(Collection $journals)
|
||||||
{
|
{
|
||||||
$subTitle = trans('firefly.mass_delete_journals');
|
$subTitle = trans('firefly.mass_delete_journals');
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ class MassController extends Controller
|
|||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function massDestroy(MassDeleteJournalRequest $request, JournalRepositoryInterface $repository)
|
public function destroy(MassDeleteJournalRequest $request, JournalRepositoryInterface $repository)
|
||||||
{
|
{
|
||||||
$ids = $request->get('confirm_mass_delete');
|
$ids = $request->get('confirm_mass_delete');
|
||||||
$set = new Collection;
|
$set = new Collection;
|
||||||
@@ -114,7 +114,7 @@ class MassController extends Controller
|
|||||||
*
|
*
|
||||||
* @return View
|
* @return View
|
||||||
*/
|
*/
|
||||||
public function massEdit(Collection $journals)
|
public function edit(Collection $journals)
|
||||||
{
|
{
|
||||||
$subTitle = trans('firefly.mass_edit_journals');
|
$subTitle = trans('firefly.mass_edit_journals');
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ class MassController extends Controller
|
|||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function massUpdate(MassEditJournalRequest $request, JournalRepositoryInterface $repository)
|
public function update(MassEditJournalRequest $request, JournalRepositoryInterface $repository)
|
||||||
{
|
{
|
||||||
$journalIds = $request->get('journals');
|
$journalIds = $request->get('journals');
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ class SingleController extends Controller
|
|||||||
if ($this->isOpeningBalance($transactionJournal)) {
|
if ($this->isOpeningBalance($transactionJournal)) {
|
||||||
return $this->redirectToAccount($transactionJournal);
|
return $this->redirectToAccount($transactionJournal);
|
||||||
}
|
}
|
||||||
|
$journalId = $transactionJournal->id;
|
||||||
$type = TransactionJournal::transactionTypeStr($transactionJournal);
|
$type = TransactionJournal::transactionTypeStr($transactionJournal);
|
||||||
Session::flash('success', strval(trans('firefly.deleted_' . strtolower($type), ['description' => e($transactionJournal->description)])));
|
Session::flash('success', strval(trans('firefly.deleted_' . strtolower($type), ['description' => e($transactionJournal->description)])));
|
||||||
|
|
||||||
@@ -161,8 +161,13 @@ class SingleController extends Controller
|
|||||||
|
|
||||||
Preferences::mark();
|
Preferences::mark();
|
||||||
|
|
||||||
// redirect to previous URL:
|
$uri = session('transactions.delete.url');
|
||||||
return redirect(session('transactions.delete.url'));
|
if (!(strpos($uri, sprintf('transactions/show/%s', $journalId)) === false)) {
|
||||||
|
// uri would point back to transaction
|
||||||
|
$uri = route('transactions.index', [strtolower($type)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect($uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -184,7 +189,7 @@ class SingleController extends Controller
|
|||||||
|
|
||||||
$what = strtolower(TransactionJournal::transactionTypeStr($journal));
|
$what = strtolower(TransactionJournal::transactionTypeStr($journal));
|
||||||
$assetAccounts = ExpandedForm::makeSelectList($this->accounts->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]));
|
$assetAccounts = ExpandedForm::makeSelectList($this->accounts->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]));
|
||||||
$budgetList = ExpandedForm::makeSelectListWithEmpty($this->budgets->getActiveBudgets());
|
$budgetList = ExpandedForm::makeSelectListWithEmpty($this->budgets->getBudgets());
|
||||||
|
|
||||||
// view related code
|
// view related code
|
||||||
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
|
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ class SplitController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(Request $request, JournalRepositoryInterface $repository, TransactionJournal $journal)
|
public function update(Request $request, JournalRepositoryInterface $repository, TransactionJournal $journal)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ($this->isOpeningBalance($journal)) {
|
if ($this->isOpeningBalance($journal)) {
|
||||||
return $this->redirectToAccount($journal);
|
return $this->redirectToAccount($journal);
|
||||||
}
|
}
|
||||||
|
|||||||
0
app/Http/Kernel.php
Executable file → Normal file
0
app/Http/Kernel.php
Executable file → Normal file
0
app/Http/Middleware/EncryptCookies.php
Executable file → Normal file
0
app/Http/Middleware/EncryptCookies.php
Executable file → Normal file
@@ -17,6 +17,7 @@ use Closure;
|
|||||||
use FireflyConfig;
|
use FireflyConfig;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Log;
|
||||||
use Preferences;
|
use Preferences;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,9 +48,13 @@ class IsNotConfirmed
|
|||||||
}
|
}
|
||||||
// must the user be confirmed in the first place?
|
// must the user be confirmed in the first place?
|
||||||
$mustConfirmAccount = FireflyConfig::get('must_confirm_account', config('firefly.configuration.must_confirm_account'))->data;
|
$mustConfirmAccount = FireflyConfig::get('must_confirm_account', config('firefly.configuration.must_confirm_account'))->data;
|
||||||
|
Log::debug(sprintf('mustConfirmAccount is %s', $mustConfirmAccount));
|
||||||
// user must be logged in, then continue:
|
// user must be logged in, then continue:
|
||||||
$isConfirmed = Preferences::get('user_confirmed', false)->data;
|
$isConfirmed = Preferences::get('user_confirmed', false)->data;
|
||||||
|
Log::debug(sprintf('isConfirmed is %s', $isConfirmed));
|
||||||
if ($isConfirmed || $mustConfirmAccount === false) {
|
if ($isConfirmed || $mustConfirmAccount === false) {
|
||||||
|
Log::debug('User is confirmed or user does not have to confirm account. Redirect home.');
|
||||||
|
|
||||||
// user account is confirmed, simply send them home.
|
// user account is confirmed, simply send them home.
|
||||||
return redirect(route('home'));
|
return redirect(route('home'));
|
||||||
}
|
}
|
||||||
|
|||||||
0
app/Http/Middleware/RedirectIfAuthenticated.php
Executable file → Normal file
0
app/Http/Middleware/RedirectIfAuthenticated.php
Executable file → Normal file
0
app/Http/Middleware/VerifyCsrfToken.php
Executable file → Normal file
0
app/Http/Middleware/VerifyCsrfToken.php
Executable file → Normal file
@@ -39,15 +39,15 @@ class AccountFormRequest extends Request
|
|||||||
public function getAccountData(): array
|
public function getAccountData(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => trim($this->input('name')),
|
'name' => trim(strval($this->input('name'))),
|
||||||
'active' => intval($this->input('active')) === 1,
|
'active' => intval($this->input('active')) === 1,
|
||||||
'accountType' => $this->input('what'),
|
'accountType' => $this->input('what'),
|
||||||
'currency_id' => intval($this->input('currency_id')),
|
'currency_id' => intval($this->input('currency_id')),
|
||||||
'virtualBalance' => round($this->input('virtualBalance'), 2),
|
'virtualBalance' => round($this->input('virtualBalance'), 2),
|
||||||
'virtualBalanceCurrency' => intval($this->input('amount_currency_id_virtualBalance')),
|
'virtualBalanceCurrency' => intval($this->input('amount_currency_id_virtualBalance')),
|
||||||
'iban' => trim($this->input('iban')),
|
'iban' => trim(strval($this->input('iban'))),
|
||||||
'BIC' => trim($this->input('BIC')),
|
'BIC' => trim(strval($this->input('BIC'))),
|
||||||
'accountNumber' => trim($this->input('accountNumber')),
|
'accountNumber' => trim(strval($this->input('accountNumber'))),
|
||||||
'accountRole' => $this->input('accountRole'),
|
'accountRole' => $this->input('accountRole'),
|
||||||
'openingBalance' => round($this->input('openingBalance'), 2),
|
'openingBalance' => round($this->input('openingBalance'), 2),
|
||||||
'openingBalanceDate' => new Carbon((string)$this->input('openingBalanceDate')),
|
'openingBalanceDate' => new Carbon((string)$this->input('openingBalanceDate')),
|
||||||
|
|||||||
42
app/Http/Requests/BudgetIncomeRequest.php
Normal file
42
app/Http/Requests/BudgetIncomeRequest.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BudgetIncomeRequest.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Http\Requests;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BudgetIncomeRequest
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Http\Requests
|
||||||
|
*/
|
||||||
|
class BudgetIncomeRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
// Only allow logged in users
|
||||||
|
return auth()->check();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'amount' => 'numeric|required|min:0',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,11 @@ class ConfigurationRequest extends Request
|
|||||||
'single_user_mode' => intval($this->get('single_user_mode')) === 1,
|
'single_user_mode' => intval($this->get('single_user_mode')) === 1,
|
||||||
'must_confirm_account' => intval($this->get('must_confirm_account')) === 1,
|
'must_confirm_account' => intval($this->get('must_confirm_account')) === 1,
|
||||||
'is_demo_site' => intval($this->get('is_demo_site')) === 1,
|
'is_demo_site' => intval($this->get('is_demo_site')) === 1,
|
||||||
|
'mail_for_lockout' => intval($this->get('mail_for_lockout')) === 1,
|
||||||
|
'mail_for_blocked_domain' => intval($this->get('mail_for_blocked_domain')) === 1,
|
||||||
|
'mail_for_blocked_email' => intval($this->get('mail_for_blocked_email')) === 1,
|
||||||
|
'mail_for_bad_login' => intval($this->get('mail_for_bad_login')) === 1,
|
||||||
|
'mail_for_blocked_login' => intval($this->get('mail_for_blocked_login')) === 1,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +56,11 @@ class ConfigurationRequest extends Request
|
|||||||
'single_user_mode' => 'between:0,1|numeric',
|
'single_user_mode' => 'between:0,1|numeric',
|
||||||
'must_confirm_account' => 'between:0,1|numeric',
|
'must_confirm_account' => 'between:0,1|numeric',
|
||||||
'is_demo_site' => 'between:0,1|numeric',
|
'is_demo_site' => 'between:0,1|numeric',
|
||||||
|
'mail_for_lockout' => 'between:0,1|numeric',
|
||||||
|
'mail_for_blocked_domain' => 'between:0,1|numeric',
|
||||||
|
'mail_for_blocked_email' => 'between:0,1|numeric',
|
||||||
|
'mail_for_bad_login' => 'between:0,1|numeric',
|
||||||
|
'mail_for_blocked_login' => 'between:0,1|numeric',
|
||||||
];
|
];
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ class JournalFormRequest extends Request
|
|||||||
private function getFieldOrEmptyString(string $field): string
|
private function getFieldOrEmptyString(string $field): string
|
||||||
{
|
{
|
||||||
$string = $this->get($field) ?? '';
|
$string = $this->get($field) ?? '';
|
||||||
|
|
||||||
return trim($string);
|
return trim($string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ class PiggyBankFormRequest extends Request
|
|||||||
'startdate' => new Carbon,
|
'startdate' => new Carbon,
|
||||||
'account_id' => intval($this->get('account_id')),
|
'account_id' => intval($this->get('account_id')),
|
||||||
'targetamount' => round($this->get('targetamount'), 2),
|
'targetamount' => round($this->get('targetamount'), 2),
|
||||||
'targetdate' => strlen($this->get('targetdate')) > 0 ? new Carbon($this->get('targetdate')) : null,
|
'targetdate' => strlen(strval($this->get('targetdate'))) > 0 ? new Carbon($this->get('targetdate')) : null,
|
||||||
'note' => trim($this->get('note')),
|
'note' => trim(strval($this->get('note'))),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ class PiggyBankFormRequest extends Request
|
|||||||
'name' => $nameRule,
|
'name' => $nameRule,
|
||||||
'account_id' => 'required|belongsToUser:accounts',
|
'account_id' => 'required|belongsToUser:accounts',
|
||||||
'targetamount' => 'required|min:0.01',
|
'targetamount' => 'required|min:0.01',
|
||||||
'amount_currency_id_targetamount' => 'exists:transaction_currencies,id',
|
'amount_currency_id_targetamount' => 'required|exists:transaction_currencies,id',
|
||||||
'startdate' => 'date',
|
'startdate' => 'date',
|
||||||
'targetdate' => $targetDateRule,
|
'targetdate' => $targetDateRule,
|
||||||
'order' => 'integer|min:1',
|
'order' => 'integer|min:1',
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use Carbon\Carbon;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
@@ -58,6 +59,27 @@ class ReportFormRequest extends Request
|
|||||||
return $collection;
|
return $collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getBudgetList(): Collection
|
||||||
|
{
|
||||||
|
/** @var BudgetRepositoryInterface $repository */
|
||||||
|
$repository = app(BudgetRepositoryInterface::class);
|
||||||
|
$set = $this->get('budget');
|
||||||
|
$collection = new Collection;
|
||||||
|
if (is_array($set)) {
|
||||||
|
foreach ($set as $budgetId) {
|
||||||
|
$budget = $repository->find(intval($budgetId));
|
||||||
|
if (!is_null($budget->id)) {
|
||||||
|
$collection->push($budget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
@@ -125,7 +147,7 @@ class ReportFormRequest extends Request
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'report_type' => 'in:audit,default,category',
|
'report_type' => 'in:audit,default,category,budget',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types = 1);
|
||||||
/**
|
|
||||||
* RuleGroupFormRequest.php
|
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
|
||||||
*
|
|
||||||
* This software may be modified and distributed under the terms
|
|
||||||
* of the MIT license. See the LICENSE file for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace FireflyIII\Http\Requests;
|
namespace FireflyIII\Http\Requests;
|
||||||
|
|
||||||
|
|||||||
60
app/Http/Requests/UserFormRequest.php
Normal file
60
app/Http/Requests/UserFormRequest.php
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* UserFormRequest.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms of the
|
||||||
|
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
*
|
||||||
|
* See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Http\Requests;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UserFormRequest
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Http\Requests
|
||||||
|
*/
|
||||||
|
class UserFormRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
// Only allow logged in users
|
||||||
|
return auth()->check();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getUserData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'email' => trim($this->get('email')),
|
||||||
|
'blocked' => intval($this->get('blocked')),
|
||||||
|
'blocked_code' => trim($this->get('blocked_code')),
|
||||||
|
'password' => trim($this->get('password')),
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => 'required|exists:users,id',
|
||||||
|
'email' => 'required',
|
||||||
|
'password' => 'confirmed',
|
||||||
|
'blocked_code' => 'between:0,30',
|
||||||
|
'blocked' => 'between:0,1|numeric',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ use FireflyIII\Models\Attachment;
|
|||||||
use FireflyIII\Models\Bill;
|
use FireflyIII\Models\Bill;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\Category;
|
use FireflyIII\Models\Category;
|
||||||
|
use FireflyIII\Models\ImportJob;
|
||||||
use FireflyIII\Models\LimitRepetition;
|
use FireflyIII\Models\LimitRepetition;
|
||||||
use FireflyIII\Models\PiggyBank;
|
use FireflyIII\Models\PiggyBank;
|
||||||
use FireflyIII\Models\Rule;
|
use FireflyIII\Models\Rule;
|
||||||
@@ -27,6 +28,7 @@ use FireflyIII\Models\TransactionCurrency;
|
|||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HOME
|
* HOME
|
||||||
@@ -67,29 +69,33 @@ Breadcrumbs::register(
|
|||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'accounts.show', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
|
'accounts.show', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
|
||||||
$what = config('firefly.shortNamesByFullName.' . $account->accountType->type);
|
$what = config('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||||
|
|
||||||
$breadcrumbs->parent('accounts.index', $what);
|
$breadcrumbs->parent('accounts.index', $what);
|
||||||
$breadcrumbs->push(e($account->name), route('accounts.show', [$account->id]));
|
$breadcrumbs->push($account->name, route('accounts.show', [$account->id]));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'accounts.show.date', function (BreadCrumbGenerator $breadcrumbs, Account $account, Carbon $date) {
|
'accounts.show.date', function (BreadCrumbGenerator $breadcrumbs, Account $account, Carbon $start, Carbon $end) {
|
||||||
|
|
||||||
|
$startString = $start->formatLocalized(strval(trans('config.month_and_day')));
|
||||||
|
$endString = $end->formatLocalized(strval(trans('config.month_and_day')));
|
||||||
|
$title = sprintf('%s (%s)', $account->name, trans('firefly.from_to', ['start' => $startString, 'end' => $endString]));
|
||||||
|
|
||||||
$breadcrumbs->parent('accounts.show', $account);
|
$breadcrumbs->parent('accounts.show', $account);
|
||||||
|
$breadcrumbs->push($title, route('accounts.show.date', [$account->id, $start->format('Y-m-d')]));
|
||||||
$range = Preferences::get('viewRange', '1M')->data;
|
|
||||||
$title = $account->name . ' (' . Navigation::periodShow($date, $range) . ')';
|
|
||||||
|
|
||||||
$breadcrumbs->push($title, route('accounts.show.date', [$account->id, $date->format('Y-m-d')]));
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'accounts.show.all', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
|
'accounts.show.all', function (BreadCrumbGenerator $breadcrumbs, Account $account, Carbon $start, Carbon $end) {
|
||||||
|
|
||||||
|
$startString = $start->formatLocalized(strval(trans('config.month_and_day')));
|
||||||
|
$endString = $end->formatLocalized(strval(trans('config.month_and_day')));
|
||||||
|
$title = sprintf('%s (%s)', $account->name, trans('firefly.from_to', ['start' => $startString, 'end' => $endString]));
|
||||||
|
|
||||||
$breadcrumbs->parent('accounts.show', $account);
|
$breadcrumbs->parent('accounts.show', $account);
|
||||||
|
$breadcrumbs->push($title, route('accounts.show.all', [$account->id, $start->format('Y-m-d')]));
|
||||||
$title = sprintf('%s (%s)', $account->name, strtolower(trans('firefly.everything')));
|
|
||||||
|
|
||||||
$breadcrumbs->push($title, route('accounts.show.all', [$account->id]));
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -134,6 +140,12 @@ Breadcrumbs::register(
|
|||||||
$breadcrumbs->push(trans('firefly.single_user_administration', ['email' => $user->email]), route('admin.users.show', [$user->id]));
|
$breadcrumbs->push(trans('firefly.single_user_administration', ['email' => $user->email]), route('admin.users.show', [$user->id]));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'admin.users.edit', function (BreadCrumbGenerator $breadcrumbs, User $user) {
|
||||||
|
$breadcrumbs->parent('admin.users');
|
||||||
|
$breadcrumbs->push(trans('firefly.edit_user', ['email' => $user->email]), route('admin.users.edit', [$user->id]));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'admin.users.domains', function (BreadCrumbGenerator $breadcrumbs) {
|
'admin.users.domains', function (BreadCrumbGenerator $breadcrumbs) {
|
||||||
@@ -248,22 +260,27 @@ Breadcrumbs::register(
|
|||||||
);
|
);
|
||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'budgets.noBudget', function (BreadCrumbGenerator $breadcrumbs, $subTitle) {
|
'budgets.no-budget', function (BreadCrumbGenerator $breadcrumbs, $subTitle) {
|
||||||
$breadcrumbs->parent('budgets.index');
|
$breadcrumbs->parent('budgets.index');
|
||||||
$breadcrumbs->push($subTitle, route('budgets.noBudget'));
|
$breadcrumbs->push($subTitle, route('budgets.no-budget'));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'budgets.show', function (BreadCrumbGenerator $breadcrumbs, Budget $budget, LimitRepetition $repetition = null) {
|
'budgets.show', function (BreadCrumbGenerator $breadcrumbs, Budget $budget) {
|
||||||
$breadcrumbs->parent('budgets.index');
|
$breadcrumbs->parent('budgets.index');
|
||||||
$breadcrumbs->push(e($budget->name), route('budgets.show', [$budget->id]));
|
$breadcrumbs->push(e($budget->name), route('budgets.show', [$budget->id]));
|
||||||
if (!is_null($repetition) && !is_null($repetition->id)) {
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'budgets.show.repetition', function (BreadCrumbGenerator $breadcrumbs, Budget $budget, LimitRepetition $repetition) {
|
||||||
|
$breadcrumbs->parent('budgets.index');
|
||||||
|
$breadcrumbs->push(e($budget->name), route('budgets.show.repetition', [$budget->id, $repetition->id]));
|
||||||
$breadcrumbs->push(
|
$breadcrumbs->push(
|
||||||
Navigation::periodShow($repetition->startdate, $repetition->budgetLimit->repeat_freq), route('budgets.show', [$budget->id, $repetition->id])
|
Navigation::periodShow($repetition->startdate, $repetition->budgetLimit->repeat_freq), route('budgets.show', [$budget->id, $repetition->id])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -317,9 +334,9 @@ Breadcrumbs::register(
|
|||||||
);
|
);
|
||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'categories.noCategory', function (BreadCrumbGenerator $breadcrumbs, $subTitle) {
|
'categories.no-category', function (BreadCrumbGenerator $breadcrumbs, $subTitle) {
|
||||||
$breadcrumbs->parent('categories.index');
|
$breadcrumbs->parent('categories.index');
|
||||||
$breadcrumbs->push($subTitle, route('categories.noCategory'));
|
$breadcrumbs->push($subTitle, route('categories.no-category'));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -396,10 +413,54 @@ Breadcrumbs::register(
|
|||||||
'piggy-banks.show', function (BreadCrumbGenerator $breadcrumbs, PiggyBank $piggyBank) {
|
'piggy-banks.show', function (BreadCrumbGenerator $breadcrumbs, PiggyBank $piggyBank) {
|
||||||
$breadcrumbs->parent('piggy-banks.index');
|
$breadcrumbs->parent('piggy-banks.index');
|
||||||
$breadcrumbs->push(e($piggyBank->name), route('piggy-banks.show', [$piggyBank->id]));
|
$breadcrumbs->push(e($piggyBank->name), route('piggy-banks.show', [$piggyBank->id]));
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'piggy-banks.add-money-mobile', function (BreadCrumbGenerator $breadcrumbs, PiggyBank $piggyBank) {
|
||||||
|
$breadcrumbs->parent('piggy-banks.show', $piggyBank);
|
||||||
|
$breadcrumbs->push(trans('firefly.add_money_to_piggy', ['name' => $piggyBank->name]), route('piggy-banks.add-money-mobile', [$piggyBank->id]));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'piggy-banks.remove-money-mobile', function (BreadCrumbGenerator $breadcrumbs, PiggyBank $piggyBank) {
|
||||||
|
$breadcrumbs->parent('piggy-banks.show', $piggyBank);
|
||||||
|
$breadcrumbs->push(
|
||||||
|
trans('firefly.remove_money_from_piggy_title', ['name' => $piggyBank->name]), route('piggy-banks.remove-money-mobile', [$piggyBank->id])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMPORT
|
||||||
|
*/
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'import.index', function (BreadCrumbGenerator $breadcrumbs) {
|
||||||
|
$breadcrumbs->parent('home');
|
||||||
|
$breadcrumbs->push(trans('firefly.import'), route('import.index'));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'import.complete', function (BreadCrumbGenerator $breadcrumbs, ImportJob $job) {
|
||||||
|
$breadcrumbs->parent('import.index');
|
||||||
|
$breadcrumbs->push(trans('firefly.bread_crumb_import_complete', ['key' => $job->key]), route('import.complete', [$job->key]));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'import.configure', function (BreadCrumbGenerator $breadcrumbs, ImportJob $job) {
|
||||||
|
$breadcrumbs->parent('import.index');
|
||||||
|
$breadcrumbs->push(trans('firefly.bread_crumb_configure_import', ['key' => $job->key]), route('import.configure', [$job->key]));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'import.finished', function (BreadCrumbGenerator $breadcrumbs, ImportJob $job) {
|
||||||
|
$breadcrumbs->parent('import.index');
|
||||||
|
$breadcrumbs->push(trans('firefly.bread_crumb_import_finished', ['key' => $job->key]), route('import.finished', [$job->key]));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PREFERENCES
|
* PREFERENCES
|
||||||
*/
|
*/
|
||||||
@@ -407,7 +468,6 @@ Breadcrumbs::register(
|
|||||||
'preferences.index', function (BreadCrumbGenerator $breadcrumbs) {
|
'preferences.index', function (BreadCrumbGenerator $breadcrumbs) {
|
||||||
$breadcrumbs->parent('home');
|
$breadcrumbs->parent('home');
|
||||||
$breadcrumbs->push(trans('breadcrumbs.preferences'), route('preferences.index'));
|
$breadcrumbs->push(trans('breadcrumbs.preferences'), route('preferences.index'));
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -455,16 +515,63 @@ Breadcrumbs::register(
|
|||||||
);
|
);
|
||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'reports.report', function (BreadCrumbGenerator $breadcrumbs, Carbon $start, Carbon $end, $reportType, $accountIds) {
|
'reports.report.audit', function (BreadCrumbGenerator $breadcrumbs, string $accountIds, Carbon $start, Carbon $end) {
|
||||||
$breadcrumbs->parent('reports.index');
|
$breadcrumbs->parent('reports.index');
|
||||||
|
|
||||||
$monthFormat = (string)trans('config.month_and_day');
|
$monthFormat = (string)trans('config.month_and_day');
|
||||||
$title = (string)trans(
|
$startString = $start->formatLocalized($monthFormat);
|
||||||
'firefly.report_' . $reportType,
|
$endString = $end->formatLocalized($monthFormat);
|
||||||
['start' => $start->formatLocalized($monthFormat), 'end' => $end->formatLocalized($monthFormat)]
|
$title = (string)trans('firefly.report_audit', ['start' => $startString, 'end' => $endString]);
|
||||||
|
|
||||||
|
$breadcrumbs->push($title, route('reports.report.audit', [$accountIds, $start->format('Ymd'), $end->format('Ymd')]));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'reports.report.budget', function (BreadCrumbGenerator $breadcrumbs, string $accountIds, string $budgetIds, Carbon $start, Carbon $end) {
|
||||||
|
$breadcrumbs->parent('reports.index');
|
||||||
|
|
||||||
|
$monthFormat = (string)trans('config.month_and_day');
|
||||||
|
$startString = $start->formatLocalized($monthFormat);
|
||||||
|
$endString = $end->formatLocalized($monthFormat);
|
||||||
|
$title = (string)trans('firefly.report_budget', ['start' => $startString, 'end' => $endString]);
|
||||||
|
|
||||||
|
$breadcrumbs->push($title, route('reports.report.budget', [$accountIds, $budgetIds, $start->format('Ymd'), $end->format('Ymd')]));
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
$breadcrumbs->push($title, route('reports.report', [$reportType, $start->format('Ymd'), $end->format('Ymd'), $accountIds]));
|
Breadcrumbs::register(
|
||||||
|
'reports.report.category', function (BreadCrumbGenerator $breadcrumbs, string $accountIds, string $categoryIds, Carbon $start, Carbon $end) {
|
||||||
|
$breadcrumbs->parent('reports.index');
|
||||||
|
|
||||||
|
$monthFormat = (string)trans('config.month_and_day');
|
||||||
|
$startString = $start->formatLocalized($monthFormat);
|
||||||
|
$endString = $end->formatLocalized($monthFormat);
|
||||||
|
$title = (string)trans('firefly.report_category', ['start' => $startString, 'end' => $endString]);
|
||||||
|
|
||||||
|
$breadcrumbs->push($title, route('reports.report.category', [$accountIds, $categoryIds, $start->format('Ymd'), $end->format('Ymd')]));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'reports.report.default', function (BreadCrumbGenerator $breadcrumbs, string $accountIds, Carbon $start, Carbon $end) {
|
||||||
|
$breadcrumbs->parent('reports.index');
|
||||||
|
|
||||||
|
$monthFormat = (string)trans('config.month_and_day');
|
||||||
|
$startString = $start->formatLocalized($monthFormat);
|
||||||
|
$endString = $end->formatLocalized($monthFormat);
|
||||||
|
$title = (string)trans('firefly.report_default', ['start' => $startString, 'end' => $endString]);
|
||||||
|
|
||||||
|
$breadcrumbs->push($title, route('reports.report.default', [$accountIds, $start->format('Ymd'), $end->format('Ymd')]));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* New user Controller
|
||||||
|
*/
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'new-user.index', function (BreadCrumbGenerator $breadcrumbs) {
|
||||||
|
$breadcrumbs->parent('home');
|
||||||
|
$breadcrumbs->push(trans('firefly.getting_started'), route('new-user.index'));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -479,47 +586,54 @@ Breadcrumbs::register(
|
|||||||
);
|
);
|
||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'rules.rule.create', function (BreadCrumbGenerator $breadcrumbs, RuleGroup $ruleGroup) {
|
'rules.create', function (BreadCrumbGenerator $breadcrumbs, RuleGroup $ruleGroup) {
|
||||||
$breadcrumbs->parent('rules.index');
|
$breadcrumbs->parent('rules.index');
|
||||||
$breadcrumbs->push(trans('firefly.make_new_rule', ['title' => $ruleGroup->title]), route('rules.rule.create', [$ruleGroup]));
|
$breadcrumbs->push(trans('firefly.make_new_rule', ['title' => $ruleGroup->title]), route('rules.create', [$ruleGroup]));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'rules.rule.edit', function (BreadCrumbGenerator $breadcrumbs, Rule $rule) {
|
'rules.edit', function (BreadCrumbGenerator $breadcrumbs, Rule $rule) {
|
||||||
$breadcrumbs->parent('rules.index');
|
$breadcrumbs->parent('rules.index');
|
||||||
$breadcrumbs->push(trans('firefly.edit_rule', ['title' => $rule->title]), route('rules.rule.edit', [$rule]));
|
$breadcrumbs->push(trans('firefly.edit_rule', ['title' => $rule->title]), route('rules.edit', [$rule]));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'rules.rule.delete', function (BreadCrumbGenerator $breadcrumbs, Rule $rule) {
|
'rules.delete', function (BreadCrumbGenerator $breadcrumbs, Rule $rule) {
|
||||||
$breadcrumbs->parent('rules.index');
|
$breadcrumbs->parent('rules.index');
|
||||||
$breadcrumbs->push(trans('firefly.delete_rule', ['title' => $rule->title]), route('rules.rule.delete', [$rule]));
|
$breadcrumbs->push(trans('firefly.delete_rule', ['title' => $rule->title]), route('rules.delete', [$rule]));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'rules.rule-group.create', function (BreadCrumbGenerator $breadcrumbs) {
|
'rule-groups.create', function (BreadCrumbGenerator $breadcrumbs) {
|
||||||
$breadcrumbs->parent('rules.index');
|
$breadcrumbs->parent('rules.index');
|
||||||
$breadcrumbs->push(trans('firefly.make_new_rule_group'), route('rules.rule-group.create'));
|
$breadcrumbs->push(trans('firefly.make_new_rule_group'), route('rule-groups.create'));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'rules.rule-group.edit', function (BreadCrumbGenerator $breadcrumbs, RuleGroup $ruleGroup) {
|
'rule-groups.edit', function (BreadCrumbGenerator $breadcrumbs, RuleGroup $ruleGroup) {
|
||||||
$breadcrumbs->parent('rules.index');
|
$breadcrumbs->parent('rules.index');
|
||||||
$breadcrumbs->push(trans('firefly.edit_rule_group', ['title' => $ruleGroup->title]), route('rules.rule-group.edit', [$ruleGroup]));
|
$breadcrumbs->push(trans('firefly.edit_rule_group', ['title' => $ruleGroup->title]), route('rule-groups.edit', [$ruleGroup]));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'rules.rule-group.delete', function (BreadCrumbGenerator $breadcrumbs, RuleGroup $ruleGroup) {
|
'rule-groups.delete', function (BreadCrumbGenerator $breadcrumbs, RuleGroup $ruleGroup) {
|
||||||
$breadcrumbs->parent('rules.index');
|
$breadcrumbs->parent('rules.index');
|
||||||
$breadcrumbs->push(trans('firefly.delete_rule_group', ['title' => $ruleGroup->title]), route('rules.rule-group.delete', [$ruleGroup]));
|
$breadcrumbs->push(trans('firefly.delete_rule_group', ['title' => $ruleGroup->title]), route('rule-groups.delete', [$ruleGroup]));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'rules.rule-group.select_transactions', function (BreadCrumbGenerator $breadcrumbs, RuleGroup $ruleGroup) {
|
'rule-groups.select-transactions', function (BreadCrumbGenerator $breadcrumbs, RuleGroup $ruleGroup) {
|
||||||
|
$breadcrumbs->parent('rules.index');
|
||||||
|
$breadcrumbs->push(trans('firefly.rule_group_select_transactions', ['title' => $ruleGroup->title]), route('rule-groups.select-transactions', [$ruleGroup]));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'rule-groups.select_transactions', function (BreadCrumbGenerator $breadcrumbs, RuleGroup $ruleGroup) {
|
||||||
$breadcrumbs->parent('rules.index');
|
$breadcrumbs->parent('rules.index');
|
||||||
$breadcrumbs->push(
|
$breadcrumbs->push(
|
||||||
trans('firefly.execute_group_on_existing_transactions', ['title' => $ruleGroup->title]), route('rules.rule-group.select_transactions', [$ruleGroup])
|
trans('firefly.execute_group_on_existing_transactions', ['title' => $ruleGroup->title]), route('rule-groups.select_transactions', [$ruleGroup])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -646,20 +760,36 @@ Breadcrumbs::register(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MASS TRANSACTION EDIT / DELETE
|
||||||
|
*/
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'transactions.mass.edit', function (BreadCrumbGenerator $breadcrumbs, Collection $journals) {
|
||||||
|
|
||||||
|
$journalIds = $journals->pluck('id')->toArray();
|
||||||
|
$what = strtolower($journals->first()->transactionType->type);
|
||||||
|
$breadcrumbs->parent('transactions.index', $what);
|
||||||
|
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.edit', $journalIds));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Breadcrumbs::register(
|
||||||
|
'transactions.mass.delete', function (BreadCrumbGenerator $breadcrumbs, Collection $journals) {
|
||||||
|
|
||||||
|
$journalIds = $journals->pluck('id')->toArray();
|
||||||
|
$what = strtolower($journals->first()->transactionType->type);
|
||||||
|
$breadcrumbs->parent('transactions.index', $what);
|
||||||
|
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.delete', $journalIds));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SPLIT
|
* SPLIT
|
||||||
*/
|
*/
|
||||||
Breadcrumbs::register(
|
Breadcrumbs::register(
|
||||||
'transactions.edit-split', function (BreadCrumbGenerator $breadcrumbs, TransactionJournal $journal) {
|
'transactions.split.edit', function (BreadCrumbGenerator $breadcrumbs, TransactionJournal $journal) {
|
||||||
$breadcrumbs->parent('transactions.show', $journal);
|
$breadcrumbs->parent('transactions.show', $journal);
|
||||||
$breadcrumbs->push(trans('breadcrumbs.edit_journal', ['description' => $journal->description]), route('transactions.edit-split', [$journal->id]));
|
$breadcrumbs->push(trans('breadcrumbs.edit_journal', ['description' => $journal->description]), route('transactions.split.edit', [$journal->id]));
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Breadcrumbs::register(
|
|
||||||
'split.journal.create', function (BreadCrumbGenerator $breadcrumbs, string $what) {
|
|
||||||
$breadcrumbs->parent('transactions.index', $what);
|
|
||||||
$breadcrumbs->push(trans('breadcrumbs.create_' . e($what)), route('split.journal.create', [$what]));
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ class ImportEntry
|
|||||||
case 'account-id':
|
case 'account-id':
|
||||||
case 'account-iban':
|
case 'account-iban':
|
||||||
case 'account-name':
|
case 'account-name':
|
||||||
|
case 'account-number':
|
||||||
$this->setObject('asset-account', $convertedValue, $certainty);
|
$this->setObject('asset-account', $convertedValue, $certainty);
|
||||||
break;
|
break;
|
||||||
case 'opposing-number':
|
case 'opposing-number':
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use Illuminate\Support\Collection;
|
|||||||
*
|
*
|
||||||
* @package FireflyIII\Import
|
* @package FireflyIII\Import
|
||||||
*/
|
*/
|
||||||
class ImportProcedure
|
class ImportProcedure implements ImportProcedureInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,7 +31,7 @@ class ImportProcedure
|
|||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public static function runImport(ImportJob $job): Collection
|
public function runImport(ImportJob $job): Collection
|
||||||
{
|
{
|
||||||
// update job to say we started.
|
// update job to say we started.
|
||||||
$job->status = 'import_running';
|
$job->status = 'import_running';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* PiggyBankChartGeneratorInterface.php
|
* ImportProcedureInterface.php
|
||||||
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
*
|
*
|
||||||
* This software may be modified and distributed under the terms of the
|
* This software may be modified and distributed under the terms of the
|
||||||
@@ -11,21 +11,23 @@
|
|||||||
|
|
||||||
declare(strict_types = 1);
|
declare(strict_types = 1);
|
||||||
|
|
||||||
namespace FireflyIII\Generator\Chart\PiggyBank;
|
namespace FireflyIII\Import;
|
||||||
|
|
||||||
|
use FireflyIII\Models\ImportJob;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface PiggyBankChartGeneratorInterface
|
* Interface ImportProcedureInterface
|
||||||
*
|
*
|
||||||
* @package FireflyIII\Generator\Chart\PiggyBank
|
* @package FireflyIII\Import
|
||||||
*/
|
*/
|
||||||
interface PiggyBankChartGeneratorInterface
|
interface ImportProcedureInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param Collection $set
|
* @param ImportJob $job
|
||||||
*
|
*
|
||||||
* @return array
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function history(Collection $set): array;
|
public function runImport(ImportJob $job): Collection;
|
||||||
|
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user