mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-21 10:41:22 +00:00
Compare commits
3295 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa110279de | ||
|
|
8fdeaf73cc | ||
|
|
a7ffdf062a | ||
|
|
3bad92dd6d | ||
|
|
2e88024bca | ||
|
|
ca2301959c | ||
|
|
3285fae7f0 | ||
|
|
312079657b | ||
|
|
18c183afd6 | ||
|
|
f424d9cf20 | ||
|
|
5c3da9fd9e | ||
|
|
1f321fadd4 | ||
|
|
65f5d27b12 | ||
|
|
cdb591de7f | ||
|
|
a0ea3882e1 | ||
|
|
a9444ac702 | ||
|
|
d0c6afc3a9 | ||
|
|
e7a0a5937c | ||
|
|
08992b5298 | ||
|
|
6490a4240d | ||
|
|
43a7544dd7 | ||
|
|
0fe70dae17 | ||
|
|
7079e76886 | ||
|
|
0ec021c375 | ||
|
|
ff3396e286 | ||
|
|
78912903ce | ||
|
|
4c015e2d12 | ||
|
|
172634a55a | ||
|
|
58ca7d551a | ||
|
|
fd8ed4c9aa | ||
|
|
c03f5f5ff0 | ||
|
|
6775fc58c8 | ||
|
|
9f250fc61b | ||
|
|
94609f1419 | ||
|
|
53402aa5e2 | ||
|
|
5aadb29905 | ||
|
|
d4f8c41d80 | ||
|
|
a2e14f8b8d | ||
|
|
98c4ac955a | ||
|
|
70b63e1736 | ||
|
|
106665a468 | ||
|
|
da5e48d769 | ||
|
|
85f484e73c | ||
|
|
d287ae97f8 | ||
|
|
117bb602dc | ||
|
|
e440d55034 | ||
|
|
7f5b94fe43 | ||
|
|
c58eea6654 | ||
|
|
bbed5d0701 | ||
|
|
2775690fc8 | ||
|
|
1fd9f6e724 | ||
|
|
3d63903128 | ||
|
|
ef876a165a | ||
|
|
c4d6aaeef3 | ||
|
|
37b735c2e3 | ||
|
|
62d30c7b0e | ||
|
|
9cac7d46c0 | ||
|
|
99b3e24836 | ||
|
|
ffb699cb06 | ||
|
|
2947ec0002 | ||
|
|
5c4d010bde | ||
|
|
955306d877 | ||
|
|
015935ed55 | ||
|
|
48f4cceb19 | ||
|
|
9850220aac | ||
|
|
c4ac1460f0 | ||
|
|
b9e1e01337 | ||
|
|
76649cb7de | ||
|
|
5e310776b4 | ||
|
|
4d7fa11172 | ||
|
|
28962007c1 | ||
|
|
2111873bcf | ||
|
|
0aaf9a6fda | ||
|
|
186b704509 | ||
|
|
efe9933721 | ||
|
|
200366f5be | ||
|
|
c9bd72337d | ||
|
|
d4510440b8 | ||
|
|
5a9cf698f7 | ||
|
|
5826fec519 | ||
|
|
7035600984 | ||
|
|
b1dfb5811f | ||
|
|
51570a5d08 | ||
|
|
f065f3a0b8 | ||
|
|
47376f1f35 | ||
|
|
bcfe2c6410 | ||
|
|
09d63b584d | ||
|
|
5f5469a7d4 | ||
|
|
38800d61b0 | ||
|
|
1186e95c51 | ||
|
|
d870e0f42e | ||
|
|
0db9852769 | ||
|
|
7e3f9048fe | ||
|
|
1ba88f182b | ||
|
|
c8f5a6b7ad | ||
|
|
d26bbf3cdc | ||
|
|
0de72b6914 | ||
|
|
e41c89bd59 | ||
|
|
541d9ebdd9 | ||
|
|
1e724712e0 | ||
|
|
3682467ae3 | ||
|
|
7707c81b2d | ||
|
|
e434de72a3 | ||
|
|
ce191fa6d3 | ||
|
|
90865a5284 | ||
|
|
684f6e0b5c | ||
|
|
c287bc139c | ||
|
|
1392275b81 | ||
|
|
87c0f1d86e | ||
|
|
a4a723cfc6 | ||
|
|
921e2c06f4 | ||
|
|
cb9433f4b9 | ||
|
|
1be6af820e | ||
|
|
3b686b6d1c | ||
|
|
697566fe42 | ||
|
|
5130ba7ea4 | ||
|
|
c9e46a4dd1 | ||
|
|
f5b3dc36e3 | ||
|
|
f1e8d1cf1e | ||
|
|
e8e7ab01d2 | ||
|
|
9244994233 | ||
|
|
ae768a8525 | ||
|
|
162c762973 | ||
|
|
57b5981904 | ||
|
|
275d19e71d | ||
|
|
189b11befa | ||
|
|
a56a5fc228 | ||
|
|
cbe3fb73a8 | ||
|
|
3d58fbebec | ||
|
|
b947ff50ed | ||
|
|
18d2741814 | ||
|
|
93a54780ab | ||
|
|
3d201db6fc | ||
|
|
9ffc0936ee | ||
|
|
fbf9e00208 | ||
|
|
2c826451d1 | ||
|
|
617a5c0606 | ||
|
|
8331a7e34a | ||
|
|
8ee1676f0a | ||
|
|
5dc8620c43 | ||
|
|
d2733a4df0 | ||
|
|
ae649223d8 | ||
|
|
6267930938 | ||
|
|
bdee8cde77 | ||
|
|
e63f216905 | ||
|
|
ec18165698 | ||
|
|
307e6a2337 | ||
|
|
b80d8cf774 | ||
|
|
7a5ef6013a | ||
|
|
13b92c47d9 | ||
|
|
5a79bc0a99 | ||
|
|
beda6ec3a9 | ||
|
|
c619b8730b | ||
|
|
c14ec8b006 | ||
|
|
10c7786248 | ||
|
|
08ff08685c | ||
|
|
8091dbfdfa | ||
|
|
8dc106b79a | ||
|
|
7527433738 | ||
|
|
1502e08a7a | ||
|
|
c9679f1d4f | ||
|
|
6b976dd6b9 | ||
|
|
8da4abf655 | ||
|
|
2e26193333 | ||
|
|
ada43bc0dd | ||
|
|
a447c886c4 | ||
|
|
288e713f94 | ||
|
|
f8eb1fa44a | ||
|
|
afc794513f | ||
|
|
7e6d3c9d6b | ||
|
|
44960e8e42 | ||
|
|
41430c3bb2 | ||
|
|
2f435019e0 | ||
|
|
480e70dfac | ||
|
|
c4818334e7 | ||
|
|
a5d5f86aed | ||
|
|
78afb771b1 | ||
|
|
a74a646777 | ||
|
|
87f9ca3bb2 | ||
|
|
d54e264a91 | ||
|
|
99aea5ce7a | ||
|
|
e10d5e89e5 | ||
|
|
0105456828 | ||
|
|
5c7df5c04d | ||
|
|
563ede822f | ||
|
|
786cfc21c7 | ||
|
|
8f0856e31a | ||
|
|
bea075c74d | ||
|
|
5f82accb61 | ||
|
|
95f50ca2fd | ||
|
|
d8b76bdfd2 | ||
|
|
74a9edaaf7 | ||
|
|
7dd858be39 | ||
|
|
7d7ff71384 | ||
|
|
003177fa49 | ||
|
|
3c3a83330d | ||
|
|
724f423692 | ||
|
|
65b8882ed4 | ||
|
|
66d7fd7d4c | ||
|
|
782a6f289c | ||
|
|
70d936bb8f | ||
|
|
dda3082c7e | ||
|
|
ed948cc965 | ||
|
|
0347649f42 | ||
|
|
c66fe2b541 | ||
|
|
8c1ae76c7a | ||
|
|
04dee404c0 | ||
|
|
b22dd29835 | ||
|
|
536a5cd1c8 | ||
|
|
b7f1bcf7c9 | ||
|
|
5e590072dd | ||
|
|
d204b9b752 | ||
|
|
22d1121193 | ||
|
|
e23c6521b9 | ||
|
|
b0cb9663a6 | ||
|
|
95b7da89f0 | ||
|
|
b0a5b53abb | ||
|
|
ce78c8993f | ||
|
|
2538b4a885 | ||
|
|
109d96ad16 | ||
|
|
4cbb0d9716 | ||
|
|
65ecea3b1c | ||
|
|
495b80f5ef | ||
|
|
e113736887 | ||
|
|
042b7a4966 | ||
|
|
5ab8cb38d3 | ||
|
|
fc4ab29244 | ||
|
|
5a43e6cb9f | ||
|
|
4effc95c5f | ||
|
|
962965b5b7 | ||
|
|
260b611293 | ||
|
|
d2131c371b | ||
|
|
eedf6a07f0 | ||
|
|
5cd1e7c100 | ||
|
|
6a750a998f | ||
|
|
bd818b2dea | ||
|
|
4164ebcc69 | ||
|
|
60d732067b | ||
|
|
b7b52707fb | ||
|
|
f373c72679 | ||
|
|
ec2027b8db | ||
|
|
a84de5db77 | ||
|
|
5065b1ee03 | ||
|
|
a0aa114ee6 | ||
|
|
823839fbf6 | ||
|
|
1c93d8bf79 | ||
|
|
626404407e | ||
|
|
446ab62d38 | ||
|
|
0d39161ec3 | ||
|
|
29be16dcba | ||
|
|
b0bb790386 | ||
|
|
e64b40d58b | ||
|
|
4870945af2 | ||
|
|
a547a5f3f9 | ||
|
|
e5eabdf7e7 | ||
|
|
f78d56b149 | ||
|
|
771926c779 | ||
|
|
6090efe2df | ||
|
|
863227c55c | ||
|
|
5a6967cefd | ||
|
|
5166171e5d | ||
|
|
3e36a29c23 | ||
|
|
20e1e50032 | ||
|
|
36bc483edb | ||
|
|
aa59227786 | ||
|
|
2d8449ed68 | ||
|
|
d7ab482ae1 | ||
|
|
cfcc4ce88a | ||
|
|
eda44bbed0 | ||
|
|
988049061d | ||
|
|
ebb1c5ae25 | ||
|
|
ce7eebac5c | ||
|
|
b7c446f7db | ||
|
|
7c39a04c4b | ||
|
|
037d84b810 | ||
|
|
529bf50c85 | ||
|
|
d2b4bd78a9 | ||
|
|
e1c146a5c1 | ||
|
|
ed9acbdfde | ||
|
|
dc825d5a9c | ||
|
|
9f8faf15f1 | ||
|
|
934656c954 | ||
|
|
d233a2df3c | ||
|
|
7c7740d3ba | ||
|
|
cda6cfb4cd | ||
|
|
a90d095609 | ||
|
|
98e683329e | ||
|
|
3588bd881c | ||
|
|
0460811e6c | ||
|
|
27f5fe18df | ||
|
|
6d944ec98f | ||
|
|
adf6691470 | ||
|
|
dd8b500efd | ||
|
|
4e1ff8c4a3 | ||
|
|
e73d590ead | ||
|
|
5cc22f49cf | ||
|
|
eb3d2b1749 | ||
|
|
21a197ba46 | ||
|
|
0b74707638 | ||
|
|
16dc8b7d68 | ||
|
|
5a8abe004e | ||
|
|
b211d72c8b | ||
|
|
36f3eb8b2f | ||
|
|
cb1cb9f328 | ||
|
|
3344bb7263 | ||
|
|
5e1167b8ae | ||
|
|
b80db054e2 | ||
|
|
c66df3cb2c | ||
|
|
ac8ff4e565 | ||
|
|
bfa7ee90f4 | ||
|
|
77c9e37584 | ||
|
|
80350f8423 | ||
|
|
3c1ff4d21f | ||
|
|
55b8f03590 | ||
|
|
1fd7852309 | ||
|
|
9c5292962f | ||
|
|
c05c6e72c0 | ||
|
|
bdcd033952 | ||
|
|
4ec6bcc8c7 | ||
|
|
11ea4b6d47 | ||
|
|
e4f45b5370 | ||
|
|
9baadd3793 | ||
|
|
94a79876ce | ||
|
|
42c3d1fa68 | ||
|
|
0e3ccebd0b | ||
|
|
4af8272faa | ||
|
|
0ef3d0cf03 | ||
|
|
f266b92ef1 | ||
|
|
462c9fb3aa | ||
|
|
568186828c | ||
|
|
8bcc319b7d | ||
|
|
baff9780de | ||
|
|
d8b8f98738 | ||
|
|
b714eaac06 | ||
|
|
14b94a5bd2 | ||
|
|
ea014a6504 | ||
|
|
e28e66e8f1 | ||
|
|
b47a140c2f | ||
|
|
19d7e27fa9 | ||
|
|
2d368f226e | ||
|
|
75d81f8f18 | ||
|
|
e3437ba697 | ||
|
|
84f299c33b | ||
|
|
3d4489efe6 | ||
|
|
6aa50e3c00 | ||
|
|
b70498c337 | ||
|
|
f34aa77d1d | ||
|
|
3833a41acb | ||
|
|
b5a5a216cd | ||
|
|
d9da2a57b6 | ||
|
|
1591b61b77 | ||
|
|
66f2df9677 | ||
|
|
5199377113 | ||
|
|
da202317c0 | ||
|
|
1d2a4e707e | ||
|
|
edf9dbc6e8 | ||
|
|
dfbe6e5b6e | ||
|
|
d551333fa2 | ||
|
|
01cab599bb | ||
|
|
1c8834fffb | ||
|
|
22e6ea700f | ||
|
|
7f7d6cf893 | ||
|
|
a94d476b75 | ||
|
|
eb5e55a272 | ||
|
|
53c80aaef8 | ||
|
|
607d0115f0 | ||
|
|
b4f18dbe77 | ||
|
|
51d97cdca5 | ||
|
|
2cd593157f | ||
|
|
ec70fde557 | ||
|
|
950576d38b | ||
|
|
ce5304277d | ||
|
|
53760766a0 | ||
|
|
ed863986a7 | ||
|
|
89ff5a83b5 | ||
|
|
fe0b62b9b4 | ||
|
|
32c8ddbe1b | ||
|
|
2cfbfd8649 | ||
|
|
3f6c19dec4 | ||
|
|
93421b50f9 | ||
|
|
54e829173a | ||
|
|
4fe38bd31b | ||
|
|
fb0638e824 | ||
|
|
108794a6b6 | ||
|
|
9c16fc1380 | ||
|
|
99c219ed97 | ||
|
|
ec12238ea1 | ||
|
|
bdbd22f98b | ||
|
|
b8e1944d20 | ||
|
|
8883d185fe | ||
|
|
19e40e9976 | ||
|
|
fa85b2b5b2 | ||
|
|
5cf0131d75 | ||
|
|
3948cb8e6c | ||
|
|
f43938726a | ||
|
|
8c8bb7a930 | ||
|
|
3972882a33 | ||
|
|
0ef5eeeb55 | ||
|
|
ef48a79d0c | ||
|
|
2bb883219c | ||
|
|
23c0bb49c4 | ||
|
|
13e59105ec | ||
|
|
98c057c516 | ||
|
|
e293d69798 | ||
|
|
b097e29104 | ||
|
|
29fbd46e33 | ||
|
|
6a15afc723 | ||
|
|
c56a39a726 | ||
|
|
4b80e46d26 | ||
|
|
a6f3e61520 | ||
|
|
cce4ef19e5 | ||
|
|
1951491c04 | ||
|
|
87b72e4bcd | ||
|
|
2c6643d691 | ||
|
|
d02df46517 | ||
|
|
0c0cc417ee | ||
|
|
f0c03e8a3b | ||
|
|
345766f387 | ||
|
|
3fa659632c | ||
|
|
95b92b7d1e | ||
|
|
466e988627 | ||
|
|
dc3c967c9f | ||
|
|
1fc31b4d8f | ||
|
|
e4a4b0a4eb | ||
|
|
a9c026884d | ||
|
|
e893000ce9 | ||
|
|
32eeb3424d | ||
|
|
ab523b6102 | ||
|
|
b062222c45 | ||
|
|
2dddc843ce | ||
|
|
b74c1c8cf9 | ||
|
|
d5d4bb2c4b | ||
|
|
89ac27ad10 | ||
|
|
48b169c026 | ||
|
|
0715b7406e | ||
|
|
6e4991a34b | ||
|
|
8730af59bc | ||
|
|
bdcc2c6c9f | ||
|
|
6f0f6e86a1 | ||
|
|
3962d9da92 | ||
|
|
5ed53d5f04 | ||
|
|
ddb28b78c3 | ||
|
|
7699b6b4ea | ||
|
|
d783d05462 | ||
|
|
33bf373151 | ||
|
|
8116644526 | ||
|
|
dc4665e82a | ||
|
|
732a85e51d | ||
|
|
32190db8bb | ||
|
|
25d3a115e0 | ||
|
|
30e3ed6410 | ||
|
|
8b5a775dc5 | ||
|
|
2942c3a4be | ||
|
|
768d3bb3e8 | ||
|
|
250b2c2f53 | ||
|
|
c8440af9a5 | ||
|
|
37fe2d22b0 | ||
|
|
b0b5d90976 | ||
|
|
27b0c7f425 | ||
|
|
7c23571806 | ||
|
|
ea378c8d82 | ||
|
|
0fb45974ef | ||
|
|
6490f9c128 | ||
|
|
2d7f1af52c | ||
|
|
ac27659a59 | ||
|
|
11d59c8bd1 | ||
|
|
a6936cbd02 | ||
|
|
3be84d76ef | ||
|
|
9aed1f344f | ||
|
|
4fff264630 | ||
|
|
2e444da2a3 | ||
|
|
7a216f95ca | ||
|
|
f22a9799a1 | ||
|
|
90bdc40393 | ||
|
|
622a97c8d8 | ||
|
|
03691c81c2 | ||
|
|
885b56c465 | ||
|
|
23cc7be231 | ||
|
|
bb82b0eb79 | ||
|
|
2e05f640b8 | ||
|
|
697a02ffee | ||
|
|
ad402021ed | ||
|
|
67caf6ef1f | ||
|
|
3277858c5a | ||
|
|
3fbedf323f | ||
|
|
144a6130f2 | ||
|
|
fa38c975b6 | ||
|
|
c14fa1021c | ||
|
|
5e78cc02bd | ||
|
|
429ef80fb9 | ||
|
|
e4d93cad27 | ||
|
|
d9a4840e37 | ||
|
|
a93070b98d | ||
|
|
c05a942862 | ||
|
|
f9a7879c1e | ||
|
|
bdfbc6d6a7 | ||
|
|
21181d8d8e | ||
|
|
1c7a27b816 | ||
|
|
e953f58c74 | ||
|
|
9250cee9e7 | ||
|
|
bb075d15ff | ||
|
|
a31f16bba7 | ||
|
|
88a41c37f3 | ||
|
|
d21885ca98 | ||
|
|
d774f8e870 | ||
|
|
08b5e66628 | ||
|
|
6fdfec3967 | ||
|
|
ab4616a3ad | ||
|
|
cb34ff4c83 | ||
|
|
bdbead256c | ||
|
|
f200086d01 | ||
|
|
ef97c3b42d | ||
|
|
ed8b41e8ec | ||
|
|
aada3371b7 | ||
|
|
38a9782bdf | ||
|
|
c6ac81dcf6 | ||
|
|
2d3f3f0fde | ||
|
|
993a2c7823 | ||
|
|
87b36cf7e3 | ||
|
|
742f2c8d9f | ||
|
|
0d7ac5f1d8 | ||
|
|
3adccff611 | ||
|
|
08b8bd27f9 | ||
|
|
1059c7e2be | ||
|
|
3ebcd5f738 | ||
|
|
4627ea1dec | ||
|
|
7ed24e78d5 | ||
|
|
ae02e3fd8d | ||
|
|
cc88d5962e | ||
|
|
70c8a524cd | ||
|
|
9a8efc8a58 | ||
|
|
f0f67b87c4 | ||
|
|
1a3ec98896 | ||
|
|
efff44cba9 | ||
|
|
7227418c4c | ||
|
|
29f93a9b73 | ||
|
|
532aa2acd0 | ||
|
|
6aca410f37 | ||
|
|
f20656b516 | ||
|
|
bcd7866e10 | ||
|
|
c1b8d44209 | ||
|
|
50e947fbbe | ||
|
|
189d969ee6 | ||
|
|
201790ff8d | ||
|
|
cc26ce4143 | ||
|
|
745e0aa525 | ||
|
|
6602b1587a | ||
|
|
6698b57f52 | ||
|
|
628268d47c | ||
|
|
56a635212a | ||
|
|
7e67eb17e0 | ||
|
|
935d72d672 | ||
|
|
fccb510186 | ||
|
|
e7ea0dc842 | ||
|
|
a40d6b0649 | ||
|
|
b7429a358f | ||
|
|
cf8b4e2f76 | ||
|
|
48c865e57a | ||
|
|
059764cd23 | ||
|
|
c205eee6fd | ||
|
|
7b22099608 | ||
|
|
b56b42d6fb | ||
|
|
ef6ef57e67 | ||
|
|
47d3cf1d45 | ||
|
|
9cfac9a884 | ||
|
|
dc172476e1 | ||
|
|
6fc7763380 | ||
|
|
ce45f21dba | ||
|
|
2de713c946 | ||
|
|
3d1dfe20b3 | ||
|
|
0404735ccb | ||
|
|
83f200f5a2 | ||
|
|
a29eb9b993 | ||
|
|
c939be97fb | ||
|
|
f31e62a532 | ||
|
|
34c195159e | ||
|
|
322fef2db1 | ||
|
|
7aa2565e89 | ||
|
|
8f3572f2d3 | ||
|
|
fb165ef28b | ||
|
|
a26acf4a25 | ||
|
|
645400e17f | ||
|
|
ccad52b80f | ||
|
|
f6303deaa4 | ||
|
|
d3a3083b85 | ||
|
|
99452056ec | ||
|
|
fca21bab4d | ||
|
|
9c58b77f01 | ||
|
|
b5c5f67fcc | ||
|
|
0f17423465 | ||
|
|
f093e29bd1 | ||
|
|
fe9b8e834d | ||
|
|
64f273120e | ||
|
|
31c1dd466b | ||
|
|
99b369bf45 | ||
|
|
e2a1535c44 | ||
|
|
3dfa88020e | ||
|
|
a220094941 | ||
|
|
ababdacf89 | ||
|
|
114dd5fc2a | ||
|
|
c058629172 | ||
|
|
79d7f577e4 | ||
|
|
631bafc6ab | ||
|
|
be58da539e | ||
|
|
a508ac9dda | ||
|
|
538fd2cef0 | ||
|
|
42557446a1 | ||
|
|
b9586481fc | ||
|
|
a0434e3271 | ||
|
|
15a5bcc21a | ||
|
|
edb838045b | ||
|
|
41a2e657b1 | ||
|
|
18b80a69c2 | ||
|
|
ce80fb39e8 | ||
|
|
2f19ff314b | ||
|
|
a0fd4b505a | ||
|
|
919aa70251 | ||
|
|
1aea4045a3 | ||
|
|
4cded0bf57 | ||
|
|
cd0585c7c4 | ||
|
|
8281279452 | ||
|
|
8f1bf846fe | ||
|
|
c26bf557d0 | ||
|
|
499b92cdd1 | ||
|
|
3dce5e162f | ||
|
|
f9de65c035 | ||
|
|
6f95e9a3cb | ||
|
|
ce09da084c | ||
|
|
5d50f92dd3 | ||
|
|
d054e085d6 | ||
|
|
59cdfa6fe6 | ||
|
|
ee0e9011b2 | ||
|
|
654ebe0c48 | ||
|
|
a40859c0bb | ||
|
|
74e3f6dee5 | ||
|
|
e553bfb204 | ||
|
|
96caace068 | ||
|
|
5310ccebbe | ||
|
|
ccd55257cd | ||
|
|
583687f3a7 | ||
|
|
e06dc86bf7 | ||
|
|
8828aa0621 | ||
|
|
e472e105f2 | ||
|
|
6ad10f1772 | ||
|
|
fcf7d98834 | ||
|
|
90ad06c65c | ||
|
|
888e9beb4c | ||
|
|
69b338ca85 | ||
|
|
0c009445d4 | ||
|
|
c5fb734e42 | ||
|
|
d2c8475504 | ||
|
|
f38d99653f | ||
|
|
cdce43d226 | ||
|
|
89ab0a7e97 | ||
|
|
c7250bfcba | ||
|
|
4a9b693da8 | ||
|
|
fff35aa820 | ||
|
|
a9a542d68f | ||
|
|
35ff3f0cbf | ||
|
|
abf92b6df3 | ||
|
|
8517fc9f24 | ||
|
|
21b473108f | ||
|
|
d4367f73a2 | ||
|
|
7ff46c3cd6 | ||
|
|
4a88e241b5 | ||
|
|
8da0317b19 | ||
|
|
297c2e244d | ||
|
|
a51d752a35 | ||
|
|
7800b0a7f5 | ||
|
|
5ce4104644 | ||
|
|
b4f1bbf793 | ||
|
|
ca33bea6b7 | ||
|
|
42d20ff693 | ||
|
|
22a14416ad | ||
|
|
98bd9bdaa0 | ||
|
|
13bac92a24 | ||
|
|
d9eb14d6e5 | ||
|
|
6ec0471e8b | ||
|
|
8008311d9c | ||
|
|
fcf16051a2 | ||
|
|
3a236456cd | ||
|
|
2606d77c62 | ||
|
|
3d2f33c120 | ||
|
|
4f14969464 | ||
|
|
7234f011ec | ||
|
|
5b949d6e00 | ||
|
|
2fd476ada8 | ||
|
|
2e7703bc97 | ||
|
|
9b69a6addd | ||
|
|
500243b0b3 | ||
|
|
3ef84dc1fc | ||
|
|
b04d68d087 | ||
|
|
715c381eb2 | ||
|
|
ca32ae4561 | ||
|
|
6b277c5e67 | ||
|
|
1ac64fd0b3 | ||
|
|
f2c1dd41d0 | ||
|
|
869360f26c | ||
|
|
dbdc334931 | ||
|
|
b317d1a171 | ||
|
|
b00c7b0ce3 | ||
|
|
a61eafeac2 | ||
|
|
5978b1c421 | ||
|
|
9f16799453 | ||
|
|
74fe0ee4e4 | ||
|
|
e8880232b3 | ||
|
|
556e9f1df7 | ||
|
|
beb301e781 | ||
|
|
056c809754 | ||
|
|
fa47eac9ff | ||
|
|
bf4a7846dd | ||
|
|
b0cc6dd714 | ||
|
|
d6e2d8e4a2 | ||
|
|
bbfc962727 | ||
|
|
8ddb357e5a | ||
|
|
560c10898f | ||
|
|
04f5214bb7 | ||
|
|
4c35d52234 | ||
|
|
01be5e3e23 | ||
|
|
46dc4102e0 | ||
|
|
cf31049c51 | ||
|
|
c624c4342f | ||
|
|
701d7baca8 | ||
|
|
8e45959483 | ||
|
|
6858d67897 | ||
|
|
9b23cbd2c2 | ||
|
|
ec1bb300e2 | ||
|
|
69a8cad47b | ||
|
|
bcaca0eca3 | ||
|
|
a1f79e58db | ||
|
|
2cc5fdcf62 | ||
|
|
dd1b4e21f5 | ||
|
|
91eb052c22 | ||
|
|
ecefcfabc0 | ||
|
|
8e42e71528 | ||
|
|
a2275ae111 | ||
|
|
3976803d8f | ||
|
|
7921fc74fd | ||
|
|
1732acfee2 | ||
|
|
3a4fc65712 | ||
|
|
9ce9caba02 | ||
|
|
07f4995c8f | ||
|
|
8200c7248a | ||
|
|
bd9f1d5398 | ||
|
|
ce0ca23d79 | ||
|
|
35863c8d3a | ||
|
|
dad73ce9df | ||
|
|
f716692591 | ||
|
|
6387114a18 | ||
|
|
55ab39ca55 | ||
|
|
28a4f724d5 | ||
|
|
f2d06bcea1 | ||
|
|
4d1771614a | ||
|
|
61efabb3b5 | ||
|
|
b00458c2b9 | ||
|
|
594f9822c7 | ||
|
|
9b3131b95e | ||
|
|
d7ad32a8cc | ||
|
|
59127e4029 | ||
|
|
7edf70a77b | ||
|
|
3fd90a37fb | ||
|
|
356ec276bc | ||
|
|
ad8d945c1d | ||
|
|
a3bf30a77b | ||
|
|
3f829a3114 | ||
|
|
537b4ae003 | ||
|
|
08b4c9ea5c | ||
|
|
6b00f5a97d | ||
|
|
d259df9a47 | ||
|
|
aeaebd082f | ||
|
|
0c9c0f2032 | ||
|
|
155801ab2b | ||
|
|
deeeb06488 | ||
|
|
28fd719ce3 | ||
|
|
317075aa6d | ||
|
|
eaf2efc510 | ||
|
|
88555bbea2 | ||
|
|
a4d7bf4ebe | ||
|
|
50e5c21735 | ||
|
|
2ddacf48d4 | ||
|
|
cd66d2c7b0 | ||
|
|
2e7c26c539 | ||
|
|
f0f47530bf | ||
|
|
e7be4e3e49 | ||
|
|
7a7ce7fcea | ||
|
|
bd104a7ea8 | ||
|
|
31d6789ff0 | ||
|
|
bdcb7372a5 | ||
|
|
b8df2226ae | ||
|
|
106bae5c97 | ||
|
|
651297fa0b | ||
|
|
1b2873fc5f | ||
|
|
f82a2b3bc5 | ||
|
|
4cb616ebeb | ||
|
|
1bcc975d7b | ||
|
|
98fd5b8858 | ||
|
|
6f08482aaf | ||
|
|
f7d06b9759 | ||
|
|
a178fed0c6 | ||
|
|
ff342f6789 | ||
|
|
b1c2f8faa1 | ||
|
|
6f59e79b28 | ||
|
|
6c22bad77a | ||
|
|
1cf0125d1b | ||
|
|
49211482b0 | ||
|
|
b3aecec11d | ||
|
|
7cb86d0254 | ||
|
|
0ba9389ca2 | ||
|
|
1902787104 | ||
|
|
b3e32db073 | ||
|
|
01d53bdb85 | ||
|
|
51acc34a80 | ||
|
|
694447e66c | ||
|
|
05b7a610ef | ||
|
|
1e799402ee | ||
|
|
5f9c61c4b4 | ||
|
|
12b6791e8b | ||
|
|
8024ad123e | ||
|
|
2bd2f5a5aa | ||
|
|
37d79b2a1c | ||
|
|
cd057045e6 | ||
|
|
ddfbd69e8b | ||
|
|
28fa1264b7 | ||
|
|
a6c3189833 | ||
|
|
0d2fe08dc9 | ||
|
|
8cfe25bfac | ||
|
|
f9e2a677d9 | ||
|
|
2ef1c54417 | ||
|
|
f9c3c0c8ae | ||
|
|
44a15551ba | ||
|
|
732e181312 | ||
|
|
919187f7fd | ||
|
|
7840a5ea49 | ||
|
|
3a33ac1455 | ||
|
|
2eb7d8ba91 | ||
|
|
7ec5cce2c8 | ||
|
|
8fdc6c11e1 | ||
|
|
1a110de597 | ||
|
|
317aa591c3 | ||
|
|
0d44f82c86 | ||
|
|
9cac61dc33 | ||
|
|
52481a6e8b | ||
|
|
b3e18f4e56 | ||
|
|
aa25ac774e | ||
|
|
af7da586aa | ||
|
|
b671da900a | ||
|
|
d8bb83e8c4 | ||
|
|
bc3d64a2ff | ||
|
|
70e72c246d | ||
|
|
7c8c82edd7 | ||
|
|
5dc556f0af | ||
|
|
c8c69f1a66 | ||
|
|
985019e117 | ||
|
|
b9620b3a21 | ||
|
|
e7bb4a8ec6 | ||
|
|
bb5f935d7a | ||
|
|
17dad27610 | ||
|
|
ee960d76c7 | ||
|
|
dfb595193a | ||
|
|
0a91a40c1b | ||
|
|
12f4305691 | ||
|
|
dd865b0dfb | ||
|
|
7cbfa9fcd4 | ||
|
|
28d880a7c4 | ||
|
|
e83d45fce5 | ||
|
|
693ff3cc66 | ||
|
|
706b095f95 | ||
|
|
8e2e96d513 | ||
|
|
28bce44f69 | ||
|
|
53d88dfd50 | ||
|
|
42daf7ed32 | ||
|
|
e5402ea7c1 | ||
|
|
05e8d6b578 | ||
|
|
505f340917 | ||
|
|
46856c9394 | ||
|
|
c63a2ad39d | ||
|
|
68a7078614 | ||
|
|
2e15f1e2a3 | ||
|
|
a790838222 | ||
|
|
cd14360d62 | ||
|
|
74c94a60a6 | ||
|
|
56cbc7683e | ||
|
|
bf778d2fca | ||
|
|
6e5bca8306 | ||
|
|
7e8fea6ed3 | ||
|
|
43ff3e11ed | ||
|
|
f1750e3c35 | ||
|
|
8b1fe26c84 | ||
|
|
6ab09a3603 | ||
|
|
df45298c1f | ||
|
|
4a64dce737 | ||
|
|
27ad428b5e | ||
|
|
2da33bae43 | ||
|
|
3dab683a45 | ||
|
|
d08fa37ccf | ||
|
|
4cd7976f63 | ||
|
|
569e8b6180 | ||
|
|
9a443bd08e | ||
|
|
efb37ae709 | ||
|
|
4658ef9918 | ||
|
|
2b6a1c9cb1 | ||
|
|
c4606b1854 | ||
|
|
d47b946d00 | ||
|
|
a886e8087d | ||
|
|
d473455680 | ||
|
|
40245ef43b | ||
|
|
aa057d6a57 | ||
|
|
5c03e64f46 | ||
|
|
1d4d156749 | ||
|
|
4fc6da1fa1 | ||
|
|
9fac48fcea | ||
|
|
ff4fdd3740 | ||
|
|
da1cce035a | ||
|
|
49292bbb2d | ||
|
|
3e502db772 | ||
|
|
426351bb54 | ||
|
|
4d6e244100 | ||
|
|
71253b23d5 | ||
|
|
076ff7c7ba | ||
|
|
94b6c7975a | ||
|
|
0b08010221 | ||
|
|
bc67113d77 | ||
|
|
5974bdcc2a | ||
|
|
f9696287a4 | ||
|
|
807dede90a | ||
|
|
1f2b37b70e | ||
|
|
7288ba0fd7 | ||
|
|
f48c17cf88 | ||
|
|
fba9cc3739 | ||
|
|
e04388a230 | ||
|
|
fbe3be169d | ||
|
|
4e4ae0fca0 | ||
|
|
2f278c8618 | ||
|
|
905ae3437b | ||
|
|
7679721007 | ||
|
|
9f29a2e04f | ||
|
|
ff5bf0c6e5 | ||
|
|
0eb8c2b7ba | ||
|
|
deb140e3bc | ||
|
|
9a1710eb27 | ||
|
|
e478238d77 | ||
|
|
c9c9410908 | ||
|
|
42372cabd5 | ||
|
|
ab9c991530 | ||
|
|
9429d84cf8 | ||
|
|
b22774a599 | ||
|
|
ca3b0a2ab1 | ||
|
|
62f76d08ad | ||
|
|
92bff24d43 | ||
|
|
eddd3e508f | ||
|
|
649eb65bb1 | ||
|
|
8fb3348a7c | ||
|
|
6c2df1a783 | ||
|
|
55afc98108 | ||
|
|
b875eb31d2 | ||
|
|
060b031272 | ||
|
|
95c4c4a238 | ||
|
|
4424e48926 | ||
|
|
b8c7876454 | ||
|
|
8256f60340 | ||
|
|
1d0cb45e4c | ||
|
|
d1a184e3f2 | ||
|
|
aa38b31015 | ||
|
|
466067bd95 | ||
|
|
c9b56efaaa | ||
|
|
e56920edee | ||
|
|
0e0c475c83 | ||
|
|
241190c4da | ||
|
|
69d0c31ae5 | ||
|
|
c3993fd943 | ||
|
|
8a3b7d7c1a | ||
|
|
87f14617cc | ||
|
|
9f24f765ea | ||
|
|
48c802e5cc | ||
|
|
388d141d82 | ||
|
|
7fa93e97db | ||
|
|
030d241130 | ||
|
|
bac392d331 | ||
|
|
1542d5e386 | ||
|
|
f1b6b3386a | ||
|
|
7d05999ced | ||
|
|
d477feb930 | ||
|
|
9465a6d2b5 | ||
|
|
c3f78b698d | ||
|
|
a4e699f781 | ||
|
|
cd871e5aad | ||
|
|
c9b215684c | ||
|
|
82a4c706b0 | ||
|
|
082e6f5e99 | ||
|
|
b90c7c09b6 | ||
|
|
1ee72a6ce5 | ||
|
|
f72a8c5c06 | ||
|
|
ba5db2c15f | ||
|
|
f5b89ca783 | ||
|
|
4ef840e210 | ||
|
|
e2d0ee125f | ||
|
|
8e1dbc03d9 | ||
|
|
9c0893fa8c | ||
|
|
0dfb97c5f7 | ||
|
|
cb52af28e7 | ||
|
|
4b4384b1a8 | ||
|
|
62483e748b | ||
|
|
9b10984d81 | ||
|
|
c5e283a13e | ||
|
|
df918e8529 | ||
|
|
aa1193a9eb | ||
|
|
8f7f263a48 | ||
|
|
0bad227548 | ||
|
|
78bcd3e1bb | ||
|
|
554640c345 | ||
|
|
baecc256f6 | ||
|
|
10a2a4cf5b | ||
|
|
c5dc073d49 | ||
|
|
d48e4c66b2 | ||
|
|
d357142075 | ||
|
|
af17381e04 | ||
|
|
2e7d339d7e | ||
|
|
c6cddad13c | ||
|
|
54bd54b521 | ||
|
|
8cbbb970e1 | ||
|
|
fbbf7f75c3 | ||
|
|
5a23b95352 | ||
|
|
6f9675b6d6 | ||
|
|
bb8ce30552 | ||
|
|
581e2ad431 | ||
|
|
45deb493ba | ||
|
|
4531d0ee32 | ||
|
|
a26e8a5f83 | ||
|
|
be74fbd677 | ||
|
|
ee8c83bbd8 | ||
|
|
dbd32abdd1 | ||
|
|
f300287814 | ||
|
|
dd361bb9ad | ||
|
|
744205cb6e | ||
|
|
86c22c9fdd | ||
|
|
d7a66f6782 | ||
|
|
902f310eb0 | ||
|
|
3bb107e192 | ||
|
|
78f8b1454d | ||
|
|
70ba9a4db5 | ||
|
|
93d9c44585 | ||
|
|
f0bb462f1c | ||
|
|
151e8e8f17 | ||
|
|
23f474b003 | ||
|
|
15104de84c | ||
|
|
55e4875662 | ||
|
|
5c3165efa2 | ||
|
|
3690a53dc9 | ||
|
|
fb119cc208 | ||
|
|
7343304284 | ||
|
|
c1ecc62ac1 | ||
|
|
bd40615f8e | ||
|
|
0df8d096f0 | ||
|
|
749dd1e8e3 | ||
|
|
ade6558769 | ||
|
|
6303b172b1 | ||
|
|
636ae193a7 | ||
|
|
aff8493204 | ||
|
|
8f2d4494d5 | ||
|
|
7a2bb4eb96 | ||
|
|
4916c06797 | ||
|
|
a818ab0942 | ||
|
|
9aa89393c0 | ||
|
|
216b304fe1 | ||
|
|
cf8a687b4d | ||
|
|
d1d6ba4114 | ||
|
|
a5ac713310 | ||
|
|
6fa8c33672 | ||
|
|
dd2b019d3c | ||
|
|
3a12ad192f | ||
|
|
d669b75352 | ||
|
|
746d50d459 | ||
|
|
f741552d91 | ||
|
|
c38e4b86b4 | ||
|
|
b044d85e90 | ||
|
|
24d111f026 | ||
|
|
f50058e3c2 | ||
|
|
ce9445168c | ||
|
|
27b8b4b35a | ||
|
|
9ccb67db8a | ||
|
|
3d82afd4e6 | ||
|
|
5f9cb61160 | ||
|
|
7f54b70c24 | ||
|
|
a156dce281 | ||
|
|
c0b0e58720 | ||
|
|
170ffbae04 | ||
|
|
6755ec7eb0 | ||
|
|
c8bc9a096a | ||
|
|
dc7f5a562b | ||
|
|
3b5b51578d | ||
|
|
41188a1bd6 | ||
|
|
d9bafe34eb | ||
|
|
43dbba5378 | ||
|
|
168ed5ac56 | ||
|
|
e5b4a55d8e | ||
|
|
167c057e8a | ||
|
|
71bf054ab1 | ||
|
|
111fcd77c4 | ||
|
|
287c1c4ffa | ||
|
|
3d69dc786d | ||
|
|
57a3f20c13 | ||
|
|
eab2c57594 | ||
|
|
b019962f34 | ||
|
|
5c59c819b6 | ||
|
|
93b97b8d72 | ||
|
|
f1f922031a | ||
|
|
390cace775 | ||
|
|
28fdad9426 | ||
|
|
9155c13e08 | ||
|
|
e8776d44c5 | ||
|
|
5ee8d04800 | ||
|
|
eb31934fb7 | ||
|
|
000f86d318 | ||
|
|
d9b3ebc82f | ||
|
|
91b3ca047a | ||
|
|
08131e42af | ||
|
|
a013553a6c | ||
|
|
7b2fe8eb4a | ||
|
|
610f782054 | ||
|
|
94700f4064 | ||
|
|
0f12ebb31c | ||
|
|
00a8a9ac0e | ||
|
|
92616c6ae3 | ||
|
|
97db618cd8 | ||
|
|
2832d308f1 | ||
|
|
a7ecdf715f | ||
|
|
935dc3ff9f | ||
|
|
99d14e8cbe | ||
|
|
664fde2344 | ||
|
|
27c45eface | ||
|
|
f83bc3c8b3 | ||
|
|
0d5efb8d27 | ||
|
|
bf9c1c1875 | ||
|
|
049d866f62 | ||
|
|
d672f0c2ad | ||
|
|
7b040e8583 | ||
|
|
e1cf285272 | ||
|
|
53f7f13362 | ||
|
|
f710677cdc | ||
|
|
b5fbc8b632 | ||
|
|
1fdc0a196c | ||
|
|
559f429f5e | ||
|
|
ae4b198d3d | ||
|
|
e088ecbbad | ||
|
|
f6b7bd5b44 | ||
|
|
f5a21f64c0 | ||
|
|
f5cbed7c0c | ||
|
|
59fff8928b | ||
|
|
8743b49a17 | ||
|
|
19dc91937e | ||
|
|
4846cb7b14 | ||
|
|
54e0ac816b | ||
|
|
9ce960b3d7 | ||
|
|
cc9d1c4bfd | ||
|
|
d211555beb | ||
|
|
9350557d10 | ||
|
|
ea6c54cad0 | ||
|
|
81287602d7 | ||
|
|
441ba79ec7 | ||
|
|
c9e4a09da6 | ||
|
|
c84f4e2bc0 | ||
|
|
6938f8ab89 | ||
|
|
4fdd2c851f | ||
|
|
78b56712fc | ||
|
|
6dcdb0f9a0 | ||
|
|
cfab837b96 | ||
|
|
b8461cdeb6 | ||
|
|
e07d65ef6b | ||
|
|
80cbc35c89 | ||
|
|
2faf84780f | ||
|
|
ebdb1a8836 | ||
|
|
2dfa51652a | ||
|
|
1cf1ea230f | ||
|
|
86e127ebff | ||
|
|
a313265785 | ||
|
|
37693ad08d | ||
|
|
e8180d252b | ||
|
|
9957c95c68 | ||
|
|
3354d53a48 | ||
|
|
ddaa53b940 | ||
|
|
c2e04a11bf | ||
|
|
00d059b8df | ||
|
|
f3fff6f1c5 | ||
|
|
9360eb6a70 | ||
|
|
26fb03e6c8 | ||
|
|
eed3d021d9 | ||
|
|
48728e8418 | ||
|
|
f39f25760a | ||
|
|
10ea60daaf | ||
|
|
f2fa5e140b | ||
|
|
be5ff35b13 | ||
|
|
bd5d73d1e6 | ||
|
|
cc712b0c75 | ||
|
|
a5ac84e1b9 | ||
|
|
cbe1f762ca | ||
|
|
e6db49c20c | ||
|
|
4909fcc8b4 | ||
|
|
68cdfd00b0 | ||
|
|
323c16ebe1 | ||
|
|
c20a38b7b0 | ||
|
|
20993342a2 | ||
|
|
1b3198c143 | ||
|
|
173d0290ea | ||
|
|
ae4cd8da12 | ||
|
|
a494398332 | ||
|
|
c82bdd1f5a | ||
|
|
e6ac3ccfad | ||
|
|
b13b58a2b2 | ||
|
|
2b6790f83f | ||
|
|
fe30850568 | ||
|
|
493c71b89e | ||
|
|
deaebc373c | ||
|
|
e834489206 | ||
|
|
1b316e462e | ||
|
|
7bf75128a8 | ||
|
|
3857e8d49f | ||
|
|
b16149b842 | ||
|
|
32ed8a4d8d | ||
|
|
f949d2476b | ||
|
|
0620830b10 | ||
|
|
7ee25693aa | ||
|
|
7cb86add64 | ||
|
|
fbc9720f7a | ||
|
|
ffdd37ddd5 | ||
|
|
51062bc80b | ||
|
|
31533b5ef8 | ||
|
|
3649b595df | ||
|
|
83b7c9aa32 | ||
|
|
4e3c59a2da | ||
|
|
dcbfe90cf7 | ||
|
|
f69be86c74 | ||
|
|
820722f44e | ||
|
|
2ff806dedc | ||
|
|
a755badd5f | ||
|
|
4df1e5393b | ||
|
|
8c55bd179f | ||
|
|
ccfc5ece66 | ||
|
|
6c12f1bc86 | ||
|
|
88839e9610 | ||
|
|
4f6a733238 | ||
|
|
dc9083a764 | ||
|
|
6f231b840b | ||
|
|
61a703e605 | ||
|
|
8e0e9734a5 | ||
|
|
2afb455bac | ||
|
|
01792f91e2 | ||
|
|
651dff0750 | ||
|
|
9cbfbd41dc | ||
|
|
168d6f403c | ||
|
|
41f200e630 | ||
|
|
0809cfdc6d | ||
|
|
466d739da8 | ||
|
|
daf65cb387 | ||
|
|
2605f60983 | ||
|
|
fcf6cdb134 | ||
|
|
209258b507 | ||
|
|
f80bc214f9 | ||
|
|
f76990bb9b | ||
|
|
eef68c9b31 | ||
|
|
006c2ae186 | ||
|
|
8b66ff6afe | ||
|
|
4cc6d57e6e | ||
|
|
af1c6b22bb | ||
|
|
5958990ed5 | ||
|
|
cd4cbdc197 | ||
|
|
1f538be16e | ||
|
|
9703439a4c | ||
|
|
42203ba872 | ||
|
|
cd60b852a1 | ||
|
|
5b1d9e1a0d | ||
|
|
e02657a7c7 | ||
|
|
c352eb0c74 | ||
|
|
81b9d5da09 | ||
|
|
b9b0413510 | ||
|
|
97770da619 | ||
|
|
521623797e | ||
|
|
15d3414443 | ||
|
|
245f06c93a | ||
|
|
33899f0e2f | ||
|
|
4697fbdeef | ||
|
|
06174d6afb | ||
|
|
b2bb16c1e0 | ||
|
|
27aae279e6 | ||
|
|
e9ee93beb7 | ||
|
|
20941dedd3 | ||
|
|
5ac88623ed | ||
|
|
768508dd4b | ||
|
|
668633e764 | ||
|
|
3dbb1f034d | ||
|
|
1270e5d15c | ||
|
|
afec8480fb | ||
|
|
8720511046 | ||
|
|
a7a00ecf40 | ||
|
|
88bbafd3e8 | ||
|
|
ae3258b449 | ||
|
|
cf4d7cfeef | ||
|
|
46ee2a0568 | ||
|
|
ce250c85fc | ||
|
|
1087b9f5df | ||
|
|
0dc74d9d14 | ||
|
|
98b272383f | ||
|
|
e722daafd0 | ||
|
|
670ab059d1 | ||
|
|
09f826ceba | ||
|
|
df5e3c9be9 | ||
|
|
31c336b3b1 | ||
|
|
b3a419b2f3 | ||
|
|
11f63fa6ce | ||
|
|
4b35059140 | ||
|
|
7836feba63 | ||
|
|
1e54366f1f | ||
|
|
d039bb0e03 | ||
|
|
166d32f073 | ||
|
|
321890992e | ||
|
|
d644403d8a | ||
|
|
44e76f9518 | ||
|
|
f9703eca4c | ||
|
|
48551e8bf5 | ||
|
|
74b538805b | ||
|
|
35f493beff | ||
|
|
06d11c9133 | ||
|
|
da7eb615db | ||
|
|
5da5024ad3 | ||
|
|
c1346d4c86 | ||
|
|
c38a4a15ff | ||
|
|
bdec94ead6 | ||
|
|
69bebf202f | ||
|
|
38895afea6 | ||
|
|
70ed4188b6 | ||
|
|
d889094863 | ||
|
|
c96eb8753e | ||
|
|
5a7607f6c6 | ||
|
|
71bb88529a | ||
|
|
b26164a168 | ||
|
|
19444551e4 | ||
|
|
e0b2a6e627 | ||
|
|
2973765866 | ||
|
|
2a08a25064 | ||
|
|
a55e291908 | ||
|
|
2003d37a9a | ||
|
|
29145bf6cf | ||
|
|
caa1ff120a | ||
|
|
ef4e964c94 | ||
|
|
1f263f60a7 | ||
|
|
5fc7cafcbe | ||
|
|
397c4926eb | ||
|
|
a14544398b | ||
|
|
d439dceac1 | ||
|
|
af29b31ea8 | ||
|
|
b311ef70bc | ||
|
|
9f9d744406 | ||
|
|
e094871bc9 | ||
|
|
dfc95cee45 | ||
|
|
fdca234721 | ||
|
|
cf5cc626d7 | ||
|
|
358d9aac7d | ||
|
|
681bc580c4 | ||
|
|
4a2768f8d1 | ||
|
|
05f8773fa0 | ||
|
|
5e5fdfdd51 | ||
|
|
5e744390c0 | ||
|
|
cb5fa401cb | ||
|
|
2980860377 | ||
|
|
9ff0b282f3 | ||
|
|
4bc1c032bd | ||
|
|
9fcb00f10b | ||
|
|
723e461559 | ||
|
|
9b24e6d448 | ||
|
|
e622774775 | ||
|
|
84ce9bc94b | ||
|
|
a3a1bc30b1 | ||
|
|
b4c9a7698e | ||
|
|
8b2d7fc32f | ||
|
|
90e66cbd94 | ||
|
|
fd9a7080ea | ||
|
|
c0fad106f0 | ||
|
|
78c8243184 | ||
|
|
780abecd53 | ||
|
|
ea6896816d | ||
|
|
95a456860a | ||
|
|
b1b2fda155 | ||
|
|
5847f534c3 | ||
|
|
e8e8163fa7 | ||
|
|
6a21d82dcf | ||
|
|
d6b47656bc | ||
|
|
8c37ef3a95 | ||
|
|
35deed1d10 | ||
|
|
ba32a665f1 | ||
|
|
bbd19be554 | ||
|
|
c360cc6db6 | ||
|
|
7e4b9af315 | ||
|
|
9b03e6b124 | ||
|
|
013e16e15f | ||
|
|
180ec52798 | ||
|
|
c7b47b4453 | ||
|
|
4b00db7662 | ||
|
|
78a7b995d2 | ||
|
|
f7c50a123a | ||
|
|
9617d17aca | ||
|
|
d9884ddf73 | ||
|
|
8157f0a958 | ||
|
|
b7580a5f83 | ||
|
|
66703b30b3 | ||
|
|
53677e3c64 | ||
|
|
feef6a1756 | ||
|
|
5f299b895b | ||
|
|
4e1bb5fbac | ||
|
|
47ccc513ad | ||
|
|
cce1a01936 | ||
|
|
6f2b1a6a76 | ||
|
|
8526907f50 | ||
|
|
bc192a8e54 | ||
|
|
9ff6f8fc52 | ||
|
|
6573bd6b4b | ||
|
|
9dc3f614af | ||
|
|
3888b8cceb | ||
|
|
294df4a2b3 | ||
|
|
265dd37212 | ||
|
|
eb7c79ad27 | ||
|
|
de111c7100 | ||
|
|
e892c9a824 | ||
|
|
5eb0e18cae | ||
|
|
27cabb398e | ||
|
|
64dbb14241 | ||
|
|
bb4e2be9eb | ||
|
|
7d1de0da17 | ||
|
|
bf16c9a42b | ||
|
|
1a7b1ce499 | ||
|
|
efc9bc71a7 | ||
|
|
fc5b315af0 | ||
|
|
7a4a78628d | ||
|
|
d16fb30a62 | ||
|
|
2d177e660e | ||
|
|
2f131dc170 | ||
|
|
94810e371a | ||
|
|
59731878f6 | ||
|
|
54ede8aa18 | ||
|
|
b415b6b043 | ||
|
|
70c922cdc5 | ||
|
|
068fc32cb2 | ||
|
|
3dcdacc3b8 | ||
|
|
a6594358d8 | ||
|
|
f98921da46 | ||
|
|
25747fbcf2 | ||
|
|
aac5c2b13c | ||
|
|
cc810a5b6f | ||
|
|
1b3592d959 | ||
|
|
d75614e9a7 | ||
|
|
08703e282f | ||
|
|
2904baf44e | ||
|
|
f99e46bf75 | ||
|
|
9f87890ead | ||
|
|
638184cf66 | ||
|
|
03babfe75c | ||
|
|
238ed3c788 | ||
|
|
6a9d931ba3 | ||
|
|
a3d2a9e00b | ||
|
|
39b88e8207 | ||
|
|
449c6dfde5 | ||
|
|
7cc47ca0b1 | ||
|
|
95f4a83f41 | ||
|
|
35154dc7a3 | ||
|
|
0fd0d7d080 | ||
|
|
658265c938 | ||
|
|
38fe9e7e1c | ||
|
|
77056dcf8d | ||
|
|
026683a8e1 | ||
|
|
6ab6dd6ac3 | ||
|
|
83de3482ce | ||
|
|
919a35aed3 | ||
|
|
ad3defb071 | ||
|
|
9c929ecd1b | ||
|
|
f79c9f7cf1 | ||
|
|
8e75c345d9 | ||
|
|
44886d9aad | ||
|
|
c2d444347d | ||
|
|
5cb497596d | ||
|
|
1857469d2f | ||
|
|
ea71b4843d | ||
|
|
97727e2e3d | ||
|
|
f81e7da8bb | ||
|
|
8e827bf83b | ||
|
|
9e1fa284ca | ||
|
|
3bf800be6e | ||
|
|
635b9f9dba | ||
|
|
52a0d7cf7b | ||
|
|
a34516932b | ||
|
|
929a2a30a2 | ||
|
|
ffa88eeb08 | ||
|
|
51b45b4ed4 | ||
|
|
f263844793 | ||
|
|
18c46df9aa | ||
|
|
15846e157b | ||
|
|
bc59f2db0d | ||
|
|
cd2be8c1a4 | ||
|
|
f958115c50 | ||
|
|
e7d677bfb6 | ||
|
|
3e80ffc52b | ||
|
|
d0c7a5c076 | ||
|
|
f3f4e6b354 | ||
|
|
5a45b25614 | ||
|
|
0b5ee1edfc | ||
|
|
da3dc599f9 | ||
|
|
f013b435ab | ||
|
|
5f6975a113 | ||
|
|
c5dee29e4b | ||
|
|
633ee02f13 | ||
|
|
6b750c909a | ||
|
|
5f8b6640a9 | ||
|
|
dd42d8437c | ||
|
|
67a178591d | ||
|
|
f5e5659c1f | ||
|
|
8b0f0fb615 | ||
|
|
209116e766 | ||
|
|
79392ab656 | ||
|
|
3ca1207231 | ||
|
|
cec1b147f2 | ||
|
|
46cfcfa3e7 | ||
|
|
b833e8dfa2 | ||
|
|
77b843efd8 | ||
|
|
db72ad7c60 | ||
|
|
eadc630fcb | ||
|
|
170c1793cc | ||
|
|
9f7c6c2d0c | ||
|
|
72d054c55c | ||
|
|
524edfe7c2 | ||
|
|
c25c5623d2 | ||
|
|
4f38b77ef6 | ||
|
|
5862803434 | ||
|
|
5b3beded39 | ||
|
|
c61fb7a598 | ||
|
|
33d9148029 | ||
|
|
63969f5a33 | ||
|
|
edde18aeef | ||
|
|
657116d361 | ||
|
|
e16269daa8 | ||
|
|
c07591ff5c | ||
|
|
75a478ad54 | ||
|
|
8dae8b1a7f | ||
|
|
15fd8cf486 | ||
|
|
55333156ac | ||
|
|
8cdcba3231 | ||
|
|
8bab9e84e2 | ||
|
|
2faae83912 | ||
|
|
5a61a11a61 | ||
|
|
a6d71988f2 | ||
|
|
7069e242ae | ||
|
|
56ee830558 | ||
|
|
6dd12729e6 | ||
|
|
14a48303cb | ||
|
|
72cf6c9c0f | ||
|
|
144ee6b8ca | ||
|
|
8967d86da6 | ||
|
|
18c6edbb5d | ||
|
|
53de3c4717 | ||
|
|
ad577e4e81 | ||
|
|
44811a3e7c | ||
|
|
1ab3f05b3a | ||
|
|
5e76488ae7 | ||
|
|
32771fe7e1 | ||
|
|
9b40cc6881 | ||
|
|
2e35260bbb | ||
|
|
a067704277 | ||
|
|
de281818ac | ||
|
|
c49bfad38d | ||
|
|
c1ba591b26 | ||
|
|
719af38a61 | ||
|
|
ac61dfae6b | ||
|
|
813fb679a7 | ||
|
|
e7562781f7 | ||
|
|
56d36b7f53 | ||
|
|
53b3f7f821 | ||
|
|
08a53156bd | ||
|
|
8985cd6309 | ||
|
|
3833da7410 | ||
|
|
4210cd10db | ||
|
|
a7bd1c6892 | ||
|
|
52b0111afa | ||
|
|
7921d128e4 | ||
|
|
d7e838701a | ||
|
|
289bcb22aa | ||
|
|
3fe57b7983 | ||
|
|
32e92c2a16 | ||
|
|
1b3d208540 | ||
|
|
6a8bf0aa62 | ||
|
|
56715556ed | ||
|
|
838330b909 | ||
|
|
69553b138b | ||
|
|
36d7a02994 | ||
|
|
301528e2d2 | ||
|
|
0303b45707 | ||
|
|
ba722e8ed5 | ||
|
|
289e5a5442 | ||
|
|
fdad96e2bc | ||
|
|
af994e4dae | ||
|
|
006d68e279 | ||
|
|
29dc122ad3 | ||
|
|
cf4a8c6204 | ||
|
|
3c73fe92bf | ||
|
|
6637590797 | ||
|
|
b8bab11acd | ||
|
|
a2f600feac | ||
|
|
80dd62ef0a | ||
|
|
827b1c9cd8 | ||
|
|
2e4fcf803d | ||
|
|
d00d95fc6f | ||
|
|
3e3ab9bd25 | ||
|
|
6eecc7722d | ||
|
|
ada4aaf69a | ||
|
|
93244c1f78 | ||
|
|
be056cea6b | ||
|
|
659ca8be14 | ||
|
|
ea9af8366d | ||
|
|
80edd47d36 | ||
|
|
d7746b3649 | ||
|
|
c4c4fbc34c | ||
|
|
59f57c96e9 | ||
|
|
a2f852fecf | ||
|
|
ad114ed329 | ||
|
|
c4c3d0f07f | ||
|
|
6cf8102de5 | ||
|
|
e7e4aa2218 | ||
|
|
6d84f4b6c1 | ||
|
|
ce3e9ffd11 | ||
|
|
3ada260e0e | ||
|
|
8fdd0cb795 | ||
|
|
913e05a2e6 | ||
|
|
fa1f703ef6 | ||
|
|
4004c53e1b | ||
|
|
4838670649 | ||
|
|
a985e09282 | ||
|
|
9bd1503cb4 | ||
|
|
a2ccbf7844 | ||
|
|
61bbe8a905 | ||
|
|
59bc5d22d1 | ||
|
|
1423d5b314 | ||
|
|
152d0eb1d0 | ||
|
|
6426d1df06 | ||
|
|
9284eb3fe9 | ||
|
|
afdae8bc1e | ||
|
|
2a7085e593 | ||
|
|
2408fb3ed4 | ||
|
|
8316afb176 | ||
|
|
e59fd098a3 | ||
|
|
e044199693 | ||
|
|
8f8e29fc22 | ||
|
|
8de5384158 | ||
|
|
216c659335 | ||
|
|
041ca8a5d3 | ||
|
|
fe4f1b306d | ||
|
|
a0972d99fb | ||
|
|
e332bfef7c | ||
|
|
cba5e226d8 | ||
|
|
5aff0c4943 | ||
|
|
cb49c00f4d | ||
|
|
e26d797d57 | ||
|
|
938581527e | ||
|
|
c38ae09735 | ||
|
|
28c3cfe084 | ||
|
|
4a2823bcba | ||
|
|
18eba02026 | ||
|
|
d4690ce580 | ||
|
|
a785c450b1 | ||
|
|
7480dc4a19 | ||
|
|
ad01891a67 | ||
|
|
67fe35d564 | ||
|
|
7f19b6957a | ||
|
|
0a54caf202 | ||
|
|
4b4c1c7f8f | ||
|
|
d071f3947e | ||
|
|
b3d99cd210 | ||
|
|
90e696f82c | ||
|
|
958fcd1cfa | ||
|
|
8f57c7dcb3 | ||
|
|
77262f52a4 | ||
|
|
16bfbc8a12 | ||
|
|
1fd375b875 | ||
|
|
46131ad39d | ||
|
|
0b5c5b2ae9 | ||
|
|
55be174037 | ||
|
|
a17b7025f1 | ||
|
|
170cf7fd77 | ||
|
|
23cdb4d326 | ||
|
|
cbbe529572 | ||
|
|
0b382426e9 | ||
|
|
1cbbf9baa4 | ||
|
|
8d41ff7b79 | ||
|
|
e3b6057bf8 | ||
|
|
66a4042cad | ||
|
|
56c08d8302 | ||
|
|
d4e759754d | ||
|
|
a96e171cbf | ||
|
|
bd4a8c8397 | ||
|
|
04f71b3b43 | ||
|
|
d124de51db | ||
|
|
d87d12a0f5 | ||
|
|
f2b08346d0 | ||
|
|
d3682a6727 | ||
|
|
371bbd9508 | ||
|
|
a8a28f442f | ||
|
|
65ddd8a736 | ||
|
|
8bb27de233 | ||
|
|
37e2f097ba | ||
|
|
1966d87ce6 | ||
|
|
7b8c86e1e3 | ||
|
|
de634da513 | ||
|
|
96836e2d6c | ||
|
|
8a9d576f61 | ||
|
|
791d12fbb4 | ||
|
|
d1329be2fa | ||
|
|
3ed6561702 | ||
|
|
7a0587f433 | ||
|
|
0fe682bfe6 | ||
|
|
0f685e8789 | ||
|
|
420771c233 | ||
|
|
5e3e9271ca | ||
|
|
1e603c0833 | ||
|
|
03e1673e92 | ||
|
|
9f992f003d | ||
|
|
f50244a41f | ||
|
|
8b9607f9b5 | ||
|
|
af107ad5e8 | ||
|
|
8926d62165 | ||
|
|
45344ee347 | ||
|
|
baf9ebab15 | ||
|
|
b7dab817f2 | ||
|
|
fb2fa54480 | ||
|
|
2c966a1234 | ||
|
|
143ea69c0d | ||
|
|
8a02ead013 | ||
|
|
930d5ab941 | ||
|
|
e54a56d3a8 | ||
|
|
f5216c0d85 | ||
|
|
ebc77540b9 | ||
|
|
28d2583c10 | ||
|
|
b0988a7b00 | ||
|
|
2c4920db2d | ||
|
|
8321663815 | ||
|
|
ac0280d460 | ||
|
|
ba6f4268f0 | ||
|
|
0bd18f94ac | ||
|
|
66fb63661f | ||
|
|
d9b16beb0a | ||
|
|
6a01a9bdfd | ||
|
|
b81b34a706 | ||
|
|
3750a00b5f | ||
|
|
05ddcc169d | ||
|
|
f571a5f1bd | ||
|
|
48b786adea | ||
|
|
d691fa9b4d | ||
|
|
da50f9e419 | ||
|
|
103de5e18a | ||
|
|
dac6efd98b | ||
|
|
46aa7f81b2 | ||
|
|
0683c7cd67 | ||
|
|
50d7aa7b6a | ||
|
|
b781215d0a | ||
|
|
866bc2f3bd | ||
|
|
49d4705014 | ||
|
|
9163fcfccb | ||
|
|
7e10641461 | ||
|
|
cdc0e3cfd8 | ||
|
|
466e81d56a | ||
|
|
5953f691d1 | ||
|
|
e2790ca6c1 | ||
|
|
66dbd48b76 | ||
|
|
73cfbbd2ba | ||
|
|
38bc38bf26 | ||
|
|
e12d13c838 | ||
|
|
fcc3af6136 | ||
|
|
491298e1cb | ||
|
|
72b5895217 | ||
|
|
0a8f4017bd | ||
|
|
cb985f5897 | ||
|
|
968ec0853f | ||
|
|
0bde72d3df | ||
|
|
45293fbd42 | ||
|
|
72997065f0 | ||
|
|
a838dc163d | ||
|
|
3d15a4ca6d | ||
|
|
51c7d4fb1b | ||
|
|
fa586dba7e | ||
|
|
8ad40389f2 | ||
|
|
b3333cc2d3 | ||
|
|
3699a7ba9a | ||
|
|
204e521ba4 | ||
|
|
c9bab3e5c3 | ||
|
|
3d00e20238 | ||
|
|
c3958ed3c4 | ||
|
|
e5b88be5fa | ||
|
|
425552988a | ||
|
|
a81dd8abe5 | ||
|
|
bac8154a5b | ||
|
|
737d15fa0e | ||
|
|
5f2317af7f | ||
|
|
2bd1f783e5 | ||
|
|
d6c0c9f963 | ||
|
|
21b6ad7a41 | ||
|
|
a65d609fdc | ||
|
|
04e676b936 | ||
|
|
be8eaaffdf | ||
|
|
28c753523f | ||
|
|
7fbd0b2ffc | ||
|
|
7ffb48a87a | ||
|
|
d485270e1f | ||
|
|
5fd688b266 | ||
|
|
3716668e0c | ||
|
|
ae7fd18c34 | ||
|
|
4f59b1d32f | ||
|
|
90cb3279df | ||
|
|
cf0c7ef6b2 | ||
|
|
47c23781d9 | ||
|
|
e258c050f7 | ||
|
|
57801b2f34 | ||
|
|
710e9c9423 | ||
|
|
deefef83bd | ||
|
|
51e30aed66 | ||
|
|
8d109a3cfe | ||
|
|
3424e019b5 | ||
|
|
c6b4bceb67 | ||
|
|
afb4155015 | ||
|
|
8d99baf38a | ||
|
|
b91cb60328 | ||
|
|
c0d62237fc | ||
|
|
223ea80860 | ||
|
|
5a77bef494 | ||
|
|
80c0efe821 | ||
|
|
8044d89557 | ||
|
|
4f0ed97410 | ||
|
|
af7952f204 | ||
|
|
d8dcae856b | ||
|
|
7296796ed9 | ||
|
|
a2c2bb4948 | ||
|
|
72ebfdc20e | ||
|
|
16b95ea78a | ||
|
|
c04f08dfd8 | ||
|
|
a30793e818 | ||
|
|
e39e1eaf21 | ||
|
|
ab22d2cbaa | ||
|
|
96ddbe7227 | ||
|
|
4d09235aef | ||
|
|
136b8975e3 | ||
|
|
e21b1eca17 | ||
|
|
244b90b1d4 | ||
|
|
b318f3f940 | ||
|
|
e211c9812e | ||
|
|
eef28d96f4 | ||
|
|
c8227e09ee | ||
|
|
3e05fd91d9 | ||
|
|
450baba56a | ||
|
|
17a8c4918c | ||
|
|
0e2419d61a | ||
|
|
79b1a2ca6d | ||
|
|
2213c68155 | ||
|
|
2492b1fa96 | ||
|
|
6c6598dac5 | ||
|
|
a137112e66 | ||
|
|
8642ae8180 | ||
|
|
894c4dc5a7 | ||
|
|
d96063ea6e | ||
|
|
c3dc193f3e | ||
|
|
3c2952009e | ||
|
|
f4ade470df | ||
|
|
2e33b43389 | ||
|
|
92799699bc | ||
|
|
7ab0508167 | ||
|
|
3c65c28936 | ||
|
|
43892da07e | ||
|
|
7c436920a4 | ||
|
|
89d565e63b | ||
|
|
150b6fe5b6 | ||
|
|
0e77574c26 | ||
|
|
df23863443 | ||
|
|
581bf11b21 | ||
|
|
d602d4b429 | ||
|
|
d1d4a52934 | ||
|
|
375d113769 | ||
|
|
9b83974bff | ||
|
|
3c68c99bd5 | ||
|
|
ec4b37c596 | ||
|
|
ba9601d21c | ||
|
|
50c13fd469 | ||
|
|
7af072b8fc | ||
|
|
faa128d41e | ||
|
|
868fe46932 | ||
|
|
e9e4307ce5 | ||
|
|
774d4844a9 | ||
|
|
586c53e670 | ||
|
|
68e073fbff | ||
|
|
8101dc37b1 | ||
|
|
63f16c458d | ||
|
|
821e007e95 | ||
|
|
1656a2f11a | ||
|
|
4dbc135dce | ||
|
|
fc886f6bc1 | ||
|
|
f93e480466 | ||
|
|
fe807e23f8 | ||
|
|
ecf61c31f1 | ||
|
|
4feff18af5 | ||
|
|
a07c52e0d8 | ||
|
|
7bb07d7f55 | ||
|
|
f12dfc8a14 | ||
|
|
be030f15c4 | ||
|
|
f5fb6c063b | ||
|
|
fb722f06b9 | ||
|
|
c0ea19e15e | ||
|
|
cdeb1ad87c | ||
|
|
0dbe4e94fa | ||
|
|
b5e2e8aa1d | ||
|
|
9502010248 | ||
|
|
fea0557b47 | ||
|
|
ed4fcc9011 | ||
|
|
ed12ea7cfb | ||
|
|
73e526645e | ||
|
|
72aeafb2b5 | ||
|
|
cc1af60cb4 | ||
|
|
359fab315f | ||
|
|
6a9574bab9 | ||
|
|
83d6158483 | ||
|
|
63ef89b6cc | ||
|
|
b0beab4cd3 | ||
|
|
a34782575f | ||
|
|
142bdc9430 | ||
|
|
14b79cb0a4 | ||
|
|
ce5beeaf2c | ||
|
|
31114a2ca5 | ||
|
|
32528094ad | ||
|
|
0a2a01c44c | ||
|
|
c1888dc3ac | ||
|
|
4d76afbe01 | ||
|
|
76d7a97f93 | ||
|
|
8b1366b20a | ||
|
|
e0f9685578 | ||
|
|
5235657954 | ||
|
|
a15fbc8094 | ||
|
|
546f1d9c50 | ||
|
|
74231f552a | ||
|
|
b250a10e3c | ||
|
|
a9f1b31dd6 | ||
|
|
7fe393acaf | ||
|
|
04faba4db5 | ||
|
|
91bba40c20 | ||
|
|
79e39f7de8 | ||
|
|
9c09353559 | ||
|
|
50752a5bfe | ||
|
|
d59879db7d | ||
|
|
aab125da27 | ||
|
|
74fc731f96 | ||
|
|
bd0050fec2 | ||
|
|
aa5e313b92 | ||
|
|
e89d613b7e | ||
|
|
8757929ead | ||
|
|
e0a9b19802 | ||
|
|
308da6dc6e | ||
|
|
b6960fb0e5 | ||
|
|
137208c3fd | ||
|
|
d7a9a62a1d | ||
|
|
075315bdaa | ||
|
|
3948fcd614 | ||
|
|
8e61e129ab | ||
|
|
20cffd0502 | ||
|
|
5df09dab09 | ||
|
|
7446b911e5 | ||
|
|
f15267c1ab | ||
|
|
9c9fc2b5dc | ||
|
|
28f601b54b | ||
|
|
18b8a05014 | ||
|
|
910c995ed8 | ||
|
|
498468aa2c | ||
|
|
637aebcb34 | ||
|
|
9afd5cb277 | ||
|
|
bc525e7272 | ||
|
|
a80180780d | ||
|
|
0d73086c37 | ||
|
|
02ae39238d | ||
|
|
43d6b51d42 | ||
|
|
84566310de | ||
|
|
6a6ec9fbe4 | ||
|
|
84a7f825d7 | ||
|
|
0372c1aaf1 | ||
|
|
c9fff197f7 | ||
|
|
6900392e43 | ||
|
|
c00bcd78cc | ||
|
|
b2b82124e6 | ||
|
|
3de57c668f | ||
|
|
43669648ce | ||
|
|
3b73b416d5 | ||
|
|
5153591c8f | ||
|
|
3172bc90da | ||
|
|
76a1b2cd51 | ||
|
|
bdf7eee72f | ||
|
|
2d4b148b2c | ||
|
|
d67db74ca2 | ||
|
|
516725456f | ||
|
|
001d72a484 | ||
|
|
c555e28988 | ||
|
|
af13d1943f | ||
|
|
52df2edc8f | ||
|
|
cd08484a13 | ||
|
|
f38d38f139 | ||
|
|
93b6c68938 | ||
|
|
a4cc25175a | ||
|
|
3fb14b4708 | ||
|
|
6bdb6db330 | ||
|
|
d05c165ace | ||
|
|
ab53cdb896 | ||
|
|
c1f142af78 | ||
|
|
6e261abb73 | ||
|
|
39af9e4414 | ||
|
|
5b50abb2c7 | ||
|
|
13bda0a264 | ||
|
|
1658c666ab | ||
|
|
170aebfe54 | ||
|
|
c4ef379d0e | ||
|
|
18b038d8ff | ||
|
|
12ee5da872 | ||
|
|
601f9f86bb | ||
|
|
d7329a5915 | ||
|
|
9e7b730002 | ||
|
|
2d59d845bc | ||
|
|
c2645894e0 | ||
|
|
3751106317 | ||
|
|
60bb639351 | ||
|
|
74c50930bd | ||
|
|
9105104303 | ||
|
|
540dde135e | ||
|
|
f8936210cf | ||
|
|
1dc6d8de40 | ||
|
|
1069db3c13 | ||
|
|
65122f0144 | ||
|
|
d2c018f7da | ||
|
|
46493c2af6 | ||
|
|
c303e03f76 | ||
|
|
d8b65f62e7 | ||
|
|
854368a8f3 | ||
|
|
7653a34aea | ||
|
|
ee50b58e00 | ||
|
|
1eb60ab100 | ||
|
|
4a20eef351 | ||
|
|
26c9b2c353 | ||
|
|
16374bce9b | ||
|
|
86011d4ea2 | ||
|
|
fcb8b02da9 | ||
|
|
571165c2bb | ||
|
|
c842113610 | ||
|
|
974a8b3b70 | ||
|
|
2e20c99ada | ||
|
|
aa88ff6f2c | ||
|
|
5e6aa63d03 | ||
|
|
ad6700c114 | ||
|
|
f08c6efb00 | ||
|
|
cc807ec132 | ||
|
|
24e7c68243 | ||
|
|
ab25edd37a | ||
|
|
be47fde6c2 | ||
|
|
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 | ||
|
|
ccf0e1875e | ||
|
|
9c009aceaf | ||
|
|
da4b1c7276 | ||
|
|
add098d5c0 | ||
|
|
aca096548c | ||
|
|
75aa3abcae | ||
|
|
e685d262cc | ||
|
|
d2599d6ef9 | ||
|
|
cd5223d98d | ||
|
|
7b68d9047d | ||
|
|
9a7ea06d66 | ||
|
|
c69ef34ac9 | ||
|
|
021999d05f | ||
|
|
6054430a5e | ||
|
|
8f578ed95a | ||
|
|
fc5c339e27 | ||
|
|
defad3d820 | ||
|
|
c0f96aa948 | ||
|
|
f2eae2fc98 | ||
|
|
0e4f786978 | ||
|
|
d36b2318fd | ||
|
|
d83b508bbc | ||
|
|
5b9c2cdc13 | ||
|
|
49066c282a | ||
|
|
3e28c0c00a | ||
|
|
220d689f69 | ||
|
|
5a0a28a04c | ||
|
|
b44e69e09b | ||
|
|
fcbe10f5ec | ||
|
|
182fe170fd | ||
|
|
184e9bdaf6 | ||
|
|
0096f50cde | ||
|
|
460f14deca | ||
|
|
910ad45bee | ||
|
|
74e319855d | ||
|
|
9af0fb4cd5 | ||
|
|
185f5cce29 | ||
|
|
aca1174566 | ||
|
|
e791f7fde2 | ||
|
|
7bba7fcf66 | ||
|
|
1d78f98ec8 | ||
|
|
7ed2e03654 | ||
|
|
549e0f3477 | ||
|
|
7785ec0222 | ||
|
|
ca504965f9 | ||
|
|
3841259779 | ||
|
|
169d1065cc | ||
|
|
e864f5507a | ||
|
|
434b4ded4a | ||
|
|
3d01669cea | ||
|
|
1499b2cd40 | ||
|
|
6b54ef8398 | ||
|
|
07ad43f7a2 | ||
|
|
72e72c60c2 | ||
|
|
f9a242d33e | ||
|
|
b0f43eaa07 | ||
|
|
b02046b884 | ||
|
|
864c931ee9 | ||
|
|
5cd8da6d91 | ||
|
|
4a4671c2ae | ||
|
|
8de142cd9a | ||
|
|
1a42bec51c | ||
|
|
577e38759e | ||
|
|
9cdf43a2c9 | ||
|
|
62d43c2cb2 | ||
|
|
2dc67d1674 | ||
|
|
fb1c78c657 | ||
|
|
37e58ac13a | ||
|
|
de715c14be | ||
|
|
c4d8a0da05 | ||
|
|
1b54b14671 | ||
|
|
a92efbc55f | ||
|
|
1bd02529e0 | ||
|
|
bc16298b6e | ||
|
|
804a97cad7 | ||
|
|
ab52bdec15 | ||
|
|
ddc3e82c14 | ||
|
|
57691471bb | ||
|
|
c502dd445b | ||
|
|
ed475b1b9c | ||
|
|
df165a817c | ||
|
|
d16015d625 | ||
|
|
a4b3bf3ef4 | ||
|
|
6b006853e6 | ||
|
|
6001180e29 | ||
|
|
662fbed1d0 | ||
|
|
19c7e08c5d | ||
|
|
72f04aaedc | ||
|
|
2998382969 | ||
|
|
37fe79944f | ||
|
|
536735519a | ||
|
|
6b0a711395 | ||
|
|
13d3d40376 | ||
|
|
6873336aca | ||
|
|
c2d2eb53e8 | ||
|
|
210d597a48 | ||
|
|
e41ede0a6b | ||
|
|
4a8b17ac7c | ||
|
|
1f5f515d72 | ||
|
|
1e6242b89f | ||
|
|
dde09f9f89 | ||
|
|
916d85c3fe | ||
|
|
b243ed93aa | ||
|
|
70d28bbf6e | ||
|
|
3c76da7132 | ||
|
|
3254565c09 | ||
|
|
cd0033791f | ||
|
|
2427ee44a5 | ||
|
|
ff0e617b2a | ||
|
|
e6cfe040b5 | ||
|
|
94e2f9b6dc | ||
|
|
512b81ad93 | ||
|
|
fc0e76f431 | ||
|
|
9da69358e2 | ||
|
|
aa246b0b2b | ||
|
|
6ed649bc8a | ||
|
|
725f5b7110 | ||
|
|
5a890c5c3a | ||
|
|
7752329b94 | ||
|
|
5f48f13890 | ||
|
|
a734e04561 | ||
|
|
5aa1db293f | ||
|
|
f89aee37f5 | ||
|
|
538018fed1 | ||
|
|
a2327c50ec | ||
|
|
c2711023e2 | ||
|
|
cac30f0b4c | ||
|
|
4bb17019a4 | ||
|
|
ba2a40bdf3 | ||
|
|
f3460cca49 | ||
|
|
64ce53ac30 | ||
|
|
a43238360c | ||
|
|
b2cbadf5d8 | ||
|
|
81640ba06d | ||
|
|
9327430484 | ||
|
|
a24c90eae8 | ||
|
|
1d3987ece6 | ||
|
|
83f5b5e293 | ||
|
|
f231263085 | ||
|
|
4ad67a87f1 | ||
|
|
b766d93d9a | ||
|
|
0905ceb1d5 | ||
|
|
2fbf837354 | ||
|
|
4bd79c880c | ||
|
|
4af041e015 | ||
|
|
8dc3e3ec93 | ||
|
|
f4b68d26d6 | ||
|
|
1887977b92 | ||
|
|
8eb84acf4f | ||
|
|
1b685da3e3 | ||
|
|
406b658801 | ||
|
|
bba1ee1264 | ||
|
|
02b6191d47 | ||
|
|
c5a3de09cd | ||
|
|
0afe2a680e | ||
|
|
03e0510c4f | ||
|
|
1068dcb8a4 | ||
|
|
10a93df653 | ||
|
|
79ff67852f | ||
|
|
a36cab969f | ||
|
|
45447646fa | ||
|
|
8a0f76ab68 | ||
|
|
037135e764 | ||
|
|
21e89c3b64 | ||
|
|
bd11ec69fa | ||
|
|
9e2b34bc12 | ||
|
|
0faebc290f | ||
|
|
fc0ef4b79d | ||
|
|
027b954b50 | ||
|
|
33c830a432 | ||
|
|
a7887f1e25 | ||
|
|
fa7a59572a | ||
|
|
d9c2df5b0d | ||
|
|
a854b2c17e | ||
|
|
7d4006b205 | ||
|
|
86ecca6011 | ||
|
|
0ea5cf2caa | ||
|
|
a950e02e9b | ||
|
|
9eec6641dd | ||
|
|
18f46676fd | ||
|
|
9735ef6d41 | ||
|
|
d3e8ceee00 | ||
|
|
144e329eca | ||
|
|
21d5420b2a | ||
|
|
3011b5074d | ||
|
|
83190572c7 | ||
|
|
9cf9e5f865 | ||
|
|
5bdef7f1c7 | ||
|
|
ba285a2d2d | ||
|
|
0dff371e62 | ||
|
|
ce4a2a5851 | ||
|
|
2c978dc89a | ||
|
|
4b8b819109 | ||
|
|
c230b3a806 | ||
|
|
df08b9c5c6 | ||
|
|
eca65376a3 | ||
|
|
88e3705636 | ||
|
|
5476509ef5 | ||
|
|
0bd6636453 | ||
|
|
105894e00d | ||
|
|
230a319510 | ||
|
|
ae16a2b14f | ||
|
|
da0c0742bf | ||
|
|
61d60a9048 |
@@ -1,3 +0,0 @@
|
|||||||
src_dir: .
|
|
||||||
coverage_clover: tests/_output/coverage.xml
|
|
||||||
json_path: tests/_output/coveralls-upload.json
|
|
||||||
44
.env.example
Executable file
44
.env.example
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
APP_ENV=production
|
||||||
|
APP_DEBUG=false
|
||||||
|
APP_FORCE_SSL=false
|
||||||
|
APP_FORCE_ROOT=
|
||||||
|
APP_KEY=SomeRandomStringOf32CharsExactly
|
||||||
|
LOG_LEVEL=warning
|
||||||
|
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_DATABASE=homestead
|
||||||
|
DB_USERNAME=homestead
|
||||||
|
DB_PASSWORD=secret
|
||||||
|
|
||||||
|
CACHE_DRIVER=file
|
||||||
|
SESSION_DRIVER=file
|
||||||
|
QUEUE_DRIVER=sync
|
||||||
|
|
||||||
|
COOKIE_PATH="/"
|
||||||
|
COOKIE_DOMAIN=
|
||||||
|
COOKIE_SECURE=false
|
||||||
|
|
||||||
|
DEFAULT_CURRENCY=EUR
|
||||||
|
DEFAULT_LANGUAGE=en_US
|
||||||
|
|
||||||
|
REDIS_HOST=localhost
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_DRIVER=smtp
|
||||||
|
MAIL_HOST=mailtrap.io
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_FROM=enter_your_email_here
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
|
||||||
|
SEND_REGISTRATION_MAIL=true
|
||||||
|
MUST_CONFIRM_ACCOUNT=false
|
||||||
|
|
||||||
|
SHOW_INCOMPLETE_TRANSLATIONS=false
|
||||||
|
SHOW_DEMO_WARNING=false
|
||||||
|
|
||||||
|
ANALYTICS_ID=
|
||||||
|
SITE_OWNER=mail@example.com
|
||||||
38
.env.testing
Executable file
38
.env.testing
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
APP_ENV=testing
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_FORCE_SSL=false
|
||||||
|
APP_KEY=SomeRandomStringOf32CharsExactly
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
DB_CONNECTION=sqlite
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_DATABASE=homestead
|
||||||
|
DB_USERNAME=homestead
|
||||||
|
DB_PASSWORD=secret
|
||||||
|
|
||||||
|
CACHE_DRIVER=array
|
||||||
|
SESSION_DRIVER=array
|
||||||
|
QUEUE_DRIVER=array
|
||||||
|
|
||||||
|
DEFAULT_CURRENCY=EUR
|
||||||
|
DEFAULT_LANGUAGE=en_US
|
||||||
|
|
||||||
|
REDIS_HOST=localhost
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_DRIVER=log
|
||||||
|
MAIL_HOST=mailtrap.io
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_FROM=your_address_here@example.com
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
|
||||||
|
SHOW_INCOMPLETE_TRANSLATIONS=false
|
||||||
|
|
||||||
|
ANALYTICS_ID=abcde
|
||||||
|
RUNCLEANUP=false
|
||||||
|
SITE_OWNER=your_address_here@example.com
|
||||||
|
|
||||||
|
BLOCKED_DOMAINS=
|
||||||
2
.gitattributes
vendored
Normal file → Executable file
2
.gitattributes
vendored
Normal file → Executable file
@@ -1 +1,3 @@
|
|||||||
* text=auto
|
* text=auto
|
||||||
|
*.css linguist-vendored
|
||||||
|
*.less linguist-vendored
|
||||||
|
|||||||
34
.gitignore
vendored
34
.gitignore
vendored
@@ -1,27 +1,9 @@
|
|||||||
/bootstrap/compiled.php
|
|
||||||
/vendor
|
/vendor
|
||||||
composer.phar
|
/node_modules
|
||||||
.env.*.php
|
.env
|
||||||
.env.php
|
_development
|
||||||
Thumbs.db
|
.env.local
|
||||||
.idea/
|
result.html
|
||||||
tests/_output/*
|
test-import.sh
|
||||||
_ide_helper.php
|
test-import-report.txt
|
||||||
/build/logs/clover.xml
|
public/google*.html
|
||||||
index.html*
|
|
||||||
app/storage/firefly-export*
|
|
||||||
.vagrant
|
|
||||||
firefly-iii-import-*.json
|
|
||||||
tests/_output/*
|
|
||||||
testing.sqlite
|
|
||||||
_ide_helper_models.php
|
|
||||||
clean.sqlite
|
|
||||||
tests/acceptance/AcceptanceTester.php
|
|
||||||
tests/functional/FunctionalTester.php
|
|
||||||
tests/unit/UnitTester.php
|
|
||||||
pi.php
|
|
||||||
tests/_data/db.sqlite
|
|
||||||
tests/_data/dump.sql
|
|
||||||
db.sqlite_snapshot
|
|
||||||
c3.php
|
|
||||||
db.sqlite-journal
|
|
||||||
|
|||||||
7
.scrutinizer.yml
Normal file
7
.scrutinizer.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# .scrutinizer.yml
|
||||||
|
tools:
|
||||||
|
external_code_coverage: false
|
||||||
|
filter:
|
||||||
|
excluded_paths:
|
||||||
|
- app/Support/Migration/*
|
||||||
|
- app/database/migrations/*
|
||||||
16
.travis.yml
16
.travis.yml
@@ -1,16 +0,0 @@
|
|||||||
language: php
|
|
||||||
|
|
||||||
php:
|
|
||||||
- 5.5
|
|
||||||
- 5.6
|
|
||||||
|
|
||||||
install:
|
|
||||||
- composer install
|
|
||||||
|
|
||||||
script:
|
|
||||||
- ./tests/_data/db.sh
|
|
||||||
- php vendor/bin/codecept build
|
|
||||||
- php vendor/bin/codecept run --coverage --coverage-xml
|
|
||||||
|
|
||||||
after_script:
|
|
||||||
- php vendor/bin/coveralls
|
|
||||||
201
CHANGELOG.md
Normal file
201
CHANGELOG.md
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
# Change Log
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
- No unreleased changes yet.
|
||||||
|
|
||||||
|
## [3.10.2] - 2016-08-29
|
||||||
|
### Added
|
||||||
|
- New Chinese translations. Set Firefly III to show incomplete translations to follow the progress. Want to translate Firefly III in Chinese, or in any other language? Then check out [the Crowdin project](https://crowdin.com/project/firefly-iii).
|
||||||
|
- Added more admin pages. They do nothing yet.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Import routine will now also apply user rules.
|
||||||
|
- Various code cleanup.
|
||||||
|
- Some small HTML changes.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Bug in the mass edit routines.
|
||||||
|
- Firefly III over a proxy will now work (see [issue #290](https://github.com/JC5/firefly-iii/issues/290)), thanks @dfiel for reporting.
|
||||||
|
- Sneaky bug in the import routine, fixed by @Bonno
|
||||||
|
|
||||||
|
## [3.10.1] - 2016-08-25
|
||||||
|
### Added
|
||||||
|
- More feedback in the import procedure.
|
||||||
|
- Extended model for import job.
|
||||||
|
- Web bases import procedure.
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Scrutinizer configuration
|
||||||
|
- Various code clean up.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Code climate YAML file.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed a bug where a migration would check an empty table name.
|
||||||
|
- Fixed various bugs in the import routine.
|
||||||
|
- Fixed various bugs in the piggy banks pages.
|
||||||
|
- Fixed a bug in the ``firefly:verify`` routine
|
||||||
|
|
||||||
|
## [3.10] - 2015-05-25
|
||||||
|
### Added
|
||||||
|
- New charts in year report
|
||||||
|
- Can add / remove money from piggy bank on mobile device.
|
||||||
|
- Bill overview shows some useful things.
|
||||||
|
- Firefly will track registration / activation IP addresses.
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Rewrote the import routine.
|
||||||
|
- The date picker now supports more ranges and periods.
|
||||||
|
- Rewrote all migrations. #272
|
||||||
|
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Issue #264
|
||||||
|
- Issue #265
|
||||||
|
- Fixed amount calculation problems, #266, thanks @xzaz
|
||||||
|
- Issue #271
|
||||||
|
- Issue #278, #273, thanks @StevenReitsma and @rubella
|
||||||
|
- Bug in attachment download routine would report the wrong size to the user's browser.
|
||||||
|
- Various NULL errors fixed.
|
||||||
|
- Various strict typing errors fixed.
|
||||||
|
- Fixed pagination problems, #276, thanks @xzaz
|
||||||
|
- Fixed a bug where an expense would be assigned to a piggy bank if you created a transfer first.
|
||||||
|
- Bulk update problems, #280, thanks @stickgrinder
|
||||||
|
- Fixed various problems with amount reporting of split transactions.
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
|
||||||
|
[3.9.1]
|
||||||
|
### Fixed
|
||||||
|
- Fixed a bug where removing money from a piggy bank would not work. See issue #265 and #269
|
||||||
|
|
||||||
|
[3.9.0]
|
||||||
|
### Added
|
||||||
|
- @zjean has added code that allows you to force "https://"-URL's.
|
||||||
|
- @tonicospinelli has added Portuguese (Brazil) translations.
|
||||||
|
- Firefly III supports the *splitting* of transactions:
|
||||||
|
- A withdrawal (expense) can be split into multiple sub-transactions (with multiple destinations)
|
||||||
|
- Likewise for deposits (incomes). You can set multiple sources.
|
||||||
|
- Likewise for transfers.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Update a lot of libraries.
|
||||||
|
- Big improvement to test data generation.
|
||||||
|
- Cleaned up many repositories.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Front page boxes will no longer respond to credit card bills.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Many bugs
|
||||||
|
|
||||||
|
## [3.8.4] - 2016-04-24
|
||||||
|
### Added
|
||||||
|
- Lots of new translations.
|
||||||
|
- Can now set page size.
|
||||||
|
- Can now mass edit transactions.
|
||||||
|
- Can now mass delete transactions.
|
||||||
|
- Firefly will now attempt to verify the integrity of your database when updating.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- New version of Charts library.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Several CSV related bugs.
|
||||||
|
- Several other bugs.
|
||||||
|
- Bugs fixed by @Bonno.
|
||||||
|
|
||||||
|
## [3.8.3] - 2016-04-17
|
||||||
|
### Added
|
||||||
|
- New audit report to see what happened.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- New Chart JS release used.
|
||||||
|
- Help function is more reliable.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Expected bill amount is now correct.
|
||||||
|
- Upgrade will now invalidate cache.
|
||||||
|
- Search was broken.
|
||||||
|
- Queries run better
|
||||||
|
|
||||||
|
## [3.8.2] - 2016-04-03
|
||||||
|
### Added
|
||||||
|
- Small user administration at /admin.
|
||||||
|
- Informational popups are working in reports.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- User activation emails are better
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Some bugs related to accounts and rules.
|
||||||
|
|
||||||
|
|
||||||
|
## [3.8.1] - 2016-03-29
|
||||||
|
### Added
|
||||||
|
- More translations
|
||||||
|
- Extended cookie control.
|
||||||
|
- User accounts can now be activated (disabled by default).
|
||||||
|
- Bills can now take the source and destination account name into account.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- The pages related to rules have new URL's.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Spelling errors.
|
||||||
|
- Problems related to the "account repository".
|
||||||
|
- Some views showed empty (0.0) amounts.
|
||||||
|
|
||||||
|
## [3.8.0] - 2016-03-20
|
||||||
|
### Added
|
||||||
|
- Two factor authentication, thanks to the excellent work of [zjean](https://github.com/zjean).
|
||||||
|
- A new chart showing your net worth in year and multi-year reports.
|
||||||
|
- You can now see if your current or future rules actually match any transactions, thanks to the excellent work of @roberthorlings.
|
||||||
|
- New date fields for transactions. They are not used yet in reports or anything, but they can be filled in.
|
||||||
|
- New routine to export your data.
|
||||||
|
- Firefly III will mail the site owner when blocked users try to login, or when blocked domains are used in registrations.
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Firefly III now requires PHP 7.0 minimum.
|
||||||
|
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- HTML fixes, thanks to [roberthorlings](https://github.com/roberthorlings) and [zjean](https://github.com/zjean)..
|
||||||
|
- A bug fix in the ABN Amro importer, thanks to [roberthorlings](https://github.com/roberthorlings)
|
||||||
|
- It was not possible to change the opening balance, once it had been set. Thanks to [xnyhps](https://github.com/xnyhps) and [marcoveeneman](https://github.com/marcoveeneman) for spotting this.
|
||||||
|
- Various other bug fixes.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.4.2] - 2015-05-25
|
||||||
|
### Added
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Initial release.
|
||||||
7
LICENSE
Normal file
7
LICENSE
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
78
README.md
78
README.md
@@ -1,74 +1,30 @@
|
|||||||
Firefly III
|
# Firefly III [](https://secure.php.net/downloads.php#v7.0.4) [](https://packagist.org/packages/grumpydictator/firefly-iii) [](https://scrutinizer-ci.com/g/JC5/firefly-iii/?branch=master)
|
||||||
===========
|
|
||||||
|
|
||||||
[](https://travis-ci.org/JC5/firefly-iii)
|
## A personal finances manager
|
||||||
[](http://stillmaintained.com/JC5/firefly-iii)
|
|
||||||
[](https://coveralls.io/r/JC5/firefly-iii?branch=master)
|
|
||||||
[](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102)
|
|
||||||
|
|
||||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
[](https://i.nder.be/hhfv03hp) [](https://i.nder.be/hhmwmqw9)
|
||||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
|
||||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
|
||||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
|
||||||
|
|
||||||
Firefly II 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).
|
[](https://i.nder.be/g63q05m0) [](https://i.nder.be/c2g30ngg)
|
||||||
|
|
||||||
Firefly Mark III is a new version of Firefly built upon best practices and lessons learned
|
"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.
|
||||||
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.
|
|
||||||
|
|
||||||
## Current features
|
## Installation
|
||||||
|
|
||||||
- [A double-entry bookkeeping system](http://en.wikipedia.org/wiki/Double-entry_bookkeeping_system);
|
To install Firefly III, you'll need a web server (preferrably on Linux) and access to the command line. Then, please read the [installation guide](https://jc5.github.io/firefly-iii/installation-guide/).
|
||||||
- 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_;
|
|
||||||
- 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;
|
|
||||||
|
|
||||||
Everything is organised:
|
## More about Firefly III
|
||||||
|
|
||||||
- Clear views that should show you how you're doing;
|
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.
|
||||||
- Easy navigation through your records;
|
|
||||||
- Browse back and forth to see previous months or even years;
|
|
||||||
- Lots of charts because we all love them.
|
|
||||||
|
|
||||||
## Changes
|
Firefly works on the principle that if you know where you're money is going, you can stop it from going there.
|
||||||
|
|
||||||
Firefly III will feature, but does not feature yet:
|
#### Some advantages of using Firefly
|
||||||
|
|
||||||
- Financial reporting showing you how well you are doing;
|
- Firefly can import any CSV file, so migrating from other systems is easy.
|
||||||
- More control over other resources outside of personal finance
|
- Firefly runs on your own server, so you are fully in control of your data. Remember, there is no such thing as "the cloud", it’s just somebody else’s computer!
|
||||||
- Accounts shared with a partner (household accounts)
|
- Firefly has lots of features without becoming fancy or bloated.
|
||||||
- Debts
|
- If you feel you're missing something you can just ask me and I'll add it!
|
||||||
- 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:
|
Firefly is pretty awesome. [You can read more about Firefly III, and its features, on the Github Pages](https://jc5.github.io/firefly-iii/).
|
||||||
|
|
||||||
- The nesting of budgets, categories and beneficiaries is removed because it was pretty pointless.
|
If you want to contact me, please open an issue or [email me](mailto:thegrumpydictator@gmail.com).
|
||||||
- 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.
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
Questions, ideas or other things to contribute? [Let me know](https://github.com/JC5/firefly-iii/issues/new)!
|
|
||||||
45
app/Bootstrap/ConfigureLogging.php
Normal file
45
app/Bootstrap/ConfigureLogging.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ConfigureLogging.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Bootstrap;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
|
use Illuminate\Foundation\Bootstrap\ConfigureLogging as IlluminateConfigureLogging;
|
||||||
|
use Illuminate\Log\Writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ConfigureLogging
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Bootstrap
|
||||||
|
*/
|
||||||
|
class ConfigureLogging extends IlluminateConfigureLogging
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Application $app
|
||||||
|
* @param Writer $log
|
||||||
|
*/
|
||||||
|
protected function configureDailyHandler(Application $app, Writer $log)
|
||||||
|
{
|
||||||
|
$log->useDailyFiles(
|
||||||
|
$app->storagePath() . '/logs/firefly-iii.log',
|
||||||
|
$app->make('config')->get('app.log_max_files', 5)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Application $app
|
||||||
|
* @param Writer $log
|
||||||
|
*/
|
||||||
|
protected function configureSingleHandler(Application $app, Writer $log)
|
||||||
|
{
|
||||||
|
$log->useFiles($app->storagePath() . '/logs/firefly-iii.log');
|
||||||
|
}
|
||||||
|
}
|
||||||
66
app/Console/Commands/EncryptFile.php
Normal file
66
app/Console/Commands/EncryptFile.php
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EncryptFile.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Console\Commands;
|
||||||
|
|
||||||
|
use Crypt;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EncryptFile
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Console\Commands
|
||||||
|
*/
|
||||||
|
class EncryptFile extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Encrypts a file and places it in the storage/upload directory.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'firefly:encrypt {file} {key}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$file = e(strval($this->argument('file')));
|
||||||
|
if (!file_exists($file)) {
|
||||||
|
$this->error(sprintf('File "%s" does not seem to exist.', $file));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$content = file_get_contents($file);
|
||||||
|
$content = Crypt::encrypt($content);
|
||||||
|
$newName = e(strval($this->argument('key'))) . '.upload';
|
||||||
|
|
||||||
|
$path = storage_path('upload') . '/' . $newName;
|
||||||
|
file_put_contents($path, $content);
|
||||||
|
$this->line(sprintf('Encrypted "%s" and put it in "%s"', $file, $path));
|
||||||
|
}
|
||||||
|
}
|
||||||
120
app/Console/Commands/Import.php
Normal file
120
app/Console/Commands/Import.php
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Import.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Console\Commands;
|
||||||
|
|
||||||
|
use FireflyIII\Import\ImportProcedure;
|
||||||
|
use FireflyIII\Import\Logging\CommandHandler;
|
||||||
|
use FireflyIII\Models\ImportJob;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Import
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Console\Commands
|
||||||
|
*/
|
||||||
|
class Import extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Import stuff into Firefly III.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'firefly:import {key}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$jobKey = $this->argument('key');
|
||||||
|
$job = ImportJob::whereKey($jobKey)->first();
|
||||||
|
if (!$this->isValid($job)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->line('Going to import job with key "' . $job->key . '" of type ' . $job->file_type);
|
||||||
|
|
||||||
|
$monolog = Log::getMonolog();
|
||||||
|
$handler = new CommandHandler($this);
|
||||||
|
$monolog->pushHandler($handler);
|
||||||
|
|
||||||
|
$result = ImportProcedure::runImport($job);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int $index
|
||||||
|
* @var TransactionJournal $journal
|
||||||
|
*/
|
||||||
|
foreach ($result as $index => $journal) {
|
||||||
|
if (!is_null($journal->id)) {
|
||||||
|
$this->line(sprintf('Line #%d has been imported as transaction #%d.', $index, $journal->id));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->error(sprintf('Could not store line #%d', $index));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->line('The import has completed.');
|
||||||
|
|
||||||
|
// get any errors from the importer:
|
||||||
|
$extendedStatus = $job->extended_status;
|
||||||
|
if (isset($extendedStatus['errors']) && count($extendedStatus['errors']) > 0) {
|
||||||
|
$this->line(sprintf('The following %d error(s) occured during the import:', count($extendedStatus['errors'])));
|
||||||
|
foreach ($extendedStatus['errors'] as $error) {
|
||||||
|
$this->error($error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ImportJob $job
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isValid(ImportJob $job): bool
|
||||||
|
{
|
||||||
|
if (is_null($job)) {
|
||||||
|
$this->error('This job does not seem to exist.');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($job->status != 'settings_complete') {
|
||||||
|
$this->error('This job is not ready to be imported.');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
74
app/Console/Commands/UpgradeFireflyInstructions.php
Normal file
74
app/Console/Commands/UpgradeFireflyInstructions.php
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* UpgradeFireflyInstructions.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UpgradeFireflyInstructions
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Console\Commands
|
||||||
|
*/
|
||||||
|
class UpgradeFireflyInstructions extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Instructions in case of upgrade trouble.';
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'firefly:upgrade-instructions';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
/** @var string $version */
|
||||||
|
$version = config('firefly.version');
|
||||||
|
$config = config('upgrade.text');
|
||||||
|
$text = $config[$version] ?? null;
|
||||||
|
|
||||||
|
$this->line('+------------------------------------------------------------------------------+');
|
||||||
|
$this->line('');
|
||||||
|
|
||||||
|
if (is_null($text)) {
|
||||||
|
$this->line('Thank you for installing Firefly III, v' . $version);
|
||||||
|
$this->line('If you are upgrading from a previous version,');
|
||||||
|
$this->info('there are no extra upgrade instructions.');
|
||||||
|
$this->line('Firefly III should be ready for use.');
|
||||||
|
} else {
|
||||||
|
$this->line('Thank you for installing Firefly III, v' . $version);
|
||||||
|
$this->line('If you are upgrading from a previous version,');
|
||||||
|
$this->line('please follow these upgrade instructions carefully:');
|
||||||
|
$this->info(wordwrap($text));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->line('');
|
||||||
|
$this->line('+------------------------------------------------------------------------------+');
|
||||||
|
}
|
||||||
|
}
|
||||||
309
app/Console/Commands/VerifyDatabase.php
Normal file
309
app/Console/Commands/VerifyDatabase.php
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* VerifyDatabase.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Console\Commands;
|
||||||
|
|
||||||
|
use Crypt;
|
||||||
|
use DB;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\Budget;
|
||||||
|
use FireflyIII\Models\Category;
|
||||||
|
use FireflyIII\Models\Tag;
|
||||||
|
use FireflyIII\Models\Transaction;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class VerifyDatabase
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Console\Commands
|
||||||
|
*/
|
||||||
|
class VerifyDatabase extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Will verify your database.';
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'firefly:verify';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
// accounts with no transactions.
|
||||||
|
$this->reportAccounts();
|
||||||
|
// budgets with no limits
|
||||||
|
$this->reportBudgetLimits();
|
||||||
|
// budgets with no transactions
|
||||||
|
$this->reportBudgets();
|
||||||
|
// categories with no transactions
|
||||||
|
$this->reportCategories();
|
||||||
|
// tags with no transactions
|
||||||
|
$this->reportTags();
|
||||||
|
// sum of transactions is not zero.
|
||||||
|
$this->reportSum();
|
||||||
|
// any deleted transaction journals that have transactions that are NOT deleted:
|
||||||
|
$this->reportJournals();
|
||||||
|
// deleted transactions that are connected to a not deleted journal.
|
||||||
|
$this->reportTransactions();
|
||||||
|
// deleted accounts that still have not deleted transactions or journals attached to them.
|
||||||
|
$this->reportDeletedAccounts();
|
||||||
|
|
||||||
|
// report on journals with no transactions at all.
|
||||||
|
$this->reportNoTransactions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports on accounts with no transactions.
|
||||||
|
*/
|
||||||
|
private function reportAccounts()
|
||||||
|
{
|
||||||
|
$set = Account
|
||||||
|
::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
|
||||||
|
->leftJoin('users', 'accounts.user_id', '=', 'users.id')
|
||||||
|
->groupBy('accounts.id')
|
||||||
|
->having('transaction_count', '=', 0)
|
||||||
|
->get(
|
||||||
|
['accounts.id', 'accounts.encrypted', 'accounts.name', 'accounts.user_id', 'users.email',
|
||||||
|
DB::raw('COUNT(`transactions`.`id`) AS `transaction_count`')]
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @var stdClass $entry */
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$name = $entry->name;
|
||||||
|
$line = 'User #%d (%s) has account #%d ("%s") which has no transactions.';
|
||||||
|
$line = sprintf($line, $entry->user_id, $entry->email, $entry->id, $name);
|
||||||
|
$this->line($line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports on budgets with no budget limits (which makes them pointless).
|
||||||
|
*/
|
||||||
|
private function reportBudgetLimits()
|
||||||
|
{
|
||||||
|
$set = Budget
|
||||||
|
::leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
|
||||||
|
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
|
||||||
|
->groupBy('budgets.id')
|
||||||
|
->having('budget_limit_count', '=', 0)
|
||||||
|
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'users.email', DB::raw('COUNT(`budget_limits`.`id`) AS `budget_limit_count`')]);
|
||||||
|
|
||||||
|
/** @var stdClass $entry */
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$line = 'Notice: User #' . $entry->user_id . ' (' . $entry->email . ') has budget #' . $entry->id . ' ("' . Crypt::decrypt($entry->name)
|
||||||
|
. '") which has no budget limits.';
|
||||||
|
$this->line($line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports on budgets without any transactions.
|
||||||
|
*/
|
||||||
|
private function reportBudgets()
|
||||||
|
{
|
||||||
|
$set = Budget
|
||||||
|
::leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id')
|
||||||
|
->leftJoin('users', 'budgets.user_id', '=', 'users.id')
|
||||||
|
->distinct()
|
||||||
|
->whereNull('budget_transaction_journal.budget_id')
|
||||||
|
->whereNull('budgets.deleted_at')
|
||||||
|
->get(['budgets.id', 'budgets.name', 'budgets.user_id', 'users.email']);
|
||||||
|
|
||||||
|
/** @var stdClass $entry */
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$line = 'Notice: User #' . $entry->user_id . ' (' . $entry->email . ') has budget #' . $entry->id . ' ("' . Crypt::decrypt($entry->name)
|
||||||
|
. '") which has no transactions.';
|
||||||
|
$this->line($line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports on categories without any transactions.
|
||||||
|
*/
|
||||||
|
private function reportCategories()
|
||||||
|
{
|
||||||
|
$set = Category
|
||||||
|
::leftJoin('category_transaction_journal', 'categories.id', '=', 'category_transaction_journal.category_id')
|
||||||
|
->leftJoin('users', 'categories.user_id', '=', 'users.id')
|
||||||
|
->distinct()
|
||||||
|
->whereNull('category_transaction_journal.category_id')
|
||||||
|
->whereNull('categories.deleted_at')
|
||||||
|
->get(['categories.id', 'categories.name', 'categories.user_id', 'users.email']);
|
||||||
|
|
||||||
|
/** @var stdClass $entry */
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$line = 'Notice: User #' . $entry->user_id . ' (' . $entry->email . ') has category #' . $entry->id . ' ("' . Crypt::decrypt($entry->name)
|
||||||
|
. '") which has no transactions.';
|
||||||
|
$this->line($line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports on deleted accounts that still have not deleted transactions or journals attached to them.
|
||||||
|
*/
|
||||||
|
private function reportDeletedAccounts()
|
||||||
|
{
|
||||||
|
$set = Account
|
||||||
|
::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
|
||||||
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
|
->whereNotNull('accounts.deleted_at')
|
||||||
|
->whereNotNull('transactions.id')
|
||||||
|
->where(
|
||||||
|
function (Builder $q) {
|
||||||
|
$q->whereNull('transactions.deleted_at');
|
||||||
|
$q->orWhereNull('transaction_journals.deleted_at');
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->get(
|
||||||
|
['accounts.id as account_id', 'accounts.deleted_at as account_deleted_at', 'transactions.id as transaction_id',
|
||||||
|
'transactions.deleted_at as transaction_deleted_at', 'transaction_journals.id as journal_id',
|
||||||
|
'transaction_journals.deleted_at as journal_deleted_at']
|
||||||
|
);
|
||||||
|
/** @var stdClass $entry */
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$date = is_null($entry->transaction_deleted_at) ? $entry->journal_deleted_at : $entry->transaction_deleted_at;
|
||||||
|
$this->error(
|
||||||
|
'Error: Account #' . $entry->account_id . ' should have been deleted, but has not.' .
|
||||||
|
' Find it in the table called `accounts` and change the `deleted_at` field to: "' . $date . '"'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any deleted transaction journals that have transactions that are NOT deleted:
|
||||||
|
*/
|
||||||
|
private function reportJournals()
|
||||||
|
{
|
||||||
|
$set = TransactionJournal
|
||||||
|
::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->whereNotNull('transaction_journals.deleted_at')// USE THIS
|
||||||
|
->whereNull('transactions.deleted_at')
|
||||||
|
->whereNotNull('transactions.id')
|
||||||
|
->get(
|
||||||
|
[
|
||||||
|
'transaction_journals.id as journal_id',
|
||||||
|
'transaction_journals.description',
|
||||||
|
'transaction_journals.deleted_at as journal_deleted',
|
||||||
|
'transactions.id as transaction_id',
|
||||||
|
'transactions.deleted_at as transaction_deleted_at']
|
||||||
|
);
|
||||||
|
/** @var stdClass $entry */
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$this->error(
|
||||||
|
'Error: Transaction #' . $entry->transaction_id . ' should have been deleted, but has not.' .
|
||||||
|
' Find it in the table called `transactions` and change the `deleted_at` field to: "' . $entry->journal_deleted . '"'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function reportNoTransactions()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* select transaction_journals.id, count(transactions.id) as transaction_count from transaction_journals
|
||||||
|
left join transactions ON transaction_journals.id = transactions.transaction_journal_id
|
||||||
|
group by transaction_journals.id
|
||||||
|
having transaction_count = 0
|
||||||
|
*/
|
||||||
|
$set = TransactionJournal
|
||||||
|
::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->groupBy('transaction_journals.id')
|
||||||
|
->having('transaction_count', '=', 0)
|
||||||
|
->get(['transaction_journals.id', DB::raw('COUNT(`transactions`.`id`) as `transaction_count`')]);
|
||||||
|
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$this->error(
|
||||||
|
'Error: Journal #' . $entry->id . ' has zero transactions. Open table `transaction_journals` and delete the entry with id #' . $entry->id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports for each user when the sum of their transactions is not zero.
|
||||||
|
*/
|
||||||
|
private function reportSum()
|
||||||
|
{
|
||||||
|
/** @var UserRepositoryInterface $userRepository */
|
||||||
|
$userRepository = app(UserRepositoryInterface::class);
|
||||||
|
|
||||||
|
/** @var User $user */
|
||||||
|
foreach ($userRepository->all() as $user) {
|
||||||
|
$sum = strval($user->transactions()->sum('amount'));
|
||||||
|
if (bccomp($sum, '0') !== 0) {
|
||||||
|
$this->error('Error: Transactions for user #' . $user->id . ' (' . $user->email . ') are off by ' . $sum . '!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports on tags without any transactions.
|
||||||
|
*/
|
||||||
|
private function reportTags()
|
||||||
|
{
|
||||||
|
$set = Tag
|
||||||
|
::leftJoin('tag_transaction_journal', 'tags.id', '=', 'tag_transaction_journal.tag_id')
|
||||||
|
->leftJoin('users', 'tags.user_id', '=', 'users.id')
|
||||||
|
->distinct()
|
||||||
|
->whereNull('tag_transaction_journal.tag_id')
|
||||||
|
->whereNull('tags.deleted_at')
|
||||||
|
->get(['tags.id', 'tags.tag', 'tags.user_id', 'users.email']);
|
||||||
|
|
||||||
|
/** @var stdClass $entry */
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$line = 'Notice: User #' . $entry->user_id . ' (' . $entry->email . ') has tag #' . $entry->id . ' ("' . $entry->tag
|
||||||
|
. '") which has no transactions.';
|
||||||
|
$this->line($line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports on deleted transactions that are connected to a not deleted journal.
|
||||||
|
*/
|
||||||
|
private function reportTransactions()
|
||||||
|
{
|
||||||
|
$set = Transaction
|
||||||
|
::leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->whereNotNull('transactions.deleted_at')
|
||||||
|
->whereNull('transaction_journals.deleted_at')
|
||||||
|
->get(
|
||||||
|
['transactions.id as transaction_id', 'transactions.deleted_at as transaction_deleted', 'transaction_journals.id as journal_id',
|
||||||
|
'transaction_journals.deleted_at']
|
||||||
|
);
|
||||||
|
/** @var stdClass $entry */
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
$this->error(
|
||||||
|
'Error: Transaction journal #' . $entry->journal_id . ' should have been deleted, but has not.' .
|
||||||
|
' Find it in the table called `transaction_journals` and change the `deleted_at` field to: "' . $entry->transaction_deleted . '"'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
app/Console/Kernel.php
Normal file
59
app/Console/Kernel.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Kernel.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Console;
|
||||||
|
|
||||||
|
use FireflyIII\Console\Commands\EncryptFile;
|
||||||
|
use FireflyIII\Console\Commands\Import;
|
||||||
|
use FireflyIII\Console\Commands\UpgradeFireflyInstructions;
|
||||||
|
use FireflyIII\Console\Commands\VerifyDatabase;
|
||||||
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Kernel
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Console
|
||||||
|
*/
|
||||||
|
class Kernel extends ConsoleKernel
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bootstrap classes for the application.
|
||||||
|
*
|
||||||
|
* This needs to be for with the next upgrade.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $bootstrappers
|
||||||
|
= [
|
||||||
|
'Illuminate\Foundation\Bootstrap\DetectEnvironment',
|
||||||
|
'Illuminate\Foundation\Bootstrap\LoadConfiguration',
|
||||||
|
'FireflyIII\Bootstrap\ConfigureLogging',
|
||||||
|
'Illuminate\Foundation\Bootstrap\HandleExceptions',
|
||||||
|
'Illuminate\Foundation\Bootstrap\RegisterFacades',
|
||||||
|
'Illuminate\Foundation\Bootstrap\SetRequestForConsole',
|
||||||
|
'Illuminate\Foundation\Bootstrap\RegisterProviders',
|
||||||
|
'Illuminate\Foundation\Bootstrap\BootProviders',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Artisan commands provided by your application.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $commands
|
||||||
|
= [
|
||||||
|
UpgradeFireflyInstructions::class,
|
||||||
|
VerifyDatabase::class,
|
||||||
|
Import::class,
|
||||||
|
EncryptFile::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
530
app/Crud/Account/AccountCrud.php
Normal file
530
app/Crud/Account/AccountCrud.php
Normal file
@@ -0,0 +1,530 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AccountCrud.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Crud\Account;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use DB;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\AccountMeta;
|
||||||
|
use FireflyIII\Models\AccountType;
|
||||||
|
use FireflyIII\Models\Transaction;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AccountCrud
|
||||||
|
*
|
||||||
|
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Crud\Account
|
||||||
|
*/
|
||||||
|
class AccountCrud implements AccountCrudInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var User */
|
||||||
|
private $user;
|
||||||
|
/** @var array */
|
||||||
|
private $validFields = ['accountRole', 'ccMonthlyPaymentDate', 'ccType', 'accountNumber'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AccountCrud constructor.
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
*/
|
||||||
|
public function __construct(User $user)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param Account $moveTo
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function destroy(Account $account, Account $moveTo): bool
|
||||||
|
{
|
||||||
|
if (!is_null($moveTo->id)) {
|
||||||
|
DB::table('transactions')->where('account_id', $account->id)->update(['account_id' => $moveTo->id]);
|
||||||
|
}
|
||||||
|
if (!is_null($account)) {
|
||||||
|
$account->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $accountId
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function find(int $accountId): Account
|
||||||
|
{
|
||||||
|
$account = $this->user->accounts()->find($accountId);
|
||||||
|
if (is_null($account)) {
|
||||||
|
return new Account;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $number
|
||||||
|
* @param array $types
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function findByAccountNumber(string $number, array $types): Account
|
||||||
|
{
|
||||||
|
$query = $this->user->accounts()
|
||||||
|
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
|
||||||
|
->where('account_meta.name', 'accountNumber')
|
||||||
|
->where('account_meta.data', json_encode($number));
|
||||||
|
|
||||||
|
if (count($types) > 0) {
|
||||||
|
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||||
|
$query->whereIn('account_types.type', $types);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Collection $accounts */
|
||||||
|
$accounts = $query->get(['accounts.*']);
|
||||||
|
if ($accounts->count() > 0) {
|
||||||
|
return $accounts->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $iban
|
||||||
|
* @param array $types
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function findByIban(string $iban, array $types): Account
|
||||||
|
{
|
||||||
|
$query = $this->user->accounts()->where('iban', '!=', '');
|
||||||
|
|
||||||
|
if (count($types) > 0) {
|
||||||
|
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||||
|
$query->whereIn('account_types.type', $types);
|
||||||
|
}
|
||||||
|
|
||||||
|
$accounts = $query->get(['accounts.*']);
|
||||||
|
/** @var Account $account */
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
if ($account->iban === $iban) {
|
||||||
|
return $account;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @param array $types
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function findByName(string $name, array $types): Account
|
||||||
|
{
|
||||||
|
$query = $this->user->accounts();
|
||||||
|
|
||||||
|
if (count($types) > 0) {
|
||||||
|
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||||
|
$query->whereIn('account_types.type', $types);
|
||||||
|
}
|
||||||
|
|
||||||
|
$accounts = $query->get(['accounts.*']);
|
||||||
|
/** @var Account $account */
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
if ($account->name === $name) {
|
||||||
|
|
||||||
|
return $account;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $accountIds
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getAccountsById(array $accountIds): Collection
|
||||||
|
{
|
||||||
|
/** @var Collection $result */
|
||||||
|
$query = $this->user->accounts()->with(
|
||||||
|
['accountmeta' => function (HasMany $query) {
|
||||||
|
$query->where('name', 'accountRole');
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (count($accountIds) > 0) {
|
||||||
|
$query->whereIn('accounts.id', $accountIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $query->get(['accounts.*']);
|
||||||
|
$result = $result->sortBy(
|
||||||
|
function (Account $account) {
|
||||||
|
return strtolower($account->name);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $types
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getAccountsByType(array $types): Collection
|
||||||
|
{
|
||||||
|
/** @var Collection $result */
|
||||||
|
$query = $this->user->accounts()->with(
|
||||||
|
['accountmeta' => function (HasMany $query) {
|
||||||
|
$query->where('name', 'accountRole');
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
if (count($types) > 0) {
|
||||||
|
$query->accountTypeIn($types);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $query->get(['accounts.*']);
|
||||||
|
$result = $result->sortBy(
|
||||||
|
function (Account $account) {
|
||||||
|
return strtolower($account->name);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function store(array $data): Account
|
||||||
|
{
|
||||||
|
$newAccount = $this->storeAccount($data);
|
||||||
|
if (!is_null($newAccount->id)) {
|
||||||
|
$this->storeMetadata($newAccount, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data['openingBalance'] != 0) {
|
||||||
|
$this->storeInitialBalance($newAccount, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $newAccount;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $account
|
||||||
|
* @param $name
|
||||||
|
* @param $value
|
||||||
|
*
|
||||||
|
* @return AccountMeta
|
||||||
|
*/
|
||||||
|
public function storeMeta(Account $account, string $name, $value): AccountMeta
|
||||||
|
{
|
||||||
|
return AccountMeta::create(['name' => $name, 'data' => $value, 'account_id' => $account->id,]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function update(Account $account, array $data): Account
|
||||||
|
{
|
||||||
|
// update the account:
|
||||||
|
$account->name = $data['name'];
|
||||||
|
$account->active = $data['active'] == '1' ? true : false;
|
||||||
|
$account->virtual_balance = $data['virtualBalance'];
|
||||||
|
$account->iban = $data['iban'];
|
||||||
|
$account->save();
|
||||||
|
|
||||||
|
$this->updateMetadata($account, $data);
|
||||||
|
$this->updateInitialBalance($account, $data);
|
||||||
|
|
||||||
|
return $account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param string $type
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function updateAccountType(Account $account, string $type): Account
|
||||||
|
{
|
||||||
|
$type = AccountType::whereType($type)->first();
|
||||||
|
if (!is_null($type)) {
|
||||||
|
$account->accountType()->associate($type);
|
||||||
|
$account->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->find($account->id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
protected function storeAccount(array $data): Account
|
||||||
|
{
|
||||||
|
$type = config('firefly.accountTypeByIdentifier.' . $data['accountType']);
|
||||||
|
$accountType = AccountType::whereType($type)->first();
|
||||||
|
$newAccount = new Account(
|
||||||
|
[
|
||||||
|
'user_id' => $data['user'],
|
||||||
|
'account_type_id' => $accountType->id,
|
||||||
|
'name' => $data['name'],
|
||||||
|
'virtual_balance' => $data['virtualBalance'],
|
||||||
|
'active' => $data['active'] === true ? true : false,
|
||||||
|
'iban' => $data['iban'],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$newAccount->isValid()) {
|
||||||
|
// does the account already exist?
|
||||||
|
$searchData = [
|
||||||
|
'user_id' => $data['user'],
|
||||||
|
'account_type_id' => $accountType->id,
|
||||||
|
'virtual_balance' => $data['virtualBalance'],
|
||||||
|
'name' => $data['name'],
|
||||||
|
'iban' => $data['iban'],
|
||||||
|
];
|
||||||
|
$existingAccount = Account::firstOrNullEncrypted($searchData);
|
||||||
|
if (!$existingAccount) {
|
||||||
|
Log::error('Account create error', $newAccount->getErrors()->toArray());
|
||||||
|
|
||||||
|
return new Account;
|
||||||
|
}
|
||||||
|
$newAccount = $existingAccount;
|
||||||
|
|
||||||
|
}
|
||||||
|
$newAccount->save();
|
||||||
|
|
||||||
|
return $newAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return TransactionJournal
|
||||||
|
*/
|
||||||
|
protected function storeInitialBalance(Account $account, array $data): TransactionJournal
|
||||||
|
{
|
||||||
|
$amount = $data['openingBalance'];
|
||||||
|
$user = $data['user'];
|
||||||
|
$name = $data['name'];
|
||||||
|
$opposing = $this->storeOpposingAccount($amount, $user, $name);
|
||||||
|
$transactionType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
|
||||||
|
$journal = TransactionJournal::create(
|
||||||
|
[
|
||||||
|
'user_id' => $data['user'],
|
||||||
|
'transaction_type_id' => $transactionType->id,
|
||||||
|
'transaction_currency_id' => $data['openingBalanceCurrency'],
|
||||||
|
'description' => 'Initial balance for "' . $account->name . '"',
|
||||||
|
'completed' => true,
|
||||||
|
'date' => $data['openingBalanceDate'],
|
||||||
|
'encrypted' => true,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$firstAccount = $account;
|
||||||
|
$secondAccount = $opposing;
|
||||||
|
$firstAmount = $amount;
|
||||||
|
$secondAmount = $amount * -1;
|
||||||
|
|
||||||
|
if ($data['openingBalance'] < 0) {
|
||||||
|
$firstAccount = $opposing;
|
||||||
|
$secondAccount = $account;
|
||||||
|
$firstAmount = $amount * -1;
|
||||||
|
$secondAmount = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$one = new Transaction(['account_id' => $firstAccount->id, 'transaction_journal_id' => $journal->id, 'amount' => $firstAmount]);
|
||||||
|
$one->save();// first transaction: from
|
||||||
|
$two = new Transaction(['account_id' => $secondAccount->id, 'transaction_journal_id' => $journal->id, 'amount' => $secondAmount]);
|
||||||
|
$two->save(); // second transaction: to
|
||||||
|
|
||||||
|
return $journal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param array $data
|
||||||
|
*/
|
||||||
|
protected function storeMetadata(Account $account, array $data)
|
||||||
|
{
|
||||||
|
foreach ($this->validFields as $field) {
|
||||||
|
if (isset($data[$field])) {
|
||||||
|
$metaData = new AccountMeta(
|
||||||
|
[
|
||||||
|
'account_id' => $account->id,
|
||||||
|
'name' => $field,
|
||||||
|
'data' => $data[$field],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$metaData->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function updateInitialBalance(Account $account, array $data): bool
|
||||||
|
{
|
||||||
|
$openingBalance = $this->openingBalanceTransaction($account);
|
||||||
|
if ($data['openingBalance'] != 0) {
|
||||||
|
if (!is_null($openingBalance->id)) {
|
||||||
|
$date = $data['openingBalanceDate'];
|
||||||
|
$amount = $data['openingBalance'];
|
||||||
|
|
||||||
|
return $this->updateJournal($account, $openingBalance, $date, $amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->storeInitialBalance($account, $data);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// else, delete it:
|
||||||
|
if ($openingBalance) { // opening balance is zero, should we delete it?
|
||||||
|
$openingBalance->delete(); // delete existing opening balance.
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function updateMetadata(Account $account, array $data)
|
||||||
|
{
|
||||||
|
foreach ($this->validFields as $field) {
|
||||||
|
$entry = $account->accountMeta()->where('name', $field)->first();
|
||||||
|
|
||||||
|
if (isset($data[$field])) {
|
||||||
|
// update if new data is present:
|
||||||
|
if (!is_null($entry)) {
|
||||||
|
$entry->data = $data[$field];
|
||||||
|
$entry->save();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$metaData = new AccountMeta(
|
||||||
|
[
|
||||||
|
'account_id' => $account->id,
|
||||||
|
'name' => $field,
|
||||||
|
'data' => $data[$field],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$metaData->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return TransactionJournal|null
|
||||||
|
*/
|
||||||
|
private function openingBalanceTransaction(Account $account): TransactionJournal
|
||||||
|
{
|
||||||
|
$journal = TransactionJournal
|
||||||
|
::sortCorrectly()
|
||||||
|
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->where('transactions.account_id', $account->id)
|
||||||
|
->transactionTypes([TransactionType::OPENING_BALANCE])
|
||||||
|
->first(['transaction_journals.*']);
|
||||||
|
if (is_null($journal)) {
|
||||||
|
return new TransactionJournal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $journal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param float $amount
|
||||||
|
* @param int $user
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
private function storeOpposingAccount(float $amount, int $user, string $name):Account
|
||||||
|
{
|
||||||
|
$type = $amount < 0 ? 'expense' : 'revenue';
|
||||||
|
$opposingData = [
|
||||||
|
'user' => $user,
|
||||||
|
'accountType' => $type,
|
||||||
|
'name' => $name . ' initial balance',
|
||||||
|
'active' => false,
|
||||||
|
'iban' => '',
|
||||||
|
'virtualBalance' => 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->storeAccount($opposingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
* @param Carbon $date
|
||||||
|
* @param float $amount
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function updateJournal(Account $account, TransactionJournal $journal, Carbon $date, float $amount): bool
|
||||||
|
{
|
||||||
|
// update date:
|
||||||
|
$journal->date = $date;
|
||||||
|
$journal->save();
|
||||||
|
// update transactions:
|
||||||
|
/** @var Transaction $transaction */
|
||||||
|
foreach ($journal->transactions()->get() as $transaction) {
|
||||||
|
if ($account->id == $transaction->account_id) {
|
||||||
|
$transaction->amount = $amount;
|
||||||
|
$transaction->save();
|
||||||
|
}
|
||||||
|
if ($account->id != $transaction->account_id) {
|
||||||
|
$transaction->amount = $amount * -1;
|
||||||
|
$transaction->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
109
app/Crud/Account/AccountCrudInterface.php
Normal file
109
app/Crud/Account/AccountCrudInterface.php
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AccountCrudInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Crud\Account;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\AccountMeta;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface AccountCrudInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Crud\Account
|
||||||
|
*/
|
||||||
|
interface AccountCrudInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param Account $moveTo
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function destroy(Account $account, Account $moveTo): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $accountId
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function find(int $accountId): Account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $number
|
||||||
|
* @param array $types
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function findByAccountNumber(string $number, array $types): Account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $iban
|
||||||
|
* @param array $types
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function findByIban(string $iban, array $types): Account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @param array $types
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function findByName(string $name, array $types): Account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $accountIds
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getAccountsById(array $accountIds): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $types
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getAccountsByType(array $types): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function store(array $data) : Account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $account
|
||||||
|
* @param $name
|
||||||
|
* @param $value
|
||||||
|
*
|
||||||
|
* @return AccountMeta
|
||||||
|
*/
|
||||||
|
public function storeMeta(Account $account, string $name, $value): AccountMeta;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function update(Account $account, array $data): Account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param string $type
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public function updateAccountType(Account $account, string $type): Account;
|
||||||
|
}
|
||||||
216
app/Crud/Split/Journal.php
Normal file
216
app/Crud/Split/Journal.php
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Journal.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Crud\Split;
|
||||||
|
|
||||||
|
use FireflyIII\Events\TransactionStored;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\AccountType;
|
||||||
|
use FireflyIII\Models\Budget;
|
||||||
|
use FireflyIII\Models\Category;
|
||||||
|
use FireflyIII\Models\Transaction;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Journal
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Crud\Split
|
||||||
|
*/
|
||||||
|
class Journal implements JournalInterface
|
||||||
|
{
|
||||||
|
/** @var User */
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AttachmentRepository constructor.
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
*/
|
||||||
|
public function __construct(User $user)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $journal
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function markAsComplete(TransactionJournal $journal)
|
||||||
|
{
|
||||||
|
$journal->completed = 1;
|
||||||
|
$journal->save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
* @param array $transaction
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function storeTransaction(TransactionJournal $journal, array $transaction): Collection
|
||||||
|
{
|
||||||
|
// store accounts (depends on type)
|
||||||
|
list($sourceAccount, $destinationAccount) = $this->storeAccounts($journal->transactionType->type, $transaction);
|
||||||
|
|
||||||
|
// store transaction one way:
|
||||||
|
/** @var Transaction $one */
|
||||||
|
$one = Transaction::create(
|
||||||
|
['account_id' => $sourceAccount->id, 'transaction_journal_id' => $journal->id, 'amount' => $transaction['amount'] * -1,
|
||||||
|
'description' => $transaction['description']]
|
||||||
|
);
|
||||||
|
$two = Transaction::create(
|
||||||
|
['account_id' => $destinationAccount->id, 'transaction_journal_id' => $journal->id, 'amount' => $transaction['amount'],
|
||||||
|
'description' => $transaction['description']]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (strlen($transaction['category']) > 0) {
|
||||||
|
$category = Category::firstOrCreateEncrypted(['name' => $transaction['category'], 'user_id' => $journal->user_id]);
|
||||||
|
$one->categories()->save($category);
|
||||||
|
$two->categories()->save($category);
|
||||||
|
}
|
||||||
|
if (intval($transaction['budget_id']) > 0) {
|
||||||
|
$budget = Budget::find($transaction['budget_id']);
|
||||||
|
$one->budgets()->save($budget);
|
||||||
|
$two->budgets()->save($budget);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($transaction['piggy_bank_id'] > 0) {
|
||||||
|
$transaction['date'] = $journal->date->format('Y-m-d');
|
||||||
|
event(new TransactionStored($transaction));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Collection([$one, $two]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return TransactionJournal
|
||||||
|
*/
|
||||||
|
public function updateJournal(TransactionJournal $journal, array $data): TransactionJournal
|
||||||
|
{
|
||||||
|
$journal->description = $data['journal_description'];
|
||||||
|
$journal->transaction_currency_id = $data['journal_currency_id'];
|
||||||
|
$journal->date = $data['date'];
|
||||||
|
$journal->interest_date = $data['interest_date'];
|
||||||
|
$journal->book_date = $data['book_date'];
|
||||||
|
$journal->process_date = $data['process_date'];
|
||||||
|
$journal->save();
|
||||||
|
|
||||||
|
// delete original transactions, and recreate them.
|
||||||
|
$journal->transactions()->delete();
|
||||||
|
|
||||||
|
foreach ($data['transactions'] as $transaction) {
|
||||||
|
$this->storeTransaction($journal, $transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
$journal->completed = true;
|
||||||
|
$journal->save();
|
||||||
|
|
||||||
|
return $journal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $type
|
||||||
|
* @param array $transaction
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws FireflyException
|
||||||
|
*/
|
||||||
|
private function storeAccounts(string $type, array $transaction): array
|
||||||
|
{
|
||||||
|
$sourceAccount = null;
|
||||||
|
$destinationAccount = null;
|
||||||
|
switch ($type) {
|
||||||
|
case TransactionType::WITHDRAWAL:
|
||||||
|
list($sourceAccount, $destinationAccount) = $this->storeWithdrawalAccounts($transaction);
|
||||||
|
break;
|
||||||
|
case TransactionType::DEPOSIT:
|
||||||
|
list($sourceAccount, $destinationAccount) = $this->storeDepositAccounts($transaction);
|
||||||
|
break;
|
||||||
|
case TransactionType::TRANSFER:
|
||||||
|
$sourceAccount = Account::where('user_id', $this->user->id)->where('id', $transaction['source_account_id'])->first();
|
||||||
|
$destinationAccount = Account::where('user_id', $this->user->id)->where('id', $transaction['destination_account_id'])->first();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new FireflyException('Cannot handle ' . e($type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$sourceAccount, $destinationAccount];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function storeDepositAccounts(array $data): array
|
||||||
|
{
|
||||||
|
$destinationAccount = Account::where('user_id', $this->user->id)->where('id', $data['destination_account_id'])->first(['accounts.*']);
|
||||||
|
|
||||||
|
|
||||||
|
if (isset($data['source_account_name']) && strlen($data['source_account_name']) > 0) {
|
||||||
|
$sourceType = AccountType::where('type', 'Revenue account')->first();
|
||||||
|
$sourceAccount = Account::firstOrCreateEncrypted(
|
||||||
|
['user_id' => $this->user->id, 'account_type_id' => $sourceType->id, 'name' => $data['source_account_name'], 'active' => 1]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [$sourceAccount, $destinationAccount];
|
||||||
|
}
|
||||||
|
|
||||||
|
$sourceType = AccountType::where('type', 'Cash account')->first();
|
||||||
|
$sourceAccount = Account::firstOrCreateEncrypted(
|
||||||
|
['user_id' => $this->user->id, 'account_type_id' => $sourceType->id, 'name' => 'Cash account', 'active' => 1]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [$sourceAccount, $destinationAccount];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function storeWithdrawalAccounts(array $data): array
|
||||||
|
{
|
||||||
|
$sourceAccount = Account::where('user_id', $this->user->id)->where('id', $data['source_account_id'])->first(['accounts.*']);
|
||||||
|
|
||||||
|
if (strlen($data['destination_account_name']) > 0) {
|
||||||
|
$destinationType = AccountType::where('type', 'Expense account')->first();
|
||||||
|
$destinationAccount = Account::firstOrCreateEncrypted(
|
||||||
|
[
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'account_type_id' => $destinationType->id,
|
||||||
|
'name' => $data['destination_account_name'],
|
||||||
|
'active' => 1,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [$sourceAccount, $destinationAccount];
|
||||||
|
}
|
||||||
|
$destinationType = AccountType::where('type', 'Cash account')->first();
|
||||||
|
$destinationAccount = Account::firstOrCreateEncrypted(
|
||||||
|
['user_id' => $this->user->id, 'account_type_id' => $destinationType->id, 'name' => 'Cash account', 'active' => 1]
|
||||||
|
);
|
||||||
|
|
||||||
|
return [$sourceAccount, $destinationAccount];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
47
app/Crud/Split/JournalInterface.php
Normal file
47
app/Crud/Split/JournalInterface.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* JournalInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Crud\Split;
|
||||||
|
|
||||||
|
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface JournalInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Crud\Split
|
||||||
|
*/
|
||||||
|
interface JournalInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param $journal
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function markAsComplete(TransactionJournal $journal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
* @param array $transaction
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function storeTransaction(TransactionJournal $journal, array $transaction): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return TransactionJournal
|
||||||
|
*/
|
||||||
|
public function updateJournal(TransactionJournal $journal, array $data): TransactionJournal;
|
||||||
|
}
|
||||||
48
app/Events/BudgetLimitStored.php
Normal file
48
app/Events/BudgetLimitStored.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BudgetLimitStored.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Models\BudgetLimit;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BudgetLimitStored
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class BudgetLimitStored extends Event
|
||||||
|
{
|
||||||
|
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
/** @var BudgetLimit */
|
||||||
|
public $budgetLimit;
|
||||||
|
|
||||||
|
/** @var Carbon */
|
||||||
|
public $end; // the only variable we can't get from the budget limit (if necessary).
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BudgetLimitEvents constructor.
|
||||||
|
*
|
||||||
|
* @param BudgetLimit $budgetLimit
|
||||||
|
* @param Carbon $end
|
||||||
|
*/
|
||||||
|
public function __construct(BudgetLimit $budgetLimit, Carbon $end)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
$this->budgetLimit = $budgetLimit;
|
||||||
|
$this->end = $end;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
48
app/Events/BudgetLimitUpdated.php
Normal file
48
app/Events/BudgetLimitUpdated.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BudgetLimitUpdated.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Models\BudgetLimit;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BudgetLimitUpdated
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class BudgetLimitUpdated extends Event
|
||||||
|
{
|
||||||
|
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
/** @var BudgetLimit */
|
||||||
|
public $budgetLimit;
|
||||||
|
|
||||||
|
/** @var Carbon */
|
||||||
|
public $end; // the only variable we can't get from the budget limit (if necessary).
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BudgetLimitEvents constructor.
|
||||||
|
*
|
||||||
|
* @param BudgetLimit $budgetLimit
|
||||||
|
* @param Carbon $end
|
||||||
|
*/
|
||||||
|
public function __construct(BudgetLimit $budgetLimit, Carbon $end)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
$this->budgetLimit = $budgetLimit;
|
||||||
|
$this->end = $end;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
21
app/Events/Event.php
Normal file
21
app/Events/Event.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Event.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Event
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
abstract class Event
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
40
app/Events/ResendConfirmation.php
Normal file
40
app/Events/ResendConfirmation.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ResendConfirmation.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ResendConfirmation
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class ResendConfirmation extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $ipAddress;
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
* @param string $ipAddress
|
||||||
|
*/
|
||||||
|
public function __construct(User $user, string $ipAddress)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->ipAddress = $ipAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
44
app/Events/TransactionJournalStored.php
Normal file
44
app/Events/TransactionJournalStored.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* TransactionJournalStored.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class TransactionJournalStored
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class TransactionJournalStored extends Event
|
||||||
|
{
|
||||||
|
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $journal;
|
||||||
|
public $piggyBankId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
* @param int $piggyBankId
|
||||||
|
*/
|
||||||
|
public function __construct(TransactionJournal $journal, int $piggyBankId)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
$this->journal = $journal;
|
||||||
|
$this->piggyBankId = $piggyBankId;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
app/Events/TransactionJournalUpdated.php
Normal file
40
app/Events/TransactionJournalUpdated.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* TransactionJournalUpdated.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class TransactionJournalUpdated
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class TransactionJournalUpdated extends Event
|
||||||
|
{
|
||||||
|
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $journal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
*/
|
||||||
|
public function __construct(TransactionJournal $journal)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
$this->journal = $journal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
app/Events/TransactionStored.php
Normal file
39
app/Events/TransactionStored.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* TransactionStored.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class TransactionJournalStored
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class TransactionStored extends Event
|
||||||
|
{
|
||||||
|
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $transaction = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @param array $transaction
|
||||||
|
*/
|
||||||
|
public function __construct(array $transaction)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
$this->transaction = $transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
app/Events/UserIsConfirmed.php
Normal file
40
app/Events/UserIsConfirmed.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* UserIsConfirmed.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UserIsConfirmed
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class UserIsConfirmed extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $ipAddress;
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
* @param string $ipAddress
|
||||||
|
*/
|
||||||
|
public function __construct(User $user, string $ipAddress)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->ipAddress = $ipAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
app/Events/UserIsDeleted.php
Normal file
40
app/Events/UserIsDeleted.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* UserIsDeleted.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UserIsDeleted
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class UserIsDeleted extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $ipAddress;
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
* @param string $ipAddress
|
||||||
|
*/
|
||||||
|
public function __construct(User $user, string $ipAddress)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->ipAddress = $ipAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
app/Events/UserRegistration.php
Normal file
40
app/Events/UserRegistration.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* UserRegistration.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Events;
|
||||||
|
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UserRegistration
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Events
|
||||||
|
*/
|
||||||
|
class UserRegistration extends Event
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $ipAddress;
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
* @param string $ipAddress
|
||||||
|
*/
|
||||||
|
public function __construct(User $user, string $ipAddress)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->ipAddress = $ipAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
app/Exceptions/FireflyException.php
Normal file
22
app/Exceptions/FireflyException.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* FireflyException.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Exceptions;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FireflyException
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Exceptions
|
||||||
|
*/
|
||||||
|
class FireflyException extends \Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
101
app/Exceptions/Handler.php
Normal file
101
app/Exceptions/Handler.php
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handler.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Exceptions;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use ErrorException;
|
||||||
|
use Exception;
|
||||||
|
use FireflyIII\Jobs\MailError;
|
||||||
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
|
use Request;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Handler
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Exceptions
|
||||||
|
*/
|
||||||
|
class Handler extends ExceptionHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A list of the exception types that should not be reported.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $dontReport
|
||||||
|
= [
|
||||||
|
AuthorizationException::class,
|
||||||
|
HttpException::class,
|
||||||
|
ModelNotFoundException::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render an exception into an HTTP response.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Exception $exception
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function render($request, Exception $exception)
|
||||||
|
{
|
||||||
|
if ($exception instanceof FireflyException || $exception instanceof ErrorException) {
|
||||||
|
|
||||||
|
$isDebug = env('APP_DEBUG', false);
|
||||||
|
|
||||||
|
return response()->view('errors.FireflyException', ['exception' => $exception, 'debug' => $isDebug], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::render($request, $exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report or log an exception.
|
||||||
|
*
|
||||||
|
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
|
||||||
|
*
|
||||||
|
* @param Exception $exception
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function report(Exception $exception)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ($exception instanceof FireflyException || $exception instanceof ErrorException) {
|
||||||
|
$userData = [
|
||||||
|
'id' => 0,
|
||||||
|
'email' => 'unknown@example.com',
|
||||||
|
];
|
||||||
|
if (Auth::check()) {
|
||||||
|
$userData['id'] = Auth::user()->id;
|
||||||
|
$userData['email'] = Auth::user()->email;
|
||||||
|
}
|
||||||
|
$data = [
|
||||||
|
'class' => get_class($exception),
|
||||||
|
'errorMessage' => $exception->getMessage(),
|
||||||
|
'time' => date('r'),
|
||||||
|
'stackTrace' => $exception->getTraceAsString(),
|
||||||
|
'file' => $exception->getFile(),
|
||||||
|
'line' => $exception->getLine(),
|
||||||
|
'code' => $exception->getCode(),
|
||||||
|
];
|
||||||
|
|
||||||
|
// create job that will mail.
|
||||||
|
$job = new MailError($userData, env('SITE_OWNER'), Request::ip(), $data);
|
||||||
|
dispatch($job);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::report($exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
app/Exceptions/NotImplementedException.php
Normal file
22
app/Exceptions/NotImplementedException.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* NotImplementedException.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Exceptions;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class NotImplementedException
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Exceptions
|
||||||
|
*/
|
||||||
|
class NotImplementedException extends \Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
21
app/Exceptions/ValidationException.php
Normal file
21
app/Exceptions/ValidationException.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ValidationException.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ValidationExceptions
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Exception
|
||||||
|
*/
|
||||||
|
class ValidationException extends \Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
148
app/Export/Collector/AttachmentCollector.php
Normal file
148
app/Export/Collector/AttachmentCollector.php
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AttachmentCollector.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Collector;
|
||||||
|
|
||||||
|
use Amount;
|
||||||
|
use Crypt;
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
|
use FireflyIII\Models\ExportJob;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||||
|
use Illuminate\Contracts\Encryption\DecryptException;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Log;
|
||||||
|
use Storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AttachmentCollector
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Collector
|
||||||
|
*/
|
||||||
|
class AttachmentCollector extends BasicCollector implements CollectorInterface
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $explanationString = '';
|
||||||
|
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||||
|
private $exportDisk;
|
||||||
|
/** @var AttachmentRepositoryInterface */
|
||||||
|
private $repository;
|
||||||
|
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||||
|
private $uploadDisk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AttachmentCollector constructor.
|
||||||
|
*
|
||||||
|
* @param ExportJob $job
|
||||||
|
*/
|
||||||
|
public function __construct(ExportJob $job)
|
||||||
|
{
|
||||||
|
/** @var AttachmentRepositoryInterface repository */
|
||||||
|
$this->repository = app(AttachmentRepositoryInterface::class);
|
||||||
|
// make storage:
|
||||||
|
$this->uploadDisk = Storage::disk('upload');
|
||||||
|
$this->exportDisk = Storage::disk('export');
|
||||||
|
|
||||||
|
parent::__construct($job);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function run(): bool
|
||||||
|
{
|
||||||
|
// grab all the users attachments:
|
||||||
|
$attachments = $this->getAttachments();
|
||||||
|
|
||||||
|
/** @var Attachment $attachment */
|
||||||
|
foreach ($attachments as $attachment) {
|
||||||
|
$this->exportAttachment($attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// put the explanation string in a file and attach it as well.
|
||||||
|
$file = $this->job->key . '-Source of all your attachments explained.txt';
|
||||||
|
$this->exportDisk->put($file, $this->explanationString);
|
||||||
|
$this->getFiles()->push($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Attachment $attachment
|
||||||
|
*/
|
||||||
|
private function explain(Attachment $attachment)
|
||||||
|
{
|
||||||
|
/** @var TransactionJournal $journal */
|
||||||
|
$journal = $attachment->attachable;
|
||||||
|
$args = [
|
||||||
|
'attachment_name' => e($attachment->filename),
|
||||||
|
'attachment_id' => $attachment->id,
|
||||||
|
'type' => strtolower($journal->transactionType->type),
|
||||||
|
'description' => e($journal->description),
|
||||||
|
'journal_id' => $journal->id,
|
||||||
|
'date' => $journal->date->formatLocalized(strval(trans('config.month_and_day'))),
|
||||||
|
'amount' => Amount::formatJournal($journal, false),
|
||||||
|
];
|
||||||
|
$string = trans('firefly.attachment_explanation', $args) . "\n";
|
||||||
|
Log::debug('Appended explanation string', ['string' => $string]);
|
||||||
|
$this->explanationString .= $string;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Attachment $attachment
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function exportAttachment(Attachment $attachment): bool
|
||||||
|
{
|
||||||
|
$file = $attachment->fileName();
|
||||||
|
if ($this->uploadDisk->exists($file)) {
|
||||||
|
try {
|
||||||
|
$decrypted = Crypt::decrypt($this->uploadDisk->get($file));
|
||||||
|
$exportFile = $this->exportFileName($attachment);
|
||||||
|
$this->exportDisk->put($exportFile, $decrypted);
|
||||||
|
$this->getFiles()->push($exportFile);
|
||||||
|
|
||||||
|
// explain:
|
||||||
|
$this->explain($attachment);
|
||||||
|
} catch (DecryptException $e) {
|
||||||
|
Log::error('Catchable error: could not decrypt attachment #' . $attachment->id . ' because: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the new file name for the export file.
|
||||||
|
*
|
||||||
|
* @param $attachment
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function exportFileName($attachment): string
|
||||||
|
{
|
||||||
|
|
||||||
|
return sprintf('%s-Attachment nr. %s - %s', $this->job->key, strval($attachment->id), $attachment->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function getAttachments(): Collection
|
||||||
|
{
|
||||||
|
$attachments = $this->repository->get();
|
||||||
|
|
||||||
|
return $attachments;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
app/Export/Collector/BasicCollector.php
Normal file
58
app/Export/Collector/BasicCollector.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BasicCollector.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Collector;
|
||||||
|
|
||||||
|
|
||||||
|
use FireflyIII\Models\ExportJob;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BasicCollector
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Collector
|
||||||
|
*/
|
||||||
|
class BasicCollector
|
||||||
|
{
|
||||||
|
/** @var ExportJob */
|
||||||
|
protected $job;
|
||||||
|
/** @var Collection */
|
||||||
|
private $files;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BasicCollector constructor.
|
||||||
|
*
|
||||||
|
* @param ExportJob $job
|
||||||
|
*/
|
||||||
|
public function __construct(ExportJob $job)
|
||||||
|
{
|
||||||
|
$this->files = new Collection;
|
||||||
|
$this->job = $job;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getFiles(): Collection
|
||||||
|
{
|
||||||
|
return $this->files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $files
|
||||||
|
*/
|
||||||
|
public function setFiles(Collection $files)
|
||||||
|
{
|
||||||
|
$this->files = $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
39
app/Export/Collector/CollectorInterface.php
Normal file
39
app/Export/Collector/CollectorInterface.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* CollectorInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Collector;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface CollectorInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Collector
|
||||||
|
*/
|
||||||
|
interface CollectorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getFiles(): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function run(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $files
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setFiles(Collection $files);
|
||||||
|
|
||||||
|
}
|
||||||
200
app/Export/Collector/UploadCollector.php
Normal file
200
app/Export/Collector/UploadCollector.php
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* UploadCollector.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Collector;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Crypt;
|
||||||
|
use FireflyIII\Models\ExportJob;
|
||||||
|
use Illuminate\Contracts\Encryption\DecryptException;
|
||||||
|
use Log;
|
||||||
|
use Storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UploadCollector
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Collector
|
||||||
|
*/
|
||||||
|
class UploadCollector extends BasicCollector implements CollectorInterface
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $expected;
|
||||||
|
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||||
|
private $exportDisk;
|
||||||
|
private $importKeys = [];
|
||||||
|
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||||
|
private $uploadDisk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* AttachmentCollector constructor.
|
||||||
|
*
|
||||||
|
* @param ExportJob $job
|
||||||
|
*/
|
||||||
|
public function __construct(ExportJob $job)
|
||||||
|
{
|
||||||
|
parent::__construct($job);
|
||||||
|
|
||||||
|
Log::debug('Going to collect attachments', ['key' => $job->key]);
|
||||||
|
|
||||||
|
// make storage:
|
||||||
|
$this->uploadDisk = Storage::disk('upload');
|
||||||
|
$this->exportDisk = Storage::disk('export');
|
||||||
|
|
||||||
|
// file names associated with the old import routine.
|
||||||
|
$this->expected = 'csv-upload-' . Auth::user()->id . '-';
|
||||||
|
|
||||||
|
// for the new import routine:
|
||||||
|
$this->getImportKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function run(): bool
|
||||||
|
{
|
||||||
|
// grab upload directory.
|
||||||
|
$files = $this->uploadDisk->files();
|
||||||
|
|
||||||
|
foreach ($files as $entry) {
|
||||||
|
$this->processUpload($entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function getImportKeys()
|
||||||
|
{
|
||||||
|
$set = Auth::user()->importJobs()->where('status', 'import_complete')->get(['import_jobs.*']);
|
||||||
|
if ($set->count() > 0) {
|
||||||
|
$keys = $set->pluck('key')->toArray();
|
||||||
|
$this->importKeys = $keys;
|
||||||
|
|
||||||
|
}
|
||||||
|
Log::debug('Valid import keys are ', $this->importKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $entry
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getOriginalUploadDate(string $entry): string
|
||||||
|
{
|
||||||
|
// this is an original upload.
|
||||||
|
$parts = explode('-', str_replace(['.csv.encrypted', $this->expected], '', $entry));
|
||||||
|
$originalUpload = intval($parts[1]);
|
||||||
|
$date = date('Y-m-d \a\t H-i-s', $originalUpload);
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $entry
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isImportFile(string $entry): bool
|
||||||
|
{
|
||||||
|
$name = str_replace('.upload', '', $entry);
|
||||||
|
if (in_array($name, $this->importKeys)) {
|
||||||
|
Log::debug(sprintf('Import file "%s" is in array', $name), $this->importKeys);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Log::debug(sprintf('Import file "%s" is NOT in array', $name), $this->importKeys);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $entry
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isOldImport(string $entry): bool
|
||||||
|
{
|
||||||
|
$len = strlen($this->expected);
|
||||||
|
// file is part of the old import routine:
|
||||||
|
if (substr($entry, 0, $len) === $this->expected) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $entry
|
||||||
|
*/
|
||||||
|
private function processUpload(string $entry)
|
||||||
|
{
|
||||||
|
// file is old import:
|
||||||
|
if ($this->isOldImport($entry)) {
|
||||||
|
$this->saveOldImportFile($entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// file is current import.
|
||||||
|
if ($this->isImportFile($entry)) {
|
||||||
|
$this->saveImportFile($entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $entry
|
||||||
|
*/
|
||||||
|
private function saveImportFile(string $entry)
|
||||||
|
{
|
||||||
|
// find job associated with import file:
|
||||||
|
$name = str_replace('.upload', '', $entry);
|
||||||
|
$job = Auth::user()->importJobs()->where('key', $name)->first();
|
||||||
|
$content = '';
|
||||||
|
try {
|
||||||
|
$content = Crypt::decrypt($this->uploadDisk->get($entry));
|
||||||
|
} catch (DecryptException $e) {
|
||||||
|
Log::error('Could not decrypt old import file ' . $entry . '. Skipped because ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($job) && strlen($content) > 0) {
|
||||||
|
// add to export disk.
|
||||||
|
$date = $job->created_at->format('Y-m-d');
|
||||||
|
$file = sprintf('%s-Old %s import dated %s.%s', $this->job->key, strtoupper($job->file_type), $date, $job->file_type);
|
||||||
|
$this->exportDisk->put($file, $content);
|
||||||
|
$this->getFiles()->push($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $entry
|
||||||
|
*/
|
||||||
|
private function saveOldImportFile(string $entry)
|
||||||
|
{
|
||||||
|
$content = '';
|
||||||
|
try {
|
||||||
|
$content = Crypt::decrypt($this->uploadDisk->get($entry));
|
||||||
|
} catch (DecryptException $e) {
|
||||||
|
Log::error('Could not decrypt old CSV import file ' . $entry . '. Skipped because ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($content) > 0) {
|
||||||
|
// add to export disk.
|
||||||
|
$date = $this->getOriginalUploadDate($entry);
|
||||||
|
$file = $this->job->key . '-Old import dated ' . $date . '.csv';
|
||||||
|
$this->exportDisk->put($file, $content);
|
||||||
|
$this->getFiles()->push($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
66
app/Export/ConfigurationFile.php
Normal file
66
app/Export/ConfigurationFile.php
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ConfigurationFile.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export;
|
||||||
|
|
||||||
|
use FireflyIII\Export\Entry\Entry;
|
||||||
|
use FireflyIII\Models\ExportJob;
|
||||||
|
use Storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ConfigurationFile
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export
|
||||||
|
*/
|
||||||
|
class ConfigurationFile
|
||||||
|
{
|
||||||
|
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||||
|
private $exportDisk;
|
||||||
|
/** @var ExportJob */
|
||||||
|
private $job;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigurationFile constructor.
|
||||||
|
*
|
||||||
|
* @param ExportJob $job
|
||||||
|
*/
|
||||||
|
public function __construct(ExportJob $job)
|
||||||
|
{
|
||||||
|
$this->job = $job;
|
||||||
|
$this->exportDisk = Storage::disk('export');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function make(): string
|
||||||
|
{
|
||||||
|
$fields = array_keys(Entry::getFieldsAndTypes());
|
||||||
|
$types = Entry::getFieldsAndTypes();
|
||||||
|
|
||||||
|
$configuration = [
|
||||||
|
'date-format' => 'Y-m-d', // unfortunately, this is hard-coded.
|
||||||
|
'has-headers' => true,
|
||||||
|
'map' => [], // we could build a map if necessary for easy re-import.
|
||||||
|
'roles' => [],
|
||||||
|
'mapped' => [],
|
||||||
|
'specifix' => [],
|
||||||
|
];
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
$configuration['roles'][] = $types[$field];
|
||||||
|
}
|
||||||
|
$file = $this->job->key . '-configuration.json';
|
||||||
|
$this->exportDisk->put($file, json_encode($configuration, JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
130
app/Export/Entry/Entry.php
Normal file
130
app/Export/Entry/Entry.php
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Entry.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Entry;
|
||||||
|
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To extend the exported object, in case of new features in Firefly III for example,
|
||||||
|
* do the following:
|
||||||
|
*
|
||||||
|
* - Add the field(s) to this class. If you add more than one related field, add a new object.
|
||||||
|
* - Make sure the "fromJournal"-routine fills these fields.
|
||||||
|
* - Add them to the static function that returns its type (key=value. Remember that the only
|
||||||
|
* valid types can be found in config/csv.php (under "roles").
|
||||||
|
*
|
||||||
|
* These new entries should be should be strings and numbers as much as possible.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Class Entry
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Entry
|
||||||
|
*/
|
||||||
|
final class Entry
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $amount;
|
||||||
|
/** @var EntryBill */
|
||||||
|
public $bill;
|
||||||
|
/** @var EntryBudget */
|
||||||
|
public $budget;
|
||||||
|
/** @var EntryCategory */
|
||||||
|
public $category;
|
||||||
|
/** @var string */
|
||||||
|
public $date;
|
||||||
|
/** @var string */
|
||||||
|
public $description;
|
||||||
|
/** @var EntryAccount */
|
||||||
|
public $destinationAccount;
|
||||||
|
/** @var Collection */
|
||||||
|
public $destinationAccounts;
|
||||||
|
/** @var EntryAccount */
|
||||||
|
public $sourceAccount;
|
||||||
|
/** @var Collection */
|
||||||
|
public $sourceAccounts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry constructor.
|
||||||
|
*/
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
$this->sourceAccounts = new Collection;
|
||||||
|
$this->destinationAccounts = new Collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
*
|
||||||
|
* @return Entry
|
||||||
|
*/
|
||||||
|
public static function fromJournal(TransactionJournal $journal)
|
||||||
|
{
|
||||||
|
|
||||||
|
$entry = new self;
|
||||||
|
$entry->description = $journal->description;
|
||||||
|
$entry->date = $journal->date->format('Y-m-d');
|
||||||
|
$entry->amount = TransactionJournal::amount($journal);
|
||||||
|
|
||||||
|
$entry->budget = new EntryBudget($journal->budgets->first());
|
||||||
|
$entry->category = new EntryCategory($journal->categories->first());
|
||||||
|
$entry->bill = new EntryBill($journal->bill);
|
||||||
|
|
||||||
|
$sources = TransactionJournal::sourceAccountList($journal);
|
||||||
|
$destinations = TransactionJournal::destinationAccountList($journal);
|
||||||
|
$entry->sourceAccount = new EntryAccount($sources->first());
|
||||||
|
$entry->destinationAccount = new EntryAccount($destinations->first());
|
||||||
|
|
||||||
|
foreach ($sources as $source) {
|
||||||
|
$entry->sourceAccounts->push(new EntryAccount($source));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($destinations as $destination) {
|
||||||
|
$entry->destinationAccounts->push(new EntryAccount($destination));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $entry;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getFieldsAndTypes(): array
|
||||||
|
{
|
||||||
|
// key = field name (see top of class)
|
||||||
|
// value = field type (see csv.php under 'roles')
|
||||||
|
return [
|
||||||
|
'description' => 'description',
|
||||||
|
'amount' => 'amount',
|
||||||
|
'date' => 'date-transaction',
|
||||||
|
'source_account_id' => 'account-id',
|
||||||
|
'source_account_name' => 'account-name',
|
||||||
|
'source_account_iban' => 'account-iban',
|
||||||
|
'source_account_type' => '_ignore',
|
||||||
|
'source_account_number' => 'account-number',
|
||||||
|
'destination_account_id' => 'opposing-id',
|
||||||
|
'destination_account_name' => 'opposing-name',
|
||||||
|
'destination_account_iban' => 'opposing-iban',
|
||||||
|
'destination_account_type' => '_ignore',
|
||||||
|
'destination_account_number' => 'account-number',
|
||||||
|
'budget_id' => 'budget-id',
|
||||||
|
'budget_name' => 'budget-name',
|
||||||
|
'category_id' => 'category-id',
|
||||||
|
'category_name' => 'category-name',
|
||||||
|
'bill_id' => 'bill-id',
|
||||||
|
'bill_name' => 'bill-name',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
47
app/Export/Entry/EntryAccount.php
Normal file
47
app/Export/Entry/EntryAccount.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EntryAccount.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Entry;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EntryAccount
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Entry
|
||||||
|
*/
|
||||||
|
class EntryAccount
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
public $accountId;
|
||||||
|
/** @var string */
|
||||||
|
public $iban;
|
||||||
|
/** @var string */
|
||||||
|
public $name;
|
||||||
|
/** @var string */
|
||||||
|
public $number;
|
||||||
|
/** @var string */
|
||||||
|
public $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EntryAccount constructor.
|
||||||
|
*
|
||||||
|
* @param Account $account
|
||||||
|
*/
|
||||||
|
public function __construct(Account $account)
|
||||||
|
{
|
||||||
|
$this->accountId = $account->id;
|
||||||
|
$this->name = $account->name;
|
||||||
|
$this->iban = $account->iban;
|
||||||
|
$this->type = $account->accountType->type;
|
||||||
|
$this->number = $account->getMeta('accountNumber');
|
||||||
|
}
|
||||||
|
}
|
||||||
41
app/Export/Entry/EntryBill.php
Normal file
41
app/Export/Entry/EntryBill.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EntryBill.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Entry;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Bill;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EntryBill
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Entry
|
||||||
|
*/
|
||||||
|
class EntryBill
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
public $billId = '';
|
||||||
|
/** @var string */
|
||||||
|
public $name = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EntryBill constructor.
|
||||||
|
*
|
||||||
|
* @param Bill $bill
|
||||||
|
*/
|
||||||
|
public function __construct(Bill $bill = null)
|
||||||
|
{
|
||||||
|
if (!is_null($bill)) {
|
||||||
|
$this->billId = $bill->id;
|
||||||
|
$this->name = $bill->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
app/Export/Entry/EntryBudget.php
Normal file
41
app/Export/Entry/EntryBudget.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EntryBudget.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Entry;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Budget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EntryBudget
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Entry
|
||||||
|
*/
|
||||||
|
class EntryBudget
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
public $budgetId = '';
|
||||||
|
/** @var string */
|
||||||
|
public $name = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EntryBudget constructor.
|
||||||
|
*
|
||||||
|
* @param Budget $budget
|
||||||
|
*/
|
||||||
|
public function __construct(Budget $budget = null)
|
||||||
|
{
|
||||||
|
if (!is_null($budget)) {
|
||||||
|
$this->budgetId = $budget->id;
|
||||||
|
$this->name = $budget->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
app/Export/Entry/EntryCategory.php
Normal file
40
app/Export/Entry/EntryCategory.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EntryCategory.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Entry;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EntryCategory
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Entry
|
||||||
|
*/
|
||||||
|
class EntryCategory
|
||||||
|
{
|
||||||
|
/** @var int */
|
||||||
|
public $categoryId = '';
|
||||||
|
/** @var string */
|
||||||
|
public $name = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EntryCategory constructor.
|
||||||
|
*
|
||||||
|
* @param Category $category
|
||||||
|
*/
|
||||||
|
public function __construct(Category $category = null)
|
||||||
|
{
|
||||||
|
if (!is_null($category)) {
|
||||||
|
$this->categoryId = $category->id;
|
||||||
|
$this->name = $category->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
app/Export/Exporter/BasicExporter.php
Normal file
57
app/Export/Exporter/BasicExporter.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BasicExporter.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Exporter;
|
||||||
|
|
||||||
|
|
||||||
|
use FireflyIII\Models\ExportJob;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BasicExporter
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Exporter
|
||||||
|
*/
|
||||||
|
class BasicExporter
|
||||||
|
{
|
||||||
|
/** @var ExportJob */
|
||||||
|
protected $job;
|
||||||
|
private $entries;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BasicExporter constructor.
|
||||||
|
*
|
||||||
|
* @param ExportJob $job
|
||||||
|
*/
|
||||||
|
public function __construct(ExportJob $job)
|
||||||
|
{
|
||||||
|
$this->entries = new Collection;
|
||||||
|
$this->job = $job;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getEntries(): Collection
|
||||||
|
{
|
||||||
|
return $this->entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*/
|
||||||
|
public function setEntries(Collection $entries)
|
||||||
|
{
|
||||||
|
$this->entries = $entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
172
app/Export/Exporter/CsvExporter.php
Normal file
172
app/Export/Exporter/CsvExporter.php
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* CsvExporter.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Exporter;
|
||||||
|
|
||||||
|
use FireflyIII\Export\Entry\Entry;
|
||||||
|
use FireflyIII\Export\Entry\EntryAccount;
|
||||||
|
use FireflyIII\Models\ExportJob;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use League\Csv\Writer;
|
||||||
|
use SplFileObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CsvExporter
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Exporter
|
||||||
|
*/
|
||||||
|
class CsvExporter extends BasicExporter implements ExporterInterface
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $fileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CsvExporter constructor.
|
||||||
|
*
|
||||||
|
* @param ExportJob $job
|
||||||
|
*/
|
||||||
|
public function __construct(ExportJob $job)
|
||||||
|
{
|
||||||
|
parent::__construct($job);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFileName(): string
|
||||||
|
{
|
||||||
|
return $this->fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function run(): bool
|
||||||
|
{
|
||||||
|
// create temporary file:
|
||||||
|
$this->tempFile();
|
||||||
|
|
||||||
|
// necessary for CSV writer:
|
||||||
|
$fullPath = storage_path('export') . DIRECTORY_SEPARATOR . $this->fileName;
|
||||||
|
$writer = Writer::createFromPath(new SplFileObject($fullPath, 'a+'), 'w');
|
||||||
|
$rows = [];
|
||||||
|
|
||||||
|
// Count the maximum number of sources and destinations each entry has. May need to expand the number of export fields:
|
||||||
|
$maxSourceAccounts = 1;
|
||||||
|
$maxDestAccounts = 1;
|
||||||
|
/** @var Entry $entry */
|
||||||
|
foreach ($this->getEntries() as $entry) {
|
||||||
|
$sources = $entry->sourceAccounts->count();
|
||||||
|
$destinations = $entry->destinationAccounts->count();
|
||||||
|
$maxSourceAccounts = max($maxSourceAccounts, $sources);
|
||||||
|
$maxDestAccounts = max($maxDestAccounts, $destinations);
|
||||||
|
}
|
||||||
|
$rows[] = array_keys($this->getFieldsAndTypes($maxSourceAccounts, $maxDestAccounts));
|
||||||
|
|
||||||
|
/** @var Entry $entry */
|
||||||
|
foreach ($this->getEntries() as $entry) {
|
||||||
|
// order is defined in Entry::getFieldsAndTypes.
|
||||||
|
$current = [$entry->description, $entry->amount, $entry->date];
|
||||||
|
$sourceData = $this->getAccountData($maxSourceAccounts, $entry->sourceAccounts);
|
||||||
|
$current = array_merge($current, $sourceData);
|
||||||
|
$destData = $this->getAccountData($maxDestAccounts, $entry->destinationAccounts);
|
||||||
|
$current = array_merge($current, $destData);
|
||||||
|
$rest = [$entry->budget->budgetId, $entry->budget->name, $entry->category->categoryId, $entry->category->name, $entry->bill->billId,
|
||||||
|
$entry->bill->name];
|
||||||
|
$current = array_merge($current, $rest);
|
||||||
|
$rows[] = $current;
|
||||||
|
}
|
||||||
|
$writer->insertAll($rows);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $max
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getAccountData(int $max, Collection $accounts): array
|
||||||
|
{
|
||||||
|
$current = [];
|
||||||
|
for ($i = 0; $i < $max; $i++) {
|
||||||
|
/** @var EntryAccount $source */
|
||||||
|
$source = $accounts->get($i);
|
||||||
|
$currentId = '';
|
||||||
|
$currentName = '';
|
||||||
|
$currentIban = '';
|
||||||
|
$currentType = '';
|
||||||
|
$currentNumber = '';
|
||||||
|
if ($source) {
|
||||||
|
$currentId = $source->accountId;
|
||||||
|
$currentName = $source->name;
|
||||||
|
$currentIban = $source->iban;
|
||||||
|
$currentType = $source->type;
|
||||||
|
$currentNumber = $source->number;
|
||||||
|
}
|
||||||
|
$current[] = $currentId;
|
||||||
|
$current[] = $currentName;
|
||||||
|
$current[] = $currentIban;
|
||||||
|
$current[] = $currentType;
|
||||||
|
$current[] = $currentNumber;
|
||||||
|
}
|
||||||
|
unset($source);
|
||||||
|
|
||||||
|
return $current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $sources
|
||||||
|
* @param int $destinations
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getFieldsAndTypes(int $sources, int $destinations): array
|
||||||
|
{
|
||||||
|
// key = field name (see top of class)
|
||||||
|
// value = field type (see csv.php under 'roles')
|
||||||
|
$array = [
|
||||||
|
'description' => 'description',
|
||||||
|
'amount' => 'amount',
|
||||||
|
'date' => 'date-transaction',
|
||||||
|
];
|
||||||
|
for ($i = 0; $i < $sources; $i++) {
|
||||||
|
$array['source_account_' . $i . '_id'] = 'account-id';
|
||||||
|
$array['source_account_' . $i . '_name'] = 'account-name';
|
||||||
|
$array['source_account_' . $i . '_iban'] = 'account-iban';
|
||||||
|
$array['source_account_' . $i . '_type'] = '_ignore';
|
||||||
|
$array['source_account_' . $i . '_number'] = 'account-number';
|
||||||
|
}
|
||||||
|
for ($i = 0; $i < $destinations; $i++) {
|
||||||
|
$array['destination_account_' . $i . '_id'] = 'account-id';
|
||||||
|
$array['destination_account_' . $i . '_name'] = 'account-name';
|
||||||
|
$array['destination_account_' . $i . '_iban'] = 'account-iban';
|
||||||
|
$array['destination_account_' . $i . '_type'] = '_ignore';
|
||||||
|
$array['destination_account_' . $i . '_number'] = 'account-number';
|
||||||
|
}
|
||||||
|
|
||||||
|
$array['budget_id'] = 'budget-id';
|
||||||
|
$array['budget_name'] = 'budget-name';
|
||||||
|
$array['category_id'] = 'category-id';
|
||||||
|
$array['category_name'] = 'category-name';
|
||||||
|
$array['bill_id'] = 'bill-id';
|
||||||
|
$array['bill_name'] = 'bill-name';
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function tempFile()
|
||||||
|
{
|
||||||
|
$this->fileName = $this->job->key . '-records.csv';
|
||||||
|
}
|
||||||
|
}
|
||||||
44
app/Export/Exporter/ExporterInterface.php
Normal file
44
app/Export/Exporter/ExporterInterface.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ExporterInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export\Exporter;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface ExporterInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export\Exporter
|
||||||
|
*/
|
||||||
|
interface ExporterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getEntries(): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFileName(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function run(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setEntries(Collection $entries);
|
||||||
|
|
||||||
|
}
|
||||||
203
app/Export/Processor.php
Normal file
203
app/Export/Processor.php
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Processor.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Export;
|
||||||
|
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
|
use FireflyIII\Export\Collector\AttachmentCollector;
|
||||||
|
use FireflyIII\Export\Collector\UploadCollector;
|
||||||
|
use FireflyIII\Export\Entry\Entry;
|
||||||
|
use FireflyIII\Models\ExportJob;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||||
|
use Illuminate\Filesystem\FilesystemAdapter;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Storage;
|
||||||
|
use ZipArchive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Processor
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Export
|
||||||
|
*/
|
||||||
|
class Processor
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var Collection */
|
||||||
|
public $accounts;
|
||||||
|
/** @var string */
|
||||||
|
public $exportFormat;
|
||||||
|
/** @var bool */
|
||||||
|
public $includeAttachments;
|
||||||
|
/** @var bool */
|
||||||
|
public $includeConfig;
|
||||||
|
/** @var bool */
|
||||||
|
public $includeOldUploads;
|
||||||
|
/** @var ExportJob */
|
||||||
|
public $job;
|
||||||
|
/** @var array */
|
||||||
|
public $settings;
|
||||||
|
/** @var \FireflyIII\Export\ConfigurationFile */
|
||||||
|
private $configurationMaker;
|
||||||
|
/** @var Collection */
|
||||||
|
private $exportEntries;
|
||||||
|
/** @var Collection */
|
||||||
|
private $files;
|
||||||
|
/** @var Collection */
|
||||||
|
private $journals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processor constructor.
|
||||||
|
*
|
||||||
|
* @param array $settings
|
||||||
|
*/
|
||||||
|
public function __construct(array $settings)
|
||||||
|
{
|
||||||
|
// save settings
|
||||||
|
$this->settings = $settings;
|
||||||
|
$this->accounts = $settings['accounts'];
|
||||||
|
$this->exportFormat = $settings['exportFormat'];
|
||||||
|
$this->includeAttachments = $settings['includeAttachments'];
|
||||||
|
$this->includeConfig = $settings['includeConfig'];
|
||||||
|
$this->includeOldUploads = $settings['includeOldUploads'];
|
||||||
|
$this->job = $settings['job'];
|
||||||
|
$this->journals = new Collection;
|
||||||
|
$this->exportEntries = new Collection;
|
||||||
|
$this->files = new Collection;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function collectAttachments(): bool
|
||||||
|
{
|
||||||
|
/** @var AttachmentCollector $attachmentCollector */
|
||||||
|
$attachmentCollector = app(AttachmentCollector::class, [$this->job]);
|
||||||
|
$attachmentCollector->run();
|
||||||
|
$this->files = $this->files->merge($attachmentCollector->getFiles());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function collectJournals(): bool
|
||||||
|
{
|
||||||
|
/** @var JournalRepositoryInterface $repository */
|
||||||
|
$repository = app(JournalRepositoryInterface::class);
|
||||||
|
$this->journals = $repository->getJournalsInRange($this->accounts, $this->settings['startDate'], $this->settings['endDate']);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function collectOldUploads(): bool
|
||||||
|
{
|
||||||
|
/** @var UploadCollector $uploadCollector */
|
||||||
|
$uploadCollector = app(UploadCollector::class, [$this->job]);
|
||||||
|
$uploadCollector->run();
|
||||||
|
|
||||||
|
$this->files = $this->files->merge($uploadCollector->getFiles());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function convertJournals(): bool
|
||||||
|
{
|
||||||
|
$count = 0;
|
||||||
|
/** @var TransactionJournal $journal */
|
||||||
|
foreach ($this->journals as $journal) {
|
||||||
|
$this->exportEntries->push(Entry::fromJournal($journal));
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function createConfigFile(): bool
|
||||||
|
{
|
||||||
|
$this->configurationMaker = app(ConfigurationFile::class, [$this->job]);
|
||||||
|
$this->files->push($this->configurationMaker->make());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
* @throws FireflyException
|
||||||
|
*/
|
||||||
|
public function createZipFile(): bool
|
||||||
|
{
|
||||||
|
$zip = new ZipArchive;
|
||||||
|
$file = $this->job->key . '.zip';
|
||||||
|
$fullPath = storage_path('export') . '/' . $file;
|
||||||
|
|
||||||
|
if ($zip->open($fullPath, ZipArchive::CREATE) !== true) {
|
||||||
|
throw new FireflyException('Cannot store zip file.');
|
||||||
|
}
|
||||||
|
// for each file in the collection, add it to the zip file.
|
||||||
|
$disk = Storage::disk('export');
|
||||||
|
foreach ($this->getFiles() as $entry) {
|
||||||
|
// is part of this job?
|
||||||
|
$zipFileName = str_replace($this->job->key . '-', '', $entry);
|
||||||
|
$zip->addFromString($zipFileName, $disk->get($entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
$zip->close();
|
||||||
|
|
||||||
|
// delete the files:
|
||||||
|
$this->deleteFiles($disk);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function exportJournals(): bool
|
||||||
|
{
|
||||||
|
$exporterClass = config('firefly.export_formats.' . $this->exportFormat);
|
||||||
|
$exporter = app($exporterClass, [$this->job]);
|
||||||
|
$exporter->setEntries($this->exportEntries);
|
||||||
|
$exporter->run();
|
||||||
|
$this->files->push($exporter->getFileName());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getFiles(): Collection
|
||||||
|
{
|
||||||
|
return $this->files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param FilesystemAdapter $disk
|
||||||
|
*/
|
||||||
|
private function deleteFiles(FilesystemAdapter $disk)
|
||||||
|
{
|
||||||
|
foreach ($this->getFiles() as $file) {
|
||||||
|
$disk->delete($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AccountChartGeneratorInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Chart\Account;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface AccountChartGeneratorInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Account
|
||||||
|
*/
|
||||||
|
interface AccountChartGeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function frontpage(Collection $accounts, Carbon $start, Carbon $end): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param array $labels
|
||||||
|
* @param array $dataSet
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function single(Account $account, array $labels, array $dataSet): array;
|
||||||
|
}
|
||||||
107
app/Generator/Chart/Account/ChartJsAccountChartGenerator.php
Normal file
107
app/Generator/Chart/Account/ChartJsAccountChartGenerator.php
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ChartJsAccountChartGenerator.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Generator\Chart\Account;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ChartJsAccountChartGenerator
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Account
|
||||||
|
*/
|
||||||
|
class ChartJsAccountChartGenerator implements AccountChartGeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'count' => 1,
|
||||||
|
'labels' => [], 'datasets' => [[
|
||||||
|
'label' => trans('firefly.spent'),
|
||||||
|
'data' => []]]];
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
if ($account->difference > 0) {
|
||||||
|
$data['labels'][] = $account->name;
|
||||||
|
$data['datasets'][0]['data'][] = $account->difference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function frontpage(Collection $accounts, Carbon $start, Carbon $end): array
|
||||||
|
{
|
||||||
|
// language:
|
||||||
|
$format = (string)trans('config.month_and_day');
|
||||||
|
$data = ['count' => 0, 'labels' => [], 'datasets' => [],];
|
||||||
|
$current = clone $start;
|
||||||
|
while ($current <= $end) {
|
||||||
|
$data['labels'][] = $current->formatLocalized($format);
|
||||||
|
$current->addDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$data['datasets'][] = [
|
||||||
|
'label' => $account->name,
|
||||||
|
'fillColor' => 'rgba(220,220,220,0.2)',
|
||||||
|
'strokeColor' => 'rgba(220,220,220,1)',
|
||||||
|
'pointColor' => 'rgba(220,220,220,1)',
|
||||||
|
'pointStrokeColor' => '#fff',
|
||||||
|
'pointHighlightFill' => '#fff',
|
||||||
|
'pointHighlightStroke' => 'rgba(220,220,220,1)',
|
||||||
|
'data' => $account->balances,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$data['count'] = count($data['datasets']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param array $labels
|
||||||
|
* @param array $dataSet
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function single(Account $account, array $labels, array $dataSet): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'count' => 1,
|
||||||
|
'labels' => $labels,
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => $account->name,
|
||||||
|
'data' => $dataSet,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
42
app/Generator/Chart/Bill/BillChartGeneratorInterface.php
Normal file
42
app/Generator/Chart/Bill/BillChartGeneratorInterface.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BillChartGeneratorInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Chart\Bill;
|
||||||
|
|
||||||
|
|
||||||
|
use FireflyIII\Models\Bill;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface BillChartGeneratorInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Bill
|
||||||
|
*/
|
||||||
|
interface BillChartGeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $paid
|
||||||
|
* @param string $unpaid
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function frontpage(string $paid, string $unpaid): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Bill $bill
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function single(Bill $bill, Collection $entries): array;
|
||||||
|
|
||||||
|
}
|
||||||
91
app/Generator/Chart/Bill/ChartJsBillChartGenerator.php
Normal file
91
app/Generator/Chart/Bill/ChartJsBillChartGenerator.php
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ChartJsBillChartGenerator.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Chart\Bill;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Bill;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ChartJsBillChartGenerator
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Bill
|
||||||
|
*/
|
||||||
|
class ChartJsBillChartGenerator implements BillChartGeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $paid
|
||||||
|
* @param string $unpaid
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function frontpage(string $paid, string $unpaid): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'data' => [round($unpaid, 2), round(bcmul($paid, '-1'), 2)],
|
||||||
|
'backgroundColor' => ['rgba(53, 124, 165,0.7)', 'rgba(0, 141, 76, 0.7)',],
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
'labels' => [strval(trans('firefly.unpaid')), strval(trans('firefly.paid'))],
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Bill $bill
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function single(Bill $bill, Collection $entries): array
|
||||||
|
{
|
||||||
|
$format = (string)trans('config.month');
|
||||||
|
$data = ['count' => 3, 'labels' => [], 'datasets' => [],];
|
||||||
|
$minAmount = [];
|
||||||
|
$maxAmount = [];
|
||||||
|
$actualAmount = [];
|
||||||
|
/** @var TransactionJournal $entry */
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$data['labels'][] = $entry->date->formatLocalized($format);
|
||||||
|
$minAmount[] = round($bill->amount_min, 2);
|
||||||
|
$maxAmount[] = round($bill->amount_max, 2);
|
||||||
|
// journalAmount has been collected in BillRepository::getJournals
|
||||||
|
$actualAmount[] = round(TransactionJournal::amountPositive($entry), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['datasets'][] = [
|
||||||
|
'type' => 'bar',
|
||||||
|
'label' => trans('firefly.minAmount'),
|
||||||
|
'data' => $minAmount,
|
||||||
|
];
|
||||||
|
$data['datasets'][] = [
|
||||||
|
'type' => 'line',
|
||||||
|
'label' => trans('firefly.billEntry'),
|
||||||
|
'data' => $actualAmount,
|
||||||
|
];
|
||||||
|
$data['datasets'][] = [
|
||||||
|
'type' => 'bar',
|
||||||
|
'label' => trans('firefly.maxAmount'),
|
||||||
|
'data' => $maxAmount,
|
||||||
|
];
|
||||||
|
|
||||||
|
$data['count'] = count($data['datasets']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
62
app/Generator/Chart/Budget/BudgetChartGeneratorInterface.php
Normal file
62
app/Generator/Chart/Budget/BudgetChartGeneratorInterface.php
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BudgetChartGeneratorInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Chart\Budget;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface BudgetChartGeneratorInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Budget
|
||||||
|
*/
|
||||||
|
interface BudgetChartGeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
* @param string $dateFormat
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function budgetLimit(Collection $entries, string $dateFormat): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function frontpage(Collection $entries): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYear(Collection $entries): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
* @param string $viewRange
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function period(Collection $entries, string $viewRange) : array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function year(Collection $budgets, Collection $entries): array;
|
||||||
|
|
||||||
|
}
|
||||||
208
app/Generator/Chart/Budget/ChartJsBudgetChartGenerator.php
Normal file
208
app/Generator/Chart/Budget/ChartJsBudgetChartGenerator.php
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ChartJsBudgetChartGenerator.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Generator\Chart\Budget;
|
||||||
|
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Navigation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ChartJsBudgetChartGenerator
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Budget
|
||||||
|
*/
|
||||||
|
class ChartJsBudgetChartGenerator implements BudgetChartGeneratorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Collection $entries
|
||||||
|
* @param string $dateFormat
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function budgetLimit(Collection $entries, string $dateFormat = 'month_and_day'): array
|
||||||
|
{
|
||||||
|
$format = strval(trans('config.' . $dateFormat));
|
||||||
|
$data = [
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => 'Amount',
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var array $entry */
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$data['labels'][] = $entry[0]->formatLocalized($format);
|
||||||
|
$data['datasets'][0]['data'][] = $entry[1];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['count'] = count($data['datasets']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function frontpage(Collection $entries): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'count' => 0,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [],
|
||||||
|
];
|
||||||
|
$left = [];
|
||||||
|
$spent = [];
|
||||||
|
$overspent = [];
|
||||||
|
$filtered = $entries->filter(
|
||||||
|
function ($entry) {
|
||||||
|
return ($entry[1] != 0 || $entry[2] != 0 || $entry[3] != 0);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
foreach ($filtered as $entry) {
|
||||||
|
$data['labels'][] = $entry[0];
|
||||||
|
$left[] = round($entry[1], 2);
|
||||||
|
$spent[] = round(bcmul($entry[2], '-1'), 2); // spent is coming in negative, must be positive
|
||||||
|
$overspent[] = round(bcmul($entry[3], '-1'), 2); // same
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['datasets'][] = [
|
||||||
|
'label' => trans('firefly.overspent'),
|
||||||
|
'data' => $overspent,
|
||||||
|
];
|
||||||
|
$data['datasets'][] = [
|
||||||
|
'label' => trans('firefly.left'),
|
||||||
|
'data' => $left,
|
||||||
|
];
|
||||||
|
$data['datasets'][] = [
|
||||||
|
'label' => trans('firefly.spent'),
|
||||||
|
'data' => $spent,
|
||||||
|
];
|
||||||
|
|
||||||
|
$data['count'] = 3;
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYear(Collection $entries): array
|
||||||
|
{
|
||||||
|
// dataset:
|
||||||
|
$data = [
|
||||||
|
'count' => 0,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [],
|
||||||
|
];
|
||||||
|
// get labels from one of the budgets (assuming there's at least one):
|
||||||
|
$first = $entries->first();
|
||||||
|
$keys = array_keys($first['budgeted']);
|
||||||
|
foreach ($keys as $year) {
|
||||||
|
$data['labels'][] = strval($year);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then, loop all entries and create datasets:
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$name = $entry['name'];
|
||||||
|
$spent = $entry['spent'];
|
||||||
|
$budgeted = $entry['budgeted'];
|
||||||
|
$data['datasets'][] = ['label' => 'Spent on ' . $name, 'data' => array_values($spent)];
|
||||||
|
$data['datasets'][] = ['label' => 'Budgeted for ' . $name, 'data' => array_values($budgeted)];
|
||||||
|
}
|
||||||
|
$data['count'] = count($data['datasets']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
* @param string $viewRange
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function period(Collection $entries, string $viewRange) : array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [
|
||||||
|
0 => [
|
||||||
|
'label' => trans('firefly.budgeted'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
1 => [
|
||||||
|
'label' => trans('firefly.spent'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'count' => 2,
|
||||||
|
];
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$label = Navigation::periodShow($entry['date'], $viewRange);
|
||||||
|
$data['labels'][] = $label;
|
||||||
|
// data set 0 is budgeted
|
||||||
|
// data set 1 is spent:
|
||||||
|
$data['datasets'][0]['data'][] = $entry['budgeted'];
|
||||||
|
$data['datasets'][1]['data'][] = round(($entry['spent'] * -1), 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $budgets
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function year(Collection $budgets, Collection $entries): array
|
||||||
|
{
|
||||||
|
// language:
|
||||||
|
$format = (string)trans('config.month');
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($budgets as $budget) {
|
||||||
|
$data['labels'][] = $budget->name;
|
||||||
|
}
|
||||||
|
// also add "no budget"
|
||||||
|
$data['labels'][] = strval(trans('firefly.no_budget'));
|
||||||
|
|
||||||
|
/** @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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* CategoryChartGeneratorInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Chart\Category;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface CategoryChartGeneratorInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Category
|
||||||
|
*/
|
||||||
|
interface CategoryChartGeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function all(Collection $entries): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function earnedInPeriod(Collection $categories, Collection $entries): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function frontpage(Collection $entries): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYear(Collection $entries): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function period(Collection $entries): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function spentInPeriod(Collection $categories, Collection $entries): array;
|
||||||
|
}
|
||||||
190
app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php
Normal file
190
app/Generator/Chart/Category/ChartJsCategoryChartGenerator.php
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ChartJsCategoryChartGenerator.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Generator\Chart\Category;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ChartJsCategoryChartGenerator
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Category
|
||||||
|
*/
|
||||||
|
class ChartJsCategoryChartGenerator implements CategoryChartGeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function all(Collection $entries): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'count' => 2,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.spent'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.earned'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$data['labels'][] = $entry[1];
|
||||||
|
$spent = $entry[2];
|
||||||
|
$earned = $entry[3];
|
||||||
|
|
||||||
|
$data['datasets'][0]['data'][] = bccomp($spent, '0') === 0 ? null : round(bcmul($spent, '-1'), 4);
|
||||||
|
$data['datasets'][1]['data'][] = bccomp($earned, '0') === 0 ? null : round($earned, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function earnedInPeriod(Collection $categories, Collection $entries): array
|
||||||
|
{
|
||||||
|
|
||||||
|
// language:
|
||||||
|
$format = (string)trans('config.month');
|
||||||
|
|
||||||
|
$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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function frontpage(Collection $entries): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'count' => 1,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.spent'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
if ($entry->spent != 0) {
|
||||||
|
$data['labels'][] = $entry->name;
|
||||||
|
$data['datasets'][0]['data'][] = round(bcmul($entry->spent, '-1'), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYear(Collection $entries): array
|
||||||
|
{
|
||||||
|
// get labels from one of the categories (assuming there's at least one):
|
||||||
|
$first = $entries->first();
|
||||||
|
$data = ['count' => 0, 'labels' => array_keys($first['spent']), 'datasets' => [],];
|
||||||
|
|
||||||
|
// then, loop all entries and create datasets:
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$name = $entry['name'];
|
||||||
|
$spent = $entry['spent'];
|
||||||
|
$earned = $entry['earned'];
|
||||||
|
if (array_sum(array_values($spent)) != 0) {
|
||||||
|
$data['datasets'][] = ['label' => 'Spent in category ' . $name, 'data' => array_values($spent)];
|
||||||
|
}
|
||||||
|
if (array_sum(array_values($earned)) != 0) {
|
||||||
|
$data['datasets'][] = ['label' => 'Earned in category ' . $name, 'data' => array_values($earned)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data['count'] = count($data['datasets']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function period(Collection $entries): array
|
||||||
|
{
|
||||||
|
return $this->all($entries);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $categories
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function spentInPeriod(Collection $categories, Collection $entries): array
|
||||||
|
{
|
||||||
|
|
||||||
|
// language:
|
||||||
|
$format = (string)trans('config.month');
|
||||||
|
|
||||||
|
$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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ChartJsPiggyBankChartGenerator.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Generator\Chart\PiggyBank;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ChartJsPiggyBankChartGenerator
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\PiggyBank
|
||||||
|
*/
|
||||||
|
class ChartJsPiggyBankChartGenerator implements PiggyBankChartGeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $set
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function history(Collection $set): array
|
||||||
|
{
|
||||||
|
|
||||||
|
// language:
|
||||||
|
$format = (string)trans('config.month_and_day');
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'count' => 1,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => 'Diff',
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$sum = '0';
|
||||||
|
foreach ($set as $key => $value) {
|
||||||
|
$date = new Carbon($key);
|
||||||
|
$sum = bcadd($sum, $value);
|
||||||
|
$data['labels'][] = $date->formatLocalized($format);
|
||||||
|
$data['datasets'][0]['data'][] = round($sum, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PiggyBankChartGeneratorInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Chart\PiggyBank;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface PiggyBankChartGeneratorInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\PiggyBank
|
||||||
|
*/
|
||||||
|
interface PiggyBankChartGeneratorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Collection $set
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function history(Collection $set): array;
|
||||||
|
}
|
||||||
178
app/Generator/Chart/Report/ChartJsReportChartGenerator.php
Normal file
178
app/Generator/Chart/Report/ChartJsReportChartGenerator.php
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ChartJsReportChartGenerator.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Generator\Chart\Report;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ChartJsReportChartGenerator
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Report
|
||||||
|
*/
|
||||||
|
class ChartJsReportChartGenerator implements ReportChartGeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as above but other translations.
|
||||||
|
*
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYearInOut(Collection $entries): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'count' => 2,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.income'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.expenses'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$data['labels'][] = $entry[0]->formatLocalized('%Y');
|
||||||
|
$data['datasets'][0]['data'][] = round($entry[1], 2);
|
||||||
|
$data['datasets'][1]['data'][] = round($entry[2], 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $income
|
||||||
|
* @param string $expense
|
||||||
|
* @param int $count
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYearInOutSummarized(string $income, string $expense, int $count): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'count' => 2,
|
||||||
|
'labels' => [trans('firefly.sum_of_years'), trans('firefly.average_of_years')],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.income'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.expenses'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$data['datasets'][0]['data'][] = round($income, 2);
|
||||||
|
$data['datasets'][1]['data'][] = round($expense, 2);
|
||||||
|
$data['datasets'][0]['data'][] = round(($income / $count), 2);
|
||||||
|
$data['datasets'][1]['data'][] = round(($expense / $count), 2);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function netWorth(Collection $entries) : array
|
||||||
|
{
|
||||||
|
$format = (string)trans('config.month_and_day');
|
||||||
|
$data = [
|
||||||
|
'count' => 1,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.net_worth'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$data['labels'][] = trim($entry['date']->formatLocalized($format));
|
||||||
|
$data['datasets'][0]['data'][] = round($entry['net-worth'], 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function yearInOut(Collection $entries): array
|
||||||
|
{
|
||||||
|
// language:
|
||||||
|
$format = (string)trans('config.month');
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'count' => 2,
|
||||||
|
'labels' => [],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.income'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.expenses'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$data['labels'][] = $entry[0]->formatLocalized($format);
|
||||||
|
$data['datasets'][0]['data'][] = round($entry[1], 2);
|
||||||
|
$data['datasets'][1]['data'][] = round($entry[2], 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $income
|
||||||
|
* @param string $expense
|
||||||
|
* @param int $count
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function yearInOutSummarized(string $income, string $expense, int $count): array
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'count' => 2,
|
||||||
|
'labels' => [trans('firefly.sum_of_year'), trans('firefly.average_of_year')],
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.income'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => trans('firefly.expenses'),
|
||||||
|
'data' => [],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$data['datasets'][0]['data'][] = round($income, 2);
|
||||||
|
$data['datasets'][1]['data'][] = round($expense, 2);
|
||||||
|
$data['datasets'][0]['data'][] = round(($income / $count), 2);
|
||||||
|
$data['datasets'][1]['data'][] = round(($expense / $count), 2);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
63
app/Generator/Chart/Report/ReportChartGeneratorInterface.php
Normal file
63
app/Generator/Chart/Report/ReportChartGeneratorInterface.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ReportChartGeneratorInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Generator\Chart\Report;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface ReportChartGeneratorInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Generator\Chart\Report
|
||||||
|
*/
|
||||||
|
interface ReportChartGeneratorInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYearInOut(Collection $entries): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $income
|
||||||
|
* @param string $expense
|
||||||
|
* @param int $count
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function multiYearInOutSummarized(string $income, string $expense, int $count): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function netWorth(Collection $entries) : array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $entries
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function yearInOut(Collection $entries): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $income
|
||||||
|
* @param string $expense
|
||||||
|
* @param int $count
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function yearInOutSummarized(string $income, string $expense, int $count): array;
|
||||||
|
|
||||||
|
}
|
||||||
50
app/Handlers/Events/AttachUserRole.php
Normal file
50
app/Handlers/Events/AttachUserRole.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AttachUserRole.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use FireflyIII\Events\UserRegistration;
|
||||||
|
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AttachUserRole
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class AttachUserRole
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param UserRegistration $event
|
||||||
|
*/
|
||||||
|
public function handle(UserRegistration $event)
|
||||||
|
{
|
||||||
|
/** @var UserRepositoryInterface $repository */
|
||||||
|
$repository = app(UserRepositoryInterface::class);
|
||||||
|
|
||||||
|
// first user ever?
|
||||||
|
if ($repository->count() == 1) {
|
||||||
|
$repository->attachRole($event->user, 'owner');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
107
app/Handlers/Events/BudgetLimitEventHandler.php
Normal file
107
app/Handlers/Events/BudgetLimitEventHandler.php
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BudgetLimitEventHandler.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
use FireflyIII\Events\BudgetLimitStored;
|
||||||
|
use FireflyIII\Events\BudgetLimitUpdated;
|
||||||
|
use FireflyIII\Models\LimitRepetition;
|
||||||
|
use Illuminate\Database\QueryException;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BudgetLimitEventHandler
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class BudgetLimitEventHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In a perfect world, the store() routine should be different from the update()
|
||||||
|
* routine. It would not have to check count() == 0 because there could be NO
|
||||||
|
* limit repetitions at this point. However, the database can be wrong so we check.
|
||||||
|
*
|
||||||
|
* @param BudgetLimitStored $event
|
||||||
|
*/
|
||||||
|
public function store(BudgetLimitStored $event)
|
||||||
|
{
|
||||||
|
$budgetLimit = $event->budgetLimit;
|
||||||
|
$end = $event->end;
|
||||||
|
$set = $budgetLimit->limitrepetitions()
|
||||||
|
->where('startdate', $budgetLimit->startdate->format('Y-m-d 00:00:00'))
|
||||||
|
->where('enddate', $end->format('Y-m-d 00:00:00'))
|
||||||
|
->get();
|
||||||
|
if ($set->count() == 0) {
|
||||||
|
$repetition = new LimitRepetition;
|
||||||
|
$repetition->startdate = $budgetLimit->startdate;
|
||||||
|
$repetition->enddate = $end;
|
||||||
|
$repetition->amount = $budgetLimit->amount;
|
||||||
|
$repetition->budgetLimit()->associate($budgetLimit);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$repetition->save();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Log::error('Trying to save new LimitRepetition failed: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($set->count() == 1) {
|
||||||
|
$repetition = $set->first();
|
||||||
|
$repetition->amount = $budgetLimit->amount;
|
||||||
|
$repetition->save();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BudgetLimitUpdated $event
|
||||||
|
*/
|
||||||
|
public function update(BudgetLimitUpdated $event)
|
||||||
|
{
|
||||||
|
$budgetLimit = $event->budgetLimit;
|
||||||
|
$end = $event->end;
|
||||||
|
$set = $budgetLimit->limitrepetitions()
|
||||||
|
->where('startdate', $budgetLimit->startdate->format('Y-m-d 00:00:00'))
|
||||||
|
->where('enddate', $end->format('Y-m-d 00:00:00'))
|
||||||
|
->get();
|
||||||
|
if ($set->count() == 0) {
|
||||||
|
$repetition = new LimitRepetition;
|
||||||
|
$repetition->startdate = $budgetLimit->startdate;
|
||||||
|
$repetition->enddate = $end;
|
||||||
|
$repetition->amount = $budgetLimit->amount;
|
||||||
|
$repetition->budgetLimit()->associate($budgetLimit);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$repetition->save();
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
Log::error('Trying to save new LimitRepetition failed: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($set->count() == 1) {
|
||||||
|
$repetition = $set->first();
|
||||||
|
$repetition->amount = $budgetLimit->amount;
|
||||||
|
$repetition->save();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
71
app/Handlers/Events/ConnectJournalToPiggyBank.php
Normal file
71
app/Handlers/Events/ConnectJournalToPiggyBank.php
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ConnectJournalToPiggyBank.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use FireflyIII\Events\TransactionJournalStored;
|
||||||
|
use FireflyIII\Models\PiggyBank;
|
||||||
|
use FireflyIII\Models\PiggyBankEvent;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ConnectJournalToPiggyBank
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class ConnectJournalToPiggyBank
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect a new transaction journal to any related piggy banks.
|
||||||
|
*
|
||||||
|
* @param TransactionJournalStored $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function handle(TransactionJournalStored $event): bool
|
||||||
|
{
|
||||||
|
/** @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 true;
|
||||||
|
}
|
||||||
|
// update piggy bank rep for date of transaction journal.
|
||||||
|
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
|
||||||
|
if (is_null($repetition)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = TransactionJournal::amountPositive($journal);
|
||||||
|
// if piggy account matches source account, the amount is positive
|
||||||
|
$sources = TransactionJournal::sourceAccountList($journal)->pluck('id')->toArray();
|
||||||
|
if (in_array($piggyBank->account_id, $sources)) {
|
||||||
|
$amount = bcmul($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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
68
app/Handlers/Events/ConnectTransactionToPiggyBank.php
Normal file
68
app/Handlers/Events/ConnectTransactionToPiggyBank.php
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ConnectTransactionToPiggyBank.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
use FireflyIII\Events\TransactionStored;
|
||||||
|
use FireflyIII\Models\PiggyBankEvent;
|
||||||
|
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ConnectTransactionToPiggyBank
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class ConnectTransactionToPiggyBank
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect a new transaction journal to any related piggy banks.
|
||||||
|
*
|
||||||
|
* @param TransactionStored $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function handle(TransactionStored $event): bool
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var PiggyBankRepositoryInterface $repository */
|
||||||
|
$repository = app(PiggyBankRepositoryInterface::class);
|
||||||
|
$transaction = $event->transaction;
|
||||||
|
|
||||||
|
$piggyBank = $repository->find($transaction['piggy_bank_id']);
|
||||||
|
|
||||||
|
// valid piggy:
|
||||||
|
if (is_null($piggyBank->id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$amount = strval($transaction['amount']);
|
||||||
|
// piggy bank account something with amount:
|
||||||
|
if ($transaction['source_account_id'] == $piggyBank->account_id) {
|
||||||
|
// if the source of this transaction is the same as the piggy bank,
|
||||||
|
// the money is being removed from the piggy bank. So the
|
||||||
|
// amount must be negative:
|
||||||
|
$amount = bcmul($amount, '-1');
|
||||||
|
}
|
||||||
|
|
||||||
|
$repetition = $piggyBank->currentRelevantRep();
|
||||||
|
// add or remove the money from the piggy bank:
|
||||||
|
$newAmount = bcadd(strval($repetition->currentamount), $amount);
|
||||||
|
$repetition->currentamount = $newAmount;
|
||||||
|
$repetition->save();
|
||||||
|
|
||||||
|
// now generate a piggy bank event:
|
||||||
|
PiggyBankEvent::create(['piggy_bank_id' => $piggyBank->id, 'date' => $transaction['date'], 'amount' => $newAmount]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
67
app/Handlers/Events/FireRulesForStore.php
Normal file
67
app/Handlers/Events/FireRulesForStore.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* FireRulesForStore.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use FireflyIII\Events\TransactionJournalStored;
|
||||||
|
use FireflyIII\Models\Rule;
|
||||||
|
use FireflyIII\Models\RuleGroup;
|
||||||
|
use FireflyIII\Rules\Processor;
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FireRulesForStore
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class FireRulesForStore
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect a new transaction journal to any related piggy banks.
|
||||||
|
*
|
||||||
|
* @param TransactionJournalStored $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function handle(TransactionJournalStored $event): bool
|
||||||
|
{
|
||||||
|
// get all the user's rule groups, with the rules, order by 'order'.
|
||||||
|
/** @var User $user */
|
||||||
|
$user = Auth::user();
|
||||||
|
$groups = $user->ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get();
|
||||||
|
//
|
||||||
|
/** @var RuleGroup $group */
|
||||||
|
foreach ($groups as $group) {
|
||||||
|
$rules = $group->rules()
|
||||||
|
->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id')
|
||||||
|
->where('rule_triggers.trigger_type', 'user_action')
|
||||||
|
->where('rule_triggers.trigger_value', 'store-journal')
|
||||||
|
->where('rules.active', 1)
|
||||||
|
->get(['rules.*']);
|
||||||
|
/** @var Rule $rule */
|
||||||
|
foreach ($rules as $rule) {
|
||||||
|
|
||||||
|
$processor = Processor::make($rule);
|
||||||
|
$processor->handleTransactionJournal($event->journal);
|
||||||
|
|
||||||
|
if ($rule->stop_processing) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
64
app/Handlers/Events/FireRulesForUpdate.php
Normal file
64
app/Handlers/Events/FireRulesForUpdate.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* FireRulesForUpdate.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use FireflyIII\Events\TransactionJournalUpdated;
|
||||||
|
use FireflyIII\Models\Rule;
|
||||||
|
use FireflyIII\Models\RuleGroup;
|
||||||
|
use FireflyIII\Rules\Processor;
|
||||||
|
use FireflyIII\User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FireRulesForUpdate
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class FireRulesForUpdate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param TransactionJournalUpdated $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function handle(TransactionJournalUpdated $event): bool
|
||||||
|
{
|
||||||
|
// get all the user's rule groups, with the rules, order by 'order'.
|
||||||
|
/** @var User $user */
|
||||||
|
$user = Auth::user();
|
||||||
|
$groups = $user->ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get();
|
||||||
|
//
|
||||||
|
/** @var RuleGroup $group */
|
||||||
|
foreach ($groups as $group) {
|
||||||
|
$rules = $group->rules()
|
||||||
|
->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id')
|
||||||
|
->where('rule_triggers.trigger_type', 'user_action')
|
||||||
|
->where('rule_triggers.trigger_value', 'update-journal')
|
||||||
|
->where('rules.active', 1)
|
||||||
|
->get(['rules.*']);
|
||||||
|
/** @var Rule $rule */
|
||||||
|
foreach ($rules as $rule) {
|
||||||
|
$processor = Processor::make($rule);
|
||||||
|
$processor->handleTransactionJournal($event->journal);
|
||||||
|
|
||||||
|
if ($rule->stop_processing) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
app/Handlers/Events/ScanForBillsAfterStore.php
Normal file
40
app/Handlers/Events/ScanForBillsAfterStore.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ScanForBillsAfterStore.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
use FireflyIII\Events\TransactionJournalStored;
|
||||||
|
use FireflyIII\Support\Events\BillScanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class RescanJournal
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class ScanForBillsAfterStore
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan a transaction journal for possible links to bills, right after storing.
|
||||||
|
*
|
||||||
|
* @param TransactionJournalStored $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function handle(TransactionJournalStored $event): bool
|
||||||
|
{
|
||||||
|
$journal = $event->journal;
|
||||||
|
BillScanner::scan($journal);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
app/Handlers/Events/ScanForBillsAfterUpdate.php
Normal file
39
app/Handlers/Events/ScanForBillsAfterUpdate.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ScanForBillsAfterUpdate.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
use FireflyIII\Events\TransactionJournalUpdated;
|
||||||
|
use FireflyIII\Support\Events\BillScanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class RescanJournal
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class ScanForBillsAfterUpdate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Scan a transaction journal for possibly related bills after it has been updated.
|
||||||
|
*
|
||||||
|
* @param TransactionJournalUpdated $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function handle(TransactionJournalUpdated $event): bool
|
||||||
|
{
|
||||||
|
$journal = $event->journal;
|
||||||
|
BillScanner::scan($journal);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
67
app/Handlers/Events/SendRegistrationMail.php
Normal file
67
app/Handlers/Events/SendRegistrationMail.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SendRegistrationMail.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use FireflyIII\Events\UserRegistration;
|
||||||
|
use Illuminate\Mail\Message;
|
||||||
|
use Log;
|
||||||
|
use Mail;
|
||||||
|
use Swift_TransportException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SendRegistrationMail
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class SendRegistrationMail
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param UserRegistration $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function handle(UserRegistration $event): bool
|
||||||
|
{
|
||||||
|
$sendMail = env('SEND_REGISTRATION_MAIL', true);
|
||||||
|
if (!$sendMail) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// get the email address
|
||||||
|
$email = $event->user->email;
|
||||||
|
$address = route('index');
|
||||||
|
$ipAddress = $event->ipAddress;
|
||||||
|
// send email.
|
||||||
|
try {
|
||||||
|
Mail::send(
|
||||||
|
['emails.registered-html', 'emails.registered'], ['address' => $address, 'ip' => $ipAddress], function (Message $message) use ($email) {
|
||||||
|
$message->to($email, $email)->subject('Welcome to Firefly III! ');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (Swift_TransportException $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
72
app/Handlers/Events/UpdateJournalConnection.php
Normal file
72
app/Handlers/Events/UpdateJournalConnection.php
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* UpdateJournalConnection.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
use FireflyIII\Events\TransactionJournalUpdated;
|
||||||
|
use FireflyIII\Models\PiggyBankEvent;
|
||||||
|
use FireflyIII\Models\PiggyBankRepetition;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UpdateJournalConnection
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class UpdateJournalConnection
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param TransactionJournalUpdated $event
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly 5.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function handle(TransactionJournalUpdated $event):bool
|
||||||
|
{
|
||||||
|
$journal = $event->journal;
|
||||||
|
|
||||||
|
if (!$journal->isTransfer()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the event connected to this journal:
|
||||||
|
/** @var PiggyBankEvent $event */
|
||||||
|
$event = PiggyBankEvent::where('transaction_journal_id', $journal->id)->first();
|
||||||
|
if (is_null($event)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$piggyBank = $event->piggyBank()->first();
|
||||||
|
$repetition = null;
|
||||||
|
if (!is_null($piggyBank)) {
|
||||||
|
/** @var PiggyBankRepetition $repetition */
|
||||||
|
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($repetition)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = TransactionJournal::amount($journal);
|
||||||
|
$diff = bcsub($amount, $event->amount); // update current repetition
|
||||||
|
|
||||||
|
$repetition->currentamount = bcadd($repetition->currentamount, $diff);
|
||||||
|
$repetition->save();
|
||||||
|
|
||||||
|
|
||||||
|
$event->amount = $amount;
|
||||||
|
$event->save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
107
app/Handlers/Events/UserConfirmation.php
Normal file
107
app/Handlers/Events/UserConfirmation.php
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* UserConfirmation.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use FireflyIII\Events\ResendConfirmation;
|
||||||
|
use FireflyIII\Events\UserRegistration;
|
||||||
|
use FireflyIII\User;
|
||||||
|
use Illuminate\Mail\Message;
|
||||||
|
use Log;
|
||||||
|
use Mail;
|
||||||
|
use Preferences;
|
||||||
|
use Swift_TransportException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UserConfirmation
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class UserConfirmation
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ResendConfirmation $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function resendConfirmation(ResendConfirmation $event): bool
|
||||||
|
{
|
||||||
|
$user = $event->user;
|
||||||
|
$ipAddress = $event->ipAddress;
|
||||||
|
$this->doConfirm($user, $ipAddress);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param UserRegistration $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function sendConfirmation(UserRegistration $event): bool
|
||||||
|
{
|
||||||
|
$user = $event->user;
|
||||||
|
$ipAddress = $event->ipAddress;
|
||||||
|
$this->doConfirm($user, $ipAddress);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User $user
|
||||||
|
* @param string $ipAddress
|
||||||
|
*/
|
||||||
|
private function doConfirm(User $user, string $ipAddress)
|
||||||
|
{
|
||||||
|
$confirmAccount = env('MUST_CONFIRM_ACCOUNT', false);
|
||||||
|
if ($confirmAccount === false) {
|
||||||
|
Preferences::setForUser($user, 'user_confirmed', true);
|
||||||
|
Preferences::setForUser($user, 'user_confirmed_last_mail', 0);
|
||||||
|
Preferences::mark();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$email = $user->email;
|
||||||
|
$code = str_random(16);
|
||||||
|
$route = route('do_confirm_account', [$code]);
|
||||||
|
Preferences::setForUser($user, 'user_confirmed', false);
|
||||||
|
Preferences::setForUser($user, 'user_confirmed_last_mail', time());
|
||||||
|
Preferences::setForUser($user, 'user_confirmed_code', $code);
|
||||||
|
try {
|
||||||
|
Mail::send(
|
||||||
|
['emails.confirm-account-html', 'emails.confirm-account'], ['route' => $route, 'ip' => $ipAddress],
|
||||||
|
function (Message $message) use ($email) {
|
||||||
|
$message->to($email, $email)->subject('Please confirm your Firefly III account');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (Swift_TransportException $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
36
app/Handlers/Events/UserEventListener.php
Normal file
36
app/Handlers/Events/UserEventListener.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* UserEventListener.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
use Session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UserEventListener
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class UserEventListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle user logout events.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function onUserLogout(): bool
|
||||||
|
{
|
||||||
|
// dump stuff from the session:
|
||||||
|
Session::forget('twofactor-authenticated');
|
||||||
|
Session::forget('twofactor-authenticated-date');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
61
app/Handlers/Events/UserSaveIpAddress.php
Normal file
61
app/Handlers/Events/UserSaveIpAddress.php
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* UserSaveIpAddress.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Handlers\Events;
|
||||||
|
|
||||||
|
use FireflyIII\Events\UserIsConfirmed;
|
||||||
|
use FireflyIII\Events\UserRegistration;
|
||||||
|
use Preferences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class UserSaveIpAddress
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Handlers\Events
|
||||||
|
*/
|
||||||
|
class UserSaveIpAddress
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param UserIsConfirmed $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function saveFromConfirmation(UserIsConfirmed $event): bool
|
||||||
|
{
|
||||||
|
Preferences::setForUser($event->user, 'confirmation_ip_address', $event->ipAddress);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param UserRegistration $event
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function saveFromRegistration(UserRegistration $event): bool
|
||||||
|
{
|
||||||
|
Preferences::setForUser($event->user, 'registration_ip_address', $event->ipAddress);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
269
app/Helpers/Attachments/AttachmentHelper.php
Normal file
269
app/Helpers/Attachments/AttachmentHelper.php
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AttachmentHelper.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Attachments;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Crypt;
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\MessageBag;
|
||||||
|
use Input;
|
||||||
|
use Log;
|
||||||
|
use Storage;
|
||||||
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
use TypeError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AttachmentHelper
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Attachments
|
||||||
|
*/
|
||||||
|
class AttachmentHelper implements AttachmentHelperInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var MessageBag */
|
||||||
|
public $errors;
|
||||||
|
/** @var MessageBag */
|
||||||
|
public $messages;
|
||||||
|
/** @var array */
|
||||||
|
protected $allowedMimes;
|
||||||
|
/** @var int */
|
||||||
|
protected $maxUploadSize;
|
||||||
|
|
||||||
|
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||||
|
protected $uploadDisk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->maxUploadSize = config('firefly.maxUploadSize');
|
||||||
|
$this->allowedMimes = config('firefly.allowedMimes');
|
||||||
|
$this->errors = new MessageBag;
|
||||||
|
$this->messages = new MessageBag;
|
||||||
|
$this->uploadDisk = Storage::disk('upload');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Attachment $attachment
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAttachmentLocation(Attachment $attachment): string
|
||||||
|
{
|
||||||
|
$path = storage_path('upload') . DIRECTORY_SEPARATOR . 'at-' . $attachment->id . '.data';
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return MessageBag
|
||||||
|
*/
|
||||||
|
public function getErrors(): MessageBag
|
||||||
|
{
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return MessageBag
|
||||||
|
*/
|
||||||
|
public function getMessages(): MessageBag
|
||||||
|
{
|
||||||
|
return $this->messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Model $model
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function saveAttachmentsForModel(Model $model): bool
|
||||||
|
{
|
||||||
|
$files = $this->getFiles();
|
||||||
|
|
||||||
|
if (!is_null($files) && !is_array($files)) {
|
||||||
|
$this->processFile($files, $model);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($files)) {
|
||||||
|
$this->processFiles($files, $model);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param UploadedFile $file
|
||||||
|
* @param Model $model
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function hasFile(UploadedFile $file, Model $model): bool
|
||||||
|
{
|
||||||
|
$md5 = md5_file($file->getRealPath());
|
||||||
|
$name = $file->getClientOriginalName();
|
||||||
|
$class = get_class($model);
|
||||||
|
$count = Auth::user()->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
|
||||||
|
|
||||||
|
if ($count > 0) {
|
||||||
|
$msg = (string)trans('validation.file_already_attached', ['name' => $name]);
|
||||||
|
$this->errors->add('attachments', $msg);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param UploadedFile $file
|
||||||
|
* @param Model $model
|
||||||
|
*
|
||||||
|
* @return Attachment
|
||||||
|
*/
|
||||||
|
protected function processFile(UploadedFile $file, Model $model): Attachment
|
||||||
|
{
|
||||||
|
$validation = $this->validateUpload($file, $model);
|
||||||
|
if ($validation === false) {
|
||||||
|
return new Attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachment = new Attachment; // create Attachment object.
|
||||||
|
$attachment->user()->associate(Auth::user());
|
||||||
|
$attachment->attachable()->associate($model);
|
||||||
|
$attachment->md5 = md5_file($file->getRealPath());
|
||||||
|
$attachment->filename = $file->getClientOriginalName();
|
||||||
|
$attachment->mime = $file->getMimeType();
|
||||||
|
$attachment->size = $file->getSize();
|
||||||
|
$attachment->uploaded = 0;
|
||||||
|
$attachment->save();
|
||||||
|
|
||||||
|
$fileObject = $file->openFile('r');
|
||||||
|
$fileObject->rewind();
|
||||||
|
$content = $fileObject->fread($file->getSize());
|
||||||
|
$encrypted = Crypt::encrypt($content);
|
||||||
|
|
||||||
|
// store it:
|
||||||
|
$this->uploadDisk->put($attachment->fileName(), $encrypted);
|
||||||
|
|
||||||
|
$attachment->uploaded = 1; // update attachment
|
||||||
|
$attachment->save();
|
||||||
|
|
||||||
|
$name = e($file->getClientOriginalName()); // add message:
|
||||||
|
$msg = (string)trans('validation.file_attached', ['name' => $name]);
|
||||||
|
$this->messages->add('attachments', $msg);
|
||||||
|
|
||||||
|
// return it.
|
||||||
|
return $attachment;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param UploadedFile $file
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function validMime(UploadedFile $file): bool
|
||||||
|
{
|
||||||
|
$mime = e($file->getMimeType());
|
||||||
|
$name = e($file->getClientOriginalName());
|
||||||
|
|
||||||
|
if (!in_array($mime, $this->allowedMimes)) {
|
||||||
|
$msg = (string)trans('validation.file_invalid_mime', ['name' => $name, 'mime' => $mime]);
|
||||||
|
$this->errors->add('attachments', $msg);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param UploadedFile $file
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function validSize(UploadedFile $file): bool
|
||||||
|
{
|
||||||
|
$size = $file->getSize();
|
||||||
|
$name = e($file->getClientOriginalName());
|
||||||
|
if ($size > $this->maxUploadSize) {
|
||||||
|
$msg = (string)trans('validation.file_too_large', ['name' => $name]);
|
||||||
|
$this->errors->add('attachments', $msg);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param UploadedFile $file
|
||||||
|
* @param Model $model
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function validateUpload(UploadedFile $file, Model $model): bool
|
||||||
|
{
|
||||||
|
if (!$this->validMime($file)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!$this->validSize($file)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($this->hasFile($file, $model)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|null|UploadedFile
|
||||||
|
*/
|
||||||
|
private function getFiles()
|
||||||
|
{
|
||||||
|
$files = null;
|
||||||
|
try {
|
||||||
|
if (Input::hasFile('attachments')) {
|
||||||
|
$files = Input::file('attachments');
|
||||||
|
}
|
||||||
|
} catch (TypeError $e) {
|
||||||
|
// Log it, do nothing else.
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $files
|
||||||
|
*
|
||||||
|
* @param Model $model
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function processFiles(array $files, Model $model): bool
|
||||||
|
{
|
||||||
|
foreach ($files as $entry) {
|
||||||
|
if (!is_null($entry)) {
|
||||||
|
$this->processFile($entry, $model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
49
app/Helpers/Attachments/AttachmentHelperInterface.php
Normal file
49
app/Helpers/Attachments/AttachmentHelperInterface.php
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AttachmentHelperInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Attachments;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Attachment;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\MessageBag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface AttachmentHelperInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Attachments
|
||||||
|
*/
|
||||||
|
interface AttachmentHelperInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Attachment $attachment
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAttachmentLocation(Attachment $attachment): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return MessageBag
|
||||||
|
*/
|
||||||
|
public function getErrors(): MessageBag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return MessageBag
|
||||||
|
*/
|
||||||
|
public function getMessages(): MessageBag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Model $model
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function saveAttachmentsForModel(Model $model): bool;
|
||||||
|
|
||||||
|
}
|
||||||
105
app/Helpers/Collection/Account.php
Normal file
105
app/Helpers/Collection/Account.php
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Account.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Account
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Collection
|
||||||
|
*/
|
||||||
|
class Account
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var Collection */
|
||||||
|
protected $accounts;
|
||||||
|
/** @var string */
|
||||||
|
protected $difference = '';
|
||||||
|
/** @var string */
|
||||||
|
protected $end = '';
|
||||||
|
/** @var string */
|
||||||
|
protected $start = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Account constructor.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->accounts = new Collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getAccounts(): Collection
|
||||||
|
{
|
||||||
|
return $this->accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
*/
|
||||||
|
public function setAccounts(Collection $accounts)
|
||||||
|
{
|
||||||
|
$this->accounts = $accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDifference(): string
|
||||||
|
{
|
||||||
|
return $this->difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $difference
|
||||||
|
*/
|
||||||
|
public function setDifference(string $difference)
|
||||||
|
{
|
||||||
|
$this->difference = $difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getEnd(): string
|
||||||
|
{
|
||||||
|
return $this->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $end
|
||||||
|
*/
|
||||||
|
public function setEnd(string $end)
|
||||||
|
{
|
||||||
|
$this->end = $end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getStart(): string
|
||||||
|
{
|
||||||
|
return $this->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $start
|
||||||
|
*/
|
||||||
|
public function setStart(string $start)
|
||||||
|
{
|
||||||
|
$this->start = $start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
79
app/Helpers/Collection/Balance.php
Normal file
79
app/Helpers/Collection/Balance.php
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Balance.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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(): BalanceHeader
|
||||||
|
{
|
||||||
|
return $this->balanceHeader ?? new BalanceHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BalanceHeader $balanceHeader
|
||||||
|
*/
|
||||||
|
public function setBalanceHeader(BalanceHeader $balanceHeader)
|
||||||
|
{
|
||||||
|
$this->balanceHeader = $balanceHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getBalanceLines(): Collection
|
||||||
|
{
|
||||||
|
return $this->balanceLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $balanceLines
|
||||||
|
*/
|
||||||
|
public function setBalanceLines(Collection $balanceLines)
|
||||||
|
{
|
||||||
|
$this->balanceLines = $balanceLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
81
app/Helpers/Collection/BalanceEntry.php
Normal file
81
app/Helpers/Collection/BalanceEntry.php
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BalanceEntry.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Account as AccountModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Class BalanceEntry
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Collection
|
||||||
|
*/
|
||||||
|
class BalanceEntry
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/** @var AccountModel */
|
||||||
|
protected $account;
|
||||||
|
/** @var string */
|
||||||
|
protected $left = '0';
|
||||||
|
/** @var string */
|
||||||
|
protected $spent = '0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AccountModel
|
||||||
|
*/
|
||||||
|
public function getAccount(): AccountModel
|
||||||
|
{
|
||||||
|
return $this->account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AccountModel $account
|
||||||
|
*/
|
||||||
|
public function setAccount(AccountModel $account)
|
||||||
|
{
|
||||||
|
$this->account = $account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLeft(): string
|
||||||
|
{
|
||||||
|
return $this->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $left
|
||||||
|
*/
|
||||||
|
public function setLeft(string $left)
|
||||||
|
{
|
||||||
|
$this->left = $left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSpent(): string
|
||||||
|
{
|
||||||
|
return $this->spent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $spent
|
||||||
|
*/
|
||||||
|
public function setSpent(string $spent)
|
||||||
|
{
|
||||||
|
$this->spent = $spent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
53
app/Helpers/Collection/BalanceHeader.php
Normal file
53
app/Helpers/Collection/BalanceHeader.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BalanceHeader.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Account as AccountModel;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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(): Collection
|
||||||
|
{
|
||||||
|
return $this->accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
178
app/Helpers/Collection/BalanceLine.php
Normal file
178
app/Helpers/Collection/BalanceLine.php
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BalanceLine.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Models\Budget as BudgetModel;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 Carbon */
|
||||||
|
protected $endDate;
|
||||||
|
/** @var int */
|
||||||
|
protected $role = self::ROLE_DEFAULTROLE;
|
||||||
|
/** @var Carbon */
|
||||||
|
protected $startDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->balanceEntries = new Collection;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BalanceEntry $balanceEntry
|
||||||
|
*/
|
||||||
|
public function addBalanceEntry(BalanceEntry $balanceEntry)
|
||||||
|
{
|
||||||
|
$this->balanceEntries->push($balanceEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getBalanceEntries(): Collection
|
||||||
|
{
|
||||||
|
return $this->balanceEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $balanceEntries
|
||||||
|
*/
|
||||||
|
public function setBalanceEntries(Collection $balanceEntries)
|
||||||
|
{
|
||||||
|
$this->balanceEntries = $balanceEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return BudgetModel
|
||||||
|
*/
|
||||||
|
public function getBudget(): BudgetModel
|
||||||
|
{
|
||||||
|
return $this->budget ?? new BudgetModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BudgetModel $budget
|
||||||
|
*/
|
||||||
|
public function setBudget(BudgetModel $budget)
|
||||||
|
{
|
||||||
|
$this->budget = $budget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function getEndDate()
|
||||||
|
{
|
||||||
|
return $this->endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $endDate
|
||||||
|
*/
|
||||||
|
public function setEndDate($endDate)
|
||||||
|
{
|
||||||
|
$this->endDate = $endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getRole(): int
|
||||||
|
{
|
||||||
|
return $this->role;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $role
|
||||||
|
*/
|
||||||
|
public function setRole(int $role)
|
||||||
|
{
|
||||||
|
$this->role = $role;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function getStartDate()
|
||||||
|
{
|
||||||
|
return $this->startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $startDate
|
||||||
|
*/
|
||||||
|
public function setStartDate($startDate)
|
||||||
|
{
|
||||||
|
$this->startDate = $startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
if ($this->getBudget() instanceof BudgetModel && !is_null($this->getBudget()->id)) {
|
||||||
|
return $this->getBudget()->name;
|
||||||
|
}
|
||||||
|
if ($this->getRole() == self::ROLE_DEFAULTROLE) {
|
||||||
|
return trans('firefly.no_budget');
|
||||||
|
}
|
||||||
|
if ($this->getRole() == self::ROLE_TAGROLE) {
|
||||||
|
return trans('firefly.coveredWithTags');
|
||||||
|
}
|
||||||
|
if ($this->getRole() == self::ROLE_DIFFROLE) {
|
||||||
|
return trans('firefly.leftUnbalanced');
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 string
|
||||||
|
*/
|
||||||
|
public function leftOfRepetition(): string
|
||||||
|
{
|
||||||
|
$start = $this->budget->amount ?? '0';
|
||||||
|
/** @var BalanceEntry $balanceEntry */
|
||||||
|
foreach ($this->getBalanceEntries() as $balanceEntry) {
|
||||||
|
$start = bcadd($balanceEntry->getSpent(), $start);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $start;
|
||||||
|
}
|
||||||
|
}
|
||||||
63
app/Helpers/Collection/Bill.php
Normal file
63
app/Helpers/Collection/Bill.php
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Bill.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(): Collection
|
||||||
|
{
|
||||||
|
$set = $this->bills->sortBy(
|
||||||
|
function (BillLine $bill) {
|
||||||
|
$active = intval($bill->getBill()->active) == 0 ? 1 : 0;
|
||||||
|
$name = $bill->getBill()->name;
|
||||||
|
|
||||||
|
return $active . $name;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
152
app/Helpers/Collection/BillLine.php
Normal file
152
app/Helpers/Collection/BillLine.php
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BillLine.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Bill as BillModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private $transactionJournalId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAmount(): string
|
||||||
|
{
|
||||||
|
return $this->amount ?? '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $amount
|
||||||
|
*/
|
||||||
|
public function setAmount(string $amount)
|
||||||
|
{
|
||||||
|
$this->amount = $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return BillModel
|
||||||
|
*/
|
||||||
|
public function getBill(): BillModel
|
||||||
|
{
|
||||||
|
return $this->bill;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BillModel $bill
|
||||||
|
*/
|
||||||
|
public function setBill(BillModel $bill)
|
||||||
|
{
|
||||||
|
$this->bill = $bill;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getMax(): string
|
||||||
|
{
|
||||||
|
return $this->max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $max
|
||||||
|
*/
|
||||||
|
public function setMax(string $max)
|
||||||
|
{
|
||||||
|
$this->max = $max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getMin(): string
|
||||||
|
{
|
||||||
|
return $this->min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $min
|
||||||
|
*/
|
||||||
|
public function setMin(string $min)
|
||||||
|
{
|
||||||
|
$this->min = $min;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getTransactionJournalId(): int
|
||||||
|
{
|
||||||
|
return $this->transactionJournalId ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $transactionJournalId
|
||||||
|
*/
|
||||||
|
public function setTransactionJournalId(int $transactionJournalId)
|
||||||
|
{
|
||||||
|
$this->transactionJournalId = $transactionJournalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isActive(): bool
|
||||||
|
{
|
||||||
|
return $this->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $active
|
||||||
|
*/
|
||||||
|
public function setActive(bool $active)
|
||||||
|
{
|
||||||
|
$this->active = $active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isHit(): bool
|
||||||
|
{
|
||||||
|
return $this->hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $hit
|
||||||
|
*/
|
||||||
|
public function setHit(bool $hit)
|
||||||
|
{
|
||||||
|
$this->hit = $hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
195
app/Helpers/Collection/Budget.php
Normal file
195
app/Helpers/Collection/Budget.php
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Budget.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* @return Budget
|
||||||
|
*/
|
||||||
|
public function addBudgetLine(BudgetLine $budgetLine): Budget
|
||||||
|
{
|
||||||
|
$this->budgetLines->push($budgetLine);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $add
|
||||||
|
*
|
||||||
|
* @return Budget
|
||||||
|
*/
|
||||||
|
public function addBudgeted(string $add): Budget
|
||||||
|
{
|
||||||
|
$add = strval(round($add, 2));
|
||||||
|
$this->budgeted = bcadd($this->budgeted, $add);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $add
|
||||||
|
*
|
||||||
|
* @return Budget
|
||||||
|
*/
|
||||||
|
public function addLeft(string $add): Budget
|
||||||
|
{
|
||||||
|
$add = strval(round($add, 2));
|
||||||
|
$this->left = bcadd($this->left, $add);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $add
|
||||||
|
*
|
||||||
|
* @return Budget
|
||||||
|
*/
|
||||||
|
public function addOverspent(string $add): Budget
|
||||||
|
{
|
||||||
|
$add = strval(round($add, 2));
|
||||||
|
$this->overspent = bcadd($this->overspent, $add);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $add
|
||||||
|
*
|
||||||
|
* @return Budget
|
||||||
|
*/
|
||||||
|
public function addSpent(string $add): Budget
|
||||||
|
{
|
||||||
|
$add = strval(round($add, 2));
|
||||||
|
$this->spent = bcadd($this->spent, $add);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Support\Collection
|
||||||
|
*/
|
||||||
|
public function getBudgetLines(): Collection
|
||||||
|
{
|
||||||
|
return $this->budgetLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getBudgeted(): string
|
||||||
|
{
|
||||||
|
return $this->budgeted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $budgeted
|
||||||
|
*
|
||||||
|
* @return Budget
|
||||||
|
*/
|
||||||
|
public function setBudgeted(string $budgeted): Budget
|
||||||
|
{
|
||||||
|
$this->budgeted = $budgeted;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLeft(): string
|
||||||
|
{
|
||||||
|
return $this->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $left
|
||||||
|
*
|
||||||
|
* @return Budget
|
||||||
|
*/
|
||||||
|
public function setLeft(string $left): Budget
|
||||||
|
{
|
||||||
|
$this->left = $left;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getOverspent(): string
|
||||||
|
{
|
||||||
|
return $this->overspent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $overspent
|
||||||
|
*
|
||||||
|
* @return Budget
|
||||||
|
*/
|
||||||
|
public function setOverspent(string $overspent): Budget
|
||||||
|
{
|
||||||
|
$this->overspent = strval(round($overspent, 2));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSpent(): string
|
||||||
|
{
|
||||||
|
return $this->spent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $spent
|
||||||
|
*
|
||||||
|
* @return Budget
|
||||||
|
*/
|
||||||
|
public function setSpent(string $spent): Budget
|
||||||
|
{
|
||||||
|
$this->spent = strval(round($spent, 2));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
159
app/Helpers/Collection/BudgetLine.php
Normal file
159
app/Helpers/Collection/BudgetLine.php
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BudgetLine.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Budget as BudgetModel;
|
||||||
|
use FireflyIII\Models\LimitRepetition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Class BudgetLine
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Collection
|
||||||
|
*/
|
||||||
|
class BudgetLine
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var BudgetModel */
|
||||||
|
protected $budget;
|
||||||
|
/** @var string */
|
||||||
|
protected $budgeted = '0';
|
||||||
|
/** @var string */
|
||||||
|
protected $left = '0';
|
||||||
|
/** @var string */
|
||||||
|
protected $overspent = '0';
|
||||||
|
/** @var LimitRepetition */
|
||||||
|
protected $repetition;
|
||||||
|
/** @var string */
|
||||||
|
protected $spent = '0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return BudgetModel
|
||||||
|
*/
|
||||||
|
public function getBudget(): BudgetModel
|
||||||
|
{
|
||||||
|
return $this->budget ?? new BudgetModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BudgetModel $budget
|
||||||
|
*
|
||||||
|
* @return BudgetLine
|
||||||
|
*/
|
||||||
|
public function setBudget(BudgetModel $budget): BudgetLine
|
||||||
|
{
|
||||||
|
$this->budget = $budget;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getBudgeted(): string
|
||||||
|
{
|
||||||
|
return $this->budgeted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $budgeted
|
||||||
|
*
|
||||||
|
* @return BudgetLine
|
||||||
|
*/
|
||||||
|
public function setBudgeted(string $budgeted): BudgetLine
|
||||||
|
{
|
||||||
|
$this->budgeted = $budgeted;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLeft(): string
|
||||||
|
{
|
||||||
|
return $this->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $left
|
||||||
|
*
|
||||||
|
* @return BudgetLine
|
||||||
|
*/
|
||||||
|
public function setLeft(string $left): BudgetLine
|
||||||
|
{
|
||||||
|
$this->left = $left;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getOverspent(): string
|
||||||
|
{
|
||||||
|
return $this->overspent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $overspent
|
||||||
|
*
|
||||||
|
* @return BudgetLine
|
||||||
|
*/
|
||||||
|
public function setOverspent(string $overspent): BudgetLine
|
||||||
|
{
|
||||||
|
$this->overspent = $overspent;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return LimitRepetition
|
||||||
|
*/
|
||||||
|
public function getRepetition(): LimitRepetition
|
||||||
|
{
|
||||||
|
return $this->repetition ?? new LimitRepetition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param LimitRepetition $repetition
|
||||||
|
*
|
||||||
|
* @return BudgetLine
|
||||||
|
*/
|
||||||
|
public function setRepetition(LimitRepetition $repetition): BudgetLine
|
||||||
|
{
|
||||||
|
$this->repetition = $repetition;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSpent(): string
|
||||||
|
{
|
||||||
|
return $this->spent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $spent
|
||||||
|
*
|
||||||
|
* @return BudgetLine
|
||||||
|
*/
|
||||||
|
public function setSpent(string $spent): BudgetLine
|
||||||
|
{
|
||||||
|
$this->spent = $spent;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
84
app/Helpers/Collection/Category.php
Normal file
84
app/Helpers/Collection/Category.php
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Category.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use FireflyIII\Models\Category as CategoryModel;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
// spent is minus zero for an expense report:
|
||||||
|
if ($category->spent < 0) {
|
||||||
|
$this->categories->push($category);
|
||||||
|
$this->addTotal($category->spent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $add
|
||||||
|
*/
|
||||||
|
public function addTotal(string $add)
|
||||||
|
{
|
||||||
|
$add = strval(round($add, 2));
|
||||||
|
$this->total = bcadd($this->total, $add);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getCategories(): Collection
|
||||||
|
{
|
||||||
|
$set = $this->categories->sortBy(
|
||||||
|
function (CategoryModel $category) {
|
||||||
|
return $category->spent;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTotal(): string
|
||||||
|
{
|
||||||
|
return strval(round($this->total, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
109
app/Helpers/Collection/Expense.php
Normal file
109
app/Helpers/Collection/Expense.php
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Expense.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
// add each account individually:
|
||||||
|
$destinations = TransactionJournal::destinationTransactionList($entry);
|
||||||
|
|
||||||
|
foreach ($destinations as $transaction) {
|
||||||
|
$amount = strval($transaction->amount);
|
||||||
|
$account = $transaction->account;
|
||||||
|
if (bccomp('0', $amount) === -1) {
|
||||||
|
$amount = bcmul($amount, '-1');
|
||||||
|
}
|
||||||
|
|
||||||
|
$object = new stdClass;
|
||||||
|
$object->amount = $amount;
|
||||||
|
$object->name = $account->name;
|
||||||
|
$object->count = 1;
|
||||||
|
$object->id = $account->id;
|
||||||
|
|
||||||
|
// overrule some properties:
|
||||||
|
if ($this->expenses->has($account->id)) {
|
||||||
|
$object = $this->expenses->get($account->id);
|
||||||
|
$object->amount = bcadd($object->amount, $amount);
|
||||||
|
$object->count++;
|
||||||
|
}
|
||||||
|
$this->expenses->put($account->id, $object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $add
|
||||||
|
*/
|
||||||
|
public function addToTotal(string $add)
|
||||||
|
{
|
||||||
|
$add = strval(round($add, 2));
|
||||||
|
if (bccomp('0', $add) === -1) {
|
||||||
|
$add = bcmul($add, '-1');
|
||||||
|
}
|
||||||
|
|
||||||
|
// if amount is positive, the original transaction
|
||||||
|
// was a transfer. But since this is an expense report,
|
||||||
|
// that amount must be negative.
|
||||||
|
|
||||||
|
$this->total = bcadd($this->total, $add);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getExpenses(): Collection
|
||||||
|
{
|
||||||
|
$set = $this->expenses->sortBy(
|
||||||
|
function (stdClass $object) {
|
||||||
|
return $object->amount;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTotal(): string
|
||||||
|
{
|
||||||
|
return strval(round($this->total, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
101
app/Helpers/Collection/Income.php
Normal file
101
app/Helpers/Collection/Income.php
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Income.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Collection;
|
||||||
|
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Class Income
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Collection
|
||||||
|
*/
|
||||||
|
class Income
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var Collection */
|
||||||
|
protected $incomes;
|
||||||
|
/** @var string */
|
||||||
|
protected $total = '0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->incomes = new Collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TransactionJournal $entry
|
||||||
|
*/
|
||||||
|
public function addOrCreateIncome(TransactionJournal $entry)
|
||||||
|
{
|
||||||
|
// add each account individually:
|
||||||
|
$sources = TransactionJournal::sourceTransactionList($entry);
|
||||||
|
|
||||||
|
foreach ($sources as $transaction) {
|
||||||
|
$amount = strval($transaction->amount);
|
||||||
|
$account = $transaction->account;
|
||||||
|
$amount = bcmul($amount, '-1');
|
||||||
|
|
||||||
|
$object = new stdClass;
|
||||||
|
$object->amount = $amount;
|
||||||
|
$object->name = $account->name;
|
||||||
|
$object->count = 1;
|
||||||
|
$object->id = $account->id;
|
||||||
|
|
||||||
|
// overrule some properties:
|
||||||
|
if ($this->incomes->has($account->id)) {
|
||||||
|
$object = $this->incomes->get($account->id);
|
||||||
|
$object->amount = bcadd($object->amount, $amount);
|
||||||
|
$object->count++;
|
||||||
|
}
|
||||||
|
$this->incomes->put($account->id, $object);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $add
|
||||||
|
*/
|
||||||
|
public function addToTotal(string $add)
|
||||||
|
{
|
||||||
|
$add = strval(round($add, 2));
|
||||||
|
$this->total = bcadd($this->total, $add);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getIncomes(): Collection
|
||||||
|
{
|
||||||
|
$set = $this->incomes->sortByDesc(
|
||||||
|
function (stdClass $object) {
|
||||||
|
return $object->amount;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTotal(): string
|
||||||
|
{
|
||||||
|
return strval(round($this->total, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
85
app/Helpers/FiscalHelper.php
Normal file
85
app/Helpers/FiscalHelper.php
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* FiscalHelper.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Helpers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Preferences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class FiscalHelper
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers
|
||||||
|
*/
|
||||||
|
class FiscalHelper implements FiscalHelperInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
protected $useCustomFiscalYear;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FiscalHelper constructor.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->useCustomFiscalYear = Preferences::get('customFiscalYear', false)->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return Carbon date object
|
||||||
|
*/
|
||||||
|
public function endOfFiscalYear(Carbon $date): Carbon
|
||||||
|
{
|
||||||
|
// get start of fiscal year for passed date
|
||||||
|
$endDate = $this->startOfFiscalYear($date);
|
||||||
|
if ($this->useCustomFiscalYear === true) {
|
||||||
|
// add 1 year and sub 1 day
|
||||||
|
$endDate->addYear();
|
||||||
|
$endDate->subDay();
|
||||||
|
|
||||||
|
return $endDate;
|
||||||
|
}
|
||||||
|
$endDate->endOfYear();
|
||||||
|
|
||||||
|
|
||||||
|
return $endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return Carbon date object
|
||||||
|
*/
|
||||||
|
public function startOfFiscalYear(Carbon $date): Carbon
|
||||||
|
{
|
||||||
|
// get start mm-dd. Then create a start date in the year passed.
|
||||||
|
$startDate = clone $date;
|
||||||
|
if ($this->useCustomFiscalYear === true) {
|
||||||
|
$prefStartStr = Preferences::get('fiscalYearStart', '01-01')->data;
|
||||||
|
list($mth, $day) = explode('-', $prefStartStr);
|
||||||
|
$startDate->month(intval($mth))->day(intval($day));
|
||||||
|
|
||||||
|
// if start date is after passed date, sub 1 year.
|
||||||
|
if ($startDate > $date) {
|
||||||
|
$startDate->subYear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $startDate;
|
||||||
|
}
|
||||||
|
$startDate->startOfYear();
|
||||||
|
|
||||||
|
return $startDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
44
app/Helpers/FiscalHelperInterface.php
Normal file
44
app/Helpers/FiscalHelperInterface.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* FiscalHelperInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Helpers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface FiscalHelperInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers
|
||||||
|
*/
|
||||||
|
interface FiscalHelperInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method produces a clone of the Carbon date object passed, checks preferences
|
||||||
|
* and calculates the last day of the fiscal year.
|
||||||
|
*
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return Carbon date object
|
||||||
|
*/
|
||||||
|
public function endOfFiscalYear(Carbon $date): Carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method produces a clone of the Carbon date object passed, checks preferences
|
||||||
|
* and calculates the first day of the fiscal year.
|
||||||
|
*
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return Carbon date object
|
||||||
|
*/
|
||||||
|
public function startOfFiscalYear(Carbon $date): Carbon;
|
||||||
|
|
||||||
|
}
|
||||||
108
app/Helpers/Help/Help.php
Normal file
108
app/Helpers/Help/Help.php
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Help.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Help;
|
||||||
|
|
||||||
|
use Cache;
|
||||||
|
use League\CommonMark\CommonMarkConverter;
|
||||||
|
use Requests;
|
||||||
|
use Route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Help
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Help
|
||||||
|
*/
|
||||||
|
class Help implements HelpInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFromCache(string $key): string
|
||||||
|
{
|
||||||
|
return Cache::get($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $language
|
||||||
|
* @param string $route
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getFromGithub(string $language, string $route): array
|
||||||
|
{
|
||||||
|
|
||||||
|
$uri = sprintf('https://raw.githubusercontent.com/JC5/firefly-iii-help/master/%s/%s.md', $language, $route);
|
||||||
|
$routeIndex = str_replace('.', '-', $route);
|
||||||
|
$title = trans('help.' . $routeIndex);
|
||||||
|
$content = [
|
||||||
|
'text' => '<p>' . strval(trans('firefly.route_has_no_help')) . '</p>',
|
||||||
|
'title' => $title,
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
$result = Requests::get($uri);
|
||||||
|
|
||||||
|
|
||||||
|
if ($result->status_code === 200) {
|
||||||
|
$content['text'] = $result->body;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (strlen(trim($content['text'])) == 0) {
|
||||||
|
$content['text'] = '<p>' . strval(trans('firefly.route_has_no_help')) . '</p>';
|
||||||
|
}
|
||||||
|
$converter = new CommonMarkConverter();
|
||||||
|
$content['text'] = $converter->convertToHtml($content['text']);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRoute(string $route):bool
|
||||||
|
{
|
||||||
|
return Route::has($route);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function inCache(string $route):bool
|
||||||
|
{
|
||||||
|
return Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
* @param string $language
|
||||||
|
* @param array $content
|
||||||
|
*
|
||||||
|
* @internal param $title
|
||||||
|
*/
|
||||||
|
public function putInCache(string $route, string $language, array $content)
|
||||||
|
{
|
||||||
|
Cache::put('help.' . $route . '.text.' . $language, $content['text'], 10080); // a week.
|
||||||
|
Cache::put('help.' . $route . '.title.' . $language, $content['title'], 10080);
|
||||||
|
}
|
||||||
|
}
|
||||||
56
app/Helpers/Help/HelpInterface.php
Normal file
56
app/Helpers/Help/HelpInterface.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* HelpInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
namespace FireflyIII\Helpers\Help;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface HelpInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Help
|
||||||
|
*/
|
||||||
|
interface HelpInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $key
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFromCache(string $key): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $language
|
||||||
|
* @param string $route
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getFromGithub(string $language, string $route):array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $route
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRoute(string $route): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $route
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function inCache(string $route): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $route
|
||||||
|
* @param string $language
|
||||||
|
* @param array $content
|
||||||
|
*/
|
||||||
|
public function putInCache(string $route, string $language, array $content);
|
||||||
|
}
|
||||||
142
app/Helpers/Report/AccountReportHelper.php
Normal file
142
app/Helpers/Report/AccountReportHelper.php
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AccountReportHelper.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Helpers\Report;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use DB;
|
||||||
|
use FireflyIII\Helpers\Collection\Account as AccountCollection;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AccountReportHelper
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Report
|
||||||
|
*/
|
||||||
|
class AccountReportHelper implements AccountReportHelperInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Account $account
|
||||||
|
* @param Collection $startSet
|
||||||
|
* @param Collection $endSet
|
||||||
|
* @param Collection $backupSet
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*/
|
||||||
|
public static function reportFilter(Account $account, Collection $startSet, Collection $endSet, Collection $backupSet)
|
||||||
|
{
|
||||||
|
// The balance for today always incorporates transactions made on today. So to get todays "start" balance, we sub one day.
|
||||||
|
$account->startBalance = '0';
|
||||||
|
$account->endBalance = '0';
|
||||||
|
$currentStart = $startSet->filter(
|
||||||
|
function (Account $entry) use ($account) {
|
||||||
|
return $account->id == $entry->id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$currentBackup = $backupSet->filter( // grab entry from current backup as well:
|
||||||
|
function (Account $entry) use ($account) {
|
||||||
|
return $account->id == $entry->id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// first try to set from backup
|
||||||
|
if (!is_null($currentBackup->first())) {
|
||||||
|
$account->startBalance = $currentBackup->first()->balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// overrule with data from start
|
||||||
|
if (!is_null($currentStart->first())) {
|
||||||
|
$account->startBalance = $currentStart->first()->balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentEnd = $endSet->filter(
|
||||||
|
function (Account $entry) use ($account) {
|
||||||
|
return $account->id == $entry->id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!is_null($currentEnd->first())) {
|
||||||
|
$account->endBalance = $currentEnd->first()->balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method generates a full report for the given period on all
|
||||||
|
* given accounts.
|
||||||
|
*
|
||||||
|
* a special consideration for accounts that did exist on this exact day.
|
||||||
|
* we also grab the balance from today just in case, to see if that changes things.
|
||||||
|
* it's a fall back for users who (rightly so) start keeping score at the first of
|
||||||
|
* the month and find the first report lacking / broken.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return AccountCollection
|
||||||
|
*/
|
||||||
|
public function getAccountReport(Carbon $start, Carbon $end, Collection $accounts): AccountCollection
|
||||||
|
{
|
||||||
|
$startAmount = '0';
|
||||||
|
$endAmount = '0';
|
||||||
|
$diff = '0';
|
||||||
|
$ids = $accounts->pluck('id')->toArray();
|
||||||
|
$yesterday = clone $start;
|
||||||
|
$yesterday->subDay();
|
||||||
|
$startSet = $this->getSet($ids, $yesterday); // get balances for start.
|
||||||
|
$backupSet = $this->getSet($ids, $start);
|
||||||
|
$endSet = $this->getSet($ids, $end);
|
||||||
|
|
||||||
|
$accounts->each(
|
||||||
|
function (Account $account) use ($startSet, $endSet, $backupSet) {
|
||||||
|
return self::reportFilter($account, $startSet, $endSet, $backupSet);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// summarize:
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$startAmount = bcadd($startAmount, $account->startBalance);
|
||||||
|
$endAmount = bcadd($endAmount, $account->endBalance);
|
||||||
|
$diff = bcadd($diff, bcsub($account->endBalance, $account->startBalance));
|
||||||
|
}
|
||||||
|
|
||||||
|
$object = new AccountCollection;
|
||||||
|
$object->setStart($startAmount);
|
||||||
|
$object->setEnd($endAmount);
|
||||||
|
$object->setDifference($diff);
|
||||||
|
$object->setAccounts($accounts);
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $ids
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function getSet(array $ids, Carbon $date): Collection
|
||||||
|
{
|
||||||
|
return Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
|
||||||
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
|
->whereIn('accounts.id', $ids)
|
||||||
|
->whereNull('transaction_journals.deleted_at')
|
||||||
|
->whereNull('transactions.deleted_at')
|
||||||
|
->where('transaction_journals.date', '<=', $date->format('Y-m-d'))
|
||||||
|
->groupBy('accounts.id')
|
||||||
|
->get(['accounts.id', DB::raw('SUM(`transactions`.`amount`) as `balance`')]);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
app/Helpers/Report/AccountReportHelperInterface.php
Normal file
38
app/Helpers/Report/AccountReportHelperInterface.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AccountReportHelperInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Helpers\Report;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Helpers\Collection\Account as AccountCollection;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface AccountReportHelperInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Report
|
||||||
|
*/
|
||||||
|
interface AccountReportHelperInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This method generates a full report for the given period on all
|
||||||
|
* given accounts
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return AccountCollection
|
||||||
|
*/
|
||||||
|
public function getAccountReport(Carbon $start, Carbon $end, Collection $accounts): AccountCollection;
|
||||||
|
|
||||||
|
}
|
||||||
292
app/Helpers/Report/BalanceReportHelper.php
Normal file
292
app/Helpers/Report/BalanceReportHelper.php
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BalanceReportHelper.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Helpers\Report;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use DB;
|
||||||
|
use FireflyIII\Helpers\Collection\Balance;
|
||||||
|
use FireflyIII\Helpers\Collection\BalanceEntry;
|
||||||
|
use FireflyIII\Helpers\Collection\BalanceHeader;
|
||||||
|
use FireflyIII\Helpers\Collection\BalanceLine;
|
||||||
|
use FireflyIII\Models\Budget;
|
||||||
|
use FireflyIII\Models\LimitRepetition;
|
||||||
|
use FireflyIII\Models\Tag;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
|
use Illuminate\Database\Query\JoinClause;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BalanceReportHelper
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Report
|
||||||
|
*/
|
||||||
|
class BalanceReportHelper implements BalanceReportHelperInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var BudgetRepositoryInterface */
|
||||||
|
protected $budgetRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReportHelper constructor.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param BudgetRepositoryInterface $budgetRepository
|
||||||
|
*/
|
||||||
|
public function __construct(BudgetRepositoryInterface $budgetRepository)
|
||||||
|
{
|
||||||
|
$this->budgetRepository = $budgetRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Balance
|
||||||
|
*/
|
||||||
|
public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts): Balance
|
||||||
|
{
|
||||||
|
$balance = new Balance;
|
||||||
|
$header = new BalanceHeader;
|
||||||
|
$limitRepetitions = $this->budgetRepository->getAllBudgetLimitRepetitions($start, $end);
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$header->addAccount($account);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var LimitRepetition $repetition */
|
||||||
|
foreach ($limitRepetitions as $repetition) {
|
||||||
|
$budget = $this->budgetRepository->find($repetition->budget_id);
|
||||||
|
$line = $this->createBalanceLine($budget, $repetition, $accounts);
|
||||||
|
$balance->addBalanceLine($line);
|
||||||
|
}
|
||||||
|
$noBudgetLine = $this->createNoBudgetLine($accounts, $start, $end);
|
||||||
|
$coveredByTagLine = $this->createTagsBalanceLine($accounts, $start, $end);
|
||||||
|
$leftUnbalancedLine = $this->createLeftUnbalancedLine($noBudgetLine, $coveredByTagLine);
|
||||||
|
|
||||||
|
$balance->addBalanceLine($noBudgetLine);
|
||||||
|
$balance->addBalanceLine($coveredByTagLine);
|
||||||
|
$balance->addBalanceLine($leftUnbalancedLine);
|
||||||
|
$balance->setBalanceHeader($header);
|
||||||
|
|
||||||
|
// remove budgets without expenses from balance lines:
|
||||||
|
$balance = $this->removeUnusedBudgets($balance);
|
||||||
|
|
||||||
|
return $balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method collects all transfers that are part of a "balancing act" tag
|
||||||
|
* and groups the amounts of those transfers by their destination account.
|
||||||
|
*
|
||||||
|
* This is used to indicate which expenses, usually outside of budgets, have been
|
||||||
|
* corrected by transfers from a savings account.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
private function allCoveredByBalancingActs(Collection $accounts, Carbon $start, Carbon $end): Collection
|
||||||
|
{
|
||||||
|
$ids = $accounts->pluck('id')->toArray();
|
||||||
|
$set = Auth::user()->tags()
|
||||||
|
->leftJoin('tag_transaction_journal', 'tag_transaction_journal.tag_id', '=', 'tags.id')
|
||||||
|
->leftJoin('transaction_journals', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
|
||||||
|
->leftJoin(
|
||||||
|
'transactions AS t_source', function (JoinClause $join) {
|
||||||
|
$join->on('transaction_journals.id', '=', 't_source.transaction_journal_id')->where('t_source.amount', '<', 0);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->leftJoin(
|
||||||
|
'transactions AS t_destination', function (JoinClause $join) {
|
||||||
|
$join->on('transaction_journals.id', '=', 't_destination.transaction_journal_id')->where('t_destination.amount', '>', 0);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->where('tags.tagMode', 'balancingAct')
|
||||||
|
->where('transaction_types.type', TransactionType::TRANSFER)
|
||||||
|
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||||
|
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||||
|
->whereNull('transaction_journals.deleted_at')
|
||||||
|
->whereIn('t_source.account_id', $ids)
|
||||||
|
->whereIn('t_destination.account_id', $ids)
|
||||||
|
->groupBy('t_destination.account_id')
|
||||||
|
->get(
|
||||||
|
[
|
||||||
|
't_destination.account_id',
|
||||||
|
DB::raw('SUM(`t_destination`.`amount`) as `sum`'),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Budget $budget
|
||||||
|
* @param LimitRepetition $repetition
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return BalanceLine
|
||||||
|
*/
|
||||||
|
private function createBalanceLine(Budget $budget, LimitRepetition $repetition, Collection $accounts): BalanceLine
|
||||||
|
{
|
||||||
|
$line = new BalanceLine;
|
||||||
|
$budget->amount = $repetition->amount;
|
||||||
|
$line->setBudget($budget);
|
||||||
|
$line->setStartDate($repetition->startdate);
|
||||||
|
$line->setEndDate($repetition->enddate);
|
||||||
|
|
||||||
|
// loop accounts:
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$balanceEntry = new BalanceEntry;
|
||||||
|
$balanceEntry->setAccount($account);
|
||||||
|
$spent = $this->budgetRepository->spentInPeriod(
|
||||||
|
new Collection([$budget]), new Collection([$account]), $repetition->startdate, $repetition->enddate
|
||||||
|
);
|
||||||
|
$balanceEntry->setSpent($spent);
|
||||||
|
$line->addBalanceEntry($balanceEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BalanceLine $noBudgetLine
|
||||||
|
* @param BalanceLine $coveredByTagLine
|
||||||
|
*
|
||||||
|
* @return BalanceLine
|
||||||
|
*/
|
||||||
|
private function createLeftUnbalancedLine(BalanceLine $noBudgetLine, BalanceLine $coveredByTagLine): BalanceLine
|
||||||
|
{
|
||||||
|
$line = new BalanceLine;
|
||||||
|
$line->setRole(BalanceLine::ROLE_DIFFROLE);
|
||||||
|
$noBudgetEntries = $noBudgetLine->getBalanceEntries();
|
||||||
|
$tagEntries = $coveredByTagLine->getBalanceEntries();
|
||||||
|
|
||||||
|
foreach ($noBudgetEntries as $entry) {
|
||||||
|
$account = $entry->getAccount();
|
||||||
|
$tagEntry = $tagEntries->filter(
|
||||||
|
function (BalanceEntry $current) use ($account) {
|
||||||
|
return $current->getAccount()->id === $account->id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if ($tagEntry->first()) {
|
||||||
|
// found corresponding entry. As we should:
|
||||||
|
$newEntry = new BalanceEntry;
|
||||||
|
$newEntry->setAccount($account);
|
||||||
|
$spent = bcadd($tagEntry->first()->getLeft(), $entry->getSpent());
|
||||||
|
$newEntry->setSpent($spent);
|
||||||
|
$line->addBalanceEntry($newEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return BalanceLine
|
||||||
|
*/
|
||||||
|
private function createNoBudgetLine(Collection $accounts, Carbon $start, Carbon $end): BalanceLine
|
||||||
|
{
|
||||||
|
$empty = new BalanceLine;
|
||||||
|
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$spent = $this->budgetRepository->spentInPeriodWithoutBudget(new Collection([$account]), $start, $end);
|
||||||
|
// budget
|
||||||
|
$budgetEntry = new BalanceEntry;
|
||||||
|
$budgetEntry->setAccount($account);
|
||||||
|
$budgetEntry->setSpent($spent);
|
||||||
|
$empty->addBalanceEntry($budgetEntry);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return BalanceLine
|
||||||
|
*/
|
||||||
|
private function createTagsBalanceLine(Collection $accounts, Carbon $start, Carbon $end): BalanceLine
|
||||||
|
{
|
||||||
|
$tags = new BalanceLine;
|
||||||
|
$tagsLeft = $this->allCoveredByBalancingActs($accounts, $start, $end);
|
||||||
|
|
||||||
|
$tags->setRole(BalanceLine::ROLE_TAGROLE);
|
||||||
|
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$leftEntry = $tagsLeft->filter(
|
||||||
|
function (Tag $tag) use ($account) {
|
||||||
|
return $tag->account_id == $account->id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$left = '0';
|
||||||
|
if (!is_null($leftEntry->first())) {
|
||||||
|
$left = $leftEntry->first()->sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// balanced by tags
|
||||||
|
$tagEntry = new BalanceEntry;
|
||||||
|
$tagEntry->setAccount($account);
|
||||||
|
$tagEntry->setLeft($left);
|
||||||
|
$tags->addBalanceEntry($tagEntry);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Balance $balance
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly 5.
|
||||||
|
*
|
||||||
|
* @return Balance
|
||||||
|
*/
|
||||||
|
private function removeUnusedBudgets(Balance $balance): Balance
|
||||||
|
{
|
||||||
|
$set = $balance->getBalanceLines();
|
||||||
|
$newSet = new Collection;
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
if (!is_null($entry->getBudget()->id)) {
|
||||||
|
$sum = '0';
|
||||||
|
foreach ($entry->getBalanceEntries() as $balanceEntry) {
|
||||||
|
$sum = bcadd($sum, $balanceEntry->getSpent());
|
||||||
|
}
|
||||||
|
if (bccomp($sum, '0') === -1) {
|
||||||
|
$newSet->push($entry);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$newSet->push($entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
$balance->setBalanceLines($newSet);
|
||||||
|
|
||||||
|
return $balance;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
34
app/Helpers/Report/BalanceReportHelperInterface.php
Normal file
34
app/Helpers/Report/BalanceReportHelperInterface.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BalanceReportHelperInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Helpers\Report;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Helpers\Collection\Balance;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface BalanceReportHelperInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Report
|
||||||
|
*/
|
||||||
|
interface BalanceReportHelperInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Balance
|
||||||
|
*/
|
||||||
|
public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts): Balance;
|
||||||
|
}
|
||||||
275
app/Helpers/Report/BudgetReportHelper.php
Normal file
275
app/Helpers/Report/BudgetReportHelper.php
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BudgetReportHelper.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Helpers\Report;
|
||||||
|
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
|
||||||
|
use FireflyIII\Helpers\Collection\BudgetLine;
|
||||||
|
use FireflyIII\Models\Budget;
|
||||||
|
use FireflyIII\Models\LimitRepetition;
|
||||||
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
|
use FireflyIII\Support\CacheProperties;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BudgetReportHelper
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Report
|
||||||
|
*/
|
||||||
|
class BudgetReportHelper implements BudgetReportHelperInterface
|
||||||
|
{
|
||||||
|
/** @var BudgetRepositoryInterface */
|
||||||
|
private $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BudgetReportHelper constructor.
|
||||||
|
*
|
||||||
|
* @param BudgetRepositoryInterface $repository
|
||||||
|
*/
|
||||||
|
public function __construct(BudgetRepositoryInterface $repository)
|
||||||
|
{
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @SuppressWarnings(PHPMD.ExcessiveMethodLength) // at 43, its ok.
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly 5.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function budgetYearOverview(Carbon $start, Carbon $end, Collection $accounts): Collection
|
||||||
|
{
|
||||||
|
// chart properties for cache:
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty('budget-year');
|
||||||
|
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
$current = clone $start;
|
||||||
|
$return = new Collection;
|
||||||
|
$set = $this->repository->getBudgets();
|
||||||
|
$budgets = [];
|
||||||
|
$spent = [];
|
||||||
|
$headers = $this->createYearHeaders($current, $end);
|
||||||
|
|
||||||
|
/** @var Budget $budget */
|
||||||
|
foreach ($set as $budget) {
|
||||||
|
$id = $budget->id;
|
||||||
|
$budgets[$id] = $budget->name;
|
||||||
|
$current = clone $start;
|
||||||
|
$budgetData = $this->getBudgetSpentData($current, $end, $budget, $accounts);
|
||||||
|
$sum = $budgetData['sum'];
|
||||||
|
$spent[$id] = $budgetData['spent'];
|
||||||
|
|
||||||
|
if (bccomp('0', $sum) === 0) {
|
||||||
|
// not spent anything.
|
||||||
|
unset($spent[$id]);
|
||||||
|
unset($budgets[$id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$return->put('headers', $headers);
|
||||||
|
$return->put('budgets', $budgets);
|
||||||
|
$return->put('spent', $spent);
|
||||||
|
|
||||||
|
$cache->store($return);
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return BudgetCollection
|
||||||
|
*/
|
||||||
|
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts): BudgetCollection
|
||||||
|
{
|
||||||
|
$object = new BudgetCollection;
|
||||||
|
$set = $this->repository->getBudgets();
|
||||||
|
|
||||||
|
/** @var Budget $budget */
|
||||||
|
foreach ($set as $budget) {
|
||||||
|
$repetitions = $budget->limitrepetitions()->before($end)->after($start)->get();
|
||||||
|
|
||||||
|
// no repetition(s) for this budget:
|
||||||
|
if ($repetitions->count() == 0) {
|
||||||
|
// spent for budget in time range:
|
||||||
|
$spent = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end);
|
||||||
|
|
||||||
|
if ($spent > 0) {
|
||||||
|
$budgetLine = new BudgetLine;
|
||||||
|
$budgetLine->setBudget($budget)->setOverspent($spent);
|
||||||
|
$object->addOverspent($spent)->addBudgetLine($budgetLine);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// one or more repetitions for budget:
|
||||||
|
/** @var LimitRepetition $repetition */
|
||||||
|
foreach ($repetitions as $repetition) {
|
||||||
|
$data = $this->calculateExpenses($budget, $repetition, $accounts);
|
||||||
|
|
||||||
|
$budgetLine = new BudgetLine;
|
||||||
|
$budgetLine->setBudget($budget)->setRepetition($repetition)
|
||||||
|
->setLeft($data['left'])->setSpent($data['expenses'])->setOverspent($data['overspent'])
|
||||||
|
->setBudgeted(strval($repetition->amount));
|
||||||
|
|
||||||
|
$object->addBudgeted(strval($repetition->amount))->addSpent($data['spent'])
|
||||||
|
->addLeft($data['left'])->addOverspent($data['overspent'])->addBudgetLine($budgetLine);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// stuff outside of budgets:
|
||||||
|
|
||||||
|
$noBudget = $this->repository->spentInPeriodWithoutBudget($accounts, $start, $end);
|
||||||
|
$budgetLine = new BudgetLine;
|
||||||
|
$budgetLine->setOverspent($noBudget)->setSpent($noBudget);
|
||||||
|
$object->addOverspent($noBudget)->addBudgetLine($budgetLine);
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getBudgetsWithExpenses(Carbon $start, Carbon $end, Collection $accounts): Collection
|
||||||
|
{
|
||||||
|
/** @var BudgetRepositoryInterface $repository */
|
||||||
|
$repository = app(BudgetRepositoryInterface::class);
|
||||||
|
$budgets = $repository->getActiveBudgets();
|
||||||
|
|
||||||
|
$set = new Collection;
|
||||||
|
/** @var Budget $budget */
|
||||||
|
foreach ($budgets as $budget) {
|
||||||
|
$total = $repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end);
|
||||||
|
if (bccomp($total, '0') === -1) {
|
||||||
|
$set->push($budget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$set = $set->sortBy(
|
||||||
|
function (Budget $budget) {
|
||||||
|
return $budget->name;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return $set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take the array as returned by CategoryRepositoryInterface::spentPerDay and CategoryRepositoryInterface::earnedByDay
|
||||||
|
* and sum up everything in the array in the given range.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param array $array
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getSumOfRange(Carbon $start, Carbon $end, array $array)
|
||||||
|
{
|
||||||
|
$sum = '0';
|
||||||
|
$currentStart = clone $start; // to not mess with the original one
|
||||||
|
$currentEnd = clone $end; // to not mess with the original one
|
||||||
|
|
||||||
|
while ($currentStart <= $currentEnd) {
|
||||||
|
$date = $currentStart->format('Y-m-d');
|
||||||
|
if (isset($array[$date])) {
|
||||||
|
$sum = bcadd($sum, $array[$date]);
|
||||||
|
}
|
||||||
|
$currentStart->addDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Budget $budget
|
||||||
|
* @param LimitRepetition $repetition
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function calculateExpenses(Budget $budget, LimitRepetition $repetition, Collection $accounts): array
|
||||||
|
{
|
||||||
|
$array = [];
|
||||||
|
$expenses = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $repetition->startdate, $repetition->enddate);
|
||||||
|
$array['left'] = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? bcadd($repetition->amount, $expenses) : '0';
|
||||||
|
$array['spent'] = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? $expenses : '0';
|
||||||
|
$array['overspent'] = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? '0' : bcadd($expenses, $repetition->amount);
|
||||||
|
$array['expenses'] = $expenses;
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $current
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function createYearHeaders(Carbon $current, Carbon $end): array
|
||||||
|
{
|
||||||
|
$headers = [];
|
||||||
|
while ($current < $end) {
|
||||||
|
$short = $current->format('m-Y');
|
||||||
|
$headers[$short] = $current->formatLocalized((string)trans('config.month'));
|
||||||
|
$current->addMonth();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $current
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Budget $budget
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getBudgetSpentData(Carbon $current, Carbon $end, Budget $budget, Collection $accounts): array
|
||||||
|
{
|
||||||
|
$sum = '0';
|
||||||
|
$spent = [];
|
||||||
|
while ($current < $end) {
|
||||||
|
$currentEnd = clone $current;
|
||||||
|
$currentEnd->endOfMonth();
|
||||||
|
$format = $current->format('m-Y');
|
||||||
|
$budgetSpent = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $current, $currentEnd);
|
||||||
|
$spent[$format] = $budgetSpent;
|
||||||
|
$sum = bcadd($sum, $budgetSpent);
|
||||||
|
$current->addMonth();
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'spent' => $spent,
|
||||||
|
'sum' => $sum,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
53
app/Helpers/Report/BudgetReportHelperInterface.php
Normal file
53
app/Helpers/Report/BudgetReportHelperInterface.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* BudgetReportHelperInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Helpers\Report;
|
||||||
|
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface BudgetReportHelperInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Report
|
||||||
|
*/
|
||||||
|
interface BudgetReportHelperInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function budgetYearOverview(Carbon $start, Carbon $end, Collection $accounts): Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return BudgetCollection
|
||||||
|
*/
|
||||||
|
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts): BudgetCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getBudgetsWithExpenses(Carbon $start, Carbon $end, Collection $accounts): Collection;
|
||||||
|
|
||||||
|
}
|
||||||
320
app/Helpers/Report/ReportHelper.php
Normal file
320
app/Helpers/Report/ReportHelper.php
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ReportHelper.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Helpers\Report;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Helpers\Collection\Bill as BillCollection;
|
||||||
|
use FireflyIII\Helpers\Collection\BillLine;
|
||||||
|
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
|
||||||
|
use FireflyIII\Helpers\Collection\Expense;
|
||||||
|
use FireflyIII\Helpers\Collection\Income;
|
||||||
|
use FireflyIII\Helpers\FiscalHelperInterface;
|
||||||
|
use FireflyIII\Models\Bill;
|
||||||
|
use FireflyIII\Models\Category;
|
||||||
|
use FireflyIII\Models\Tag;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Query\JoinClause;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ReportHelper
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Report
|
||||||
|
*/
|
||||||
|
class ReportHelper implements ReportHelperInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @var BudgetRepositoryInterface */
|
||||||
|
protected $budgetRepository;
|
||||||
|
/** @var TagRepositoryInterface */
|
||||||
|
protected $tagRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReportHelper constructor.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param BudgetRepositoryInterface $budgetRepository
|
||||||
|
* @param TagRepositoryInterface $tagRepository
|
||||||
|
*/
|
||||||
|
public function __construct(BudgetRepositoryInterface $budgetRepository, TagRepositoryInterface $tagRepository)
|
||||||
|
{
|
||||||
|
$this->budgetRepository = $budgetRepository;
|
||||||
|
$this->tagRepository = $tagRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method generates a full report for the given period on all
|
||||||
|
* the users bills and their payments.
|
||||||
|
*
|
||||||
|
* Excludes bills which have not had a payment on the mentioned accounts.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return BillCollection
|
||||||
|
*/
|
||||||
|
public function getBillReport(Carbon $start, Carbon $end, Collection $accounts): BillCollection
|
||||||
|
{
|
||||||
|
/** @var BillRepositoryInterface $repository */
|
||||||
|
$repository = app(BillRepositoryInterface::class);
|
||||||
|
$bills = $repository->getBillsForAccounts($accounts);
|
||||||
|
$journals = $repository->getAllJournalsInRange($bills, $start, $end);
|
||||||
|
$collection = new BillCollection;
|
||||||
|
|
||||||
|
/** @var Bill $bill */
|
||||||
|
foreach ($bills as $bill) {
|
||||||
|
$billLine = new BillLine;
|
||||||
|
$billLine->setBill($bill);
|
||||||
|
$billLine->setActive(intval($bill->active) === 1);
|
||||||
|
$billLine->setMin(strval($bill->amount_min));
|
||||||
|
$billLine->setMax(strval($bill->amount_max));
|
||||||
|
$billLine->setHit(false);
|
||||||
|
// is hit in period?
|
||||||
|
|
||||||
|
$entry = $journals->filter(
|
||||||
|
function (TransactionJournal $journal) use ($bill) {
|
||||||
|
return $journal->bill_id === $bill->id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$first = $entry->first();
|
||||||
|
if (!is_null($first)) {
|
||||||
|
$billLine->setTransactionJournalId($first->id);
|
||||||
|
$billLine->setAmount($first->journalAmount);
|
||||||
|
$billLine->setHit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($billLine->isActive()) {
|
||||||
|
$collection->addBill($billLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return CategoryCollection
|
||||||
|
*/
|
||||||
|
public function getCategoryReport(Carbon $start, Carbon $end, Collection $accounts): CategoryCollection
|
||||||
|
{
|
||||||
|
$object = new CategoryCollection;
|
||||||
|
/** @var CategoryRepositoryInterface $repository */
|
||||||
|
$repository = app(CategoryRepositoryInterface::class);
|
||||||
|
$categories = $repository->getCategories();
|
||||||
|
|
||||||
|
/** @var Category $category */
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $end);
|
||||||
|
// CategoryCollection expects the amount in $spent:
|
||||||
|
$category->spent = $spent;
|
||||||
|
$object->addCategory($category);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a full report on the users expenses during the period for a list of accounts.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Expense
|
||||||
|
*/
|
||||||
|
public function getExpenseReport(Carbon $start, Carbon $end, Collection $accounts): Expense
|
||||||
|
{
|
||||||
|
$object = new Expense;
|
||||||
|
/** @var AccountRepositoryInterface $repos */
|
||||||
|
$repos = app(AccountRepositoryInterface::class);
|
||||||
|
$journals = $repos->expensesInPeriod($accounts, $start, $end);
|
||||||
|
|
||||||
|
/** @var TransactionJournal $entry */
|
||||||
|
foreach ($journals as $entry) {
|
||||||
|
$amount = TransactionJournal::amount($entry);
|
||||||
|
$object->addToTotal($amount);
|
||||||
|
$object->addOrCreateExpense($entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a full report on the users incomes during the period for the given accounts.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Income
|
||||||
|
*/
|
||||||
|
public function getIncomeReport(Carbon $start, Carbon $end, Collection $accounts): Income
|
||||||
|
{
|
||||||
|
$object = new Income;
|
||||||
|
/** @var AccountRepositoryInterface $repos */
|
||||||
|
$repos = app(AccountRepositoryInterface::class);
|
||||||
|
$journals = $repos->incomesInPeriod($accounts, $start, $end);
|
||||||
|
|
||||||
|
foreach ($journals as $entry) {
|
||||||
|
$amount = TransactionJournal::amount($entry);
|
||||||
|
$object->addToTotal($amount);
|
||||||
|
$object->addOrCreateIncome($entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function listOfMonths(Carbon $date): array
|
||||||
|
{
|
||||||
|
/** @var FiscalHelperInterface $fiscalHelper */
|
||||||
|
$fiscalHelper = app(FiscalHelperInterface::class);
|
||||||
|
$start = clone $date;
|
||||||
|
$start->startOfMonth();
|
||||||
|
$end = Carbon::now();
|
||||||
|
$end->endOfMonth();
|
||||||
|
$months = [];
|
||||||
|
|
||||||
|
while ($start <= $end) {
|
||||||
|
$year = $fiscalHelper->endOfFiscalYear($start)->year; // current year
|
||||||
|
if (!isset($months[$year])) {
|
||||||
|
$months[$year] = [
|
||||||
|
'fiscal_start' => $fiscalHelper->startOfFiscalYear($start)->format('Y-m-d'),
|
||||||
|
'fiscal_end' => $fiscalHelper->endOfFiscalYear($start)->format('Y-m-d'),
|
||||||
|
'start' => Carbon::createFromDate($year, 1, 1)->format('Y-m-d'),
|
||||||
|
'end' => Carbon::createFromDate($year, 12, 31)->format('Y-m-d'),
|
||||||
|
'months' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentEnd = clone $start;
|
||||||
|
$currentEnd->endOfMonth();
|
||||||
|
$months[$year]['months'][] = [
|
||||||
|
'formatted' => $start->formatLocalized('%B %Y'),
|
||||||
|
'start' => $start->format('Y-m-d'),
|
||||||
|
'end' => $currentEnd->format('Y-m-d'),
|
||||||
|
'month' => $start->month,
|
||||||
|
'year' => $year,
|
||||||
|
];
|
||||||
|
|
||||||
|
$start = clone $currentEnd; // to make the hop to the next month properly
|
||||||
|
$start->addDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $months;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of tags and their comparitive size with amounts bla bla.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function tagReport(Carbon $start, Carbon $end, Collection $accounts): array
|
||||||
|
{
|
||||||
|
$ids = $accounts->pluck('id')->toArray();
|
||||||
|
$set = Tag::
|
||||||
|
leftJoin('tag_transaction_journal', 'tags.id', '=', 'tag_transaction_journal.tag_id')
|
||||||
|
->leftJoin('transaction_journals', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
|
||||||
|
->leftJoin(
|
||||||
|
'transactions AS source', function (JoinClause $join) {
|
||||||
|
$join->on('source.transaction_journal_id', '=', 'transaction_journals.id')->where('source.amount', '<', '0');
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->leftJoin(
|
||||||
|
'transactions AS destination', function (JoinClause $join) {
|
||||||
|
$join->on('destination.transaction_journal_id', '=', 'transaction_journals.id')->where('destination.amount', '>', '0');
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
|
||||||
|
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
|
||||||
|
->where(
|
||||||
|
function (Builder $q) use ($ids) {
|
||||||
|
$q->whereIn('source.account_id', $ids)
|
||||||
|
->whereIn('destination.account_id', $ids, 'xor');
|
||||||
|
}
|
||||||
|
)
|
||||||
|
->get(['tags.id', 'tags.tag', 'transaction_journals.id as journal_id', 'destination.amount']);
|
||||||
|
$collection = [];
|
||||||
|
if ($set->count() === 0) {
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
/** @var Tag $entry */
|
||||||
|
foreach ($set as $entry) {
|
||||||
|
// less than zero? multiply to be above zero.
|
||||||
|
$amount = $entry->amount;
|
||||||
|
$id = intval($entry->id);
|
||||||
|
$previousAmount = $collection[$id]['amount'] ?? '0';
|
||||||
|
$collection[$id] = [
|
||||||
|
'id' => $id,
|
||||||
|
'tag' => $entry->tag,
|
||||||
|
'amount' => bcadd($previousAmount, $amount),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup collection (match "fonts")
|
||||||
|
$max = strval(max(array_column($collection, 'amount')));
|
||||||
|
foreach ($collection as $id => $entry) {
|
||||||
|
$size = bcdiv($entry['amount'], $max, 4);
|
||||||
|
if (bccomp($size, '0.25') === -1) {
|
||||||
|
$size = '0.5';
|
||||||
|
}
|
||||||
|
$collection[$id]['fontsize'] = $size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take the array as returned by CategoryRepositoryInterface::spentPerDay and CategoryRepositoryInterface::earnedByDay
|
||||||
|
* and sum up everything in the array in the given range.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param array $array
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getSumOfRange(Carbon $start, Carbon $end, array $array)
|
||||||
|
{
|
||||||
|
$sum = '0';
|
||||||
|
$currentStart = clone $start; // to not mess with the original one
|
||||||
|
$currentEnd = clone $end; // to not mess with the original one
|
||||||
|
|
||||||
|
while ($currentStart <= $currentEnd) {
|
||||||
|
$date = $currentStart->format('Y-m-d');
|
||||||
|
if (isset($array[$date])) {
|
||||||
|
$sum = bcadd($sum, $array[$date]);
|
||||||
|
}
|
||||||
|
$currentStart->addDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
92
app/Helpers/Report/ReportHelperInterface.php
Normal file
92
app/Helpers/Report/ReportHelperInterface.php
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ReportHelperInterface.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Helpers\Report;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Helpers\Collection\Bill as BillCollection;
|
||||||
|
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
|
||||||
|
use FireflyIII\Helpers\Collection\Expense;
|
||||||
|
use FireflyIII\Helpers\Collection\Income;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface ReportHelperInterface
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Helpers\Report
|
||||||
|
*/
|
||||||
|
interface ReportHelperInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method generates a full report for the given period on all
|
||||||
|
* the users bills and their payments.
|
||||||
|
*
|
||||||
|
* Excludes bills which have not had a payment on the mentioned accounts.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return BillCollection
|
||||||
|
*/
|
||||||
|
public function getBillReport(Carbon $start, Carbon $end, Collection $accounts): BillCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return CategoryCollection
|
||||||
|
*/
|
||||||
|
public function getCategoryReport(Carbon $start, Carbon $end, Collection $accounts): CategoryCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a full report on the users expenses during the period for a list of accounts.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Expense
|
||||||
|
*/
|
||||||
|
public function getExpenseReport(Carbon $start, Carbon $end, Collection $accounts): Expense;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a full report on the users incomes during the period for the given accounts.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return Income
|
||||||
|
*/
|
||||||
|
public function getIncomeReport(Carbon $start, Carbon $end, Collection $accounts): Income;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function listOfMonths(Carbon $date): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of tags and their comparitive size with amounts bla bla.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
* @param Collection $accounts
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function tagReport(Carbon $start, Carbon $end, Collection $accounts): array;
|
||||||
|
|
||||||
|
}
|
||||||
458
app/Http/Controllers/AccountController.php
Normal file
458
app/Http/Controllers/AccountController.php
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* AccountController.php
|
||||||
|
* Copyright (C) 2016 thegrumpydictator@gmail.com
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace FireflyIII\Http\Controllers;
|
||||||
|
|
||||||
|
use Auth;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use ExpandedForm;
|
||||||
|
use FireflyIII\Crud\Account\AccountCrudInterface;
|
||||||
|
use FireflyIII\Http\Requests\AccountFormRequest;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\AccountType;
|
||||||
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
|
||||||
|
use FireflyIII\Support\CacheProperties;
|
||||||
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Input;
|
||||||
|
use Navigation;
|
||||||
|
use Preferences;
|
||||||
|
use Session;
|
||||||
|
use Steam;
|
||||||
|
use URL;
|
||||||
|
use View;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AccountController
|
||||||
|
*
|
||||||
|
* @package FireflyIII\Http\Controllers
|
||||||
|
*/
|
||||||
|
class AccountController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
View::share('mainTitleIcon', 'fa-credit-card');
|
||||||
|
View::share('title', trans('firefly.accounts'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $what
|
||||||
|
*
|
||||||
|
* @return View
|
||||||
|
*/
|
||||||
|
public function create(string $what = 'asset')
|
||||||
|
{
|
||||||
|
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||||
|
$subTitle = trans('firefly.make_new_' . $what . '_account');
|
||||||
|
Session::flash('preFilled', []);
|
||||||
|
|
||||||
|
// put previous url in session if not redirect from store (not "create another").
|
||||||
|
if (session('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'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AccountCrudInterface $crud
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return View
|
||||||
|
*/
|
||||||
|
public function delete(AccountCrudInterface $crud, Account $account)
|
||||||
|
{
|
||||||
|
$typeName = config('firefly.shortNamesByFullName.' . $account->accountType->type);
|
||||||
|
$subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]);
|
||||||
|
$accountList = ExpandedForm::makeSelectListWithEmpty($crud->getAccountsByType([$account->accountType->type]));
|
||||||
|
unset($accountList[$account->id]);
|
||||||
|
|
||||||
|
// 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', 'accountList'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AccountCrudInterface $crud
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
|
*/
|
||||||
|
public function destroy(AccountCrudInterface $crud, Account $account)
|
||||||
|
{
|
||||||
|
$type = $account->accountType->type;
|
||||||
|
$typeName = config('firefly.shortNamesByFullName.' . $type);
|
||||||
|
$name = $account->name;
|
||||||
|
$moveTo = $crud->find(intval(Input::get('move_account_before_delete')));
|
||||||
|
|
||||||
|
$crud->destroy($account, $moveTo);
|
||||||
|
|
||||||
|
Session::flash('success', strval(trans('firefly.' . $typeName . '_deleted', ['name' => $name])));
|
||||||
|
Preferences::mark();
|
||||||
|
|
||||||
|
return redirect(session('accounts.delete.url'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ARI $repository
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return View
|
||||||
|
*/
|
||||||
|
public function edit(ARI $repository, Account $account)
|
||||||
|
{
|
||||||
|
|
||||||
|
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
|
||||||
|
$subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
|
||||||
|
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||||
|
$openingBalance = $repository->openingBalanceTransaction($account);
|
||||||
|
|
||||||
|
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||||
|
if (session('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->id) {
|
||||||
|
$transaction = $repository->getFirstTransaction($openingBalance, $account);
|
||||||
|
$openingBalanceAmount = $transaction->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$preFilled = [
|
||||||
|
'accountNumber' => $account->getMeta('accountNumber'),
|
||||||
|
'accountRole' => $account->getMeta('accountRole'),
|
||||||
|
'ccType' => $account->getMeta('ccType'),
|
||||||
|
'ccMonthlyPaymentDate' => $account->getMeta('ccMonthlyPaymentDate'),
|
||||||
|
'openingBalanceDate' => $openingBalance->id ? $openingBalance->date->format('Y-m-d') : null,
|
||||||
|
'openingBalance' => $openingBalanceAmount,
|
||||||
|
'virtualBalance' => round($account->virtual_balance, 2),
|
||||||
|
];
|
||||||
|
Session::flash('preFilled', $preFilled);
|
||||||
|
Session::flash('gaEventCategory', 'accounts');
|
||||||
|
Session::flash('gaEventAction', 'edit-' . $what);
|
||||||
|
|
||||||
|
return view('accounts.edit', compact('account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AccountCrudInterface $crud
|
||||||
|
* @param string $what
|
||||||
|
*
|
||||||
|
* @return View
|
||||||
|
*/
|
||||||
|
public function index(AccountCrudInterface $crud, string $what)
|
||||||
|
{
|
||||||
|
$what = $what ?? 'asset';
|
||||||
|
|
||||||
|
$subTitle = trans('firefly.' . $what . '_accounts');
|
||||||
|
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||||
|
$types = config('firefly.accountTypesByIdentifier.' . $what);
|
||||||
|
$accounts = $crud->getAccountsByType($types);
|
||||||
|
/** @var Carbon $start */
|
||||||
|
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||||
|
/** @var Carbon $end */
|
||||||
|
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||||
|
$start->subDay();
|
||||||
|
|
||||||
|
$ids = $accounts->pluck('id')->toArray();
|
||||||
|
$startBalances = Steam::balancesById($ids, $start);
|
||||||
|
$endBalances = Steam::balancesById($ids, $end);
|
||||||
|
$activities = Steam::getLastActivities($ids);
|
||||||
|
|
||||||
|
$accounts->each(
|
||||||
|
function (Account $account) use ($activities, $startBalances, $endBalances) {
|
||||||
|
$account->lastActivityDate = $this->isInArray($activities, $account->id);
|
||||||
|
$account->startBalance = $this->isInArray($startBalances, $account->id);
|
||||||
|
$account->endBalance = $this->isInArray($endBalances, $account->id);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ARI $repository
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return View
|
||||||
|
*/
|
||||||
|
public function show(ARI $repository, Account $account)
|
||||||
|
{
|
||||||
|
// show journals from current period only:
|
||||||
|
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
||||||
|
$subTitle = $account->name;
|
||||||
|
$range = Preferences::get('viewRange', '1M')->data;
|
||||||
|
/** @var Carbon $start */
|
||||||
|
$start = session('start', Navigation::startOfPeriod(new Carbon, $range));
|
||||||
|
/** @var Carbon $end */
|
||||||
|
$end = session('end', Navigation::endOfPeriod(new Carbon, $range));
|
||||||
|
$page = intval(Input::get('page'));
|
||||||
|
$pageSize = Preferences::get('transactionPageSize', 50)->data;
|
||||||
|
$offset = ($page - 1) * $pageSize;
|
||||||
|
$set = $repository->journalsInPeriod(new Collection([$account]), [], $start, $end);
|
||||||
|
$count = $set->count();
|
||||||
|
$subSet = $set->splice($offset, $pageSize);
|
||||||
|
$journals = new LengthAwarePaginator($subSet, $count, $pageSize, $page);
|
||||||
|
$journals->setPath('accounts/show/' . $account->id);
|
||||||
|
|
||||||
|
// grouped other months thing:
|
||||||
|
// oldest transaction in account:
|
||||||
|
$start = $repository->firstUseDate($account);
|
||||||
|
if ($start->year == 1900) {
|
||||||
|
$start = new Carbon;
|
||||||
|
}
|
||||||
|
$range = Preferences::get('viewRange', '1M')->data;
|
||||||
|
$start = Navigation::startOfPeriod($start, $range);
|
||||||
|
$end = Navigation::endOfX(new Carbon, $range);
|
||||||
|
$entries = new Collection;
|
||||||
|
|
||||||
|
// chart properties for cache:
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty('account-show');
|
||||||
|
$cache->addProperty($account->id);
|
||||||
|
|
||||||
|
|
||||||
|
if ($cache->has()) {
|
||||||
|
$entries = $cache->get();
|
||||||
|
|
||||||
|
return view('accounts.show', compact('account', 'what', 'entries', 'subTitleIcon', 'journals', 'subTitle'));
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($end >= $start) {
|
||||||
|
$end = Navigation::startOfPeriod($end, $range);
|
||||||
|
$currentEnd = Navigation::endOfPeriod($end, $range);
|
||||||
|
$spent = $this->spentInPeriod($account, $end, $currentEnd);
|
||||||
|
$earned = $this->earnedInPeriod($account, $end, $currentEnd);
|
||||||
|
$dateStr = $end->format('Y-m-d');
|
||||||
|
$dateName = Navigation::periodShow($end, $range);
|
||||||
|
$entries->push([$dateStr, $dateName, $spent, $earned]);
|
||||||
|
$end = Navigation::subtractPeriod($end, $range, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
$cache->store($entries);
|
||||||
|
|
||||||
|
return view('accounts.show', compact('account', 'what', 'entries', 'subTitleIcon', 'journals', 'subTitle'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ARI $repository
|
||||||
|
* @param Account $account
|
||||||
|
* @param string $date
|
||||||
|
*
|
||||||
|
* @return View
|
||||||
|
*/
|
||||||
|
public function showWithDate(ARI $repository, Account $account, string $date)
|
||||||
|
{
|
||||||
|
$carbon = new Carbon($date);
|
||||||
|
$range = Preferences::get('viewRange', '1M')->data;
|
||||||
|
$start = Navigation::startOfPeriod($carbon, $range);
|
||||||
|
$end = Navigation::endOfPeriod($carbon, $range);
|
||||||
|
$subTitle = $account->name . ' (' . Navigation::periodShow($start, $range) . ')';
|
||||||
|
$page = intval(Input::get('page'));
|
||||||
|
$page = $page === 0 ? 1 : $page;
|
||||||
|
$pageSize = Preferences::get('transactionPageSize', 50)->data;
|
||||||
|
$offset = ($page - 1) * $pageSize;
|
||||||
|
$set = $repository->journalsInPeriod(new Collection([$account]), [], $start, $end);
|
||||||
|
$count = $set->count();
|
||||||
|
$subSet = $set->splice($offset, $pageSize);
|
||||||
|
$journals = new LengthAwarePaginator($subSet, $count, $pageSize, $page);
|
||||||
|
$journals->setPath('accounts/show/' . $account->id . '/' . $date);
|
||||||
|
|
||||||
|
return view('accounts.show_with_date', compact('category', 'date', 'account', 'journals', 'subTitle', 'carbon'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AccountFormRequest $request
|
||||||
|
* @param AccountCrudInterface $crud
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
|
*/
|
||||||
|
public function store(AccountFormRequest $request, AccountCrudInterface $crud)
|
||||||
|
{
|
||||||
|
$accountData = [
|
||||||
|
'name' => $request->input('name'),
|
||||||
|
'accountType' => $request->input('what'),
|
||||||
|
'virtualBalance' => round($request->input('virtualBalance'), 2),
|
||||||
|
'virtualBalanceCurrency' => intval($request->input('amount_currency_id_virtualBalance')),
|
||||||
|
'active' => true,
|
||||||
|
'user' => Auth::user()->id,
|
||||||
|
'iban' => $request->input('iban'),
|
||||||
|
'accountNumber' => $request->input('accountNumber'),
|
||||||
|
'accountRole' => $request->input('accountRole'),
|
||||||
|
'openingBalance' => round($request->input('openingBalance'), 2),
|
||||||
|
'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')),
|
||||||
|
'openingBalanceCurrency' => intval($request->input('amount_currency_id_openingBalance')),
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
$account = $crud->store($accountData);
|
||||||
|
|
||||||
|
Session::flash('success', strval(trans('firefly.stored_new_account', ['name' => $account->name])));
|
||||||
|
Preferences::mark();
|
||||||
|
|
||||||
|
// update preferences if necessary:
|
||||||
|
$frontPage = Preferences::get('frontPageAccounts', [])->data;
|
||||||
|
if (count($frontPage) > 0) {
|
||||||
|
$frontPage[] = $account->id;
|
||||||
|
Preferences::set('frontPageAccounts', $frontPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
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', [$request->input('what')]))->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
// redirect to previous URL.
|
||||||
|
return redirect(session('accounts.create.url'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AccountFormRequest $request
|
||||||
|
* @param AccountCrudInterface $crud
|
||||||
|
* @param Account $account
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
|
*/
|
||||||
|
public function update(AccountFormRequest $request, AccountCrudInterface $crud, Account $account)
|
||||||
|
{
|
||||||
|
|
||||||
|
$accountData = [
|
||||||
|
'name' => $request->input('name'),
|
||||||
|
'active' => $request->input('active'),
|
||||||
|
'user' => Auth::user()->id,
|
||||||
|
'iban' => $request->input('iban'),
|
||||||
|
'accountNumber' => $request->input('accountNumber'),
|
||||||
|
'accountRole' => $request->input('accountRole'),
|
||||||
|
'virtualBalance' => round($request->input('virtualBalance'), 2),
|
||||||
|
'openingBalance' => round($request->input('openingBalance'), 2),
|
||||||
|
'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')),
|
||||||
|
'openingBalanceCurrency' => intval($request->input('amount_currency_id_openingBalance')),
|
||||||
|
'ccType' => $request->input('ccType'),
|
||||||
|
'ccMonthlyPaymentDate' => $request->input('ccMonthlyPaymentDate'),
|
||||||
|
];
|
||||||
|
$crud->update($account, $accountData);
|
||||||
|
|
||||||
|
Session::flash('success', strval(trans('firefly.updated_account', ['name' => $account->name])));
|
||||||
|
Preferences::mark();
|
||||||
|
|
||||||
|
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(session('accounts.edit.url'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $array
|
||||||
|
* @param int $entryId
|
||||||
|
*
|
||||||
|
* @return null|mixed
|
||||||
|
*/
|
||||||
|
protected function isInArray(array $array, int $entryId)
|
||||||
|
{
|
||||||
|
if (isset($array[$entryId])) {
|
||||||
|
return $array[$entryId];
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asset accounts actually earn money by being the destination of a deposit or the destination
|
||||||
|
* of a transfer. The money moves to them.
|
||||||
|
*
|
||||||
|
* A revenue account doesn't really earn money itself. Money is earned "from" the revenue account.
|
||||||
|
* So, the call to find out how many money has been earned by/from a revenue account is slightly different.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param Account $account
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function earnedInPeriod(Account $account, Carbon $start, Carbon $end)
|
||||||
|
{
|
||||||
|
/** @var ARI $repository */
|
||||||
|
$repository = app(ARI::class);
|
||||||
|
$collection = new Collection([$account]);
|
||||||
|
$type = $account->accountType->type;
|
||||||
|
switch ($type) {
|
||||||
|
case AccountType::DEFAULT:
|
||||||
|
case AccountType::ASSET:
|
||||||
|
return $repository->earnedInPeriod($collection, $start, $end);
|
||||||
|
case AccountType::REVENUE:
|
||||||
|
return $repository->earnedFromInPeriod($collection, $start, $end);
|
||||||
|
default:
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asset accounts actually spend money by being the source of a withdrawal or the source
|
||||||
|
* of a transfer. The money moves away from them.
|
||||||
|
*
|
||||||
|
* An expense account doesn't really spend money itself. Money is spent "at" the expense account.
|
||||||
|
* So, the call to find out how many money has been spent on/at an expense account is slightly different.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param Account $account
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function spentInPeriod(Account $account, Carbon $start, Carbon $end): string
|
||||||
|
{
|
||||||
|
/** @var ARI $repository */
|
||||||
|
$repository = app(ARI::class);
|
||||||
|
$collection = new Collection([$account]);
|
||||||
|
$type = $account->accountType->type;
|
||||||
|
switch ($type) {
|
||||||
|
case AccountType::DEFAULT:
|
||||||
|
case AccountType::ASSET:
|
||||||
|
return $repository->spentInPeriod($collection, $start, $end);
|
||||||
|
case AccountType::EXPENSE:
|
||||||
|
return $repository->spentAtInPeriod($collection, $start, $end);
|
||||||
|
default:
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user