mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-10 21:31:20 +00:00
Compare commits
1043 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fcb8b02da9 | ||
|
|
c842113610 | ||
|
|
974a8b3b70 | ||
|
|
2e20c99ada | ||
|
|
aa88ff6f2c | ||
|
|
5e6aa63d03 | ||
|
|
f08c6efb00 | ||
|
|
1ffa8c5e72 | ||
|
|
d855ccb8a7 | ||
|
|
d88919474b | ||
|
|
e139664301 | ||
|
|
5adf5f6e3f | ||
|
|
aef2075c8e | ||
|
|
922b2962a3 | ||
|
|
b4a401700e | ||
|
|
e9601bb9c1 | ||
|
|
58af3dc6ea | ||
|
|
074295df61 | ||
|
|
ec349b31c7 | ||
|
|
5ae236e016 | ||
|
|
d7c5897aba | ||
|
|
5252e7efe7 | ||
|
|
fc7d65629a | ||
|
|
f28fdf8252 | ||
|
|
5d07c4a949 | ||
|
|
fdd9eaab4b | ||
|
|
e0d863a46f | ||
|
|
3aacb6f5f3 | ||
|
|
428e331b3e | ||
|
|
847e05e9a7 | ||
|
|
087eb5dbe6 | ||
|
|
f15932b2ac | ||
|
|
d3a4c3795d | ||
|
|
b15d55e1d9 | ||
|
|
4f5889cc5b | ||
|
|
bf2a104a4e | ||
|
|
0c6dd5cd16 | ||
|
|
5efb06a7aa | ||
|
|
b13acef272 | ||
|
|
cfa67d6c0f | ||
|
|
e70444f19a | ||
|
|
0258982e60 | ||
|
|
70eed5cb5e | ||
|
|
a650fa51f7 | ||
|
|
cb205580d8 | ||
|
|
f9329aac00 | ||
|
|
745f4a7523 | ||
|
|
60254dafd7 | ||
|
|
a8d60388ba | ||
|
|
83ec60254c | ||
|
|
c15c45f765 | ||
|
|
cbe52b5089 | ||
|
|
e4e2921f3e | ||
|
|
4673170531 | ||
|
|
2c2ed26c38 | ||
|
|
94be5244fe | ||
|
|
f137a08493 | ||
|
|
48624d0a34 | ||
|
|
4cceb3ddaa | ||
|
|
f728395603 | ||
|
|
3e82d43807 | ||
|
|
2194c4e0a9 | ||
|
|
c581080f3f | ||
|
|
f6b1ec27e5 | ||
|
|
368b183230 | ||
|
|
9028ad36ad | ||
|
|
6cc041cd39 | ||
|
|
63ff01e78d | ||
|
|
9e5484937e | ||
|
|
b8ed489b14 | ||
|
|
765152d04b | ||
|
|
14934367d8 | ||
|
|
04164500c8 | ||
|
|
5160f2c298 | ||
|
|
124c9303b9 | ||
|
|
cd27f0ad69 | ||
|
|
a7555bcce3 | ||
|
|
6b5c4fd3f4 | ||
|
|
cc55e2acee | ||
|
|
1511f75a80 | ||
|
|
f01bbefc1f | ||
|
|
1d1eb5ffa8 | ||
|
|
a465cb2191 | ||
|
|
42d13e02ef | ||
|
|
d00786c43f | ||
|
|
4b47f99829 | ||
|
|
35aaf40003 | ||
|
|
cc5b4a1e02 | ||
|
|
7079521e8c | ||
|
|
b5025560a5 | ||
|
|
3f4bdd7f0e | ||
|
|
e94bb9b549 | ||
|
|
1ddaacbef5 | ||
|
|
e8b40518e0 | ||
|
|
0f88cbb41b | ||
|
|
780d137b76 | ||
|
|
ad8a9717d1 | ||
|
|
9d6ea6b2f6 | ||
|
|
7559383089 | ||
|
|
f84381c927 | ||
|
|
cb0122a43f | ||
|
|
6776b20989 | ||
|
|
e98d556022 | ||
|
|
5bf18b69d7 | ||
|
|
ea17f045a7 | ||
|
|
526f565ea7 | ||
|
|
4aff9d6e73 | ||
|
|
bf516d4d21 | ||
|
|
ae92e409d9 | ||
|
|
4d017dc8a9 | ||
|
|
707f4e2965 | ||
|
|
1c3bffdc50 | ||
|
|
e54ddcb8b0 | ||
|
|
ddefb0debc | ||
|
|
92d8dde90d | ||
|
|
1bb0508ddf | ||
|
|
a280a326b9 | ||
|
|
683e9b7c2c | ||
|
|
a44e5da421 | ||
|
|
8cd2c90ad7 | ||
|
|
5e57a390a2 | ||
|
|
620848272e | ||
|
|
1e86794416 | ||
|
|
e36717259b | ||
|
|
75b9238b90 | ||
|
|
ce5b20027e | ||
|
|
0de1242c83 | ||
|
|
8bd445ab19 | ||
|
|
fdef0de163 | ||
|
|
b1b03a4325 | ||
|
|
0587d96474 | ||
|
|
c2241567e4 | ||
|
|
7ac24ba418 | ||
|
|
c933ffec66 | ||
|
|
e587d934b1 | ||
|
|
f354e90656 | ||
|
|
1b0bc7ec6e | ||
|
|
ee1acb9c00 | ||
|
|
06862a2812 | ||
|
|
5fa87e18db | ||
|
|
77989e2720 | ||
|
|
3a1102fa4e | ||
|
|
8a9974ce53 | ||
|
|
4be8f1ca03 | ||
|
|
1ec2970ee3 | ||
|
|
81b3a22606 | ||
|
|
f81a475cc9 | ||
|
|
d7ee03d4f9 | ||
|
|
c1c06410c2 | ||
|
|
657d16bb60 | ||
|
|
e65a4c1010 | ||
|
|
e23d3f5661 | ||
|
|
e13611f7af | ||
|
|
596cd09489 | ||
|
|
0be5b27d34 | ||
|
|
a27471ae55 | ||
|
|
e27e3622a8 | ||
|
|
e95273b72b | ||
|
|
583d4f3249 | ||
|
|
d6967c4516 | ||
|
|
40b3097374 | ||
|
|
1a1f127993 | ||
|
|
a0f34a7ce1 | ||
|
|
db020db34b | ||
|
|
681167bc1b | ||
|
|
40e49ffc37 | ||
|
|
834b1afb38 | ||
|
|
62d5a1da87 | ||
|
|
8d8308e557 | ||
|
|
e1aa63487a | ||
|
|
b7fbe110d4 | ||
|
|
58859eb35a | ||
|
|
4b7e1ae1c6 | ||
|
|
3a06a6ac07 | ||
|
|
db0f269dc8 | ||
|
|
3cabe6ca5a | ||
|
|
d483005219 | ||
|
|
fea9bc4e7e | ||
|
|
d579992c98 | ||
|
|
ad1c61d959 | ||
|
|
bb1da31830 | ||
|
|
a50949e554 | ||
|
|
14dce8a10b | ||
|
|
1240c8f685 | ||
|
|
cc7c2e952c | ||
|
|
409ec2e086 | ||
|
|
a7f6848e53 | ||
|
|
4b0b79199d | ||
|
|
d1d6c48d9b | ||
|
|
21631780bb | ||
|
|
b935e32340 | ||
|
|
72dd064932 | ||
|
|
2e75446665 | ||
|
|
be17e4481e | ||
|
|
616c849b1f | ||
|
|
71947c097f | ||
|
|
546787802d | ||
|
|
294d0e388a | ||
|
|
193a1b0325 | ||
|
|
12743217a2 | ||
|
|
b252b9da66 | ||
|
|
cdef9c3c7e | ||
|
|
71dcebb744 | ||
|
|
25f248c60a | ||
|
|
d5cbc17831 | ||
|
|
7a10217511 | ||
|
|
7559efab77 | ||
|
|
8254efbd03 | ||
|
|
4ae24225a5 | ||
|
|
67d9154563 | ||
|
|
ad0319c188 | ||
|
|
eb650ea3ec | ||
|
|
7eba33e805 | ||
|
|
e1cb9d387e | ||
|
|
2ace7c3ca0 | ||
|
|
58014f0592 | ||
|
|
1d4938bb09 | ||
|
|
bbf4007c3e | ||
|
|
4d5124fb4c | ||
|
|
14a7cd05b1 | ||
|
|
946be80eef | ||
|
|
9ad8b1a980 | ||
|
|
f733216fcb | ||
|
|
ffc6139e21 | ||
|
|
571cac6644 | ||
|
|
2738ac5a5c | ||
|
|
7dfde51b84 | ||
|
|
2d2f18e538 | ||
|
|
3af0dd2e3b | ||
|
|
349e077802 | ||
|
|
812aae358f | ||
|
|
c3c59d0627 | ||
|
|
89518b412d | ||
|
|
f43b026162 | ||
|
|
b806c70f52 | ||
|
|
10bff3c0b8 | ||
|
|
65c12fd0b2 | ||
|
|
50f71c4130 | ||
|
|
8e401a53dc | ||
|
|
64a289a47c | ||
|
|
8f2c37061b | ||
|
|
39f2de6b90 | ||
|
|
855ba8d4f3 | ||
|
|
74f098e718 | ||
|
|
56c8a84691 | ||
|
|
8bbf319032 | ||
|
|
afbca4ae65 | ||
|
|
0ef6d2f91a | ||
|
|
fbe4435599 | ||
|
|
34be565dd1 | ||
|
|
af838e4ed1 | ||
|
|
60fe8ce011 | ||
|
|
8ece341467 | ||
|
|
dfa6bdbcb8 | ||
|
|
fb2481ebaa | ||
|
|
4874c116cf | ||
|
|
e19c44efbd | ||
|
|
4b687b9bdc | ||
|
|
6af79ef601 | ||
|
|
352b996ad2 | ||
|
|
4a93bb35f8 | ||
|
|
8e1f493daf | ||
|
|
59ee153375 | ||
|
|
60f7f1fc16 | ||
|
|
b7433683d8 | ||
|
|
42799b9273 | ||
|
|
860a0f790e | ||
|
|
8daccbfbb4 | ||
|
|
285b77dcb7 | ||
|
|
6e48827d3f | ||
|
|
f0c20cc706 | ||
|
|
8916c0a3de | ||
|
|
7193a77840 | ||
|
|
61930b5b51 | ||
|
|
11a494cacf | ||
|
|
17f9bf0339 | ||
|
|
3d9755ca8c | ||
|
|
b5cf2d03e6 | ||
|
|
e3b35b8f35 | ||
|
|
1c1fe672bd | ||
|
|
6c71f68ed8 | ||
|
|
8f2f912cdf | ||
|
|
bf6ea16acb | ||
|
|
288546c2b9 | ||
|
|
724db6c34c | ||
|
|
067c451c1d | ||
|
|
11e3696191 | ||
|
|
41e20664de | ||
|
|
d8de90d6f3 | ||
|
|
b01e8299d3 | ||
|
|
1ec11e3e2e | ||
|
|
422f429725 | ||
|
|
5c55fa5fbb | ||
|
|
80d845fdf2 | ||
|
|
601fe68346 | ||
|
|
9e050fb059 | ||
|
|
99d4adf5e6 | ||
|
|
85f8d1e8e9 | ||
|
|
8334d3d99f | ||
|
|
cff08d19eb | ||
|
|
2d86390bc1 | ||
|
|
7a20835571 | ||
|
|
ff3c9676b5 | ||
|
|
055f97dab1 | ||
|
|
8a867e71a1 | ||
|
|
b8275b4734 | ||
|
|
36b951b146 | ||
|
|
c5a5f17643 | ||
|
|
16b909c4df | ||
|
|
92b7648e03 | ||
|
|
ca46ebe3b2 | ||
|
|
676e48254a | ||
|
|
b15b55227d | ||
|
|
3c3b723913 | ||
|
|
f05002c729 | ||
|
|
1c2cbd5b40 | ||
|
|
54c6ca9f45 | ||
|
|
c10efbb170 | ||
|
|
a496ad5814 | ||
|
|
50cf7f6a3b | ||
|
|
f946f10afd | ||
|
|
eecb4db34c | ||
|
|
1f865d3ea4 | ||
|
|
623bb4b350 | ||
|
|
dc8ad673a6 | ||
|
|
4914ad821e | ||
|
|
f099cbadc3 | ||
|
|
42cda384c8 | ||
|
|
23c91b9990 | ||
|
|
ff0379182e | ||
|
|
e08a23948f | ||
|
|
bd56de6d36 | ||
|
|
42970aea80 | ||
|
|
003a05ee8d | ||
|
|
ffb11b01a6 | ||
|
|
e426f5d5da | ||
|
|
6989f61e1b | ||
|
|
0e6677ccb3 | ||
|
|
8f104d555a | ||
|
|
b1d3158db1 | ||
|
|
7645005d5a | ||
|
|
411f77fd29 | ||
|
|
568ab26db1 | ||
|
|
29652108f0 | ||
|
|
f07e4dc711 | ||
|
|
8a2ac457c2 | ||
|
|
9e54eecfaa | ||
|
|
95ef691077 | ||
|
|
7a0ad5a587 | ||
|
|
42b49d0e4b | ||
|
|
9217c2f003 | ||
|
|
fbdf66998d | ||
|
|
deda9d3c54 | ||
|
|
a5d78f20ae | ||
|
|
5ed09e3f38 | ||
|
|
3e9774cd66 | ||
|
|
54387c8fdf | ||
|
|
7eec949a13 | ||
|
|
4113c4ff40 | ||
|
|
1bf0968bfe | ||
|
|
374b90fb00 | ||
|
|
064e60e9d5 | ||
|
|
b637455970 | ||
|
|
68158937d1 | ||
|
|
adb1356b7a | ||
|
|
d880ccb8e0 | ||
|
|
050fb1d1ef | ||
|
|
6580752bde | ||
|
|
c9df265c9b | ||
|
|
098e5bc162 | ||
|
|
4b2dcc74d4 | ||
|
|
a9254c5c9a | ||
|
|
7ce57e6ccb | ||
|
|
0fcb32a66f | ||
|
|
9946535f01 | ||
|
|
2b17396d6b | ||
|
|
b01d5bc237 | ||
|
|
b123860304 | ||
|
|
033f5b67db | ||
|
|
6280448dfb | ||
|
|
01cd3333e4 | ||
|
|
63050907b9 | ||
|
|
beedf7d780 | ||
|
|
6b8194261f | ||
|
|
dbb1c4d534 | ||
|
|
e6263f9ff5 | ||
|
|
6ca119c4db | ||
|
|
c483a1ab3a | ||
|
|
2e7edd033c | ||
|
|
c576902501 | ||
|
|
66c2951594 | ||
|
|
b812881cdb | ||
|
|
cdeac2c6db | ||
|
|
bca2ddd529 | ||
|
|
e7285c6499 | ||
|
|
bdff275672 | ||
|
|
bec58a1ee6 | ||
|
|
f64616748c | ||
|
|
512ce15973 | ||
|
|
ed8b301574 | ||
|
|
d22a6c019c | ||
|
|
a0cb1b9d9e | ||
|
|
a5294c62ea | ||
|
|
e155d3311c | ||
|
|
0a372b0daf | ||
|
|
69143399d1 | ||
|
|
3270d3bf96 | ||
|
|
3896a66122 | ||
|
|
b94781aef1 | ||
|
|
bed1adc367 | ||
|
|
ae54497efa | ||
|
|
06b747c221 | ||
|
|
f159beee0d | ||
|
|
49d7dea086 | ||
|
|
3e65733dc5 | ||
|
|
cc375d58bb | ||
|
|
911c7c662a | ||
|
|
aae003be33 | ||
|
|
aede03d8b2 | ||
|
|
f0f5ada7de | ||
|
|
58365121a3 | ||
|
|
d5a154d2e6 | ||
|
|
b20f369aef | ||
|
|
abb8aa0b29 | ||
|
|
5368a0f1d7 | ||
|
|
d3897eece7 | ||
|
|
a82b829da9 | ||
|
|
9f5058e81a | ||
|
|
5b19263720 | ||
|
|
9d5a0db0d9 | ||
|
|
4bd8a7014f | ||
|
|
353e96d951 | ||
|
|
149a6f92b0 | ||
|
|
d66426c137 | ||
|
|
4fc9966392 | ||
|
|
417766f0db | ||
|
|
de9ac97887 | ||
|
|
6be42f112a | ||
|
|
3895ae63c7 | ||
|
|
607d416d54 | ||
|
|
038693dc86 | ||
|
|
cc9be13544 | ||
|
|
9c1474087f | ||
|
|
831de2bcf4 | ||
|
|
eb687333bb | ||
|
|
5cc7966d54 | ||
|
|
d1a34e7a6f | ||
|
|
d63d791717 | ||
|
|
015570c741 | ||
|
|
8400ebc9c6 | ||
|
|
9f99e7c0af | ||
|
|
392c1fc399 | ||
|
|
d3cea7a89c | ||
|
|
1dcf7407e6 | ||
|
|
d543c033a3 | ||
|
|
aaa186be5e | ||
|
|
2054b5b3dd | ||
|
|
98ae5b0ca0 | ||
|
|
36c8171d0f | ||
|
|
3603eb94cc | ||
|
|
0e068d4ccf | ||
|
|
199f348ff4 | ||
|
|
b22655fb7c | ||
|
|
06cc9618ba | ||
|
|
b9019c8c7f | ||
|
|
77e133e67c | ||
|
|
571e7df807 | ||
|
|
22f4d2979a | ||
|
|
e46e366694 | ||
|
|
7b4bc23815 | ||
|
|
9ca79f767c | ||
|
|
274dba7408 | ||
|
|
31708ca29e | ||
|
|
671b025588 | ||
|
|
a7956e4856 | ||
|
|
355862025a | ||
|
|
a2a39ee0f8 | ||
|
|
ec8e39c16f | ||
|
|
88f714999e | ||
|
|
c0c2aa3be0 | ||
|
|
822044820e | ||
|
|
6ffc182142 | ||
|
|
3d54a78573 | ||
|
|
8ddf7d953a | ||
|
|
8b9e9ad103 | ||
|
|
5737224c40 | ||
|
|
ec9aacbcae | ||
|
|
9395454997 | ||
|
|
66198a8d98 | ||
|
|
96ed9a4256 | ||
|
|
10e54b2263 | ||
|
|
cf00922ad2 | ||
|
|
84e8e007a5 | ||
|
|
d07b2e773b | ||
|
|
506ef7b0b9 | ||
|
|
2cd5dae8e2 | ||
|
|
a1cd49c111 | ||
|
|
aca2973aef | ||
|
|
0a7a691c95 | ||
|
|
72906a7afd | ||
|
|
d1a4a83570 | ||
|
|
e0396b29e8 | ||
|
|
536833cfe0 | ||
|
|
317b02d1b9 | ||
|
|
75e279ea0d | ||
|
|
dc2ad21f4c | ||
|
|
484d49aae1 | ||
|
|
ca39438ad4 | ||
|
|
49a65ebff4 | ||
|
|
befdc05084 | ||
|
|
1fbffe761b | ||
|
|
36aad379ff | ||
|
|
540cfa072e | ||
|
|
3b049c15cc | ||
|
|
3e93ed0a17 | ||
|
|
d7d9358136 | ||
|
|
5cf0939ff9 | ||
|
|
8dc6f91d3c | ||
|
|
a3a25db230 | ||
|
|
c06f18c815 | ||
|
|
6802f04036 | ||
|
|
beeccdf345 | ||
|
|
58241ed39d | ||
|
|
31128020f0 | ||
|
|
6c48afc37b | ||
|
|
7a2f169dfc | ||
|
|
ed910b99a7 | ||
|
|
54195c0826 | ||
|
|
cefbbcd1df | ||
|
|
cc01592085 | ||
|
|
5a98a5252d | ||
|
|
184e8b1132 | ||
|
|
2b6b896c2e | ||
|
|
96d06b7a93 | ||
|
|
f54f1611b5 | ||
|
|
69ad757e8b | ||
|
|
e0beb796ad | ||
|
|
f331e7d820 | ||
|
|
cbb62d3d78 | ||
|
|
c85bc59c1d | ||
|
|
8081eeb007 | ||
|
|
56f91bd10d | ||
|
|
8e20b78731 | ||
|
|
23a09b7081 | ||
|
|
67fdd27499 | ||
|
|
e1941daedd | ||
|
|
f28bc568a4 | ||
|
|
f24cfe39aa | ||
|
|
59d2bf3f79 | ||
|
|
3176e54614 | ||
|
|
eb090f7265 | ||
|
|
6d3a9bfd18 | ||
|
|
76f08b7acb | ||
|
|
1ff99346aa | ||
|
|
369695ab32 | ||
|
|
7e23dd1d66 | ||
|
|
0205d3fc5c | ||
|
|
4660cf2ad5 | ||
|
|
e26d08d674 | ||
|
|
0932bf2797 | ||
|
|
f560fc6d76 | ||
|
|
aa6209af00 | ||
|
|
4a51176193 | ||
|
|
bb84f7a434 | ||
|
|
48168b1ef0 | ||
|
|
8281c7c83e | ||
|
|
a07c1e3c71 | ||
|
|
0766bb31fe | ||
|
|
ff4472c1a5 | ||
|
|
17424740e5 | ||
|
|
dad0b2fcd3 | ||
|
|
c48dbf030f | ||
|
|
617808d603 | ||
|
|
845149deee | ||
|
|
1a9e009327 | ||
|
|
ae90815708 | ||
|
|
1c460343b7 | ||
|
|
26079622f9 | ||
|
|
06c6d6096f | ||
|
|
c8183aea51 | ||
|
|
7531134ad2 | ||
|
|
cd0c6439c2 | ||
|
|
c918c93f51 | ||
|
|
97d3bd68ed | ||
|
|
75f1e034ae | ||
|
|
8e72f218f1 | ||
|
|
d643e05c5a | ||
|
|
fea44834d0 | ||
|
|
195a2d7523 | ||
|
|
b2fd346ef8 | ||
|
|
1ff8b62cb7 | ||
|
|
c7ae15a41a | ||
|
|
efe6f59f79 | ||
|
|
8e31d0491d | ||
|
|
73d4a10351 | ||
|
|
81d9d4dbc7 | ||
|
|
184ec13f99 | ||
|
|
dee0422eff | ||
|
|
81a2975f1a | ||
|
|
5cd2ef4a5e | ||
|
|
466c2a68c2 | ||
|
|
0fb9fba531 | ||
|
|
356dd2c6cd | ||
|
|
32c4661233 | ||
|
|
a245b504ec | ||
|
|
a2f5fbdfd3 | ||
|
|
04be26adc5 | ||
|
|
be0adb7cf2 | ||
|
|
84fd92bf5a | ||
|
|
ee4e061739 | ||
|
|
4a2b01cd9a | ||
|
|
efdd6460fb | ||
|
|
803827e05c | ||
|
|
a41d5e9ab3 | ||
|
|
e94333f877 | ||
|
|
6dbb80d687 | ||
|
|
31a1031624 | ||
|
|
f8e9ce0d52 | ||
|
|
11baa968cd | ||
|
|
3e5e5b376f | ||
|
|
bda18f296d | ||
|
|
287d110c84 | ||
|
|
c98275e73a | ||
|
|
aa573cc951 | ||
|
|
883d3d86e3 | ||
|
|
fb047bd5f4 | ||
|
|
66a04d8365 | ||
|
|
a0e501f9fd | ||
|
|
8b40d3346d | ||
|
|
eddf5cd250 | ||
|
|
ee5c534ca3 | ||
|
|
fd4e77ae0f | ||
|
|
b747c50aa3 | ||
|
|
deebdd86a6 | ||
|
|
b2db79cc10 | ||
|
|
bbab370b1e | ||
|
|
db4adf399d | ||
|
|
0683c87e52 | ||
|
|
3f62b647fc | ||
|
|
2562a5b30d | ||
|
|
e232f2e223 | ||
|
|
21644ff4dd | ||
|
|
be96a4fce5 | ||
|
|
a1cabcbed3 | ||
|
|
ce933b1f06 | ||
|
|
51ae130922 | ||
|
|
da1bc18a47 | ||
|
|
e7165a526b | ||
|
|
6081cc399f | ||
|
|
7c5c24e15d | ||
|
|
e3e55b4347 | ||
|
|
40d8e7d1ad | ||
|
|
59e23b89f2 | ||
|
|
cc33af8193 | ||
|
|
0e1e7eb2a9 | ||
|
|
52a28a7758 | ||
|
|
3f752d6832 | ||
|
|
fe714e9989 | ||
|
|
0d3213a379 | ||
|
|
44056629e8 | ||
|
|
54125c05d3 | ||
|
|
7d32e50f25 | ||
|
|
4af9ff49a0 | ||
|
|
23faef845c | ||
|
|
41dad4091a | ||
|
|
daf859b977 | ||
|
|
f47ba6c977 | ||
|
|
4b9b207d92 | ||
|
|
875cbf66af | ||
|
|
412d6d4fd7 | ||
|
|
91c6deeb1f | ||
|
|
6d1978fd9a | ||
|
|
52d23b6ef5 | ||
|
|
0656ccbdd9 | ||
|
|
e774ebd0a3 | ||
|
|
edbda32a84 | ||
|
|
721fa04e3c | ||
|
|
9fd8d8915d | ||
|
|
7a9f5ebdd1 | ||
|
|
a3423f0321 | ||
|
|
c37e9a4467 | ||
|
|
6157d82a0b | ||
|
|
38b27fec92 | ||
|
|
c43439bb68 | ||
|
|
8d9561d7a5 | ||
|
|
2a72cce3b7 | ||
|
|
d3bbb6fb1f | ||
|
|
7b6723e9a2 | ||
|
|
1ee741460d | ||
|
|
967b0b493b | ||
|
|
b53aaf7dde | ||
|
|
714c13bdbf | ||
|
|
651a4fd3cc | ||
|
|
505aee22bb | ||
|
|
ca3d59dc33 | ||
|
|
13890e32a1 | ||
|
|
df8976eabe | ||
|
|
3e01daa172 | ||
|
|
f6999f355b | ||
|
|
5c06b45eb1 | ||
|
|
1802bb967a | ||
|
|
d8d92f147f | ||
|
|
4a95bdd8ba | ||
|
|
db5d94d956 | ||
|
|
06f2e34bb5 | ||
|
|
2ef7a01945 | ||
|
|
d3f642551d | ||
|
|
490997157e | ||
|
|
2432af7883 | ||
|
|
7abeece3f0 | ||
|
|
3851652821 | ||
|
|
1d67d2250a | ||
|
|
37f40d8637 | ||
|
|
0224d1d59b | ||
|
|
587b94153d | ||
|
|
5124ce0302 | ||
|
|
950c4045b0 | ||
|
|
9c8ba66873 | ||
|
|
25d1d1be1b | ||
|
|
339c352505 | ||
|
|
c587081fe4 | ||
|
|
8f9b1b866b | ||
|
|
ff5ecf6182 | ||
|
|
05670cf393 | ||
|
|
f10f5d30bf | ||
|
|
0d336727e8 | ||
|
|
bf354275b3 | ||
|
|
1932bf277a | ||
|
|
192db4bb6e | ||
|
|
701efb943d | ||
|
|
b2674971f1 | ||
|
|
c907cb4cf1 | ||
|
|
bb1462b4d9 | ||
|
|
1035f0e139 | ||
|
|
8475757716 | ||
|
|
20ffd8d61b | ||
|
|
8601428c4c | ||
|
|
59998573ee | ||
|
|
293cd72001 | ||
|
|
22ab9ebb2f | ||
|
|
9136e592d3 | ||
|
|
ed8e392616 | ||
|
|
e57ce6e644 | ||
|
|
8204e46086 | ||
|
|
9e365d9f80 | ||
|
|
6b40a933e9 | ||
|
|
8520a5002f | ||
|
|
b38ed06f6e | ||
|
|
48427b1143 | ||
|
|
5d505f4ed0 | ||
|
|
0c02a08954 | ||
|
|
0221bd0f80 | ||
|
|
28216cbcb5 | ||
|
|
3e08a8cd6b | ||
|
|
67fafdeef7 | ||
|
|
cc82505b66 | ||
|
|
fd5f075f63 | ||
|
|
a115960411 | ||
|
|
e9fa4ca816 | ||
|
|
75d92bc7f0 | ||
|
|
74aa6e911e | ||
|
|
9d000c1898 | ||
|
|
b2254875b2 | ||
|
|
78d04230d5 | ||
|
|
1c04477393 | ||
|
|
2a9679c94e | ||
|
|
6009f8ecde | ||
|
|
35cdbec70a | ||
|
|
0faef542c1 | ||
|
|
8b085af6a1 | ||
|
|
e3b11a9eb2 | ||
|
|
72fc88f3c6 | ||
|
|
a5b759f268 | ||
|
|
6a9ffae25d | ||
|
|
64c031c7fe | ||
|
|
720926c50d | ||
|
|
36ec974284 | ||
|
|
cff77c39e2 | ||
|
|
056a0a1736 | ||
|
|
f301da83c6 | ||
|
|
5362231efa | ||
|
|
4bb14cad73 | ||
|
|
7f5188f5a4 | ||
|
|
a80b7aac6c | ||
|
|
83f32478fa | ||
|
|
7578ec6801 | ||
|
|
e14a32f76f | ||
|
|
58faa189ac | ||
|
|
9b4f87d44a | ||
|
|
7830a64170 | ||
|
|
8f0fa02107 | ||
|
|
e000fb5d80 | ||
|
|
566fadad15 | ||
|
|
cf23858c10 | ||
|
|
216a223617 | ||
|
|
638f38d823 | ||
|
|
98ee70f04e | ||
|
|
b365db5a4b | ||
|
|
02e55496df | ||
|
|
e11e53913a | ||
|
|
f8a5fb4225 | ||
|
|
3a49450461 | ||
|
|
3c375fb955 | ||
|
|
011fea2cc6 | ||
|
|
a079eec2cb | ||
|
|
776b37f4ea | ||
|
|
a4d8bbe3da | ||
|
|
72166743fa | ||
|
|
c4312c0b11 | ||
|
|
38ba645415 | ||
|
|
ac12a47071 | ||
|
|
bea321939e | ||
|
|
210f84b6ea | ||
|
|
d4c642741f | ||
|
|
e6b1b58379 | ||
|
|
8d982c1a90 | ||
|
|
be10e836dc | ||
|
|
9be05e7e17 | ||
|
|
bd96b2819f | ||
|
|
f601af3da0 | ||
|
|
70a01c082b | ||
|
|
bcf066ead7 | ||
|
|
24dd3578ed | ||
|
|
d5c39d54d8 | ||
|
|
6e3f6abc67 | ||
|
|
463201df2c | ||
|
|
a7501c396f | ||
|
|
4c8bc49a7e | ||
|
|
f254674f88 | ||
|
|
a97c267378 | ||
|
|
eaa947894b | ||
|
|
fb3a26510b | ||
|
|
bfe8b14e49 | ||
|
|
afb47eb742 | ||
|
|
ba97f96288 | ||
|
|
ecbafb8f4b | ||
|
|
12d3800d67 | ||
|
|
d586b82372 | ||
|
|
ba9877c9b4 | ||
|
|
907933f3df | ||
|
|
2e91d21a88 | ||
|
|
dca395a018 | ||
|
|
625070a5b9 | ||
|
|
f875c7cbf5 | ||
|
|
eed88fc103 | ||
|
|
6fc54d1d27 | ||
|
|
0ef52bf909 | ||
|
|
95e34af6ef | ||
|
|
650b99ead2 | ||
|
|
57941a19de | ||
|
|
6157db0b6a | ||
|
|
c9358acf5d | ||
|
|
ed29eb8a5d | ||
|
|
bcf7452312 | ||
|
|
b9000519e4 | ||
|
|
2694297466 | ||
|
|
53ff5c1490 | ||
|
|
32a036b076 | ||
|
|
aae2ab2693 | ||
|
|
4ef23e28a3 | ||
|
|
38beb7f8d2 | ||
|
|
0129a66906 | ||
|
|
45bced7b34 | ||
|
|
7f5a55dffb | ||
|
|
80289df6d3 | ||
|
|
2115c3ced8 | ||
|
|
1c2d0e6618 | ||
|
|
ea4f7f79ce | ||
|
|
b17f8ac311 | ||
|
|
6870d13b72 | ||
|
|
81fa304fd2 | ||
|
|
a663ddb0d9 | ||
|
|
f7969afc22 | ||
|
|
52ce4cd313 | ||
|
|
247175881f | ||
|
|
fcf5009338 | ||
|
|
12542d8f63 | ||
|
|
e94194e28b | ||
|
|
115499f3b2 | ||
|
|
12af05b94f | ||
|
|
88b83d8164 | ||
|
|
fcc22c692a | ||
|
|
a876e8005c | ||
|
|
2288e3705a | ||
|
|
e8b58154e0 | ||
|
|
4393475af3 | ||
|
|
3fc560597c | ||
|
|
9f9af0b693 | ||
|
|
a83fe2caea | ||
|
|
30c5376217 | ||
|
|
6dddd6629d | ||
|
|
f80de12cb5 | ||
|
|
544ffca3a5 | ||
|
|
e0730c7b39 | ||
|
|
3d59d141c4 | ||
|
|
ccddc2623d | ||
|
|
fcc47b58b4 | ||
|
|
f67ac2e25e | ||
|
|
26127c9ccf | ||
|
|
d624efa799 | ||
|
|
ed3d40a4e0 | ||
|
|
6e90ce5496 | ||
|
|
ab851b1be4 | ||
|
|
340de53825 | ||
|
|
a867b60af0 | ||
|
|
26eafb0bd2 | ||
|
|
0dbe44764b | ||
|
|
2159df6802 | ||
|
|
23389b9f17 | ||
|
|
6d3e3b894a | ||
|
|
55340aefa3 | ||
|
|
94bc751e41 | ||
|
|
89259c11e2 | ||
|
|
6bbaf1523c | ||
|
|
fa3f18b60f | ||
|
|
3dc794002f | ||
|
|
f50b133f2e | ||
|
|
1d6f6d28c9 | ||
|
|
c913de3c8b | ||
|
|
bbc7b54a38 | ||
|
|
05fa1b40d1 | ||
|
|
6a88c8634d | ||
|
|
8ae1efa230 | ||
|
|
ab8df4c8ab | ||
|
|
c259a46ed3 | ||
|
|
5dc0677599 | ||
|
|
7ed662ecc2 | ||
|
|
4361cc69d4 | ||
|
|
461cbcbc28 | ||
|
|
09ae6c488b | ||
|
|
271a0ade26 | ||
|
|
4b076d227a | ||
|
|
3c4e7158a1 | ||
|
|
0b16765f37 | ||
|
|
20c2ff3443 | ||
|
|
96f2e598f4 | ||
|
|
7374f0f9dd | ||
|
|
ccc44a74a0 | ||
|
|
66cd63a68d | ||
|
|
decf7e5485 | ||
|
|
063c8025aa | ||
|
|
2fa7d2bd56 | ||
|
|
e55e7bce74 | ||
|
|
f572445a65 | ||
|
|
8b4f656d90 | ||
|
|
6c1e093ebd | ||
|
|
6dd1b4537a | ||
|
|
39ca9bea72 | ||
|
|
999103277e | ||
|
|
3cc57ab89c | ||
|
|
4e830079de | ||
|
|
ea7231e9fe | ||
|
|
ddfaca6d0c | ||
|
|
3b11bd0593 | ||
|
|
3f89057528 | ||
|
|
2f1073712f | ||
|
|
678e504c48 | ||
|
|
e69545fd95 | ||
|
|
a7ed025cd6 | ||
|
|
3d8e1f2484 | ||
|
|
c38c9608da | ||
|
|
2396b75e3c | ||
|
|
e5c19b7562 | ||
|
|
114788567d | ||
|
|
17ae4b7d2a | ||
|
|
12d652bd0e | ||
|
|
ff1bed97b8 | ||
|
|
56490f0e84 | ||
|
|
0b028a8923 | ||
|
|
43ac541cb8 | ||
|
|
5218443678 | ||
|
|
d9028ed9b7 | ||
|
|
9b9bd11ebb | ||
|
|
07011ec5f7 | ||
|
|
c3990ac32f | ||
|
|
081ff3ff55 | ||
|
|
93996ada96 | ||
|
|
a60671d4c1 | ||
|
|
3f716cc369 | ||
|
|
9f23cffd1b | ||
|
|
07c416cfbf | ||
|
|
389fcc1c8d | ||
|
|
fa07811375 | ||
|
|
fc91a50979 | ||
|
|
f9c518f321 | ||
|
|
015b439f0d | ||
|
|
0675622508 | ||
|
|
e9969bdd5f | ||
|
|
1139f950ed | ||
|
|
284732c7a6 | ||
|
|
0cb0720d8b | ||
|
|
8ad1ede0c5 | ||
|
|
a349aac8a4 | ||
|
|
83b169c6ef | ||
|
|
49c37baac5 | ||
|
|
8d62088576 | ||
|
|
f5437a17f8 | ||
|
|
92af4e5c96 | ||
|
|
0619adb0cd | ||
|
|
65a5107854 | ||
|
|
0fcc1e252b | ||
|
|
4b7f817475 | ||
|
|
0439599971 | ||
|
|
fa344d5308 | ||
|
|
f0316f09ed | ||
|
|
b1af6bab28 | ||
|
|
ad2aebb54d | ||
|
|
23fc652092 | ||
|
|
f0a5756f25 | ||
|
|
14c7ad201a | ||
|
|
08ca3c89d3 | ||
|
|
edda470bf8 | ||
|
|
7183d72e5c | ||
|
|
5e38ebfce5 | ||
|
|
56e36847a5 | ||
|
|
6dba916d02 | ||
|
|
fd57086ffd | ||
|
|
d98d366eea | ||
|
|
b261b0b447 | ||
|
|
c6042a9053 | ||
|
|
ae1245abec | ||
|
|
e26d2376fc | ||
|
|
bb36ad64a7 | ||
|
|
262d4f92d4 | ||
|
|
675530458c | ||
|
|
19e34b460f | ||
|
|
dddb8cdbc0 | ||
|
|
0d0df5f143 | ||
|
|
d1cf683f57 | ||
|
|
d099c33e5b | ||
|
|
21fb41545b | ||
|
|
4c56814785 | ||
|
|
cffe05e22b | ||
|
|
4237850299 | ||
|
|
b5fc36a8e1 | ||
|
|
4586c1ef52 | ||
|
|
2722f0b749 | ||
|
|
d6cf7c4872 | ||
|
|
3aedfed432 | ||
|
|
edeaf13259 | ||
|
|
c1290c4e9b | ||
|
|
b2c1527b17 | ||
|
|
a4a65ea56e |
25
.codeclimate.yml
Normal file
25
.codeclimate.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
# Save as .codeclimate.yml (note leading .) in project root directory
|
||||
languages:
|
||||
JavaScript: true
|
||||
PHP: true
|
||||
exclude_paths:
|
||||
- "public/packages/maximebf/php-debugbar/debugbar.js"
|
||||
- "public/packages/maximebf/php-debugbar/widgets.js"
|
||||
- "public/packages/maximebf/php-debugbar/openhandler.js"
|
||||
- "public/packages/maximebf/php-debugbar/widgets/sqlqueries/widget.js"
|
||||
- "public/js/bootstrap3-typeahead.min.js"
|
||||
- "public/js/bootstrap-sortable.js"
|
||||
- "public/js/bootstrap-tagsinput.min.js"
|
||||
- "public/js/bootstrap-tagsinput.min.js.map"
|
||||
- "public/js/daterangepicker.js"
|
||||
- "public/js/jquery-2.1.3.min.js"
|
||||
- "public/js/jquery-2.1.3.min.js.map"
|
||||
- "public/js/jquery-ui.min.js"
|
||||
- "public/js/metisMenu.js"
|
||||
- "public/js/moment.min.js"
|
||||
- "public/js/sb-admin-2.js"
|
||||
- "public/bootstrap/*"
|
||||
- "resources/lang/*"
|
||||
- "tests/*"
|
||||
- "database/*"
|
||||
- "storage/*"
|
||||
@@ -1,3 +1 @@
|
||||
src_dir: .
|
||||
coverage_clover: tests/_output/coverage.xml
|
||||
json_path: tests/_output/coveralls-upload.json
|
||||
src_dir: .
|
||||
@@ -1,5 +1,5 @@
|
||||
APP_ENV=local
|
||||
APP_DEBUG=true
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_KEY=SomeRandomString
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
@@ -12,5 +12,10 @@ CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
EMAIL_SMTP=
|
||||
EMAIL_DRIVER=smtp
|
||||
EMAIL_USERNAME=
|
||||
EMAIL_PASSWORD=
|
||||
ANALYTICS_ID=
|
||||
EMAIL_PRETEND=false
|
||||
RUNCLEANUP=true
|
||||
SITE_OWNER=mail@example.com
|
||||
@@ -8,6 +8,11 @@ DB_DATABASE=homestead
|
||||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
CACHE_DRIVER=array
|
||||
SESSION_DRIVER=array
|
||||
|
||||
EMAIL_SMTP=
|
||||
EMAIL_USERNAME=
|
||||
EMAIL_PASSWORD=
|
||||
ANALYTICS_ID=ABC
|
||||
EMAIL_PRETEND=true
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -25,3 +25,11 @@ c3.php
|
||||
db.sqlite-journal
|
||||
tests/_output/*
|
||||
.env
|
||||
clover.xml
|
||||
node_modules/
|
||||
addNewLines.php
|
||||
.phpstorm.meta.php
|
||||
.env.backup
|
||||
.env.local
|
||||
|
||||
tests/_output/*
|
||||
22
.jshintrc
Normal file
22
.jshintrc
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"undef": true,
|
||||
"unused": false,
|
||||
"strict": true,
|
||||
"browser": true,
|
||||
"jquery": true,
|
||||
"devel": true,
|
||||
"globals": [
|
||||
"language",
|
||||
"token",
|
||||
"currencyCode",
|
||||
"$",
|
||||
"token",
|
||||
"accountID",
|
||||
"billID",
|
||||
"currentMonthName",
|
||||
"previousMonthName",
|
||||
"nextMonthName",
|
||||
"everything",
|
||||
"moment"
|
||||
]
|
||||
}
|
||||
3
.scrutinizer.yml
Normal file
3
.scrutinizer.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
# .scrutinizer.yml
|
||||
tools:
|
||||
external_code_coverage: false
|
||||
19
.travis.yml
19
.travis.yml
@@ -1,26 +1,15 @@
|
||||
language: php
|
||||
sudo: false
|
||||
|
||||
|
||||
php:
|
||||
- 5.5
|
||||
- 5.6
|
||||
|
||||
addons:
|
||||
code_climate:
|
||||
repo_token: 26489f9e854fcdf7e7660ba29c1455694685465b1f90329a79f7d2bf448acb61
|
||||
|
||||
install:
|
||||
- rm composer.lock
|
||||
- composer install
|
||||
- composer update
|
||||
- php artisan env
|
||||
- mv -v .env.testing .env
|
||||
|
||||
script:
|
||||
- ./tests/_data/db.sh
|
||||
- php vendor/bin/codecept build
|
||||
- php vendor/bin/codecept run --coverage --coverage-xml --no-exit
|
||||
|
||||
after_script:
|
||||
- cp -v tests/_output/coverage.xml build/logs/clover.xml
|
||||
- php vendor/bin/coveralls
|
||||
- vendor/bin/test-reporter --stdout > codeclimate.json
|
||||
- "curl -X POST -d @codeclimate.json -H 'Content-Type: application/json' -H 'User-Agent: Code Climate (PHP Test Reporter v0.1.1)' https://codeclimate.com/test_reports"
|
||||
- phpunit
|
||||
|
||||
143
README.md
143
README.md
@@ -1,76 +1,115 @@
|
||||
Firefly III (v3.3)
|
||||
===========
|
||||
# Firefly III
|
||||
|
||||
[](https://travis-ci.org/JC5/firefly-iii)
|
||||
[](http://stillmaintained.com/JC5/firefly-iii)
|
||||
[](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102)
|
||||
[](https://codeclimate.com/github/JC5/firefly-iii)
|
||||
[](https://codeclimate.com/github/JC5/firefly-iii)
|
||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
||||
|
||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
||||
[](https://scrutinizer-ci.com/g/JC5/firefly-iii/?branch=master)
|
||||
[](https://scrutinizer-ci.com/g/JC5/firefly-iii/build-status/master)
|
||||
|
||||
Firefly III is a tool to help you manage your finances. Please read the full description [in the wiki](https://github.com/JC5/firefly-iii/wiki/full-description).
|
||||
## About
|
||||
|
||||
Firefly Mark III is a new version of Firefly built upon best practices and lessons learned
|
||||
from building [Firefly](https://github.com/JC5/Firefly). It's Mark III since the original Firefly never made it outside of my
|
||||
laptop and [Firefly II](https://github.com/JC5/Firefly) is live.
|
||||
"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 is a system you'll have install yourself on webhosting of your choosing._
|
||||
|
||||
Personal financial management is pretty difficult, and everybody has their own approach to it. Some people
|
||||
make budgets, other people limit their cashflow by throwing away their credit cards, others try to increase
|
||||
their current cashflow. There are tons of ways to save and earn money.
|
||||
|
||||
Firefly works on the principle that if you know where you're money is going, you can stop it from going there.
|
||||
|
||||
|
||||
To get to know Firefly, and to see if it fits you, check out these resources:
|
||||
|
||||
- The screenshots below on this very page.
|
||||
- The featurelist below, also on this very page.
|
||||
- The [full description](https://github.com/JC5/firefly-iii/wiki/full-description), which will tell you how Firefly works,
|
||||
and the philosophy behind it.
|
||||
|
||||
|
||||
#### About the name (should you care)
|
||||
|
||||
It's III, or 3, because [version 2](https://github.com/JC5/Firefly) and version 1 (not online) preceded it. It has been growing steadily ever since.
|
||||
|
||||
## Current features
|
||||
|
||||
- [A double-entry bookkeeping system](http://en.wikipedia.org/wiki/Double-entry_bookkeeping_system);
|
||||
- You can store, edit and remove withdrawals, deposits and transfers. This allows you full financial management;
|
||||
- It's possible to create, change and manage money using _budgets_;
|
||||
- [A double-entry bookkeeping system](https://en.wikipedia.org/wiki/Double-entry_bookkeeping_system);
|
||||
- You can store, edit and remove [withdrawals, deposits and transfers](https://en.wikipedia.org/wiki/Financial_transaction). This allows you full financial management;
|
||||
- You can manage different types of accounts;
|
||||
- [Asset](https://en.wikipedia.org/wiki/Asset) accounts
|
||||
- Shared [asset accounts](https://en.wikipedia.org/wiki/Asset) ([household accounts](https://en.wikipedia.org/wiki/Household))
|
||||
- Saving accounts
|
||||
- Credit cards
|
||||
- It's possible to create, change and manage money using _[budgets](https://en.wikipedia.org/wiki/Envelope_system)_;
|
||||
- Organize transactions using categories;
|
||||
- Save towards a goal using piggy banks;
|
||||
- Predict and anticipate large expenses using "repeated expenses" (ie. yearly taxes);
|
||||
- Predict and anticipate bills using "recurring transactions" (rent for example);
|
||||
- View basic income / expense reports.
|
||||
- Lots of help text in case you don't get it;
|
||||
- Save towards a goal using [piggy banks](https://en.wikipedia.org/wiki/Piggy_bank);
|
||||
- Predict and anticipate [bills](https://en.wikipedia.org/wiki/Invoice);
|
||||
- View income / expense [reports](https://en.wikipedia.org/wiki/Financial_statement);
|
||||
- Organize expenses using tags;
|
||||
- Lots of help text in case you don't get it.
|
||||
|
||||
Everything is organised:
|
||||
|
||||
- Clear views that should show you how you're doing;
|
||||
- Easy navigation through your records;
|
||||
- Browse back and forth to see previous months or even years;
|
||||
- Lots of charts because we all love them.
|
||||
- Financial reporting showing you how well you are doing;
|
||||
|
||||
## Changes
|
||||
|
||||
Firefly III will feature, but does not feature yet:
|
||||
|
||||
|
||||
- More control over other resources outside of personal finance
|
||||
- Accounts shared with a partner (household accounts)
|
||||
- Debts
|
||||
- Credit cards
|
||||
- More test-coverage;
|
||||
- Firefly will be able to split transactions; a single purchase can be split in multiple entries, for more fine-grained control.
|
||||
- Firefly will be able to join transactions.
|
||||
- Any other features I might not have thought of.
|
||||
|
||||
Some stuff has been removed:
|
||||
|
||||
- The nesting of budgets, categories and beneficiaries is removed because it was pretty pointless.
|
||||
- Firefly will not encrypt the content of the (MySQL) tables. Old versions of Firefly had this capability but it sucks when searching, sorting and organizing entries.
|
||||
- Lots of charts because we all love them;
|
||||
- Financial reporting showing you how well you are doing.
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
_Please note that everything in these screenshots is fictional and may not be realistic._
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Running and installing
|
||||
|
||||
If you're still interested please read [the installation guide](https://github.com/JC5/firefly-iii/wiki/Installation),
|
||||
[the upgrade guide](https://github.com/JC5/firefly-iii/wiki/Upgrade-instructions) (if applicable)
|
||||
and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**.
|
||||
|
||||
If you want to try out Firefly III, you can do so on [this dedicated website](https://geld.nder.be/).
|
||||
This site always runs the latest version of Firefly III. If you want to use it, please read the [privacy considerations](https://github.com/JC5/firefly-iii/wiki/Privacy-on-demo-site) for this demo-site.
|
||||
|
||||
## Credits
|
||||
|
||||
Firefly III uses the following libraries and tools:
|
||||
|
||||
* The AdminLTE template by [Almsaseed Studio](https://almsaeedstudio.com/)
|
||||
* The [Google charts](https://developers.google.com/chart/) library.
|
||||
* [Bootstrap](http://getbootstrap.com/)
|
||||
* [Laravel](http://laravel.com/)
|
||||
* [Twig](http://twig.sensiolabs.org/)
|
||||
* For development, some of the excellent tools made by [Barry van den Heuvel](https://github.com/barryvdh)
|
||||
* [Bootstrap sortable](https://github.com/drvic10k/bootstrap-sortable) by [Matúš Brliť](https://github.com/drvic10k).
|
||||
* [Date range picker](https://github.com/dangrossman/bootstrap-daterangepicker/) by [Dan Grossman](https://github.com/dangrossman)
|
||||
* The [real favicon generator](http://realfavicongenerator.net/)
|
||||
* Various other open source components (see [composer.json](https://github.com/JC5/firefly-iii/blob/master/composer.json))
|
||||
|
||||

|
||||
|
||||
## Current state
|
||||
I have the basics up and running. Test coverage is currently coming, slowly.
|
||||
|
||||
Although I have not checked extensively, some forms and views have CSRF vulnerabilities. This is because not all
|
||||
views escape all characters by default. Will be fixed.
|
||||
Firefly III is pretty much all grown up. Full test coverage (nerd alert!) is coming. Translations are a work in progress.
|
||||
|
||||
Questions, ideas or other things to contribute? [Let me know](https://github.com/JC5/firefly-iii/issues/new)!
|
||||
Questions, ideas, bugs or other things to contribute? [Let me know](https://github.com/JC5/firefly-iii/issues/new)!
|
||||
|
||||
If you like this tool, feel free to [donate me some beer money](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2ZMV952UUSCLU&lc=NL&item_name=Development%20of%20Firefly¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted).
|
||||
|
||||
[](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102)
|
||||
[](https://codeclimate.com/github/JC5/firefly-iii)
|
||||
[](http://stillmaintained.com/JC5/firefly-iii)
|
||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
||||

|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/**
|
||||
* Class Command
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Commands
|
||||
*/
|
||||
abstract class Command
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php namespace FireflyIII\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Foundation\Inspiring;
|
||||
|
||||
/**
|
||||
* Class Inspire
|
||||
*
|
||||
* @package FireflyIII\Console\Commands
|
||||
*/
|
||||
class Inspire extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Display an inspiring quote';
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'inspire';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->comment(PHP_EOL . Inspiring::quote() . PHP_EOL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
/**
|
||||
* Class Kernel
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Console
|
||||
*/
|
||||
class Kernel extends ConsoleKernel
|
||||
@@ -18,7 +19,6 @@ class Kernel extends ConsoleKernel
|
||||
*/
|
||||
protected $commands
|
||||
= [
|
||||
'FireflyIII\Console\Commands\Inspire',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -26,12 +26,12 @@ class Kernel extends ConsoleKernel
|
||||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
$schedule->command('inspire')
|
||||
->hourly();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/**
|
||||
* Class Event
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Events
|
||||
*/
|
||||
abstract class Event
|
||||
|
||||
34
app/Events/JournalCreated.php
Normal file
34
app/Events/JournalCreated.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php namespace FireflyIII\Events;
|
||||
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class JournalCreated
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Events
|
||||
*/
|
||||
class JournalCreated extends Event
|
||||
{
|
||||
|
||||
use SerializesModels;
|
||||
|
||||
public $journal;
|
||||
public $piggyBankId;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @param $piggyBankId
|
||||
*/
|
||||
public function __construct(TransactionJournal $journal, $piggyBankId)
|
||||
{
|
||||
//
|
||||
$this->journal = $journal;
|
||||
$this->piggyBankId = $piggyBankId;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class JournalDeleted
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Events
|
||||
*/
|
||||
class JournalDeleted extends Event
|
||||
{
|
||||
|
||||
@@ -10,7 +16,6 @@ class JournalDeleted extends Event
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
30
app/Events/JournalSaved.php
Normal file
30
app/Events/JournalSaved.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php namespace FireflyIII\Events;
|
||||
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class JournalSaved
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Events
|
||||
*/
|
||||
class JournalSaved extends Event
|
||||
{
|
||||
|
||||
use SerializesModels;
|
||||
|
||||
public $journal;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*/
|
||||
public function __construct(TransactionJournal $journal)
|
||||
{
|
||||
//
|
||||
$this->journal = $journal;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ namespace FireflyIII\Exceptions;
|
||||
/**
|
||||
* Class FireflyException
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Exceptions
|
||||
*/
|
||||
class FireflyException extends \Exception
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
/**
|
||||
* Class Handler
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Exceptions
|
||||
*/
|
||||
class Handler extends ExceptionHandler
|
||||
@@ -26,12 +28,13 @@ class Handler extends ExceptionHandler
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Exception $e
|
||||
* @SuppressWarnings(PHPMD.ShortVariable)
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function render($request, Exception $e)
|
||||
{
|
||||
if ($this->isHttpException($e)) {
|
||||
if ($e instanceof HttpException) {
|
||||
return $this->renderHttpException($e);
|
||||
} else {
|
||||
return parent::render($request, $e);
|
||||
@@ -42,6 +45,7 @@ class Handler extends ExceptionHandler
|
||||
* Report or log an exception.
|
||||
*
|
||||
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
|
||||
* @SuppressWarnings(PHPMD.ShortVariable)
|
||||
*
|
||||
* @param \Exception $e
|
||||
*
|
||||
@@ -49,8 +53,7 @@ class Handler extends ExceptionHandler
|
||||
*/
|
||||
public function report(Exception $e)
|
||||
{
|
||||
/** @noinspection PhpInconsistentReturnPointsInspection */
|
||||
return parent::report($e);
|
||||
parent::report($e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace FireflyIII\Exceptions;
|
||||
/**
|
||||
* Class NotImplementedException
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Exceptions
|
||||
*/
|
||||
class NotImplementedException extends \Exception
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace FireflyIII\Exceptions;
|
||||
/**
|
||||
* Class ValidationExceptions
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Exception
|
||||
*/
|
||||
class ValidationException extends \Exception
|
||||
|
||||
43
app/Generator/Chart/Account/AccountChartGenerator.php
Normal file
43
app/Generator/Chart/Account/AccountChartGenerator.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Account;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface AccountChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Account
|
||||
*/
|
||||
interface AccountChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all(Collection $accounts, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $accounts, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function single(Account $account, Carbon $start, Carbon $end);
|
||||
}
|
||||
114
app/Generator/Chart/Account/ChartJsAccountChartGenerator.php
Normal file
114
app/Generator/Chart/Account/ChartJsAccountChartGenerator.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Account;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use FireflyIII\Models\Account;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class ChartJsAccountChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Account
|
||||
*/
|
||||
class ChartJsAccountChartGenerator implements AccountChartGenerator
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @param Collection $accounts
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all(Collection $accounts, Carbon $start, Carbon $end)
|
||||
{
|
||||
return $this->frontpage($accounts, $start, $end);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $accounts, Carbon $start, Carbon $end)
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.monthAndDay.' . $language);
|
||||
$data = [
|
||||
'count' => 0,
|
||||
'labels' => [],
|
||||
'datasets' => [],
|
||||
];
|
||||
$current = clone $start;
|
||||
while ($current <= $end) {
|
||||
$data['labels'][] = $current->formatLocalized($format);
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
$set = [
|
||||
'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' => [],
|
||||
];
|
||||
$current = clone $start;
|
||||
while ($current <= $end) {
|
||||
$set['data'][] = Steam::balance($account, $current);
|
||||
$current->addDay();
|
||||
}
|
||||
$data['datasets'][] = $set;
|
||||
}
|
||||
$data['count'] = count($data['datasets']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function single(Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.monthAndDay.' . $language);
|
||||
|
||||
$data = [
|
||||
'count' => 1,
|
||||
'labels' => [],
|
||||
'datasets' => [
|
||||
[
|
||||
'label' => $account->name,
|
||||
'data' => []
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
$current = clone $start;
|
||||
|
||||
while ($end >= $current) {
|
||||
$data['labels'][] = $current->formatLocalized($format);
|
||||
$data['datasets'][0]['data'][] = Steam::balance($account, $current);
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
122
app/Generator/Chart/Account/GoogleAccountChartGenerator.php
Normal file
122
app/Generator/Chart/Account/GoogleAccountChartGenerator.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Account;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use Grumpydictator\Gchart\GChart;
|
||||
use Illuminate\Support\Collection;
|
||||
use Steam;
|
||||
|
||||
|
||||
/**
|
||||
* Class GoogleAccountChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Account
|
||||
*/
|
||||
class GoogleAccountChartGenerator implements AccountChartGenerator
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all(Collection $accounts, Carbon $start, Carbon $end)
|
||||
{
|
||||
// make chart (original code):
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.dayOfMonth'), 'date');
|
||||
$index = 1;
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$chart->addColumn(trans('firefly.balanceFor', ['name' => $account->name]), 'number');
|
||||
$chart->addCertainty($index);
|
||||
$index++;
|
||||
}
|
||||
$current = clone $start;
|
||||
$current->subDay();
|
||||
$today = Carbon::now();
|
||||
while ($end >= $current) {
|
||||
$row = [clone $current];
|
||||
$certain = $current < $today;
|
||||
foreach ($accounts as $account) {
|
||||
$row[] = Steam::balance($account, $current);
|
||||
$row[] = $certain;
|
||||
}
|
||||
$chart->addRowArray($row);
|
||||
$current->addDay();
|
||||
}
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $accounts, Carbon $start, Carbon $end)
|
||||
{
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.dayOfMonth'), 'date');
|
||||
|
||||
$index = 1;
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$chart->addColumn(trans('firefly.balanceFor', ['name' => $account->name]), 'number');
|
||||
$chart->addCertainty($index);
|
||||
$index++;
|
||||
}
|
||||
$current = clone $start;
|
||||
$current->subDay();
|
||||
$today = Carbon::now();
|
||||
while ($end >= $current) {
|
||||
$row = [clone $current];
|
||||
$certain = $current < $today;
|
||||
foreach ($accounts as $account) {
|
||||
$row[] = Steam::balance($account, $current);
|
||||
$row[] = $certain;
|
||||
}
|
||||
$chart->addRowArray($row);
|
||||
$current->addDay();
|
||||
}
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function single(Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
$current = clone $start;
|
||||
$today = new Carbon;
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.dayOfMonth'), 'date');
|
||||
$chart->addColumn(trans('firefly.balanceFor', ['name' => $account->name]), 'number');
|
||||
$chart->addCertainty(1);
|
||||
|
||||
while ($end >= $current) {
|
||||
$certain = $current < $today;
|
||||
$chart->addRow(clone $current, Steam::balance($account, $current), $certain);
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
}
|
||||
32
app/Generator/Chart/Bill/BillChartGenerator.php
Normal file
32
app/Generator/Chart/Bill/BillChartGenerator.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace FireflyIII\Generator\Chart\Bill;
|
||||
|
||||
|
||||
use FireflyIII\Models\Bill;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface BillChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Bill
|
||||
*/
|
||||
interface BillChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $paid
|
||||
* @param Collection $unpaid
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $paid, Collection $unpaid);
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function single(Bill $bill, Collection $entries);
|
||||
|
||||
}
|
||||
125
app/Generator/Chart/Bill/ChartJsBillChartGenerator.php
Normal file
125
app/Generator/Chart/Bill/ChartJsBillChartGenerator.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: sander
|
||||
* Date: 27/06/15
|
||||
* Time: 17:21
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Bill;
|
||||
|
||||
use Config;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class ChartJsBillChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Bill
|
||||
*/
|
||||
class ChartJsBillChartGenerator implements BillChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $paid
|
||||
* @param Collection $unpaid
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $paid, Collection $unpaid)
|
||||
{
|
||||
|
||||
// loop paid and create single entry:
|
||||
$paidDescriptions = [];
|
||||
$paidAmount = 0;
|
||||
$unpaidDescriptions = [];
|
||||
$unpaidAmount = 0;
|
||||
|
||||
|
||||
/** @var TransactionJournal $entry */
|
||||
foreach ($paid as $entry) {
|
||||
|
||||
$paidDescriptions[] = $entry->description;
|
||||
$paidAmount += floatval($entry->amount);
|
||||
}
|
||||
|
||||
// loop unpaid:
|
||||
/** @var Bill $entry */
|
||||
foreach ($unpaid as $entry) {
|
||||
$description = $entry[0]->name . ' (' . $entry[1]->format('jS M Y') . ')';
|
||||
$amount = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
|
||||
$unpaidDescriptions[] = $description;
|
||||
$unpaidAmount += $amount;
|
||||
unset($amount, $description);
|
||||
}
|
||||
|
||||
$data = [
|
||||
[
|
||||
'value' => $unpaidAmount,
|
||||
'color' => 'rgba(53, 124, 165,0.7)',
|
||||
'highlight' => 'rgba(53, 124, 165,0.9)',
|
||||
'label' => trans('firefly.unpaid'),
|
||||
],
|
||||
[
|
||||
'value' => $paidAmount,
|
||||
'color' => 'rgba(0, 141, 76, 0.7)',
|
||||
'highlight' => 'rgba(0, 141, 76, 0.9)',
|
||||
'label' => trans('firefly.paid'),
|
||||
]
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function single(Bill $bill, Collection $entries)
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
|
||||
$data = [
|
||||
'count' => 3,
|
||||
'labels' => [],
|
||||
'datasets' => [],
|
||||
];
|
||||
|
||||
// dataset: max amount
|
||||
// dataset: min amount
|
||||
// dataset: actual amount
|
||||
|
||||
$minAmount = [];
|
||||
$maxAmount = [];
|
||||
$actualAmount = [];
|
||||
foreach ($entries as $entry) {
|
||||
$data['labels'][] = $entry->date->formatLocalized($format);
|
||||
$minAmount[] = round($bill->amount_min, 2);
|
||||
$maxAmount[] = round($bill->amount_max, 2);
|
||||
$actualAmount[] = round($entry->amount, 2);
|
||||
}
|
||||
|
||||
$data['datasets'][] = [
|
||||
'label' => trans('firefly.minAmount'),
|
||||
'data' => $minAmount,
|
||||
];
|
||||
$data['datasets'][] = [
|
||||
'label' => trans('firefly.billEntry'),
|
||||
'data' => $actualAmount,
|
||||
];
|
||||
$data['datasets'][] = [
|
||||
'label' => trans('firefly.maxAmount'),
|
||||
'data' => $maxAmount,
|
||||
];
|
||||
|
||||
$data['count'] = count($data['datasets']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
87
app/Generator/Chart/Bill/GoogleBillChartGenerator.php
Normal file
87
app/Generator/Chart/Bill/GoogleBillChartGenerator.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Bill;
|
||||
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Grumpydictator\Gchart\GChart;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class GoogleBillChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Bill
|
||||
*/
|
||||
class GoogleBillChartGenerator implements BillChartGenerator
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Collection $paid
|
||||
* @param Collection $unpaid
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $paid, Collection $unpaid)
|
||||
{
|
||||
// loop paid and create single entry:
|
||||
$paidDescriptions = [];
|
||||
$paidAmount = 0;
|
||||
$unpaidDescriptions = [];
|
||||
$unpaidAmount = 0;
|
||||
|
||||
|
||||
/** @var TransactionJournal $entry */
|
||||
foreach ($paid as $entry) {
|
||||
|
||||
$paidDescriptions[] = $entry->description;
|
||||
$paidAmount += floatval($entry->amount);
|
||||
}
|
||||
|
||||
// loop unpaid:
|
||||
/** @var Bill $entry */
|
||||
foreach ($unpaid as $entry) {
|
||||
$description = $entry[0]->name . ' (' . $entry[1]->format('jS M Y') . ')';
|
||||
$amount = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
|
||||
$unpaidDescriptions[] = $description;
|
||||
$unpaidAmount += $amount;
|
||||
unset($amount, $description);
|
||||
}
|
||||
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.name'), 'string');
|
||||
$chart->addColumn(trans('firefly.amount'), 'number');
|
||||
|
||||
$chart->addRow(trans('firefly.unpaid') . ': ' . join(', ', $unpaidDescriptions), $unpaidAmount);
|
||||
$chart->addRow(trans('firefly.paid') . ': ' . join(', ', $paidDescriptions), $paidAmount);
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function single(Bill $bill, Collection $entries)
|
||||
{
|
||||
// make chart:
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.date'), 'date');
|
||||
$chart->addColumn(trans('firefly.maxAmount'), 'number');
|
||||
$chart->addColumn(trans('firefly.minAmount'), 'number');
|
||||
$chart->addColumn(trans('firefly.billEntry'), 'number');
|
||||
|
||||
/** @var TransactionJournal $result */
|
||||
foreach ($entries as $result) {
|
||||
$chart->addRow(clone $result->date, floatval($bill->amount_max), floatval($bill->amount_min), floatval($result->amount));
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
}
|
||||
43
app/Generator/Chart/Budget/BudgetChartGenerator.php
Normal file
43
app/Generator/Chart/Budget/BudgetChartGenerator.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Budget;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface BudgetChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Budget
|
||||
*/
|
||||
interface BudgetChartGenerator
|
||||
{
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function budget(Collection $entries);
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function budgetLimit(Collection $entries);
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $entries);
|
||||
|
||||
/**
|
||||
* @param Collection $budgets
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function year(Collection $budgets, Collection $entries);
|
||||
|
||||
}
|
||||
144
app/Generator/Chart/Budget/ChartJsBudgetChartGenerator.php
Normal file
144
app/Generator/Chart/Budget/ChartJsBudgetChartGenerator.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Budget;
|
||||
|
||||
|
||||
use Config;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class ChartJsBudgetChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Budget
|
||||
*/
|
||||
class ChartJsBudgetChartGenerator implements BudgetChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
* @param string $dateFormat
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function budget(Collection $entries, $dateFormat = 'month')
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.' . $dateFormat . '.' . $language);
|
||||
|
||||
$data = [
|
||||
'count' => 1,
|
||||
'labels' => [],
|
||||
'datasets' => [
|
||||
[
|
||||
'label' => 'Amount',
|
||||
'data' => [],
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$data['labels'][] = $entry[0]->formatLocalized($format);
|
||||
$data['datasets'][0]['data'][] = $entry[1];
|
||||
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function budgetLimit(Collection $entries)
|
||||
{
|
||||
return $this->budget($entries, 'monthAndDay');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $entries)
|
||||
{
|
||||
$data = [
|
||||
'count' => 0,
|
||||
'labels' => [],
|
||||
'datasets' => [],
|
||||
];
|
||||
// dataset: left
|
||||
// dataset: spent
|
||||
// dataset: overspent
|
||||
$left = [];
|
||||
$spent = [];
|
||||
$overspent = [];
|
||||
foreach ($entries as $entry) {
|
||||
if ($entry[1] != 0 || $entry[2] != 0 || $entry[3] != 0) {
|
||||
$data['labels'][] = $entry[0];
|
||||
$left[] = round($entry[1], 2);
|
||||
$spent[] = round($entry[2], 2);
|
||||
$overspent[] = round($entry[3], 2);
|
||||
}
|
||||
}
|
||||
|
||||
$data['datasets'][] = [
|
||||
'label' => trans('firefly.left'),
|
||||
'data' => $left,
|
||||
];
|
||||
$data['datasets'][] = [
|
||||
'label' => trans('firefly.spent'),
|
||||
'data' => $spent,
|
||||
];
|
||||
$data['datasets'][] = [
|
||||
'label' => trans('firefly.overspent'),
|
||||
'data' => $overspent,
|
||||
];
|
||||
|
||||
$data['count'] = count($data['datasets']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $budgets
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function year(Collection $budgets, Collection $entries)
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
|
||||
$data = [
|
||||
'count' => 0,
|
||||
'labels' => [],
|
||||
'datasets' => [],
|
||||
];
|
||||
|
||||
foreach ($budgets as $budget) {
|
||||
$data['labels'][] = $budget->name;
|
||||
}
|
||||
/** @var array $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$array = [
|
||||
'label' => $entry[0]->formatLocalized($format),
|
||||
'data' => [],
|
||||
];
|
||||
array_shift($entry);
|
||||
$array['data'] = $entry;
|
||||
$data['datasets'][] = $array;
|
||||
|
||||
}
|
||||
$data['count'] = count($data['datasets']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
101
app/Generator/Chart/Budget/GoogleBudgetChartGenerator.php
Normal file
101
app/Generator/Chart/Budget/GoogleBudgetChartGenerator.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Budget;
|
||||
|
||||
use Grumpydictator\Gchart\GChart;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class GoogleBudgetChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Budget
|
||||
*/
|
||||
class GoogleBudgetChartGenerator implements BudgetChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function budget(Collection $entries)
|
||||
{
|
||||
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.period'), 'date');
|
||||
$chart->addColumn(trans('firefly.spent'), 'number');
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$chart->addRow($entry[0], $entry[1]);
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function budgetLimit(Collection $entries)
|
||||
{
|
||||
return $this->budget($entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $entries)
|
||||
{
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.budget'), 'string');
|
||||
$chart->addColumn(trans('firefly.left'), 'number');
|
||||
$chart->addColumn(trans('firefly.spent'), 'number');
|
||||
$chart->addColumn(trans('firefly.overspent'), 'number');
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($entries as $entry) {
|
||||
if ($entry[1] != 0 || $entry[2] != 0 || $entry[3] != 0) {
|
||||
$chart->addRow($entry[0], $entry[1], $entry[2], $entry[3]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $budgets
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function year(Collection $budgets, Collection $entries)
|
||||
{
|
||||
$chart = new GChart;
|
||||
// add columns:
|
||||
$chart->addColumn(trans('firefly.month'), 'date');
|
||||
foreach ($budgets as $budget) {
|
||||
$chart->addColumn($budget->name, 'number');
|
||||
}
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($entries as $entry) {
|
||||
|
||||
$chart->addRowArray($entry);
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
}
|
||||
44
app/Generator/Chart/Category/CategoryChartGenerator.php
Normal file
44
app/Generator/Chart/Category/CategoryChartGenerator.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Category;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface CategoryChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Category
|
||||
*/
|
||||
interface CategoryChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all(Collection $entries);
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $entries);
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function month(Collection $entries);
|
||||
|
||||
|
||||
/**
|
||||
* @param Collection $categories
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function year(Collection $categories, Collection $entries);
|
||||
}
|
||||
122
app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php
Normal file
122
app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Category;
|
||||
|
||||
use Config;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
|
||||
|
||||
/**
|
||||
* Class ChartJsCategoryChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Category
|
||||
*/
|
||||
class ChartJsCategoryChartGenerator implements CategoryChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
* @param string $dateFormat
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all(Collection $entries, $dateFormat = 'month')
|
||||
{
|
||||
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.' . $dateFormat . '.' . $language);
|
||||
|
||||
$data = [
|
||||
'count' => 1,
|
||||
'labels' => [],
|
||||
'datasets' => [
|
||||
[
|
||||
'label' => trans('firefly.spent'),
|
||||
'data' => []
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
$data['labels'][] = $entry[0]->formatLocalized($format);
|
||||
$data['datasets'][0]['data'][] = round($entry[1], 2);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $entries)
|
||||
{
|
||||
$data = [
|
||||
'count' => 1,
|
||||
'labels' => [],
|
||||
'datasets' => [
|
||||
[
|
||||
'label' => trans('firefly.spent'),
|
||||
'data' => []
|
||||
]
|
||||
],
|
||||
];
|
||||
foreach ($entries as $entry) {
|
||||
if ($entry['sum'] != 0) {
|
||||
$data['labels'][] = $entry['name'];
|
||||
$data['datasets'][0]['data'][] = round($entry['sum'], 2);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function month(Collection $entries)
|
||||
{
|
||||
return $this->all($entries, 'monthAndDay');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $categories
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function year(Collection $categories, Collection $entries)
|
||||
{
|
||||
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
|
||||
$data = [
|
||||
'count' => 0,
|
||||
'labels' => [],
|
||||
'datasets' => [],
|
||||
];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
$data['labels'][] = $category->name;
|
||||
}
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
$date = $entry[0]->formatLocalized($format);
|
||||
array_shift($entry);
|
||||
$data['count']++;
|
||||
$data['datasets'][] = ['label' => $date, 'data' => $entry];
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
||||
}
|
||||
}
|
||||
105
app/Generator/Chart/Category/GoogleCategoryChartGenerator.php
Normal file
105
app/Generator/Chart/Category/GoogleCategoryChartGenerator.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Category;
|
||||
|
||||
use Grumpydictator\Gchart\GChart;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class GoogleCategoryChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Category
|
||||
*/
|
||||
class GoogleCategoryChartGenerator implements CategoryChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function all(Collection $entries)
|
||||
{
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.period'), 'date');
|
||||
$chart->addColumn(trans('firefly.spent'), 'number');
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$chart->addRow($entry[0], $entry[1]);
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function frontpage(Collection $entries)
|
||||
{
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.category'), 'string');
|
||||
$chart->addColumn(trans('firefly.spent'), 'number');
|
||||
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$sum = $entry['sum'];
|
||||
if ($sum != 0) {
|
||||
$chart->addRow($entry['name'], $sum);
|
||||
}
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function month(Collection $entries)
|
||||
{
|
||||
$chart = new GChart;
|
||||
|
||||
$chart->addColumn(trans('firefly.period'), 'date');
|
||||
$chart->addColumn(trans('firefly.spent'), 'number');
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$chart->addRow($entry[0], $entry[1]);
|
||||
}
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $categories
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function year(Collection $categories, Collection $entries)
|
||||
{
|
||||
$chart = new GChart;
|
||||
|
||||
$chart->addColumn(trans('firefly.month'), 'date');
|
||||
foreach ($categories as $category) {
|
||||
$chart->addColumn($category->name, 'number');
|
||||
}
|
||||
/** @var array $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$chart->addRowArray($entry);
|
||||
}
|
||||
$chart->generate();
|
||||
return $chart->getData();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\PiggyBank;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
|
||||
|
||||
/**
|
||||
* Class GooglePiggyBankChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\PiggyBank
|
||||
*/
|
||||
class ChartJsPiggyBankChartGenerator implements PiggyBankChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function history(Collection $set)
|
||||
{
|
||||
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
|
||||
$data = [
|
||||
'count' => 1,
|
||||
'labels' => [],
|
||||
'datasets' => [
|
||||
[
|
||||
'label' => 'Diff',
|
||||
'data' => []
|
||||
]
|
||||
],
|
||||
];
|
||||
$sum = '0';
|
||||
bcscale(2);
|
||||
foreach ($set as $entry) {
|
||||
$date = new Carbon($entry->date);
|
||||
$sum = bcadd($sum, $entry->sum);
|
||||
$data['labels'][] = $date->formatLocalized($format);
|
||||
$data['datasets'][0]['data'][] = round($sum, 2);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\PiggyBank;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Grumpydictator\Gchart\GChart;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
|
||||
/**
|
||||
* Class GooglePiggyBankChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\PiggyBank
|
||||
*/
|
||||
class GooglePiggyBankChartGenerator implements PiggyBankChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function history(Collection $set)
|
||||
{
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.date'), 'date');
|
||||
$chart->addColumn(trans('firefly.balance'), 'number');
|
||||
|
||||
$sum = '0';
|
||||
bcscale(2);
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$sum = bcadd($sum, $entry->sum);
|
||||
$chart->addRow(new Carbon($entry->date), $sum);
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
}
|
||||
20
app/Generator/Chart/PiggyBank/PiggyBankChartGenerator.php
Normal file
20
app/Generator/Chart/PiggyBank/PiggyBankChartGenerator.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\PiggyBank;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface PiggyBankChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\PiggyBank
|
||||
*/
|
||||
interface PiggyBankChartGenerator
|
||||
{
|
||||
/**
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function history(Collection $set);
|
||||
}
|
||||
83
app/Generator/Chart/Report/ChartJsReportChartGenerator.php
Normal file
83
app/Generator/Chart/Report/ChartJsReportChartGenerator.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Report;
|
||||
|
||||
use Config;
|
||||
use Grumpydictator\Gchart\GChart;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class GoogleReportChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Report
|
||||
*/
|
||||
class ChartJsReportChartGenerator implements ReportChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function yearInOut(Collection $entries)
|
||||
{
|
||||
// language:
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$format = Config::get('firefly.month.' . $language);
|
||||
|
||||
$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 yearInOutSummarized($income, $expense, $count)
|
||||
{
|
||||
|
||||
$data = [
|
||||
'count' => 2,
|
||||
'labels' => [],
|
||||
'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;
|
||||
}
|
||||
}
|
||||
58
app/Generator/Chart/Report/GoogleReportChartGenerator.php
Normal file
58
app/Generator/Chart/Report/GoogleReportChartGenerator.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Report;
|
||||
|
||||
use Grumpydictator\Gchart\GChart;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class GoogleReportChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Report
|
||||
*/
|
||||
class GoogleReportChartGenerator implements ReportChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function yearInOut(Collection $entries)
|
||||
{
|
||||
$chart = new GChart;
|
||||
$chart->addColumn(trans('firefly.month'), 'date');
|
||||
$chart->addColumn(trans('firefly.income'), 'number');
|
||||
$chart->addColumn(trans('firefly.expenses'), 'number');
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($entries as $entry) {
|
||||
$chart->addRowArray($entry);
|
||||
}
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $income
|
||||
* @param string $expense
|
||||
* @param int $count
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function yearInOutSummarized($income, $expense, $count)
|
||||
{
|
||||
$chart = new GChart;
|
||||
|
||||
$chart->addColumn(trans('firefly.summary'), 'string');
|
||||
$chart->addColumn(trans('firefly.income'), 'number');
|
||||
$chart->addColumn(trans('firefly.expenses'), 'number');
|
||||
$chart->addRow(trans('firefly.sum'), $income, $expense);
|
||||
$chart->addRow(trans('firefly.average'), ($income / $count), ($expense / $count));
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return $chart->getData();
|
||||
}
|
||||
}
|
||||
31
app/Generator/Chart/Report/ReportChartGenerator.php
Normal file
31
app/Generator/Chart/Report/ReportChartGenerator.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Report;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface ReportChartGenerator
|
||||
*
|
||||
* @package FireflyIII\Generator\Chart\Report
|
||||
*/
|
||||
interface ReportChartGenerator
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Collection $entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function yearInOut(Collection $entries);
|
||||
|
||||
/**
|
||||
* @param string $income
|
||||
* @param string $expense
|
||||
* @param int $count
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function yearInOutSummarized($income, $expense, $count);
|
||||
|
||||
}
|
||||
73
app/Handlers/Events/ConnectJournalToPiggyBank.php
Normal file
73
app/Handlers/Events/ConnectJournalToPiggyBank.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Events\JournalCreated;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
|
||||
/**
|
||||
* Class ConnectJournalToPiggyBank
|
||||
*
|
||||
* @package FireflyIII\Handlers\Events
|
||||
*/
|
||||
class ConnectJournalToPiggyBank
|
||||
{
|
||||
|
||||
/**
|
||||
* Create the event handler.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event when journal is saved.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*
|
||||
* @param JournalCreated $event
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function handle(JournalCreated $event)
|
||||
{
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $event->journal;
|
||||
$piggyBankId = $event->piggyBankId;
|
||||
|
||||
/** @var PiggyBank $piggyBank */
|
||||
$piggyBank = Auth::user()->piggybanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
|
||||
|
||||
if (is_null($piggyBank)) {
|
||||
return false;
|
||||
}
|
||||
// update piggy bank rep for date of transaction journal.
|
||||
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
|
||||
if (is_null($repetition)) {
|
||||
return false;
|
||||
}
|
||||
bcscale(2);
|
||||
|
||||
$amount = $journal->actual_amount;
|
||||
// if piggy account matches source account, the amount is positive
|
||||
if ($piggyBank->account_id == $journal->source_account->id) {
|
||||
$amount = $amount * -1;
|
||||
}
|
||||
|
||||
|
||||
$repetition->currentamount = bcadd($repetition->currentamount, $amount);
|
||||
$repetition->save();
|
||||
|
||||
PiggyBankEvent::create(['piggy_bank_id' => $piggyBank->id, 'transaction_journal_id' => $journal->id, 'date' => $journal->date, 'amount' => $amount]);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Events\JournalDeleted;
|
||||
use Illuminate\Contracts\Queue\ShouldBeQueued;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class JournalDeletedHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* Create the event handler.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param JournalDeleted $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(JournalDeleted $event)
|
||||
{
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
53
app/Handlers/Events/RescanJournal.php
Normal file
53
app/Handlers/Events/RescanJournal.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use App;
|
||||
use FireflyIII\Events\JournalSaved;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class RescanJournal
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Handlers\Events
|
||||
*/
|
||||
class RescanJournal
|
||||
{
|
||||
|
||||
/**
|
||||
* Create the event handler.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param JournalSaved $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(JournalSaved $event)
|
||||
{
|
||||
$journal = $event->journal;
|
||||
|
||||
Log::debug('Triggered saved event for journal #' . $journal->id . ' (' . $journal->description . ')');
|
||||
|
||||
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
|
||||
$repository = App::make('FireflyIII\Repositories\Bill\BillRepositoryInterface');
|
||||
$list = $journal->user->bills()->where('active', 1)->where('automatch', 1)->get();
|
||||
|
||||
Log::debug('Found ' . $list->count() . ' bills to check.');
|
||||
|
||||
/** @var \FireflyIII\Models\Bill $bill */
|
||||
foreach ($list as $bill) {
|
||||
Log::debug('Now calling bill #' . $bill->id . ' (' . $bill->name . ')');
|
||||
$repository->scan($bill, $journal);
|
||||
}
|
||||
|
||||
Log::debug('Done!');
|
||||
}
|
||||
|
||||
}
|
||||
63
app/Handlers/Events/UpdateJournalConnection.php
Normal file
63
app/Handlers/Events/UpdateJournalConnection.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Events\JournalSaved;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\PiggyBankRepetition;
|
||||
|
||||
/**
|
||||
* Class UpdateJournalConnection
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Handlers\Events
|
||||
*/
|
||||
class UpdateJournalConnection
|
||||
{
|
||||
|
||||
/**
|
||||
* Create the event handler.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param JournalSaved $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(JournalSaved $event)
|
||||
{
|
||||
$journal = $event->journal;
|
||||
|
||||
// get the event connected to this journal:
|
||||
/** @var PiggyBankEvent $event */
|
||||
$event = PiggyBankEvent::where('transaction_journal_id', $journal->id)->first();
|
||||
if (is_null($event)) {
|
||||
return;
|
||||
}
|
||||
$piggyBank = $event->piggyBank()->first();
|
||||
$repetition = null;
|
||||
if ($piggyBank) {
|
||||
/** @var PiggyBankRepetition $repetition */
|
||||
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
|
||||
}
|
||||
|
||||
if (is_null($repetition)) {
|
||||
return;
|
||||
}
|
||||
$amount = $journal->amount;
|
||||
$diff = $amount - $event->amount; // update current repetition
|
||||
|
||||
$repetition->currentamount += $diff;
|
||||
$repetition->save();
|
||||
|
||||
|
||||
$event->amount = $amount;
|
||||
$event->save();
|
||||
}
|
||||
|
||||
}
|
||||
90
app/Helpers/Collection/Account.php
Normal file
90
app/Helpers/Collection/Account.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Class Account
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class Account
|
||||
{
|
||||
|
||||
/** @var Collection */
|
||||
protected $accounts;
|
||||
/** @var float */
|
||||
protected $difference;
|
||||
/** @var float */
|
||||
protected $end;
|
||||
/** @var float */
|
||||
protected $start;
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getAccounts()
|
||||
{
|
||||
return $this->accounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Support\Collection $accounts
|
||||
*/
|
||||
public function setAccounts($accounts)
|
||||
{
|
||||
$this->accounts = $accounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getDifference()
|
||||
{
|
||||
return $this->difference;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $difference
|
||||
*/
|
||||
public function setDifference($difference)
|
||||
{
|
||||
$this->difference = $difference;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getEnd()
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $end
|
||||
*/
|
||||
public function setEnd($end)
|
||||
{
|
||||
$this->end = $end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getStart()
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $start
|
||||
*/
|
||||
public function setStart($start)
|
||||
{
|
||||
$this->start = $start;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
64
app/Helpers/Collection/Balance.php
Normal file
64
app/Helpers/Collection/Balance.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class Balance
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class Balance
|
||||
{
|
||||
|
||||
/** @var BalanceHeader */
|
||||
protected $balanceHeader;
|
||||
|
||||
/** @var Collection */
|
||||
protected $balanceLines;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->balanceLines = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BalanceLine $line
|
||||
*/
|
||||
public function addBalanceLine(BalanceLine $line)
|
||||
{
|
||||
$this->balanceLines->push($line);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BalanceHeader
|
||||
*/
|
||||
public function getBalanceHeader()
|
||||
{
|
||||
return $this->balanceHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BalanceHeader $balanceHeader
|
||||
*/
|
||||
public function setBalanceHeader($balanceHeader)
|
||||
{
|
||||
$this->balanceHeader = $balanceHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getBalanceLines()
|
||||
{
|
||||
return $this->balanceLines;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
74
app/Helpers/Collection/BalanceEntry.php
Normal file
74
app/Helpers/Collection/BalanceEntry.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Account as AccountModel;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class BalanceEntry
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class BalanceEntry
|
||||
{
|
||||
|
||||
|
||||
/** @var AccountModel */
|
||||
protected $account;
|
||||
/** @var float */
|
||||
protected $left = 0.0;
|
||||
/** @var float */
|
||||
protected $spent = 0.0;
|
||||
|
||||
/**
|
||||
* @return AccountModel
|
||||
*/
|
||||
public function getAccount()
|
||||
{
|
||||
return $this->account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountModel $account
|
||||
*/
|
||||
public function setAccount($account)
|
||||
{
|
||||
$this->account = $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getLeft()
|
||||
{
|
||||
return $this->left;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $left
|
||||
*/
|
||||
public function setLeft($left)
|
||||
{
|
||||
$this->left = $left;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getSpent()
|
||||
{
|
||||
return $this->spent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $spent
|
||||
*/
|
||||
public function setSpent($spent)
|
||||
{
|
||||
$this->spent = $spent;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
46
app/Helpers/Collection/BalanceHeader.php
Normal file
46
app/Helpers/Collection/BalanceHeader.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Account as AccountModel;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class BalanceHeader
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class BalanceHeader
|
||||
{
|
||||
|
||||
/** @var Collection */
|
||||
protected $accounts;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->accounts = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountModel $account
|
||||
*/
|
||||
public function addAccount(AccountModel $account)
|
||||
{
|
||||
$this->accounts->push($account);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAccounts()
|
||||
{
|
||||
return $this->accounts;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
173
app/Helpers/Collection/BalanceLine.php
Normal file
173
app/Helpers/Collection/BalanceLine.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Budget as BudgetModel;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class BalanceLine
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class BalanceLine
|
||||
{
|
||||
|
||||
const ROLE_DEFAULTROLE = 1;
|
||||
const ROLE_TAGROLE = 2;
|
||||
const ROLE_DIFFROLE = 3;
|
||||
|
||||
/** @var Collection */
|
||||
protected $balanceEntries;
|
||||
|
||||
/** @var BudgetModel */
|
||||
protected $budget;
|
||||
|
||||
/** @var LimitRepetition */
|
||||
protected $repetition;
|
||||
|
||||
protected $role = self::ROLE_DEFAULTROLE;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->balanceEntries = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BalanceEntry $balanceEntry
|
||||
*/
|
||||
public function addBalanceEntry(BalanceEntry $balanceEntry)
|
||||
{
|
||||
$this->balanceEntries->push($balanceEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
if ($this->getBudget() instanceof BudgetModel) {
|
||||
return $this->getBudget()->name;
|
||||
}
|
||||
if ($this->getRole() == self::ROLE_DEFAULTROLE) {
|
||||
return trans('firefly.noBudget');
|
||||
}
|
||||
if ($this->getRole() == self::ROLE_TAGROLE) {
|
||||
return trans('firefly.coveredWithTags');
|
||||
}
|
||||
if ($this->getRole() == self::ROLE_DIFFROLE) {
|
||||
return trans('firefly.leftUnbalanced');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BudgetModel
|
||||
*/
|
||||
public function getBudget()
|
||||
{
|
||||
return $this->budget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetModel $budget
|
||||
*/
|
||||
public function setBudget($budget)
|
||||
{
|
||||
$this->budget = $budget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getRole()
|
||||
{
|
||||
return $this->role;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $role
|
||||
*/
|
||||
public function setRole($role)
|
||||
{
|
||||
$this->role = $role;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a BalanceLine has a budget/repetition, each BalanceEntry in this BalanceLine
|
||||
* should have a "spent" value, which is the amount of money that has been spent
|
||||
* on the given budget/repetition. If you subtract all those amounts from the budget/repetition's
|
||||
* total amount, this is returned:
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function leftOfRepetition()
|
||||
{
|
||||
$start = $this->getRepetition() ? $this->getRepetition()->amount : 0;
|
||||
/** @var BalanceEntry $balanceEntry */
|
||||
foreach ($this->getBalanceEntries() as $balanceEntry) {
|
||||
$start += $balanceEntry->getSpent();
|
||||
}
|
||||
|
||||
return $start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LimitRepetition
|
||||
*/
|
||||
public function getRepetition()
|
||||
{
|
||||
return $this->repetition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LimitRepetition $repetition
|
||||
*/
|
||||
public function setRepetition($repetition)
|
||||
{
|
||||
$this->repetition = $repetition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBalanceEntries()
|
||||
{
|
||||
return $this->balanceEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $balanceEntries
|
||||
*/
|
||||
public function setBalanceEntries($balanceEntries)
|
||||
{
|
||||
$this->balanceEntries = $balanceEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the BalanceEntries for a BalanceLine have a "left" value, the amount
|
||||
* of money left in the entire BalanceLine is returned here:
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function sumOfLeft()
|
||||
{
|
||||
$sum = '0';
|
||||
bcscale(2);
|
||||
/** @var BalanceEntry $balanceEntry */
|
||||
foreach ($this->getBalanceEntries() as $balanceEntry) {
|
||||
$sum = bcadd($sum, $balanceEntry->getLeft());
|
||||
}
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
56
app/Helpers/Collection/Bill.php
Normal file
56
app/Helpers/Collection/Bill.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Class Bill
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class Bill
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Collection
|
||||
*/
|
||||
protected $bills;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->bills = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BillLine $bill
|
||||
*/
|
||||
public function addBill(BillLine $bill)
|
||||
{
|
||||
$this->bills->push($bill);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBills()
|
||||
{
|
||||
$set = $this->bills->sortBy(
|
||||
function (BillLine $bill) {
|
||||
$active = intval($bill->getBill()->active) == 0 ? 1 : 0;
|
||||
$name = $bill->getBill()->name;
|
||||
|
||||
return $active . $name;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
}
|
||||
127
app/Helpers/Collection/BillLine.php
Normal file
127
app/Helpers/Collection/BillLine.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Bill as BillModel;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class BillLine
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class BillLine
|
||||
{
|
||||
|
||||
/** @var bool */
|
||||
protected $active;
|
||||
/** @var string */
|
||||
protected $amount;
|
||||
/** @var BillModel */
|
||||
protected $bill;
|
||||
/** @var bool */
|
||||
protected $hit;
|
||||
/** @var string */
|
||||
protected $max;
|
||||
/** @var string */
|
||||
protected $min;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAmount()
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $amount
|
||||
*/
|
||||
public function setAmount($amount)
|
||||
{
|
||||
$this->amount = $amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BillModel
|
||||
*/
|
||||
public function getBill()
|
||||
{
|
||||
return $this->bill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BillModel $bill
|
||||
*/
|
||||
public function setBill($bill)
|
||||
{
|
||||
$this->bill = $bill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMax()
|
||||
{
|
||||
return $this->max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $max
|
||||
*/
|
||||
public function setMax($max)
|
||||
{
|
||||
$this->max = $max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMin()
|
||||
{
|
||||
return $this->min;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $min
|
||||
*/
|
||||
public function setMin($min)
|
||||
{
|
||||
$this->min = $min;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function isActive()
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $active
|
||||
*/
|
||||
public function setActive($active)
|
||||
{
|
||||
$this->active = $active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function isHit()
|
||||
{
|
||||
return $this->hit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $hit
|
||||
*/
|
||||
public function setHit($hit)
|
||||
{
|
||||
$this->hit = $hit;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
156
app/Helpers/Collection/Budget.php
Normal file
156
app/Helpers/Collection/Budget.php
Normal file
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class Budget
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class Budget
|
||||
{
|
||||
/** @var Collection */
|
||||
protected $budgetLines;
|
||||
/** @var string */
|
||||
protected $budgeted = '0';
|
||||
/** @var string */
|
||||
protected $left = '0';
|
||||
/** @var string */
|
||||
protected $overspent = '0';
|
||||
/** @var string */
|
||||
protected $spent = '0';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->budgetLines = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetLine $budgetLine
|
||||
*/
|
||||
public function addBudgetLine(BudgetLine $budgetLine)
|
||||
{
|
||||
$this->budgetLines->push($budgetLine);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $add
|
||||
*/
|
||||
public function addBudgeted($add)
|
||||
{
|
||||
$add = strval(round($add, 2));
|
||||
bcscale(2);
|
||||
$this->budgeted = bcadd($this->budgeted, $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $add
|
||||
*/
|
||||
public function addLeft($add)
|
||||
{
|
||||
$add = strval(round($add, 2));
|
||||
bcscale(2);
|
||||
$this->left = bcadd($this->left, $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $add
|
||||
*/
|
||||
public function addOverspent($add)
|
||||
{
|
||||
$add = strval(round($add, 2));
|
||||
bcscale(2);
|
||||
$this->overspent = bcadd($this->overspent, $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $add
|
||||
*/
|
||||
public function addSpent($add)
|
||||
{
|
||||
$add = strval(round($add, 2));
|
||||
bcscale(2);
|
||||
$this->spent = bcadd($this->spent, $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getBudgetLines()
|
||||
{
|
||||
return $this->budgetLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getBudgeted()
|
||||
{
|
||||
return $this->budgeted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $budgeted
|
||||
*/
|
||||
public function setBudgeted($budgeted)
|
||||
{
|
||||
$this->budgeted = $budgeted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLeft()
|
||||
{
|
||||
return $this->left;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $left
|
||||
*/
|
||||
public function setLeft($left)
|
||||
{
|
||||
$this->left = $left;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOverspent()
|
||||
{
|
||||
return $this->overspent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $overspent
|
||||
*/
|
||||
public function setOverspent($overspent)
|
||||
{
|
||||
$this->overspent = strval(round($overspent, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSpent()
|
||||
{
|
||||
return $this->spent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $spent
|
||||
*/
|
||||
public function setSpent($spent)
|
||||
{
|
||||
$this->spent = strval(round($spent, 2));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
128
app/Helpers/Collection/BudgetLine.php
Normal file
128
app/Helpers/Collection/BudgetLine.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Budget as BudgetModel;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class BudgetLine
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class BudgetLine
|
||||
{
|
||||
|
||||
/** @var BudgetModel */
|
||||
protected $budget;
|
||||
/** @var float */
|
||||
protected $budgeted = 0;
|
||||
/** @var float */
|
||||
protected $left = 0;
|
||||
/** @var float */
|
||||
protected $overspent = 0;
|
||||
/** @var LimitRepetition */
|
||||
protected $repetition;
|
||||
/** @var float */
|
||||
protected $spent = 0;
|
||||
|
||||
/**
|
||||
* @return BudgetModel
|
||||
*/
|
||||
public function getBudget()
|
||||
{
|
||||
return $this->budget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetModel $budget
|
||||
*/
|
||||
public function setBudget($budget)
|
||||
{
|
||||
$this->budget = $budget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getBudgeted()
|
||||
{
|
||||
return $this->budgeted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $budgeted
|
||||
*/
|
||||
public function setBudgeted($budgeted)
|
||||
{
|
||||
$this->budgeted = $budgeted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getLeft()
|
||||
{
|
||||
return $this->left;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $left
|
||||
*/
|
||||
public function setLeft($left)
|
||||
{
|
||||
$this->left = $left;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getOverspent()
|
||||
{
|
||||
return $this->overspent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $overspent
|
||||
*/
|
||||
public function setOverspent($overspent)
|
||||
{
|
||||
$this->overspent = $overspent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LimitRepetition
|
||||
*/
|
||||
public function getRepetition()
|
||||
{
|
||||
return $this->repetition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LimitRepetition $repetition
|
||||
*/
|
||||
public function setRepetition($repetition)
|
||||
{
|
||||
$this->repetition = $repetition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getSpent()
|
||||
{
|
||||
return $this->spent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $spent
|
||||
*/
|
||||
public function setSpent($spent)
|
||||
{
|
||||
$this->spent = $spent;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
76
app/Helpers/Collection/Category.php
Normal file
76
app/Helpers/Collection/Category.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Category as CategoryModel;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class Category
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class Category
|
||||
{
|
||||
|
||||
/** @var Collection */
|
||||
protected $categories;
|
||||
/** @var string */
|
||||
protected $total = '0';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->categories = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CategoryModel $category
|
||||
*/
|
||||
public function addCategory(CategoryModel $category)
|
||||
{
|
||||
if ($category->spent > 0) {
|
||||
$this->categories->push($category);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $add
|
||||
*/
|
||||
public function addTotal($add)
|
||||
{
|
||||
$add = strval(round($add, 2));
|
||||
bcscale(2);
|
||||
$this->total = bcadd($this->total, $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getCategories()
|
||||
{
|
||||
$set = $this->categories->sortByDesc(
|
||||
function (CategoryModel $category) {
|
||||
return $category->spent;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTotal()
|
||||
{
|
||||
return strval(round($this->total, 2));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
85
app/Helpers/Collection/Expense.php
Normal file
85
app/Helpers/Collection/Expense.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Support\Collection;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class Expense
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class Expense
|
||||
{
|
||||
/** @var Collection */
|
||||
protected $expenses;
|
||||
/** @var string */
|
||||
protected $total = '0';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->expenses = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $entry
|
||||
*/
|
||||
public function addOrCreateExpense(TransactionJournal $entry)
|
||||
{
|
||||
|
||||
$accountId = $entry->account_id;
|
||||
if (!$this->expenses->has($accountId)) {
|
||||
$newObject = new stdClass;
|
||||
$newObject->amount = strval(round($entry->amount, 2));
|
||||
$newObject->name = $entry->name;
|
||||
$newObject->count = 1;
|
||||
$newObject->id = $accountId;
|
||||
$this->expenses->put($accountId, $newObject);
|
||||
} else {
|
||||
bcscale(2);
|
||||
$existing = $this->expenses->get($accountId);
|
||||
$existing->amount = bcadd($existing->amount, $entry->amount);
|
||||
$existing->count++;
|
||||
$this->expenses->put($accountId, $existing);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $add
|
||||
*/
|
||||
public function addToTotal($add)
|
||||
{
|
||||
$add = strval(round($add, 2));
|
||||
bcscale(2);
|
||||
$this->total = bcadd($this->total, $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getExpenses()
|
||||
{
|
||||
$set = $this->expenses->sortByDesc(
|
||||
function (stdClass $object) {
|
||||
return $object->amount;
|
||||
}
|
||||
);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTotal()
|
||||
{
|
||||
return strval(round($this->total, 2));
|
||||
}
|
||||
}
|
||||
88
app/Helpers/Collection/Income.php
Normal file
88
app/Helpers/Collection/Income.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Support\Collection;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* Class Income
|
||||
*
|
||||
* @package FireflyIII\Helpers\Collection
|
||||
*/
|
||||
class Income
|
||||
{
|
||||
|
||||
/** @var Collection */
|
||||
protected $incomes;
|
||||
/** @var string */
|
||||
protected $total;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->incomes = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $entry
|
||||
*/
|
||||
public function addOrCreateIncome(TransactionJournal $entry)
|
||||
{
|
||||
|
||||
$accountId = $entry->account_id;
|
||||
if (!$this->incomes->has($accountId)) {
|
||||
$newObject = new stdClass;
|
||||
$newObject->amount = strval(round($entry->amount, 2));
|
||||
$newObject->name = $entry->name;
|
||||
$newObject->count = 1;
|
||||
$newObject->id = $accountId;
|
||||
$this->incomes->put($accountId, $newObject);
|
||||
} else {
|
||||
bcscale(2);
|
||||
$existing = $this->incomes->get($accountId);
|
||||
$existing->amount = bcadd($existing->amount, $entry->amount);
|
||||
$existing->count++;
|
||||
$this->incomes->put($accountId, $existing);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $add
|
||||
*/
|
||||
public function addToTotal($add)
|
||||
{
|
||||
$add = strval(round($add, 2));
|
||||
bcscale(2);
|
||||
$this->total = bcadd($this->total, $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getIncomes()
|
||||
{
|
||||
$set = $this->incomes->sortByDesc(
|
||||
function (stdClass $object) {
|
||||
return $object->amount;
|
||||
}
|
||||
);
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTotal()
|
||||
{
|
||||
return strval(round($this->total, 2));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
99
app/Helpers/Help/Help.php
Normal file
99
app/Helpers/Help/Help.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Help;
|
||||
|
||||
use Cache;
|
||||
use ErrorException;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use Log;
|
||||
use Route;
|
||||
|
||||
/**
|
||||
* Class Help
|
||||
*
|
||||
* @package FireflyIII\Helpers\Help
|
||||
*/
|
||||
class Help implements HelpInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromCache($key)
|
||||
{
|
||||
return Cache::get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param $route
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFromGithub($route)
|
||||
{
|
||||
$uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/en/' . e($route) . '.md';
|
||||
$routeIndex = str_replace('.', '-', $route);
|
||||
$title = trans('help.' . $routeIndex);
|
||||
$content = [
|
||||
'text' => '<p>There is no help for this route!</p>',
|
||||
'title' => $title,
|
||||
];
|
||||
try {
|
||||
$content['text'] = file_get_contents($uri);
|
||||
} catch (ErrorException $e) {
|
||||
Log::error(trim($e->getMessage()));
|
||||
}
|
||||
if (strlen(trim($content['text'])) == 0) {
|
||||
$content['text'] = '<p>There is no help for this route.</p>';
|
||||
}
|
||||
$converter = new CommonMarkConverter();
|
||||
$content['text'] = $converter->convertToHtml($content['text']);
|
||||
|
||||
return $content;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasRoute($route)
|
||||
{
|
||||
return Route::has($route);
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function inCache($route)
|
||||
{
|
||||
return Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text');
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param $route
|
||||
* @param array $content
|
||||
*
|
||||
* @internal param $title
|
||||
*/
|
||||
public function putInCache($route, array $content)
|
||||
{
|
||||
Cache::put('help.' . $route . '.text', $content['text'], 10080); // a week.
|
||||
Cache::put('help.' . $route . '.title', $content['title'], 10080);
|
||||
}
|
||||
}
|
||||
48
app/Helpers/Help/HelpInterface.php
Normal file
48
app/Helpers/Help/HelpInterface.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Helpers\Help;
|
||||
|
||||
/**
|
||||
* Interface HelpInterface
|
||||
*
|
||||
* @package FireflyIII\Helpers\Help
|
||||
*/
|
||||
interface HelpInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromCache($key);
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFromGithub($route);
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasRoute($route);
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function inCache($route);
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param array $content
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function putInCache($route, array $content);
|
||||
}
|
||||
@@ -2,11 +2,24 @@
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
use Auth;
|
||||
use App;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Collection\Account as AccountCollection;
|
||||
use FireflyIII\Helpers\Collection\Balance;
|
||||
use FireflyIII\Helpers\Collection\BalanceEntry;
|
||||
use FireflyIII\Helpers\Collection\BalanceHeader;
|
||||
use FireflyIII\Helpers\Collection\BalanceLine;
|
||||
use FireflyIII\Helpers\Collection\Bill as BillCollection;
|
||||
use FireflyIII\Helpers\Collection\BillLine;
|
||||
use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
|
||||
use FireflyIII\Helpers\Collection\BudgetLine;
|
||||
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
|
||||
use FireflyIII\Helpers\Collection\Expense;
|
||||
use FireflyIII\Helpers\Collection\Income;
|
||||
use FireflyIII\Models\Account;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Budget as BudgetModel;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
|
||||
/**
|
||||
* Class ReportHelper
|
||||
@@ -16,76 +29,352 @@ use Illuminate\Support\Collection;
|
||||
class ReportHelper implements ReportHelperInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* This methods fails to take in account transfers FROM shared accounts.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function expensesGroupedByAccount(Carbon $start, Carbon $end, $limit = 15)
|
||||
{
|
||||
$result = $this->_queries->journalsByExpenseAccount($start, $end);
|
||||
$array = $this->_helper->makeArray($result);
|
||||
$limited = $this->_helper->limitArray($array, $limit);
|
||||
/** @var ReportQueryInterface */
|
||||
protected $query;
|
||||
|
||||
return $limited;
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param ReportQueryInterface $query
|
||||
*
|
||||
*/
|
||||
public function __construct(ReportQueryInterface $query)
|
||||
{
|
||||
$this->query = $query;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Carbon
|
||||
*/
|
||||
public function firstDate()
|
||||
{
|
||||
$journal = Auth::user()->transactionjournals()->orderBy('date', 'ASC')->first();
|
||||
if ($journal) {
|
||||
return $journal->date;
|
||||
}
|
||||
|
||||
return Carbon::now();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets some kind of list for a monthly overview.
|
||||
* This method generates a full report for the given period on all
|
||||
* the users asset and cash accounts.
|
||||
*
|
||||
* @param Carbon $date
|
||||
* @param Carbon $end
|
||||
* @param $shared
|
||||
*
|
||||
* @return Collection
|
||||
* @return AccountCollection
|
||||
*/
|
||||
public function getBudgetsForMonth(Carbon $date)
|
||||
public function getAccountReport(Carbon $date, Carbon $end, $shared)
|
||||
{
|
||||
$start = clone $date;
|
||||
$start->startOfMonth();
|
||||
$end = clone $date;
|
||||
$end->endOfMonth();
|
||||
// all budgets
|
||||
$set = \Auth::user()->budgets()
|
||||
->leftJoin(
|
||||
'budget_limits', function (JoinClause $join) use ($date) {
|
||||
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
|
||||
}
|
||||
)
|
||||
->get(['budgets.*', 'budget_limits.amount as amount']);
|
||||
|
||||
|
||||
$budgets = $this->_helper->makeArray($set);
|
||||
$amountSet = $this->_queries->journalsByBudget($start, $end);
|
||||
$amounts = $this->_helper->makeArray($amountSet);
|
||||
$combined = $this->_helper->mergeArrays($budgets, $amounts);
|
||||
$combined[0]['spent'] = isset($combined[0]['spent']) ? $combined[0]['spent'] : 0.0;
|
||||
$combined[0]['amount'] = isset($combined[0]['amount']) ? $combined[0]['amount'] : 0.0;
|
||||
$combined[0]['name'] = 'No budget';
|
||||
$accounts = $this->query->getAllAccounts($date, $end, $shared);
|
||||
$start = 0;
|
||||
$end = 0;
|
||||
$diff = 0;
|
||||
|
||||
// find transactions to shared expense accounts, which are without a budget by default:
|
||||
$transfers = $this->_queries->sharedExpenses($start, $end);
|
||||
foreach ($transfers as $transfer) {
|
||||
$combined[0]['spent'] += floatval($transfer->amount) * -1;
|
||||
// remove cash account, if any:
|
||||
$accounts = $accounts->filter(
|
||||
function (Account $account) {
|
||||
if ($account->accountType->type != 'Cash account') {
|
||||
return $account;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
// summarize:
|
||||
foreach ($accounts as $account) {
|
||||
$start += $account->startBalance;
|
||||
$end += $account->endBalance;
|
||||
$diff += ($account->endBalance - $account->startBalance);
|
||||
}
|
||||
|
||||
return $combined;
|
||||
$object = new AccountCollection;
|
||||
$object->setStart($start);
|
||||
$object->setEnd($end);
|
||||
$object->setDifference($diff);
|
||||
$object->setAccounts($accounts);
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* The balance report contains a Balance object which in turn contains:
|
||||
*
|
||||
* A BalanceHeader object which contains all relevant user asset accounts for the report.
|
||||
*
|
||||
* A number of BalanceLine objects, which hold:
|
||||
* - A budget
|
||||
* - A number of BalanceEntry objects.
|
||||
*
|
||||
* The BalanceEntry object holds:
|
||||
* - The same budget (again)
|
||||
* - A user asset account as mentioned in the BalanceHeader
|
||||
* - The amount of money spent on the budget by the user asset account
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return Balance
|
||||
*/
|
||||
public function getBalanceReport(Carbon $start, Carbon $end, $shared)
|
||||
{
|
||||
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||
$tagRepository = App::make('FireflyIII\Repositories\Tag\TagRepositoryInterface');
|
||||
$balance = new Balance;
|
||||
|
||||
// build a balance header:
|
||||
$header = new BalanceHeader;
|
||||
|
||||
$accounts = $this->query->getAllAccounts($start, $end, $shared);
|
||||
$budgets = $repository->getBudgets();
|
||||
foreach ($accounts as $account) {
|
||||
$header->addAccount($account);
|
||||
}
|
||||
|
||||
/** @var BudgetModel $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
$line = new BalanceLine;
|
||||
$line->setBudget($budget);
|
||||
|
||||
// get budget amount for current period:
|
||||
$rep = $repository->getCurrentRepetition($budget, $start);
|
||||
$line->setRepetition($rep);
|
||||
|
||||
// loop accounts:
|
||||
foreach ($accounts as $account) {
|
||||
$balanceEntry = new BalanceEntry;
|
||||
$balanceEntry->setAccount($account);
|
||||
|
||||
// get spent:
|
||||
$spent = $this->query->spentInBudgetCorrected($account, $budget, $start, $end); // I think shared is irrelevant.
|
||||
|
||||
$balanceEntry->setSpent($spent);
|
||||
$line->addBalanceEntry($balanceEntry);
|
||||
}
|
||||
// add line to balance:
|
||||
$balance->addBalanceLine($line);
|
||||
}
|
||||
|
||||
// then a new line for without budget.
|
||||
// and one for the tags:
|
||||
$empty = new BalanceLine;
|
||||
$tags = new BalanceLine;
|
||||
$diffLine = new BalanceLine;
|
||||
|
||||
$tags->setRole(BalanceLine::ROLE_TAGROLE);
|
||||
$diffLine->setRole(BalanceLine::ROLE_DIFFROLE);
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
$spent = $this->query->spentNoBudget($account, $start, $end);
|
||||
$left = $tagRepository->coveredByBalancingActs($account, $start, $end);
|
||||
bcscale(2);
|
||||
$diff = bcsub($spent, $left);
|
||||
|
||||
// budget
|
||||
$budgetEntry = new BalanceEntry;
|
||||
$budgetEntry->setAccount($account);
|
||||
$budgetEntry->setSpent($spent);
|
||||
$empty->addBalanceEntry($budgetEntry);
|
||||
|
||||
// balanced by tags
|
||||
$tagEntry = new BalanceEntry;
|
||||
$tagEntry->setAccount($account);
|
||||
$tagEntry->setLeft($left);
|
||||
$tags->addBalanceEntry($tagEntry);
|
||||
|
||||
// difference:
|
||||
$diffEntry = new BalanceEntry;
|
||||
$diffEntry->setAccount($account);
|
||||
$diffEntry->setSpent($diff);
|
||||
$diffLine->addBalanceEntry($diffEntry);
|
||||
|
||||
}
|
||||
|
||||
$balance->addBalanceLine($empty);
|
||||
$balance->addBalanceLine($tags);
|
||||
$balance->addBalanceLine($diffLine);
|
||||
|
||||
$balance->setBalanceHeader($header);
|
||||
|
||||
return $balance;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method generates a full report for the given period on all
|
||||
* the users bills and their payments.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return BillCollection
|
||||
*/
|
||||
public function getBillReport(Carbon $start, Carbon $end, $shared)
|
||||
{
|
||||
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
|
||||
$repository = App::make('FireflyIII\Repositories\Bill\BillRepositoryInterface');
|
||||
$bills = $repository->getBills();
|
||||
$collection = new BillCollection;
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
$billLine = new BillLine;
|
||||
$billLine->setBill($bill);
|
||||
$billLine->setActive(intval($bill->active) == 1);
|
||||
$billLine->setMin($bill->amount_min);
|
||||
$billLine->setMax($bill->amount_max);
|
||||
|
||||
// is hit in period?
|
||||
bcscale(2);
|
||||
$set = $repository->getJournalsInRange($bill, $start, $end);
|
||||
if ($set->count() == 0) {
|
||||
$billLine->setHit(false);
|
||||
} else {
|
||||
$billLine->setHit(true);
|
||||
$amount = '0';
|
||||
foreach ($set as $entry) {
|
||||
$amount = bcadd($amount, $entry->amount);
|
||||
}
|
||||
$billLine->setAmount($amount);
|
||||
}
|
||||
|
||||
$collection->addBill($billLine);
|
||||
|
||||
}
|
||||
|
||||
return $collection;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return BudgetCollection
|
||||
*/
|
||||
public function getBudgetReport(Carbon $start, Carbon $end, $shared)
|
||||
{
|
||||
$object = new BudgetCollection;
|
||||
/** @var \FireflyIII\Repositories\Budget\BudgetRepositoryInterface $repository */
|
||||
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
|
||||
$set = $repository->getBudgets();
|
||||
|
||||
foreach ($set as $budget) {
|
||||
|
||||
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
|
||||
|
||||
// no repetition(s) for this budget:
|
||||
if ($repetitions->count() == 0) {
|
||||
$spent = $repository->spentInPeriodCorrected($budget, $start, $end, $shared);
|
||||
$budgetLine = new BudgetLine;
|
||||
$budgetLine->setBudget($budget);
|
||||
$budgetLine->setOverspent($spent);
|
||||
$object->addOverspent($spent);
|
||||
$object->addBudgetLine($budgetLine);
|
||||
continue;
|
||||
}
|
||||
|
||||
// one or more repetitions for budget:
|
||||
/** @var LimitRepetition $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
$budgetLine = new BudgetLine;
|
||||
$budgetLine->setBudget($budget);
|
||||
$budgetLine->setRepetition($repetition);
|
||||
$expenses = $repository->spentInPeriodCorrected($budget, $repetition->startdate, $repetition->enddate, $shared);
|
||||
$left = $expenses < floatval($repetition->amount) ? floatval($repetition->amount) - $expenses : 0;
|
||||
$spent = $expenses > floatval($repetition->amount) ? 0 : $expenses;
|
||||
$overspent = $expenses > floatval($repetition->amount) ? $expenses - floatval($repetition->amount) : 0;
|
||||
|
||||
$budgetLine->setLeft($left);
|
||||
$budgetLine->setSpent($spent);
|
||||
$budgetLine->setOverspent($overspent);
|
||||
$budgetLine->setBudgeted($repetition->amount);
|
||||
|
||||
$object->addBudgeted($repetition->amount);
|
||||
$object->addSpent($spent);
|
||||
$object->addLeft($left);
|
||||
$object->addOverspent($overspent);
|
||||
$object->addBudgetLine($budgetLine);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// stuff outside of budgets:
|
||||
$noBudget = $repository->getWithoutBudgetSum($start, $end);
|
||||
$budgetLine = new BudgetLine;
|
||||
$budgetLine->setOverspent($noBudget);
|
||||
$object->addOverspent($noBudget);
|
||||
$object->addBudgetLine($budgetLine);
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return CategoryCollection
|
||||
*/
|
||||
public function getCategoryReport(Carbon $start, Carbon $end, $shared)
|
||||
{
|
||||
$object = new CategoryCollection;
|
||||
|
||||
|
||||
/**
|
||||
* GET CATEGORIES:
|
||||
*/
|
||||
/** @var \FireflyIII\Repositories\Category\CategoryRepositoryInterface $repository */
|
||||
$repository = App::make('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
|
||||
$set = $repository->getCategories();
|
||||
foreach ($set as $category) {
|
||||
$spent = $repository->spentInPeriodCorrected($category, $start, $end, $shared);
|
||||
$category->spent = $spent;
|
||||
$object->addCategory($category);
|
||||
$object->addTotal($spent);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a full report on the users expenses during the period.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return Expense
|
||||
*/
|
||||
public function getExpenseReport($start, $end, $shared)
|
||||
{
|
||||
$object = new Expense;
|
||||
$set = $this->query->expenseInPeriodCorrected($start, $end, $shared);
|
||||
foreach ($set as $entry) {
|
||||
$object->addToTotal($entry->amount);
|
||||
$object->addOrCreateExpense($entry);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a full report on the users incomes during the period.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return Income
|
||||
*/
|
||||
public function getIncomeReport($start, $end, $shared)
|
||||
{
|
||||
$object = new Income;
|
||||
$set = $this->query->incomeInPeriodCorrected($start, $end, $shared);
|
||||
foreach ($set as $entry) {
|
||||
$object->addToTotal($entry->amount);
|
||||
$object->addOrCreateIncome($entry);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,81 +384,20 @@ class ReportHelper implements ReportHelperInterface
|
||||
*/
|
||||
public function listOfMonths(Carbon $date)
|
||||
{
|
||||
|
||||
$start = clone $date;
|
||||
$end = Carbon::now();
|
||||
$months = [];
|
||||
while ($start <= $end) {
|
||||
$months[] = [
|
||||
'formatted' => $start->format('F Y'),
|
||||
'month' => intval($start->format('m')),
|
||||
'year' => intval($start->format('Y')),
|
||||
$year = $start->year;
|
||||
$months[$year][] = [
|
||||
'formatted' => $start->formatLocalized('%B %Y'),
|
||||
'month' => $start->month,
|
||||
'year' => $year,
|
||||
];
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
return $months;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listOfYears(Carbon $date)
|
||||
{
|
||||
$start = clone $date;
|
||||
$end = Carbon::now();
|
||||
$years = [];
|
||||
while ($start <= $end) {
|
||||
$years[] = $start->format('Y');
|
||||
$start->addYear();
|
||||
}
|
||||
|
||||
return $years;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function yearBalanceReport(Carbon $date)
|
||||
{
|
||||
$start = clone $date;
|
||||
$end = clone $date;
|
||||
$sharedAccounts = [];
|
||||
$sharedCollection = \Auth::user()->accounts()
|
||||
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
|
||||
->where('account_meta.name', '=', 'accountRole')
|
||||
->where('account_meta.data', '=', json_encode('sharedExpense'))
|
||||
->get(['accounts.id']);
|
||||
|
||||
foreach ($sharedCollection as $account) {
|
||||
$sharedAccounts[] = $account->id;
|
||||
}
|
||||
|
||||
$accounts = \Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])->filter(
|
||||
function (Account $account) use ($sharedAccounts) {
|
||||
if (!in_array($account->id, $sharedAccounts)) {
|
||||
return $account;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
$report = [];
|
||||
$start->startOfYear()->subDay();
|
||||
$end->endOfYear();
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
$report[] = [
|
||||
'start' => \Steam::balance($account, $start),
|
||||
'end' => \Steam::balance($account, $end),
|
||||
'account' => $account,
|
||||
'shared' => $account->accountRole == 'sharedExpense'
|
||||
];
|
||||
}
|
||||
|
||||
return $report;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,13 @@
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use FireflyIII\Helpers\Collection\Account as AccountCollection;
|
||||
use FireflyIII\Helpers\Collection\Balance;
|
||||
use FireflyIII\Helpers\Collection\Bill as BillCollection;
|
||||
use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
|
||||
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
|
||||
use FireflyIII\Helpers\Collection\Expense;
|
||||
use FireflyIII\Helpers\Collection\Income;
|
||||
|
||||
/**
|
||||
* Interface ReportHelperInterface
|
||||
@@ -13,11 +19,78 @@ use Illuminate\Support\Collection;
|
||||
interface ReportHelperInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* This method generates a full report for the given period on all
|
||||
* the users asset and cash accounts.
|
||||
*
|
||||
* @param Carbon $date
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return AccountCollection
|
||||
*/
|
||||
public function getAccountReport(Carbon $date, Carbon $end, $shared);
|
||||
|
||||
/**
|
||||
* @return Carbon
|
||||
* This method generates a full report for the given period on all
|
||||
* the users bills and their payments.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return BillCollection
|
||||
*/
|
||||
public function firstDate();
|
||||
public function getBillReport(Carbon $start, Carbon $end, $shared);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return Balance
|
||||
*/
|
||||
public function getBalanceReport(Carbon $start, Carbon $end, $shared);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return BudgetCollection
|
||||
*/
|
||||
public function getBudgetReport(Carbon $start, Carbon $end, $shared);
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return CategoryCollection
|
||||
*/
|
||||
public function getCategoryReport(Carbon $start, Carbon $end, $shared);
|
||||
|
||||
/**
|
||||
* Get a full report on the users expenses during the period.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return Expense
|
||||
*/
|
||||
public function getExpenseReport($start, $end, $shared);
|
||||
|
||||
/**
|
||||
* Get a full report on the users incomes during the period.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return Income
|
||||
*/
|
||||
public function getIncomeReport($start, $end, $shared);
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
@@ -26,37 +99,4 @@ interface ReportHelperInterface
|
||||
*/
|
||||
public function listOfMonths(Carbon $date);
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listOfYears(Carbon $date);
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function yearBalanceReport(Carbon $date);
|
||||
|
||||
/**
|
||||
* This methods fails to take in account transfers FROM shared accounts.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function expensesGroupedByAccount(Carbon $start, Carbon $end, $limit = 15);
|
||||
|
||||
/**
|
||||
* This method gets some kind of list for a monthly overview.
|
||||
*
|
||||
* @param Carbon $date
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgetsForMonth(Carbon $date);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: sander
|
||||
* Date: 22/02/15
|
||||
* Time: 18:30
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Crypt;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
@@ -25,79 +20,64 @@ use Steam;
|
||||
*/
|
||||
class ReportQuery implements ReportQueryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* This query retrieves a list of accounts that are active and not shared.
|
||||
* See ReportQueryInterface::incomeInPeriodCorrected
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param bool $includeShared
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function accountList()
|
||||
{
|
||||
return Auth::user()->accounts()
|
||||
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
||||
->leftJoin(
|
||||
'account_meta', function (JoinClause $join) {
|
||||
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', "accountRole");
|
||||
}
|
||||
)
|
||||
->whereIn('account_types.type', ['Default account', 'Cash account', 'Asset account'])
|
||||
->where('active', 1)
|
||||
->where(
|
||||
function (Builder $query) {
|
||||
$query->where('account_meta.data', '!=', '"sharedExpense"');
|
||||
$query->orWhereNull('account_meta.data');
|
||||
}
|
||||
)
|
||||
->get(['accounts.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will get a list of all expenses in a certain time period that have no budget
|
||||
* and are balanced by a transfer to make up for it.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balancedTransactionsList(Account $account, Carbon $start, Carbon $end)
|
||||
public function expenseInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false)
|
||||
{
|
||||
|
||||
$set = TransactionJournal::
|
||||
leftJoin('transaction_group_transaction_journal', 'transaction_group_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin(
|
||||
'transaction_group_transaction_journal as otherFromGroup', function (JoinClause $join) {
|
||||
$join->on('otherFromGroup.transaction_group_id', '=', 'transaction_group_transaction_journal.transaction_group_id')
|
||||
->on('otherFromGroup.transaction_journal_id', '!=', 'transaction_journals.id');
|
||||
}
|
||||
)
|
||||
->leftJoin('transaction_journals as otherJournals', 'otherJournals.id', '=', 'otherFromGroup.transaction_journal_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'otherJournals.transaction_type_id')
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'otherJournals.id')
|
||||
->before($end)->after($start)
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->where('transaction_journals.user_id', \Auth::user()->id)
|
||||
->whereNull('budget_transaction_journal.budget_id')->whereNull('transaction_journals.deleted_at')
|
||||
->whereNull('otherJournals.deleted_at')
|
||||
->where('transactions.account_id', $account->id)
|
||||
->whereNotNull('transaction_group_transaction_journal.transaction_group_id')
|
||||
->first(
|
||||
[
|
||||
DB::Raw('SUM(`transactions`.`amount`) as `amount`')
|
||||
]
|
||||
);
|
||||
$sum = 0;
|
||||
if (!is_null($set)) {
|
||||
$sum = floatval($set->amount);
|
||||
$query = $this->queryJournalsWithTransactions($start, $end);
|
||||
if ($includeShared === false) {
|
||||
$query->where(
|
||||
function (Builder $query) {
|
||||
$query->where(
|
||||
function (Builder $q) { // only get withdrawals not from a shared account
|
||||
$q->where('transaction_types.type', 'Withdrawal');
|
||||
$q->where('acm_from.data', '!=', '"sharedAsset"');
|
||||
}
|
||||
);
|
||||
$query->orWhere(
|
||||
function (Builder $q) { // and transfers from a shared account.
|
||||
$q->where('transaction_types.type', 'Transfer');
|
||||
$q->where('acm_to.data', '=', '"sharedAsset"');
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
$query->where('transaction_types.type', 'Withdrawal'); // any withdrawal is fine.
|
||||
}
|
||||
$query->orderBy('transaction_journals.date');
|
||||
|
||||
return $sum;
|
||||
// get everything
|
||||
$data = $query->get(
|
||||
['transaction_journals.*', 'transaction_types.type', 'ac_to.name as name', 'ac_to.id as account_id', 'ac_to.encrypted as account_encrypted']
|
||||
);
|
||||
|
||||
$data->each(
|
||||
function (TransactionJournal $journal) {
|
||||
if (intval($journal->account_encrypted) == 1) {
|
||||
$journal->name = Crypt::decrypt($journal->name);
|
||||
}
|
||||
}
|
||||
);
|
||||
$data = $data->filter(
|
||||
function (TransactionJournal $journal) {
|
||||
if ($journal->amount != 0) {
|
||||
return $journal;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,29 +85,42 @@ class ReportQuery implements ReportQueryInterface
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param bool $includeShared
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAllAccounts(Carbon $start, Carbon $end)
|
||||
public function getAllAccounts(Carbon $start, Carbon $end, $includeShared = false)
|
||||
{
|
||||
$set = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')
|
||||
->accountTypeIn(['Default account', 'Asset account', 'Cash account'])
|
||||
->leftJoin(
|
||||
'account_meta', function (JoinClause $join) {
|
||||
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->where(
|
||||
function (Builder $query) {
|
||||
$query->where('account_meta.data', '!=', '"sharedExpense"');
|
||||
$query->orWhereNull('account_meta.data');
|
||||
}
|
||||
)
|
||||
->get(['accounts.*']);
|
||||
$query = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')
|
||||
->accountTypeIn(['Default account', 'Asset account', 'Cash account']);
|
||||
if ($includeShared === false) {
|
||||
$query->leftJoin(
|
||||
'account_meta', function (JoinClause $join) {
|
||||
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->where(
|
||||
function (Builder $query) {
|
||||
|
||||
$query->where('account_meta.data', '!=', '"sharedAsset"');
|
||||
$query->orWhereNull('account_meta.data');
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
$set = $query->get(['accounts.*']);
|
||||
$set->each(
|
||||
function (Account $account) use ($start, $end) {
|
||||
/**
|
||||
* The balance for today always incorporates transactions
|
||||
* made on today. So to get todays "start" balance, we sub one
|
||||
* day.
|
||||
*/
|
||||
$yesterday = clone $start;
|
||||
$yesterday->subDay();
|
||||
|
||||
/** @noinspection PhpParamsInspection */
|
||||
$account->startBalance = Steam::balance($account, $start);
|
||||
$account->startBalance = Steam::balance($account, $yesterday);
|
||||
$account->endBalance = Steam::balance($account, $end);
|
||||
}
|
||||
);
|
||||
@@ -135,376 +128,156 @@ class ReportQuery implements ReportQueryInterface
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs a summary of all expenses grouped by budget, related to the account.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBudgetSummary(Account $account, Carbon $start, Carbon $end)
|
||||
{
|
||||
$set = TransactionJournal::
|
||||
leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('budgets', 'budgets.id', '=', 'budget_transaction_journal.budget_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
||||
->before($end)
|
||||
->after($start)
|
||||
->where('accounts.id', $account->id)
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->groupBy('budgets.id')
|
||||
->orderBy('budgets.name', 'ASC')
|
||||
->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) as `amount`')]);
|
||||
|
||||
return $set;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results
|
||||
* will simply list the transaction journals only. This should allow any follow up counting to be accurate with
|
||||
* regards to tags.
|
||||
*
|
||||
* This method returns all "income" journals in a certain period, which are both transfers from a shared account
|
||||
* and "ordinary" deposits. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
|
||||
* not group and returns different fields.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param bool $includeShared
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function incomeByPeriod(Carbon $start, Carbon $end)
|
||||
public function incomeInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false)
|
||||
{
|
||||
return TransactionJournal::
|
||||
$query = $this->queryJournalsWithTransactions($start, $end);
|
||||
if ($includeShared === false) {
|
||||
// only get deposits not to a shared account
|
||||
// and transfers to a shared account.
|
||||
$query->where(
|
||||
function (Builder $query) {
|
||||
$query->where(
|
||||
function (Builder $q) {
|
||||
$q->where('transaction_types.type', 'Deposit');
|
||||
$q->where('acm_to.data', '!=', '"sharedAsset"');
|
||||
}
|
||||
);
|
||||
$query->orWhere(
|
||||
function (Builder $q) {
|
||||
$q->where('transaction_types.type', 'Transfer');
|
||||
$q->where('acm_from.data', '=', '"sharedAsset"');
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// any deposit is fine.
|
||||
$query->where('transaction_types.type', 'Deposit');
|
||||
}
|
||||
$query->orderBy('transaction_journals.date');
|
||||
|
||||
// get everything
|
||||
$data = $query->get(
|
||||
['transaction_journals.*', 'transaction_types.type', 'ac_from.name as name', 'ac_from.id as account_id', 'ac_from.encrypted as account_encrypted']
|
||||
);
|
||||
|
||||
$data->each(
|
||||
function (TransactionJournal $journal) {
|
||||
if (intval($journal->account_encrypted) == 1) {
|
||||
$journal->name = Crypt::decrypt($journal->name);
|
||||
}
|
||||
}
|
||||
);
|
||||
$data = $data->filter(
|
||||
function (TransactionJournal $journal) {
|
||||
if ($journal->amount != 0) {
|
||||
return $journal;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Covers tags
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function spentInBudgetCorrected(Account $account, Budget $budget, Carbon $start, Carbon $end)
|
||||
{
|
||||
|
||||
return floatval(
|
||||
Auth::user()->transactionjournals()
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->where('transactions.account_id', $account->id)
|
||||
->before($end)
|
||||
->after($start)
|
||||
->where('budget_transaction_journal.budget_id', $budget->id)
|
||||
->get(['transaction_journals.*'])->sum('amount')
|
||||
) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param bool $shared
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function spentNoBudget(Account $account, Carbon $start, Carbon $end, $shared = false)
|
||||
{
|
||||
return
|
||||
Auth::user()->transactionjournals()
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->where('transactions.account_id', $account->id)
|
||||
->before($end)
|
||||
->after($start)
|
||||
->whereNull('budget_transaction_journal.budget_id')->get(['transaction_journals.*'])->sum('amount');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Builder
|
||||
*/
|
||||
protected function queryJournalsWithTransactions(Carbon $start, Carbon $end)
|
||||
{
|
||||
$query = TransactionJournal::
|
||||
leftJoin(
|
||||
'transactions as t_from', function (JoinClause $join) {
|
||||
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
|
||||
->leftJoin(
|
||||
'account_meta as acm_from', function (JoinClause $join) {
|
||||
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'transactions as t_to', function (JoinClause $join) {
|
||||
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
|
||||
->leftJoin(
|
||||
'account_meta as acm_to', function (JoinClause $join) {
|
||||
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->where(
|
||||
function ($query) {
|
||||
$query->where(
|
||||
function ($q) {
|
||||
$q->where('transaction_types.type', 'Deposit');
|
||||
$q->where('acm_to.data', '!=', '"sharedExpense"');
|
||||
}
|
||||
);
|
||||
$query->orWhere(
|
||||
function ($q) {
|
||||
$q->where('transaction_types.type', 'Transfer');
|
||||
$q->where('acm_from.data', '=', '"sharedExpense"');
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
->before($end)->after($start)
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->groupBy('t_from.account_id')->orderBy('transaction_journals.date')
|
||||
->get(
|
||||
['transaction_journals.id',
|
||||
'transaction_journals.description',
|
||||
'transaction_journals.encrypted',
|
||||
'transaction_types.type',
|
||||
't_to.amount', 'transaction_journals.date', 't_from.account_id as account_id',
|
||||
'ac_from.name as name']
|
||||
);
|
||||
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
|
||||
->leftJoin(
|
||||
'account_meta as acm_from', function (JoinClause $join) {
|
||||
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'transactions as t_to', function (JoinClause $join) {
|
||||
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
|
||||
->leftJoin(
|
||||
'account_meta as acm_to', function (JoinClause $join) {
|
||||
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
|
||||
$query->before($end)->after($start)->where('transaction_journals.user_id', Auth::user()->id);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of expenses grouped by the budget they were filed under.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function journalsByBudget(Carbon $start, Carbon $end)
|
||||
{
|
||||
return Auth::user()->transactionjournals()
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id')
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
||||
->leftJoin(
|
||||
'account_meta', function (JoinClause $join) {
|
||||
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->where('account_meta.data', '!=', '"sharedExpense"')
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->groupBy('budgets.id')
|
||||
->orderBy('budgets.name', 'ASC')
|
||||
->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) AS `spent`')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of categories and the expenses therein, grouped by the relevant category.
|
||||
* This result excludes transfers to shared accounts which are expenses, technically.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function journalsByCategory(Carbon $start, Carbon $end)
|
||||
{
|
||||
return Auth::user()->transactionjournals()
|
||||
->leftJoin(
|
||||
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
|
||||
)
|
||||
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
||||
->leftJoin(
|
||||
'account_meta', function (JoinClause $join) {
|
||||
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||
->where('account_meta.data', '!=', '"sharedExpense"')
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->groupBy('categories.id')
|
||||
->orderBy('amount')
|
||||
->get(['categories.id', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `amount`')]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of expense accounts and the expenses therein, grouped by that expense account.
|
||||
* This result excludes transfers to shared accounts which are expenses, technically.
|
||||
*
|
||||
* So now it will include them!
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function journalsByExpenseAccount(Carbon $start, Carbon $end)
|
||||
{
|
||||
return TransactionJournal::
|
||||
leftJoin(
|
||||
'transactions as t_from', function (JoinClause $join) {
|
||||
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
|
||||
->leftJoin(
|
||||
'account_meta as acm_from', function (JoinClause $join) {
|
||||
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'transactions as t_to', function (JoinClause $join) {
|
||||
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
|
||||
->leftJoin(
|
||||
'account_meta as acm_to', function (JoinClause $join) {
|
||||
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->where(
|
||||
function ($query) {
|
||||
$query->where(
|
||||
function ($q) {
|
||||
$q->where('transaction_types.type', 'Withdrawal');
|
||||
$q->where('acm_from.data', '!=', '"sharedExpense"');
|
||||
}
|
||||
);
|
||||
$query->orWhere(
|
||||
function ($q) {
|
||||
$q->where('transaction_types.type', 'Transfer');
|
||||
$q->where('acm_to.data', '=', '"sharedExpense"');
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
->before($end)
|
||||
->after($start)
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->groupBy('t_to.account_id')
|
||||
->orderBy('amount', 'DESC')
|
||||
->get(['t_to.account_id as id', 'ac_to.name as name', DB::Raw('SUM(t_to.amount) as `amount`')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns all deposits into asset accounts, grouped by the revenue account,
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function journalsByRevenueAccount(Carbon $start, Carbon $end)
|
||||
{
|
||||
return TransactionJournal::
|
||||
leftJoin(
|
||||
'transactions as t_from', function (JoinClause $join) {
|
||||
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
|
||||
->leftJoin(
|
||||
'account_meta as acm_from', function (JoinClause $join) {
|
||||
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'transactions as t_to', function (JoinClause $join) {
|
||||
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
|
||||
->leftJoin(
|
||||
'account_meta as acm_to', function (JoinClause $join) {
|
||||
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->where(
|
||||
function ($query) {
|
||||
$query->where(
|
||||
function ($q) {
|
||||
$q->where('transaction_types.type', 'Deposit');
|
||||
$q->where('acm_to.data', '!=', '"sharedExpense"');
|
||||
}
|
||||
);
|
||||
$query->orWhere(
|
||||
function ($q) {
|
||||
$q->where('transaction_types.type', 'Transfer');
|
||||
$q->where('acm_from.data', '=', '"sharedExpense"');
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
->before($end)->after($start)
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->groupBy('t_from.account_id')->orderBy('amount')
|
||||
->get(['t_from.account_id as account_id', 'ac_from.name as name', DB::Raw('SUM(t_from.amount) as `amount`')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* With an equally misleading name, this query returns are transfers to shared accounts. These are considered
|
||||
* expenses.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function sharedExpenses(Carbon $start, Carbon $end)
|
||||
{
|
||||
return TransactionJournal::
|
||||
leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where(
|
||||
'transactions.amount', '>', 0
|
||||
);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
||||
->leftJoin(
|
||||
'account_meta', function (JoinClause $join) {
|
||||
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->where('account_meta.data', '"sharedExpense"')
|
||||
->after($start)
|
||||
->before($end)
|
||||
->where('transaction_types.type', 'Transfer')
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->get(
|
||||
['transaction_journals.id', 'transaction_journals.description', 'transactions.account_id', 'accounts.name',
|
||||
'transactions.amount']
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* With a slightly misleading name, this query returns all transfers to shared accounts
|
||||
* which are technically expenses, since it won't be just your money that gets spend.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function sharedExpensesByCategory(Carbon $start, Carbon $end)
|
||||
{
|
||||
return TransactionJournal::
|
||||
leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where(
|
||||
'transactions.amount', '>', 0
|
||||
);
|
||||
}
|
||||
)
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
|
||||
->leftJoin(
|
||||
'account_meta', function (JoinClause $join) {
|
||||
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
|
||||
)
|
||||
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
|
||||
->where('account_meta.data', '"sharedExpense"')
|
||||
->after($start)
|
||||
->before($end)
|
||||
->where('transaction_types.type', 'Transfer')
|
||||
->where('transaction_journals.user_id', Auth::user()->id)
|
||||
->groupBy('categories.name')
|
||||
->get(
|
||||
[
|
||||
'categories.id',
|
||||
'categories.name as name',
|
||||
DB::Raw('SUM(`transactions`.`amount`) * -1 AS `amount`')
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace FireflyIII\Helpers\Report;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Budget;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
@@ -15,120 +16,66 @@ interface ReportQueryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* This query retrieves a list of accounts that are active and not shared.
|
||||
* See ReportQueryInterface::incomeInPeriodCorrected
|
||||
*
|
||||
* This method returns all "expense" journals in a certain period, which are both transfers to a shared account
|
||||
* and "ordinary" withdrawals. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
|
||||
* not group and returns different fields.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param bool $includeShared
|
||||
*
|
||||
* @return Collection
|
||||
*
|
||||
*/
|
||||
public function accountList();
|
||||
public function expenseInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false);
|
||||
|
||||
/**
|
||||
* Get a users accounts combined with various meta-data related to the start and end date.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param bool $includeShared
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAllAccounts(Carbon $start, Carbon $end);
|
||||
public function getAllAccounts(Carbon $start, Carbon $end, $includeShared = false);
|
||||
|
||||
/**
|
||||
* This method returns all "income" journals in a certain period, which are both transfers from a shared account
|
||||
* and "ordinary" deposits. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
|
||||
* not group and returns different fields.
|
||||
* This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results
|
||||
* will simply list the transaction journals only. This should allow any follow up counting to be accurate with
|
||||
* regards to tags.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param bool $includeShared
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function incomeByPeriod(Carbon $start, Carbon $end);
|
||||
public function incomeInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false);
|
||||
|
||||
/**
|
||||
* Gets a list of expenses grouped by the budget they were filed under.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function journalsByBudget(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* Gets a list of categories and the expenses therein, grouped by the relevant category.
|
||||
* This result excludes transfers to shared accounts which are expenses, technically.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function journalsByCategory(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* Gets a list of expense accounts and the expenses therein, grouped by that expense account.
|
||||
* This result excludes transfers to shared accounts which are expenses, technically.
|
||||
*
|
||||
* So now it will include them!
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function journalsByExpenseAccount(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* This method returns all deposits into asset accounts, grouped by the revenue account,
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function journalsByRevenueAccount(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* With an equally misleading name, this query returns are transfers to shared accounts. These are considered
|
||||
* expenses.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function sharedExpenses(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* With a slightly misleading name, this query returns all transfers to shared accounts
|
||||
* which are technically expenses, since it won't be just your money that gets spend.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function sharedExpensesByCategory(Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* Grabs a summary of all expenses grouped by budget, related to the account.
|
||||
* Covers tags as well.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Budget $budget
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
*
|
||||
* @return mixed
|
||||
* @return float
|
||||
*/
|
||||
public function getBudgetSummary(Account $account, Carbon $start, Carbon $end);
|
||||
public function spentInBudgetCorrected(Account $account, Budget $budget, Carbon $start, Carbon $end);
|
||||
|
||||
/**
|
||||
* This method will get a list of all expenses in a certain time period that have no budget
|
||||
* and are balanced by a transfer to make up for it.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param bool $shared
|
||||
*
|
||||
* @return Collection
|
||||
* @return string
|
||||
*/
|
||||
public function balancedTransactionsList(Account $account, Carbon $start, Carbon $end);
|
||||
}
|
||||
public function spentNoBudget(Account $account, Carbon $start, Carbon $end, $shared = false);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use App;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\AccountFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use Steam;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
@@ -21,12 +22,13 @@ use View;
|
||||
class AccountController extends Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('mainTitleIcon', 'fa-credit-card');
|
||||
View::share('title', 'Accounts');
|
||||
View::share('title', trans('firefly.accounts'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,8 +38,16 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function create($what = 'asset')
|
||||
{
|
||||
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $what);
|
||||
$subTitle = 'Create a new ' . e($what) . ' account';
|
||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||
$subTitle = trans('firefly.make_new_' . $what . '_account');
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('accounts.create.fromStore') !== true) {
|
||||
Session::put('accounts.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('accounts.create.fromStore');
|
||||
Session::flash('gaEventCategory', 'accounts');
|
||||
Session::flash('gaEventAction', 'create-' . $what);
|
||||
|
||||
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
|
||||
|
||||
@@ -50,17 +60,24 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function delete(Account $account)
|
||||
{
|
||||
$subTitle = 'Delete ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
|
||||
$typeName = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
$subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]);
|
||||
|
||||
// put previous url in session
|
||||
Session::put('accounts.delete.url', URL::previous());
|
||||
Session::flash('gaEventCategory', 'accounts');
|
||||
Session::flash('gaEventAction', 'delete-' . $typeName);
|
||||
|
||||
return view('accounts.delete', compact('account', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Account $account, AccountRepositoryInterface $repository)
|
||||
public function destroy(AccountRepositoryInterface $repository, Account $account)
|
||||
{
|
||||
|
||||
$type = $account->accountType->type;
|
||||
@@ -69,70 +86,103 @@ class AccountController extends Controller
|
||||
|
||||
$repository->destroy($account);
|
||||
|
||||
Session::flash('success', 'The ' . e($typeName) . ' account "' . e($name) . '" was deleted.');
|
||||
Session::flash('success', trans('firefly.' . $typeName . '_deleted', ['name' => $name]));
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('accounts.index', $typeName);
|
||||
return Redirect::to(Session::get('accounts.delete.url'));
|
||||
}
|
||||
|
||||
public function edit(Account $account, AccountRepositoryInterface $repository)
|
||||
/**
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(AccountRepositoryInterface $repository, Account $account)
|
||||
{
|
||||
|
||||
$what = Config::get('firefly.shortNamesByFullName')[$account->accountType->type];
|
||||
$subTitle = 'Edit ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
|
||||
$subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
|
||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||
$openingBalance = $repository->openingBalanceTransaction($account);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('accounts.edit.fromUpdate') !== true) {
|
||||
Session::put('accounts.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('accounts.edit.fromUpdate');
|
||||
|
||||
// pre fill some useful values.
|
||||
|
||||
// the opening balance is tricky:
|
||||
$openingBalanceAmount = null;
|
||||
|
||||
if ($openingBalance) {
|
||||
$transaction = $openingBalance->transactions()->where('account_id', $account->id)->first();
|
||||
$transaction = $repository->getFirstTransaction($openingBalance, $account);
|
||||
$openingBalanceAmount = $transaction->amount;
|
||||
}
|
||||
|
||||
$preFilled = [
|
||||
'accountRole' => $account->getMeta('accountRole'),
|
||||
'openingBalanceDate' => $openingBalance ? $openingBalance->date->format('Y-m-d') : null,
|
||||
'openingBalance' => $openingBalanceAmount
|
||||
'accountRole' => $account->getMeta('accountRole'),
|
||||
'ccType' => $account->getMeta('ccType'),
|
||||
'ccMonthlyPaymentDate' => $account->getMeta('ccMonthlyPaymentDate'),
|
||||
'openingBalanceDate' => $openingBalance ? $openingBalance->date->format('Y-m-d') : null,
|
||||
'openingBalance' => $openingBalanceAmount,
|
||||
'virtualBalance' => floatval($account->virtual_balance)
|
||||
];
|
||||
Session::flash('preFilled', $preFilled);
|
||||
Session::flash('gaEventCategory', 'accounts');
|
||||
Session::flash('gaEventAction', 'edit-' . $what);
|
||||
|
||||
return view('accounts.edit', compact('account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $what
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param $what
|
||||
*
|
||||
* @return View
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index($what = 'default')
|
||||
public function index(AccountRepositoryInterface $repository, $what)
|
||||
{
|
||||
$subTitle = Config::get('firefly.subTitlesByIdentifier.' . $what);
|
||||
$subTitle = trans('firefly.' . $what . '_accounts');
|
||||
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
|
||||
$types = Config::get('firefly.accountTypesByIdentifier.' . $what);
|
||||
$accounts = Auth::user()->accounts()->accountTypeIn($types)->get(['accounts.*']);
|
||||
$accounts = $repository->getAccounts($types);
|
||||
// last activity:
|
||||
/**
|
||||
* HERE WE ARE
|
||||
*/
|
||||
$start = clone Session::get('start', Carbon::now()->startOfMonth());
|
||||
$start->subDay();
|
||||
$accounts->each(
|
||||
function (Account $account) use ($start, $repository) {
|
||||
$account->lastActivityDate = $repository->getLastActivity($account);
|
||||
$account->startBalance = Steam::balance($account, $start);
|
||||
$account->endBalance = Steam::balance($account, clone Session::get('end', Carbon::now()->endOfMonth()));
|
||||
}
|
||||
);
|
||||
|
||||
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param string $range
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(Account $account, $range = 'session')
|
||||
public function show(AccountRepositoryInterface $repository, Account $account)
|
||||
{
|
||||
/** @var \FireflyIII\Repositories\Account\AccountRepositoryInterface $repository */
|
||||
$repository = App::make('FireflyIII\Repositories\Account\AccountRepositoryInterface');
|
||||
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
|
||||
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $account->accountType->type);
|
||||
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
$journals = $repository->getJournals($account, $page, $range);
|
||||
$subTitle = 'Details for ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
|
||||
$journals = $repository->getJournals($account, $page);
|
||||
$subTitle = trans('firefly.details_for_' . $what, ['name' => $account->name]);
|
||||
$journals->setPath('accounts/show/' . $account->id);
|
||||
|
||||
return view('accounts.show', compact('account', 'what', 'range', 'subTitleIcon', 'journals', 'subTitle'));
|
||||
|
||||
return view('accounts.show', compact('account', 'what', 'subTitleIcon', 'journals', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,47 +196,70 @@ class AccountController extends Controller
|
||||
$accountData = [
|
||||
'name' => $request->input('name'),
|
||||
'accountType' => $request->input('what'),
|
||||
'virtualBalance' => floatval($request->input('virtualBalance')),
|
||||
'active' => true,
|
||||
'user' => Auth::user()->id,
|
||||
'accountRole' => $request->input('accountRole'),
|
||||
'openingBalance' => floatval($request->input('openingBalance')),
|
||||
'openingBalanceDate' => new Carbon($request->input('openingBalanceDate')),
|
||||
'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')),
|
||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
||||
|
||||
];
|
||||
$account = $repository->store($accountData);
|
||||
|
||||
Session::flash('success', 'New account "' . $account->name . '" stored!');
|
||||
Preferences::mark();
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('accounts.create.fromStore', true);
|
||||
|
||||
return Redirect::route('accounts.create')->withInput();
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('accounts.create.url'));
|
||||
|
||||
return Redirect::route('accounts.index', $request->input('what'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param AccountFormRequest $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(Account $account, AccountFormRequest $request, AccountRepositoryInterface $repository)
|
||||
public function update(AccountFormRequest $request, AccountRepositoryInterface $repository, Account $account)
|
||||
{
|
||||
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||
|
||||
$accountData = [
|
||||
'name' => $request->input('name'),
|
||||
'active' => $request->input('active'),
|
||||
'user' => Auth::user()->id,
|
||||
'accountRole' => $request->input('accountRole'),
|
||||
'virtualBalance' => floatval($request->input('virtualBalance')),
|
||||
'openingBalance' => floatval($request->input('openingBalance')),
|
||||
'openingBalanceDate' => new Carbon($request->input('openingBalanceDate')),
|
||||
'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')),
|
||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
||||
'ccType' => $request->input('ccType'),
|
||||
'ccMonthlyPaymentDate' => $request->input('ccMonthlyPaymentDate'),
|
||||
];
|
||||
|
||||
$repository->update($account, $accountData);
|
||||
|
||||
Session::flash('success', 'Account "' . $account->name . '" updated.');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('accounts.index', $what);
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('accounts.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('accounts.edit', [$account->id])->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('accounts.edit.url'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
<?php namespace FireflyIII\Http\Controllers\Auth;
|
||||
|
||||
use App;
|
||||
use Auth;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Contracts\Auth\Registrar;
|
||||
use FireflyIII\Models\Role;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Mail\Message;
|
||||
use Mail;
|
||||
use Session;
|
||||
use Twig;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
* Class AuthController
|
||||
@@ -31,16 +39,113 @@ class AuthController extends Controller
|
||||
/**
|
||||
* Create a new authentication controller instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Guard $auth
|
||||
* @param \Illuminate\Contracts\Auth\Registrar $registrar
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
*/
|
||||
public function __construct(Guard $auth, Registrar $registrar)
|
||||
public function __construct()
|
||||
{
|
||||
$this->auth = $auth;
|
||||
$this->registrar = $registrar;
|
||||
|
||||
$this->middleware('guest', ['except' => 'getLogout']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application login form.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
*/
|
||||
public function getLogin()
|
||||
{
|
||||
return Twig::render('auth.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a registration request for the application.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function postRegister(Request $request)
|
||||
{
|
||||
$validator = $this->validator($request->all());
|
||||
|
||||
if ($validator->fails()) {
|
||||
$this->throwValidationException(
|
||||
$request, $validator
|
||||
);
|
||||
// @codeCoverageIgnoreStart
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$data = $request->all();
|
||||
$data['password'] = bcrypt($data['password']);
|
||||
|
||||
Auth::login($this->create($data));
|
||||
|
||||
// get the email address
|
||||
if (Auth::user() instanceof User) {
|
||||
$email = Auth::user()->email;
|
||||
$address = route('index');
|
||||
// send email.
|
||||
Mail::send(
|
||||
['emails.registered-html', 'emails.registered'], ['address' => $address], function (Message $message) use ($email) {
|
||||
$message->to($email, $email)->subject('Welcome to Firefly III! ');
|
||||
}
|
||||
);
|
||||
|
||||
// set flash message
|
||||
Session::flash('success', 'You have registered successfully!');
|
||||
Session::flash('gaEventCategory', 'user');
|
||||
Session::flash('gaEventAction', 'new-registration');
|
||||
|
||||
// first user ever?
|
||||
if (User::count() == 1) {
|
||||
$admin = Role::where('name', 'owner')->first();
|
||||
Auth::user()->attachRole($admin);
|
||||
}
|
||||
|
||||
|
||||
return redirect($this->redirectPath());
|
||||
}
|
||||
// @codeCoverageIgnoreStart
|
||||
App::abort(500, 'Not a user!');
|
||||
|
||||
return redirect('/');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a validator for an incoming registration request.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public function validator(array $data)
|
||||
{
|
||||
return Validator::make(
|
||||
$data, [
|
||||
'email' => 'required|email|max:255|unique:users',
|
||||
'password' => 'required|confirmed|min:6',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user instance after a valid registration.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function create(array $data)
|
||||
{
|
||||
return User::create(
|
||||
[
|
||||
'email' => $data['email'],
|
||||
'password' => $data['password'],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<?php namespace FireflyIII\Http\Controllers\Auth;
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Contracts\Auth\PasswordBroker;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
|
||||
/**
|
||||
* Class PasswordController
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Controllers\Auth
|
||||
*/
|
||||
class PasswordController extends Controller
|
||||
@@ -32,15 +31,11 @@ class PasswordController extends Controller
|
||||
/**
|
||||
* Create a new password controller instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Guard $auth
|
||||
* @param \Illuminate\Contracts\Auth\PasswordBroker $passwords
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
*/
|
||||
public function __construct(Guard $auth, PasswordBroker $passwords)
|
||||
public function __construct()
|
||||
{
|
||||
$this->auth = $auth;
|
||||
$this->passwords = $passwords;
|
||||
|
||||
|
||||
$this->middleware('guest');
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Requests;
|
||||
use Config;
|
||||
use FireflyIII\Http\Requests\BillFormRequest;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use URL;
|
||||
@@ -21,56 +20,88 @@ use View;
|
||||
class BillController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
View::share('title', 'Bills');
|
||||
parent::__construct();
|
||||
View::share('title', trans('firefly.bills'));
|
||||
View::share('mainTitleIcon', 'fa-calendar-o');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$periods = \Config::get('firefly.periods_to_text');
|
||||
$periods = Config::get('firefly.periods_to_text');
|
||||
$subTitle = trans('firefly.create_new_bill');
|
||||
|
||||
return view('bills.create')->with('periods', $periods)->with('subTitle', 'Create new');
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('bills.create.fromStore') !== true) {
|
||||
Session::put('bills.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('bills.create.fromStore');
|
||||
Session::flash('gaEventCategory', 'bills');
|
||||
Session::flash('gaEventAction', 'create');
|
||||
|
||||
return view('bills.create', compact('periods', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return $this
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function delete(Bill $bill)
|
||||
{
|
||||
return view('bills.delete')->with('bill', $bill)->with('subTitle', 'Delete "' . e($bill->name) . '"');
|
||||
// put previous url in session
|
||||
Session::put('bills.delete.url', URL::previous());
|
||||
Session::flash('gaEventCategory', 'bills');
|
||||
Session::flash('gaEventAction', 'delete');
|
||||
$subTitle = trans('firefly.delete_bill', ['name' => $bill->name]);
|
||||
|
||||
return view('bills.delete', compact('bill', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param BillRepositoryInterface $repository
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Bill $bill)
|
||||
public function destroy(BillRepositoryInterface $repository, Bill $bill)
|
||||
{
|
||||
$bill->delete();
|
||||
Session::flash('success', 'The bill was deleted.');
|
||||
$repository->destroy($bill);
|
||||
|
||||
return Redirect::route('bills.index');
|
||||
Session::flash('success', 'The bill was deleted.');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::to(Session::get('bills.delete.url'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return $this
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Bill $bill)
|
||||
{
|
||||
$periods = \Config::get('firefly.periods_to_text');
|
||||
$periods = Config::get('firefly.periods_to_text');
|
||||
$subTitle = trans('firefly.edit_bill', ['name' => $bill->name]);
|
||||
|
||||
return view('bills.edit')->with('periods', $periods)->with('bill', $bill)->with('subTitle', 'Edit "' . e($bill->name) . '"');
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('bills.edit.fromUpdate') !== true) {
|
||||
Session::put('bills.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('bills.edit.fromUpdate');
|
||||
Session::flash('gaEventCategory', 'bills');
|
||||
Session::flash('gaEventAction', 'edit');
|
||||
|
||||
return view('bills.edit', compact('subTitle', 'periods', 'bill'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,15 +111,11 @@ class BillController extends Controller
|
||||
*/
|
||||
public function index(BillRepositoryInterface $repository)
|
||||
{
|
||||
$bills = Auth::user()->bills()->get();
|
||||
$bills = $repository->getBills();
|
||||
$bills->each(
|
||||
function (Bill $bill) use ($repository) {
|
||||
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
|
||||
$last = $bill->transactionjournals()->orderBy('date', 'DESC')->first();
|
||||
$bill->lastFoundMatch = null;
|
||||
if ($last) {
|
||||
$bill->lastFoundMatch = $last->date;
|
||||
}
|
||||
$bill->lastFoundMatch = $repository->lastFoundMatch($bill);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -96,144 +123,97 @@ class BillController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param BillRepositoryInterface $repository
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return mixed
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function rescan(Bill $bill, BillRepositoryInterface $repository)
|
||||
public function rescan(BillRepositoryInterface $repository, Bill $bill)
|
||||
{
|
||||
if (intval($bill->active) == 0) {
|
||||
Session::flash('warning', 'Inactive bills cannot be scanned.');
|
||||
|
||||
return Redirect::intended('/');
|
||||
return Redirect::to(URL::previous());
|
||||
}
|
||||
|
||||
$set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)->get(['transaction_journal_id']);
|
||||
$ids = [];
|
||||
$journals = $repository->getPossiblyRelatedJournals($bill);
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$repository->scan($bill, $journal);
|
||||
}
|
||||
|
||||
/** @var Transaction $entry */
|
||||
foreach ($set as $entry) {
|
||||
$ids[] = intval($entry->transaction_journal_id);
|
||||
}
|
||||
if (count($ids) > 0) {
|
||||
$journals = Auth::user()->transactionjournals()->whereIn('id',$ids)->get();
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$repository->scan($bill, $journal);
|
||||
}
|
||||
}
|
||||
|
||||
Session::flash('success', 'Rescanned everything.');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::to(URL::previous());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param BillRepositoryInterface $repository
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return mixed
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(Bill $bill, BillRepositoryInterface $repository)
|
||||
public function show(BillRepositoryInterface $repository, Bill $bill)
|
||||
{
|
||||
$journals = $bill->transactionjournals()->withRelevantData()->orderBy('date', 'DESC')->get();
|
||||
$journals = $repository->getJournals($bill);
|
||||
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
|
||||
$hideBill = true;
|
||||
$subTitle = e($bill->name);
|
||||
|
||||
|
||||
return view('bills.show', compact('journals', 'hideBill', 'bill'))->with('subTitle', e($bill->name));
|
||||
return view('bills.show', compact('journals', 'hideBill', 'bill', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @param BillFormRequest $request
|
||||
* @param BillRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(BillFormRequest $request, BillRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
var_dump($request->all());
|
||||
|
||||
$billData = [
|
||||
'name' => $request->get('name'),
|
||||
'match' => $request->get('match'),
|
||||
'amount_min' => floatval($request->get('amount_min')),
|
||||
'amount_currency_id' => floatval($request->get('amount_currency_id')),
|
||||
'amount_max' => floatval($request->get('amount_max')),
|
||||
'date' => new Carbon($request->get('date')),
|
||||
'user' => Auth::user()->id,
|
||||
'repeat_freq' => $request->get('repeat_freq'),
|
||||
'skip' => intval($request->get('skip')),
|
||||
'automatch' => intval($request->get('automatch')) === 1,
|
||||
'active' => intval($request->get('active')) === 1,
|
||||
];
|
||||
|
||||
$bill = $repository->store($billData);
|
||||
$billData = $request->getBillData();
|
||||
$bill = $repository->store($billData);
|
||||
Session::flash('success', 'Bill "' . e($bill->name) . '" stored.');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('bills.index');
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('bills.create.fromStore', true);
|
||||
|
||||
return Redirect::route('bills.create')->withInput();
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('bills.create.url'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param BillFormRequest $request
|
||||
* @param BillRepositoryInterface $repository
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return $this
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(Bill $bill, BillFormRequest $request, BillRepositoryInterface $repository)
|
||||
public function update(BillFormRequest $request, BillRepositoryInterface $repository, Bill $bill)
|
||||
{
|
||||
$billData = [
|
||||
'name' => $request->get('name'),
|
||||
'match' => $request->get('match'),
|
||||
'amount_min' => floatval($request->get('amount_min')),
|
||||
'amount_currency_id' => floatval($request->get('amount_currency_id')),
|
||||
'amount_max' => floatval($request->get('amount_max')),
|
||||
'date' => new Carbon($request->get('date')),
|
||||
'user' => Auth::user()->id,
|
||||
'repeat_freq' => $request->get('repeat_freq'),
|
||||
'skip' => intval($request->get('skip')),
|
||||
'automatch' => intval($request->get('automatch')) === 1,
|
||||
'active' => intval($request->get('active')) === 1,
|
||||
];
|
||||
|
||||
$bill = $repository->update($bill, $billData);
|
||||
$billData = $request->getBillData();
|
||||
$bill = $repository->update($bill, $billData);
|
||||
|
||||
Session::flash('success', 'Bill "' . e($bill->name) . '" updated.');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('bills.index');
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('bills.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('bills.edit', [$bill->id])->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
// $data = Input::except('_token');
|
||||
// $data['active'] = intval(Input::get('active'));
|
||||
// $data['automatch'] = intval(Input::get('automatch'));
|
||||
// $data['user_id'] = Auth::user()->id;
|
||||
//
|
||||
// // always validate:
|
||||
// $messages = $this->_repository->validate($data);
|
||||
//
|
||||
// // flash messages:
|
||||
// Session::flash('warnings', $messages['warnings']);
|
||||
// Session::flash('successes', $messages['successes']);
|
||||
// Session::flash('errors', $messages['errors']);
|
||||
// if ($messages['errors']->count() > 0) {
|
||||
// Session::flash('error', 'Could not update bill: ' . $messages['errors']->first());
|
||||
//
|
||||
// return Redirect::route('bills.edit', $bill->id)->withInput();
|
||||
// }
|
||||
//
|
||||
// // return to update screen:
|
||||
// if ($data['post_submit_action'] == 'validate_only') {
|
||||
// return Redirect::route('bills.edit', $bill->id)->withInput();
|
||||
// }
|
||||
//
|
||||
// // update
|
||||
// $this->_repository->update($bill, $data);
|
||||
// Session::flash('success', 'Bill "' . e($data['name']) . '" updated.');
|
||||
//
|
||||
// // go back to list
|
||||
// if ($data['post_submit_action'] == 'update') {
|
||||
// return Redirect::route('bills.index');
|
||||
// }
|
||||
//
|
||||
// // go back to update screen.
|
||||
// return Redirect::route('bills.edit', $bill->id)->withInput(['post_submit_action' => 'return_to_edit']);
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('bills.edit.url'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Amount;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\BudgetFormRequest;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
@@ -12,44 +12,64 @@ use Preferences;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use Session;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class BudgetController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
* @SuppressWarnings(PHPMD.TooManyMethods)
|
||||
*/
|
||||
class BudgetController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
View::share('title', 'Budgets');
|
||||
parent::__construct();
|
||||
View::share('title', trans('firefly.budgets'));
|
||||
View::share('mainTitleIcon', 'fa-tasks');
|
||||
View::share('hideBudgets', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws Exception
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function amount(Budget $budget, BudgetRepositoryInterface $repository)
|
||||
public function amount(BudgetRepositoryInterface $repository, Budget $budget)
|
||||
{
|
||||
$amount = intval(Input::get('amount'));
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$limitRepetition = $repository->updateLimitAmount($budget, $date, $amount);
|
||||
if ($amount == 0) {
|
||||
$limitRepetition = null;
|
||||
}
|
||||
Preferences::mark();
|
||||
|
||||
return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('budgets.create')->with('subTitle', 'Create a new budget');
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('budgets.create.fromStore') !== true) {
|
||||
Session::put('budgets.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('budgets.create.fromStore');
|
||||
Session::flash('gaEventCategory', 'budgets');
|
||||
Session::flash('gaEventAction', 'create');
|
||||
$subTitle = trans('firefly.create_new_budget');
|
||||
|
||||
return view('budgets.create', compact('subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,13 +79,19 @@ class BudgetController extends Controller
|
||||
*/
|
||||
public function delete(Budget $budget)
|
||||
{
|
||||
$subTitle = 'Delete budget' . e($budget->name) . '"';
|
||||
$subTitle = trans('firefly.delete_budget', ['name' => $budget->name]);
|
||||
|
||||
// put previous url in session
|
||||
Session::put('budgets.delete.url', URL::previous());
|
||||
Session::flash('gaEventCategory', 'budgets');
|
||||
Session::flash('gaEventAction', 'delete');
|
||||
|
||||
return view('budgets.delete', compact('budget', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Budget $budget
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
@@ -75,83 +101,144 @@ class BudgetController extends Controller
|
||||
$name = $budget->name;
|
||||
$repository->destroy($budget);
|
||||
|
||||
Session::flash('success', 'The budget "' . e($name) . '" was deleted.');
|
||||
|
||||
return Redirect::route('budgets.index');
|
||||
Session::flash('success', 'The budget "' . e($name) . '" was deleted.');
|
||||
Preferences::mark();
|
||||
|
||||
|
||||
return Redirect::to(Session::get('budgets.delete.url'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return $this
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Budget $budget)
|
||||
{
|
||||
$subTitle = 'Edit budget "' . e($budget->name) . '"';
|
||||
$subTitle = trans('firefly.edit_budget', ['name' => $budget->name]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('budgets.edit.fromUpdate') !== true) {
|
||||
Session::put('budgets.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('budgets.edit.fromUpdate');
|
||||
Session::flash('gaEventCategory', 'budgets');
|
||||
Session::flash('gaEventAction', 'edit');
|
||||
|
||||
return view('budgets.edit', compact('budget', 'subTitle'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$budgets = Auth::user()->budgets()->get();
|
||||
$budgets = $repository->getActiveBudgets();
|
||||
$inactive = $repository->getInactiveBudgets();
|
||||
$spent = '0';
|
||||
$budgeted = '0';
|
||||
bcscale(2);
|
||||
/**
|
||||
* Do some cleanup:
|
||||
*/
|
||||
$repository->cleanupBudgets();
|
||||
|
||||
|
||||
// loop the budgets:
|
||||
$budgets->each(
|
||||
function (Budget $budget) use ($repository) {
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$budget->spent = $repository->spentInMonth($budget, $date);
|
||||
$budget->currentRep = $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']);
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$budget->spent = $repository->spentInPeriodCorrected($budget, $date, $end);
|
||||
$budget->currentRep = $repository->getCurrentRepetition($budget, $date);
|
||||
if ($budget->currentRep) {
|
||||
$budgeted = bcadd($budgeted, $budget->currentRep->amount);
|
||||
}
|
||||
$spent = bcadd($spent, $budget->spent);
|
||||
|
||||
}
|
||||
|
||||
$dateAsString = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
|
||||
$budgetIncomeTotal = Preferences::get('budgetIncomeTotal' . $dateAsString, 1000)->data;
|
||||
$budgetMaximum = Preferences::get('budgetMaximum', 1000)->data;
|
||||
$defaultCurrency = Amount::getDefaultCurrency();
|
||||
|
||||
return view(
|
||||
'budgets.index', compact('budgetMaximum', 'budgetIncomeTotal', 'defaultCurrency', 'inactive', 'budgets', 'spent', 'budgeted')
|
||||
);
|
||||
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
|
||||
$spent = $budgets->sum('spent');
|
||||
$amount = Preferences::get('budgetIncomeTotal' . $date, 1000)->data;
|
||||
$overspent = $spent > $amount;
|
||||
$spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100);
|
||||
$budgetMax = Preferences::get('budgetMaximum', 1000);
|
||||
$budgetMaximum = $budgetMax->data;
|
||||
|
||||
return view('budgets.index', compact('budgetMaximum', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function noBudget()
|
||||
public function noBudget(BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$start = \Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = \Session::get('end', Carbon::now()->startOfMonth());
|
||||
$list = Auth::user()
|
||||
->transactionjournals()
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->whereNull('budget_transaction_journal.id')
|
||||
->before($end)
|
||||
->after($start)
|
||||
->orderBy('transaction_journals.date')
|
||||
->get(['transaction_journals.*']);
|
||||
$subTitle = 'Transactions without a budget in ' . $start->format('F Y');
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->startOfMonth());
|
||||
$list = $repository->getWithoutBudget($start, $end);
|
||||
$subTitle = trans(
|
||||
'firefly.without_budget_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
|
||||
return view('budgets.noBudget', compact('list', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function postUpdateIncome()
|
||||
{
|
||||
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
|
||||
Preferences::set('budgetIncomeTotal' . $date, intval(Input::get('amount')));
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('budgets.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
* @param Budget $budget
|
||||
* @param LimitRepetition $repetition
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(BudgetRepositoryInterface $repository, Budget $budget, LimitRepetition $repetition = null)
|
||||
{
|
||||
if (!is_null($repetition->id) && $repetition->budgetLimit->budget->id != $budget->id) {
|
||||
$message = 'Invalid selection.';
|
||||
|
||||
return view('error', compact('message'));
|
||||
}
|
||||
|
||||
$journals = $repository->getJournals($budget, $repetition);
|
||||
|
||||
if (is_null($repetition->id)) {
|
||||
$limits = $repository->getBudgetLimits($budget);
|
||||
$subTitle = e($budget->name);
|
||||
} else {
|
||||
$limits = [$repetition->budgetLimit];
|
||||
$subTitle = trans('firefly.budget_in_month', ['name' => $budget->name, 'month' => $repetition->startdate->formatLocalized($this->monthFormat)]);
|
||||
}
|
||||
|
||||
$journals->setPath('/budgets/show/' . $budget->id);
|
||||
|
||||
return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetFormRequest $request
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(BudgetFormRequest $request, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$budgetData = [
|
||||
@@ -161,62 +248,60 @@ class BudgetController extends Controller
|
||||
$budget = $repository->store($budgetData);
|
||||
|
||||
Session::flash('success', 'New budget "' . $budget->name . '" stored!');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('budgets.index');
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('budgets.create.fromStore', true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param LimitRepetition $repetition
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(Budget $budget, LimitRepetition $repetition = null, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
if (!is_null($repetition->id) && $repetition->budgetLimit->budget->id != $budget->id) {
|
||||
return view('error')->with('message', 'Invalid selection.');
|
||||
return Redirect::route('budgets.create')->withInput();
|
||||
}
|
||||
|
||||
$hideBudget = true; // used in transaction list.
|
||||
$journals = $repository->getJournals($budget, $repetition);
|
||||
$limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $budget->budgetLimits()->orderBy('startdate', 'DESC')->get();
|
||||
$subTitle = !is_null($repetition->id) ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name);
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('budgets.create.url'));
|
||||
|
||||
return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle', 'hideBudget'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param BudgetFormRequest $request
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(Budget $budget, BudgetFormRequest $request, BudgetRepositoryInterface $repository)
|
||||
public function update(BudgetFormRequest $request, BudgetRepositoryInterface $repository, Budget $budget)
|
||||
{
|
||||
$budgetData = [
|
||||
'name' => $request->input('name'),
|
||||
'name' => $request->input('name'),
|
||||
'active' => intval($request->input('active')) == 1
|
||||
];
|
||||
|
||||
$repository->update($budget, $budgetData);
|
||||
|
||||
Session::flash('success', 'Budget "' . $budget->name . '" updated.');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('budgets.index');
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('budgets.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('budgets.edit', [$budget->id])->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('budgets.edit.url'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function updateIncome()
|
||||
{
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
|
||||
$budgetAmount = Preferences::get('budgetIncomeTotal' . $date, 1000);
|
||||
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
|
||||
$amount = Preferences::get('budgetIncomeTotal' . $date, 1000);
|
||||
|
||||
return view('budgets.income')->with('amount', $budgetAmount);
|
||||
return view('budgets.income', compact('amount'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\CategoryFormRequest;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use URL;
|
||||
use View;
|
||||
use Input;
|
||||
|
||||
|
||||
/**
|
||||
* Class CategoryController
|
||||
@@ -22,58 +22,30 @@ class CategoryController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
View::share('title', 'Categories');
|
||||
parent::__construct();
|
||||
View::share('title', trans('firefly.categories'));
|
||||
View::share('mainTitleIcon', 'fa-bar-chart');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('categories.create')->with('subTitle', 'Create a new category');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function show(Category $category, CategoryRepositoryInterface $repository)
|
||||
{
|
||||
$hideCategory = true; // used in list.
|
||||
$page = intval(Input::get('page'));
|
||||
$offset = $page > 0 ? $page * 50 : 0;
|
||||
$set = $category->transactionJournals()->withRelevantData()->take(50)->offset($offset)->orderBy('date', 'DESC')->get(['transaction_journals.*']);
|
||||
$count = $category->transactionJournals()->count();
|
||||
|
||||
$journals = new LengthAwarePaginator($set, $count, 50, $page);
|
||||
|
||||
return view('categories.show', compact('category', 'journals', 'hideCategory'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function noCategory()
|
||||
public function create()
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->startOfMonth());
|
||||
$list = Auth::user()
|
||||
->transactionjournals()
|
||||
->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->whereNull('category_transaction_journal.id')
|
||||
->before($end)
|
||||
->after($start)
|
||||
->orderBy('transaction_journals.date')
|
||||
->get(['transaction_journals.*']);
|
||||
$subTitle = 'Transactions without a category in ' . $start->format('F Y');
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('categories.create.fromStore') !== true) {
|
||||
Session::put('categories.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('categories.create.fromStore');
|
||||
Session::flash('gaEventCategory', 'categories');
|
||||
Session::flash('gaEventAction', 'create');
|
||||
$subTitle = trans('firefly.create_new_category');
|
||||
|
||||
return view('categories.noCategory', compact('list', 'subTitle'));
|
||||
return view('categories.create', compact('subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,55 +55,114 @@ class CategoryController extends Controller
|
||||
*/
|
||||
public function delete(Category $category)
|
||||
{
|
||||
$subTitle = 'Delete category' . e($category->name) . '"';
|
||||
$subTitle = trans('firefly.delete_category', ['name' => $category->name]);
|
||||
|
||||
// put previous url in session
|
||||
Session::put('categories.delete.url', URL::previous());
|
||||
Session::flash('gaEventCategory', 'categories');
|
||||
Session::flash('gaEventAction', 'delete');
|
||||
|
||||
return view('categories.delete', compact('category', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
* @param Category $category
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Category $category, CategoryRepositoryInterface $repository)
|
||||
public function destroy(CategoryRepositoryInterface $repository, Category $category)
|
||||
{
|
||||
|
||||
$name = $category->name;
|
||||
$repository->destroy($category);
|
||||
|
||||
Session::flash('success', 'The category "' . e($name) . '" was deleted.');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('categories.index');
|
||||
return Redirect::to(Session::get('categories.delete.url'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return $this
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Category $category)
|
||||
{
|
||||
$subTitle = 'Edit category "' . e($category->name) . '"';
|
||||
$subTitle = trans('firefly.edit_category', ['name' => $category->name]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('categories.edit.fromUpdate') !== true) {
|
||||
Session::put('categories.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('categories.edit.fromUpdate');
|
||||
Session::flash('gaEventCategory', 'categories');
|
||||
Session::flash('gaEventAction', 'edit');
|
||||
|
||||
return view('categories.edit', compact('category', 'subTitle'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
public function index(CategoryRepositoryInterface $repository)
|
||||
{
|
||||
$categories = Auth::user()->categories()->get();
|
||||
$categories = $repository->getCategories();
|
||||
|
||||
$categories->each(
|
||||
function (Category $category) use ($repository) {
|
||||
$category->lastActivity = $repository->getLatestActivity($category);
|
||||
}
|
||||
);
|
||||
|
||||
return view('categories.index', compact('categories'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function noCategory(CategoryRepositoryInterface $repository)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->startOfMonth());
|
||||
$list = $repository->getWithoutCategory($start, $end);
|
||||
$subTitle = trans(
|
||||
'firefly.without_category_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
|
||||
return view('categories.noCategory', compact('list', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
* @param Category $category
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(CategoryRepositoryInterface $repository, Category $category)
|
||||
{
|
||||
$hideCategory = true; // used in list.
|
||||
$page = intval(Input::get('page'));
|
||||
$set = $repository->getJournals($category, $page);
|
||||
$count = $repository->countJournals($category);
|
||||
$journals = new LengthAwarePaginator($set, $count, 50, $page);
|
||||
$journals->setPath('categories/show/' . $category->id);
|
||||
|
||||
return view('categories.show', compact('category', 'journals', 'hideCategory'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CategoryFormRequest $request
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
*
|
||||
* @return mixed
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(CategoryFormRequest $request, CategoryRepositoryInterface $repository)
|
||||
{
|
||||
@@ -142,20 +173,26 @@ class CategoryController extends Controller
|
||||
$category = $repository->store($categoryData);
|
||||
|
||||
Session::flash('success', 'New category "' . $category->name . '" stored!');
|
||||
Preferences::mark();
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
Session::put('categories.create.fromStore', true);
|
||||
|
||||
return Redirect::route('categories.create')->withInput();
|
||||
}
|
||||
|
||||
return Redirect::route('categories.index');
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param CategoryFormRequest $request
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
* @param Category $category
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(Category $category, CategoryFormRequest $request, CategoryRepositoryInterface $repository)
|
||||
public function update(CategoryFormRequest $request, CategoryRepositoryInterface $repository, Category $category)
|
||||
{
|
||||
$categoryData = [
|
||||
'name' => $request->input('name'),
|
||||
@@ -164,8 +201,16 @@ class CategoryController extends Controller
|
||||
$repository->update($category, $categoryData);
|
||||
|
||||
Session::flash('success', 'Category "' . $category->name . '" updated.');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('categories.index');
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
Session::put('categories.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('categories.edit', [$category->id]);
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('categories.edit.url'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
144
app/Http/Controllers/Chart/AccountController.php
Normal file
144
app/Http/Controllers/Chart/AccountController.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Chart;
|
||||
|
||||
use App;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use Session;
|
||||
|
||||
/**
|
||||
* Class AccountController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers\Chart
|
||||
*/
|
||||
class AccountController extends Controller
|
||||
{
|
||||
|
||||
/** @var \FireflyIII\Generator\Chart\Account\AccountChartGenerator */
|
||||
protected $generator;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
// create chart generator:
|
||||
$this->generator = App::make('FireflyIII\Generator\Chart\Account\AccountChartGenerator');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows the balances for all the user's accounts.
|
||||
*
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @param $year
|
||||
* @param $month
|
||||
* @param bool $shared
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function all(AccountRepositoryInterface $repository, $year, $month, $shared = false)
|
||||
{
|
||||
$start = new Carbon($year . '-' . $month . '-01');
|
||||
$end = clone $start;
|
||||
$end->endOfMonth();
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('all');
|
||||
$cache->addProperty('accounts');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/** @var Collection $accounts */
|
||||
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
|
||||
if ($shared === false) {
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $index => $account) {
|
||||
if ($account->getMeta('accountRole') == 'sharedAsset') {
|
||||
$accounts->forget($index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make chart:
|
||||
$data = $this->generator->all($accounts, $start, $end);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the balances for all the user's frontpage accounts.
|
||||
*
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function frontpage(AccountRepositoryInterface $repository)
|
||||
{
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
$start = clone Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = clone Session::get('end', Carbon::now()->endOfMonth());
|
||||
$accounts = $repository->getFrontpageAccounts($frontPage);
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('frontpage');
|
||||
$cache->addProperty('accounts');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$data = $this->generator->frontpage($accounts, $start, $end);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an account's balance for a single month.
|
||||
*
|
||||
* @param Account $account
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function single(Account $account)
|
||||
{
|
||||
|
||||
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('frontpage');
|
||||
$cache->addProperty('single');
|
||||
$cache->addProperty($account->id);
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$data = $this->generator->single($account, $start, $end);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
}
|
||||
145
app/Http/Controllers/Chart/BillController.php
Normal file
145
app/Http/Controllers/Chart/BillController.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Chart;
|
||||
|
||||
use App;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
use Response;
|
||||
use Session;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class BillController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers\Chart
|
||||
*/
|
||||
class BillController extends Controller
|
||||
{
|
||||
|
||||
/** @var \FireflyIII\Generator\Chart\Bill\BillChartGenerator */
|
||||
protected $generator;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
// create chart generator:
|
||||
$this->generator = App::make('FireflyIII\Generator\Chart\Bill\BillChartGenerator');
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows all bills and whether or not theyve been paid this month (pie chart).
|
||||
*
|
||||
* @param BillRepositoryInterface $repository
|
||||
* @param AccountRepositoryInterface $accounts
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function frontpage(BillRepositoryInterface $repository, AccountRepositoryInterface $accounts)
|
||||
{
|
||||
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('bills');
|
||||
$cache->addProperty('frontpage');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$bills = $repository->getActiveBills();
|
||||
$paid = new Collection; // journals.
|
||||
$unpaid = new Collection; // bills
|
||||
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
$ranges = $repository->getRanges($bill, $start, $end);
|
||||
|
||||
foreach ($ranges as $range) {
|
||||
// paid a bill in this range?
|
||||
$journals = $repository->getJournalsInRange($bill, $range['start'], $range['end']);
|
||||
if ($journals->count() == 0) {
|
||||
$unpaid->push([$bill, $range['start']]);
|
||||
} else {
|
||||
$paid = $paid->merge($journals);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$creditCards = $accounts->getCreditCards();
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, $end, true);
|
||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||
if ($balance < 0) {
|
||||
// unpaid! create a fake bill that matches the amount.
|
||||
$description = $creditCard->name;
|
||||
$amount = $balance * -1;
|
||||
$fakeBill = $repository->createFakeBill($description, $date, $amount);
|
||||
unset($description, $amount);
|
||||
$unpaid->push([$fakeBill, $date]);
|
||||
}
|
||||
if ($balance == 0) {
|
||||
// find transfer(s) TO the credit card which should account for
|
||||
// anything paid. If not, the CC is not yet used.
|
||||
$journals = $accounts->getTransfersInRange($creditCard, $start, $end);
|
||||
$paid = $paid->merge($journals);
|
||||
}
|
||||
}
|
||||
|
||||
// build chart:
|
||||
$data = $this->generator->frontpage($paid, $unpaid);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the overview for a bill. The min/max amount and matched journals.
|
||||
*
|
||||
* @param BillRepositoryInterface $repository
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function single(BillRepositoryInterface $repository, Bill $bill)
|
||||
{
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('single');
|
||||
$cache->addProperty('bill');
|
||||
$cache->addProperty($bill->id);
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// get first transaction or today for start:
|
||||
$results = $repository->getJournals($bill);
|
||||
|
||||
// resort:
|
||||
$results = $results->sortBy(
|
||||
function (TransactionJournal $journal) {
|
||||
return $journal->date->format('U');
|
||||
}
|
||||
);
|
||||
|
||||
$data = $this->generator->single($bill, $results);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
}
|
||||
239
app/Http/Controllers/Chart/BudgetController.php
Normal file
239
app/Http/Controllers/Chart/BudgetController.php
Normal file
@@ -0,0 +1,239 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Chart;
|
||||
|
||||
use App;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use Session;
|
||||
|
||||
/**
|
||||
* Class BudgetController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers\Chart
|
||||
*/
|
||||
class BudgetController extends Controller
|
||||
{
|
||||
|
||||
/** @var \FireflyIII\Generator\Chart\Budget\BudgetChartGenerator */
|
||||
protected $generator;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
// create chart generator:
|
||||
$this->generator = App::make('FireflyIII\Generator\Chart\Budget\BudgetChartGenerator');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function budget(BudgetRepositoryInterface $repository, Budget $budget)
|
||||
{
|
||||
|
||||
// dates and times
|
||||
$first = $repository->getFirstBudgetLimitDate($budget);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$last = Session::get('end', new Carbon);
|
||||
$final = clone $last;
|
||||
$final->addYears(2);
|
||||
$last = Navigation::endOfX($last, $range, $final);
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($first);
|
||||
$cache->addProperty($last);
|
||||
$cache->addProperty('budget');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$entries = new Collection;
|
||||
|
||||
while ($first < $last) {
|
||||
$end = Navigation::addPeriod($first, $range, 0);
|
||||
$end->subDay();
|
||||
$chartDate = clone $end;
|
||||
$chartDate->startOfMonth();
|
||||
$spent = $repository->spentInPeriodCorrected($budget, $first, $end);
|
||||
$entries->push([$chartDate, $spent]);
|
||||
$first = Navigation::addPeriod($first, $range, 0);
|
||||
}
|
||||
|
||||
$data = $this->generator->budget($entries);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the amount left in a specific budget limit.
|
||||
*
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
* @param Budget $budget
|
||||
* @param LimitRepetition $repetition
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function budgetLimit(BudgetRepositoryInterface $repository, Budget $budget, LimitRepetition $repetition)
|
||||
{
|
||||
$start = clone $repetition->startdate;
|
||||
$end = $repetition->enddate;
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('budget');
|
||||
$cache->addProperty('limit');
|
||||
$cache->addProperty($budget->id);
|
||||
$cache->addProperty($repetition->id);
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$entries = new Collection;
|
||||
$amount = $repetition->amount;
|
||||
|
||||
while ($start <= $end) {
|
||||
/*
|
||||
* Sum of expenses on this day:
|
||||
*/
|
||||
$sum = $repository->expensesOnDayCorrected($budget, $start);
|
||||
$amount += $sum;
|
||||
$entries->push([clone $start, $amount]);
|
||||
$start->addDay();
|
||||
}
|
||||
|
||||
$data = $this->generator->budgetLimit($entries);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a budget list with spent/left/overspent.
|
||||
*
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function frontpage(BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$budgets = $repository->getBudgets();
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$allEntries = new Collection;
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('budget');
|
||||
$cache->addProperty('all');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
bcscale(2);
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
|
||||
if ($repetitions->count() == 0) {
|
||||
$expenses = $repository->spentInPeriodCorrected($budget, $start, $end, true);
|
||||
$allEntries->push([$budget->name, 0, 0, $expenses, 0, 0]);
|
||||
continue;
|
||||
}
|
||||
/** @var LimitRepetition $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
$expenses = $repository->spentInPeriodCorrected($budget, $repetition->startdate, $repetition->enddate, true);
|
||||
// $left can be less than zero.
|
||||
// $overspent can be more than zero ( = overspending)
|
||||
|
||||
$left = max(bcsub($repetition->amount, $expenses), 0); // limited at zero.
|
||||
$overspent = max(bcsub($expenses, $repetition->amount), 0); // limited at zero.
|
||||
$name = $budget->name;
|
||||
|
||||
// $spent is maxed to the repetition amount:
|
||||
$spent = $expenses > $repetition->amount ? $repetition->amount : $expenses;
|
||||
|
||||
|
||||
$allEntries->push([$name, $left, $spent, $overspent, $repetition->amount, $expenses]);
|
||||
}
|
||||
}
|
||||
|
||||
$noBudgetExpenses = $repository->getWithoutBudgetSum($start, $end) * -1;
|
||||
$allEntries->push([trans('firefly.noBudget'), 0, 0, $noBudgetExpenses, 0, 0]);
|
||||
|
||||
$data = $this->generator->frontpage($allEntries);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a yearly overview for a budget.
|
||||
*
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
* @param $year
|
||||
* @param bool $shared
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function year(BudgetRepositoryInterface $repository, $year, $shared = false)
|
||||
{
|
||||
$start = new Carbon($year . '-01-01');
|
||||
$end = new Carbon($year . '-12-31');
|
||||
$shared = $shared == 'shared' ? true : false;
|
||||
$budgets = $repository->getBudgets();
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('budget');
|
||||
$cache->addProperty('year');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$entries = new Collection;
|
||||
|
||||
while ($start < $end) {
|
||||
// month is the current end of the period:
|
||||
$month = clone $start;
|
||||
$month->endOfMonth();
|
||||
$row = [clone $start];
|
||||
|
||||
// each budget, fill the row:
|
||||
foreach ($budgets as $budget) {
|
||||
$spent = $repository->spentInPeriodCorrected($budget, $start, $month, $shared);
|
||||
$row[] = $spent;
|
||||
}
|
||||
$entries->push($row);
|
||||
$start->endOfMonth()->addDay();
|
||||
}
|
||||
|
||||
$data = $this->generator->year($budgets, $entries);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
}
|
||||
216
app/Http/Controllers/Chart/CategoryController.php
Normal file
216
app/Http/Controllers/Chart/CategoryController.php
Normal file
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Chart;
|
||||
|
||||
|
||||
use App;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use Session;
|
||||
|
||||
/**
|
||||
* Class CategoryController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers\Chart
|
||||
*/
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
/** @var \FireflyIII\Generator\Chart\Category\CategoryChartGenerator */
|
||||
protected $generator;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
// create chart generator:
|
||||
$this->generator = App::make('FireflyIII\Generator\Chart\Category\CategoryChartGenerator');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show an overview for a category for all time, per month/week/year.
|
||||
*
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
* @param Category $category
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function all(CategoryRepositoryInterface $repository, Category $category)
|
||||
{
|
||||
// oldest transaction in category:
|
||||
$start = $repository->getFirstActivityDate($category);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = new Carbon;
|
||||
|
||||
$entries = new Collection;
|
||||
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('all');
|
||||
$cache->addProperty('categories');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
while ($start <= $end) {
|
||||
$currentEnd = Navigation::endOfPeriod($start, $range);
|
||||
$spent = $repository->spentInPeriodCorrected($category, $start, $currentEnd);
|
||||
$entries->push([clone $start, $spent]);
|
||||
$start = Navigation::addPeriod($start, $range, 0);
|
||||
|
||||
}
|
||||
|
||||
$data = $this->generator->all($entries);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Show this month's category overview.
|
||||
*
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function frontpage(CategoryRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('category');
|
||||
$cache->addProperty('frontpage');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$array = $repository->getCategoriesAndExpensesCorrected($start, $end);
|
||||
// sort by callback:
|
||||
uasort(
|
||||
$array,
|
||||
function ($left, $right) {
|
||||
if ($left['sum'] == $right['sum']) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($left['sum'] < $right['sum']) ? 1 : -1;
|
||||
}
|
||||
);
|
||||
$set = new Collection($array);
|
||||
$data = $this->generator->frontpage($set);
|
||||
|
||||
return Response::json($data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
* @param Category $category
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function month(CategoryRepositoryInterface $repository, Category $category)
|
||||
{
|
||||
$start = clone Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($category->id);
|
||||
$cache->addProperty('category');
|
||||
$cache->addProperty('month');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
$entries = new Collection;
|
||||
|
||||
|
||||
while ($start <= $end) {
|
||||
$spent = $repository->spentOnDaySumCorrected($category, $start);
|
||||
|
||||
$entries->push([clone $start, $spent]);
|
||||
$start->addDay();
|
||||
}
|
||||
|
||||
$data = $this->generator->month($entries);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This chart will only show expenses.
|
||||
*
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
* @param $year
|
||||
* @param bool $shared
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function year(CategoryRepositoryInterface $repository, $year, $shared = false)
|
||||
{
|
||||
$start = new Carbon($year . '-01-01');
|
||||
$end = new Carbon($year . '-12-31');
|
||||
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('category');
|
||||
$cache->addProperty('year');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$shared = $shared == 'shared' ? true : false;
|
||||
$categories = $repository->getCategories();
|
||||
$entries = new Collection;
|
||||
|
||||
while ($start < $end) {
|
||||
// month is the current end of the period:
|
||||
$month = clone $start;
|
||||
$month->endOfMonth();
|
||||
// make a row:
|
||||
$row = [clone $start];
|
||||
|
||||
// each budget, fill the row:
|
||||
foreach ($categories as $category) {
|
||||
$spent = $repository->spentInPeriodCorrected($category, $start, $month, $shared);
|
||||
$row[] = $spent;
|
||||
}
|
||||
$entries->push($row);
|
||||
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
$data = $this->generator->year($categories, $entries);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
}
|
||||
61
app/Http/Controllers/Chart/PiggyBankController.php
Normal file
61
app/Http/Controllers/Chart/PiggyBankController.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Chart;
|
||||
|
||||
use App;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
use Response;
|
||||
|
||||
|
||||
/**
|
||||
* Class PiggyBankController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers\Chart
|
||||
*/
|
||||
class PiggyBankController extends Controller
|
||||
{
|
||||
|
||||
/** @var \FireflyIII\Generator\Chart\PiggyBank\PiggyBankChartGenerator */
|
||||
protected $generator;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
// create chart generator:
|
||||
$this->generator = App::make('FireflyIII\Generator\Chart\PiggyBank\PiggyBankChartGenerator');
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the piggy bank history.
|
||||
*
|
||||
* @param PiggyBankRepositoryInterface $repository
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function history(PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
|
||||
{
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('piggy-history');
|
||||
$cache->addProperty($piggyBank->id);
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/** @var Collection $set */
|
||||
$set = new Collection($repository->getEventSummarySet($piggyBank));
|
||||
$data = $this->generator->history($set);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
|
||||
}
|
||||
}
|
||||
126
app/Http/Controllers/Chart/ReportController.php
Normal file
126
app/Http/Controllers/Chart/ReportController.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Chart;
|
||||
|
||||
|
||||
use App;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Report\ReportQueryInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
use Response;
|
||||
|
||||
/**
|
||||
* Class ReportController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers\Chart
|
||||
*/
|
||||
class ReportController extends Controller
|
||||
{
|
||||
|
||||
/** @var \FireflyIII\Generator\Chart\Report\ReportChartGenerator */
|
||||
protected $generator;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
// create chart generator:
|
||||
$this->generator = App::make('FireflyIII\Generator\Chart\Report\ReportChartGenerator');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Summarizes all income and expenses, per month, for a given year.
|
||||
*
|
||||
* @param ReportQueryInterface $query
|
||||
* @param $year
|
||||
* @param bool $shared
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function yearInOut(ReportQueryInterface $query, $year, $shared = false)
|
||||
{
|
||||
// get start and end of year
|
||||
$start = new Carbon($year . '-01-01');
|
||||
$end = new Carbon($year . '-12-31');
|
||||
$shared = $shared == 'shared' ? true : false;
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('yearInOut');
|
||||
$cache->addProperty($year);
|
||||
$cache->addProperty($shared);
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$entries = new Collection;
|
||||
while ($start < $end) {
|
||||
$month = clone $start;
|
||||
$month->endOfMonth();
|
||||
// total income and total expenses:
|
||||
$incomeSum = $query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount');
|
||||
$expenseSum = $query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount');
|
||||
|
||||
$entries->push([clone $start, $incomeSum, $expenseSum]);
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
$data = $this->generator->yearInOut($entries);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Summarizes all income and expenses for a given year. Gives a total and an average.
|
||||
*
|
||||
* @param ReportQueryInterface $query
|
||||
* @param $year
|
||||
* @param bool $shared
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function yearInOutSummarized(ReportQueryInterface $query, $year, $shared = false)
|
||||
{
|
||||
|
||||
// chart properties for cache:
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('yearInOutSummarized');
|
||||
$cache->addProperty($year);
|
||||
$cache->addProperty($shared);
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$start = new Carbon($year . '-01-01');
|
||||
$end = new Carbon($year . '-12-31');
|
||||
$shared = $shared == 'shared' ? true : false;
|
||||
$income = '0';
|
||||
$expense = '0';
|
||||
$count = 0;
|
||||
|
||||
bcscale(2);
|
||||
|
||||
while ($start < $end) {
|
||||
$month = clone $start;
|
||||
$month->endOfMonth();
|
||||
// total income and total expenses:
|
||||
$income = bcadd($income, $query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount'));
|
||||
$expense = bcadd($expense, $query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount'));
|
||||
$count++;
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
$data = $this->generator->yearInOutSummarized($income, $expense, $count);
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Bus\DispatchesCommands;
|
||||
use Auth;
|
||||
use Config;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Preferences;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class Controller
|
||||
@@ -12,6 +16,32 @@ use Illuminate\Routing\Controller as BaseController;
|
||||
abstract class Controller extends BaseController
|
||||
{
|
||||
|
||||
use DispatchesCommands, ValidatesRequests;
|
||||
use DispatchesJobs, ValidatesRequests;
|
||||
|
||||
/** @var string */
|
||||
protected $monthAndDayFormat;
|
||||
/** @var string */
|
||||
protected $monthFormat;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
View::share('hideBudgets', false);
|
||||
View::share('hideCategories', false);
|
||||
View::share('hideBills', false);
|
||||
View::share('hideTags', false);
|
||||
|
||||
if (Auth::check()) {
|
||||
$pref = Preferences::get('language', 'en');
|
||||
$lang = $pref->data;
|
||||
$this->monthFormat = Config::get('firefly.month.' . $lang);
|
||||
$this->monthAndDayFormat = Config::get('firefly.monthAndDay.' . $lang);
|
||||
|
||||
View::share('monthFormat', $this->monthFormat);
|
||||
View::share('monthAndDayFormat', $this->monthAndDayFormat);
|
||||
View::share('language', $lang);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use FireflyIII\Http\Requests;
|
||||
use Auth;
|
||||
use Cache;
|
||||
use FireflyIII\Http\Requests\CurrencyFormRequest;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use URL;
|
||||
use View;
|
||||
use Cache;
|
||||
|
||||
/**
|
||||
* Class CurrencyController
|
||||
@@ -20,12 +22,12 @@ class CurrencyController extends Controller
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
View::share('title', 'Currencies');
|
||||
parent::__construct();
|
||||
View::share('title', trans('firefly.currencies'));
|
||||
View::share('mainTitleIcon', 'fa-usd');
|
||||
}
|
||||
|
||||
@@ -35,7 +37,15 @@ class CurrencyController extends Controller
|
||||
public function create()
|
||||
{
|
||||
$subTitleIcon = 'fa-plus';
|
||||
$subTitle = 'Create a new currency';
|
||||
$subTitle = trans('firefly.create_currency');
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('currency.create.fromStore') !== true) {
|
||||
Session::put('currency.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('currency.create.fromStore');
|
||||
Session::flash('gaEventCategory', 'currency');
|
||||
Session::flash('gaEventAction', 'create');
|
||||
|
||||
return view('currency.create', compact('subTitleIcon', 'subTitle'));
|
||||
}
|
||||
@@ -48,9 +58,8 @@ class CurrencyController extends Controller
|
||||
public function defaultCurrency(TransactionCurrency $currency)
|
||||
{
|
||||
|
||||
$currencyPreference = Preferences::get('currencyPreference', 'EUR');
|
||||
$currencyPreference->data = $currency->code;
|
||||
$currencyPreference->save();
|
||||
Preferences::set('currencyPreference', $currency->code);
|
||||
Preferences::mark();
|
||||
|
||||
Session::flash('success', $currency->name . ' is now the default currency.');
|
||||
Cache::forget('FFCURRENCYSYMBOL');
|
||||
@@ -61,40 +70,51 @@ class CurrencyController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
||||
* @return \Illuminate\Http\RedirectResponse|View
|
||||
*/
|
||||
public function delete(TransactionCurrency $currency)
|
||||
public function delete(CurrencyRepositoryInterface $repository, TransactionCurrency $currency)
|
||||
{
|
||||
if ($currency->transactionJournals()->count() > 0) {
|
||||
|
||||
if ($repository->countJournals($currency) > 0) {
|
||||
Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.');
|
||||
|
||||
return Redirect::route('currency.index');
|
||||
}
|
||||
|
||||
// put previous url in session
|
||||
Session::put('currency.delete.url', URL::previous());
|
||||
Session::flash('gaEventCategory', 'currency');
|
||||
Session::flash('gaEventAction', 'delete');
|
||||
$subTitle = trans('form.delete_currency', ['name' => $currency->name]);
|
||||
|
||||
return view('currency.delete', compact('currency'));
|
||||
|
||||
return view('currency.delete', compact('currency', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function destroy(TransactionCurrency $currency)
|
||||
public function destroy(CurrencyRepositoryInterface $repository, TransactionCurrency $currency)
|
||||
{
|
||||
if ($currency->transactionJournals()->count() > 0) {
|
||||
Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.');
|
||||
if ($repository->countJournals($currency) > 0) {
|
||||
Session::flash('error', 'Cannot destroy ' . e($currency->name) . ' because there are still transactions attached to it.');
|
||||
|
||||
return Redirect::route('currency.index');
|
||||
}
|
||||
|
||||
Session::flash('success', 'Currency "' . e($currency->name) . '" deleted');
|
||||
if (Auth::user()->hasRole('owner')) {
|
||||
$currency->delete();
|
||||
}
|
||||
|
||||
$currency->delete();
|
||||
|
||||
return Redirect::route('currency.index');
|
||||
return Redirect::to(Session::get('currency.delete.url'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,67 +125,93 @@ class CurrencyController extends Controller
|
||||
public function edit(TransactionCurrency $currency)
|
||||
{
|
||||
$subTitleIcon = 'fa-pencil';
|
||||
$subTitle = 'Edit currency "' . e($currency->name) . '"';
|
||||
$subTitle = trans('firefly.edit_currency', ['name' => $currency->name]);
|
||||
$currency->symbol = htmlentities($currency->symbol);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('currency.edit.fromUpdate') !== true) {
|
||||
Session::put('currency.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('currency.edit.fromUpdate');
|
||||
Session::flash('gaEventCategory', 'currency');
|
||||
Session::flash('gaEventAction', 'edit');
|
||||
|
||||
return view('currency.edit', compact('currency', 'subTitle', 'subTitleIcon'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
public function index(CurrencyRepositoryInterface $repository)
|
||||
{
|
||||
$currencies = TransactionCurrency::get();
|
||||
$currencyPreference = Preferences::get('currencyPreference', 'EUR');
|
||||
$defaultCurrency = TransactionCurrency::whereCode($currencyPreference->data)->first();
|
||||
$currencies = $repository->get();
|
||||
$defaultCurrency = $repository->getCurrencyByPreference(Preferences::get('currencyPreference', 'EUR'));
|
||||
|
||||
|
||||
if (!Auth::user()->hasRole('owner')) {
|
||||
Session::flash('warning', 'Please ask ' . env('SITE_OWNER') . ' to add, remove or edit currencies.');
|
||||
}
|
||||
|
||||
|
||||
return view('currency.index', compact('currencies', 'defaultCurrency'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
* @param CurrencyFormRequest $request
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(CurrencyFormRequest $request)
|
||||
public function store(CurrencyFormRequest $request, CurrencyRepositoryInterface $repository)
|
||||
{
|
||||
$data = $request->getCurrencyData();
|
||||
if (Auth::user()->hasRole('owner')) {
|
||||
$currency = $repository->store($data);
|
||||
Session::flash('success', 'Currency "' . $currency->name . '" created');
|
||||
|
||||
}
|
||||
|
||||
// no repository, because the currency controller is relatively simple.
|
||||
$currency = TransactionCurrency::create(
|
||||
[
|
||||
'name' => $request->get('name'),
|
||||
'code' => $request->get('code'),
|
||||
'symbol' => $request->get('symbol'),
|
||||
]
|
||||
);
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
Session::put('currency.create.fromStore', true);
|
||||
|
||||
Session::flash('success', 'Currency "' . $currency->name . '" created');
|
||||
return Redirect::route('currency.create')->withInput();
|
||||
}
|
||||
|
||||
return Redirect::route('currency.index');
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('currency.create.url'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
* @param CurrencyFormRequest $request
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(TransactionCurrency $currency, CurrencyFormRequest $request)
|
||||
public function update(CurrencyFormRequest $request, CurrencyRepositoryInterface $repository, TransactionCurrency $currency)
|
||||
{
|
||||
$data = $request->getCurrencyData();
|
||||
if (Auth::user()->hasRole('owner')) {
|
||||
$currency = $repository->update($currency, $data);
|
||||
}
|
||||
Session::flash('success', 'Currency "' . e($currency->name) . '" updated.');
|
||||
Preferences::mark();
|
||||
|
||||
$currency->code = $request->get('code');
|
||||
$currency->symbol = $request->get('symbol');
|
||||
$currency->name = $request->get('name');
|
||||
$currency->save();
|
||||
|
||||
Session::flash('success', 'Currency "' . e($currency->namename) . '" updated.');
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
Session::put('currency.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('currency.index');
|
||||
return Redirect::route('currency.edit', [$currency->id]);
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('currency.edit.url'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,635 +0,0 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use App;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Crypt;
|
||||
use Exception;
|
||||
use FireflyIII\Helpers\Report\ReportQueryInterface;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use Grumpydictator\Gchart\GChart;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use Session;
|
||||
use DB;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class GoogleChartController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class GoogleChartController extends Controller
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param string $view
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function accountBalanceChart(Account $account, $view = 'session', GChart $chart)
|
||||
{
|
||||
$chart->addColumn('Day of month', 'date');
|
||||
$chart->addColumn('Balance for ' . $account->name, 'number');
|
||||
$chart->addCertainty(1);
|
||||
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$count = $account->transactions()->count();
|
||||
|
||||
if ($view == 'all' && $count > 0) {
|
||||
$first = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy(
|
||||
'date', 'ASC'
|
||||
)->first(['transaction_journals.date']);
|
||||
$last = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy(
|
||||
'date', 'DESC'
|
||||
)->first(['transaction_journals.date']);
|
||||
$start = new Carbon($first->date);
|
||||
$end = new Carbon($last->date);
|
||||
}
|
||||
|
||||
$current = clone $start;
|
||||
|
||||
while ($end >= $current) {
|
||||
$chart->addRow(clone $current, Steam::balance($account, $current), false);
|
||||
$current->addDay();
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GChart $chart
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function allAccountsBalanceChart(GChart $chart)
|
||||
{
|
||||
$chart->addColumn('Day of the month', 'date');
|
||||
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
if ($frontPage->data == []) {
|
||||
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']);
|
||||
} else {
|
||||
$accounts = Auth::user()->accounts()->whereIn('id', $frontPage->data)->get(['accounts.*']);
|
||||
}
|
||||
$index = 1;
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$chart->addColumn('Balance for ' . $account->name, 'number');
|
||||
$chart->addCertainty($index);
|
||||
$index++;
|
||||
}
|
||||
$current = clone $start;
|
||||
$current->subDay();
|
||||
$today = Carbon::now();
|
||||
while ($end >= $current) {
|
||||
$row = [clone $current];
|
||||
$certain = $current < $today;
|
||||
foreach ($accounts as $account) {
|
||||
$row[] = Steam::balance($account, $current);
|
||||
$row[] = $certain;
|
||||
}
|
||||
$chart->addRowArray($row);
|
||||
$current->addDay();
|
||||
}
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $year
|
||||
*
|
||||
* @return $this|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function allBudgetsAndSpending($year, GChart $chart, BudgetRepositoryInterface $repository)
|
||||
{
|
||||
try {
|
||||
new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid year.');
|
||||
}
|
||||
$budgets = Auth::user()->budgets()->get();
|
||||
$budgets->sortBy('name');
|
||||
$chart->addColumn('Month', 'date');
|
||||
foreach ($budgets as $budget) {
|
||||
$chart->addColumn($budget->name, 'number');
|
||||
}
|
||||
$start = Carbon::createFromDate(intval($year), 1, 1);
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
|
||||
|
||||
while ($start <= $end) {
|
||||
$row = [clone $start];
|
||||
foreach ($budgets as $budget) {
|
||||
$spent = $repository->spentInMonth($budget, $start);
|
||||
$row[] = $spent;
|
||||
}
|
||||
$chart->addRowArray($row);
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GChart $chart
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function allBudgetsHomeChart(GChart $chart)
|
||||
{
|
||||
$chart->addColumn('Budget', 'string');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
$budgets = Auth::user()->budgets()->orderBy('name', 'DESC')->get();
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
|
||||
/** @var \LimitRepetition $repetition */
|
||||
$repetition = LimitRepetition::
|
||||
leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.budget_id', $budget->id)
|
||||
->first(['limit_repetitions.*']);
|
||||
if (is_null($repetition)) { // use the session start and end for our search query
|
||||
$searchStart = $start;
|
||||
$searchEnd = $end;
|
||||
$limit = 0; // the limit is zero:
|
||||
} else {
|
||||
// use the limit's start and end for our search query
|
||||
$searchStart = $repetition->startdate;
|
||||
$searchEnd = $repetition->enddate;
|
||||
$limit = floatval($repetition->amount); // the limit is the repetitions limit:
|
||||
}
|
||||
|
||||
$expenses = floatval($budget->transactionjournals()->before($searchEnd)->after($searchStart)->lessThan(0)->sum('amount')) * -1;
|
||||
if ($expenses > 0) {
|
||||
$chart->addRow($budget->name, $limit, $expenses);
|
||||
}
|
||||
}
|
||||
|
||||
$noBudgetSet = Auth::user()
|
||||
->transactionjournals()
|
||||
->whereNotIn(
|
||||
'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) {
|
||||
$query
|
||||
->select('transaction_journals.id')
|
||||
->from('transaction_journals')
|
||||
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'));
|
||||
}
|
||||
)
|
||||
->before($end)
|
||||
->after($start)
|
||||
->lessThan(0)
|
||||
->transactionTypes(['Withdrawal'])
|
||||
->get();
|
||||
$sum = $noBudgetSet->sum('amount') * -1;
|
||||
$chart->addRow('No budget', 0, $sum);
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GChart $chart
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function allCategoriesHomeChart(GChart $chart)
|
||||
{
|
||||
$chart->addColumn('Category', 'string');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
// query!
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$set = TransactionJournal::leftJoin(
|
||||
'transactions',
|
||||
function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
|
||||
)
|
||||
->leftJoin('categories', 'categories.id', '=', 'category_transaction_journal.category_id')
|
||||
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->before($end)
|
||||
->after($start)
|
||||
->where('transaction_types.type', 'Withdrawal')
|
||||
->groupBy('categories.id')
|
||||
->orderBy('sum', 'DESC')
|
||||
->get(['categories.id', 'categories.name', \DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$entry->name = strlen($entry->name) == 0 ? '(no category)' : $entry->name;
|
||||
$chart->addRow($entry->name, floatval($entry->sum));
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function billOverview(Bill $bill, GChart $chart)
|
||||
{
|
||||
|
||||
$chart->addColumn('Date', 'date');
|
||||
$chart->addColumn('Max amount', 'number');
|
||||
$chart->addColumn('Min amount', 'number');
|
||||
$chart->addColumn('Current entry', 'number');
|
||||
|
||||
// get first transaction or today for start:
|
||||
$first = $bill->transactionjournals()->orderBy('date', 'ASC')->first();
|
||||
if ($first) {
|
||||
$start = $first->date;
|
||||
} else {
|
||||
$start = new Carbon;
|
||||
}
|
||||
$end = new Carbon;
|
||||
while ($start <= $end) {
|
||||
$result = $bill->transactionjournals()->before($end)->after($start)->first();
|
||||
if ($result) {
|
||||
/** @var Transaction $tr */
|
||||
foreach ($result->transactions()->get() as $tr) {
|
||||
if (floatval($tr->amount) > 0) {
|
||||
$amount = floatval($tr->amount);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$amount = 0;
|
||||
}
|
||||
unset($result);
|
||||
$chart->addRow(clone $start, $bill->amount_max, $bill->amount_min, $amount);
|
||||
$start = Navigation::addPeriod($start, $bill->repeat_freq, 0);
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GChart $chart
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function billsOverview(GChart $chart)
|
||||
{
|
||||
$paid = ['items' => [], 'amount' => 0];
|
||||
$unpaid = ['items' => [], 'amount' => 0];
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
$chart->addColumn('Name', 'string');
|
||||
$chart->addColumn('Amount', 'number');
|
||||
|
||||
$set = Bill::
|
||||
leftJoin(
|
||||
'transaction_journals', function (JoinClause $join) use ($start, $end) {
|
||||
$join->on('bills.id', '=', 'transaction_journals.bill_id')
|
||||
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||
->where('transaction_journals.date', '<=', $end->format('Y-m-d'));
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'transactions', function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '>', 0);
|
||||
}
|
||||
)
|
||||
->where('active', 1)
|
||||
->groupBy('bills.id')
|
||||
->get(
|
||||
['bills.id', 'bills.name', 'transaction_journals.description',
|
||||
'transaction_journals.encrypted',
|
||||
'transaction_journals.id as journalId',
|
||||
\DB::Raw('SUM(`bills`.`amount_min` + `bills`.`amount_max`) / 2 as `averageAmount`'),
|
||||
'transactions.amount AS actualAmount']
|
||||
);
|
||||
|
||||
foreach ($set as $entry) {
|
||||
if (intval($entry->journalId) == 0) {
|
||||
$unpaid['items'][] = $entry->name;
|
||||
$unpaid['amount'] += floatval($entry->averageAmount);
|
||||
} else {
|
||||
$description = intval($entry->encrypted) == 1 ? Crypt::decrypt($entry->description) : $entry->description;
|
||||
$paid['items'][] = $description;
|
||||
$paid['amount'] += floatval($entry->actualAmount);
|
||||
}
|
||||
}
|
||||
$chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
|
||||
$chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Budget $budget
|
||||
* @param LimitRepetition $repetition
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function budgetLimitSpending(Budget $budget, LimitRepetition $repetition, GChart $chart)
|
||||
{
|
||||
$start = clone $repetition->startdate;
|
||||
$end = $repetition->enddate;
|
||||
|
||||
$chart->addColumn('Day', 'date');
|
||||
$chart->addColumn('Left', 'number');
|
||||
|
||||
|
||||
$amount = $repetition->amount;
|
||||
|
||||
while ($start <= $end) {
|
||||
/*
|
||||
* Sum of expenses on this day:
|
||||
*/
|
||||
$sum = floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($start)->sum('amount'));
|
||||
$amount += $sum;
|
||||
$chart->addRow(clone $start, $amount);
|
||||
$start->addDay();
|
||||
}
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @param int $year
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function budgetsAndSpending(Budget $budget, $year = 0)
|
||||
{
|
||||
|
||||
$chart = App::make('Grumpydictator\Gchart\GChart');
|
||||
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepository');
|
||||
$chart->addColumn('Month', 'date');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
if ($year == 0) {
|
||||
// grab the first budgetlimit ever:
|
||||
$firstLimit = $budget->budgetlimits()->orderBy('startdate', 'ASC')->first();
|
||||
if ($firstLimit) {
|
||||
$start = new Carbon($firstLimit->startdate);
|
||||
} else {
|
||||
$start = Carbon::now()->startOfYear();
|
||||
}
|
||||
|
||||
// grab the last budget limit ever:
|
||||
$lastLimit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first();
|
||||
if ($lastLimit) {
|
||||
$end = new Carbon($lastLimit->startdate);
|
||||
} else {
|
||||
$end = Carbon::now()->endOfYear();
|
||||
}
|
||||
} else {
|
||||
$start = Carbon::createFromDate(intval($year), 1, 1);
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
}
|
||||
|
||||
while ($start <= $end) {
|
||||
$spent = $repository->spentInMonth($budget, $start);
|
||||
$repetition = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
|
||||
->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.budget_id', $budget->id)
|
||||
->first(['limit_repetitions.*']);
|
||||
|
||||
if ($repetition) {
|
||||
$budgeted = floatval($repetition->amount);
|
||||
\Log::debug('Found a repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name . '!');
|
||||
} else {
|
||||
\Log::debug('No repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name);
|
||||
$budgeted = null;
|
||||
}
|
||||
$chart->addRow(clone $start, $budgeted, $spent);
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Category $category
|
||||
* @param $year
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function categoriesAndSpending(Category $category, $year, GChart $chart)
|
||||
{
|
||||
try {
|
||||
new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid year.');
|
||||
}
|
||||
|
||||
$chart->addColumn('Month', 'date');
|
||||
$chart->addColumn('Budgeted', 'number');
|
||||
$chart->addColumn('Spent', 'number');
|
||||
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
while ($start <= $end) {
|
||||
|
||||
$currentEnd = clone $start;
|
||||
$currentEnd->endOfMonth();
|
||||
$spent = floatval($category->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
|
||||
$budgeted = null;
|
||||
|
||||
$chart->addRow(clone $start, $budgeted, $spent);
|
||||
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function piggyBankHistory(PiggyBank $piggyBank, GChart $chart)
|
||||
{
|
||||
$chart->addColumn('Date', 'date');
|
||||
$chart->addColumn('Balance', 'number');
|
||||
|
||||
$set = \DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$chart->addRow(new Carbon($entry->date), floatval($entry->sum));
|
||||
}
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param $year
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function yearInExp($year, GChart $chart, ReportQueryInterface $query)
|
||||
{
|
||||
try {
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid year.');
|
||||
}
|
||||
$chart->addColumn('Month', 'date');
|
||||
$chart->addColumn('Income', 'number');
|
||||
$chart->addColumn('Expenses', 'number');
|
||||
|
||||
// get report query interface.
|
||||
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
while ($start < $end) {
|
||||
$currentEnd = clone $start;
|
||||
$currentEnd->endOfMonth();
|
||||
// total income:
|
||||
$income = $query->incomeByPeriod($start, $currentEnd);
|
||||
$incomeSum = 0;
|
||||
foreach ($income as $entry) {
|
||||
$incomeSum += floatval($entry->amount);
|
||||
}
|
||||
|
||||
// total expenses:
|
||||
$expense = $query->journalsByExpenseAccount($start, $currentEnd);
|
||||
$expenseSum = 0;
|
||||
foreach ($expense as $entry) {
|
||||
$expenseSum += floatval($entry->amount);
|
||||
}
|
||||
|
||||
$chart->addRow(clone $start, $incomeSum, $expenseSum);
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param $year
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function yearInExpSum($year, GChart $chart, ReportQueryInterface $query)
|
||||
{
|
||||
try {
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid year.');
|
||||
}
|
||||
$chart->addColumn('Summary', 'string');
|
||||
$chart->addColumn('Income', 'number');
|
||||
$chart->addColumn('Expenses', 'number');
|
||||
|
||||
$income = 0;
|
||||
$expense = 0;
|
||||
$count = 0;
|
||||
|
||||
$end = clone $start;
|
||||
$end->endOfYear();
|
||||
while ($start < $end) {
|
||||
$currentEnd = clone $start;
|
||||
$currentEnd->endOfMonth();
|
||||
// total income:
|
||||
$incomeResult = $query->incomeByPeriod($start, $currentEnd);
|
||||
$incomeSum = 0;
|
||||
foreach ($incomeResult as $entry) {
|
||||
$incomeSum += floatval($entry->amount);
|
||||
}
|
||||
|
||||
// total expenses:
|
||||
$expenseResult = $query->journalsByExpenseAccount($start, $currentEnd);
|
||||
$expenseSum = 0;
|
||||
foreach ($expenseResult as $entry) {
|
||||
$expenseSum += floatval($entry->amount);
|
||||
}
|
||||
|
||||
$income += $incomeSum;
|
||||
$expense += $expenseSum;
|
||||
$count++;
|
||||
$start->addMonth();
|
||||
}
|
||||
|
||||
|
||||
$chart->addRow('Sum', $income, $expense);
|
||||
$count = $count > 0 ? $count : 1;
|
||||
$chart->addRow('Average', ($income / $count), ($expense / $count));
|
||||
|
||||
$chart->generate();
|
||||
|
||||
return Response::json($chart->getData());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,94 +1,51 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use ErrorException;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use Route;
|
||||
use FireflyIII\Helpers\Help\HelpInterface;
|
||||
use Log;
|
||||
use Response;
|
||||
use Cache;
|
||||
|
||||
/**
|
||||
* Class HelpController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class HelpController extends Controller {
|
||||
class HelpController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param HelpInterface $help
|
||||
* @param $route
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function show($route)
|
||||
public function show(HelpInterface $help, $route)
|
||||
{
|
||||
$content = [
|
||||
'text' => '<p>There is no help for this route!</p>',
|
||||
'title' => 'Help',
|
||||
];
|
||||
|
||||
if (!Route::has($route)) {
|
||||
\Log::error('No such route: ' . $route);
|
||||
if (!$help->hasRoute($route)) {
|
||||
Log::error('No such route: ' . $route);
|
||||
|
||||
return Response::json($content);
|
||||
}
|
||||
|
||||
if ($this->_inCache($route)) {
|
||||
if ($help->inCache($route)) {
|
||||
$content = [
|
||||
'text' => Cache::get('help.' . $route . '.text'),
|
||||
'title' => Cache::get('help.' . $route . '.title'),
|
||||
'text' => $help->getFromCache('help.' . $route . '.text'),
|
||||
'title' => $help->getFromCache('help.' . $route . '.title'),
|
||||
];
|
||||
|
||||
return Response::json($content);
|
||||
}
|
||||
$content = $this->_getFromGithub($route);
|
||||
$content = $help->getFromGithub($route);
|
||||
|
||||
|
||||
Cache::put('help.' . $route . '.text', $content['text'], 10080); // a week.
|
||||
Cache::put('help.' . $route . '.title', $content['title'], 10080);
|
||||
$help->putInCache($route, $content);
|
||||
|
||||
return Response::json($content);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _inCache($route)
|
||||
{
|
||||
return Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _getFromGithub($route)
|
||||
{
|
||||
$uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md';
|
||||
$content = [
|
||||
'text' => '<p>There is no help for this route!</p>',
|
||||
'title' => $route,
|
||||
];
|
||||
try {
|
||||
$content['text'] = file_get_contents($uri);
|
||||
} catch (ErrorException $e) {
|
||||
\Log::error(trim($e->getMessage()));
|
||||
}
|
||||
if (strlen(trim($content['text'])) == 0) {
|
||||
$content['text'] = '<p>There is no help for this route.</p>';
|
||||
}
|
||||
$converter = new CommonMarkConverter();
|
||||
$content['text'] = $converter->convertToHtml($content['text']);
|
||||
|
||||
return $content;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Cache;
|
||||
use Carbon\Carbon;
|
||||
use Navigation;
|
||||
use Config;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Route;
|
||||
use Session;
|
||||
use URL;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class HomeController
|
||||
@@ -17,11 +20,19 @@ use URL;
|
||||
class HomeController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
public function dateRange()
|
||||
{
|
||||
$start = new Carbon(Input::get('start'));
|
||||
$end = new Carbon(Input::get('end'));
|
||||
|
||||
$diff = $start->diffInDays($end);
|
||||
|
||||
if ($diff > 50) {
|
||||
Session::flash('warning', $diff . ' days of data may take a while to load.');
|
||||
}
|
||||
|
||||
Session::put('start', $start);
|
||||
Session::put('end', $end);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,96 +40,106 @@ class HomeController extends Controller
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
Cache::flush();
|
||||
// get all tags.
|
||||
// update all counts:
|
||||
$tags = Tag::get();
|
||||
|
||||
/** @var Tag $tag */
|
||||
foreach ($tags as $tag) {
|
||||
foreach ($tag->transactionjournals()->get() as $journal) {
|
||||
$count = $journal->tags()->count();
|
||||
$journal->tag_count = $count;
|
||||
$journal->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Session::clear();
|
||||
|
||||
return Redirect::route('index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
{
|
||||
$count = Auth::user()->accounts()->accountTypeIn(['Asset account', 'Default account'])->count();
|
||||
$types = Config::get('firefly.accountTypesByIdentifier.asset');
|
||||
$count = $repository->countAccounts($types);
|
||||
|
||||
|
||||
if ($count == 0) {
|
||||
return Redirect::route('new-user.index');
|
||||
}
|
||||
|
||||
$title = 'Firefly';
|
||||
$subTitle = 'What\'s playing?';
|
||||
$subTitle = trans('firefly.welcomeBack');
|
||||
$mainTitleIcon = 'fa-fire';
|
||||
$transactions = [];
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
if ($frontPage->data == []) {
|
||||
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']);
|
||||
} else {
|
||||
$accounts = Auth::user()->accounts()->whereIn('id', $frontPage->data)->get(['accounts.*']);
|
||||
$accounts = $repository->getFrontpageAccounts($frontPage);
|
||||
$savings = $repository->getSavingsAccounts();
|
||||
|
||||
$piggyBankAccounts = $repository->getPiggyBankAccounts();
|
||||
|
||||
|
||||
$savingsTotal = 0;
|
||||
foreach ($savings as $savingAccount) {
|
||||
$savingsTotal += Steam::balance($savingAccount, $end);
|
||||
}
|
||||
|
||||
$sum = $repository->sumOfEverything();
|
||||
|
||||
if ($sum != 0) {
|
||||
Session::flash(
|
||||
'error', 'Your transactions are unbalanced. This means a'
|
||||
. ' withdrawal, deposit or transfer was not stored properly. '
|
||||
. 'Please check your accounts and transactions for errors.'
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
$set = Auth::user()
|
||||
->transactionjournals()
|
||||
->with(['transactions', 'transactioncurrency', 'transactiontype'])
|
||||
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id)
|
||||
->where('date', '>=', $start->format('Y-m-d'))
|
||||
->where('date', '<=', $end->format('Y-m-d'))
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->take(10)
|
||||
->get(['transaction_journals.*']);
|
||||
$set = $repository->getFrontpageTransactions($account, $start, $end);
|
||||
|
||||
if (count($set) > 0) {
|
||||
$transactions[] = [$set, $account];
|
||||
}
|
||||
}
|
||||
|
||||
// var_dump($transactions);
|
||||
|
||||
return view('index', compact('count', 'title', 'subTitle', 'mainTitleIcon', 'transactions'));
|
||||
return view('index', compact('count', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions', 'savingsTotal', 'piggyBankAccounts'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $range
|
||||
*
|
||||
* @return mixed
|
||||
* @codeCoverageIgnore
|
||||
* @return \Illuminate\Http\RedirectResponse|string
|
||||
*/
|
||||
public function rangeJump($range)
|
||||
public function routes()
|
||||
{
|
||||
if (!Auth::user()->hasRole('owner')) {
|
||||
Session::flash('warning', 'This page is broken.');
|
||||
|
||||
$valid = ['1D', '1W', '1M', '3M', '6M', '1Y',];
|
||||
|
||||
if (in_array($range, $valid)) {
|
||||
Preferences::set('viewRange', $range);
|
||||
Session::forget('range');
|
||||
return Redirect::route('index');
|
||||
}
|
||||
|
||||
return Redirect::to(URL::previous());
|
||||
// get all routes:
|
||||
$routeCollection = Route::getRoutes();
|
||||
/** @var \Illuminate\Routing\Route $value */
|
||||
foreach ($routeCollection as $value) {
|
||||
$name = $value->getName();
|
||||
$methods = $value->getMethods();
|
||||
$isPost = in_array('POST', $methods);
|
||||
$index = str_replace('.', '-', $name);
|
||||
|
||||
if (strlen($name) > 0 && !$isPost) {
|
||||
echo "'" . $index . "' => '" . $name . "',<br />";
|
||||
}
|
||||
}
|
||||
|
||||
return ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function sessionNext()
|
||||
{
|
||||
$range = Session::get('range');
|
||||
$start = Session::get('start');
|
||||
|
||||
Session::put('start', Navigation::jumpToNext($range, clone $start));
|
||||
|
||||
return Redirect::to(URL::previous());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function sessionPrev()
|
||||
{
|
||||
$range = Session::get('range');
|
||||
$start = Session::get('start');
|
||||
|
||||
Session::put('start', Navigation::jumpToPrevious($range, clone $start));
|
||||
|
||||
return Redirect::to(URL::previous());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,49 +1,268 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Amount;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Report\ReportQueryInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Support\Collection;
|
||||
use Response;
|
||||
use Auth;
|
||||
use Session;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class JsonController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class JsonController extends Controller {
|
||||
class JsonController extends Controller
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param BillRepositoryInterface $repository
|
||||
*
|
||||
* @param AccountRepositoryInterface $accountRepository
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxBillsPaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
// works for json too!
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('box-bills-paid');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$amount = 0;
|
||||
|
||||
|
||||
// these two functions are the same as the chart
|
||||
$bills = $repository->getActiveBills();
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
$amount += $repository->billPaymentsInRange($bill, $start, $end);
|
||||
}
|
||||
unset($bill, $bills);
|
||||
|
||||
/**
|
||||
* Find credit card accounts and possibly unpaid credit card bills.
|
||||
*/
|
||||
$creditCards = $accountRepository->getCreditCards();
|
||||
// if the balance is not zero, the monthly payment is still underway.
|
||||
/** @var Account $creditCard */
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, $end, true);
|
||||
if ($balance == 0) {
|
||||
// find a transfer TO the credit card which should account for
|
||||
// anything paid. If not, the CC is not yet used.
|
||||
$amount += $accountRepository->getTransfersInRange($creditCard, $start, $end)->sum('amount');
|
||||
}
|
||||
}
|
||||
$data = ['box' => 'bills-paid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
|
||||
$cache->store($data);
|
||||
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BillRepositoryInterface $repository
|
||||
* @param AccountRepositoryInterface $accountRepository
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxBillsUnpaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$amount = 0;
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
// works for json too!
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('box-bills-unpaid');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$bills = $repository->getActiveBills();
|
||||
$unpaid = new Collection; // bills
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
$ranges = $repository->getRanges($bill, $start, $end);
|
||||
|
||||
foreach ($ranges as $range) {
|
||||
$journals = $repository->getJournalsInRange($bill, $range['start'], $range['end']);
|
||||
if ($journals->count() == 0) {
|
||||
$unpaid->push([$bill, $range['start']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($bill, $bills, $range, $ranges);
|
||||
|
||||
$creditCards = $accountRepository->getCreditCards();
|
||||
foreach ($creditCards as $creditCard) {
|
||||
$balance = Steam::balance($creditCard, $end, true);
|
||||
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
|
||||
if ($balance < 0) {
|
||||
// unpaid! create a fake bill that matches the amount.
|
||||
$description = $creditCard->name;
|
||||
$fakeAmount = $balance * -1;
|
||||
$fakeBill = $repository->createFakeBill($description, $date, $fakeAmount);
|
||||
$unpaid->push([$fakeBill, $date]);
|
||||
}
|
||||
}
|
||||
/** @var Bill $entry */
|
||||
foreach ($unpaid as $entry) {
|
||||
$current = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
|
||||
$amount += $current;
|
||||
}
|
||||
|
||||
$data = ['box' => 'bills-unpaid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReportQueryInterface $reportQuery
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxIn(ReportQueryInterface $reportQuery)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
// works for json too!
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('box-in');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$amount = $reportQuery->incomeInPeriodCorrected($start, $end, true)->sum('amount');
|
||||
|
||||
$data = ['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReportQueryInterface $reportQuery
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function boxOut(ReportQueryInterface $reportQuery)
|
||||
{
|
||||
$start = Session::get('start', Carbon::now()->startOfMonth());
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
|
||||
// works for json too!
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('box-out');
|
||||
if ($cache->has()) {
|
||||
return Response::json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$amount = $reportQuery->expenseInPeriodCorrected($start, $end, true)->sum('amount');
|
||||
|
||||
$data = ['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
|
||||
$cache->store($data);
|
||||
|
||||
return Response::json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of categories.
|
||||
*
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function categories()
|
||||
public function categories(CategoryRepositoryInterface $repository)
|
||||
{
|
||||
$list = Auth::user()->categories()->orderBy('name','ASC')->get();
|
||||
$return = [];
|
||||
$list = $repository->getCategories();
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
}
|
||||
sort($return);
|
||||
|
||||
return Response::json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON list of all beneficiaries.
|
||||
*
|
||||
* @param AccountRepositoryInterface $accountRepository
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function expenseAccounts(AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$list = $accountRepository->getAccounts(['Expense account', 'Beneficiary account']);
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
}
|
||||
|
||||
return Response::json($return);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountRepositoryInterface $accountRepository
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function revenueAccounts(AccountRepositoryInterface $accountRepository)
|
||||
{
|
||||
$list = $accountRepository->getAccounts(['Revenue account']);
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
}
|
||||
|
||||
return Response::json($return);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON list of all beneficiaries.
|
||||
*
|
||||
* @param TagRepositoryInterface $tagRepository
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function expenseAccounts()
|
||||
public function tags(TagRepositoryInterface $tagRepository)
|
||||
{
|
||||
$list = Auth::user()->accounts()->accountTypeIn(['Expense account', 'Beneficiary account'])->get();
|
||||
$return = [];
|
||||
$list = $tagRepository->get();
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
$return[] = $entry->tag;
|
||||
}
|
||||
|
||||
return Response::json($return);
|
||||
@@ -51,17 +270,26 @@ class JsonController extends Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param $what
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function revenueAccounts()
|
||||
public function transactionJournals(JournalRepositoryInterface $repository, $what)
|
||||
{
|
||||
$list = Auth::user()->accounts()->accountTypeIn(['Revenue account'])->get();
|
||||
$return = [];
|
||||
foreach ($list as $entry) {
|
||||
$return[] = $entry->name;
|
||||
$descriptions = [];
|
||||
$dbType = $repository->getTransactionType($what);
|
||||
|
||||
$journals = $repository->getJournalsOfType($dbType);
|
||||
foreach ($journals as $j) {
|
||||
$descriptions[] = $j->description;
|
||||
}
|
||||
|
||||
return Response::json($return);
|
||||
$descriptions = array_unique($descriptions);
|
||||
sort($descriptions);
|
||||
|
||||
return Response::json($descriptions);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
111
app/Http/Controllers/NewUserController.php
Normal file
111
app/Http/Controllers/NewUserController.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use FireflyIII\Http\Requests\NewUserFormRequest;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class NewUserController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class NewUserController extends Controller
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @@return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
||||
*/
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
{
|
||||
View::share('title', 'Welcome to Firefly!');
|
||||
View::share('mainTitleIcon', 'fa-fire');
|
||||
|
||||
|
||||
$types = Config::get('firefly.accountTypesByIdentifier.asset');
|
||||
$count = $repository->countAccounts($types);
|
||||
|
||||
if ($count > 0) {
|
||||
return Redirect::route('index');
|
||||
|
||||
}
|
||||
|
||||
return view('new-user.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NewUserFormRequest $request
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function submit(NewUserFormRequest $request, AccountRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
// create normal asset account:
|
||||
$assetAccount = [
|
||||
'name' => $request->get('bank_name'),
|
||||
'accountType' => 'asset',
|
||||
'virtualBalance' => 0,
|
||||
'active' => true,
|
||||
'user' => Auth::user()->id,
|
||||
'accountRole' => 'defaultAsset',
|
||||
'openingBalance' => floatval($request->input('bank_balance')),
|
||||
'openingBalanceDate' => new Carbon,
|
||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
||||
];
|
||||
|
||||
$repository->store($assetAccount);
|
||||
|
||||
// create savings account
|
||||
if (strlen($request->get('savings_balance') > 0)) {
|
||||
$savingsAccount = [
|
||||
'name' => $request->get('bank_name') . ' savings account',
|
||||
'accountType' => 'asset',
|
||||
'virtualBalance' => 0,
|
||||
'active' => true,
|
||||
'user' => Auth::user()->id,
|
||||
'accountRole' => 'savingAsset',
|
||||
'openingBalance' => floatval($request->input('savings_balance')),
|
||||
'openingBalanceDate' => new Carbon,
|
||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
||||
];
|
||||
$repository->store($savingsAccount);
|
||||
}
|
||||
|
||||
|
||||
// create credit card.
|
||||
if (strlen($request->get('credit_card_limit') > 0)) {
|
||||
$creditAccount = [
|
||||
'name' => 'Credit card',
|
||||
'accountType' => 'asset',
|
||||
'virtualBalance' => floatval($request->get('credit_card_limit')),
|
||||
'active' => true,
|
||||
'user' => Auth::user()->id,
|
||||
'accountRole' => 'ccAsset',
|
||||
'openingBalance' => null,
|
||||
'openingBalanceDate' => null,
|
||||
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
|
||||
];
|
||||
$creditCard = $repository->store($creditAccount);
|
||||
|
||||
// store meta for CC:
|
||||
AccountMeta::create(['name' => 'ccType', 'data' => 'monthlyFull', 'account_id' => $creditCard->id,]);
|
||||
AccountMeta::create(['name' => 'ccMonthlyPaymentDate', 'data' => Carbon::now()->year . '-01-01', 'account_id' => $creditCard->id,]);
|
||||
|
||||
}
|
||||
Session::flash('success', 'New account(s) created!');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('index');
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,26 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Amount;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use ExpandedForm;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\PiggyBankFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use Steam;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.TooManyMethods)
|
||||
*
|
||||
* Class PiggyBankController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
@@ -27,45 +29,55 @@ class PiggyBankController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
View::share('title', 'Piggy banks');
|
||||
parent::__construct();
|
||||
View::share('title', trans('firefly.piggyBanks'));
|
||||
View::share('mainTitleIcon', 'fa-sort-amount-asc');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add money to piggy bank
|
||||
*
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function add(PiggyBank $piggyBank, AccountRepositoryInterface $repository)
|
||||
public function add(AccountRepositoryInterface $repository, PiggyBank $piggyBank)
|
||||
{
|
||||
$leftOnAccount = $repository->leftOnAccount($piggyBank->account);
|
||||
$date = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$leftOnAccount = $repository->leftOnAccount($piggyBank->account, $date);
|
||||
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
|
||||
$leftToSave = $piggyBank->targetamount - $savedSoFar;
|
||||
$maxAmount = min($leftOnAccount, $leftToSave);
|
||||
|
||||
|
||||
\Log::debug('Now going to view for piggy bank #' . $piggyBank->id . ' (' . $piggyBank->name . ')');
|
||||
|
||||
return view('piggy-banks.add', compact('piggyBank', 'maxAmount'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function create()
|
||||
public function create(AccountRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$periods = Config::get('firefly.piggy_bank_periods');
|
||||
$accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']));
|
||||
$subTitle = 'Create new piggy bank';
|
||||
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
||||
$subTitle = trans('firefly.create_new_piggybank');
|
||||
$subTitleIcon = 'fa-plus';
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('piggy-banks.create.fromStore') !== true) {
|
||||
Session::put('piggy-banks.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('piggy-banks.create.fromStore');
|
||||
Session::flash('gaEventCategory', 'piggy-banks');
|
||||
Session::flash('gaEventAction', 'create');
|
||||
|
||||
return view('piggy-banks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon'));
|
||||
}
|
||||
|
||||
@@ -76,38 +88,45 @@ class PiggyBankController extends Controller
|
||||
*/
|
||||
public function delete(PiggyBank $piggyBank)
|
||||
{
|
||||
$subTitle = 'Delete "' . e($piggyBank->name) . '"';
|
||||
$subTitle = trans('firefly.delete_piggy_bank', ['name' => $piggyBank->name]);
|
||||
|
||||
return view('piggy_banks.delete', compact('piggyBank', 'subTitle'));
|
||||
// put previous url in session
|
||||
Session::put('piggy-banks.delete.url', URL::previous());
|
||||
Session::flash('gaEventCategory', 'piggy-banks');
|
||||
Session::flash('gaEventAction', 'delete');
|
||||
|
||||
return view('piggy-banks.delete', compact('piggyBank', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param PiggyBankRepositoryInterface $repository
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(PiggyBank $piggyBank)
|
||||
public function destroy(PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
|
||||
{
|
||||
|
||||
Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.');
|
||||
$this->_repository->destroy($piggyBank);
|
||||
|
||||
return Redirect::route('piggy_banks.index');
|
||||
Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.');
|
||||
Preferences::mark();
|
||||
$repository->destroy($piggyBank);
|
||||
|
||||
return Redirect::to(Session::get('piggy-banks.delete.url'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return $this
|
||||
* @return View
|
||||
*/
|
||||
public function edit(PiggyBank $piggyBank)
|
||||
public function edit(AccountRepositoryInterface $repository, PiggyBank $piggyBank)
|
||||
{
|
||||
|
||||
$periods = Config::get('firefly.piggy_bank_periods');
|
||||
$accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']));
|
||||
$subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"';
|
||||
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
||||
$subTitle = trans('firefly.update_piggy_title', ['name' => $piggyBank->name]);
|
||||
$subTitleIcon = 'fa-pencil';
|
||||
|
||||
/*
|
||||
@@ -123,28 +142,37 @@ class PiggyBankController extends Controller
|
||||
'account_id' => $piggyBank->account_id,
|
||||
'targetamount' => $piggyBank->targetamount,
|
||||
'targetdate' => $targetDate,
|
||||
'reminder' => $piggyBank->reminder,
|
||||
'remind_me' => intval($piggyBank->remind_me) == 1 || !is_null($piggyBank->reminder) ? true : false
|
||||
];
|
||||
Session::flash('preFilled', $preFilled);
|
||||
Session::flash('gaEventCategory', 'piggy-banks');
|
||||
Session::flash('gaEventAction', 'edit');
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('piggy-banks.edit.fromUpdate') !== true) {
|
||||
Session::put('piggy-banks.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('piggy-banks.edit.fromUpdate');
|
||||
|
||||
return view('piggy-banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'accounts', 'periods', 'preFilled'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param PiggyBankRepositoryInterface $piggyRepository
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
public function index(AccountRepositoryInterface $repository, PiggyBankRepositoryInterface $piggyRepository)
|
||||
{
|
||||
/** @var Collection $piggyBanks */
|
||||
$piggyBanks = Auth::user()->piggyBanks()->where('repeats', 0)->get();
|
||||
$piggyBanks = $piggyRepository->getPiggyBanks();
|
||||
$end = Session::get('end', Carbon::now()->endOfMonth());
|
||||
|
||||
$accounts = [];
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($piggyBanks as $piggyBank) {
|
||||
$piggyBank->savedSoFar = floatval($piggyBank->currentRelevantRep()->currentamount);
|
||||
$piggyBank->percentage = intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100);
|
||||
$piggyBank->percentage = $piggyBank->savedSoFar != 0 ? intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100) : 0;
|
||||
$piggyBank->leftToSave = $piggyBank->targetamount - $piggyBank->savedSoFar;
|
||||
|
||||
/*
|
||||
@@ -154,8 +182,8 @@ class PiggyBankController extends Controller
|
||||
if (!isset($accounts[$account->id])) {
|
||||
$accounts[$account->id] = [
|
||||
'name' => $account->name,
|
||||
'balance' => Steam::balance($account),
|
||||
'leftForPiggyBanks' => $repository->leftOnAccount($account),
|
||||
'balance' => Steam::balance($account, $end, true),
|
||||
'leftForPiggyBanks' => $repository->leftOnAccount($account, $end),
|
||||
'sumOfSaved' => $piggyBank->savedSoFar,
|
||||
'sumOfTargets' => floatval($piggyBank->targetamount),
|
||||
'leftToSave' => $piggyBank->leftToSave
|
||||
@@ -170,18 +198,36 @@ class PiggyBankController extends Controller
|
||||
return view('piggy-banks.index', compact('piggyBanks', 'accounts'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBankRepositoryInterface $repository
|
||||
*/
|
||||
public function order(PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
$data = Input::get('order');
|
||||
|
||||
// set all users piggy banks to zero:
|
||||
$repository->reset();
|
||||
|
||||
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $order => $id) {
|
||||
$repository->setOrder(intval($id), (intval($order) + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST add money to piggy bank
|
||||
*
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param PiggyBankRepositoryInterface $repository
|
||||
* @param AccountRepositoryInterface $accounts
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function postAdd(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository, AccountRepositoryInterface $accounts)
|
||||
public function postAdd(PiggyBankRepositoryInterface $repository, AccountRepositoryInterface $accounts, PiggyBank $piggyBank)
|
||||
{
|
||||
$amount = round(floatval(Input::get('amount')), 2);
|
||||
$leftOnAccount = $accounts->leftOnAccount($piggyBank->account);
|
||||
$date = Session::get('end', Carbon::now()->endOfMonth());
|
||||
$leftOnAccount = $accounts->leftOnAccount($piggyBank->account, $date);
|
||||
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
|
||||
$leftToSave = $piggyBank->targetamount - $savedSoFar;
|
||||
$maxAmount = round(min($leftOnAccount, $leftToSave), 2);
|
||||
@@ -191,12 +237,11 @@ class PiggyBankController extends Controller
|
||||
$repetition->currentamount += $amount;
|
||||
$repetition->save();
|
||||
|
||||
/*
|
||||
* Create event!
|
||||
*/
|
||||
//Event::fire('piggy_bank.addMoney', [$piggyBank, $amount]); // new and used.
|
||||
// create event
|
||||
$repository->createEvent($piggyBank, $amount);
|
||||
|
||||
Session::flash('success', 'Added ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".');
|
||||
Preferences::mark();
|
||||
} else {
|
||||
Session::flash('error', 'Could not add ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".');
|
||||
}
|
||||
@@ -205,11 +250,12 @@ class PiggyBankController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param PiggyBankRepositoryInterface $repository
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function postRemove(PiggyBank $piggyBank)
|
||||
public function postRemove(PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
|
||||
{
|
||||
$amount = floatval(Input::get('amount'));
|
||||
|
||||
@@ -220,12 +266,11 @@ class PiggyBankController extends Controller
|
||||
$repetition->currentamount -= $amount;
|
||||
$repetition->save();
|
||||
|
||||
/*
|
||||
* Create event!
|
||||
*/
|
||||
//Event::fire('piggy_bank.removeMoney', [$piggyBank, $amount]); // new and used.
|
||||
// create event
|
||||
$repository->createEvent($piggyBank, $amount * -1);
|
||||
|
||||
Session::flash('success', 'Removed ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".');
|
||||
Preferences::mark();
|
||||
} else {
|
||||
Session::flash('error', 'Could not remove ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".');
|
||||
}
|
||||
@@ -236,7 +281,6 @@ class PiggyBankController extends Controller
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @SuppressWarnings("Unused")
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
@@ -246,19 +290,14 @@ class PiggyBankController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param PiggyBankRepositoryInterface $repository
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return $this
|
||||
* @return View
|
||||
*/
|
||||
public function show(PiggyBank $piggyBank)
|
||||
public function show(PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
|
||||
{
|
||||
|
||||
$events = $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get();
|
||||
|
||||
/*
|
||||
* Number of reminders:
|
||||
*/
|
||||
|
||||
$events = $repository->getEvents($piggyBank);
|
||||
$subTitle = e($piggyBank->name);
|
||||
|
||||
return view('piggy-banks.show', compact('piggyBank', 'events', 'subTitle'));
|
||||
@@ -266,54 +305,76 @@ class PiggyBankController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBankFormRequest $request
|
||||
* @param PiggyBankRepositoryInterface $repository
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$piggyBankData = [
|
||||
'repeats' => false,
|
||||
'name' => $request->get('name'),
|
||||
'startdate' => new Carbon,
|
||||
'account_id' => intval($request->get('account_id')),
|
||||
'targetamount' => floatval($request->get('targetamount')),
|
||||
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
|
||||
'reminder' => $request->get('reminder'),
|
||||
'name' => $request->get('name'),
|
||||
'startdate' => new Carbon,
|
||||
'account_id' => intval($request->get('account_id')),
|
||||
'targetamount' => floatval($request->get('targetamount')),
|
||||
'remind_me' => false,
|
||||
'reminder_skip' => 0,
|
||||
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
|
||||
];
|
||||
|
||||
$piggyBank = $repository->store($piggyBankData);
|
||||
|
||||
Session::flash('success', 'Stored piggy bank "' . e($piggyBank->name) . '".');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('piggy-banks.index');
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
Session::put('piggy-banks.create.fromStore', true);
|
||||
|
||||
return Redirect::route('piggy-banks.create')->withInput();
|
||||
}
|
||||
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('piggy-banks.create.url'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
* @param PiggyBankRepositoryInterface $repository
|
||||
* @param PiggyBankFormRequest $request
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function update(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository, PiggyBankFormRequest $request)
|
||||
public function update(PiggyBankRepositoryInterface $repository, PiggyBankFormRequest $request, PiggyBank $piggyBank)
|
||||
{
|
||||
$piggyBankData = [
|
||||
'repeats' => false,
|
||||
'name' => $request->get('name'),
|
||||
'account_id' => intval($request->get('account_id')),
|
||||
'targetamount' => floatval($request->get('targetamount')),
|
||||
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
|
||||
'reminder' => $request->get('reminder'),
|
||||
'name' => $request->get('name'),
|
||||
'startdate' => is_null($piggyBank->startdate) ? $piggyBank->created_at : $piggyBank->startdate,
|
||||
'account_id' => intval($request->get('account_id')),
|
||||
'targetamount' => floatval($request->get('targetamount')),
|
||||
'remind_me' => false,
|
||||
'reminder_skip' => 0,
|
||||
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
|
||||
];
|
||||
|
||||
$piggyBank = $repository->update($piggyBank, $piggyBankData);
|
||||
|
||||
Session::flash('success', 'Updated piggy bank "' . e($piggyBank->name) . '".');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('piggy-banks.index');
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
Session::put('piggy-banks.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('piggy-banks.edit', [$piggyBank->id]);
|
||||
}
|
||||
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('piggy-banks.edit.url'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use View;
|
||||
use Auth;
|
||||
use Preferences;
|
||||
use Config;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Input;
|
||||
use Session;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class PreferencesController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class PreferencesController extends Controller {
|
||||
class PreferencesController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
View::share('title', 'Preferences');
|
||||
parent::__construct();
|
||||
View::share('title', trans('firefly.preferences'));
|
||||
View::share('mainTitleIcon', 'fa-gear');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return $this|\Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
{
|
||||
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']);
|
||||
$viewRange = Preferences::get('viewRange', '1M');
|
||||
$viewRangeValue = $viewRange->data;
|
||||
$frontPage = Preferences::get('frontPageAccounts', []);
|
||||
$budgetMax = Preferences::get('budgetMaximum', 1000);
|
||||
$budgetMaximum = $budgetMax->data;
|
||||
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
|
||||
$viewRangePref = Preferences::get('viewRange', '1M');
|
||||
$viewRange = $viewRangePref->data;
|
||||
$frontPageAccounts = Preferences::get('frontPageAccounts', []);
|
||||
$budgetMax = Preferences::get('budgetMaximum', 1000);
|
||||
$language = Preferences::get('language', 'en')->data;
|
||||
$budgetMaximum = $budgetMax->data;
|
||||
|
||||
return view('preferences.index', compact('budgetMaximum'))->with('accounts', $accounts)->with('frontPageAccounts', $frontPage)->with(
|
||||
'viewRange', $viewRangeValue
|
||||
);
|
||||
return view('preferences.index', compact('budgetMaximum', 'language', 'accounts', 'frontPageAccounts', 'viewRange'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,10 +51,12 @@ class PreferencesController extends Controller {
|
||||
{
|
||||
// front page accounts
|
||||
$frontPageAccounts = [];
|
||||
foreach (Input::get('frontPageAccounts') as $id) {
|
||||
$frontPageAccounts[] = intval($id);
|
||||
if (is_array(Input::get('frontPageAccounts'))) {
|
||||
foreach (Input::get('frontPageAccounts') as $id) {
|
||||
$frontPageAccounts[] = intval($id);
|
||||
}
|
||||
Preferences::set('frontPageAccounts', $frontPageAccounts);
|
||||
}
|
||||
Preferences::set('frontPageAccounts', $frontPageAccounts);
|
||||
|
||||
// view range:
|
||||
Preferences::set('viewRange', Input::get('viewRange'));
|
||||
@@ -67,8 +69,15 @@ class PreferencesController extends Controller {
|
||||
$budgetMaximum = intval(Input::get('budgetMaximum'));
|
||||
Preferences::set('budgetMaximum', $budgetMaximum);
|
||||
|
||||
// language:
|
||||
$lang = Input::get('language');
|
||||
if (in_array($lang, array_keys(Config::get('firefly.lang')))) {
|
||||
Preferences::set('language', $lang);
|
||||
}
|
||||
|
||||
|
||||
Session::flash('success', 'Preferences saved!');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('preferences');
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\DeleteAccountFormRequest;
|
||||
use FireflyIII\Http\Requests\ProfileFormRequest;
|
||||
use Hash;
|
||||
use Redirect;
|
||||
@@ -25,6 +26,16 @@ class ProfileController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function deleteAccount()
|
||||
{
|
||||
return view('profile.delete-account')->with('title', Auth::user()->email)->with('subTitle', 'Delete account')->with(
|
||||
'mainTitleIcon', 'fa-user'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*
|
||||
@@ -35,6 +46,8 @@ class ProfileController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProfileFormRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
||||
*/
|
||||
public function postChangePassword(ProfileFormRequest $request)
|
||||
@@ -43,13 +56,13 @@ class ProfileController extends Controller
|
||||
if (!Hash::check($request->get('current_password'), Auth::user()->password)) {
|
||||
Session::flash('error', 'Invalid current password!');
|
||||
|
||||
return Redirect::route('change-password');
|
||||
return Redirect::route('profile.change-password');
|
||||
}
|
||||
$result = $this->_validatePassword($request->get('current_password'), $request->get('new_password'), $request->get('new_password_confirmation'));
|
||||
$result = $this->validatePassword($request->get('current_password'), $request->get('new_password'));
|
||||
if (!($result === true)) {
|
||||
Session::flash('error', $result);
|
||||
|
||||
return Redirect::route('change-password');
|
||||
return Redirect::route('profile.change-password');
|
||||
}
|
||||
|
||||
// update the user with the new password.
|
||||
@@ -62,29 +75,45 @@ class ProfileController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
* @param string $old
|
||||
* @param string $new1
|
||||
* @param string $new2
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
protected function _validatePassword($old, $new1, $new2)
|
||||
protected function validatePassword($old, $new1)
|
||||
{
|
||||
if (strlen($new1) == 0 || strlen($new2) == 0) {
|
||||
return 'Do fill in a password!';
|
||||
|
||||
}
|
||||
if ($new1 == $old) {
|
||||
return 'The idea is to change your password.';
|
||||
}
|
||||
|
||||
if ($new1 !== $new2) {
|
||||
return 'New passwords do not match!';
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeleteAccountFormRequest $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function postDeleteAccount(DeleteAccountFormRequest $request)
|
||||
{
|
||||
// old, new1, new2
|
||||
if (!Hash::check($request->get('password'), Auth::user()->password)) {
|
||||
Session::flash('error', 'Invalid password!');
|
||||
|
||||
return Redirect::route('profile.delete-account');
|
||||
}
|
||||
|
||||
// DELETE!
|
||||
Auth::user()->delete();
|
||||
Session::flush();
|
||||
Session::flash('gaEventCategory', 'user');
|
||||
Session::flash('gaEventAction', 'delete-account');
|
||||
|
||||
return Redirect::route('index');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Amount;
|
||||
use Auth;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Response;
|
||||
use Input;
|
||||
|
||||
/**
|
||||
* Class RelatedController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class RelatedController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function alreadyRelated(TransactionJournal $journal)
|
||||
{
|
||||
$ids = [];
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($journal->transactiongroups()->get() as $group) {
|
||||
/** @var TransactionJournal $loopJournal */
|
||||
foreach ($group->transactionjournals()->get() as $loopJournal) {
|
||||
if ($loopJournal->id != $journal->id) {
|
||||
$ids[] = $loopJournal->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
$unique = array_unique($ids);
|
||||
if (count($unique) > 0) {
|
||||
|
||||
$set = Auth::user()->transactionjournals()->whereIn('id', $unique)->get();
|
||||
$set->each(
|
||||
function (TransactionJournal $journal) {
|
||||
/** @var Transaction $t */
|
||||
foreach ($journal->transactions()->get() as $t) {
|
||||
if ($t->amount > 0) {
|
||||
$journal->amount = $t->amount;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
return Response::json($set->toArray());
|
||||
} else {
|
||||
return Response::json((new Collection)->toArray());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $parentJournal
|
||||
* @param TransactionJournal $childJournal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function relate(TransactionJournal $parentJournal, TransactionJournal $childJournal)
|
||||
{
|
||||
$group = new TransactionGroup;
|
||||
$group->relation = 'balance';
|
||||
$group->user_id = Auth::user()->id;
|
||||
$group->save();
|
||||
$group->transactionjournals()->save($parentJournal);
|
||||
$group->transactionjournals()->save($childJournal);
|
||||
|
||||
return Response::json(true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function related(TransactionJournal $journal)
|
||||
{
|
||||
$groups = $journal->transactiongroups()->get();
|
||||
$members = new Collection;
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($groups as $group) {
|
||||
/** @var TransactionJournal $loopJournal */
|
||||
foreach ($group->transactionjournals()->get() as $loopJournal) {
|
||||
if ($loopJournal->id != $journal->id) {
|
||||
$members->push($loopJournal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return view('related.relate', compact('journal', 'members'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
* @param TransactionJournal $parentJournal
|
||||
* @param TransactionJournal $childJournal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function removeRelation(TransactionJournal $parentJournal, TransactionJournal $childJournal)
|
||||
{
|
||||
$groups = $parentJournal->transactiongroups()->get();
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($groups as $group) {
|
||||
foreach ($group->transactionjournals()->get() as $loopJournal) {
|
||||
if ($loopJournal->id == $childJournal->id) {
|
||||
// remove from group:
|
||||
$group->transactionjournals()->detach($childJournal);
|
||||
}
|
||||
}
|
||||
if ($group->transactionjournals()->count() == 1) {
|
||||
$group->delete();
|
||||
}
|
||||
}
|
||||
|
||||
return Response::json(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function search(TransactionJournal $journal, JournalRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$search = e(trim(Input::get('searchValue')));
|
||||
|
||||
$result = $repository->searchRelated($search, $journal);
|
||||
$result->each(
|
||||
function (TransactionJournal $journal) {
|
||||
/** @var Transaction $t */
|
||||
foreach ($journal->transactions()->get() as $t) {
|
||||
if ($t->amount > 0) {
|
||||
$journal->amount = $t->amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return Response::json($result->toArray());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use ExpandedForm;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Requests\PiggyBankFormRequest;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankRepetition;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class RepeatedExpenseController
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class RepeatedExpenseController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
View::share('title', 'Repeated expenses');
|
||||
View::share('mainTitleIcon', 'fa-rotate-left');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$periods = Config::get('firefly.piggy_bank_periods');
|
||||
$accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']));
|
||||
|
||||
return view('repeatedExpense.create', compact('accounts', 'periods'))->with('subTitle', 'Create new repeated expense')->with(
|
||||
'subTitleIcon', 'fa-plus'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $repeatedExpense
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function delete(PiggyBank $repeatedExpense)
|
||||
{
|
||||
$subTitle = 'Delete "' . e($repeatedExpense->name) . '"';
|
||||
|
||||
return view('repeatedExpense.delete', compact('repeatedExpense', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $repeatedExpense
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(PiggyBank $repeatedExpense)
|
||||
{
|
||||
|
||||
Session::flash('success', 'Repeated expense "' . e($repeatedExpense->name) . '" deleted.');
|
||||
|
||||
$repeatedExpense->delete();
|
||||
|
||||
return Redirect::route('repeated.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $repeatedExpense
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function edit(PiggyBank $repeatedExpense)
|
||||
{
|
||||
|
||||
$periods = Config::get('firefly.piggy_bank_periods');
|
||||
$accounts = ExpandedForm::makeSelectList(Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']));
|
||||
$subTitle = 'Edit repeated expense "' . e($repeatedExpense->name) . '"';
|
||||
$subTitleIcon = 'fa-pencil';
|
||||
|
||||
/*
|
||||
* Flash some data to fill the form.
|
||||
*/
|
||||
$preFilled = ['name' => $repeatedExpense->name,
|
||||
'account_id' => $repeatedExpense->account_id,
|
||||
'targetamount' => $repeatedExpense->targetamount,
|
||||
'reminder_skip' => $repeatedExpense->reminder_skip,
|
||||
'rep_every' => $repeatedExpense->rep_every,
|
||||
'rep_times' => $repeatedExpense->rep_times,
|
||||
'targetdate' => $repeatedExpense->targetdate->format('Y-m-d'),
|
||||
'reminder' => $repeatedExpense->reminder,
|
||||
'remind_me' => intval($repeatedExpense->remind_me) == 1 || !is_null($repeatedExpense->reminder) ? true : false
|
||||
];
|
||||
Session::flash('preFilled', $preFilled);
|
||||
|
||||
return view('repeatedExpense.edit', compact('subTitle', 'subTitleIcon', 'repeatedExpense', 'accounts', 'periods', 'preFilled'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
$subTitle = 'Overview';
|
||||
|
||||
$expenses = Auth::user()->piggyBanks()->where('repeats', 1)->get();
|
||||
$expenses->each(
|
||||
function (PiggyBank $piggyBank) {
|
||||
$piggyBank->currentRelevantRep();
|
||||
}
|
||||
);
|
||||
|
||||
return view('repeatedExpense.index', compact('expenses', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $repeatedExpense
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(PiggyBank $repeatedExpense, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
$subTitle = $repeatedExpense->name;
|
||||
$today = Carbon::now();
|
||||
$repetitions = $repeatedExpense->piggyBankRepetitions()->get();
|
||||
|
||||
$repetitions->each(
|
||||
function (PiggyBankRepetition $repetition) use ($repository) {
|
||||
$repetition->bars = $repository->calculateParts($repetition);
|
||||
}
|
||||
);
|
||||
|
||||
return view('repeatedExpense.show', compact('repetitions', 'repeatedExpense', 'today', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*/
|
||||
public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$piggyBankData = [
|
||||
'repeats' => true,
|
||||
'name' => $request->get('name'),
|
||||
'startdate' => new Carbon,
|
||||
'account_id' => intval($request->get('account_id')),
|
||||
'targetamount' => floatval($request->get('targetamount')),
|
||||
'targetdate' => new Carbon($request->get('targetdate')),
|
||||
'reminder' => $request->get('reminder'),
|
||||
'skip' => intval($request->get('skip')),
|
||||
'rep_every' => intval($request->get('rep_every')),
|
||||
'rep_times' => intval($request->get('rep_times')),
|
||||
];
|
||||
|
||||
$piggyBank = $repository->store($piggyBankData);
|
||||
|
||||
Session::flash('success', 'Stored repeated expense "' . e($piggyBank->name) . '".');
|
||||
|
||||
return Redirect::route('repeated.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
* @param PiggyBank $repeatedExpense
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function update(PiggyBank $repeatedExpense, PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository)
|
||||
{
|
||||
$piggyBankData = [
|
||||
'repeats' => false,
|
||||
'name' => $request->get('name'),
|
||||
'account_id' => intval($request->get('account_id')),
|
||||
'targetamount' => floatval($request->get('targetamount')),
|
||||
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
|
||||
'rep_length' => $request->get('rep_length'),
|
||||
'rep_every' => intval($request->get('rep_every')),
|
||||
'rep_times' => intval($request->get('rep_times')),
|
||||
'remind_me' => intval($request->get('remind_me')) == 1 ? true : false ,
|
||||
'reminder' => $request->get('reminder'),
|
||||
];
|
||||
|
||||
|
||||
$piggyBank = $repository->update($repeatedExpense, $piggyBankData);
|
||||
|
||||
Session::flash('success', 'Updated repeated expense "' . e($piggyBank->name) . '".');
|
||||
|
||||
return Redirect::route('repeated.index');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
||||
use FireflyIII\Helpers\Report\ReportQueryInterface;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Models\Account;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Steam;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Session;
|
||||
use View;
|
||||
|
||||
/**
|
||||
@@ -19,264 +15,135 @@ use View;
|
||||
class ReportController extends Controller
|
||||
{
|
||||
|
||||
/** @var ReportHelperInterface */
|
||||
protected $helper;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param ReportHelperInterface $helper
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct(ReportHelperInterface $helper)
|
||||
{
|
||||
View::share('title', 'Reports');
|
||||
parent::__construct();
|
||||
$this->helper = $helper;
|
||||
|
||||
View::share('title', trans('firefly.reports'));
|
||||
View::share('mainTitleIcon', 'fa-line-chart');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $year
|
||||
* @param string $month
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function budget($year = '2014', $month = '1', ReportQueryInterface $query)
|
||||
{
|
||||
try {
|
||||
new Carbon($year . '-' . $month . '-01');
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid date');
|
||||
}
|
||||
$date = new Carbon($year . '-' . $month . '-01');
|
||||
$start = clone $date;
|
||||
$start->startOfMonth();
|
||||
$end = clone $date;
|
||||
$end->endOfMonth();
|
||||
$start->subDay();
|
||||
|
||||
$dayEarly = clone $date;
|
||||
$subTitle = 'Budget report for ' . $date->format('F Y');
|
||||
$subTitleIcon = 'fa-calendar';
|
||||
$dayEarly = $dayEarly->subDay();
|
||||
$accounts = $query->getAllAccounts($start, $end);
|
||||
$start->addDay();
|
||||
|
||||
$accounts->each(
|
||||
function (Account $account) use ($start, $end, $query) {
|
||||
$budgets = $query->getBudgetSummary($account, $start, $end);
|
||||
$balancedAmount = $query->balancedTransactionsList($account, $start, $end);
|
||||
$array = [];
|
||||
foreach ($budgets as $budget) {
|
||||
$id = intval($budget->id);
|
||||
$data = $budget->toArray();
|
||||
$array[$id] = $data;
|
||||
}
|
||||
|
||||
$account->budgetInformation = $array;
|
||||
$account->balancedAmount = $balancedAmount;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
$start = clone $date;
|
||||
$start->startOfMonth();
|
||||
|
||||
/**
|
||||
* Start getBudgetsForMonth DONE
|
||||
*/
|
||||
$set = Auth::user()->budgets()->orderBy('budgets.name', 'ASC')
|
||||
->leftJoin(
|
||||
'budget_limits', function (JoinClause $join) use ($date) {
|
||||
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
|
||||
}
|
||||
)
|
||||
->get(['budgets.*', 'budget_limits.amount as amount']);
|
||||
$budgets = Steam::makeArray($set);
|
||||
$amountSet = $query->journalsByBudget($start, $end);
|
||||
$amounts = Steam::makeArray($amountSet);
|
||||
$budgets = Steam::mergeArrays($budgets, $amounts);
|
||||
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
|
||||
$budgets[0]['amount'] = isset($budgets[0]['amount']) ? $budgets[0]['amount'] : 0.0;
|
||||
$budgets[0]['name'] = 'No budget';
|
||||
|
||||
// find transactions to shared expense accounts, which are without a budget by default:
|
||||
$transfers = $query->sharedExpenses($start, $end);
|
||||
foreach ($transfers as $transfer) {
|
||||
$budgets[0]['spent'] += floatval($transfer->amount) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* End getBudgetsForMonth DONE
|
||||
*/
|
||||
|
||||
return view('reports.budget', compact('subTitle', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReportHelperInterface $helper
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return View
|
||||
* @internal param ReportHelperInterface $helper
|
||||
*/
|
||||
public function index(ReportHelperInterface $helper)
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
{
|
||||
$start = $helper->firstDate();
|
||||
$months = $helper->listOfMonths($start);
|
||||
$years = $helper->listOfYears($start);
|
||||
$title = 'Reports';
|
||||
$mainTitleIcon = 'fa-line-chart';
|
||||
$start = Session::get('first');
|
||||
$months = $this->helper->listOfMonths($start);
|
||||
|
||||
return view('reports.index', compact('years', 'months', 'title', 'mainTitleIcon'));
|
||||
// does the user have shared accounts?
|
||||
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
|
||||
$hasShared = false;
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
if ($account->getMeta('accountRole') == 'sharedAsset') {
|
||||
$hasShared = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return view('reports.index', compact('months', 'hasShared'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $year
|
||||
* @param string $month
|
||||
*
|
||||
* @param bool $shared
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function month($year = '2014', $month = '1', ReportQueryInterface $query)
|
||||
public function month($year = '2014', $month = '1', $shared = false)
|
||||
{
|
||||
try {
|
||||
new Carbon($year . '-' . $month . '-01');
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid date.');
|
||||
$start = new Carbon($year . '-' . $month . '-01');
|
||||
$subTitle = trans('firefly.reportForMonth', ['month' => $start->formatLocalized($this->monthFormat)]);
|
||||
$subTitleIcon = 'fa-calendar';
|
||||
$end = clone $start;
|
||||
$incomeTopLength = 8;
|
||||
$expenseTopLength = 8;
|
||||
if ($shared == 'shared') {
|
||||
$shared = true;
|
||||
$subTitle = trans('firefly.reportForMonthShared', ['month' => $start->formatLocalized($this->monthFormat)]);
|
||||
}
|
||||
$date = new Carbon($year . '-' . $month . '-01');
|
||||
$subTitle = 'Report for ' . $date->format('F Y');
|
||||
$subTitleIcon = 'fa-calendar';
|
||||
$displaySum = true; // to show sums in report.
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* get income for month (date)
|
||||
*
|
||||
*/
|
||||
|
||||
$start = clone $date;
|
||||
$start->startOfMonth();
|
||||
$end = clone $date;
|
||||
$end->endOfMonth();
|
||||
|
||||
/**
|
||||
* Start getIncomeForMonth DONE
|
||||
*/
|
||||
$income = $query->incomeByPeriod($start, $end);
|
||||
/**
|
||||
* End getIncomeForMonth DONE
|
||||
*/
|
||||
/**
|
||||
* Start getExpenseGroupedForMonth DONE
|
||||
*/
|
||||
$set = $query->journalsByExpenseAccount($start, $end);
|
||||
$expenses = Steam::makeArray($set);
|
||||
$expenses = Steam::sortArray($expenses);
|
||||
$expenses = Steam::limitArray($expenses, 10);
|
||||
/**
|
||||
* End getExpenseGroupedForMonth DONE
|
||||
*/
|
||||
/**
|
||||
* Start getBudgetsForMonth DONE
|
||||
*/
|
||||
$set = Auth::user()->budgets()
|
||||
->leftJoin(
|
||||
'budget_limits', function (JoinClause $join) use ($date) {
|
||||
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
|
||||
}
|
||||
)
|
||||
->get(['budgets.*', 'budget_limits.amount as amount']);
|
||||
$budgets = Steam::makeArray($set);
|
||||
$amountSet = $query->journalsByBudget($start, $end);
|
||||
$amounts = Steam::makeArray($amountSet);
|
||||
$budgets = Steam::mergeArrays($budgets, $amounts);
|
||||
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
|
||||
$budgets[0]['amount'] = isset($budgets[0]['amount']) ? $budgets[0]['amount'] : 0.0;
|
||||
$budgets[0]['name'] = 'No budget';
|
||||
$accounts = $this->helper->getAccountReport($start, $end, $shared);
|
||||
$incomes = $this->helper->getIncomeReport($start, $end, $shared);
|
||||
$expenses = $this->helper->getExpenseReport($start, $end, $shared);
|
||||
$budgets = $this->helper->getBudgetReport($start, $end, $shared);
|
||||
$categories = $this->helper->getCategoryReport($start, $end, $shared);
|
||||
$balance = $this->helper->getBalanceReport($start, $end, $shared);
|
||||
$bills = $this->helper->getBillReport($start, $end, $shared);
|
||||
|
||||
// find transactions to shared expense accounts, which are without a budget by default:
|
||||
$transfers = $query->sharedExpenses($start, $end);
|
||||
foreach ($transfers as $transfer) {
|
||||
$budgets[0]['spent'] += floatval($transfer->amount) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* End getBudgetsForMonth DONE
|
||||
*/
|
||||
/**
|
||||
* Start getCategoriesForMonth DONE
|
||||
*/
|
||||
// all categories.
|
||||
$result = $query->journalsByCategory($start, $end);
|
||||
$categories = Steam::makeArray($result);
|
||||
|
||||
// all transfers
|
||||
$result = $query->sharedExpensesByCategory($start, $end);
|
||||
$transfers = Steam::makeArray($result);
|
||||
$merged = Steam::mergeArrays($categories, $transfers);
|
||||
|
||||
// sort.
|
||||
$sorted = Steam::sortNegativeArray($merged);
|
||||
|
||||
// limit to $limit:
|
||||
$categories = Steam::limitArray($sorted, 10);
|
||||
/**
|
||||
* End getCategoriesForMonth DONE
|
||||
*/
|
||||
/**
|
||||
* Start getAccountsForMonth
|
||||
*/
|
||||
$list = $query->accountList();
|
||||
$accounts = [];
|
||||
/** @var Account $account */
|
||||
foreach ($list as $account) {
|
||||
$id = intval($account->id);
|
||||
/** @noinspection PhpParamsInspection */
|
||||
$accounts[$id] = [
|
||||
'name' => $account->name,
|
||||
'startBalance' => Steam::balance($account, $start),
|
||||
'endBalance' => Steam::balance($account, $end)
|
||||
];
|
||||
|
||||
$accounts[$id]['difference'] = $accounts[$id]['endBalance'] - $accounts[$id]['startBalance'];
|
||||
}
|
||||
|
||||
/**
|
||||
* End getAccountsForMonth
|
||||
*/
|
||||
Session::flash('gaEventCategory', 'report');
|
||||
Session::flash('gaEventAction', 'month');
|
||||
Session::flash('gaEventLabel', $start->format('F Y'));
|
||||
|
||||
|
||||
return view(
|
||||
'reports.month',
|
||||
compact(
|
||||
'income', 'expenses', 'budgets', 'accounts', 'categories',
|
||||
'date', 'subTitle', 'displaySum', 'subTitleIcon'
|
||||
'start', 'shared',
|
||||
'subTitle', 'subTitleIcon',
|
||||
'accounts',
|
||||
'incomes', 'incomeTopLength',
|
||||
'expenses', 'expenseTopLength',
|
||||
'budgets', 'balance',
|
||||
'categories',
|
||||
'bills'
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $year
|
||||
* @param $year
|
||||
*
|
||||
* @param bool $shared
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function year($year, ReportHelperInterface $helper, ReportQueryInterface $query)
|
||||
public function year($year, $shared = false)
|
||||
{
|
||||
try {
|
||||
new Carbon('01-01-' . $year);
|
||||
} catch (Exception $e) {
|
||||
return view('error')->with('message', 'Invalid date.');
|
||||
}
|
||||
$date = new Carbon('01-01-' . $year);
|
||||
$end = clone $date;
|
||||
$end->endOfYear();
|
||||
$title = 'Reports';
|
||||
$subTitle = $year;
|
||||
$subTitleIcon = 'fa-bar-chart';
|
||||
$mainTitleIcon = 'fa-line-chart';
|
||||
$balances = $helper->yearBalanceReport($date);
|
||||
$groupedIncomes = $query->journalsByRevenueAccount($date, $end);
|
||||
$groupedExpenses = $query->journalsByExpenseAccount($date, $end);
|
||||
$start = new Carbon('01-01-' . $year);
|
||||
$end = clone $start;
|
||||
$subTitle = trans('firefly.reportForYear', ['year' => $year]);
|
||||
$subTitleIcon = 'fa-bar-chart';
|
||||
$incomeTopLength = 8;
|
||||
$expenseTopLength = 8;
|
||||
|
||||
//$groupedExpenses = $helper-> expensesGroupedByAccount($date, $end, 15);
|
||||
if ($shared == 'shared') {
|
||||
$shared = true;
|
||||
$subTitle = trans('firefly.reportForYearShared', ['year' => $year]);
|
||||
}
|
||||
$end->endOfYear();
|
||||
|
||||
$accounts = $this->helper->getAccountReport($start, $end, $shared);
|
||||
$incomes = $this->helper->getIncomeReport($start, $end, $shared);
|
||||
$expenses = $this->helper->getExpenseReport($start, $end, $shared);
|
||||
|
||||
Session::flash('gaEventCategory', 'report');
|
||||
Session::flash('gaEventAction', 'year');
|
||||
Session::flash('gaEventLabel', $start->format('Y'));
|
||||
|
||||
return view(
|
||||
'reports.year', compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon')
|
||||
'reports.year',
|
||||
compact('start', 'shared', 'accounts', 'incomes', 'expenses', 'subTitle', 'subTitleIcon', 'incomeTopLength', 'expenseTopLength')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
<?php namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
|
||||
use FireflyIII\Support\Search\SearchInterface;
|
||||
use Illuminate\Http\Request;
|
||||
use Input;
|
||||
|
||||
/**
|
||||
@@ -12,9 +8,14 @@ use Input;
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class SearchController extends Controller {
|
||||
class SearchController extends Controller
|
||||
{
|
||||
/**
|
||||
* Results always come in the form of an array [results, count, fullCount]
|
||||
*
|
||||
* @param SearchInterface $searcher
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function index(SearchInterface $searcher)
|
||||
{
|
||||
@@ -25,7 +26,7 @@ class SearchController extends Controller {
|
||||
if (!is_null(Input::get('q')) && strlen(Input::get('q')) > 0) {
|
||||
$rawQuery = trim(Input::get('q'));
|
||||
$words = explode(' ', $rawQuery);
|
||||
$subTitle = 'Results for "' . e($rawQuery) . '"';
|
||||
$subTitle = trans('firefly.search_results_for', ['query' => $rawQuery]);
|
||||
|
||||
$transactions = $searcher->searchTransactions($words);
|
||||
$accounts = $searcher->searchAccounts($words);
|
||||
|
||||
304
app/Http/Controllers/TagController.php
Normal file
304
app/Http/Controllers/TagController.php
Normal file
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Requests\TagFormRequest;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use Session;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class TagController
|
||||
*
|
||||
* Remember: a balancingAct takes at most one expense and one transfer.
|
||||
* an advancePayment takes at most one expense, infinite deposits and NO transfers.
|
||||
*
|
||||
* transaction can only have one advancePayment OR balancingAct.
|
||||
* Other attempts to put in such a tag are blocked.
|
||||
* also show an error when editing a tag and it becomes either
|
||||
* of these two types. Or rather, block editing of the tag.
|
||||
*
|
||||
* @package FireflyIII\Http\Controllers
|
||||
*/
|
||||
class TagController extends Controller
|
||||
{
|
||||
|
||||
public $tagOptions = [];
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
View::share('title', 'Tags');
|
||||
View::share('mainTitleIcon', 'fa-tags');
|
||||
View::share('hideTags', true);
|
||||
$this->tagOptions = [
|
||||
'nothing' => 'Just a regular tag.',
|
||||
'balancingAct' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.',
|
||||
'advancePayment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
|
||||
];
|
||||
View::share('tagOptions', $this->tagOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$subTitle = trans('firefly.new_tag');
|
||||
$subTitleIcon = 'fa-tag';
|
||||
|
||||
$preFilled = [
|
||||
'tagMode' => 'nothing'
|
||||
];
|
||||
if (!Input::old('tagMode')) {
|
||||
Session::flash('preFilled', $preFilled);
|
||||
}
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('tags.create.fromStore') !== true) {
|
||||
Session::put('tags.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('tags.create.fromStore');
|
||||
Session::flash('gaEventCategory', 'tags');
|
||||
Session::flash('gaEventAction', 'create');
|
||||
|
||||
return view('tags.create', compact('subTitle', 'subTitleIcon'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function delete(Tag $tag)
|
||||
{
|
||||
$subTitle = trans('firefly.delete_tag', ['name' => $tag->tag]);
|
||||
|
||||
// put previous url in session
|
||||
Session::put('tags.delete.url', URL::previous());
|
||||
Session::flash('gaEventCategory', 'tags');
|
||||
Session::flash('gaEventAction', 'delete');
|
||||
|
||||
return view('tags.delete', compact('tag', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TagRepositoryInterface $repository
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(TagRepositoryInterface $repository, Tag $tag)
|
||||
{
|
||||
|
||||
$tagName = $tag->tag;
|
||||
$repository->destroy($tag);
|
||||
|
||||
Session::flash('success', 'Tag "' . e($tagName) . '" was deleted.');
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::to(route('tags.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @param TagRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Tag $tag, TagRepositoryInterface $repository)
|
||||
{
|
||||
$subTitle = trans('firefly.edit_tag', ['tag' => $tag->tag]);
|
||||
$subTitleIcon = 'fa-tag';
|
||||
|
||||
/*
|
||||
* Default tag options (again)
|
||||
*/
|
||||
$tagOptions = $this->tagOptions;
|
||||
|
||||
/*
|
||||
* Can this tag become another type?
|
||||
*/
|
||||
$allowAdvance = $repository->tagAllowAdvance($tag);
|
||||
$allowToBalancingAct = $repository->tagAllowBalancing($tag);
|
||||
|
||||
// edit tag options:
|
||||
if ($allowAdvance === false) {
|
||||
unset($tagOptions['advancePayment']);
|
||||
}
|
||||
if ($allowToBalancingAct === false) {
|
||||
unset($tagOptions['balancingAct']);
|
||||
}
|
||||
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('tags.edit.fromUpdate') !== true) {
|
||||
Session::put('tags.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('tags.edit.fromUpdate');
|
||||
Session::flash('gaEventCategory', 'tags');
|
||||
Session::flash('gaEventAction', 'edit');
|
||||
|
||||
return view('tags.edit', compact('tag', 'subTitle', 'subTitleIcon', 'tagOptions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $state
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function hideTagHelp($state)
|
||||
{
|
||||
|
||||
$state = $state == 'true' ? true : false;
|
||||
Preferences::set('hideTagHelp', $state);
|
||||
|
||||
return Response::json([true]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
/** @var Preference $helpHiddenPref */
|
||||
$helpHiddenPref = Preferences::get('hideTagHelp', false);
|
||||
$title = 'Tags';
|
||||
$mainTitleIcon = 'fa-tags';
|
||||
$helpHidden = $helpHiddenPref->data;
|
||||
|
||||
// group years.
|
||||
$types = ['nothing', 'balancingAct', 'advancePayment'];
|
||||
|
||||
// loop each types and get the tags, group them by year.
|
||||
$collection = [];
|
||||
foreach ($types as $type) {
|
||||
$tags = Auth::user()->tags()->where('tagMode', $type)->orderBy('date', 'ASC')->get();
|
||||
/** @var Tag $tag */
|
||||
foreach ($tags as $tag) {
|
||||
$year = is_null($tag->date) ? trans('firefly.no_year') : $tag->date->year;
|
||||
$month = is_null($tag->date) ? trans('firefly.no_month') : $tag->date->formatLocalized($this->monthFormat);
|
||||
$collection[$type][$year][$month][] = $tag;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return view('tags.index', compact('title', 'mainTitleIcon', 'types', 'helpHidden', 'collection'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(Tag $tag)
|
||||
{
|
||||
$subTitle = $tag->tag;
|
||||
$subTitleIcon = 'fa-tag';
|
||||
|
||||
return view('tags.show', compact('tag', 'subTitle', 'subTitleIcon'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TagFormRequest $request
|
||||
*
|
||||
* @param TagRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(TagFormRequest $request, TagRepositoryInterface $repository)
|
||||
{
|
||||
if (Input::get('setTag') == 'true') {
|
||||
$latitude = strlen($request->get('latitude')) > 0 ? $request->get('latitude') : null;
|
||||
$longitude = strlen($request->get('longitude')) > 0 ? $request->get('longitude') : null;
|
||||
$zoomLevel = strlen($request->get('zoomLevel')) > 0 ? $request->get('zoomLevel') : null;
|
||||
} else {
|
||||
$latitude = null;
|
||||
$longitude = null;
|
||||
$zoomLevel = null;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'tag' => $request->get('tag'),
|
||||
'date' => strlen($request->get('date')) > 0 ? new Carbon($request->get('date')) : null,
|
||||
'description' => strlen($request->get('description')) > 0 ? $request->get('description') : '',
|
||||
'latitude' => $latitude,
|
||||
'longitude' => $longitude,
|
||||
'zoomLevel' => $zoomLevel,
|
||||
'tagMode' => $request->get('tagMode'),
|
||||
];
|
||||
$repository->store($data);
|
||||
|
||||
Session::flash('success', 'The tag has been created!');
|
||||
Preferences::mark();
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('tags.create.fromStore', true);
|
||||
|
||||
return Redirect::route('tags.create')->withInput();
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('tags.create.url'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TagFormRequest $request
|
||||
* @param TagRepositoryInterface $repository
|
||||
* @param Tag $tag
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(TagFormRequest $request, TagRepositoryInterface $repository, Tag $tag)
|
||||
{
|
||||
if (Input::get('setTag') == 'true') {
|
||||
$latitude = $request->get('latitude');
|
||||
$longitude = $request->get('longitude');
|
||||
$zoomLevel = $request->get('zoomLevel');
|
||||
} else {
|
||||
$latitude = null;
|
||||
$longitude = null;
|
||||
$zoomLevel = null;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'tag' => $request->get('tag'),
|
||||
'date' => strlen($request->get('date')) > 0 ? new Carbon($request->get('date')) : null,
|
||||
'description' => strlen($request->get('description')) > 0 ? $request->get('description') : '',
|
||||
'latitude' => $latitude,
|
||||
'longitude' => $longitude,
|
||||
'zoomLevel' => $zoomLevel,
|
||||
'tagMode' => $request->get('tagMode'),
|
||||
];
|
||||
|
||||
|
||||
$repository->update($tag, $data);
|
||||
|
||||
Session::flash('success', 'Tag "' . e($data['tag']) . '" updated.');
|
||||
Preferences::mark();
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('tags.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('tags.edit', [$tag->id])->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('tags.edit.url'));
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,21 @@
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use ExpandedForm;
|
||||
use FireflyIII\Http\Requests;
|
||||
use FireflyIII\Events\JournalCreated;
|
||||
use FireflyIII\Events\JournalSaved;
|
||||
use FireflyIII\Http\Requests\JournalFormRequest;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Input;
|
||||
use Preferences;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use Session;
|
||||
use URL;
|
||||
use View;
|
||||
|
||||
|
||||
/**
|
||||
* Class TransactionController
|
||||
*
|
||||
@@ -24,40 +26,45 @@ use View;
|
||||
class TransactionController extends Controller
|
||||
{
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
View::share('title', 'Transactions');
|
||||
parent::__construct();
|
||||
View::share('title', trans('firefly.transactions'));
|
||||
View::share('mainTitleIcon', 'fa-repeat');
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the view helping the user to create a new transaction journal.
|
||||
*
|
||||
* @param string $what
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param string $what
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create($what = 'deposit')
|
||||
public function create(AccountRepositoryInterface $repository, $what = 'deposit')
|
||||
{
|
||||
$accounts = ExpandedForm::makeSelectList(
|
||||
Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->where('active', 1)->orderBy('name', 'DESC')->get(['accounts.*'])
|
||||
);
|
||||
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
||||
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
|
||||
$budgets[0] = '(no budget)';
|
||||
$budgets[0] = trans('form.noBudget');
|
||||
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
|
||||
$piggies[0] = '(no piggy bank)';
|
||||
$piggies[0] = trans('form.noPiggybank');
|
||||
$preFilled = Session::has('preFilled') ? Session::get('preFilled') : [];
|
||||
$respondTo = ['account_id', 'account_from_id'];
|
||||
$subTitle = 'Add a new ' . e($what);
|
||||
$subTitle = trans('form.add_new_' . $what);
|
||||
|
||||
foreach ($respondTo as $r) {
|
||||
if (!is_null(Input::get($r))) {
|
||||
$preFilled[$r] = Input::get($r);
|
||||
}
|
||||
$preFilled[$r] = Input::get($r);
|
||||
}
|
||||
Session::put('preFilled', $preFilled);
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (Session::get('transactions.create.fromStore') !== true) {
|
||||
Session::put('transactions.create.url', URL::previous());
|
||||
}
|
||||
Session::forget('transactions.create.fromStore');
|
||||
Session::flash('gaEventCategory', 'transactions');
|
||||
Session::flash('gaEventAction', 'create-' . $what);
|
||||
|
||||
asort($piggies);
|
||||
|
||||
|
||||
@@ -69,68 +76,70 @@ class TransactionController extends Controller
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return $this
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function delete(TransactionJournal $journal)
|
||||
{
|
||||
$type = strtolower($journal->transactionType->type);
|
||||
$subTitle = 'Delete ' . e($type) . ' "' . e($journal->description) . '"';
|
||||
$what = strtolower($journal->transactionType->type);
|
||||
$subTitle = trans('firefly.delete_' . $what, ['description' => $journal->description]);
|
||||
|
||||
return View::make('transactions.delete', compact('journal', 'subTitle'));
|
||||
// put previous url in session
|
||||
Session::put('transactions.delete.url', URL::previous());
|
||||
Session::flash('gaEventCategory', 'transactions');
|
||||
Session::flash('gaEventAction', 'delete-' . $what);
|
||||
|
||||
return view('transactions.delete', compact('journal', 'subTitle', 'what'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $transactionJournal
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param TransactionJournal $transactionJournal
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(TransactionJournal $transactionJournal)
|
||||
public function destroy(JournalRepositoryInterface $repository, TransactionJournal $transactionJournal)
|
||||
{
|
||||
$type = $transactionJournal->transactionType->type;
|
||||
$return = 'withdrawal';
|
||||
|
||||
Session::flash('success', 'Transaction "' . e($transactionJournal->description) . '" destroyed.');
|
||||
|
||||
$transactionJournal->delete();
|
||||
$repository->delete($transactionJournal);
|
||||
|
||||
switch ($type) {
|
||||
case 'Deposit':
|
||||
$return = 'deposit';
|
||||
break;
|
||||
case 'Transfer':
|
||||
$return = 'transfers';
|
||||
break;
|
||||
}
|
||||
Preferences::mark();
|
||||
|
||||
return Redirect::route('transactions.index', $return);
|
||||
// redirect to previous URL:
|
||||
return Redirect::to(Session::get('transactions.delete.url'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the view to edit a transaction.
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @param AccountRepositoryInterface $repository
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function edit(TransactionJournal $journal, JournalRepositoryInterface $repository)
|
||||
public function edit(AccountRepositoryInterface $repository, TransactionJournal $journal)
|
||||
{
|
||||
$what = strtolower($journal->transactiontype->type);
|
||||
$accounts = ExpandedForm::makeSelectList(
|
||||
Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->where('active', 1)->orderBy('name', 'DESC')->get(['accounts.*'])
|
||||
);
|
||||
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
|
||||
$budgets[0] = '(no budget)';
|
||||
$transactions = $journal->transactions()->orderBy('amount', 'DESC')->get();
|
||||
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
|
||||
$piggies[0] = '(no piggy bank)';
|
||||
$preFilled = [
|
||||
$what = strtolower($journal->transactionType->type);
|
||||
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
|
||||
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
|
||||
$budgets[0] = trans('form.noBudget');
|
||||
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
|
||||
$piggies[0] = trans('form.noPiggybank');
|
||||
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
|
||||
$preFilled = [
|
||||
'date' => $journal->date->format('Y-m-d'),
|
||||
'category' => '',
|
||||
'budget_id' => 0,
|
||||
'piggy_bank_id' => 0
|
||||
];
|
||||
// get tags:
|
||||
$tags = [];
|
||||
foreach ($journal->tags as $tag) {
|
||||
$tags[] = $tag->tag;
|
||||
}
|
||||
$preFilled['tags'] = join(',', $tags);
|
||||
|
||||
$category = $journal->categories()->first();
|
||||
if (!is_null($category)) {
|
||||
@@ -143,65 +152,70 @@ class TransactionController extends Controller
|
||||
}
|
||||
|
||||
if ($journal->piggyBankEvents()->count() > 0) {
|
||||
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->first()->piggy_bank_id;
|
||||
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->orderBy('date', 'DESC')->first()->piggy_bank_id;
|
||||
}
|
||||
|
||||
$preFilled['amount'] = 0;
|
||||
/** @var Transaction $t */
|
||||
foreach ($transactions as $t) {
|
||||
if (floatval($t->amount) > 0) {
|
||||
$preFilled['amount'] = floatval($t->amount);
|
||||
}
|
||||
$preFilled['amount'] = $journal->actual_amount;
|
||||
|
||||
if ($journal->transactionType->type == 'Withdrawal') {
|
||||
$preFilled['account_id'] = $journal->source_account->id;
|
||||
$preFilled['expense_account'] = $journal->destination_account->name_for_editform;
|
||||
} else {
|
||||
$preFilled['account_id'] = $journal->destination_account->id;
|
||||
$preFilled['revenue_account'] = $journal->source_account->name_for_editform;
|
||||
}
|
||||
$preFilled['account_id'] = $repository->getAssetAccount($journal);
|
||||
$preFilled['expense_account'] = $transactions[0]->account->name;
|
||||
$preFilled['revenue_account'] = $transactions[1]->account->name;
|
||||
$preFilled['account_from_id'] = $transactions[1]->account->id;
|
||||
$preFilled['account_to_id'] = $transactions[0]->account->id;
|
||||
|
||||
$preFilled['account_from_id'] = $journal->source_account->id;
|
||||
$preFilled['account_to_id'] = $journal->destination_account->id;
|
||||
|
||||
Session::flash('preFilled', $preFilled);
|
||||
Session::flash('gaEventCategory', 'transactions');
|
||||
Session::flash('gaEventAction', 'edit-' . $what);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (Session::get('transactions.edit.fromUpdate') !== true) {
|
||||
Session::put('transactions.edit.url', URL::previous());
|
||||
}
|
||||
Session::forget('transactions.edit.fromUpdate');
|
||||
|
||||
|
||||
return View::make('transactions.edit', compact('journal', 'accounts', 'what', 'budgets', 'piggies', 'subTitle'))->with('data', $preFilled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $what
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param $what
|
||||
*
|
||||
* @return $this
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index($what)
|
||||
public function index(JournalRepositoryInterface $repository, $what)
|
||||
{
|
||||
$types = [];
|
||||
switch ($what) {
|
||||
case 'expenses':
|
||||
case 'withdrawal':
|
||||
$subTitleIcon = 'fa-long-arrow-left';
|
||||
$subTitle = 'Expenses';
|
||||
//$journals = $this->_repository->getWithdrawalsPaginated(50);
|
||||
$types = ['Withdrawal'];
|
||||
$subTitle = trans('firefly.expenses');
|
||||
$types = ['Withdrawal'];
|
||||
break;
|
||||
case 'revenue':
|
||||
case 'deposit':
|
||||
$subTitleIcon = 'fa-long-arrow-right';
|
||||
$subTitle = 'Revenue, income and deposits';
|
||||
// $journals = $this->_repository->getDepositsPaginated(50);
|
||||
$types = ['Deposit'];
|
||||
$subTitle = trans('firefly.income');
|
||||
$types = ['Deposit'];
|
||||
break;
|
||||
case 'transfer':
|
||||
case 'transfers':
|
||||
$subTitleIcon = 'fa-arrows-h';
|
||||
$subTitle = 'Transfers';
|
||||
//$journals = $this->_repository->getTransfersPaginated(50);
|
||||
$types = ['Transfer'];
|
||||
$subTitleIcon = 'fa-exchange';
|
||||
$subTitle = trans('firefly.transfers');
|
||||
$types = ['Transfer'];
|
||||
break;
|
||||
}
|
||||
|
||||
$page = intval(\Input::get('page'));
|
||||
$offset = $page > 0 ? ($page - 1) * 50 : 0;
|
||||
$page = intval(Input::get('page'));
|
||||
$offset = $page > 0 ? ($page - 1) * 50 : 0;
|
||||
$journals = $repository->getJournalsOfTypes($types, $offset, $page);
|
||||
|
||||
$set = Auth::user()->transactionJournals()->transactionTypes($types)->withRelevantData()->take(50)->offset($offset)->orderBy('date', 'DESC')->get(
|
||||
['transaction_journals.*']
|
||||
);
|
||||
$count = Auth::user()->transactionJournals()->transactionTypes($types)->count();
|
||||
$journals = new LengthAwarePaginator($set, $count, 50, $page);
|
||||
$journals->setPath('transactions/' . $what);
|
||||
|
||||
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals'));
|
||||
@@ -209,98 +223,115 @@ class TransactionController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param JournalRepositoryInterface $repository
|
||||
*
|
||||
* @return $this
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function show(TransactionJournal $journal)
|
||||
public function reorder(JournalRepositoryInterface $repository)
|
||||
{
|
||||
$journal->transactions->each(
|
||||
function (Transaction $t) use ($journal) {
|
||||
$t->before = floatval(
|
||||
$t->account->transactions()->leftJoin(
|
||||
'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id'
|
||||
)->where('transaction_journals.date', '<=', $journal->date->format('Y-m-d'))->where(
|
||||
'transaction_journals.created_at', '<=', $journal->created_at->format('Y-m-d H:i:s')
|
||||
)->where('transaction_journals.id', '!=', $journal->id)->sum('transactions.amount')
|
||||
);
|
||||
$t->after = $t->before + $t->amount;
|
||||
}
|
||||
);
|
||||
$members = new Collection;
|
||||
/** @var TransactionGroup $group */
|
||||
foreach ($journal->transactiongroups()->get() as $group) {
|
||||
/** @var TransactionJournal $loopJournal */
|
||||
foreach ($group->transactionjournals()->get() as $loopJournal) {
|
||||
if ($loopJournal->id != $journal->id) {
|
||||
$members->push($loopJournal);
|
||||
$ids = Input::get('items');
|
||||
$date = new Carbon(Input::get('date'));
|
||||
if (count($ids) > 0) {
|
||||
$order = 0;
|
||||
foreach ($ids as $id) {
|
||||
|
||||
$journal = $repository->getWithDate($id, $date);
|
||||
if ($journal) {
|
||||
$journal->order = $order;
|
||||
$order++;
|
||||
$journal->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
Preferences::mark();
|
||||
|
||||
return view('transactions.show', compact('journal', 'members'))->with(
|
||||
'subTitle', e($journal->transactiontype->type) . ' "' . e($journal->description) . '"'
|
||||
);
|
||||
}
|
||||
|
||||
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$journalData = [
|
||||
'what' => $request->get('what'),
|
||||
'description' => $request->get('description'),
|
||||
'account_id' => intval($request->get('account_id')),
|
||||
'account_from_id' => intval($request->get('account_from_id')),
|
||||
'account_to_id' => intval($request->get('account_to_id')),
|
||||
'expense_account' => $request->get('expense_account'),
|
||||
'revenue_account' => $request->get('revenue_account'),
|
||||
'amount' => floatval($request->get('amount')),
|
||||
'user' => Auth::user()->id,
|
||||
'amount_currency_id' => intval($request->get('amount_currency_id')),
|
||||
'date' => new Carbon($request->get('date')),
|
||||
'budget_id' => intval($request->get('budget_id')),
|
||||
'category' => $request->get('category'),
|
||||
];
|
||||
|
||||
$journal = $repository->store($journalData);
|
||||
|
||||
Session::flash('success', 'New transaction "' . $journal->description . '" stored!');
|
||||
|
||||
return Redirect::route('transactions.index', $request->input('what'));
|
||||
return Response::json([true]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
|
||||
*
|
||||
* @return $this
|
||||
* @throws FireflyException
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function update(TransactionJournal $journal, JournalFormRequest $request, JournalRepositoryInterface $repository)
|
||||
public function show(JournalRepositoryInterface $repository, TransactionJournal $journal)
|
||||
{
|
||||
$journal->transactions->each(
|
||||
function (Transaction $t) use ($journal, $repository) {
|
||||
$t->before = $repository->getAmountBefore($journal, $t);
|
||||
$t->after = $t->before + $t->amount;
|
||||
}
|
||||
);
|
||||
$what = strtolower($journal->transactionType->type);
|
||||
$subTitle = trans('firefly.' . $journal->transactionType->type) . ' "' . e($journal->description) . '"';
|
||||
|
||||
return view('transactions.show', compact('journal', 'subTitle', 'what'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param JournalFormRequest $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository)
|
||||
{
|
||||
|
||||
$journalData = [
|
||||
'what' => $request->get('what'),
|
||||
'description' => $request->get('description'),
|
||||
'account_id' => intval($request->get('account_id')),
|
||||
'account_from_id' => intval($request->get('account_from_id')),
|
||||
'account_to_id' => intval($request->get('account_to_id')),
|
||||
'expense_account' => $request->get('expense_account'),
|
||||
'revenue_account' => $request->get('revenue_account'),
|
||||
'amount' => floatval($request->get('amount')),
|
||||
'user' => Auth::user()->id,
|
||||
'amount_currency_id' => intval($request->get('amount_currency_id')),
|
||||
'date' => new Carbon($request->get('date')),
|
||||
'budget_id' => intval($request->get('budget_id')),
|
||||
'category' => $request->get('category'),
|
||||
];
|
||||
$journalData = $request->getJournalData();
|
||||
$journal = $repository->store($journalData);
|
||||
|
||||
// rescan journal, UpdateJournalConnection
|
||||
event(new JournalSaved($journal));
|
||||
// ConnectJournalToPiggyBank
|
||||
if ($journal->transactionType->type == 'Transfer' && intval($request->get('piggy_bank_id')) > 0) {
|
||||
event(new JournalCreated($journal, intval($request->get('piggy_bank_id'))));
|
||||
}
|
||||
|
||||
Session::flash('success', 'New transaction "' . $journal->description . '" stored!');
|
||||
Preferences::mark();
|
||||
|
||||
if (intval(Input::get('create_another')) === 1) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
Session::put('transactions.create.fromStore', true);
|
||||
|
||||
return Redirect::route('transactions.create', [$request->input('what')])->withInput();
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('transactions.create.url'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param JournalFormRequest $request
|
||||
* @param JournalRepositoryInterface $repository
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, TransactionJournal $journal)
|
||||
{
|
||||
|
||||
$journalData = $request->getJournalData();
|
||||
$repository->update($journal, $journalData);
|
||||
Session::flash('success', 'Transaction "' . e($journalData['description']) . '" updated.');
|
||||
|
||||
return Redirect::route('transactions.index', $journalData['what']);
|
||||
event(new JournalSaved($journal));
|
||||
// update, get events by date and sort DESC
|
||||
|
||||
Session::flash('success', 'Transaction "' . e($journalData['description']) . '" updated.');
|
||||
Preferences::mark();
|
||||
|
||||
if (intval(Input::get('return_to_edit')) === 1) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
Session::put('transactions.edit.fromUpdate', true);
|
||||
|
||||
return Redirect::route('transactions.edit', [$journal->id])->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
// redirect to previous URL.
|
||||
return Redirect::to(Session::get('transactions.edit.url'));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ class Kernel extends HttpKernel
|
||||
'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
|
||||
'Illuminate\Session\Middleware\StartSession',
|
||||
'Illuminate\View\Middleware\ShareErrorsFromSession',
|
||||
'FireflyIII\Http\Middleware\ReplaceTestVars',
|
||||
'FireflyIII\Http\Middleware\VerifyCsrfToken',
|
||||
];
|
||||
|
||||
@@ -36,6 +37,7 @@ class Kernel extends HttpKernel
|
||||
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
|
||||
'guest' => 'FireflyIII\Http\Middleware\RedirectIfAuthenticated',
|
||||
'range' => 'FireflyIII\Http\Middleware\Range',
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
<?php namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use App;
|
||||
use Carbon\Carbon;
|
||||
use Closure;
|
||||
use Config;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Http\Request;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class Authenticate
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Middleware
|
||||
*/
|
||||
class Authenticate
|
||||
@@ -37,7 +43,7 @@ class Authenticate
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($this->auth->guest()) {
|
||||
if ($request->ajax()) {
|
||||
@@ -46,6 +52,12 @@ class Authenticate
|
||||
return redirect()->guest('auth/login');
|
||||
}
|
||||
}
|
||||
// if logged in, set user language:
|
||||
$pref = Preferences::get('language', 'en');
|
||||
App::setLocale($pref->data);
|
||||
Carbon::setLocale($pref->data);
|
||||
|
||||
setlocale(LC_TIME, Config::get('firefly.locales.' . $pref->data));
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
|
||||
namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use App;
|
||||
use Carbon\Carbon;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Http\Request;
|
||||
use Navigation;
|
||||
use Preferences;
|
||||
use Session;
|
||||
use View;
|
||||
|
||||
/**
|
||||
* Class SessionFilter
|
||||
@@ -40,36 +43,46 @@ class Range
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $theNext
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $theNext)
|
||||
public function handle(Request $request, Closure $theNext)
|
||||
{
|
||||
if ($this->auth->check()) {
|
||||
// user's view range comes from preferences, gets set in session:
|
||||
/** @var \FireflyIII\Models\Preference $viewRange */
|
||||
$viewRange = Preferences::get('viewRange', '1M');
|
||||
|
||||
// ignore preference. set the range to be the current month:
|
||||
if (!Session::has('start') && !Session::has('end')) {
|
||||
|
||||
// the start and end date are checked and stored:
|
||||
$start = Session::has('start') ? Session::get('start') : new Carbon;
|
||||
$start = Navigation::updateStartDate($viewRange->data, $start);
|
||||
$end = Navigation::updateEndDate($viewRange->data, $start);
|
||||
$period = Navigation::periodName($viewRange->data, $start);
|
||||
$prev = Navigation::jumpToPrevious($viewRange->data, clone $start);
|
||||
$next = Navigation::jumpToNext($viewRange->data, clone $start);
|
||||
|
||||
Session::put('range', $viewRange->data);
|
||||
Session::put('start', $start);
|
||||
Session::put('end', $end);
|
||||
Session::put('period', $period);
|
||||
Session::put('prev', Navigation::periodName($viewRange->data, $prev));
|
||||
Session::put('next', Navigation::periodName($viewRange->data, $next));
|
||||
/** @var \FireflyIII\Models\Preference $viewRange */
|
||||
$viewRange = Preferences::get('viewRange', '1M')->data;
|
||||
$start = new Carbon;
|
||||
$start = Navigation::updateStartDate($viewRange, $start);
|
||||
$end = Navigation::updateEndDate($viewRange, $start);
|
||||
|
||||
Session::put('start', $start);
|
||||
Session::put('end', $end);
|
||||
}
|
||||
if (!Session::has('first')) {
|
||||
/** @var \FireflyIII\Repositories\Journal\JournalRepositoryInterface $repository */
|
||||
$repository = App::make('FireflyIII\Repositories\Journal\JournalRepositoryInterface');
|
||||
$journal = $repository->first();
|
||||
if ($journal) {
|
||||
Session::put('first', $journal->date);
|
||||
} else {
|
||||
Session::put('first', Carbon::now()->startOfYear());
|
||||
}
|
||||
}
|
||||
$current = Carbon::now()->formatLocalized('%B %Y');
|
||||
$next = Carbon::now()->endOfMonth()->addDay()->formatLocalized('%B %Y');
|
||||
$prev = Carbon::now()->startOfMonth()->subDay()->formatLocalized('%B %Y');
|
||||
View::share('currentMonthName', $current);
|
||||
View::share('previousMonthName', $prev);
|
||||
View::share('nextMonthName', $next);
|
||||
}
|
||||
|
||||
return $theNext($request);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class RedirectIfAuthenticated
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Middleware
|
||||
*/
|
||||
class RedirectIfAuthenticated
|
||||
@@ -38,7 +40,7 @@ class RedirectIfAuthenticated
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($this->auth->check()) {
|
||||
return new RedirectResponse(url('/'));
|
||||
|
||||
57
app/Http/Middleware/ReplaceTestVars.php
Normal file
57
app/Http/Middleware/ReplaceTestVars.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class ReplaceTestVars
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Middleware
|
||||
*/
|
||||
class ReplaceTestVars
|
||||
{
|
||||
/**
|
||||
* The application implementation.
|
||||
*
|
||||
* @var Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* Create a new filter instance.
|
||||
*
|
||||
* @param Application $app
|
||||
*
|
||||
*/
|
||||
public function __construct(Application $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ('testing' === $this->app->environment() && $request->has('_token')) {
|
||||
$input = $request->all();
|
||||
$input['_token'] = $request->session()->token();
|
||||
// we need to update _token value to make sure we get the POST / PUT tests passed.
|
||||
Log::debug('Input token replaced (' . $input['_token'] . ').');
|
||||
$request->replace($input);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
|
||||
/**
|
||||
* Class VerifyCsrfToken
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Middleware
|
||||
*/
|
||||
class VerifyCsrfToken extends BaseVerifier
|
||||
|
||||
@@ -10,6 +10,7 @@ use Input;
|
||||
/**
|
||||
* Class AccountFormRequest
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class AccountFormRequest extends Request
|
||||
@@ -28,22 +29,29 @@ class AccountFormRequest extends Request
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$accountRoles = join(',', array_keys(Config::get('firefly.accountRoles')));
|
||||
$types = join(',', array_keys(Config::get('firefly.subTitlesByIdentifier')));
|
||||
$accountRoles = join(',', array_keys(Config::get('firefly.accountRoles')));
|
||||
$types = join(',', array_keys(Config::get('firefly.subTitlesByIdentifier')));
|
||||
$ccPaymentTypes = join(',', array_keys(Config::get('firefly.ccTypes')));
|
||||
|
||||
$nameRule = 'required|between:1,100|uniqueForUser:accounts,name';
|
||||
$nameRule = 'required|min:1|uniqueAccountForUser';
|
||||
$idRule = '';
|
||||
if (Account::find(Input::get('id'))) {
|
||||
$nameRule = 'required|between:1,100';
|
||||
$idRule = 'belongsToUser:accounts';
|
||||
$nameRule = 'required|min:1|uniqueAccountForUser:' . Input::get('id');
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => $nameRule,
|
||||
'openingBalance' => 'numeric',
|
||||
'openingBalanceDate' => 'date',
|
||||
'accountRole' => 'in:' . $accountRoles,
|
||||
'active' => 'boolean',
|
||||
'balance_currency_id' => 'exists:transaction_currencies,id',
|
||||
'what' => 'in:' . $types
|
||||
'id' => $idRule,
|
||||
'name' => $nameRule,
|
||||
'openingBalance' => 'numeric',
|
||||
'virtualBalance' => 'numeric',
|
||||
'openingBalanceDate' => 'date',
|
||||
'accountRole' => 'in:' . $accountRoles,
|
||||
'active' => 'boolean',
|
||||
'ccType' => 'in:' . $ccPaymentTypes,
|
||||
'ccMonthlyPaymentDate' => 'date',
|
||||
'balance_currency_id' => 'exists:transaction_currencies,id',
|
||||
'what' => 'in:' . $types
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: sander
|
||||
* Date: 25/02/15
|
||||
* Time: 12:29
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Input;
|
||||
|
||||
/**
|
||||
* Class BillFormRequest
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class BillFormRequest extends Request
|
||||
@@ -27,19 +23,41 @@ class BillFormRequest extends Request
|
||||
return Auth::check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getBillData()
|
||||
{
|
||||
return [
|
||||
'name' => $this->get('name'),
|
||||
'match' => $this->get('match'),
|
||||
'amount_min' => floatval($this->get('amount_min')),
|
||||
'amount_currency_id' => floatval($this->get('amount_currency_id')),
|
||||
'amount_max' => floatval($this->get('amount_max')),
|
||||
'date' => new Carbon($this->get('date')),
|
||||
'user' => Auth::user()->id,
|
||||
'repeat_freq' => $this->get('repeat_freq'),
|
||||
'skip' => intval($this->get('skip')),
|
||||
'automatch' => intval($this->get('automatch')) === 1,
|
||||
'active' => intval($this->get('active')) === 1,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$nameRule = 'required|between:1,255|uniqueForUser:bills,name';
|
||||
if(intval(Input::get('id')) > 0) {
|
||||
$nameRule .= ','.intval(Input::get('id'));
|
||||
$nameRule = 'required|between:1,255|uniqueObjectForUser:bills,name';
|
||||
$matchRule = 'required|between:1,255|uniqueObjectForUser:bills,match';
|
||||
if (intval(Input::get('id')) > 0) {
|
||||
$nameRule .= ',' . intval(Input::get('id'));
|
||||
$matchRule .= ',' . intval(Input::get('id'));
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'name' => $nameRule,
|
||||
'match' => 'required|between:1,255',
|
||||
'match' => $matchRule,
|
||||
'amount_min' => 'required|numeric|min:0.01',
|
||||
'amount_max' => 'required|numeric|min:0.01',
|
||||
'amount_currency_id' => 'required|exists:transaction_currencies,id',
|
||||
@@ -52,4 +70,4 @@ class BillFormRequest extends Request
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use Input;
|
||||
/**
|
||||
* Class BudgetFormRequest
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class BudgetFormRequest extends Request
|
||||
@@ -28,13 +29,14 @@ class BudgetFormRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
|
||||
$nameRule = 'required|between:1,100|uniqueForUser:budgets,name';
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:budgets,name';
|
||||
if (Budget::find(Input::get('id'))) {
|
||||
$nameRule = 'required|between:1,100';
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:budgets,name,' . intval(Input::get('id'));
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => $nameRule,
|
||||
'name' => $nameRule,
|
||||
'active' => 'numeric|between:0,1'
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use Input;
|
||||
/**
|
||||
* Class CategoryFormRequest
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class CategoryFormRequest extends Request
|
||||
@@ -28,13 +29,13 @@ class CategoryFormRequest extends Request
|
||||
public function rules()
|
||||
{
|
||||
|
||||
$nameRule = 'required|between:1,100|uniqueForUser:categories,name';
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:categories,name';
|
||||
if (Category::find(Input::get('id'))) {
|
||||
$nameRule = 'required|between:1,100';
|
||||
$nameRule = 'required|between:1,100|uniqueObjectForUser:categories,name,' . intval(Input::get('id'));
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => $nameRule,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: sander
|
||||
* Date: 25/02/15
|
||||
* Time: 12:29
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
@@ -14,6 +8,7 @@ use Input;
|
||||
/**
|
||||
* Class BillFormRequest
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class CurrencyFormRequest extends Request
|
||||
@@ -27,6 +22,18 @@ class CurrencyFormRequest extends Request
|
||||
return Auth::check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getCurrencyData()
|
||||
{
|
||||
return [
|
||||
'name' => $this->get('name'),
|
||||
'code' => $this->get('code'),
|
||||
'symbol' => $this->get('symbol'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
@@ -48,4 +55,4 @@ class CurrencyFormRequest extends Request
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
app/Http/Requests/DeleteAccountFormRequest.php
Normal file
33
app/Http/Requests/DeleteAccountFormRequest.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use Auth;
|
||||
|
||||
/**
|
||||
* Class DeleteAccountFormRequest
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class DeleteAccountFormRequest extends Request
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
// Only allow logged in users
|
||||
return Auth::check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'password' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user