Compare commits

...

256 Commits

Author SHA1 Message Date
James Cole
b252b9da66 Merge branch 'release/3.4.3' 2015-06-01 17:37:02 +02:00
James Cole
cdef9c3c7e New version. 2015-06-01 17:36:53 +02:00
James Cole
71dcebb744 New read me [skip ci] 2015-06-01 17:36:13 +02:00
James Cole
25f248c60a New read me [skip ci] 2015-06-01 17:35:48 +02:00
James Cole
d5cbc17831 Update read me. 2015-06-01 17:35:03 +02:00
James Cole
7a10217511 New read me and scrutiniser instructions. 2015-05-31 20:53:31 +02:00
James Cole
7559efab77 Update build thing. 2015-05-31 20:52:20 +02:00
James Cole
8254efbd03 Fix modal. 2015-05-31 20:24:06 +02:00
James Cole
4ae24225a5 Cleanup some modals. 2015-05-31 20:23:49 +02:00
James Cole
67d9154563 Added some new code to implement a permission scheme. 2015-05-28 06:43:07 +02:00
James Cole
ad0319c188 Some new translations [skip ci] 2015-05-28 06:11:39 +02:00
James Cole
eb650ea3ec Some code cleanup 2015-05-27 08:36:26 +02:00
James Cole
7eba33e805 Fixed some issues for scrutiniser [skip ci] 2015-05-27 07:58:54 +02:00
James Cole
e1cb9d387e Fixed chart and redirect 2015-05-27 07:51:33 +02:00
James Cole
2ace7c3ca0 Some code cleanup [skip ci] 2015-05-27 07:27:05 +02:00
James Cole
58014f0592 Extra translation [skip ci] 2015-05-27 06:57:02 +02:00
James Cole
1d4938bb09 Small fix in error handler. 2015-05-26 22:12:34 +02:00
James Cole
bbf4007c3e Fixed return type [skip ci] 2015-05-26 20:59:16 +02:00
Sander Dorigo
4d5124fb4c Merge pull request #81 from JC5/scrutinizer-patch-4
Scrutinizer Auto-Fixes
2015-05-26 20:58:11 +02:00
Scrutinizer Auto-Fixer
14a7cd05b1 Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2015-05-26 18:57:31 +00:00
James Cole
946be80eef Fix route urls. 2015-05-26 20:37:01 +02:00
James Cole
9ad8b1a980 Some optimisations. 2015-05-26 20:28:18 +02:00
James Cole
f733216fcb Trigger a build. 2015-05-26 20:18:21 +02:00
Sander Dorigo
ffc6139e21 Merge pull request #80 from JC5/scrutinizer-patch-3
Scrutinizer Auto-Fixes
2015-05-26 20:16:39 +02:00
Scrutinizer Auto-Fixer
571cac6644 Scrutinizer Auto-Fixes
This commit consists of patches automatically generated for this project on https://scrutinizer-ci.com
2015-05-26 17:50:09 +00:00
James Cole
2738ac5a5c Did some cleanup [skip ci] 2015-05-26 19:48:49 +02:00
James Cole
7dfde51b84 Fixed tests. 2015-05-26 19:38:52 +02:00
James Cole
2d2f18e538 Code cleanup. 2015-05-26 12:19:11 +02:00
James Cole
3af0dd2e3b Some code cleanup [skip ci] 2015-05-26 12:08:46 +02:00
James Cole
349e077802 Added model data to models to aid scrutiniser. 2015-05-26 11:15:45 +02:00
James Cole
812aae358f Some code cleanup. 2015-05-26 08:17:58 +02:00
James Cole
c3c59d0627 Fixed some JS things [skip ci] 2015-05-26 07:50:38 +02:00
James Cole
89518b412d Merge branch 'release/3.4.2' into develop 2015-05-25 23:18:33 +02:00
James Cole
f43b026162 Merge branch 'release/3.4.2' 2015-05-25 23:18:32 +02:00
James Cole
b806c70f52 New read me. 2015-05-25 22:58:49 +02:00
James Cole
10bff3c0b8 Fix tests. 2015-05-25 22:56:00 +02:00
James Cole
65c12fd0b2 Merge branch 'release/3.4.1' 2015-05-25 22:24:28 +02:00
James Cole
50f71c4130 Merge branch 'release/3.4.1' into develop 2015-05-25 22:24:28 +02:00
James Cole
8e401a53dc New version. 2015-05-25 22:24:21 +02:00
James Cole
64a289a47c Cleanup some code [skip ci] 2015-05-25 22:17:41 +02:00
James Cole
8f2c37061b Update translations [skip ci] 2015-05-25 22:16:00 +02:00
James Cole
39f2de6b90 Cleanup code [skip ci] 2015-05-25 22:04:24 +02:00
James Cole
855ba8d4f3 Cleanup [skip ci] 2015-05-25 22:01:48 +02:00
James Cole
74f098e718 Some new translations [skip ci] 2015-05-25 21:39:05 +02:00
James Cole
56c8a84691 Update translations [skip ci] 2015-05-25 21:26:34 +02:00
James Cole
8bbf319032 Some translations and a new test. 2015-05-25 21:17:36 +02:00
James Cole
afbca4ae65 Newline in travis.ml [skip ci] 2015-05-25 20:08:31 +02:00
James Cole
0ef6d2f91a Code cleanup. 2015-05-25 19:58:13 +02:00
James Cole
fbe4435599 Fix translation [skip ci] 2015-05-25 19:19:27 +02:00
James Cole
34be565dd1 New translations [skip ci] 2015-05-25 19:18:16 +02:00
James Cole
af838e4ed1 New translations. 2015-05-25 09:23:45 +02:00
James Cole
60fe8ce011 New GA events [skip ci] 2015-05-25 08:12:31 +02:00
James Cole
8ece341467 Add GA events [skip ci] 2015-05-25 08:01:06 +02:00
James Cole
dfa6bdbcb8 Fixed menu for mobile screens [skip ci] 2015-05-25 07:53:13 +02:00
James Cole
fb2481ebaa Add some GA events. 2015-05-25 07:26:19 +02:00
James Cole
4874c116cf Add GA to 503 page. [skip ci] 2015-05-25 07:23:35 +02:00
James Cole
e19c44efbd Some code cleanup. 2015-05-25 07:14:04 +02:00
James Cole
4b687b9bdc Clean up config 2015-05-25 07:03:26 +02:00
James Cole
6af79ef601 Fixed tests 2015-05-24 23:08:55 +02:00
James Cole
352b996ad2 Cleanup some code. 2015-05-24 22:59:48 +02:00
James Cole
4a93bb35f8 Cleanup budget view. 2015-05-24 22:54:59 +02:00
James Cole
8e1f493daf Another build routine. 2015-05-24 21:45:10 +02:00
James Cole
59ee153375 Fixed test. 2015-05-24 21:11:37 +02:00
James Cole
60f7f1fc16 New build routine. 2015-05-24 21:07:22 +02:00
James Cole
b7433683d8 Cleanup cleanup [skip ci] 2015-05-24 20:57:27 +02:00
James Cole
42799b9273 Some JS cleanup. 2015-05-24 20:48:31 +02:00
James Cole
860a0f790e Update js [skip ci] 2015-05-24 20:41:14 +02:00
James Cole
8daccbfbb4 Add JSHint stuff. [skip ci] 2015-05-24 18:22:41 +02:00
James Cole
285b77dcb7 Merge branch 'release/3.4.0.10' into develop 2015-05-24 15:56:05 +02:00
James Cole
6e48827d3f Merge branch 'release/3.4.0.10' 2015-05-24 15:56:04 +02:00
James Cole
f0c20cc706 New release. 2015-05-24 15:55:59 +02:00
James Cole
8916c0a3de Clean code [skip ci] 2015-05-24 15:18:19 +02:00
James Cole
7193a77840 Some translations and cleanup [skip ci] 2015-05-24 15:13:07 +02:00
James Cole
61930b5b51 Code cleanup [skip ci] 2015-05-24 15:03:45 +02:00
James Cole
11a494cacf Remove some middleware, fix cleanup [skip ci] 2015-05-24 12:53:47 +02:00
James Cole
17f9bf0339 Merge branch 'release/3.4.0.9' into develop 2015-05-24 11:53:44 +02:00
James Cole
3d9755ca8c Merge branch 'release/3.4.0.9' 2015-05-24 11:53:43 +02:00
James Cole
b5cf2d03e6 New version. 2015-05-24 11:53:34 +02:00
James Cole
e3b35b8f35 Add code climate file [skip ci] 2015-05-24 11:46:41 +02:00
James Cole
1c1fe672bd Some code cleanup [skip ci] 2015-05-24 11:41:52 +02:00
James Cole
6c71f68ed8 Should cover models. 2015-05-24 11:13:46 +02:00
James Cole
8f2f912cdf New (empty) tests for models. 2015-05-24 10:01:00 +02:00
James Cole
bf6ea16acb Fixed test. 2015-05-24 09:29:44 +02:00
James Cole
288546c2b9 Fixed some math. 2015-05-24 08:00:40 +02:00
James Cole
724db6c34c Built some new tests 2015-05-24 07:43:48 +02:00
James Cole
067c451c1d Fixed tests 2015-05-23 21:41:04 +02:00
James Cole
11e3696191 Cleanup tests. 2015-05-23 21:23:51 +02:00
James Cole
41e20664de Fixed coverage. 2015-05-23 21:18:20 +02:00
James Cole
d8de90d6f3 Ignore constructors. 2015-05-23 20:49:57 +02:00
James Cole
b01e8299d3 Fixed tests 2015-05-23 20:47:31 +02:00
James Cole
1ec11e3e2e Compartmentalised all tests. 2015-05-23 19:41:54 +02:00
James Cole
422f429725 Experimental count thing. 2015-05-23 17:38:16 +02:00
James Cole
5c55fa5fbb Remove encrypted amounts because it stinks. 2015-05-23 17:33:04 +02:00
James Cole
80d845fdf2 Save but don't use. 2015-05-23 17:18:23 +02:00
James Cole
601fe68346 Don't multiply transactions. 2015-05-23 17:14:36 +02:00
James Cole
9e050fb059 Updated some tests. 2015-05-23 17:11:16 +02:00
James Cole
99d4adf5e6 Translations [skip ci] 2015-05-23 15:57:38 +02:00
James Cole
85f8d1e8e9 Math is hard [skip ci] 2015-05-23 15:45:01 +02:00
James Cole
8334d3d99f Translation error [skip ci] 2015-05-23 15:43:48 +02:00
James Cole
cff08d19eb Slowly move away from using the raw 'transactions.amount' field. 2015-05-23 15:42:19 +02:00
James Cole
2d86390bc1 Experimental query.Code cleanup [skip ci] 2015-05-23 09:11:59 +02:00
James Cole
7a20835571 Code cleanup [skip ci] 2015-05-23 09:09:25 +02:00
James Cole
ff3c9676b5 Encrypt more stuff in the cleanup routine [skip ci] 2015-05-23 09:05:08 +02:00
James Cole
055f97dab1 Encrypt more stuff in the cleanup routine [skip ci] 2015-05-23 09:03:52 +02:00
James Cole
8a867e71a1 Encrypt more stuff in the cleanup routine [skip ci] 2015-05-23 09:02:27 +02:00
James Cole
b8275b4734 Encrypt more stuff in the cleanup routine [skip ci] 2015-05-23 09:01:38 +02:00
James Cole
36b951b146 Encrypt more stuff in the cleanup routine [skip ci] 2015-05-23 09:01:07 +02:00
James Cole
c5a5f17643 Encrypt more stuff in the cleanup routine [skip ci] 2015-05-23 09:00:11 +02:00
James Cole
16b909c4df Encrypt more stuff in the cleanup routine [skip ci] 2015-05-23 08:59:23 +02:00
James Cole
92b7648e03 Encrypt more stuff in the cleanup routine [skip ci] 2015-05-23 08:58:21 +02:00
James Cole
ca46ebe3b2 Encrypt bill amounts [skip ci] 2015-05-23 08:57:02 +02:00
James Cole
676e48254a Whoops [skip ci] 2015-05-23 08:55:16 +02:00
James Cole
b15b55227d Add another cleanup routine. [skip ci] 2015-05-23 08:54:25 +02:00
James Cole
3c3b723913 Some code cleanup [skip ci] 2015-05-23 08:51:24 +02:00
James Cole
f05002c729 Updated models for encryption. 2015-05-23 08:46:46 +02:00
James Cole
1c2cbd5b40 New stuff for encrypted amounts. 2015-05-23 07:47:36 +02:00
James Cole
54c6ca9f45 Expanded some tests. 2015-05-22 20:25:12 +02:00
James Cole
c10efbb170 Also encrypt meta data for reminders. 2015-05-22 19:19:18 +02:00
James Cole
a496ad5814 Simple routine to encrypt entries which were not encrypted yet. 2015-05-22 19:18:00 +02:00
James Cole
50cf7f6a3b Merge branch 'release/3.4.0.8' 2015-05-22 18:55:13 +02:00
James Cole
f946f10afd Merge branch 'release/3.4.0.8' into develop 2015-05-22 18:55:13 +02:00
James Cole
eecb4db34c Built chart tests. 2015-05-22 18:31:57 +02:00
James Cole
1f865d3ea4 Improved coverage. 2015-05-22 15:05:32 +02:00
James Cole
623bb4b350 New tests. 2015-05-22 10:17:20 +02:00
James Cole
dc8ad673a6 New test to cover some reminder stuff. 2015-05-22 08:52:30 +02:00
James Cole
4914ad821e Fixed coverage for transaction controller. 2015-05-22 08:03:34 +02:00
James Cole
f099cbadc3 Version increment. 2015-05-22 07:16:36 +02:00
James Cole
42cda384c8 Fix help routes 2015-05-22 07:15:40 +02:00
James Cole
23c91b9990 Some translations, playing around with popups. [skip ci] 2015-05-21 23:05:31 +02:00
James Cole
ff0379182e Sort chart [skip ci] 2015-05-21 18:57:14 +02:00
James Cole
e08a23948f Fixed chart. [skip ci] 2015-05-21 18:50:23 +02:00
James Cole
bd56de6d36 Fix other translations [skip ci] 2015-05-21 17:47:10 +02:00
James Cole
42970aea80 Fix some translations. 2015-05-21 17:45:01 +02:00
James Cole
003a05ee8d Fixed the category chart. 2015-05-21 17:27:48 +02:00
James Cole
ffb11b01a6 Some new translations. 2015-05-21 07:44:44 +02:00
James Cole
e426f5d5da Some new translations. 2015-05-21 07:30:38 +02:00
James Cole
6989f61e1b Extra translations [skip ci] 2015-05-20 20:10:01 +02:00
James Cole
0e6677ccb3 Remove cash accounts from list [skip ci] 2015-05-20 20:04:27 +02:00
James Cole
8f104d555a Added newlines to files. 2015-05-20 19:56:14 +02:00
James Cole
b1d3158db1 Code cleanup. 2015-05-20 19:55:53 +02:00
James Cole
7645005d5a Return of account id. 2015-05-20 18:18:05 +02:00
James Cole
411f77fd29 Fixed some other displays of money 2015-05-20 18:09:44 +02:00
James Cole
568ab26db1 Spell check [skip ci] 2015-05-20 17:06:47 +02:00
James Cole
29652108f0 Fixed tests. 2015-05-20 17:04:53 +02:00
James Cole
f07e4dc711 Fix sort. [skip ci] 2015-05-20 07:21:40 +02:00
James Cole
8a2ac457c2 Name fix [skip ci] 2015-05-20 07:21:01 +02:00
James Cole
9e54eecfaa Fixed some views. 2015-05-20 07:20:02 +02:00
James Cole
95ef691077 Fixed some more reports and charts. [skip ci] 2015-05-20 07:07:46 +02:00
James Cole
7a0ad5a587 Fixed a chart [skip ci] 2015-05-20 06:50:24 +02:00
James Cole
42b49d0e4b Added some correcting methods. [skip ci] 2015-05-20 06:50:15 +02:00
James Cole
9217c2f003 Corrected some charts [skip ci] 2015-05-20 06:49:51 +02:00
James Cole
fbdf66998d Added a forgotten chart, corrected some others. [skip ci] 2015-05-20 06:49:22 +02:00
James Cole
deda9d3c54 Add corrected expense routes [skip ci] 2015-05-20 06:49:03 +02:00
James Cole
a5d78f20ae Add corrected income and expense methods [skip ci] 2015-05-20 06:48:52 +02:00
James Cole
5ed09e3f38 Call the corrected spent function [skip ci] 2015-05-20 06:47:53 +02:00
James Cole
3e9774cd66 Merge branch 'release/3.4.0.7' 2015-05-18 18:23:07 +02:00
James Cole
54387c8fdf Merge branch 'release/3.4.0.7' into develop 2015-05-18 18:23:07 +02:00
James Cole
7eec949a13 Push new release. 2015-05-18 18:23:01 +02:00
James Cole
4113c4ff40 Fixed the tests. 2015-05-18 17:57:44 +02:00
James Cole
1bf0968bfe Show correct icon. [skip ci] 2015-05-18 17:05:22 +02:00
James Cole
374b90fb00 Show correct amount [skip ci] 2015-05-18 17:04:10 +02:00
James Cole
064e60e9d5 Show tag amount better [skip ci] 2015-05-18 17:02:18 +02:00
James Cole
b637455970 New translations [skip ci] 2015-05-18 16:59:01 +02:00
James Cole
68158937d1 Fixed translation [skip ci] 2015-05-18 06:56:59 +02:00
James Cole
adb1356b7a Small bug fix in display of income vs. expenses [skip ci] 2015-05-18 06:55:36 +02:00
James Cole
d880ccb8e0 Small bug fix in display of income vs. expenses [skip ci] 2015-05-18 06:54:46 +02:00
James Cole
050fb1d1ef Some translations [skip ci] 2015-05-17 18:06:00 +02:00
James Cole
6580752bde Now includes chart! [skip ci] 2015-05-17 18:03:16 +02:00
James Cole
c9df265c9b Included bills in month report. [skip ci] 2015-05-17 17:54:13 +02:00
James Cole
098e5bc162 Small translation fix [skip ci] 2015-05-17 17:27:56 +02:00
James Cole
4b2dcc74d4 Expanded the amount thing. 2015-05-17 16:12:00 +02:00
James Cole
a9254c5c9a Some new translations, better tag view [skip ci] 2015-05-17 15:55:24 +02:00
James Cole
7ce57e6ccb Fix a view, fix tag format. 2015-05-17 15:24:30 +02:00
James Cole
0fcb32a66f Fix update error. 2015-05-17 15:17:06 +02:00
James Cole
9946535f01 Some new bread crumbs [skip ci] 2015-05-17 15:12:45 +02:00
James Cole
2b17396d6b Fix some translations. 2015-05-17 13:44:58 +02:00
James Cole
b01d5bc237 Translation fixes [skip ci] 2015-05-17 12:53:32 +02:00
James Cole
b123860304 More stuff. 2015-05-17 12:49:09 +02:00
James Cole
033f5b67db Code cleanup 2015-05-17 11:28:58 +02:00
James Cole
6280448dfb Fixed more tests. 2015-05-17 10:47:12 +02:00
James Cole
01cd3333e4 Fixing tests. 2015-05-17 10:36:11 +02:00
James Cole
63050907b9 Code cleanup. 2015-05-17 10:30:18 +02:00
James Cole
beedf7d780 Cleaning up 2015-05-17 10:10:58 +02:00
James Cole
6b8194261f Clean up and simplify code. 2015-05-17 10:01:47 +02:00
James Cole
dbb1c4d534 Fixed some reports. 2015-05-17 09:35:49 +02:00
James Cole
e6263f9ff5 Some cleaning up 2015-05-17 09:18:44 +02:00
James Cole
6ca119c4db Minor changes [skip ci] 2015-05-17 09:04:55 +02:00
James Cole
c483a1ab3a Ignore simple classes. 2015-05-16 19:08:54 +02:00
James Cole
2e7edd033c Some expanded things. 2015-05-16 16:47:52 +02:00
James Cole
c576902501 Fixed tests. 2015-05-16 16:04:51 +02:00
James Cole
66c2951594 Cleanup 2015-05-16 15:52:09 +02:00
James Cole
b812881cdb More hip report stuff. 2015-05-16 15:43:58 +02:00
James Cole
cdeac2c6db Should simplify reports. 2015-05-16 14:51:23 +02:00
James Cole
bca2ddd529 Budget report thing. 2015-05-16 14:14:22 +02:00
James Cole
e7285c6499 Some overhauls. 2015-05-16 13:53:08 +02:00
James Cole
bdff275672 Simplified report code. 2015-05-16 13:06:38 +02:00
James Cole
bec58a1ee6 Experimental test coverage. 2015-05-16 10:34:38 +02:00
James Cole
f64616748c Expenses only [skip ci] 2015-05-16 10:18:32 +02:00
James Cole
512ce15973 Small tweaks in charts. 2015-05-16 10:13:41 +02:00
James Cole
ed8b301574 Routes and JS cleanup. 2015-05-16 10:05:22 +02:00
James Cole
d22a6c019c Fixed lots of chart references. 2015-05-16 09:57:31 +02:00
James Cole
a0cb1b9d9e Clean up and split chart controllers 2015-05-16 09:41:14 +02:00
James Cole
a5294c62ea Renamed a method. 2015-05-16 09:26:54 +02:00
James Cole
e155d3311c Fixed tests 2015-05-16 09:25:14 +02:00
James Cole
0a372b0daf Cleanup tests 2015-05-16 09:16:32 +02:00
James Cole
69143399d1 Moved some stuff around. 2015-05-16 09:09:52 +02:00
James Cole
3270d3bf96 Cleanup. 2015-05-16 08:14:26 +02:00
James Cole
3896a66122 Fixed tests. 2015-05-16 08:09:15 +02:00
James Cole
b94781aef1 Some optimisations. 2015-05-16 08:05:04 +02:00
James Cole
bed1adc367 Fixed budget. 2015-05-16 07:56:15 +02:00
James Cole
ae54497efa Differ between shared and normal transactions (not build yet). 2015-05-16 07:49:02 +02:00
James Cole
06b747c221 Some cleanup and translations. 2015-05-16 07:28:58 +02:00
James Cole
f159beee0d Fixed preferences tests. 2015-05-15 23:24:55 +02:00
James Cole
49d7dea086 Fixed some coverage. 2015-05-15 23:02:42 +02:00
James Cole
3e65733dc5 Small fix in report view [skip ci] 2015-05-15 22:12:31 +02:00
James Cole
cc375d58bb Fixed tests. 2015-05-15 22:06:52 +02:00
James Cole
911c7c662a Expanded reports. 2015-05-15 22:00:00 +02:00
James Cole
aae003be33 Some more cleaning up and fixing 2015-05-15 21:01:24 +02:00
James Cole
aede03d8b2 Some more layout changes. 2015-05-15 20:43:50 +02:00
James Cole
f0f5ada7de More changes to reports. 2015-05-15 20:38:39 +02:00
James Cole
58365121a3 Fixed tests. 2015-05-15 20:15:58 +02:00
James Cole
d5a154d2e6 Cleaned up reports and associated views. 2015-05-15 20:07:51 +02:00
James Cole
b20f369aef Some new tests. 2015-05-15 18:39:59 +02:00
James Cole
abb8aa0b29 Merge branch 'feature/translations' into develop 2015-05-15 18:38:26 +02:00
James Cole
5368a0f1d7 Some new translations. 2015-05-14 19:44:20 +02:00
James Cole
d3897eece7 This should fix the tests on the translations branch. 2015-05-14 18:15:31 +02:00
James Cole
a82b829da9 More translations. 2015-05-14 18:00:56 +02:00
James Cole
9f5058e81a Some new translations. 2015-05-14 17:52:50 +02:00
James Cole
5b19263720 Some more [skip ci] 2015-05-14 16:43:12 +02:00
James Cole
9d5a0db0d9 [skip ci] 2015-05-14 16:36:08 +02:00
James Cole
4bd8a7014f Count things [skip ci] 2015-05-14 16:35:41 +02:00
James Cole
353e96d951 Better (and translated) delete forms. [skip ci] 2015-05-14 16:32:35 +02:00
James Cole
149a6f92b0 Translations [skip ci] 2015-05-14 15:56:23 +02:00
James Cole
d66426c137 Nieuw vertalingen [skip ci] 2015-05-14 15:53:56 +02:00
James Cole
4fc9966392 Chart translations [skip ci] 2015-05-14 13:43:58 +02:00
James Cole
417766f0db Various date localisation. [skip ci] 2015-05-14 13:41:21 +02:00
James Cole
de9ac97887 Also english. [skip ci] 2015-05-14 13:19:26 +02:00
James Cole
6be42f112a Charts and titles in Dutch. [skip ci] 2015-05-14 13:17:53 +02:00
James Cole
3895ae63c7 Some translations for lists [skip ci] 2015-05-14 13:00:43 +02:00
James Cole
607d416d54 Better translation for 'balance' [skip ci] 2015-05-14 12:11:56 +02:00
James Cole
038693dc86 More index translations [skip ci] 2015-05-14 12:10:42 +02:00
James Cole
cc9be13544 Added a bread crumb [skip ci] 2015-05-14 11:50:48 +02:00
James Cole
9c1474087f Forgot one [skip ci] 2015-05-14 11:50:04 +02:00
James Cole
831de2bcf4 New menu translations [skip ci] 2015-05-14 11:48:59 +02:00
James Cole
eb687333bb Small edits to buttons and others. [skip ci] 2015-05-14 11:31:54 +02:00
James Cole
5cc7966d54 Some new form things. [skip ci] 2015-05-14 11:25:43 +02:00
James Cole
d1a34e7a6f Breadcrumbs translated to English. [skip ci] 2015-05-14 11:22:20 +02:00
James Cole
d63d791717 Translated all bread crumbs to Dutch. [skip ci] 2015-05-14 11:17:56 +02:00
James Cole
015570c741 Small translations as a basic start [skip ci] 2015-05-14 10:26:15 +02:00
James Cole
8400ebc9c6 Added a language test, added Dutch basic file. [skip ci] 2015-05-14 10:03:57 +02:00
James Cole
9f99e7c0af Edit and set language [skip ci] 2015-05-14 09:59:30 +02:00
James Cole
392c1fc399 Add language selector to preferences [skip ci] 2015-05-14 09:56:41 +02:00
James Cole
d3cea7a89c Add new supported languages [skip ci] 2015-05-14 09:52:58 +02:00
James Cole
1dcf7407e6 Cleanup [skip ci] 2015-05-14 09:51:54 +02:00
James Cole
d543c033a3 Small fixes to translations. 2015-05-14 09:50:07 +02:00
James Cole
2054b5b3dd Merge branch 'release/3.4.0.6' into develop 2015-05-14 09:21:23 +02:00
276 changed files with 12112 additions and 6627 deletions

25
.codeclimate.yml Normal file
View File

@@ -0,0 +1,25 @@
# Save as .codeclimate.yml (note leading .) in project root directory
languages:
JavaScript: true
PHP: true
exclude_paths:
- "public/packages/maximebf/php-debugbar/debugbar.js"
- "public/packages/maximebf/php-debugbar/widgets.js"
- "public/packages/maximebf/php-debugbar/openhandler.js"
- "public/packages/maximebf/php-debugbar/widgets/sqlqueries/widget.js"
- "public/js/bootstrap3-typeahead.min.js"
- "public/js/bootstrap-sortable.js"
- "public/js/bootstrap-tagsinput.min.js"
- "public/js/bootstrap-tagsinput.min.js.map"
- "public/js/daterangepicker.js"
- "public/js/jquery-2.1.3.min.js"
- "public/js/jquery-2.1.3.min.js.map"
- "public/js/jquery-ui.min.js"
- "public/js/metisMenu.js"
- "public/js/moment.min.js"
- "public/js/sb-admin-2.js"
- "public/bootstrap/*"
- "resources/lang/*"
- "tests/*"
- "database/*"
- "storage/*"

View File

@@ -1,3 +1,3 @@
src_dir: . src_dir: .
coverage_clover: storage/coverage/clover.xml coverage_clover: build/logs/clover.xml
json_path: storage/coverage/coveralls-upload.json json_path: build/logs/coveralls-upload.json

View File

@@ -17,3 +17,5 @@ EMAIL_USERNAME=
EMAIL_PASSWORD= EMAIL_PASSWORD=
ANALYTICS_ID= ANALYTICS_ID=
EMAIL_PRETEND=false EMAIL_PRETEND=false
RUNCLEANUP=true
SITE_OWNER=mail@example.com

22
.jshintrc Normal file
View File

@@ -0,0 +1,22 @@
{
"undef": true,
"unused": false,
"strict": true,
"browser": true,
"jquery": true,
"devel": true,
"globals": [
"language",
"token",
"currencyCode",
"$",
"token",
"accountID",
"billID",
"currentMonthName",
"previousMonthName",
"nextMonthName",
"everything",
"moment"
]
}

5
.scrutinizer.yml Normal file
View File

@@ -0,0 +1,5 @@
# .scrutinizer.yml
tools:
external_code_coverage:
timeout: 1800 # Timeout in seconds.
runs: 2

View File

@@ -6,10 +6,6 @@ php:
- 5.5 - 5.5
- 5.6 - 5.6
addons:
code_climate:
repo_token: 26489f9e854fcdf7e7660ba29c1455694685465b1f90329a79f7d2bf448acb61
install: install:
- composer update - composer update
- php artisan env - php artisan env
@@ -20,3 +16,7 @@ script:
after_script: after_script:
- php vendor/bin/coveralls - php vendor/bin/coveralls
- CODECLIMATE_REPO_TOKEN=26489f9e854fcdf7e7660ba29c1455694685465b1f90329a79f7d2bf448acb61 ./vendor/bin/test-reporter --stdout > codeclimate.json
- "curl -X POST -d @codeclimate.json -H 'Content-Type: application/json' -H 'User-Agent: Code Climate (PHP Test Reporter v0.1.1)' https://codeclimate.com/test_reports"
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml

View File

@@ -1,13 +1,9 @@
# Firefly III # Firefly III (v3.4.3)
#### v3.4.0.6
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/JC5/firefly-iii/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/JC5/firefly-iii/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/JC5/firefly-iii/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/JC5/firefly-iii/?branch=master)
[![Build Status](https://scrutinizer-ci.com/g/JC5/firefly-iii/badges/build.png?b=master)](https://scrutinizer-ci.com/g/JC5/firefly-iii/build-status/master)
[![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=develop)](https://travis-ci.org/JC5/firefly-iii)
[![Project Status](http://stillmaintained.com/JC5/firefly-iii.png?a=b)](http://stillmaintained.com/JC5/firefly-iii)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102/mini.png)](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102)
[![Code Climate](https://codeclimate.com/github/JC5/firefly-iii/badges/gpa.svg)](https://codeclimate.com/github/JC5/firefly-iii)
[![Coverage Status](https://coveralls.io/repos/JC5/firefly-iii/badge.svg?branch=master)](https://coveralls.io/r/JC5/firefly-iii?branch=master)
[![Latest Stable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/stable.svg)](https://packagist.org/packages/grumpydictator/firefly-iii)
![GA](https://ga-beacon.appspot.com/UA-58172398-6/firefly-iii/readme)
## About ## About
"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 "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
@@ -34,20 +30,11 @@ and the philosophy behind it.
It's III, or 3, because [version 2](https://github.com/JC5/Firefly) and version 1 (not online) preceded it. It has been growing steadily ever since. It's III, or 3, because [version 2](https://github.com/JC5/Firefly) and version 1 (not online) preceded it. It has been growing steadily ever since.
## Running and installing
If you're still interested please read [the installation guide](https://github.com/JC5/firefly-iii/wiki/Installation),
[the upgrade guide](https://github.com/JC5/firefly-iii/wiki/Upgrade-instructions) (if applicable)
and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**.
If you want to try out Firefly III, you can do so on [this dedicated website](https://geld.nder.be/).
This site always runs the latest version of Firefly III. If you want to use it, please read the [privacy considerations](https://github.com/JC5/firefly-iii/wiki/Privacy-on-demo-site) for this demo-site.
## Current features ## Current features
- [A double-entry bookkeeping system](https://en.wikipedia.org/wiki/Double-entry_bookkeeping_system); - [A double-entry bookkeeping system](https://en.wikipedia.org/wiki/Double-entry_bookkeeping_system);
- You can store, edit and remove [withdrawals, deposits and transfers](https://en.wikipedia.org/wiki/Financial_transaction). This allows you full financial management; - You can store, edit and remove [withdrawals, deposits and transfers](https://en.wikipedia.org/wiki/Financial_transaction). This allows you full financial management;
- You can manage different types of accounts - You can manage different types of accounts;
- [Asset](https://en.wikipedia.org/wiki/Asset) accounts - [Asset](https://en.wikipedia.org/wiki/Asset) accounts
- Shared [asset accounts](https://en.wikipedia.org/wiki/Asset) ([household accounts](https://en.wikipedia.org/wiki/Household)) - Shared [asset accounts](https://en.wikipedia.org/wiki/Asset) ([household accounts](https://en.wikipedia.org/wiki/Household))
- Saving accounts - Saving accounts
@@ -65,8 +52,8 @@ Everything is organised:
- Clear views that should show you how you're doing; - Clear views that should show you how you're doing;
- Easy navigation through your records; - Easy navigation through your records;
- Browse back and forth to see previous months or even years; - Browse back and forth to see previous months or even years;
- Lots of charts because we all love them. - Lots of charts because we all love them;
- Financial reporting showing you how well you are doing; - Financial reporting showing you how well you are doing.
## Screenshots ## Screenshots
@@ -86,6 +73,16 @@ _Please note that everything in these screenshots is fictional and may not be re
![Piggy banks](https://i.nder.be/hkud0h53) ![Piggy banks](https://i.nder.be/hkud0h53)
## Running and installing
If you're still interested please read [the installation guide](https://github.com/JC5/firefly-iii/wiki/Installation),
[the upgrade guide](https://github.com/JC5/firefly-iii/wiki/Upgrade-instructions) (if applicable)
and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**.
If you want to try out Firefly III, you can do so on [this dedicated website](https://geld.nder.be/).
This site always runs the latest version of Firefly III. If you want to use it, please read the [privacy considerations](https://github.com/JC5/firefly-iii/wiki/Privacy-on-demo-site) for this demo-site.
## Current state ## Current state
Firefly III is pretty much all grown up. Full test coverage (nerd alert!) is coming. One of the things on the todo-list Firefly III is pretty much all grown up. Full test coverage (nerd alert!) is coming. One of the things on the todo-list
@@ -94,3 +91,9 @@ is adding translations.
Questions, ideas, bugs or other things to contribute? [Let me know](https://github.com/JC5/firefly-iii/issues/new)! Questions, ideas, bugs or other things to contribute? [Let me know](https://github.com/JC5/firefly-iii/issues/new)!
If you like this tool, feel free to [donate me some beer money](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2ZMV952UUSCLU&lc=NL&item_name=Development%20of%20Firefly&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted). If you like this tool, feel free to [donate me some beer money](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2ZMV952UUSCLU&lc=NL&item_name=Development%20of%20Firefly&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted).
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102/mini.png)](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102)
[![Code Climate](https://codeclimate.com/github/JC5/firefly-iii/badges/gpa.svg)](https://codeclimate.com/github/JC5/firefly-iii)
[![Project Status](http://stillmaintained.com/JC5/firefly-iii.png?a=b)](http://stillmaintained.com/JC5/firefly-iii)
[![Latest Stable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/stable.svg)](https://packagist.org/packages/grumpydictator/firefly-iii)
![GA](https://ga-beacon.appspot.com/UA-58172398-6/firefly-iii/readme)

View File

@@ -26,6 +26,8 @@ class Kernel extends ConsoleKernel
* *
* @param \Illuminate\Console\Scheduling\Schedule $schedule * @param \Illuminate\Console\Scheduling\Schedule $schedule
* *
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @return void * @return void
*/ */
protected function schedule(Schedule $schedule) protected function schedule(Schedule $schedule)

View File

@@ -2,6 +2,7 @@
use Exception; use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;
/** /**
* Class Handler * Class Handler
@@ -27,12 +28,13 @@ class Handler extends ExceptionHandler
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Exception $e * @param \Exception $e
* @SuppressWarnings(PHPMD.ShortVariable)
* *
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function render($request, Exception $e) public function render($request, Exception $e)
{ {
if ($this->isHttpException($e)) { if ($e instanceof HttpException) {
return $this->renderHttpException($e); return $this->renderHttpException($e);
} else { } else {
return parent::render($request, $e); return parent::render($request, $e);
@@ -43,6 +45,7 @@ class Handler extends ExceptionHandler
* Report or log an exception. * Report or log an exception.
* *
* This is a great spot to send exceptions to Sentry, Bugsnag, etc. * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
* @SuppressWarnings(PHPMD.ShortVariable)
* *
* @param \Exception $e * @param \Exception $e
* *

View File

@@ -6,7 +6,6 @@ use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent; use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Log;
/** /**
* Class ConnectJournalToPiggyBank * Class ConnectJournalToPiggyBank
@@ -19,6 +18,8 @@ class ConnectJournalToPiggyBank
/** /**
* Create the event handler. * Create the event handler.
* *
* @codeCoverageIgnore
*
*/ */
public function __construct() public function __construct()
{ {
@@ -28,6 +29,8 @@ class ConnectJournalToPiggyBank
/** /**
* Handle the event when journal is saved. * Handle the event when journal is saved.
* *
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
* @param JournalCreated $event * @param JournalCreated $event
* *
* @return boolean * @return boolean
@@ -37,45 +40,25 @@ class ConnectJournalToPiggyBank
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
$journal = $event->journal; $journal = $event->journal;
$piggyBankId = $event->piggyBankId; $piggyBankId = $event->piggyBankId;
if (intval($piggyBankId) < 1) {
return false;
}
Log::debug('JournalCreated event: ' . $journal->id . ', ' . $piggyBankId);
/** @var PiggyBank $piggyBank */ /** @var PiggyBank $piggyBank */
$piggyBank = Auth::user()->piggybanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']); $piggyBank = Auth::user()->piggybanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
if (is_null($piggyBank) || $journal->transactionType->type != 'Transfer') { if (is_null($piggyBank)) {
return false;
}
Log::debug('Found a piggy bank');
$amount = $journal->amount;
Log::debug('Amount: ' . $amount);
if ($amount == 0) {
return false; return false;
} }
// update piggy bank rep for date of transaction journal. // update piggy bank rep for date of transaction journal.
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first(); $repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
if (is_null($repetition)) { if (is_null($repetition)) {
Log::debug('Found no repetition for piggy bank for date ' . $journal->date->format('Y M d'));
return false; return false;
} }
Log::debug('Found rep! ' . $repetition->id); $amount = $journal->amount;
/*
* Add amount when
*/
/** @var Transaction $transaction */ /** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) { foreach ($journal->transactions()->get() as $transaction) {
if ($transaction->account_id == $piggyBank->account_id) { if ($transaction->account_id == $piggyBank->account_id) {
if ($transaction->amount < 0) { if ($transaction->amount < 0) {
$amount = $amount * -1; $amount = $transaction->amount * -1;
Log::debug('Transaction is away from piggy, so amount becomes ' . $amount);
} else {
Log::debug('Transaction is to from piggy, so amount stays ' . $amount);
} }
} }
} }
@@ -83,14 +66,8 @@ class ConnectJournalToPiggyBank
$repetition->currentamount += $amount; $repetition->currentamount += $amount;
$repetition->save(); $repetition->save();
PiggyBankEvent::create( PiggyBankEvent::create(['piggy_bank_id' => $piggyBank->id, 'transaction_journal_id' => $journal->id, 'date' => $journal->date, 'amount' => $amount]);
[
'piggy_bank_id' => $piggyBank->id,
'transaction_journal_id' => $journal->id,
'date' => $journal->date,
'amount' => $amount
]
);
return true; return true;
} }

View File

@@ -1,36 +0,0 @@
<?php namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\JournalDeleted;
/**
* Class JournalDeletedHandler
*
* @codeCoverageIgnore
* @package FireflyIII\Handlers\Events
*/
class JournalDeletedHandler
{
/**
* Create the event handler.
*
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param JournalDeleted $event
*
* @return void
*/
public function handle(JournalDeleted $event)
{
//
}
}

View File

@@ -2,6 +2,7 @@
use FireflyIII\Events\JournalSaved; use FireflyIII\Events\JournalSaved;
use FireflyIII\Models\PiggyBankEvent; use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\PiggyBankRepetition;
/** /**
* Class UpdateJournalConnection * Class UpdateJournalConnection
@@ -39,13 +40,17 @@ class UpdateJournalConnection
return; return;
} }
$piggyBank = $event->piggyBank()->first(); $piggyBank = $event->piggyBank()->first();
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first(); $repetition = null;
if ($piggyBank) {
/** @var PiggyBankRepetition $repetition */
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
}
if (is_null($repetition)) { if (is_null($repetition)) {
return; return;
} }
$amount = $journal->amount; $amount = $journal->amount;
$diff = $amount - $event->amount;// update current repetition $diff = $amount - $event->amount; // update current repetition
$repetition->currentamount += $diff; $repetition->currentamount += $diff;
$repetition->save(); $repetition->save();

View File

@@ -0,0 +1,90 @@
<?php
namespace FireflyIII\Helpers\Collection;
use Illuminate\Support\Collection;
/**
* @codeCoverageIgnore
* Class Account
*
* @package FireflyIII\Helpers\Collection
*/
class Account
{
/** @var Collection */
protected $accounts;
/** @var float */
protected $difference;
/** @var float */
protected $end;
/** @var float */
protected $start;
/**
* @return \Illuminate\Support\Collection
*/
public function getAccounts()
{
return $this->accounts;
}
/**
* @param \Illuminate\Support\Collection $accounts
*/
public function setAccounts($accounts)
{
$this->accounts = $accounts;
}
/**
* @return float
*/
public function getDifference()
{
return $this->difference;
}
/**
* @param float $difference
*/
public function setDifference($difference)
{
$this->difference = $difference;
}
/**
* @return float
*/
public function getEnd()
{
return $this->end;
}
/**
* @param float $end
*/
public function setEnd($end)
{
$this->end = $end;
}
/**
* @return float
*/
public function getStart()
{
return $this->start;
}
/**
* @param float $start
*/
public function setStart($start)
{
$this->start = $start;
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace FireflyIII\Helpers\Collection;
use Illuminate\Support\Collection;
/**
* @codeCoverageIgnore
*
* Class Balance
*
* @package FireflyIII\Helpers\Collection
*/
class Balance
{
/** @var BalanceHeader */
protected $balanceHeader;
/** @var Collection */
protected $balanceLines;
/**
*
*/
public function __construct()
{
$this->balanceLines = new Collection;
}
/**
* @param BalanceLine $line
*/
public function addBalanceLine(BalanceLine $line)
{
$this->balanceLines->push($line);
}
/**
* @return BalanceHeader
*/
public function getBalanceHeader()
{
return $this->balanceHeader;
}
/**
* @param BalanceHeader $balanceHeader
*/
public function setBalanceHeader($balanceHeader)
{
$this->balanceHeader = $balanceHeader;
}
/**
* @return \Illuminate\Support\Collection
*/
public function getBalanceLines()
{
return $this->balanceLines;
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Account as AccountModel;
/**
* @codeCoverageIgnore
*
* Class BalanceEntry
*
* @package FireflyIII\Helpers\Collection
*/
class BalanceEntry
{
/** @var AccountModel */
protected $account;
/** @var float */
protected $left = 0.0;
/** @var float */
protected $spent = 0.0;
/**
* @return AccountModel
*/
public function getAccount()
{
return $this->account;
}
/**
* @param AccountModel $account
*/
public function setAccount($account)
{
$this->account = $account;
}
/**
* @return float
*/
public function getLeft()
{
return $this->left;
}
/**
* @param float $left
*/
public function setLeft($left)
{
$this->left = $left;
}
/**
* @return float
*/
public function getSpent()
{
return $this->spent;
}
/**
* @param float $spent
*/
public function setSpent($spent)
{
$this->spent = $spent;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Account as AccountModel;
use Illuminate\Support\Collection;
/**
* @codeCoverageIgnore
*
* Class BalanceHeader
*
* @package FireflyIII\Helpers\Collection
*/
class BalanceHeader
{
/** @var Collection */
protected $accounts;
/**
*
*/
public function __construct()
{
$this->accounts = new Collection;
}
/**
* @param AccountModel $account
*/
public function addAccount(AccountModel $account)
{
$this->accounts->push($account);
}
/**
* @return Collection
*/
public function getAccounts()
{
return $this->accounts;
}
}

View File

@@ -0,0 +1,171 @@
<?php
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Budget as BudgetModel;
use FireflyIII\Models\LimitRepetition;
use Illuminate\Support\Collection;
/**
* @codeCoverageIgnore
*
* Class BalanceLine
*
* @package FireflyIII\Helpers\Collection
*/
class BalanceLine
{
const ROLE_DEFAULTROLE = 1;
const ROLE_TAGROLE = 2;
const ROLE_DIFFROLE = 3;
/** @var Collection */
protected $balanceEntries;
/** @var BudgetModel */
protected $budget;
/** @var LimitRepetition */
protected $repetition;
protected $role = self::ROLE_DEFAULTROLE;
/**
*
*/
public function __construct()
{
$this->balanceEntries = new Collection;
}
/**
* @param BalanceEntry $balanceEntry
*/
public function addBalanceEntry(BalanceEntry $balanceEntry)
{
$this->balanceEntries->push($balanceEntry);
}
/**
* @return string
*/
public function getTitle()
{
if ($this->getBudget() instanceof BudgetModel) {
return $this->getBudget()->name;
}
if ($this->getRole() == self::ROLE_DEFAULTROLE) {
return trans('firefly.noBudget');
}
if ($this->getRole() == self::ROLE_TAGROLE) {
return trans('firefly.coveredWithTags');
}
if ($this->getRole() == self::ROLE_DIFFROLE) {
return trans('firefly.leftUnbalanced');
}
return '';
}
/**
* @return BudgetModel
*/
public function getBudget()
{
return $this->budget;
}
/**
* @param BudgetModel $budget
*/
public function setBudget($budget)
{
$this->budget = $budget;
}
/**
* @return int
*/
public function getRole()
{
return $this->role;
}
/**
* @param int $role
*/
public function setRole($role)
{
$this->role = $role;
}
/**
* If a BalanceLine has a budget/repetition, each BalanceEntry in this BalanceLine
* should have a "spent" value, which is the amount of money that has been spent
* on the given budget/repetition. If you subtract all those amounts from the budget/repetition's
* total amount, this is returned:
*
* @return float
*/
public function leftOfRepetition()
{
$start = $this->getRepetition() ? $this->getRepetition()->amount : 0;
/** @var BalanceEntry $balanceEntry */
foreach ($this->getBalanceEntries() as $balanceEntry) {
$start += $balanceEntry->getSpent();
}
return $start;
}
/**
* @return LimitRepetition
*/
public function getRepetition()
{
return $this->repetition;
}
/**
* @param LimitRepetition $repetition
*/
public function setRepetition($repetition)
{
$this->repetition = $repetition;
}
/**
* @return Collection
*/
public function getBalanceEntries()
{
return $this->balanceEntries;
}
/**
* @param Collection $balanceEntries
*/
public function setBalanceEntries($balanceEntries)
{
$this->balanceEntries = $balanceEntries;
}
/**
* If the BalanceEntries for a BalanceLine have a "left" value, the amount
* of money left in the entire BalanceLine is returned here:
*
* @return float
*/
public function sumOfLeft()
{
$sum = 0.0;
/** @var BalanceEntry $balanceEntry */
foreach ($this->getBalanceEntries() as $balanceEntry) {
$sum += $balanceEntry->getLeft();
}
return $sum;
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace FireflyIII\Helpers\Collection;
use Illuminate\Support\Collection;
/**
* @codeCoverageIgnore
* Class Bill
*
* @package FireflyIII\Helpers\Collection
*/
class Bill
{
/**
* @var Collection
*/
protected $bills;
/**
*
*/
public function __construct()
{
$this->bills = new Collection;
}
/**
* @param BillLine $bill
*/
public function addBill(BillLine $bill)
{
$this->bills->push($bill);
}
/**
* @return Collection
*/
public function getBills()
{
$this->bills->sortBy(
function(BillLine $bill) {
$active = intval($bill->getBill()->active) == 0 ? 1 : 0;
$name = $bill->getBill()->name;
return $active . $name;
}
);
return $this->bills;
}
}

View File

@@ -0,0 +1,127 @@
<?php
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Bill as BillModel;
/**
* @codeCoverageIgnore
*
* Class BillLine
*
* @package FireflyIII\Helpers\Collection
*/
class BillLine
{
/** @var bool */
protected $active;
/** @var float */
protected $amount;
/** @var BillModel */
protected $bill;
/** @var bool */
protected $hit;
/** @var float */
protected $max;
/** @var float */
protected $min;
/**
* @return float
*/
public function getAmount()
{
return $this->amount;
}
/**
* @param float $amount
*/
public function setAmount($amount)
{
$this->amount = $amount;
}
/**
* @return BillModel
*/
public function getBill()
{
return $this->bill;
}
/**
* @param BillModel $bill
*/
public function setBill($bill)
{
$this->bill = $bill;
}
/**
* @return float
*/
public function getMax()
{
return $this->max;
}
/**
* @param float $max
*/
public function setMax($max)
{
$this->max = $max;
}
/**
* @return float
*/
public function getMin()
{
return $this->min;
}
/**
* @param float $min
*/
public function setMin($min)
{
$this->min = $min;
}
/**
* @return boolean
*/
public function isActive()
{
return $this->active;
}
/**
* @param boolean $active
*/
public function setActive($active)
{
$this->active = $active;
}
/**
* @return boolean
*/
public function isHit()
{
return $this->hit;
}
/**
* @param boolean $hit
*/
public function setHit($hit)
{
$this->hit = $hit;
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace FireflyIII\Helpers\Collection;
use Illuminate\Support\Collection;
/**
* @codeCoverageIgnore
*
* Class Budget
*
* @package FireflyIII\Helpers\Collection
*/
class Budget
{
/** @var Collection */
protected $budgetLines;
/** @var string */
protected $budgeted = '0';
/** @var string */
protected $left = '0';
/** @var string */
protected $overspent = '0';
/** @var string */
protected $spent = '0';
/**
*
*/
public function __construct()
{
$this->budgetLines = new Collection;
}
/**
* @param BudgetLine $budgetLine
*/
public function addBudgetLine(BudgetLine $budgetLine)
{
$this->budgetLines->push($budgetLine);
}
/**
* @param float $add
*/
public function addBudgeted($add)
{
$add = strval(round($add, 2));
bcscale(2);
$this->budgeted = bcadd($this->budgeted, $add);
}
/**
* @param float $add
*/
public function addLeft($add)
{
$add = strval(round($add, 2));
bcscale(2);
$this->left = bcadd($this->left, $add);
}
/**
* @param float $add
*/
public function addOverspent($add)
{
$add = strval(round($add, 2));
bcscale(2);
$this->overspent = bcadd($this->overspent, $add);
}
/**
* @param float $add
*/
public function addSpent($add)
{
$add = strval(round($add, 2));
bcscale(2);
$this->spent = bcadd($this->spent, $add);
}
/**
* @return \Illuminate\Support\Collection
*/
public function getBudgetLines()
{
return $this->budgetLines;
}
/**
* @return string
*/
public function getBudgeted()
{
return $this->budgeted;
}
/**
* @param string $budgeted
*/
public function setBudgeted($budgeted)
{
$this->budgeted = $budgeted;
}
/**
* @return string
*/
public function getLeft()
{
return $this->left;
}
/**
* @param string $left
*/
public function setLeft($left)
{
$this->left = $left;
}
/**
* @return string
*/
public function getOverspent()
{
return $this->overspent;
}
/**
* @param string $overspent
*/
public function setOverspent($overspent)
{
$this->overspent = strval(round($overspent, 2));
}
/**
* @return string
*/
public function getSpent()
{
return $this->spent;
}
/**
* @param string $spent
*/
public function setSpent($spent)
{
$this->spent = strval(round($spent, 2));
}
}

View File

@@ -0,0 +1,128 @@
<?php
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Budget as BudgetModel;
use FireflyIII\Models\LimitRepetition;
/**
* @codeCoverageIgnore
*
* Class BudgetLine
*
* @package FireflyIII\Helpers\Collection
*/
class BudgetLine
{
/** @var BudgetModel */
protected $budget;
/** @var float */
protected $budgeted = 0;
/** @var float */
protected $left = 0;
/** @var float */
protected $overspent = 0;
/** @var LimitRepetition */
protected $repetition;
/** @var float */
protected $spent = 0;
/**
* @return BudgetModel
*/
public function getBudget()
{
return $this->budget;
}
/**
* @param BudgetModel $budget
*/
public function setBudget($budget)
{
$this->budget = $budget;
}
/**
* @return float
*/
public function getBudgeted()
{
return $this->budgeted;
}
/**
* @param float $budgeted
*/
public function setBudgeted($budgeted)
{
$this->budgeted = $budgeted;
}
/**
* @return float
*/
public function getLeft()
{
return $this->left;
}
/**
* @param float $left
*/
public function setLeft($left)
{
$this->left = $left;
}
/**
* @return float
*/
public function getOverspent()
{
return $this->overspent;
}
/**
* @param float $overspent
*/
public function setOverspent($overspent)
{
$this->overspent = $overspent;
}
/**
* @return LimitRepetition
*/
public function getRepetition()
{
return $this->repetition;
}
/**
* @param LimitRepetition $repetition
*/
public function setRepetition($repetition)
{
$this->repetition = $repetition;
}
/**
* @return float
*/
public function getSpent()
{
return $this->spent;
}
/**
* @param float $spent
*/
public function setSpent($spent)
{
$this->spent = $spent;
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Category as CategoryModel;
use Illuminate\Support\Collection;
/**
* @codeCoverageIgnore
*
* Class Category
*
* @package FireflyIII\Helpers\Collection
*/
class Category
{
/** @var Collection */
protected $categories;
/** @var string */
protected $total = '0';
/**
*
*/
public function __construct()
{
$this->categories = new Collection;
}
/**
* @param CategoryModel $category
*/
public function addCategory(CategoryModel $category)
{
if ($category->spent > 0) {
$this->categories->push($category);
}
}
/**
* @param float $add
*/
public function addTotal($add)
{
$add = strval(round($add, 2));
bcscale(2);
$this->total = bcadd($this->total, $add);
}
/**
* @return Collection
*/
public function getCategories()
{
$this->categories->sortByDesc(
function(CategoryModel $category) {
return $category->spent;
}
);
return $this->categories;
}
/**
* @return string
*/
public function getTotal()
{
return strval(round($this->total, 2));
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Support\Collection;
use stdClass;
/**
* @codeCoverageIgnore
*
* Class Expense
*
* @package FireflyIII\Helpers\Collection
*/
class Expense
{
/** @var Collection */
protected $expenses;
/** @var string */
protected $total = '0';
/**
*
*/
public function __construct()
{
$this->expenses = new Collection;
}
/**
* @param TransactionJournal $entry
*/
public function addOrCreateExpense(TransactionJournal $entry)
{
$accountId = $entry->account_id;
if (!$this->expenses->has($accountId)) {
$newObject = new stdClass;
$newObject->amount = strval(round($entry->amount, 2));
$newObject->name = $entry->name;
$newObject->count = 1;
$newObject->id = $accountId;
$this->expenses->put($accountId, $newObject);
} else {
bcscale(2);
$existing = $this->expenses->get($accountId);
$existing->amount = bcadd($existing->amount, $entry->amount);
$existing->count++;
$this->expenses->put($accountId, $existing);
}
}
/**
* @param $add
*/
public function addToTotal($add)
{
$add = strval(round($add, 2));
bcscale(2);
$this->total = bcadd($this->total, $add);
}
/**
* @return Collection
*/
public function getExpenses()
{
$this->expenses->sortByDesc(
function(stdClass $object) {
return $object->amount;
}
);
return $this->expenses;
}
/**
* @return string
*/
public function getTotal()
{
return strval(round($this->total, 2));
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Support\Collection;
use stdClass;
/**
* @codeCoverageIgnore
*
* Class Income
*
* @package FireflyIII\Helpers\Collection
*/
class Income
{
/** @var Collection */
protected $incomes;
/** @var string */
protected $total;
/**
*
*/
public function __construct()
{
$this->incomes = new Collection;
}
/**
* @param TransactionJournal $entry
*/
public function addOrCreateIncome(TransactionJournal $entry)
{
$accountId = $entry->account_id;
if (!$this->incomes->has($accountId)) {
$newObject = new stdClass;
$newObject->amount = strval(round($entry->amount, 2));
$newObject->name = $entry->name;
$newObject->count = 1;
$newObject->id = $accountId;
$this->incomes->put($accountId, $newObject);
} else {
bcscale(2);
$existing = $this->incomes->get($accountId);
$existing->amount = bcadd($existing->amount, $entry->amount);
$existing->count++;
$this->incomes->put($accountId, $existing);
}
}
/**
* @param $add
*/
public function addToTotal($add)
{
$add = strval(round($add, 2));
bcscale(2);
$this->total = bcadd($this->total, $add);
}
/**
* @return Collection
*/
public function getIncomes()
{
$this->incomes->sortByDesc(
function(stdClass $object) {
return $object->amount;
}
);
return $this->incomes;
}
/**
* @return string
*/
public function getTotal()
{
return strval(round($this->total, 2));
}
}

View File

@@ -18,6 +18,7 @@ class Help implements HelpInterface
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $key * @param $key
* *
* @return string * @return string
@@ -29,13 +30,14 @@ class Help implements HelpInterface
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $route * @param $route
* *
* @return array * @return array
*/ */
public function getFromGithub($route) public function getFromGithub($route)
{ {
$uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md'; $uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/en/' . e($route) . '.md';
$content = [ $content = [
'text' => '<p>There is no help for this route!</p>', 'text' => '<p>There is no help for this route!</p>',
'title' => $route, 'title' => $route,
@@ -57,6 +59,7 @@ class Help implements HelpInterface
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $route * @param $route
* *
* @return bool * @return bool
@@ -68,6 +71,7 @@ class Help implements HelpInterface
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $route * @param $route
* @param array $content * @param array $content
* *
@@ -81,6 +85,7 @@ class Help implements HelpInterface
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $route * @param $route
* *
* @return bool * @return bool

View File

@@ -5,9 +5,11 @@ namespace FireflyIII\Helpers\Reminders;
use Amount; use Amount;
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Config;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Reminder; use FireflyIII\Models\Reminder;
use Navigation; use Navigation;
use Preferences;
/** /**
* Class ReminderHelper * Class ReminderHelper
@@ -63,6 +65,30 @@ class ReminderHelper implements ReminderHelperInterface
} }
} }
/**
* Create all reminders for a piggy bank for a given date.
*
* @param PiggyBank $piggyBank
*
* @param Carbon $date
*
* @return mixed
*/
public function createReminders(PiggyBank $piggyBank, Carbon $date)
{
$ranges = $this->getReminderRanges($piggyBank);
foreach ($ranges as $range) {
if ($date < $range['end'] && $date > $range['start']) {
// create a reminder here!
$this->createReminder($piggyBank, $range['start'], $range['end']);
// stop looping, we're done.
break;
}
}
}
/** /**
* This routine will return an array consisting of two dates which indicate the start * This routine will return an array consisting of two dates which indicate the start
* and end date for each reminder that this piggy bank will have, if the piggy bank has * and end date for each reminder that this piggy bank will have, if the piggy bank has
@@ -130,14 +156,21 @@ class ReminderHelper implements ReminderHelperInterface
$piggyBank = $reminder->remindersable; $piggyBank = $reminder->remindersable;
if (is_null($piggyBank)) { if (is_null($piggyBank)) {
return 'Piggy bank no longer exists.'; return trans('firefly.piggy_bank_not_exists');
} }
if (is_null($piggyBank->targetdate)) { if (is_null($piggyBank->targetdate)) {
return 'Add money to this piggy bank to reach your target of ' . Amount::format($piggyBank->targetamount); return trans('firefly.add_any_amount_to_piggy', ['amount' => Amount::format($piggyBank->targetamount)]);
} }
return 'Add ' . Amount::format($reminder->metadata->perReminder) . ' to fill this piggy bank on ' . $piggyBank->targetdate->format('jS F Y'); $lang = Preferences::get('language', 'en')->data;
return trans(
'firefly.add_set_amount_to_piggy',
[
'amount' => Amount::format($reminder->metadata->perReminder),
'date' => $piggyBank->targetdate->formatLocalized(Config::get('firefly.monthAndDay.' . $lang))
]
);
} }
} }

View File

@@ -49,4 +49,15 @@ interface ReminderHelperInterface
* @return Reminder * @return Reminder
*/ */
public function createReminder(PiggyBank $piggyBank, Carbon $start, Carbon $end); public function createReminder(PiggyBank $piggyBank, Carbon $start, Carbon $end);
/**
* Create all reminders for a piggy bank for a given date.
*
* @param PiggyBank $piggyBank
*
* @param Carbon $date
*
* @return mixed
*/
public function createReminders(PiggyBank $piggyBank, Carbon $date);
} }

View File

@@ -3,12 +3,23 @@
namespace FireflyIII\Helpers\Report; namespace FireflyIII\Helpers\Report;
use App; use App;
use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Helpers\Collection\Account as AccountCollection;
use FireflyIII\Helpers\Collection\Balance;
use FireflyIII\Helpers\Collection\BalanceEntry;
use FireflyIII\Helpers\Collection\BalanceHeader;
use FireflyIII\Helpers\Collection\BalanceLine;
use FireflyIII\Helpers\Collection\Bill as BillCollection;
use FireflyIII\Helpers\Collection\BillLine;
use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
use FireflyIII\Helpers\Collection\BudgetLine;
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
use FireflyIII\Helpers\Collection\Expense;
use FireflyIII\Helpers\Collection\Income;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use Illuminate\Database\Query\JoinClause; use FireflyIII\Models\Bill;
use Illuminate\Support\Collection; use FireflyIII\Models\Budget as BudgetModel;
use Steam; use FireflyIII\Models\LimitRepetition;
/** /**
* Class ReportHelper * Class ReportHelper
@@ -18,47 +29,349 @@ use Steam;
class ReportHelper implements ReportHelperInterface class ReportHelper implements ReportHelperInterface
{ {
/** @var ReportQueryInterface */
protected $query;
/** /**
* This method gets some kind of list for a monthly overview. * @codeCoverageIgnore
*
* @param ReportQueryInterface $query
*
*/
public function __construct(ReportQueryInterface $query)
{
$this->query = $query;
}
/**
* This method generates a full report for the given period on all
* the users asset and cash accounts.
* *
* @param Carbon $date * @param Carbon $date
* @param bool $showSharedReports * @param Carbon $end
* @param $shared
* *
* @return Collection * @return AccountCollection
*/ */
public function getBudgetsForMonth(Carbon $date, $showSharedReports = false) public function getAccountReport(Carbon $date, Carbon $end, $shared)
{ {
/** @var \FireflyIII\Helpers\Report\ReportQueryInterface $query */
$query = App::make('FireflyIII\Helpers\Report\ReportQueryInterface');
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
$set = Auth::user()->budgets()->orderBy('budgets.name', 'ASC')
->leftJoin(
'budget_limits', function (JoinClause $join) use ($date) {
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
}
)
->get(['budgets.*', 'budget_limits.amount as queryAmount']);
$budgets = Steam::makeArray($set); $accounts = $this->query->getAllAccounts($date, $end, $shared);
$amountSet = $query->journalsByBudget($start, $end, $showSharedReports); $start = 0;
$amounts = Steam::makeArray($amountSet); $end = 0;
$budgets = Steam::mergeArrays($budgets, $amounts); $diff = 0;
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
$budgets[0]['queryAmount'] = isset($budgets[0]['queryAmount']) ? $budgets[0]['queryAmount'] : 0.0;
$budgets[0]['name'] = 'No budget';
// find transactions to shared asset accounts, which are without a budget by default: // remove cash account, if any:
// which is only relevant when shared asset accounts are hidden. $accounts = $accounts->filter(
if ($showSharedReports === false) { function(Account $account) {
$transfers = $query->sharedExpenses($start, $end)->sum('queryAmount'); if ($account->accountType->type != 'Cash account') {
$budgets[0]['spent'] += floatval($transfers) * -1; return $account;
}
return null;
}
);
// summarize:
foreach ($accounts as $account) {
$start += $account->startBalance;
$end += $account->endBalance;
$diff += ($account->endBalance - $account->startBalance);
} }
return $budgets; $object = new AccountCollection;
$object->setStart($start);
$object->setEnd($end);
$object->setDifference($diff);
$object->setAccounts($accounts);
return $object;
}
/**
*
* The balance report contains a Balance object which in turn contains:
*
* A BalanceHeader object which contains all relevant user asset accounts for the report.
*
* A number of BalanceLine objects, which hold:
* - A budget
* - A number of BalanceEntry objects.
*
* The BalanceEntry object holds:
* - The same budget (again)
* - A user asset account as mentioned in the BalanceHeader
* - The amount of money spent on the budget by the user asset account
*
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return Balance
*/
public function getBalanceReport(Carbon $start, Carbon $end, $shared)
{
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$tagRepository = App::make('FireflyIII\Repositories\Tag\TagRepositoryInterface');
$balance = new Balance;
// build a balance header:
$header = new BalanceHeader;
$accounts = $this->query->getAllAccounts($start, $end, $shared);
$budgets = $repository->getBudgets();
foreach ($accounts as $account) {
$header->addAccount($account);
}
/** @var BudgetModel $budget */
foreach ($budgets as $budget) {
$line = new BalanceLine;
$line->setBudget($budget);
// get budget amount for current period:
$rep = $repository->getCurrentRepetition($budget, $start);
$line->setRepetition($rep);
// loop accounts:
foreach ($accounts as $account) {
$balanceEntry = new BalanceEntry;
$balanceEntry->setAccount($account);
// get spent:
$spent = $this->query->spentInBudgetCorrected($account, $budget, $start, $end); // I think shared is irrelevant.
$balanceEntry->setSpent($spent);
$line->addBalanceEntry($balanceEntry);
}
// add line to balance:
$balance->addBalanceLine($line);
}
// then a new line for without budget.
// and one for the tags:
$empty = new BalanceLine;
$tags = new BalanceLine;
$diffLine = new BalanceLine;
$tags->setRole(BalanceLine::ROLE_TAGROLE);
$diffLine->setRole(BalanceLine::ROLE_DIFFROLE);
foreach ($accounts as $account) {
$spent = $this->query->spentNoBudget($account, $start, $end);
$left = $tagRepository->coveredByBalancingActs($account, $start, $end);
$diff = $spent + $left;
// budget
$budgetEntry = new BalanceEntry;
$budgetEntry->setAccount($account);
$budgetEntry->setSpent($spent);
$empty->addBalanceEntry($budgetEntry);
// balanced by tags
$tagEntry = new BalanceEntry;
$tagEntry->setAccount($account);
$tagEntry->setLeft($left);
$tags->addBalanceEntry($tagEntry);
// difference:
$diffEntry = new BalanceEntry;
$diffEntry->setAccount($account);
$diffEntry->setSpent($diff);
$diffLine->addBalanceEntry($diffEntry);
}
$balance->addBalanceLine($empty);
$balance->addBalanceLine($tags);
$balance->addBalanceLine($diffLine);
$balance->setBalanceHeader($header);
return $balance;
}
/**
* This method generates a full report for the given period on all
* the users bills and their payments.
*
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return BillCollection
*/
public function getBillReport(Carbon $start, Carbon $end, $shared)
{
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Bill\BillRepositoryInterface');
$bills = $repository->getBills();
$collection = new BillCollection;
/** @var Bill $bill */
foreach ($bills as $bill) {
$billLine = new BillLine;
$billLine->setBill($bill);
$billLine->setActive(intval($bill->active) == 1);
$billLine->setMin(floatval($bill->amount_min));
$billLine->setMax(floatval($bill->amount_max));
// is hit in period?
$set = $repository->getJournalsInRange($bill, $start, $end);
if ($set->count() == 0) {
$billLine->setHit(false);
} else {
$billLine->setHit(true);
$amount = 0;
foreach ($set as $entry) {
$amount += $entry->amount;
}
$billLine->setAmount($amount);
}
$collection->addBill($billLine);
}
return $collection;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return BudgetCollection
*/
public function getBudgetReport(Carbon $start, Carbon $end, $shared)
{
$object = new BudgetCollection;
/** @var \FireflyIII\Repositories\Budget\BudgetRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$set = $repository->getBudgets();
foreach ($set as $budget) {
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
// no repetition(s) for this budget:
if ($repetitions->count() == 0) {
$spent = $repository->spentInPeriodCorrected($budget, $start, $end, $shared);
$budgetLine = new BudgetLine;
$budgetLine->setBudget($budget);
$budgetLine->setOverspent($spent);
$object->addOverspent($spent);
$object->addBudgetLine($budgetLine);
continue;
}
// one or more repetitions for budget:
/** @var LimitRepetition $repetition */
foreach ($repetitions as $repetition) {
$budgetLine = new BudgetLine;
$budgetLine->setBudget($budget);
$budgetLine->setRepetition($repetition);
$expenses = $repository->spentInPeriodCorrected($budget, $repetition->startdate, $repetition->enddate, $shared);
$left = $expenses < floatval($repetition->amount) ? floatval($repetition->amount) - $expenses : 0;
$spent = $expenses > floatval($repetition->amount) ? 0 : $expenses;
$overspent = $expenses > floatval($repetition->amount) ? $expenses - floatval($repetition->amount) : 0;
$budgetLine->setLeft($left);
$budgetLine->setSpent($spent);
$budgetLine->setOverspent($overspent);
$budgetLine->setBudgeted($repetition->amount);
$object->addBudgeted($repetition->amount);
$object->addSpent($spent);
$object->addLeft($left);
$object->addOverspent($overspent);
$object->addBudgetLine($budgetLine);
}
}
// stuff outside of budgets:
$noBudget = $repository->getWithoutBudgetSum($start, $end);
$budgetLine = new BudgetLine;
$budgetLine->setOverspent($noBudget);
$object->addOverspent($noBudget);
$object->addBudgetLine($budgetLine);
return $object;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return CategoryCollection
*/
public function getCategoryReport(Carbon $start, Carbon $end, $shared)
{
$object = new CategoryCollection;
/**
* GET CATEGORIES:
*/
/** @var \FireflyIII\Repositories\Category\CategoryRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
$set = $repository->getCategories();
foreach ($set as $category) {
$spent = $repository->spentInPeriodCorrected($category, $start, $end, $shared);
$category->spent = $spent;
$object->addCategory($category);
$object->addTotal($spent);
}
return $object;
}
/**
* Get a full report on the users expenses during the period.
*
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return Expense
*/
public function getExpenseReport($start, $end, $shared)
{
$object = new Expense;
$set = $this->query->expenseInPeriodCorrected($start, $end, $shared);
foreach ($set as $entry) {
$object->addToTotal($entry->amount);
$object->addOrCreateExpense($entry);
}
return $object;
}
/**
* Get a full report on the users incomes during the period.
*
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return Income
*/
public function getIncomeReport($start, $end, $shared)
{
$object = new Income;
$set = $this->query->incomeInPeriodCorrected($start, $end, $shared);
foreach ($set as $entry) {
$object->addToTotal($entry->amount);
$object->addOrCreateIncome($entry);
}
return $object;
} }
/** /**
@@ -68,13 +381,14 @@ class ReportHelper implements ReportHelperInterface
*/ */
public function listOfMonths(Carbon $date) public function listOfMonths(Carbon $date)
{ {
$start = clone $date; $start = clone $date;
$end = Carbon::now(); $end = Carbon::now();
$months = []; $months = [];
while ($start <= $end) { while ($start <= $end) {
$year = $start->year; $year = $start->year;
$months[$year][] = [ $months[$year][] = [
'formatted' => $start->format('F Y'), 'formatted' => $start->formatLocalized('%B %Y'),
'month' => $start->month, 'month' => $start->month,
'year' => $year, 'year' => $year,
]; ];
@@ -83,77 +397,4 @@ class ReportHelper implements ReportHelperInterface
return $months; return $months;
} }
/**
* @param Carbon $date
*
* @return array
*/
public function listOfYears(Carbon $date)
{
$start = clone $date;
$end = Carbon::now();
$years = [];
while ($start <= $end) {
$years[] = $start->year;
$start->addYear();
}
$years[] = Carbon::now()->year;
// force the current year.
$years = array_unique($years);
return $years;
}
/**
* @param Carbon $date
* @param bool $showSharedReports
*
* @return array
*/
public function yearBalanceReport(Carbon $date, $showSharedReports = false)
{
$start = clone $date;
$end = clone $date;
$sharedAccounts = [];
if ($showSharedReports === false) {
$sharedCollection = Auth::user()->accounts()
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
->where('account_meta.name', '=', 'accountRole')
->where('account_meta.data', '=', json_encode('sharedAsset'))
->get(['accounts.id']);
foreach ($sharedCollection as $account) {
$sharedAccounts[] = $account->id;
}
}
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*'])
->filter(
function (Account $account) use ($sharedAccounts) {
if (!in_array($account->id, $sharedAccounts)) {
return $account;
}
return null;
}
);
$report = [];
$start->startOfYear()->subDay();
$end->endOfYear();
foreach ($accounts as $account) {
$startBalance = Steam::balance($account, $start);
$endBalance = Steam::balance($account, $end);
$report[] = [
'start' => $startBalance,
'end' => $endBalance,
'hide' => ($startBalance == 0 && $endBalance == 0),
'account' => $account,
'shared' => $account->accountRole == 'sharedAsset'
];
}
return $report;
}
} }

View File

@@ -3,7 +3,13 @@
namespace FireflyIII\Helpers\Report; namespace FireflyIII\Helpers\Report;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Collection; use FireflyIII\Helpers\Collection\Account as AccountCollection;
use FireflyIII\Helpers\Collection\Balance;
use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
use FireflyIII\Helpers\Collection\Bill as BillCollection;
use FireflyIII\Helpers\Collection\Expense;
use FireflyIII\Helpers\Collection\Income;
/** /**
* Interface ReportHelperInterface * Interface ReportHelperInterface
@@ -14,13 +20,77 @@ interface ReportHelperInterface
{ {
/** /**
* This method gets some kind of list for a monthly overview. * This method generates a full report for the given period on all
* the users asset and cash accounts.
* *
* @param Carbon $date * @param Carbon $date
* @param Carbon $end
* @param boolean $shared
* *
* @return Collection * @return AccountCollection
*/ */
public function getBudgetsForMonth(Carbon $date); public function getAccountReport(Carbon $date, Carbon $end, $shared);
/**
* This method generates a full report for the given period on all
* the users bills and their payments.
*
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return BillCollection
*/
public function getBillReport(Carbon $start, Carbon $end, $shared);
/**
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return Balance
*/
public function getBalanceReport(Carbon $start, Carbon $end, $shared);
/**
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return BudgetCollection
*/
public function getBudgetReport(Carbon $start, Carbon $end, $shared);
/**
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return CategoryCollection
*/
public function getCategoryReport(Carbon $start, Carbon $end, $shared);
/**
* Get a full report on the users expenses during the period.
*
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return Expense
*/
public function getExpenseReport($start, $end, $shared);
/**
* Get a full report on the users incomes during the period.
*
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
*
* @return Income
*/
public function getIncomeReport($start, $end, $shared);
/** /**
* @param Carbon $date * @param Carbon $date
@@ -29,18 +99,4 @@ interface ReportHelperInterface
*/ */
public function listOfMonths(Carbon $date); public function listOfMonths(Carbon $date);
/**
* @param Carbon $date
*
* @return array
*/
public function listOfYears(Carbon $date);
/**
* @param Carbon $date
* @param bool $showSharedReports
*
* @return array
*/
public function yearBalanceReport(Carbon $date, $showSharedReports = false);
} }

View File

@@ -5,11 +5,10 @@ namespace FireflyIII\Helpers\Report;
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Crypt; use Crypt;
use DB;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Steam; use Steam;
@@ -21,101 +20,63 @@ use Steam;
*/ */
class ReportQuery implements ReportQueryInterface class ReportQuery implements ReportQueryInterface
{ {
/** /**
* This query retrieves a list of accounts that are active and not shared. * See ReportQueryInterface::incomeInPeriodCorrected
* *
* @param bool $showSharedReports * @param Carbon $start
* @param Carbon $end
* @param bool $includeShared
* *
* @return Collection * @return Collection
*
*/ */
public function accountList($showSharedReports = false) public function expenseInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false)
{ {
$query = Auth::user()->accounts(); $query = $this->queryJournalsWithTransactions($start, $end);
if ($showSharedReports === false) { if ($includeShared === false) {
$query->where(
$query->leftJoin( function(Builder $query) {
'account_meta', function (JoinClause $join) { $query->where(
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', "accountRole"); function(Builder $q) { // only get withdrawals not from a shared account
} $q->where('transaction_types.type', 'Withdrawal');
)->where( $q->where('acm_from.data', '!=', '"sharedAsset"');
function (Builder $query) { }
$query->where('account_meta.data', '!=', '"sharedAsset"'); );
$query->orWhereNull('account_meta.data'); $query->orWhere(
function(Builder $q) { // and transfers from a shared account.
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_to.data', '=', '"sharedAsset"');
}
);
} }
); );
} else {
$query->where('transaction_types.type', 'Withdrawal'); // any withdrawal is fine.
} }
$query->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') $query->orderBy('transaction_journals.date');
->whereIn('account_types.type', ['Default account', 'Cash account', 'Asset account'])
->where('active', 1)
->orderBy('accounts.name', 'ASC');
return $query->get(['accounts.*']); // get everything
} $data = $query->get(
['transaction_journals.*', 'transaction_types.type', 'ac_to.name as name', 'ac_to.id as account_id', 'ac_to.encrypted as account_encrypted']
);
/** $data->each(
* This method will get a list of all expenses in a certain time period that have no budget function(TransactionJournal $journal) {
* and are balanced by a transfer to make up for it. if (intval($journal->account_encrypted) == 1) {
* $journal->name = Crypt::decrypt($journal->name);
* @param Account $account }
* @param Carbon $start }
* @param Carbon $end );
* $data = $data->filter(
* @return Collection function(TransactionJournal $journal) {
*/ if ($journal->amount != 0) {
public function balancedTransactionsList(Account $account, Carbon $start, Carbon $end) return $journal;
{ }
return null;
}
);
$set = TransactionJournal:: return $data;
leftJoin('transaction_group_transaction_journal', 'transaction_group_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin(
'transaction_group_transaction_journal as otherFromGroup', function (JoinClause $join) {
$join->on('otherFromGroup.transaction_group_id', '=', 'transaction_group_transaction_journal.transaction_group_id')
->on('otherFromGroup.transaction_journal_id', '!=', 'transaction_journals.id');
}
)
->leftJoin('transaction_journals as otherJournals', 'otherJournals.id', '=', 'otherFromGroup.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'otherJournals.transaction_type_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0);
}
)
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'otherJournals.id')
->before($end)->after($start)
->where('transaction_types.type', 'Withdrawal')
->where('transaction_journals.user_id', Auth::user()->id)
->whereNull('budget_transaction_journal.budget_id')->whereNull('transaction_journals.deleted_at')
->whereNull('otherJournals.deleted_at')
->where('transactions.account_id', $account->id)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->whereNotNull('transaction_group_transaction_journal.transaction_group_id')
->get(
[
'transaction_journals.*',
'transactions.amount as queryAmount'
]
);
return $set;
}
/**
* This method will get the sum of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return float
*/
public function balancedTransactionsSum(Account $account, Carbon $start, Carbon $end)
{
return floatval($this->balancedTransactionsList($account, $start, $end)->sum('queryAmount'));
} }
/** /**
@@ -123,33 +84,33 @@ class ReportQuery implements ReportQueryInterface
* *
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports * @param bool $includeShared
* *
* @return Collection * @return Collection
*/ */
public function getAllAccounts(Carbon $start, Carbon $end, $showSharedReports = false) public function getAllAccounts(Carbon $start, Carbon $end, $includeShared = false)
{ {
$query = Auth::user()->accounts()->orderBy('accounts.name', 'ASC') $query = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')
->accountTypeIn(['Default account', 'Asset account', 'Cash account']); ->accountTypeIn(['Default account', 'Asset account', 'Cash account']);
if ($showSharedReports === false) { if ($includeShared === false) {
$query->leftJoin( $query->leftJoin(
'account_meta', function (JoinClause $join) { 'account_meta', function(JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); $join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
} }
) )
->orderBy('accounts.name', 'ASC') ->orderBy('accounts.name', 'ASC')
->where( ->where(
function (Builder $query) { function(Builder $query) {
$query->where('account_meta.data', '!=', '"sharedAsset"'); $query->where('account_meta.data', '!=', '"sharedAsset"');
$query->orWhereNull('account_meta.data'); $query->orWhereNull('account_meta.data');
} }
); );
} }
$set = $query->get(['accounts.*']); $set = $query->get(['accounts.*']);
$set->each( $set->each(
function (Account $account) use ($start, $end) { function(Account $account) use ($start, $end) {
/** /**
* The balance for today always incorporates transactions * The balance for today always incorporates transactions
* made on today. So to get todays "start" balance, we sub one * made on today. So to get todays "start" balance, we sub one
@@ -167,67 +128,38 @@ class ReportQuery implements ReportQueryInterface
return $set; return $set;
} }
/**
* Grabs a summary of all expenses grouped by budget, related to the account.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getBudgetSummary(Account $account, Carbon $start, Carbon $end)
{
$query = $this->queryJournalsNoBudget($account, $start, $end);
return $query->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) as `queryAmount`')]);
}
/** /**
* Get a list of transaction journals that have no budget, filtered for the specified account * This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results
* and the specified date range. * will simply list the transaction journals only. This should allow any follow up counting to be accurate with
* regards to tags.
* *
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getTransactionsWithoutBudget(Account $account, Carbon $start, Carbon $end)
{
$query = $this->queryJournalsNoBudget($account, $start, $end);
return $query->get(['budgets.name', 'transactions.amount as queryAmount', 'transaction_journals.*']);
}
/**
* This method returns all "income" journals in a certain period, which are both transfers from a shared account * This method returns all "income" journals in a certain period, which are both transfers from a shared account
* and "ordinary" deposits. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does * and "ordinary" deposits. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
* not group and returns different fields. * not group and returns different fields.
* *
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports * @param bool $includeShared
* *
* @return Collection * @return Collection
*/ */
public function incomeByPeriod(Carbon $start, Carbon $end, $showSharedReports = false) public function incomeInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false)
{ {
$query = $this->queryJournalsWithTransactions($start, $end); $query = $this->queryJournalsWithTransactions($start, $end);
if ($showSharedReports === false) { if ($includeShared === false) {
// only get deposits not to a shared account // only get deposits not to a shared account
// and transfers to a shared account. // and transfers to a shared account.
$query->where( $query->where(
function (Builder $query) { function(Builder $query) {
$query->where( $query->where(
function (Builder $q) { function(Builder $q) {
$q->where('transaction_types.type', 'Deposit'); $q->where('transaction_types.type', 'Deposit');
$q->where('acm_to.data', '!=', '"sharedAsset"'); $q->where('acm_to.data', '!=', '"sharedAsset"');
} }
); );
$query->orWhere( $query->orWhere(
function (Builder $q) { function(Builder $q) {
$q->where('transaction_types.type', 'Transfer'); $q->where('transaction_types.type', 'Transfer');
$q->where('acm_from.data', '=', '"sharedAsset"'); $q->where('acm_from.data', '=', '"sharedAsset"');
} }
@@ -238,219 +170,26 @@ class ReportQuery implements ReportQueryInterface
// any deposit is fine. // any deposit is fine.
$query->where('transaction_types.type', 'Deposit'); $query->where('transaction_types.type', 'Deposit');
} }
$query->groupBy('transaction_journals.id')->orderBy('transaction_journals.date'); $query->orderBy('transaction_journals.date');
// get everything, decrypt and return // get everything
$data = $query->get( $data = $query->get(
['transaction_journals.id', ['transaction_journals.*', 'transaction_types.type', 'ac_from.name as name', 'ac_from.id as account_id', 'ac_from.encrypted as account_encrypted']
'transaction_journals.description',
'transaction_journals.encrypted',
'transaction_types.type',
DB::Raw('SUM(`t_to`.`amount`) as `queryAmount`'),
'transaction_journals.date',
't_from.account_id as account_id',
'ac_from.name as name',
'ac_from.encrypted as account_encrypted'
]
); );
$data->each( $data->each(
function (Model $object) { function(TransactionJournal $journal) {
$object->name = intval($object->account_encrypted) == 1 ? Crypt::decrypt($object->name) : $object->name; if (intval($journal->account_encrypted) == 1) {
} $journal->name = Crypt::decrypt($journal->name);
);
return $data;
}
/**
* Gets a list of expenses grouped by the budget they were filed under.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByBudget(Carbon $start, Carbon $end, $showSharedReports = false)
{
$query = Auth::user()->transactionjournals()
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id');
if ($showSharedReports === false) {
$query->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)->where('account_meta.data', '!=', '"sharedAsset"');
}
$query->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_types.type', 'Withdrawal')
->groupBy('budgets.id')
->orderBy('budgets.name', 'ASC');
return $query->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) AS `spent`')]);
}
/**
* Gets a list of categories and the expenses therein, grouped by the relevant category.
* This result excludes transfers to shared accounts which are expenses, technically.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByCategory(Carbon $start, Carbon $end, $showSharedReports = false)
{
$query = Auth::user()->transactionjournals()
->leftJoin(
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
)
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id');
if ($showSharedReports === false) {
$query->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)->where('account_meta.data', '!=', '"sharedAsset"');
}
$query->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_types.type', 'Withdrawal')
->groupBy('categories.id')
->orderBy('queryAmount');
$data = $query->get(['categories.id', 'categories.encrypted', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `queryAmount`')]);
// decrypt data:
$data->each(
function (Model $object) {
$object->name = intval($object->encrypted) == 1 ? Crypt::decrypt($object->name) : $object->name;
}
);
return $data;
}
/**
* Gets a list of expense accounts and the expenses therein, grouped by that expense account.
* This result excludes transfers to shared accounts which are expenses, technically.
*
* So now it will include them!
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByExpenseAccount(Carbon $start, Carbon $end, $showSharedReports = false)
{
$query = $this->queryJournalsWithTransactions($start, $end);
if ($showSharedReports === false) {
// get all withdrawals not from a shared accounts
// and all transfers to a shared account
$query->where(
function (Builder $query) {
$query->where(
function (Builder $q) {
$q->where('transaction_types.type', 'Withdrawal');
$q->where('acm_from.data', '!=', '"sharedAsset"');
}
);
$query->orWhere(
function (Builder $q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_to.data', '=', '"sharedAsset"');
}
);
} }
);
} else {
// any withdrawal goes:
$query->where('transaction_types.type', 'Withdrawal');
}
$query->before($end)->after($start)
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('t_to.account_id')
->orderBy('queryAmount', 'DESC');
$data = $query->get(['t_to.account_id as id', 'ac_to.name as name', 'ac_to.encrypted', DB::Raw('SUM(t_to.amount) as `queryAmount`')]);
// decrypt
$data->each(
function (Model $object) {
$object->name = intval($object->encrypted) == 1 ? Crypt::decrypt($object->name) : $object->name;
} }
); );
$data = $data->filter(
return $data; function(TransactionJournal $journal) {
} if ($journal->amount != 0) {
return $journal;
/**
* This method returns all deposits into asset accounts, grouped by the revenue account,
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByRevenueAccount(Carbon $start, Carbon $end, $showSharedReports = false)
{
$query = $this->queryJournalsWithTransactions($start, $end);
if ($showSharedReports === false) {
// show queries where transfer type is deposit, and its not to a shared account
// or where its a transfer and its from a shared account (both count as incomes)
$query->where(
function (Builder $query) {
$query->where(
function (Builder $q) {
$q->where('transaction_types.type', 'Deposit');
$q->where('acm_to.data', '!=', '"sharedAsset"');
}
);
$query->orWhere(
function (Builder $q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_from.data', '=', '"sharedAsset"');
}
);
} }
); return null;
} else {
// any deposit goes:
$query->where('transaction_types.type', 'Deposit');
}
$query->groupBy('t_from.account_id')->orderBy('queryAmount');
$data = $query->get(
['t_from.account_id as account_id', 'ac_from.name as name', 'ac_from.encrypted as encrypted', DB::Raw('SUM(t_from.amount) as `queryAmount`')]
);
// decrypt
$data->each(
function (Model $object) {
$object->name = intval($object->encrypted) == 1 ? Crypt::decrypt($object->name) : $object->name;
} }
); );
@@ -458,119 +197,51 @@ class ReportQuery implements ReportQueryInterface
} }
/** /**
* With an equally misleading name, this query returns are transfers to shared accounts. These are considered * Covers tags
* expenses.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function sharedExpenses(Carbon $start, Carbon $end)
{
return TransactionJournal::
leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where(
'transactions.amount', '>', 0
);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->where('account_meta.data', '"sharedAsset"')
->after($start)
->before($end)
->where('transaction_types.type', 'Transfer')
->where('transaction_journals.user_id', Auth::user()->id)
->get(
['transaction_journals.id', 'transaction_journals.description', 'transactions.account_id', 'accounts.name',
'transactions.amount as queryAmount']
);
}
/**
* With a slightly misleading name, this query returns all transfers to shared accounts
* which are technically expenses, since it won't be just your money that gets spend.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function sharedExpensesByCategory(Carbon $start, Carbon $end)
{
return TransactionJournal::
leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where(
'transactions.amount', '>', 0
);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->leftJoin(
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
)
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
->where('account_meta.data', '"sharedAsset"')
->after($start)
->before($end)
->where('transaction_types.type', 'Transfer')
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('categories.name')
->get(
[
'categories.id',
'categories.name as name',
DB::Raw('SUM(`transactions`.`amount`) * -1 AS `queryAmount`')
]
);
}
/**
*
* This query will get all transaction journals and budget information for a specified account
* in a certain date range, where the transaction journal does not have a budget.
* There is no get() specified, this is up to the method itself.
* *
* @param Account $account * @param Account $account
* @param Budget $budget
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @return Builder * @return float
*/ */
protected function queryJournalsNoBudget(Account $account, Carbon $start, Carbon $end) public function spentInBudgetCorrected(Account $account, Budget $budget, Carbon $start, Carbon $end)
{ {
return TransactionJournal::
leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') return floatval(
->leftJoin('budgets', 'budgets.id', '=', 'budget_transaction_journal.budget_id') Auth::user()->transactionjournals()
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin( ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
'transactions', function (JoinClause $join) { ->transactionTypes(['Withdrawal'])
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0); ->where('transactions.account_id', $account->id)
} ->before($end)
) ->after($start)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') ->where('budget_transaction_journal.budget_id', $budget->id)
->before($end) ->get(['transaction_journals.*'])->sum('amount')
->after($start) ) * -1;
->where('accounts.id', $account->id) }
->where('transaction_journals.user_id', Auth::user()->id)
->where('transaction_types.type', 'Withdrawal') /**
->groupBy('budgets.id') * @param Account $account
->orderBy('budgets.name', 'ASC'); * @param Carbon $start
* @param Carbon $end
* @param bool $shared
*
* @return float
*/
public function spentNoBudget(Account $account, Carbon $start, Carbon $end, $shared = false)
{
return floatval(
Auth::user()->transactionjournals()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->transactionTypes(['Withdrawal'])
->where('transactions.account_id', $account->id)
->before($end)
->after($start)
->whereNull('budget_transaction_journal.budget_id')->get(['transaction_journals.*'])->sum('amount')
);
} }
/** /**
@@ -583,31 +254,30 @@ class ReportQuery implements ReportQueryInterface
{ {
$query = TransactionJournal:: $query = TransactionJournal::
leftJoin( leftJoin(
'transactions as t_from', function (JoinClause $join) { 'transactions as t_from', function(JoinClause $join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0); $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
} }
) )
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id') ->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin( ->leftJoin(
'account_meta as acm_from', function (JoinClause $join) { 'account_meta as acm_from', function(JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole'); $join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
} }
) )
->leftJoin( ->leftJoin(
'transactions as t_to', function (JoinClause $join) { 'transactions as t_to', function(JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0); $join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
} }
) )
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id') ->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin( ->leftJoin(
'account_meta as acm_to', function (JoinClause $join) { 'account_meta as acm_to', function(JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole'); $join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
} }
) )
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id'); ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
$query->before($end)->after($start)->where('transaction_journals.user_id', Auth::user()->id); $query->before($end)->after($start)->where('transaction_journals.user_id', Auth::user()->id);
return $query; return $query;
} }
} }

View File

@@ -4,6 +4,7 @@ namespace FireflyIII\Helpers\Report;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**
@@ -15,152 +16,66 @@ interface ReportQueryInterface
{ {
/** /**
* This query retrieves a list of accounts that are active and not shared. * See ReportQueryInterface::incomeInPeriodCorrected
* *
* @param bool $showSharedReports * This method returns all "expense" journals in a certain period, which are both transfers to a shared account
* and "ordinary" withdrawals. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
* not group and returns different fields.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $includeShared
* *
* @return Collection * @return Collection
*
*/ */
public function accountList($showSharedReports = false); public function expenseInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false);
/**
* This method will get a list of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function balancedTransactionsList(Account $account, Carbon $start, Carbon $end);
/**
* This method will get the sum of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return float
*/
public function balancedTransactionsSum(Account $account, Carbon $start, Carbon $end);
/** /**
* Get a users accounts combined with various meta-data related to the start and end date. * Get a users accounts combined with various meta-data related to the start and end date.
* *
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $showSharedReports * @param bool $includeShared
* *
* @return Collection * @return Collection
*/ */
public function getAllAccounts(Carbon $start, Carbon $end, $showSharedReports = false); public function getAllAccounts(Carbon $start, Carbon $end, $includeShared = false);
/** /**
* Grabs a summary of all expenses grouped by budget, related to the account. * This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results
* will simply list the transaction journals only. This should allow any follow up counting to be accurate with
* regards to tags.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $includeShared
*
* @return Collection
*/
public function incomeInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false);
/**
* Covers tags as well.
* *
* @param Account $account * @param Account $account
* @param Budget $budget
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @return mixed * @return float
*/ */
public function getBudgetSummary(Account $account, Carbon $start, Carbon $end); public function spentInBudgetCorrected(Account $account, Budget $budget, Carbon $start, Carbon $end);
/** /**
* Get a list of transaction journals that have no budget, filtered for the specified account
* and the specified date range.
*
* @param Account $account * @param Account $account
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $shared
* *
* @return Collection * @return float
*/ */
public function getTransactionsWithoutBudget(Account $account, Carbon $start, Carbon $end); public function spentNoBudget(Account $account, Carbon $start, Carbon $end, $shared = false);
/**
* This method returns all "income" journals in a certain period, which are both transfers from a shared account
* and "ordinary" deposits. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
* not group and returns different fields.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function incomeByPeriod(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Gets a list of expenses grouped by the budget they were filed under.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByBudget(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Gets a list of categories and the expenses therein, grouped by the relevant category.
* This result excludes transfers to shared accounts which are expenses, technically.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByCategory(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Gets a list of expense accounts and the expenses therein, grouped by that expense account.
* This result excludes transfers to shared accounts which are expenses, technically.
*
* So now it will include them!
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByExpenseAccount(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* This method returns all deposits into asset accounts, grouped by the revenue account,
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByRevenueAccount(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* With an equally misleading name, this query returns are transfers to shared accounts. These are considered
* expenses.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function sharedExpenses(Carbon $start, Carbon $end);
/**
* With a slightly misleading name, this query returns all transfers to shared accounts
* which are technically expenses, since it won't be just your money that gets spend.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function sharedExpensesByCategory(Carbon $start, Carbon $end);
} }

View File

@@ -3,7 +3,6 @@
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Config; use Config;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\AccountFormRequest; use FireflyIII\Http\Requests\AccountFormRequest;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -22,13 +21,13 @@ use View;
class AccountController extends Controller class AccountController extends Controller
{ {
/** /**
* * @codeCoverageIgnore
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
View::share('mainTitleIcon', 'fa-credit-card'); View::share('mainTitleIcon', 'fa-credit-card');
View::share('title', 'Accounts'); View::share('title', trans('firefly.accounts'));
} }
/** /**
@@ -39,13 +38,15 @@ class AccountController extends Controller
public function create($what = 'asset') public function create($what = 'asset')
{ {
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what); $subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
$subTitle = 'Create a new ' . e($what) . ' account'; $subTitle = trans('firefly.make_new_' . $what . '_account');
// put previous url in session if not redirect from store (not "create another"). // put previous url in session if not redirect from store (not "create another").
if (Session::get('accounts.create.fromStore') !== true) { if (Session::get('accounts.create.fromStore') !== true) {
Session::put('accounts.create.url', URL::previous()); Session::put('accounts.create.url', URL::previous());
} }
Session::forget('accounts.create.fromStore'); Session::forget('accounts.create.fromStore');
Session::flash('gaEventCategory', 'accounts');
Session::flash('gaEventAction', 'create-' . $what);
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle')); return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
@@ -58,10 +59,13 @@ class AccountController extends Controller
*/ */
public function delete(Account $account) public function delete(Account $account)
{ {
$subTitle = 'Delete ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"'; $typeName = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
$subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]);
// put previous url in session // put previous url in session
Session::put('accounts.delete.url', URL::previous()); Session::put('accounts.delete.url', URL::previous());
Session::flash('gaEventCategory', 'accounts');
Session::flash('gaEventAction', 'delete-' . $typeName);
return view('accounts.delete', compact('account', 'subTitle')); return view('accounts.delete', compact('account', 'subTitle'));
} }
@@ -81,7 +85,7 @@ class AccountController extends Controller
$repository->destroy($account); $repository->destroy($account);
Session::flash('success', 'The ' . e($typeName) . ' account "' . e($name) . '" was deleted.'); Session::flash('success', trans('firefly.' . $typeName . '_deleted', ['name' => $name]));
return Redirect::to(Session::get('accounts.delete.url')); return Redirect::to(Session::get('accounts.delete.url'));
} }
@@ -90,13 +94,13 @@ class AccountController extends Controller
* @param AccountRepositoryInterface $repository * @param AccountRepositoryInterface $repository
* @param Account $account * @param Account $account
* *
* @return View * @return \Illuminate\View\View
*/ */
public function edit(AccountRepositoryInterface $repository, Account $account) public function edit(AccountRepositoryInterface $repository, Account $account)
{ {
$what = Config::get('firefly.shortNamesByFullName')[$account->accountType->type]; $what = Config::get('firefly.shortNamesByFullName')[$account->accountType->type];
$subTitle = 'Edit ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"'; $subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what); $subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
$openingBalance = $repository->openingBalanceTransaction($account); $openingBalance = $repository->openingBalanceTransaction($account);
@@ -125,6 +129,8 @@ class AccountController extends Controller
'virtualBalance' => floatval($account->virtual_balance) 'virtualBalance' => floatval($account->virtual_balance)
]; ];
Session::flash('preFilled', $preFilled); Session::flash('preFilled', $preFilled);
Session::flash('gaEventCategory', 'accounts');
Session::flash('gaEventAction', 'edit-' . $what);
return view('accounts.edit', compact('account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what')); return view('accounts.edit', compact('account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what'));
} }
@@ -133,11 +139,11 @@ class AccountController extends Controller
* @param AccountRepositoryInterface $repository * @param AccountRepositoryInterface $repository
* @param $what * @param $what
* *
* @return View * @return \Illuminate\View\View
*/ */
public function index(AccountRepositoryInterface $repository, $what) public function index(AccountRepositoryInterface $repository, $what)
{ {
$subTitle = Config::get('firefly.subTitlesByIdentifier.' . $what); $subTitle = trans('firefly.' . $what . '_accounts');
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what); $subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
$types = Config::get('firefly.accountTypesByIdentifier.' . $what); $types = Config::get('firefly.accountTypesByIdentifier.' . $what);
$accounts = $repository->getAccounts($types); $accounts = $repository->getAccounts($types);
@@ -148,7 +154,7 @@ class AccountController extends Controller
$start = clone Session::get('start', Carbon::now()->startOfMonth()); $start = clone Session::get('start', Carbon::now()->startOfMonth());
$start->subDay(); $start->subDay();
$accounts->each( $accounts->each(
function (Account $account) use ($start, $repository) { function(Account $account) use ($start, $repository) {
$account->lastActivityDate = $repository->getLastActivity($account); $account->lastActivityDate = $repository->getLastActivity($account);
$account->startBalance = Steam::balance($account, $start); $account->startBalance = Steam::balance($account, $start);
$account->endBalance = Steam::balance($account, clone Session::get('end', Carbon::now()->endOfMonth())); $account->endBalance = Steam::balance($account, clone Session::get('end', Carbon::now()->endOfMonth()));
@@ -162,7 +168,7 @@ class AccountController extends Controller
* @param AccountRepositoryInterface $repository * @param AccountRepositoryInterface $repository
* @param Account $account * @param Account $account
* *
* @return View * @return \Illuminate\View\View
*/ */
public function show(AccountRepositoryInterface $repository, Account $account) public function show(AccountRepositoryInterface $repository, Account $account)
{ {
@@ -170,7 +176,7 @@ class AccountController extends Controller
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $account->accountType->type); $subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $account->accountType->type);
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type); $what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
$journals = $repository->getJournals($account, $page); $journals = $repository->getJournals($account, $page);
$subTitle = 'Details for ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"'; $subTitle = trans('firefly.details_for_' . $what, ['name' => $account->name]);
$journals->setPath('accounts/show/' . $account->id); $journals->setPath('accounts/show/' . $account->id);
@@ -193,11 +199,11 @@ class AccountController extends Controller
'user' => Auth::user()->id, 'user' => Auth::user()->id,
'accountRole' => $request->input('accountRole'), 'accountRole' => $request->input('accountRole'),
'openingBalance' => floatval($request->input('openingBalance')), 'openingBalance' => floatval($request->input('openingBalance')),
'openingBalanceDate' => new Carbon($request->input('openingBalanceDate')), 'openingBalanceDate' => new Carbon((string) $request->input('openingBalanceDate')),
'openingBalanceCurrency' => intval($request->input('balance_currency_id')), 'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
]; ];
$account = $repository->store($accountData); $account = $repository->store($accountData);
Session::flash('success', 'New account "' . $account->name . '" stored!'); Session::flash('success', 'New account "' . $account->name . '" stored!');
@@ -219,7 +225,7 @@ class AccountController extends Controller
* @param AccountRepositoryInterface $repository * @param AccountRepositoryInterface $repository
* @param Account $account * @param Account $account
* *
* @return $this|\Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function update(AccountFormRequest $request, AccountRepositoryInterface $repository, Account $account) public function update(AccountFormRequest $request, AccountRepositoryInterface $repository, Account $account)
{ {
@@ -231,7 +237,7 @@ class AccountController extends Controller
'accountRole' => $request->input('accountRole'), 'accountRole' => $request->input('accountRole'),
'virtualBalance' => floatval($request->input('virtualBalance')), 'virtualBalance' => floatval($request->input('virtualBalance')),
'openingBalance' => floatval($request->input('openingBalance')), 'openingBalance' => floatval($request->input('openingBalance')),
'openingBalanceDate' => new Carbon($request->input('openingBalanceDate')), 'openingBalanceDate' => new Carbon((string) $request->input('openingBalanceDate')),
'openingBalanceCurrency' => intval($request->input('balance_currency_id')), 'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
'ccType' => $request->input('ccType'), 'ccType' => $request->input('ccType'),
'ccMonthlyPaymentDate' => $request->input('ccMonthlyPaymentDate'), 'ccMonthlyPaymentDate' => $request->input('ccMonthlyPaymentDate'),
@@ -245,7 +251,7 @@ class AccountController extends Controller
// set value so edit routine will not overwrite URL: // set value so edit routine will not overwrite URL:
Session::put('accounts.edit.fromUpdate', true); Session::put('accounts.edit.fromUpdate', true);
return Redirect::route('accounts.edit', $account->id)->withInput(['return_to_edit' => 1]); return Redirect::route('accounts.edit', [$account->id])->withInput(['return_to_edit' => 1]);
} }
// redirect to previous URL. // redirect to previous URL.

View File

@@ -1,6 +1,9 @@
<?php namespace FireflyIII\Http\Controllers\Auth; <?php namespace FireflyIII\Http\Controllers\Auth;
use App;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Role;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\Registrar; use Illuminate\Contracts\Auth\Registrar;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers; use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
@@ -38,6 +41,7 @@ class AuthController extends Controller
* *
* @param \Illuminate\Contracts\Auth\Guard $auth * @param \Illuminate\Contracts\Auth\Guard $auth
* @param \Illuminate\Contracts\Auth\Registrar $registrar * @param \Illuminate\Contracts\Auth\Registrar $registrar
*
* @codeCoverageIgnore * @codeCoverageIgnore
* *
*/ */
@@ -66,7 +70,7 @@ class AuthController extends Controller
* *
* @param Request $request * @param Request $request
* *
* @return \Illuminate\Http\Response * @return \Illuminate\Http\RedirectResponse
*/ */
public function postRegister(Request $request) public function postRegister(Request $request)
{ {
@@ -86,22 +90,34 @@ class AuthController extends Controller
$this->auth->login($this->registrar->create($data)); $this->auth->login($this->registrar->create($data));
// get the email address // get the email address
$email = $this->auth->user()->email; if ($this->auth->user() instanceof User) {
$email = $this->auth->user()->email;
// send email. // send email.
Mail::send( Mail::send(
'emails.registered', [], function (Message $message) use ($email) { 'emails.registered', [], function (Message $message) use ($email) {
$message->to($email, $email)->subject('Welcome to Firefly III!'); $message->to($email, $email)->subject('Welcome to Firefly III!');
}
);
// set flash message
Session::flash('success', 'You have registered successfully!');
Session::flash('gaEventCategory', 'user');
Session::flash('gaEventAction', 'new-registration');
// first user ever?
if (User::count() == 1) {
$admin = Role::where('name', 'owner')->first();
$this->auth->user()->attachRole($admin);
// $this->auth->user()->roles()->save($admin);
}
return redirect($this->redirectPath());
} }
); App::abort(500, 'Not a user!');
// set flash message return redirect('/');
Session::flash('success', 'You have registered successfully!');
Session::flash('gaEventCategory', 'user');
Session::flash('gaEventAction', 'new-registration');
return redirect($this->redirectPath());
} }
} }

View File

@@ -7,6 +7,7 @@ use Illuminate\Foundation\Auth\ResetsPasswords;
/** /**
* Class PasswordController * Class PasswordController
*
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Http\Controllers\Auth * @package FireflyIII\Http\Controllers\Auth
*/ */
@@ -35,6 +36,8 @@ class PasswordController extends Controller
* @param \Illuminate\Contracts\Auth\Guard $auth * @param \Illuminate\Contracts\Auth\Guard $auth
* @param \Illuminate\Contracts\Auth\PasswordBroker $passwords * @param \Illuminate\Contracts\Auth\PasswordBroker $passwords
* *
* @codeCoverageIgnore
*
*/ */
public function __construct(Guard $auth, PasswordBroker $passwords) public function __construct(Guard $auth, PasswordBroker $passwords)
{ {

View File

@@ -1,13 +1,9 @@
<?php namespace FireflyIII\Http\Controllers; <?php namespace FireflyIII\Http\Controllers;
use Config; use Config;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\BillFormRequest; use FireflyIII\Http\Requests\BillFormRequest;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Input; use Input;
use Redirect; use Redirect;
@@ -24,61 +20,17 @@ class BillController extends Controller
{ {
/** /**
* * @codeCoverageIgnore
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
View::share('title', 'Bills'); View::share('title', trans('firefly.bills'));
View::share('mainTitleIcon', 'fa-calendar-o'); View::share('mainTitleIcon', 'fa-calendar-o');
} }
/** /**
* @param AccountRepositoryInterface $repository * @return \Illuminate\View\View
* @param Bill $bill
*
* @return \Illuminate\Http\RedirectResponse
*/
public function add(AccountRepositoryInterface $repository, Bill $bill)
{
$matches = explode(',', $bill->match);
$description = [];
$expense = null;
// get users expense accounts:
$accounts = $repository->getAccounts(Config::get('firefly.accountTypesByIdentifier.expense'));
foreach ($matches as $match) {
$match = strtolower($match);
// find expense account for each word if not found already:
if (is_null($expense)) {
/** @var Account $account */
foreach ($accounts as $account) {
$name = strtolower($account->name);
if (!(strpos($name, $match) === false)) {
$expense = $account;
break;
}
}
}
if (is_null($expense)) {
$description[] = $match;
}
}
$parameters = [
'description' => ucfirst(join(' ', $description)),
'expense_account' => is_null($expense) ? '' : $expense->name,
'amount' => round(($bill->amount_min + $bill->amount_max), 2),
];
Session::put('preFilled', $parameters);
return Redirect::to(route('transactions.create', 'withdrawal'));
}
/**
* @return $this
*/ */
public function create() public function create()
{ {
@@ -89,6 +41,8 @@ class BillController extends Controller
Session::put('bills.create.url', URL::previous()); Session::put('bills.create.url', URL::previous());
} }
Session::forget('bills.create.fromStore'); Session::forget('bills.create.fromStore');
Session::flash('gaEventCategory', 'bills');
Session::flash('gaEventAction', 'create');
$subTitle = 'Create new bill'; $subTitle = 'Create new bill';
return view('bills.create', compact('periods', 'subTitle')); return view('bills.create', compact('periods', 'subTitle'));
@@ -97,13 +51,15 @@ class BillController extends Controller
/** /**
* @param Bill $bill * @param Bill $bill
* *
* @return $this * @return \Illuminate\View\View
*/ */
public function delete(Bill $bill) public function delete(Bill $bill)
{ {
// put previous url in session // put previous url in session
Session::put('bills.delete.url', URL::previous()); Session::put('bills.delete.url', URL::previous());
$subTitle = 'Delete "' . e($bill->name) . '"'; Session::flash('gaEventCategory', 'bills');
Session::flash('gaEventAction', 'delete');
$subTitle = trans('firefly.delete_bill', ['name' => $bill->name]);
return view('bills.delete', compact('bill', 'subTitle')); return view('bills.delete', compact('bill', 'subTitle'));
} }
@@ -127,7 +83,7 @@ class BillController extends Controller
/** /**
* @param Bill $bill * @param Bill $bill
* *
* @return $this * @return \Illuminate\View\View
*/ */
public function edit(Bill $bill) public function edit(Bill $bill)
{ {
@@ -139,6 +95,8 @@ class BillController extends Controller
Session::put('bills.edit.url', URL::previous()); Session::put('bills.edit.url', URL::previous());
} }
Session::forget('bills.edit.fromUpdate'); Session::forget('bills.edit.fromUpdate');
Session::flash('gaEventCategory', 'bills');
Session::flash('gaEventAction', 'edit');
return view('bills.edit', compact('subTitle', 'periods', 'bill')); return view('bills.edit', compact('subTitle', 'periods', 'bill'));
} }
@@ -152,7 +110,7 @@ class BillController extends Controller
{ {
$bills = $repository->getBills(); $bills = $repository->getBills();
$bills->each( $bills->each(
function (Bill $bill) use ($repository) { function(Bill $bill) use ($repository) {
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill); $bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
$bill->lastFoundMatch = $repository->lastFoundMatch($bill); $bill->lastFoundMatch = $repository->lastFoundMatch($bill);
} }
@@ -191,7 +149,7 @@ class BillController extends Controller
* @param BillRepositoryInterface $repository * @param BillRepositoryInterface $repository
* @param Bill $bill * @param Bill $bill
* *
* @return mixed * @return \Illuminate\View\View
*/ */
public function show(BillRepositoryInterface $repository, Bill $bill) public function show(BillRepositoryInterface $repository, Bill $bill)
{ {
@@ -207,7 +165,7 @@ class BillController extends Controller
* @param BillFormRequest $request * @param BillFormRequest $request
* @param BillRepositoryInterface $repository * @param BillRepositoryInterface $repository
* *
* @return $this|\Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function store(BillFormRequest $request, BillRepositoryInterface $repository) public function store(BillFormRequest $request, BillRepositoryInterface $repository)
{ {
@@ -232,7 +190,7 @@ class BillController extends Controller
* @param BillRepositoryInterface $repository * @param BillRepositoryInterface $repository
* @param Bill $bill * @param Bill $bill
* *
* @return $this|\Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function update(BillFormRequest $request, BillRepositoryInterface $repository, Bill $bill) public function update(BillFormRequest $request, BillRepositoryInterface $repository, Bill $bill)
{ {
@@ -245,7 +203,7 @@ class BillController extends Controller
// set value so edit routine will not overwrite URL: // set value so edit routine will not overwrite URL:
Session::put('bills.edit.fromUpdate', true); Session::put('bills.edit.fromUpdate', true);
return Redirect::route('bills.edit', $bill->id)->withInput(['return_to_edit' => 1]); return Redirect::route('bills.edit', [$bill->id])->withInput(['return_to_edit' => 1]);
} }
// redirect to previous URL. // redirect to previous URL.

View File

@@ -1,8 +1,8 @@
<?php namespace FireflyIII\Http\Controllers; <?php namespace FireflyIII\Http\Controllers;
use Amount;
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\BudgetFormRequest; use FireflyIII\Http\Requests\BudgetFormRequest;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\LimitRepetition;
@@ -19,17 +19,18 @@ use View;
* Class BudgetController * Class BudgetController
* *
* @package FireflyIII\Http\Controllers * @package FireflyIII\Http\Controllers
* @SuppressWarnings(PHPMD.TooManyMethods)
*/ */
class BudgetController extends Controller class BudgetController extends Controller
{ {
/** /**
* * @codeCoverageIgnore
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
View::share('title', 'Budgets'); View::share('title', trans('firefly.budgets'));
View::share('mainTitleIcon', 'fa-tasks'); View::share('mainTitleIcon', 'fa-tasks');
View::share('hideBudgets', true); View::share('hideBudgets', true);
} }
@@ -45,13 +46,16 @@ class BudgetController extends Controller
$amount = intval(Input::get('amount')); $amount = intval(Input::get('amount'));
$date = Session::get('start', Carbon::now()->startOfMonth()); $date = Session::get('start', Carbon::now()->startOfMonth());
$limitRepetition = $repository->updateLimitAmount($budget, $date, $amount); $limitRepetition = $repository->updateLimitAmount($budget, $date, $amount);
if ($amount == 0) {
$limitRepetition = null;
}
return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0]); return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0]);
} }
/** /**
* @return $this * @return \Illuminate\View\View
*/ */
public function create() public function create()
{ {
@@ -60,7 +64,9 @@ class BudgetController extends Controller
Session::put('budgets.create.url', URL::previous()); Session::put('budgets.create.url', URL::previous());
} }
Session::forget('budgets.create.fromStore'); Session::forget('budgets.create.fromStore');
$subTitle = 'Create a new budget'; Session::flash('gaEventCategory', 'budgets');
Session::flash('gaEventAction', 'create');
$subTitle = trans('firefly.create_new_budget');
return view('budgets.create', compact('subTitle')); return view('budgets.create', compact('subTitle'));
} }
@@ -72,10 +78,12 @@ class BudgetController extends Controller
*/ */
public function delete(Budget $budget) public function delete(Budget $budget)
{ {
$subTitle = 'Delete budget' . e($budget->name) . '"'; $subTitle = trans('firefly.delete_budget', ['name' => $budget->name]);
// put previous url in session // put previous url in session
Session::put('budgets.delete.url', URL::previous()); Session::put('budgets.delete.url', URL::previous());
Session::flash('gaEventCategory', 'budgets');
Session::flash('gaEventAction', 'delete');
return view('budgets.delete', compact('budget', 'subTitle')); return view('budgets.delete', compact('budget', 'subTitle'));
} }
@@ -95,13 +103,14 @@ class BudgetController extends Controller
Session::flash('success', 'The budget "' . e($name) . '" was deleted.'); Session::flash('success', 'The budget "' . e($name) . '" was deleted.');
return Redirect::to(Session::get('budgets.delete.url')); return Redirect::to(Session::get('budgets.delete.url'));
} }
/** /**
* @param Budget $budget * @param Budget $budget
* *
* @return $this * @return \Illuminate\View\View
*/ */
public function edit(Budget $budget) public function edit(Budget $budget)
{ {
@@ -112,6 +121,8 @@ class BudgetController extends Controller
Session::put('budgets.edit.url', URL::previous()); Session::put('budgets.edit.url', URL::previous());
} }
Session::forget('budgets.edit.fromUpdate'); Session::forget('budgets.edit.fromUpdate');
Session::flash('gaEventCategory', 'budgets');
Session::flash('gaEventAction', 'edit');
return view('budgets.edit', compact('budget', 'subTitle')); return view('budgets.edit', compact('budget', 'subTitle'));
@@ -120,13 +131,15 @@ class BudgetController extends Controller
/** /**
* @param BudgetRepositoryInterface $repository * @param BudgetRepositoryInterface $repository
* *
* @return View * @return \Illuminate\View\View
*/ */
public function index(BudgetRepositoryInterface $repository) public function index(BudgetRepositoryInterface $repository)
{ {
$budgets = $repository->getActiveBudgets(); $budgets = $repository->getActiveBudgets();
$inactive = $repository->getInactiveBudgets(); $inactive = $repository->getInactiveBudgets();
$spent = '0';
$budgeted = '0';
bcscale(2);
/** /**
* Do some cleanup: * Do some cleanup:
*/ */
@@ -134,36 +147,43 @@ class BudgetController extends Controller
// loop the budgets: // loop the budgets:
$budgets->each( /** @var Budget $budget */
function (Budget $budget) use ($repository) { foreach ($budgets as $budget) {
$date = Session::get('start', Carbon::now()->startOfMonth()); $date = Session::get('start', Carbon::now()->startOfMonth());
$budget->spent = $repository->spentInMonth($budget, $date); $end = Session::get('end', Carbon::now()->endOfMonth());
$budget->currentRep = $repository->getCurrentRepetition($budget, $date); $budget->spent = $repository->spentInPeriodCorrected($budget, $date, $end);
$budget->currentRep = $repository->getCurrentRepetition($budget, $date);
if ($budget->currentRep) {
$budgeted = bcadd($budgeted, $budget->currentRep->amount);
} }
$spent = bcadd($spent, $budget->spent);
}
$dateAsString = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
$budgetIncomeTotal = Preferences::get('budgetIncomeTotal' . $dateAsString, 1000)->data;
$budgetMaximum = Preferences::get('budgetMaximum', 1000)->data;
$defaultCurrency = Amount::getDefaultCurrency();
return view(
'budgets.index', compact('budgetMaximum', 'budgetIncomeTotal', 'defaultCurrency', 'inactive', 'budgets', 'spent', 'budgeted')
); );
$dateAsString = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
$spent = $budgets->sum('spent');
$amount = Preferences::get('budgetIncomeTotal' . $dateAsString, 1000)->data;
$overspent = $spent > $amount;
$spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100);
$budgetMax = Preferences::get('budgetMaximum', 1000);
$budgetMaximum = $budgetMax->data;
return view('budgets.index', compact('budgetMaximum', 'inactive', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount'));
} }
/** /**
* @param BudgetRepositoryInterface $repository * @param BudgetRepositoryInterface $repository
* *
* @return View * @return \Illuminate\View\View
*/ */
public function noBudget(BudgetRepositoryInterface $repository) public function noBudget(BudgetRepositoryInterface $repository)
{ {
$start = Session::get('start', Carbon::now()->startOfMonth()); $start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->startOfMonth()); $end = Session::get('end', Carbon::now()->startOfMonth());
$list = $repository->getWithoutBudget($start, $end); $list = $repository->getWithoutBudget($start, $end);
$subTitle = 'Transactions without a budget between ' . $start->format('jS F Y') . ' and ' . $end->format('jS F Y'); $subTitle = trans(
'firefly.without_budget_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
return view('budgets.noBudget', compact('list', 'subTitle')); return view('budgets.noBudget', compact('list', 'subTitle'));
} }
@@ -185,7 +205,7 @@ class BudgetController extends Controller
* @param Budget $budget * @param Budget $budget
* @param LimitRepetition $repetition * @param LimitRepetition $repetition
* *
* @return View * @return \Illuminate\View\View
*/ */
public function show(BudgetRepositoryInterface $repository, Budget $budget, LimitRepetition $repetition = null) public function show(BudgetRepositoryInterface $repository, Budget $budget, LimitRepetition $repetition = null)
{ {
@@ -197,7 +217,11 @@ class BudgetController extends Controller
$journals = $repository->getJournals($budget, $repetition); $journals = $repository->getJournals($budget, $repetition);
$limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $repository->getBudgetLimits($budget); $limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $repository->getBudgetLimits($budget);
$subTitle = !is_null($repetition->id) ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name); $subTitle = !is_null($repetition->id)
?
trans('firefly.budget_in_month', ['name' => $budget->name, 'month' => $repetition->startdate->formatLocalized($this->monthFormat)])
:
e($budget->name);
$journals->setPath('/budgets/show/' . $budget->id); $journals->setPath('/budgets/show/' . $budget->id);
return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle')); return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle'));
@@ -215,7 +239,7 @@ class BudgetController extends Controller
'name' => $request->input('name'), 'name' => $request->input('name'),
'user' => Auth::user()->id, 'user' => Auth::user()->id,
]; ];
$budget = $repository->store($budgetData); $budget = $repository->store($budgetData);
Session::flash('success', 'New budget "' . $budget->name . '" stored!'); Session::flash('success', 'New budget "' . $budget->name . '" stored!');
@@ -236,7 +260,7 @@ class BudgetController extends Controller
* @param BudgetRepositoryInterface $repository * @param BudgetRepositoryInterface $repository
* @param Budget $budget * @param Budget $budget
* *
* @return $this|\Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function update(BudgetFormRequest $request, BudgetRepositoryInterface $repository, Budget $budget) public function update(BudgetFormRequest $request, BudgetRepositoryInterface $repository, Budget $budget)
{ {
@@ -253,7 +277,7 @@ class BudgetController extends Controller
// set value so edit routine will not overwrite URL: // set value so edit routine will not overwrite URL:
Session::put('budgets.edit.fromUpdate', true); Session::put('budgets.edit.fromUpdate', true);
return Redirect::route('budgets.edit', $budget->id)->withInput(['return_to_edit' => 1]); return Redirect::route('budgets.edit', [$budget->id])->withInput(['return_to_edit' => 1]);
} }
// redirect to previous URL. // redirect to previous URL.
@@ -262,7 +286,7 @@ class BudgetController extends Controller
} }
/** /**
* @return View * @return \Illuminate\View\View
*/ */
public function updateIncome() public function updateIncome()
{ {

View File

@@ -21,17 +21,17 @@ class CategoryController extends Controller
{ {
/** /**
* * @codeCoverageIgnore
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
View::share('title', 'Categories'); View::share('title', trans('firefly.categories'));
View::share('mainTitleIcon', 'fa-bar-chart'); View::share('mainTitleIcon', 'fa-bar-chart');
} }
/** /**
* @return $this * @return \Illuminate\View\View
*/ */
public function create() public function create()
{ {
@@ -40,6 +40,8 @@ class CategoryController extends Controller
Session::put('categories.create.url', URL::previous()); Session::put('categories.create.url', URL::previous());
} }
Session::forget('categories.create.fromStore'); Session::forget('categories.create.fromStore');
Session::flash('gaEventCategory', 'categories');
Session::flash('gaEventAction', 'create');
$subTitle = 'Create a new category'; $subTitle = 'Create a new category';
return view('categories.create', compact('subTitle')); return view('categories.create', compact('subTitle'));
@@ -52,10 +54,12 @@ class CategoryController extends Controller
*/ */
public function delete(Category $category) public function delete(Category $category)
{ {
$subTitle = 'Delete category "' . e($category->name) . '"'; $subTitle = trans('firefly.delete_category', ['name' => $category->name]);
// put previous url in session // put previous url in session
Session::put('categories.delete.url', URL::previous()); Session::put('categories.delete.url', URL::previous());
Session::flash('gaEventCategory', 'categories');
Session::flash('gaEventAction', 'delete');
return view('categories.delete', compact('category', 'subTitle')); return view('categories.delete', compact('category', 'subTitle'));
} }
@@ -80,7 +84,7 @@ class CategoryController extends Controller
/** /**
* @param Category $category * @param Category $category
* *
* @return $this * @return \Illuminate\View\View
*/ */
public function edit(Category $category) public function edit(Category $category)
{ {
@@ -91,6 +95,8 @@ class CategoryController extends Controller
Session::put('categories.edit.url', URL::previous()); Session::put('categories.edit.url', URL::previous());
} }
Session::forget('categories.edit.fromUpdate'); Session::forget('categories.edit.fromUpdate');
Session::flash('gaEventCategory', 'categories');
Session::flash('gaEventAction', 'edit');
return view('categories.edit', compact('category', 'subTitle')); return view('categories.edit', compact('category', 'subTitle'));
@@ -99,14 +105,14 @@ class CategoryController extends Controller
/** /**
* @param CategoryRepositoryInterface $repository * @param CategoryRepositoryInterface $repository
* *
* @return $this * @return \Illuminate\View\View
*/ */
public function index(CategoryRepositoryInterface $repository) public function index(CategoryRepositoryInterface $repository)
{ {
$categories = $repository->getCategories(); $categories = $repository->getCategories();
$categories->each( $categories->each(
function (Category $category) use ($repository) { function(Category $category) use ($repository) {
$category->lastActivity = $repository->getLatestActivity($category); $category->lastActivity = $repository->getLatestActivity($category);
} }
); );
@@ -133,7 +139,7 @@ class CategoryController extends Controller
* @param CategoryRepositoryInterface $repository * @param CategoryRepositoryInterface $repository
* @param Category $category * @param Category $category
* *
* @return View * @return \Illuminate\View\View
*/ */
public function show(CategoryRepositoryInterface $repository, Category $category) public function show(CategoryRepositoryInterface $repository, Category $category)
{ {
@@ -151,7 +157,7 @@ class CategoryController extends Controller
* @param CategoryFormRequest $request * @param CategoryFormRequest $request
* @param CategoryRepositoryInterface $repository * @param CategoryRepositoryInterface $repository
* *
* @return mixed * @return \Illuminate\Http\RedirectResponse
*/ */
public function store(CategoryFormRequest $request, CategoryRepositoryInterface $repository) public function store(CategoryFormRequest $request, CategoryRepositoryInterface $repository)
{ {
@@ -159,7 +165,7 @@ class CategoryController extends Controller
'name' => $request->input('name'), 'name' => $request->input('name'),
'user' => Auth::user()->id, 'user' => Auth::user()->id,
]; ];
$category = $repository->store($categoryData); $category = $repository->store($categoryData);
Session::flash('success', 'New category "' . $category->name . '" stored!'); Session::flash('success', 'New category "' . $category->name . '" stored!');
@@ -193,7 +199,7 @@ class CategoryController extends Controller
if (intval(Input::get('return_to_edit')) === 1) { if (intval(Input::get('return_to_edit')) === 1) {
Session::put('categories.edit.fromUpdate', true); Session::put('categories.edit.fromUpdate', true);
return Redirect::route('categories.edit', $category->id); return Redirect::route('categories.edit', [$category->id]);
} }
// redirect to previous URL. // redirect to previous URL.

View File

@@ -0,0 +1,152 @@
<?php
namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
use Preferences;
use Response;
use Session;
use Steam;
/**
* Class AccountController
*
* @package FireflyIII\Http\Controllers\Chart
*/
class AccountController extends Controller
{
/**
* Shows the balances for all the user's accounts.
*
* @param GChart $chart
* @param AccountRepositoryInterface $repository
*
* @param $year
* @param $month
* @param bool $shared
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function all(GChart $chart, AccountRepositoryInterface $repository, $year, $month, $shared = false)
{
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
$chart->addColumn(trans('firefly.dayOfMonth'), 'date');
/** @var Collection $accounts */
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
if ($shared === false) {
/** @var Account $account */
foreach ($accounts as $index => $account) {
if ($account->getMeta('accountRole') == 'sharedAsset') {
$accounts->forget($index);
}
}
}
$index = 1;
/** @var Account $account */
foreach ($accounts as $account) {
$chart->addColumn(trans('firefly.balanceFor', ['name' => $account->name]), 'number');
$chart->addCertainty($index);
$index++;
}
$current = clone $start;
$current->subDay();
$today = Carbon::now();
while ($end >= $current) {
$row = [clone $current];
$certain = $current < $today;
foreach ($accounts as $account) {
$row[] = Steam::balance($account, $current);
$row[] = $certain;
}
$chart->addRowArray($row);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* Shows the balances for all the user's frontpage accounts.
*
* @param GChart $chart
* @param AccountRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function frontpage(GChart $chart, AccountRepositoryInterface $repository)
{
$chart->addColumn(trans('firefly.dayOfMonth'), 'date');
$frontPage = Preferences::get('frontPageAccounts', []);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$accounts = $repository->getFrontpageAccounts($frontPage);
$index = 1;
/** @var Account $account */
foreach ($accounts as $account) {
$chart->addColumn(trans('firefly.balanceFor', ['name' => $account->name]), 'number');
$chart->addCertainty($index);
$index++;
}
$current = clone $start;
$current->subDay();
$today = Carbon::now();
while ($end >= $current) {
$row = [clone $current];
$certain = $current < $today;
foreach ($accounts as $account) {
$row[] = Steam::balance($account, $current);
$row[] = $certain;
}
$chart->addRowArray($row);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* Shows an account's balance for a single month.
*
* @param GChart $chart
* @param Account $account
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function single(GChart $chart, Account $account)
{
$chart->addColumn(trans('firefly.dayOfMonth'), 'date');
$chart->addColumn(trans('firefly.balanceFor', ['name' => $account->name]), 'number');
$chart->addCertainty(1);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$current = clone $start;
$today = new Carbon;
while ($end >= $current) {
$certain = $current < $today;
$chart->addRow(clone $current, Steam::balance($account, $current), $certain);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
}

View File

@@ -0,0 +1,140 @@
<?php
namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
use Response;
use Session;
use Steam;
/**
* Class BillController
*
* @package FireflyIII\Http\Controllers\Chart
*/
class BillController extends Controller
{
/**
* Shows the overview for a bill. The min/max amount and matched journals.
*
* @param GChart $chart
* @param BillRepositoryInterface $repository
* @param Bill $bill
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function single(GChart $chart, BillRepositoryInterface $repository, Bill $bill)
{
$chart->addColumn(trans('firefly.date'), 'date');
$chart->addColumn(trans('firefly.maxAmount'), 'number');
$chart->addColumn(trans('firefly.minAmount'), 'number');
$chart->addColumn(trans('firefly.billEntry'), 'number');
// get first transaction or today for start:
$results = $repository->getJournals($bill);
/** @var TransactionJournal $result */
foreach ($results as $result) {
$chart->addRow(clone $result->date, floatval($bill->amount_max), floatval($bill->amount_min), floatval($result->amount));
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* Shows all bills and whether or not theyve been paid this month (pie chart).
*
* @param GChart $chart
*
* @param BillRepositoryInterface $repository
* @param AccountRepositoryInterface $accounts
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function frontpage(GChart $chart, BillRepositoryInterface $repository, AccountRepositoryInterface $accounts)
{
$chart->addColumn(trans('firefly.name'), 'string');
$chart->addColumn(trans('firefly.amount'), 'number');
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$bills = $repository->getActiveBills();
$paid = new Collection; // journals.
$unpaid = new Collection; // bills
// loop paid and create single entry:
$paidDescriptions = [];
$paidAmount = 0;
$unpaidDescriptions = [];
$unpaidAmount = 0;
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$journals = $repository->getJournalsInRange($bill, $range['start'], $range['end']);
if ($journals->count() == 0) {
$unpaid->push([$bill, $range['start']]);
} else {
$paid = $paid->merge($journals);
}
}
}
$creditCards = $accounts->getCreditCards();
foreach ($creditCards as $creditCard) {
$balance = Steam::balance($creditCard, $end, true);
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
if ($balance < 0) {
// unpaid! create a fake bill that matches the amount.
$description = $creditCard->name;
$amount = $balance * -1;
$fakeBill = $repository->createFakeBill($description, $date, $amount);
unset($description, $amount);
$unpaid->push([$fakeBill, $date]);
}
if ($balance == 0) {
// find transfer(s) TO the credit card which should account for
// anything paid. If not, the CC is not yet used.
$journals = $accounts->getTransfersInRange($creditCard, $start, $end);
$paid = $paid->merge($journals);
}
}
/** @var TransactionJournal $entry */
foreach ($paid as $entry) {
$paidDescriptions[] = $entry->description;
$paidAmount += floatval($entry->amount);
}
// loop unpaid:
/** @var Bill $entry */
foreach ($unpaid as $entry) {
$description = $entry[0]->name . ' (' . $entry[1]->format('jS M Y') . ')';
$amount = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
$unpaidDescriptions[] = $description;
$unpaidAmount += $amount;
unset($amount, $description);
}
$chart->addRow(trans('firefly.unpaid') . ': ' . join(', ', $unpaidDescriptions), $unpaidAmount);
$chart->addRow(trans('firefly.paid') . ': ' . join(', ', $paidDescriptions), $paidAmount);
$chart->generate();
return Response::json($chart->getData());
}
}

View File

@@ -0,0 +1,197 @@
<?php
namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Budget;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
use Navigation;
use Preferences;
use Response;
use Session;
/**
* Class BudgetController
*
* @package FireflyIII\Http\Controllers\Chart
*/
class BudgetController extends Controller
{
/**
* @param GChart $chart
* @param BudgetRepositoryInterface $repository
* @param Budget $budget
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function budget(GChart $chart, BudgetRepositoryInterface $repository, Budget $budget)
{
$chart->addColumn(trans('firefly.period'), 'date');
$chart->addColumn(trans('firefly.spent'), 'number');
$first = $repository->getFirstBudgetLimitDate($budget);
$range = Preferences::get('viewRange', '1M')->data;
$last = Session::get('end', new Carbon);
$final = clone $last;
$final->addYears(2);
$last = Navigation::endOfX($last, $range, $final);
while ($first < $last) {
$end = Navigation::addPeriod($first, $range, 0);
$spent = $repository->spentInPeriodCorrected($budget, $first, $end);
$chart->addRow($end, $spent);
$first = Navigation::addPeriod($first, $range, 0);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* Shows the amount left in a specific budget limit.
*
* @param GChart $chart
* @param BudgetRepositoryInterface $repository
* @param Budget $budget
* @param LimitRepetition $repetition
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function budgetLimit(GChart $chart, BudgetRepositoryInterface $repository, Budget $budget, LimitRepetition $repetition)
{
$start = clone $repetition->startdate;
$end = $repetition->enddate;
$chart->addColumn(trans('firefly.day'), 'date');
$chart->addColumn(trans('firefly.left'), 'number');
$amount = $repetition->amount;
while ($start <= $end) {
/*
* Sum of expenses on this day:
*/
$sum = $repository->expensesOnDayCorrected($budget, $start);
$amount += $sum;
$chart->addRow(clone $start, $amount);
$start->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* Shows a budget list with spent/left/overspent.
*
* @param GChart $chart
* @param BudgetRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function frontpage(GChart $chart, BudgetRepositoryInterface $repository)
{
$chart->addColumn(trans('firefly.budget'), 'string');
$chart->addColumn(trans('firefly.left'), 'number');
$chart->addColumn(trans('firefly.spent'), 'number');
$chart->addColumn(trans('firefly.overspent'), 'number');
$budgets = $repository->getBudgets();
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$allEntries = new Collection;
foreach ($budgets as $budget) {
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
if ($repetitions->count() == 0) {
$expenses = $repository->spentInPeriodCorrected($budget, $start, $end, true);
$allEntries->push([$budget->name, 0, 0, $expenses]);
continue;
}
/** @var LimitRepetition $repetition */
foreach ($repetitions as $repetition) {
$expenses = $repository->spentInPeriodCorrected($budget, $repetition->startdate, $repetition->enddate, true);
$left = $expenses < floatval($repetition->amount) ? floatval($repetition->amount) - $expenses : 0;
$spent = $expenses > floatval($repetition->amount) ? floatval($repetition->amount) : $expenses;
$overspent = $expenses > floatval($repetition->amount) ? $expenses - floatval($repetition->amount) : 0;
$allEntries->push(
[$budget->name . ' (' . $repetition->startdate->formatLocalized($this->monthAndDayFormat) . ')',
$left,
$spent,
$overspent
]
);
}
}
$noBudgetExpenses = $repository->getWithoutBudgetSum($start, $end) * -1;
$allEntries->push([trans('firefly.noBudget'), 0, 0, $noBudgetExpenses]);
foreach ($allEntries as $entry) {
if ($entry[1] != 0 || $entry[2] != 0 || $entry[3] != 0) {
$chart->addRow($entry[0], $entry[1], $entry[2], $entry[3]);
}
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* Show a yearly overview for a budget.
*
* @param GChart $chart
* @param BudgetRepositoryInterface $repository
* @param $year
* @param bool $shared
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function year(GChart $chart, BudgetRepositoryInterface $repository, $year, $shared = false)
{
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
$shared = $shared == 'shared' ? true : false;
$budgets = $repository->getBudgets();
// add columns:
$chart->addColumn(trans('firefly.month'), 'date');
foreach ($budgets as $budget) {
$chart->addColumn($budget->name, 'number');
}
while ($start < $end) {
// month is the current end of the period:
$month = clone $start;
$month->endOfMonth();
// make a row:
$row = [clone $start];
// each budget, fill the row:
foreach ($budgets as $budget) {
$spent = $repository->spentInPeriodCorrected($budget, $start, $month, $shared);
$row[] = $spent;
}
$chart->addRowArray($row);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
}

View File

@@ -0,0 +1,178 @@
<?php
namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use Grumpydictator\Gchart\GChart;
use Navigation;
use Preferences;
use Response;
use Session;
/**
* Class CategoryController
*
* @package FireflyIII\Http\Controllers\Chart
*/
class CategoryController extends Controller
{
/**
* Show an overview for a category for all time, per month/week/year.
*
* @param GChart $chart
* @param CategoryRepositoryInterface $repository
* @param Category $category
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function all(GChart $chart, CategoryRepositoryInterface $repository, Category $category)
{
// oldest transaction in category:
$start = $repository->getFirstActivityDate($category);
$range = Preferences::get('viewRange', '1M')->data;
// jump to start of week / month / year / etc
$start = Navigation::startOfPeriod($start, $range);
$chart->addColumn(trans('firefly.period'), 'date');
$chart->addColumn(trans('firefly.spent'), 'number');
$end = new Carbon;
while ($start <= $end) {
$currentEnd = Navigation::endOfPeriod($start, $range);
$spent = $repository->spentInPeriodCorrected($category, $start, $currentEnd);
$chart->addRow(clone $start, $spent);
$start = Navigation::addPeriod($start, $range, 0);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* Show this month's category overview.
*
* @param GChart $chart
* @param CategoryRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function frontpage(GChart $chart, CategoryRepositoryInterface $repository)
{
$chart->addColumn(trans('firefly.category'), 'string');
$chart->addColumn(trans('firefly.spent'), 'number');
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$set = $repository->getCategoriesAndExpensesCorrected($start, $end);
// sort by callback:
uasort(
$set,
function($left, $right) {
if ($left['sum'] == $right['sum']) {
return 0;
}
return ($left['sum'] < $right['sum']) ? 1 : -1;
}
);
foreach ($set as $entry) {
$sum = floatval($entry['sum']);
if ($sum != 0) {
$chart->addRow($entry['name'], $sum);
}
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param CategoryRepositoryInterface $repository
* @param Category $category
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function month(GChart $chart, CategoryRepositoryInterface $repository, Category $category)
{
$start = clone Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$chart->addColumn(trans('firefly.period'), 'date');
$chart->addColumn(trans('firefly.spent'), 'number');
while ($start <= $end) {
$spent = $repository->spentOnDaySumCorrected($category, $start);
$chart->addRow(clone $start, $spent);
$start->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* This chart will only show expenses.
*
* @param GChart $chart
* @param CategoryRepositoryInterface $repository
* @param $year
* @param bool $shared
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function year(GChart $chart, CategoryRepositoryInterface $repository, $year, $shared = false)
{
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
$shared = $shared == 'shared' ? true : false;
$categories = $repository->getCategories();
// add columns:
$chart->addColumn(trans('firefly.month'), 'date');
foreach ($categories as $category) {
$chart->addColumn($category->name, 'number');
}
while ($start < $end) {
// month is the current end of the period:
$month = clone $start;
$month->endOfMonth();
// make a row:
$row = [clone $start];
// each budget, fill the row:
foreach ($categories as $category) {
$spent = $repository->spentInPeriodCorrected($category, $start, $month, $shared);
$row[] = $spent;
}
$chart->addRowArray($row);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
use Response;
/**
* Class PiggyBankController
*
* @package FireflyIII\Http\Controllers\Chart
*/
class PiggyBankController extends Controller
{
/**
* Shows the piggy bank history.
*
* @param GChart $chart
* @param PiggyBankRepositoryInterface $repository
* @param PiggyBank $piggyBank
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function history(GChart $chart, PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
{
$chart->addColumn(trans('firefly.date'), 'date');
$chart->addColumn(trans('firefly.balance'), 'number');
/** @var Collection $set */
$set = $repository->getEventSummarySet($piggyBank);
$sum = 0;
foreach ($set as $entry) {
$sum += floatval($entry->sum);
$chart->addRow(new Carbon($entry->date), $sum);
}
$chart->generate();
return Response::json($chart->getData());
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Http\Controllers\Controller;
use Grumpydictator\Gchart\GChart;
use Response;
/**
* Class ReportController
*
* @package FireflyIII\Http\Controllers\Chart
*/
class ReportController extends Controller
{
/**
* Summarizes all income and expenses, per month, for a given year.
*
* @param GChart $chart
* @param ReportQueryInterface $query
* @param $year
* @param bool $shared
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function yearInOut(GChart $chart, ReportQueryInterface $query, $year, $shared = false)
{
// get start and end of year
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
$shared = $shared == 'shared' ? true : false;
$chart->addColumn(trans('firefly.month'), 'date');
$chart->addColumn(trans('firefly.income'), 'number');
$chart->addColumn(trans('firefly.expenses'), 'number');
while ($start < $end) {
$month = clone $start;
$month->endOfMonth();
// total income and total expenses:
$incomeSum = floatval($query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount'));
$expenseSum = floatval($query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount'));
$chart->addRow(clone $start, $incomeSum, $expenseSum);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* Summarizes all income and expenses for a given year. Gives a total and an average.
*
* @param GChart $chart
* @param ReportQueryInterface $query
* @param $year
* @param bool $shared
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function yearInOutSummarized(GChart $chart, ReportQueryInterface $query, $year, $shared = false)
{
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
$shared = $shared == 'shared' ? true : false;
$income = 0;
$expense = 0;
$count = 0;
$chart->addColumn(trans('firefly.summary'), 'string');
$chart->addColumn(trans('firefly.income'), 'number');
$chart->addColumn(trans('firefly.expenses'), 'number');
while ($start < $end) {
$month = clone $start;
$month->endOfMonth();
// total income and total expenses:
$income += floatval($query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount'));
$expense += floatval($query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount'));
$count++;
$start->addMonth();
}
// add total + average:
$chart->addRow(trans('firefly.sum'), $income, $expense);
$count = $count > 0 ? $count : 1;
$chart->addRow(trans('firefly.average'), ($income / $count), ($expense / $count));
$chart->generate();
return Response::json($chart->getData());
}
}

View File

@@ -1,8 +1,11 @@
<?php namespace FireflyIII\Http\Controllers; <?php namespace FireflyIII\Http\Controllers;
use Auth;
use Config;
use Illuminate\Foundation\Bus\DispatchesCommands; use Illuminate\Foundation\Bus\DispatchesCommands;
use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController; use Illuminate\Routing\Controller as BaseController;
use Preferences;
use View; use View;
/** /**
@@ -15,8 +18,13 @@ abstract class Controller extends BaseController
use DispatchesCommands, ValidatesRequests; use DispatchesCommands, ValidatesRequests;
/** @var string */
protected $monthAndDayFormat;
/** @var string */
protected $monthFormat;
/** /**
* * @codeCoverageIgnore
*/ */
public function __construct() public function __construct()
{ {
@@ -24,5 +32,16 @@ abstract class Controller extends BaseController
View::share('hideCategories', false); View::share('hideCategories', false);
View::share('hideBills', false); View::share('hideBills', false);
View::share('hideTags', false); View::share('hideTags', false);
if (Auth::check()) {
$pref = Preferences::get('language', 'en');
$lang = $pref->data;
$this->monthFormat = Config::get('firefly.month.' . $lang);
$this->monthAndDayFormat = Config::get('firefly.monthAndDay.' . $lang);
View::share('monthFormat', $this->monthFormat);
View::share('monthAndDayFormat', $this->monthAndDayFormat);
View::share('language', $lang);
}
} }
} }

View File

@@ -1,9 +1,8 @@
<?php namespace FireflyIII\Http\Controllers; <?php namespace FireflyIII\Http\Controllers;
use Auth;
use Cache; use Cache;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\CurrencyFormRequest; use FireflyIII\Http\Requests\CurrencyFormRequest;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use Input; use Input;
@@ -23,12 +22,12 @@ class CurrencyController extends Controller
/** /**
* * @codeCoverageIgnore
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
View::share('title', 'Currencies'); View::share('title', trans('firefly.currencies'));
View::share('mainTitleIcon', 'fa-usd'); View::share('mainTitleIcon', 'fa-usd');
} }
@@ -45,6 +44,8 @@ class CurrencyController extends Controller
Session::put('currency.create.url', URL::previous()); Session::put('currency.create.url', URL::previous());
} }
Session::forget('currency.create.fromStore'); Session::forget('currency.create.fromStore');
Session::flash('gaEventCategory', 'currency');
Session::flash('gaEventAction', 'create');
return view('currency.create', compact('subTitleIcon', 'subTitle')); return view('currency.create', compact('subTitleIcon', 'subTitle'));
} }
@@ -84,6 +85,8 @@ class CurrencyController extends Controller
// put previous url in session // put previous url in session
Session::put('currency.delete.url', URL::previous()); Session::put('currency.delete.url', URL::previous());
Session::flash('gaEventCategory', 'currency');
Session::flash('gaEventAction', 'delete');
return view('currency.delete', compact('currency')); return view('currency.delete', compact('currency'));
@@ -105,8 +108,9 @@ class CurrencyController extends Controller
} }
Session::flash('success', 'Currency "' . e($currency->name) . '" deleted'); Session::flash('success', 'Currency "' . e($currency->name) . '" deleted');
if (Auth::user()->hasRole('owner')) {
$currency->delete(); $currency->delete();
}
return Redirect::to(Session::get('currency.delete.url')); return Redirect::to(Session::get('currency.delete.url'));
} }
@@ -127,6 +131,8 @@ class CurrencyController extends Controller
Session::put('currency.edit.url', URL::previous()); Session::put('currency.edit.url', URL::previous());
} }
Session::forget('currency.edit.fromUpdate'); Session::forget('currency.edit.fromUpdate');
Session::flash('gaEventCategory', 'currency');
Session::flash('gaEventAction', 'edit');
return view('currency.edit', compact('currency', 'subTitle', 'subTitleIcon')); return view('currency.edit', compact('currency', 'subTitle', 'subTitleIcon'));
@@ -142,6 +148,12 @@ class CurrencyController extends Controller
$currencies = $repository->get(); $currencies = $repository->get();
$defaultCurrency = $repository->getCurrencyByPreference(Preferences::get('currencyPreference', 'EUR')); $defaultCurrency = $repository->getCurrencyByPreference(Preferences::get('currencyPreference', 'EUR'));
if (!Auth::user()->hasRole('owner')) {
Session::flash('warning', 'Please ask ' . env('SITE_OWNER') . ' to add, remove or edit currencies.');
}
return view('currency.index', compact('currencies', 'defaultCurrency')); return view('currency.index', compact('currencies', 'defaultCurrency'));
} }
@@ -154,11 +166,11 @@ class CurrencyController extends Controller
*/ */
public function store(CurrencyFormRequest $request, CurrencyRepositoryInterface $repository) public function store(CurrencyFormRequest $request, CurrencyRepositoryInterface $repository)
{ {
$data = $request->getCurrencyData(); $data = $request->getCurrencyData();
$currency = $repository->store($data); if (Auth::user()->hasRole('owner')) {
$currency = $repository->store($data);
Session::flash('success', 'Currency "' . $currency->name . '" created');
Session::flash('success', 'Currency "' . $currency->name . '" created'); }
if (intval(Input::get('create_another')) === 1) { if (intval(Input::get('create_another')) === 1) {
Session::put('currency.create.fromStore', true); Session::put('currency.create.fromStore', true);
@@ -181,16 +193,17 @@ class CurrencyController extends Controller
*/ */
public function update(CurrencyFormRequest $request, CurrencyRepositoryInterface $repository, TransactionCurrency $currency) public function update(CurrencyFormRequest $request, CurrencyRepositoryInterface $repository, TransactionCurrency $currency)
{ {
$data = $request->getCurrencyData(); $data = $request->getCurrencyData();
$currency = $repository->update($currency, $data); if (Auth::user()->hasRole('owner')) {
$currency = $repository->update($currency, $data);
}
Session::flash('success', 'Currency "' . e($currency->name) . '" updated.'); Session::flash('success', 'Currency "' . e($currency->name) . '" updated.');
if (intval(Input::get('return_to_edit')) === 1) { if (intval(Input::get('return_to_edit')) === 1) {
Session::put('currency.edit.fromUpdate', true); Session::put('currency.edit.fromUpdate', true);
return Redirect::route('currency.edit', $currency->id); return Redirect::route('currency.edit', [$currency->id]);
} }
// redirect to previous URL. // redirect to previous URL.

View File

@@ -1,590 +0,0 @@
<?php namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use Crypt;
use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Transaction;
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\PiggyBank\PiggyBankRepositoryInterface;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
use Navigation;
use Preferences;
use Response;
use Session;
use Steam;
/**
* Class GoogleChartController
*
* @package FireflyIII\Http\Controllers
*/
class GoogleChartController extends Controller
{
/**
* @param GChart $chart
* @param Account $account
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function accountBalanceChart(GChart $chart, Account $account)
{
$chart->addColumn('Day of month', 'date');
$chart->addColumn('Balance for ' . $account->name, 'number');
$chart->addCertainty(1);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$current = clone $start;
$today = new Carbon;
while ($end >= $current) {
$certain = $current < $today;
$chart->addRow(clone $current, Steam::balance($account, $current), $certain);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param AccountRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function allAccountsBalanceChart(GChart $chart, AccountRepositoryInterface $repository)
{
$chart->addColumn('Day of the month', 'date');
$frontPage = Preferences::get('frontPageAccounts', []);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$accounts = $repository->getFrontpageAccounts($frontPage);
$index = 1;
/** @var Account $account */
foreach ($accounts as $account) {
$chart->addColumn('Balance for ' . $account->name, 'number');
$chart->addCertainty($index);
$index++;
}
$current = clone $start;
$current->subDay();
$today = Carbon::now();
while ($end >= $current) {
$row = [clone $current];
$certain = $current < $today;
foreach ($accounts as $account) {
$row[] = Steam::balance($account, $current);
$row[] = $certain;
}
$chart->addRowArray($row);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param BudgetRepositoryInterface $repository
* @param $year
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function allBudgetsAndSpending(GChart $chart, BudgetRepositoryInterface $repository, $year)
{
$budgets = $repository->getBudgets();
$chart->addColumn('Month', 'date');
foreach ($budgets as $budget) {
$chart->addColumn($budget->name, 'number');
}
$start = Carbon::createFromDate(intval($year), 1, 1);
$end = clone $start;
$end->endOfYear();
while ($start <= $end) {
$row = [clone $start];
foreach ($budgets as $budget) {
$spent = $repository->spentInMonth($budget, $start);
$row[] = $spent;
}
$chart->addRowArray($row);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param BudgetRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function allBudgetsHomeChart(GChart $chart, BudgetRepositoryInterface $repository)
{
$chart->addColumn('Budget', 'string');
$chart->addColumn('Left', 'number');
$chart->addColumn('Spent', 'number');
$chart->addColumn('Overspent', 'number');
$budgets = $repository->getBudgets();
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$allEntries = new Collection;
foreach ($budgets as $budget) {
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
if ($repetitions->count() == 0) {
$expenses = $repository->sumBudgetExpensesInPeriod($budget, $start, $end);
$allEntries->push([$budget->name, 0, 0, $expenses]);
continue;
}
/** @var LimitRepetition $repetition */
foreach ($repetitions as $repetition) {
$expenses = $repository->sumBudgetExpensesInPeriod($budget, $repetition->startdate, $repetition->enddate);
$left = $expenses < floatval($repetition->amount) ? floatval($repetition->amount) - $expenses : 0;
$spent = $expenses > floatval($repetition->amount) ? 0 : $expenses;
$overspent = $expenses > floatval($repetition->amount) ? $expenses - floatval($repetition->amount) : 0;
$allEntries->push(
[$budget->name . ' (' . $repetition->startdate->format('j M Y') . ')',
$left,
$spent,
$overspent
]
);
}
}
$noBudgetExpenses = $repository->getWithoutBudgetSum($start, $end);
$allEntries->push(['(no budget)', 0, 0, $noBudgetExpenses]);
foreach ($allEntries as $entry) {
if ($entry[1] != 0 || $entry[2] != 0 || $entry[3] != 0) {
$chart->addRow($entry[0], $entry[1], $entry[2], $entry[3]);
}
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param CategoryRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function allCategoriesHomeChart(GChart $chart, CategoryRepositoryInterface $repository)
{
$chart->addColumn('Category', 'string');
$chart->addColumn('Spent', 'number');
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$set = $repository->getCategoriesAndExpenses($start, $end);
foreach ($set as $entry) {
$isEncrypted = intval($entry->encrypted) == 1 ? true : false;
$name = strlen($entry->name) == 0 ? '(no category)' : $entry->name;
$name = $isEncrypted ? Crypt::decrypt($name) : $name;
$chart->addRow($name, floatval($entry->sum));
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param BillRepositoryInterface $repository
* @param Bill $bill
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function billOverview(GChart $chart, BillRepositoryInterface $repository, Bill $bill)
{
$chart->addColumn('Date', 'date');
$chart->addColumn('Max amount', 'number');
$chart->addColumn('Min amount', 'number');
$chart->addColumn('Recorded bill entry', 'number');
// get first transaction or today for start:
$results = $repository->getJournals($bill);
/** @var TransactionJournal $result */
foreach ($results as $result) {
$chart->addRow(clone $result->date, floatval($bill->amount_max), floatval($bill->amount_min), floatval($result->amount));
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
*
* @param BillRepositoryInterface $repository
* @param AccountRepositoryInterface $accounts
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function billsOverview(GChart $chart, BillRepositoryInterface $repository, AccountRepositoryInterface $accounts)
{
$chart->addColumn('Name', 'string');
$chart->addColumn('Amount', 'number');
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$bills = $repository->getActiveBills();
$paid = new Collection; // journals.
$unpaid = new Collection; // bills
// loop paid and create single entry:
$paidDescriptions = [];
$paidAmount = 0;
$unpaidDescriptions = [];
$unpaidAmount = 0;
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$journals = $repository->getJournalsInRange($bill, $range['start'], $range['end']);
if ($journals->count() == 0) {
$unpaid->push([$bill, $range['start']]);
} else {
$paid = $paid->merge($journals);
}
}
}
$creditCards = $accounts->getCreditCards();
foreach ($creditCards as $creditCard) {
$balance = Steam::balance($creditCard, null, true);
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
if ($balance < 0) {
// unpaid! create a fake bill that matches the amount.
$description = $creditCard->name;
$amount = $balance * -1;
$fakeBill = $repository->createFakeBill($description, $date, $amount);
unset($description, $amount);
$unpaid->push([$fakeBill, $date]);
}
if ($balance == 0) {
// find transfer(s) TO the credit card which should account for
// anything paid. If not, the CC is not yet used.
$journals = $accounts->getTransfersInRange($creditCard, $start, $end);
$paid = $paid->merge($journals);
}
}
/** @var TransactionJournal $entry */
foreach ($paid as $entry) {
$paidDescriptions[] = $entry->description;
$paidAmount += floatval($entry->amount);
}
// loop unpaid:
/** @var Bill $entry */
foreach ($unpaid as $entry) {
$description = $entry[0]->name . ' (' . $entry[1]->format('jS M Y') . ')';
$amount = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
$unpaidDescriptions[] = $description;
$unpaidAmount += $amount;
unset($amount, $description);
}
$chart->addRow('Unpaid: ' . join(', ', $unpaidDescriptions), $unpaidAmount);
$chart->addRow('Paid: ' . join(', ', $paidDescriptions), $paidAmount);
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param BudgetRepositoryInterface $repository
* @param Budget $budget
* @param LimitRepetition $repetition
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function budgetLimitSpending(GChart $chart, BudgetRepositoryInterface $repository, Budget $budget, LimitRepetition $repetition)
{
$start = clone $repetition->startdate;
$end = $repetition->enddate;
$chart->addColumn('Day', 'date');
$chart->addColumn('Left', 'number');
$amount = $repetition->amount;
while ($start <= $end) {
/*
* Sum of expenses on this day:
*/
$sum = $repository->expensesOnDay($budget, $start);
$amount += $sum;
$chart->addRow(clone $start, $amount);
$start->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param BudgetRepositoryInterface $repository
* @param Budget $budget
* @param int $year
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function budgetsAndSpending(GChart $chart, BudgetRepositoryInterface $repository, Budget $budget, $year = 0)
{
$chart->addColumn('Month', 'date');
$chart->addColumn('Budgeted', 'number');
$chart->addColumn('Spent', 'number');
if ($year == 0) {
$start = $repository->getFirstBudgetLimitDate($budget);
$end = $repository->getLastBudgetLimitDate($budget);
} else {
$start = Carbon::createFromDate(intval($year), 1, 1);
$end = clone $start;
$end->endOfYear();
}
while ($start <= $end) {
$spent = $repository->spentInMonth($budget, $start);
$budgeted = $repository->getLimitAmountOnDate($budget, $start);
$chart->addRow(clone $start, $budgeted, $spent);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param CategoryRepositoryInterface $repository
* @param Category $category
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function categoryOverviewChart(GChart $chart, CategoryRepositoryInterface $repository, Category $category)
{
// oldest transaction in category:
$start = $repository->getFirstActivityDate($category);
/** @var Preference $range */
$range = Preferences::get('viewRange', '1M');
// jump to start of week / month / year / etc (TODO).
$start = Navigation::startOfPeriod($start, $range->data);
$chart->addColumn('Period', 'date');
$chart->addColumn('Spent', 'number');
$end = new Carbon;
while ($start <= $end) {
$currentEnd = Navigation::endOfPeriod($start, $range->data);
$spent = $repository->spentInPeriodSum($category, $start, $currentEnd);
$chart->addRow(clone $start, $spent);
$start = Navigation::addPeriod($start, $range->data, 0);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param CategoryRepositoryInterface $repository
* @param Category $category
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function categoryPeriodChart(GChart $chart, CategoryRepositoryInterface $repository, Category $category)
{
$start = clone Session::get('start', Carbon::now()->startOfMonth());
$chart->addColumn('Period', 'date');
$chart->addColumn('Spent', 'number');
$end = Session::get('end', Carbon::now()->endOfMonth());
while ($start <= $end) {
$spent = $repository->spentOnDaySum($category, $start);
$chart->addRow(clone $start, $spent);
$start->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param PiggyBankRepositoryInterface $repository
* @param PiggyBank $piggyBank
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function piggyBankHistory(GChart $chart, PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
{
$chart->addColumn('Date', 'date');
$chart->addColumn('Balance', 'number');
/** @var Collection $set */
$set = $repository->getEventSummarySet($piggyBank);
$sum = 0;
foreach ($set as $entry) {
$sum += floatval($entry->sum);
$chart->addRow(new Carbon($entry->date), $sum);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param ReportQueryInterface $query
* @param $year
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function yearInExp(GChart $chart, ReportQueryInterface $query, $year)
{
$start = new Carbon('01-01-' . $year);
$chart->addColumn('Month', 'date');
$chart->addColumn('Income', 'number');
$chart->addColumn('Expenses', 'number');
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
// get report query interface.
$end = clone $start;
$end->endOfYear();
while ($start < $end) {
$currentEnd = clone $start;
$currentEnd->endOfMonth();
// total income && total expenses:
$incomeSum = floatval($query->incomeByPeriod($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
$expenseSum = floatval($query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
$chart->addRow(clone $start, $incomeSum, $expenseSum);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
* @param ReportQueryInterface $query
* @param $year
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function yearInExpSum(GChart $chart, ReportQueryInterface $query, $year)
{
$start = new Carbon('01-01-' . $year);
$chart->addColumn('Summary', 'string');
$chart->addColumn('Income', 'number');
$chart->addColumn('Expenses', 'number');
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
$income = 0;
$expense = 0;
$count = 0;
$end = clone $start;
$end->endOfYear();
while ($start < $end) {
$currentEnd = clone $start;
$currentEnd->endOfMonth();
// total income:
$incomeSum = floatval($query->incomeByPeriod($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
// total expenses:
$expenseSum = floatval($query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports)->sum('queryAmount'));
$income += $incomeSum;
$expense += $expenseSum;
$count++;
$start->addMonth();
}
$chart->addRow('Sum', $income, $expense);
$count = $count > 0 ? $count : 1;
$chart->addRow('Average', ($income / $count), ($expense / $count));
$chart->generate();
return Response::json($chart->getData());
}
}

View File

@@ -6,6 +6,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Input; use Input;
use Preferences; use Preferences;
use Redirect; use Redirect;
use Route;
use Session; use Session;
use Steam; use Steam;
@@ -53,7 +54,7 @@ class HomeController extends Controller
$types = Config::get('firefly.accountTypesByIdentifier.asset'); $types = Config::get('firefly.accountTypesByIdentifier.asset');
$count = $repository->countAccounts($types); $count = $repository->countAccounts($types);
$title = 'Firefly'; $title = 'Firefly';
$subTitle = 'What\'s playing?'; $subTitle = trans('firefly.welcomeBack');
$mainTitleIcon = 'fa-fire'; $mainTitleIcon = 'fa-fire';
$transactions = []; $transactions = [];
$frontPage = Preferences::get('frontPageAccounts', []); $frontPage = Preferences::get('frontPageAccounts', []);
@@ -63,19 +64,17 @@ class HomeController extends Controller
$savings = $repository->getSavingsAccounts(); $savings = $repository->getSavingsAccounts();
$piggyBankAccounts = $repository->getPiggyBankAccounts(); $piggyBankAccounts = $repository->getPiggyBankAccounts();
$savingsTotal = 0; $savingsTotal = 0;
foreach ($savings as $savingAccount) { foreach ($savings as $savingAccount) {
$savingsTotal += Steam::balance($savingAccount, $end); $savingsTotal += Steam::balance($savingAccount, $end);
} }
// check if all books are correct.
$sum = $repository->sumOfEverything(); $sum = $repository->sumOfEverything();
if ($sum != 0) { if ($sum != 0) {
Session::flash( Session::flash(
'error', 'Your transactions are unbalanced. This means a' 'error', 'Your transactions are unbalanced. This means a'
. ' withdrawal, deposit or transfer was not stored properly. ' . ' withdrawal, deposit or transfer was not stored properly. '
. 'Please check your accounts and transactions for errors.' . 'Please check your accounts and transactions for errors.'
); );
} }
@@ -89,5 +88,78 @@ class HomeController extends Controller
return view('index', compact('count', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions', 'savingsTotal', 'piggyBankAccounts')); return view('index', compact('count', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions', 'savingsTotal', 'piggyBankAccounts'));
} }
/**
* @codeCoverageIgnore
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function routes()
{
$directory = '/vagrant_data/Sites/firefly-iii-help';
$languages = array_keys(Config::get('firefly.lang'));
$routes = [];
$ignored = [
'debugbar.openhandler', 'debugbar.assets.css', 'debugbar.assets.js', 'register', 'routes', 'daterange',
'flush', 'delete-account-post', 'change-password-post', 'logout', 'login', 'tags.hideTagHelp',
'budgets.postIncome', 'flush'
];
$ignoreMatch = ['.store', '.update', '.destroy', 'json.'];
$routeCollection = Route::getRoutes();
/** @var \Illuminate\Routing\Route $object */
foreach ($routeCollection as $object) {
// get name:
$name = $object->getName();
// has name and not in ignore list?
if (strlen($name) > 0 && !in_array($name, $ignored)) {
// not in ignoreMatch?
$continue = true;
foreach ($ignoreMatch as $ignore) {
$match = strpos($name, $ignore);
if (!($match === false)) {
$continue = false;
}
}
unset($ignore, $match);
if ($continue) {
$routes[] = $name;
// check all languages:
foreach ($languages as $lang) {
$file = $directory . '/' . $lang . '/' . $name . '.md';
if (!file_exists($file)) {
touch($file);
echo $name . '<br />';
}
}
}
}
}
// loop directories with language file.
// tag the ones not in the list of approved routes.
foreach ($languages as $lang) {
$dir = $directory . '/' . $lang;
$set = scandir($dir);
foreach ($set as $entry) {
if ($entry != '.' && $entry != '..') {
$name = str_replace('.md', '', $entry);
if (!in_array($name, $routes)) {
$file = $dir . '/' . $entry;
unlink($file);
}
}
}
}
echo 'Done!';
}
} }

View File

@@ -5,14 +5,12 @@ use Carbon\Carbon;
use FireflyIII\Helpers\Report\ReportQueryInterface; use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Preferences;
use Response; use Response;
use Session; use Session;
use Steam; use Steam;
@@ -39,19 +37,14 @@ class JsonController extends Controller
$end = Session::get('end', Carbon::now()->endOfMonth()); $end = Session::get('end', Carbon::now()->endOfMonth());
$amount = 0; $amount = 0;
// these two functions are the same as the chart TODO // these two functions are the same as the chart
$bills = $repository->getActiveBills(); $bills = $repository->getActiveBills();
/** @var Bill $bill */ /** @var Bill $bill */
foreach ($bills as $bill) { foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end); $amount += $repository->billPaymentsInRange($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$amount += $repository->getJournalsInRange($bill, $range['start'], $range['end'])->sum('amount');
}
} }
unset($ranges, $bill, $range, $bills); unset($bill, $bills);
/** /**
* Find credit card accounts and possibly unpaid credit card bills. * Find credit card accounts and possibly unpaid credit card bills.
@@ -60,7 +53,7 @@ class JsonController extends Controller
// if the balance is not zero, the monthly payment is still underway. // if the balance is not zero, the monthly payment is still underway.
/** @var Account $creditCard */ /** @var Account $creditCard */
foreach ($creditCards as $creditCard) { foreach ($creditCards as $creditCard) {
$balance = Steam::balance($creditCard, null, true); $balance = Steam::balance($creditCard, $end, true);
if ($balance == 0) { if ($balance == 0) {
// find a transfer TO the credit card which should account for // find a transfer TO the credit card which should account for
// anything paid. If not, the CC is not yet used. // anything paid. If not, the CC is not yet used.
@@ -100,7 +93,7 @@ class JsonController extends Controller
$creditCards = $accountRepository->getCreditCards(); $creditCards = $accountRepository->getCreditCards();
foreach ($creditCards as $creditCard) { foreach ($creditCards as $creditCard) {
$balance = Steam::balance($creditCard, null, true); $balance = Steam::balance($creditCard, $end, true);
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate')); $date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
if ($balance < 0) { if ($balance < 0) {
// unpaid! create a fake bill that matches the amount. // unpaid! create a fake bill that matches the amount.
@@ -128,7 +121,7 @@ class JsonController extends Controller
{ {
$start = Session::get('start', Carbon::now()->startOfMonth()); $start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth()); $end = Session::get('end', Carbon::now()->endOfMonth());
$amount = $reportQuery->incomeByPeriod($start, $end, true)->sum('queryAmount'); $amount = $reportQuery->incomeInPeriodCorrected($start, $end, true)->sum('amount');
return Response::json(['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]); return Response::json(['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
} }
@@ -142,7 +135,7 @@ class JsonController extends Controller
{ {
$start = Session::get('start', Carbon::now()->startOfMonth()); $start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth()); $end = Session::get('end', Carbon::now()->endOfMonth());
$amount = $reportQuery->journalsByExpenseAccount($start, $end, true)->sum('queryAmount'); $amount = $reportQuery->expenseInPeriodCorrected($start, $end, true)->sum('amount');
return Response::json(['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]); return Response::json(['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
} }
@@ -202,30 +195,6 @@ class JsonController extends Controller
} }
/**
* @return \Symfony\Component\HttpFoundation\Response
*/
public function setSharedReports()
{
/** @var Preference $pref */
$pref = Preferences::get('showSharedReports', false);
$new = !$pref->data;
Preferences::set('showSharedReports', $new);
return Response::json(['value' => $new]);
}
/**
* @return \Symfony\Component\HttpFoundation\Response
*/
public function showSharedReports()
{
$pref = Preferences::get('showSharedReports', false);
return Response::json(['value' => $pref->data]);
}
/** /**
* Returns a JSON list of all beneficiaries. * Returns a JSON list of all beneficiaries.
* *

View File

@@ -4,7 +4,6 @@ use Amount;
use Carbon\Carbon; use Carbon\Carbon;
use Config; use Config;
use ExpandedForm; use ExpandedForm;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\PiggyBankFormRequest; use FireflyIII\Http\Requests\PiggyBankFormRequest;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -18,6 +17,9 @@ use URL;
use View; use View;
/** /**
*
* @SuppressWarnings(PHPMD.TooManyMethods)
*
* Class PiggyBankController * Class PiggyBankController
* *
* @package FireflyIII\Http\Controllers * @package FireflyIII\Http\Controllers
@@ -26,12 +28,12 @@ class PiggyBankController extends Controller
{ {
/** /**
* * @codeCoverageIgnore
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
View::share('title', 'Piggy banks'); View::share('title', trans('firefly.piggyBanks'));
View::share('mainTitleIcon', 'fa-sort-amount-asc'); View::share('mainTitleIcon', 'fa-sort-amount-asc');
} }
@@ -45,7 +47,8 @@ class PiggyBankController extends Controller
*/ */
public function add(AccountRepositoryInterface $repository, PiggyBank $piggyBank) public function add(AccountRepositoryInterface $repository, PiggyBank $piggyBank)
{ {
$leftOnAccount = $repository->leftOnAccount($piggyBank->account); $date = Session::get('end', Carbon::now()->endOfMonth());
$leftOnAccount = $repository->leftOnAccount($piggyBank->account, $date);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount; $savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = $piggyBank->targetamount - $savedSoFar; $leftToSave = $piggyBank->targetamount - $savedSoFar;
$maxAmount = min($leftOnAccount, $leftToSave); $maxAmount = min($leftOnAccount, $leftToSave);
@@ -71,6 +74,8 @@ class PiggyBankController extends Controller
Session::put('piggy-banks.create.url', URL::previous()); Session::put('piggy-banks.create.url', URL::previous());
} }
Session::forget('piggy-banks.create.fromStore'); Session::forget('piggy-banks.create.fromStore');
Session::flash('gaEventCategory', 'piggy-banks');
Session::flash('gaEventAction', 'create');
return view('piggy-banks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon')); return view('piggy-banks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon'));
} }
@@ -82,10 +87,12 @@ class PiggyBankController extends Controller
*/ */
public function delete(PiggyBank $piggyBank) public function delete(PiggyBank $piggyBank)
{ {
$subTitle = 'Delete "' . e($piggyBank->name) . '"'; $subTitle = trans('firefly.delete_piggy_bank', ['name' => $piggyBank->name]);
// put previous url in session // put previous url in session
Session::put('piggy-banks.delete.url', URL::previous()); Session::put('piggy-banks.delete.url', URL::previous());
Session::flash('gaEventCategory', 'piggy-banks');
Session::flash('gaEventAction', 'delete');
return view('piggy-banks.delete', compact('piggyBank', 'subTitle')); return view('piggy-banks.delete', compact('piggyBank', 'subTitle'));
} }
@@ -117,7 +124,7 @@ class PiggyBankController extends Controller
$periods = Config::get('firefly.piggy_bank_periods'); $periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account'])); $accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
$subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"'; $subTitle = trans('firefly.update_piggy_title', ['name' => $piggyBank->name]);
$subTitleIcon = 'fa-pencil'; $subTitleIcon = 'fa-pencil';
/* /*
@@ -130,13 +137,15 @@ class PiggyBankController extends Controller
$targetDate = $targetDate->format('Y-m-d'); $targetDate = $targetDate->format('Y-m-d');
} }
$preFilled = ['name' => $piggyBank->name, $preFilled = ['name' => $piggyBank->name,
'account_id' => $piggyBank->account_id, 'account_id' => $piggyBank->account_id,
'targetamount' => $piggyBank->targetamount, 'targetamount' => $piggyBank->targetamount,
'targetdate' => $targetDate, 'targetdate' => $targetDate,
'reminder' => $piggyBank->reminder, 'reminder' => $piggyBank->reminder,
'remind_me' => intval($piggyBank->remind_me) == 1 && !is_null($piggyBank->reminder) ? true : false 'remind_me' => intval($piggyBank->remind_me) == 1 && !is_null($piggyBank->reminder) ? true : false
]; ];
Session::flash('preFilled', $preFilled); Session::flash('preFilled', $preFilled);
Session::flash('gaEventCategory', 'piggy-banks');
Session::flash('gaEventAction', 'edit');
// put previous url in session if not redirect from store (not "return_to_edit"). // put previous url in session if not redirect from store (not "return_to_edit").
if (Session::get('piggy-banks.edit.fromUpdate') !== true) { if (Session::get('piggy-banks.edit.fromUpdate') !== true) {
@@ -157,6 +166,7 @@ class PiggyBankController extends Controller
{ {
/** @var Collection $piggyBanks */ /** @var Collection $piggyBanks */
$piggyBanks = $piggyRepository->getPiggyBanks(); $piggyBanks = $piggyRepository->getPiggyBanks();
$end = Session::get('end', Carbon::now()->endOfMonth());
$accounts = []; $accounts = [];
/** @var PiggyBank $piggyBank */ /** @var PiggyBank $piggyBank */
@@ -172,8 +182,8 @@ class PiggyBankController extends Controller
if (!isset($accounts[$account->id])) { if (!isset($accounts[$account->id])) {
$accounts[$account->id] = [ $accounts[$account->id] = [
'name' => $account->name, 'name' => $account->name,
'balance' => Steam::balance($account, null, true), 'balance' => Steam::balance($account, $end, true),
'leftForPiggyBanks' => $repository->leftOnAccount($account), 'leftForPiggyBanks' => $repository->leftOnAccount($account, $end),
'sumOfSaved' => $piggyBank->savedSoFar, 'sumOfSaved' => $piggyBank->savedSoFar,
'sumOfTargets' => floatval($piggyBank->targetamount), 'sumOfTargets' => floatval($piggyBank->targetamount),
'leftToSave' => $piggyBank->leftToSave 'leftToSave' => $piggyBank->leftToSave
@@ -215,7 +225,8 @@ class PiggyBankController extends Controller
public function postAdd(PiggyBankRepositoryInterface $repository, AccountRepositoryInterface $accounts, PiggyBank $piggyBank) public function postAdd(PiggyBankRepositoryInterface $repository, AccountRepositoryInterface $accounts, PiggyBank $piggyBank)
{ {
$amount = round(floatval(Input::get('amount')), 2); $amount = round(floatval(Input::get('amount')), 2);
$leftOnAccount = $accounts->leftOnAccount($piggyBank->account); $date = Session::get('end', Carbon::now()->endOfMonth());
$leftOnAccount = $accounts->leftOnAccount($piggyBank->account, $date);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount; $savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = $piggyBank->targetamount - $savedSoFar; $leftToSave = $piggyBank->targetamount - $savedSoFar;
$maxAmount = round(min($leftOnAccount, $leftToSave), 2); $maxAmount = round(min($leftOnAccount, $leftToSave), 2);
@@ -228,11 +239,6 @@ class PiggyBankController extends Controller
// create event // create event
$repository->createEvent($piggyBank, $amount); $repository->createEvent($piggyBank, $amount);
/*
* Create event!
*/
//Event::fire('piggy_bank.addMoney', [$piggyBank, $amount]); // new and used.
Session::flash('success', 'Added ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".'); Session::flash('success', 'Added ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".');
} else { } else {
Session::flash('error', 'Could not add ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".'); Session::flash('error', 'Could not add ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".');
@@ -360,7 +366,7 @@ class PiggyBankController extends Controller
if (intval(Input::get('return_to_edit')) === 1) { if (intval(Input::get('return_to_edit')) === 1) {
Session::put('piggy-banks.edit.fromUpdate', true); Session::put('piggy-banks.edit.fromUpdate', true);
return Redirect::route('piggy-banks.edit', $piggyBank->id); return Redirect::route('piggy-banks.edit', [$piggyBank->id]);
} }

View File

@@ -1,5 +1,6 @@
<?php namespace FireflyIII\Http\Controllers; <?php namespace FireflyIII\Http\Controllers;
use Config;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Input; use Input;
use Preferences; use Preferences;
@@ -16,12 +17,12 @@ class PreferencesController extends Controller
{ {
/** /**
* * @codeCoverageIgnore
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
View::share('title', 'Preferences'); View::share('title', trans('firefly.preferences'));
View::share('mainTitleIcon', 'fa-gear'); View::share('mainTitleIcon', 'fa-gear');
} }
@@ -37,9 +38,10 @@ class PreferencesController extends Controller
$viewRange = $viewRangePref->data; $viewRange = $viewRangePref->data;
$frontPageAccounts = Preferences::get('frontPageAccounts', []); $frontPageAccounts = Preferences::get('frontPageAccounts', []);
$budgetMax = Preferences::get('budgetMaximum', 1000); $budgetMax = Preferences::get('budgetMaximum', 1000);
$language = Preferences::get('language', 'en')->data;
$budgetMaximum = $budgetMax->data; $budgetMaximum = $budgetMax->data;
return view('preferences.index', compact('budgetMaximum', 'accounts', 'frontPageAccounts', 'viewRange')); return view('preferences.index', compact('budgetMaximum', 'language', 'accounts', 'frontPageAccounts', 'viewRange'));
} }
/** /**
@@ -49,10 +51,12 @@ class PreferencesController extends Controller
{ {
// front page accounts // front page accounts
$frontPageAccounts = []; $frontPageAccounts = [];
foreach (Input::get('frontPageAccounts') as $id) { if (is_array(Input::get('frontPageAccounts'))) {
$frontPageAccounts[] = intval($id); foreach (Input::get('frontPageAccounts') as $id) {
$frontPageAccounts[] = intval($id);
}
Preferences::set('frontPageAccounts', $frontPageAccounts);
} }
Preferences::set('frontPageAccounts', $frontPageAccounts);
// view range: // view range:
Preferences::set('viewRange', Input::get('viewRange')); Preferences::set('viewRange', Input::get('viewRange'));
@@ -65,6 +69,12 @@ class PreferencesController extends Controller
$budgetMaximum = intval(Input::get('budgetMaximum')); $budgetMaximum = intval(Input::get('budgetMaximum'));
Preferences::set('budgetMaximum', $budgetMaximum); Preferences::set('budgetMaximum', $budgetMaximum);
// language:
$lang = Input::get('language');
if (in_array($lang, array_keys(Config::get('firefly.lang')))) {
Preferences::set('language', $lang);
}
Session::flash('success', 'Preferences saved!'); Session::flash('success', 'Preferences saved!');

View File

@@ -109,6 +109,8 @@ class ProfileController extends Controller
// DELETE! // DELETE!
Auth::user()->delete(); Auth::user()->delete();
Session::flush(); Session::flush();
Session::flash('gaEventCategory', 'user');
Session::flash('gaEventAction', 'delete-account');
return Redirect::route('index'); return Redirect::route('index');
} }

View File

@@ -31,7 +31,7 @@ class ReminderController extends Controller
]; ];
Session::flash('_old_input', $data); Session::flash('_old_input', $data);
return Redirect::route('transactions.create', 'transfer'); return Redirect::route('transactions.create', ['transfer']);
} }
/** /**

View File

@@ -2,13 +2,9 @@
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Helpers\Report\ReportHelperInterface; use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Preference; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Models\TransactionJournal;
use Preferences;
use Session; use Session;
use Steam;
use View; use View;
/** /**
@@ -21,311 +17,142 @@ class ReportController extends Controller
/** @var ReportHelperInterface */ /** @var ReportHelperInterface */
protected $helper; protected $helper;
/** @var ReportQueryInterface */
protected $query;
/** /**
* @codeCoverageIgnore
*
* @param ReportHelperInterface $helper * @param ReportHelperInterface $helper
* @param ReportQueryInterface $query
*/ */
public function __construct(ReportHelperInterface $helper, ReportQueryInterface $query) public function __construct(ReportHelperInterface $helper)
{ {
$this->query = $query; parent::__construct();
$this->helper = $helper; $this->helper = $helper;
View::share('title', 'Reports'); View::share('title', trans('firefly.reports'));
View::share('mainTitleIcon', 'fa-line-chart'); View::share('mainTitleIcon', 'fa-line-chart');
} }
/** /**
* @param string $year * @param AccountRepositoryInterface $repository
* @param string $month
* *
* @return \Illuminate\View\View
*/
public function budget($year = '2014', $month = '1')
{
$date = new Carbon($year . '-' . $month . '-01');
$subTitle = 'Budget report for ' . $date->format('F Y');
$subTitleIcon = 'fa-calendar';
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
// should show shared reports?
/** @var Preference $pref */
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
$accountAmounts = []; // array with sums of spent amounts on each account.
$accounts = $this->query->getAllAccounts($start, $end, $showSharedReports); // all accounts and some data.
foreach ($accounts as $account) {
$budgets = $this->query->getBudgetSummary($account, $start, $end);// get budget summary for this account:
$balancedAmount = $this->query->balancedTransactionsSum($account, $start, $end);
$accountAmounts[$account->id] = $balancedAmount;
// balance out the transactions (see transaction groups & tags) ^^
// array with budget information for each account:
$array = [];
// should always hide account
$hide = true;
// loop all budgets
/** @var \FireflyIII\Models\Budget $budget */
foreach ($budgets as $budget) {
$id = intval($budget->id);
$data = $budget->toArray();
$array[$id] = $data;
// no longer hide account if any budget has money in it.
if (floatval($data['queryAmount']) != 0) {
$hide = false;
}
$accountAmounts[$account->id] += $data['queryAmount'];
}
$account->hide = $hide;
$account->budgetInformation = $array;
$account->balancedAmount = $balancedAmount;
}
/**
* Start getBudgetsForMonth DONE
*/
$budgets = $this->helper->getBudgetsForMonth($date, $showSharedReports);
/**
* End getBudgetsForMonth DONE
*/
return view('reports.budget', compact('subTitle', 'accountAmounts', 'year', 'month', 'subTitleIcon', 'date', 'accounts', 'budgets'));
}
/**
* @return View * @return View
* @internal param ReportHelperInterface $helper * @internal param ReportHelperInterface $helper
*
*/ */
public function index() public function index(AccountRepositoryInterface $repository)
{ {
$start = Session::get('first'); $start = Session::get('first');
$months = $this->helper->listOfMonths($start); $months = $this->helper->listOfMonths($start);
$years = $this->helper->listOfYears($start);
$title = 'Reports';
$mainTitleIcon = 'fa-line-chart';
return view('reports.index', compact('years', 'months', 'title', 'mainTitleIcon')); // does the user have shared accounts?
} $accounts = $repository->getAccounts(['Default account', 'Asset account']);
$hasShared = false;
/** /** @var Account $account */
* @param Account $account foreach ($accounts as $account) {
* @param string $year if ($account->getMeta('accountRole') == 'sharedAsset') {
* @param string $month $hasShared = true;
*
* @return \Illuminate\View\View
*/
public function modalBalancedTransfers(Account $account, $year = '2014', $month = '1')
{
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
$journals = $this->query->balancedTransactionsList($account, $start, $end);
return view('reports.modal-journal-list', compact('journals'));
}
/**
* @param Account $account
* @param string $year
* @param string $month
*
* @return View
* @internal param ReportQueryInterface $query
*
*/
public function modalLeftUnbalanced(Account $account, $year = '2014', $month = '1')
{
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
$set = $this->query->getTransactionsWithoutBudget($account, $start, $end);
$journals = $set->filter(
function (TransactionJournal $journal) {
$count = $journal->transactiongroups()->where('relation', 'balance')->count();
if ($count == 0) {
return $journal;
}
return null;
} }
); }
return view('reports.modal-journal-list', compact('journals'));
}
/**
* @param Account $account
* @param string $year
* @param string $month
*
* @return \Illuminate\View\View
*/
public function modalNoBudget(Account $account, $year = '2014', $month = '1')
{
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
$journals = $this->query->getTransactionsWithoutBudget($account, $start, $end);
return view('reports.modal-journal-list', compact('journals'));
return view('reports.index', compact('months', 'hasShared'));
} }
/** /**
* @param string $year * @param string $year
* @param string $month * @param string $month
* *
* @param bool $shared
*
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function month($year = '2014', $month = '1') public function month($year = '2014', $month = '1', $shared = false)
{ {
$date = new Carbon($year . '-' . $month . '-01'); $start = new Carbon($year . '-' . $month . '-01');
$subTitle = 'Report for ' . $date->format('F Y'); $subTitle = trans('firefly.reportForMonth', ['date' => $start->formatLocalized($this->monthFormat)]);
$subTitleIcon = 'fa-calendar'; $subTitleIcon = 'fa-calendar';
$displaySum = true; // to show sums in report. $end = clone $start;
/** @var Preference $pref */ $incomeTopLength = 8;
$pref = Preferences::get('showSharedReports', false); $expenseTopLength = 8;
$showSharedReports = $pref->data; if ($shared == 'shared') {
$shared = true;
$subTitle = trans('firefly.reportForMonthShared', ['date' => $start->formatLocalized($this->monthFormat)]);
}
/**
*
* get income for month (date)
*
*/
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth(); $end->endOfMonth();
/** $accounts = $this->helper->getAccountReport($start, $end, $shared);
* Start getIncomeForMonth DONE $incomes = $this->helper->getIncomeReport($start, $end, $shared);
*/ $expenses = $this->helper->getExpenseReport($start, $end, $shared);
$income = $this->query->incomeByPeriod($start, $end, $showSharedReports); $budgets = $this->helper->getBudgetReport($start, $end, $shared);
/** $categories = $this->helper->getCategoryReport($start, $end, $shared);
* End getIncomeForMonth DONE $balance = $this->helper->getBalanceReport($start, $end, $shared);
*/ $bills = $this->helper->getBillReport($start, $end, $shared);
/**
* Start getExpenseGroupedForMonth DONE
*/
$set = $this->query->journalsByExpenseAccount($start, $end, $showSharedReports);
$expenses = Steam::makeArray($set); Session::flash('gaEventCategory', 'report');
$expenses = Steam::sortArray($expenses); Session::flash('gaEventAction', 'month');
$expenses = Steam::limitArray($expenses, 10); Session::flash('gaEventLabel', $start->format('F Y'));
/**
* End getExpenseGroupedForMonth DONE
*/
/**
* Start getBudgetsForMonth DONE
*/
$budgets = $this->helper->getBudgetsForMonth($date, $showSharedReports);
/**
* End getBudgetsForMonth DONE
*/
/**
* Start getCategoriesForMonth DONE
*/
// all categories.
$result = $this->query->journalsByCategory($start, $end);
$categories = Steam::makeArray($result);
// all transfers
if ($showSharedReports === false) {
$result = $this->query->sharedExpensesByCategory($start, $end);
$transfers = Steam::makeArray($result);
$merged = Steam::mergeArrays($categories, $transfers);
} else {
$merged = $categories;
}
// sort.
$sorted = Steam::sortNegativeArray($merged);
// limit to $limit:
$categories = Steam::limitArray($sorted, 10);
/**
* End getCategoriesForMonth DONE
*/
/**
* Start getAccountsForMonth
*/
$list = $this->query->accountList($showSharedReports);
$accounts = [];
/** @var Account $account */
foreach ($list as $account) {
$id = intval($account->id);
/** @noinspection PhpParamsInspection */
$accounts[$id] = [
'name' => $account->name,
'startBalance' => Steam::balance($account, $start),
'endBalance' => Steam::balance($account, $end)
];
$accounts[$id]['difference'] = $accounts[$id]['endBalance'] - $accounts[$id]['startBalance'];
}
/**
* End getAccountsForMonth
*/
return view( return view(
'reports.month', 'reports.month',
compact( compact(
'income', 'expenses', 'budgets', 'accounts', 'categories', 'start', 'shared',
'date', 'subTitle', 'displaySum', 'subTitleIcon' 'subTitle', 'subTitleIcon',
'accounts',
'incomes', 'incomeTopLength',
'expenses', 'expenseTopLength',
'budgets', 'balance',
'categories',
'bills'
) )
); );
} }
/** /**
* @param $year * @param $year
*
* @param bool $shared
* *
* @return $this * @return $this
*/ */
public function year($year) public function year($year, $shared = false)
{ {
/** @var Preference $pref */ $start = new Carbon('01-01-' . $year);
$pref = Preferences::get('showSharedReports', false); $end = clone $start;
$showSharedReports = $pref->data; $subTitle = trans('firefly.reportForYear', ['year' => $year]);
$date = new Carbon('01-01-' . $year); $subTitleIcon = 'fa-bar-chart';
$end = clone $date; $incomeTopLength = 8;
$expenseTopLength = 8;
if ($shared == 'shared') {
$shared = true;
$subTitle = trans('firefly.reportForYearShared', ['year' => $year]);
}
$end->endOfYear(); $end->endOfYear();
$title = 'Reports';
$subTitle = $year; $accounts = $this->helper->getAccountReport($start, $end, $shared);
$subTitleIcon = 'fa-bar-chart'; $incomes = $this->helper->getIncomeReport($start, $end, $shared);
$mainTitleIcon = 'fa-line-chart'; $expenses = $this->helper->getExpenseReport($start, $end, $shared);
$balances = $this->helper->yearBalanceReport($date, $showSharedReports);
$groupedIncomes = $this->query->journalsByRevenueAccount($date, $end, $showSharedReports); Session::flash('gaEventCategory', 'report');
$groupedExpenses = $this->query->journalsByExpenseAccount($date, $end, $showSharedReports); Session::flash('gaEventAction', 'year');
Session::flash('gaEventLabel', $start->format('Y'));
return view( return view(
'reports.year', compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon') 'reports.year',
compact(
'start', // the date for this report.
'shared', // is a shared report?
'accounts', // all accounts
'incomes', 'expenses', // expenses and incomes.
'subTitle', 'subTitleIcon', // subtitle and subtitle icon.
'incomeTopLength', // length of income top X
'expenseTopLength' // length of expense top X.
)
); );
} }

View File

@@ -31,8 +31,11 @@ use View;
*/ */
class TagController extends Controller class TagController extends Controller
{ {
public $tagOptions = [];
/** /**
* * @codeCoverageIgnore
*/ */
public function __construct() public function __construct()
{ {
@@ -40,12 +43,12 @@ class TagController extends Controller
View::share('title', 'Tags'); View::share('title', 'Tags');
View::share('mainTitleIcon', 'fa-tags'); View::share('mainTitleIcon', 'fa-tags');
View::share('hideTags', true); View::share('hideTags', true);
$tagOptions = [ $this->tagOptions = [
'nothing' => 'Just a regular tag.', 'nothing' => 'Just a regular tag.',
'balancingAct' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.', 'balancingAct' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.',
'advancePayment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.', 'advancePayment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
]; ];
View::share('tagOptions', $tagOptions); View::share('tagOptions', $this->tagOptions);
} }
/** /**
@@ -67,6 +70,8 @@ class TagController extends Controller
Session::put('tags.create.url', URL::previous()); Session::put('tags.create.url', URL::previous());
} }
Session::forget('tags.create.fromStore'); Session::forget('tags.create.fromStore');
Session::flash('gaEventCategory', 'tags');
Session::flash('gaEventAction', 'create');
return view('tags.create', compact('subTitle', 'subTitleIcon')); return view('tags.create', compact('subTitle', 'subTitleIcon'));
} }
@@ -78,10 +83,12 @@ class TagController extends Controller
*/ */
public function delete(Tag $tag) public function delete(Tag $tag)
{ {
$subTitle = 'Delete "' . e($tag->tag) . '"'; $subTitle = trans('firefly.delete_tag', ['name' => $tag->tag]);
// put previous url in session // put previous url in session
Session::put('tags.delete.url', URL::previous()); Session::put('tags.delete.url', URL::previous());
Session::flash('gaEventCategory', 'tags');
Session::flash('gaEventAction', 'delete');
return view('tags.delete', compact('tag', 'subTitle')); return view('tags.delete', compact('tag', 'subTitle'));
} }
@@ -104,11 +111,13 @@ class TagController extends Controller
} }
/** /**
* @param Tag $tag * @param Tag $tag
* *
* @return View * @param TagRepositoryInterface $repository
*
* @return \Illuminate\View\View
*/ */
public function edit(Tag $tag) public function edit(Tag $tag, TagRepositoryInterface $repository)
{ {
$subTitle = 'Edit tag "' . e($tag->tag) . '"'; $subTitle = 'Edit tag "' . e($tag->tag) . '"';
$subTitleIcon = 'fa-tag'; $subTitleIcon = 'fa-tag';
@@ -116,67 +125,16 @@ class TagController extends Controller
/* /*
* Default tag options (again) * Default tag options (again)
*/ */
$tagOptions = [ $tagOptions = $this->tagOptions;
'nothing' => 'Just a regular tag.',
'balancingAct' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.',
'advancePayment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
];
/* /*
* Can this tag become another type? * Can this tag become another type?
*/ */
$allowToAdvancePayment = true; $allowAdvance = $repository->tagAllowAdvance($tag);
$allowToBalancingAct = true; $allowToBalancingAct = $repository->tagAllowBalancing($tag);
/*
* If this tag is a balancing act, and it contains transfers, it cannot be
* changes to an advancePayment.
*/
if ($tag->tagMode == 'balancingAct') {
foreach ($tag->transactionjournals as $journal) {
if ($journal->transactionType->type == 'Transfer') {
$allowToAdvancePayment = false;
}
}
}
/*
* If this tag contains more than one expenses, it cannot become an advance payment.
*/
$count = 0;
foreach ($tag->transactionjournals as $journal) {
if ($journal->transactionType->type == 'Withdrawal') {
$count++;
}
}
if ($count > 1) {
$allowToAdvancePayment = false;
}
/*
* If has more than two transactions already, cannot become a balancing act:
*/
if ($tag->transactionjournals->count() > 2) {
$allowToBalancingAct = false;
}
/*
* If any transaction is a deposit, cannot become a balancing act.
*/
$count = 0;
foreach ($tag->transactionjournals as $journal) {
if ($journal->transactionType->type == 'Deposit') {
$count++;
}
}
if ($count > 0) {
$allowToBalancingAct = false;
}
// edit tag options: // edit tag options:
if ($allowToAdvancePayment === false) { if ($allowAdvance === false) {
unset($tagOptions['advancePayment']); unset($tagOptions['advancePayment']);
} }
if ($allowToBalancingAct === false) { if ($allowToBalancingAct === false) {
@@ -189,6 +147,8 @@ class TagController extends Controller
Session::put('tags.edit.url', URL::previous()); Session::put('tags.edit.url', URL::previous());
} }
Session::forget('tags.edit.fromUpdate'); Session::forget('tags.edit.fromUpdate');
Session::flash('gaEventCategory', 'tags');
Session::flash('gaEventAction', 'edit');
return view('tags.edit', compact('tag', 'subTitle', 'subTitleIcon', 'tagOptions')); return view('tags.edit', compact('tag', 'subTitle', 'subTitleIcon', 'tagOptions'));
} }
@@ -204,7 +164,7 @@ class TagController extends Controller
$state = $state == 'true' ? true : false; $state = $state == 'true' ? true : false;
Preferences::set('hideTagHelp', $state); Preferences::set('hideTagHelp', $state);
return Response::json(true); return Response::json([true]);
} }
/** /**
@@ -240,7 +200,7 @@ class TagController extends Controller
* *
* @param TagRepositoryInterface $repository * @param TagRepositoryInterface $repository
* *
* @return $this|\Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function store(TagFormRequest $request, TagRepositoryInterface $repository) public function store(TagFormRequest $request, TagRepositoryInterface $repository)
{ {
@@ -284,14 +244,14 @@ class TagController extends Controller
* @param TagRepositoryInterface $repository * @param TagRepositoryInterface $repository
* @param Tag $tag * @param Tag $tag
* *
* @return $this|\Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function update(TagFormRequest $request, TagRepositoryInterface $repository, Tag $tag) public function update(TagFormRequest $request, TagRepositoryInterface $repository, Tag $tag)
{ {
if (Input::get('setTag') == 'true') { if (Input::get('setTag') == 'true') {
$latitude = strlen($request->get('latitude')) > 0 ? $request->get('latitude') : null; $latitude = $request->get('latitude');
$longitude = strlen($request->get('longitude')) > 0 ? $request->get('longitude') : null; $longitude = $request->get('longitude');
$zoomLevel = strlen($request->get('zoomLevel')) > 0 ? $request->get('zoomLevel') : null; $zoomLevel = $request->get('zoomLevel');
} else { } else {
$latitude = null; $latitude = null;
$longitude = null; $longitude = null;
@@ -316,7 +276,7 @@ class TagController extends Controller
// set value so edit routine will not overwrite URL: // set value so edit routine will not overwrite URL:
Session::put('tags.edit.fromUpdate', true); Session::put('tags.edit.fromUpdate', true);
return Redirect::route('tags.edit', $tag->id)->withInput(['return_to_edit' => 1]); return Redirect::route('tags.edit', [$tag->id])->withInput(['return_to_edit' => 1]);
} }
// redirect to previous URL. // redirect to previous URL.

View File

@@ -5,7 +5,6 @@ use Carbon\Carbon;
use ExpandedForm; use ExpandedForm;
use FireflyIII\Events\JournalCreated; use FireflyIII\Events\JournalCreated;
use FireflyIII\Events\JournalSaved; use FireflyIII\Events\JournalSaved;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\JournalFormRequest; use FireflyIII\Http\Requests\JournalFormRequest;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -26,11 +25,12 @@ use View;
class TransactionController extends Controller class TransactionController extends Controller
{ {
/** /**
* @codeCoverageIgnore
*/ */
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
View::share('title', 'Transactions'); View::share('title', trans('firefly.transactions'));
View::share('mainTitleIcon', 'fa-repeat'); View::share('mainTitleIcon', 'fa-repeat');
} }
@@ -38,23 +38,21 @@ class TransactionController extends Controller
* @param AccountRepositoryInterface $repository * @param AccountRepositoryInterface $repository
* @param string $what * @param string $what
* *
* @return View * @return \Illuminate\View\View
*/ */
public function create(AccountRepositoryInterface $repository, $what = 'deposit') public function create(AccountRepositoryInterface $repository, $what = 'deposit')
{ {
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account'])); $accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get()); $budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = '(no budget)'; $budgets[0] = trans('form.noBudget');
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get()); $piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
$piggies[0] = '(no piggy bank)'; $piggies[0] = trans('form.noPiggybank');
$preFilled = Session::has('preFilled') ? Session::get('preFilled') : []; $preFilled = Session::has('preFilled') ? Session::get('preFilled') : [];
$respondTo = ['account_id', 'account_from_id']; $respondTo = ['account_id', 'account_from_id'];
$subTitle = 'Add a new ' . e($what); $subTitle = trans('form.add_new_' . $what);
foreach ($respondTo as $r) { foreach ($respondTo as $r) {
if (!is_null(Input::get($r))) { $preFilled[$r] = Input::get($r);
$preFilled[$r] = Input::get($r);
}
} }
Session::put('preFilled', $preFilled); Session::put('preFilled', $preFilled);
@@ -63,6 +61,8 @@ class TransactionController extends Controller
Session::put('transactions.create.url', URL::previous()); Session::put('transactions.create.url', URL::previous());
} }
Session::forget('transactions.create.fromStore'); Session::forget('transactions.create.fromStore');
Session::flash('gaEventCategory', 'transactions');
Session::flash('gaEventAction', 'create-' . $what);
asort($piggies); asort($piggies);
@@ -75,15 +75,17 @@ class TransactionController extends Controller
* *
* @param TransactionJournal $journal * @param TransactionJournal $journal
* *
* @return $this * @return \Illuminate\View\View
*/ */
public function delete(TransactionJournal $journal) public function delete(TransactionJournal $journal)
{ {
$type = strtolower($journal->transactionType->type); $type = strtolower($journal->transactionType->type);
$subTitle = 'Delete ' . e($type) . ' "' . e($journal->description) . '"'; $subTitle = trans('firefly.delete_' . $type, ['description' => $journal->description]);
// put previous url in session // put previous url in session
Session::put('transactions.delete.url', URL::previous()); Session::put('transactions.delete.url', URL::previous());
Session::flash('gaEventCategory', 'transactions');
Session::flash('gaEventAction', 'delete-' . $type);
return view('transactions.delete', compact('journal', 'subTitle')); return view('transactions.delete', compact('journal', 'subTitle'));
@@ -116,13 +118,14 @@ class TransactionController extends Controller
*/ */
public function edit(AccountRepositoryInterface $repository, TransactionJournal $journal) public function edit(AccountRepositoryInterface $repository, TransactionJournal $journal)
{ {
$what = strtolower($journal->transactiontype->type); $what = strtolower($journal->transactionType->type);
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account'])); $accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get()); $budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = '(no budget)'; $budgets[0] = trans('form.noBudget');
$transactions = $journal->transactions()->orderBy('amount', 'DESC')->get(); $transactions = $journal->transactions()->orderBy('amount', 'DESC')->get();
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get()); $piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
$piggies[0] = '(no piggy bank)'; $piggies[0] = trans('form.noPiggybank');
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
$preFilled = [ $preFilled = [
'date' => $journal->date->format('Y-m-d'), 'date' => $journal->date->format('Y-m-d'),
'category' => '', 'category' => '',
@@ -150,14 +153,16 @@ class TransactionController extends Controller
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->orderBy('date', 'DESC')->first()->piggy_bank_id; $preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->orderBy('date', 'DESC')->first()->piggy_bank_id;
} }
$preFilled['amount'] = $journal->amount; $preFilled['amount'] = $journal->actual_amount;
$preFilled['account_id'] = $journal->assetAccount->id; $preFilled['account_id'] = $journal->asset_account->id;
$preFilled['expense_account'] = $transactions[0]->account->name; $preFilled['expense_account'] = $transactions[0]->account->name;
$preFilled['revenue_account'] = $transactions[1]->account->name; $preFilled['revenue_account'] = $transactions[1]->account->name;
$preFilled['account_from_id'] = $transactions[1]->account->id; $preFilled['account_from_id'] = $transactions[1]->account->id;
$preFilled['account_to_id'] = $transactions[0]->account->id; $preFilled['account_to_id'] = $transactions[0]->account->id;
Session::flash('preFilled', $preFilled); Session::flash('preFilled', $preFilled);
Session::flash('gaEventCategory', 'transactions');
Session::flash('gaEventAction', 'edit-' . $what);
// put previous url in session if not redirect from store (not "return_to_edit"). // put previous url in session if not redirect from store (not "return_to_edit").
if (Session::get('transactions.edit.fromUpdate') !== true) { if (Session::get('transactions.edit.fromUpdate') !== true) {
@@ -173,7 +178,7 @@ class TransactionController extends Controller
* @param JournalRepositoryInterface $repository * @param JournalRepositoryInterface $repository
* @param $what * @param $what
* *
* @return View * @return \Illuminate\View\View
*/ */
public function index(JournalRepositoryInterface $repository, $what) public function index(JournalRepositoryInterface $repository, $what)
{ {
@@ -182,19 +187,19 @@ class TransactionController extends Controller
case 'expenses': case 'expenses':
case 'withdrawal': case 'withdrawal':
$subTitleIcon = 'fa-long-arrow-left'; $subTitleIcon = 'fa-long-arrow-left';
$subTitle = 'Expenses'; $subTitle = trans('firefly.expenses');
$types = ['Withdrawal']; $types = ['Withdrawal'];
break; break;
case 'revenue': case 'revenue':
case 'deposit': case 'deposit':
$subTitleIcon = 'fa-long-arrow-right'; $subTitleIcon = 'fa-long-arrow-right';
$subTitle = 'Revenue, income and deposits'; $subTitle = trans('firefly.income');
$types = ['Deposit']; $types = ['Deposit'];
break; break;
case 'transfer': case 'transfer':
case 'transfers': case 'transfers':
$subTitleIcon = 'fa-exchange'; $subTitleIcon = 'fa-exchange';
$subTitle = 'Transfers'; $subTitle = trans('firefly.transfers');
$types = ['Transfer']; $types = ['Transfer'];
break; break;
} }
@@ -231,7 +236,7 @@ class TransactionController extends Controller
} }
} }
return Response::json(true); return Response::json([true]);
} }
@@ -239,17 +244,17 @@ class TransactionController extends Controller
* @param JournalRepositoryInterface $repository * @param JournalRepositoryInterface $repository
* @param TransactionJournal $journal * @param TransactionJournal $journal
* *
* @return $this * @return \Illuminate\View\View
*/ */
public function show(JournalRepositoryInterface $repository, TransactionJournal $journal) public function show(JournalRepositoryInterface $repository, TransactionJournal $journal)
{ {
$journal->transactions->each( $journal->transactions->each(
function (Transaction $t) use ($journal, $repository) { function(Transaction $t) use ($journal, $repository) {
$t->before = $repository->getAmountBefore($journal, $t); $t->before = $repository->getAmountBefore($journal, $t);
$t->after = $t->before + $t->amount; $t->after = $t->before + $t->amount;
} }
); );
$subTitle = e($journal->transactiontype->type) . ' "' . e($journal->description) . '"'; $subTitle = trans('firefly.' . $journal->transactionType->type) . ' "' . e($journal->description) . '"';
return view('transactions.show', compact('journal', 'subTitle')); return view('transactions.show', compact('journal', 'subTitle'));
} }
@@ -258,7 +263,7 @@ class TransactionController extends Controller
* @param JournalFormRequest $request * @param JournalFormRequest $request
* @param JournalRepositoryInterface $repository * @param JournalRepositoryInterface $repository
* *
* @return $this|\Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository) public function store(JournalFormRequest $request, JournalRepositoryInterface $repository)
{ {
@@ -269,7 +274,9 @@ class TransactionController extends Controller
// rescan journal, UpdateJournalConnection // rescan journal, UpdateJournalConnection
event(new JournalSaved($journal)); event(new JournalSaved($journal));
// ConnectJournalToPiggyBank // ConnectJournalToPiggyBank
event(new JournalCreated($journal, intval($request->get('piggy_bank_id')))); if ($journal->transactionType->type == 'Transfer' && intval($request->get('piggy_bank_id')) > 0) {
event(new JournalCreated($journal, intval($request->get('piggy_bank_id'))));
}
$repository->deactivateReminder($request->get('reminder_id')); $repository->deactivateReminder($request->get('reminder_id'));
@@ -279,7 +286,7 @@ class TransactionController extends Controller
// set value so create routine will not overwrite URL: // set value so create routine will not overwrite URL:
Session::put('transactions.create.fromStore', true); Session::put('transactions.create.fromStore', true);
return Redirect::route('transactions.create', $request->input('what'))->withInput(); return Redirect::route('transactions.create', [$request->input('what')])->withInput();
} }
// redirect to previous URL. // redirect to previous URL.
@@ -293,7 +300,7 @@ class TransactionController extends Controller
* @param JournalRepositoryInterface $repository * @param JournalRepositoryInterface $repository
* @param TransactionJournal $journal * @param TransactionJournal $journal
* *
* @return $this|\Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, TransactionJournal $journal) public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, TransactionJournal $journal)
{ {
@@ -310,7 +317,7 @@ class TransactionController extends Controller
// set value so edit routine will not overwrite URL: // set value so edit routine will not overwrite URL:
Session::put('transactions.edit.fromUpdate', true); Session::put('transactions.edit.fromUpdate', true);
return Redirect::route('transactions.edit', $journal->id)->withInput(['return_to_edit' => 1]); return Redirect::route('transactions.edit', [$journal->id])->withInput(['return_to_edit' => 1]);
} }
// redirect to previous URL. // redirect to previous URL.

View File

@@ -37,8 +37,8 @@ class Kernel extends HttpKernel
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth', 'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'FireflyIII\Http\Middleware\RedirectIfAuthenticated', 'guest' => 'FireflyIII\Http\Middleware\RedirectIfAuthenticated',
'range' => 'FireflyIII\Http\Middleware\Range', 'range' => 'FireflyIII\Http\Middleware\Range',
'cleanup' => 'FireflyIII\Http\Middleware\Cleanup',
'reminders' => 'FireflyIII\Http\Middleware\Reminders', 'reminders' => 'FireflyIII\Http\Middleware\Reminders',
'piggybanks' => 'FireflyIII\Http\Middleware\PiggyBanks',
]; ];

View File

@@ -1,9 +1,12 @@
<?php namespace FireflyIII\Http\Middleware; <?php namespace FireflyIII\Http\Middleware;
use App;
use Closure; use Closure;
use Config;
use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Preferences;
use Carbon\Carbon;
/** /**
* Class Authenticate * Class Authenticate
* *
@@ -48,6 +51,12 @@ class Authenticate
return redirect()->guest('auth/login'); return redirect()->guest('auth/login');
} }
} }
// if logged in, set user language:
$pref = Preferences::get('language', 'en');
App::setLocale($pref->data);
Carbon::setLocale($pref->data);
setlocale(LC_TIME, Config::get('firefly.locales.' . $pref->data));
return $next($request); return $next($request);
} }

View File

@@ -0,0 +1,223 @@
<?php namespace FireflyIII\Http\Middleware;
use Closure;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Session;
/**
* Class Cleanup
*
* @codeCoverageIgnore
* @package FireflyIII\Http\Middleware
*/
class Cleanup
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
if ($this->auth->guest()) {
return response('Unauthorized.', 401);
}
$count = -1;
bcscale(0);
if (env('RUNCLEANUP') == 'true') {
$count = 0;
$count = bcadd($count, $this->encryptAccountAndBills());
$count = bcadd($count, $this->encryptBudgetsAndCategories());
$count = bcadd($count, $this->encryptPiggiesAndJournals());
$count = bcadd($count, $this->encryptRemindersAndPreferences());
}
if ($count == 0) {
Session::flash('warning', 'Please open the .env file and change RUNCLEANUP=true to RUNCLEANUP=false');
}
return $next($request);
}
/**
* @return int
*/
protected function encryptAccountAndBills()
{
$count = 0;
// encrypt account name
$set = Account::where('encrypted', 0)->take(5)->get();
/** @var Account $entry */
foreach ($set as $entry) {
$count++;
$name = $entry->name;
$entry->name = $name;
$entry->save();
}
unset($set, $entry, $name);
// encrypt bill name
$set = Bill::where('name_encrypted', 0)->take(5)->get();
/** @var Bill $entry */
foreach ($set as $entry) {
$count++;
$name = $entry->name;
$entry->name = $name;
$entry->save();
}
unset($set, $entry, $name);
// encrypt bill match
$set = Bill::where('match_encrypted', 0)->take(5)->get();
/** @var Bill $entry */
foreach ($set as $entry) {
$match = $entry->match;
$entry->match = $match;
$entry->save();
}
unset($set, $entry, $match);
return $count;
}
/**
* @return int
*/
protected function encryptBudgetsAndCategories()
{
$count = 0;
// encrypt budget name
$set = Budget::where('encrypted', 0)->take(5)->get();
/** @var Budget $entry */
foreach ($set as $entry) {
$count++;
$name = $entry->name;
$entry->name = $name;
$entry->save();
}
unset($set, $entry, $name);
// encrypt category name
$set = Category::where('encrypted', 0)->take(5)->get();
/** @var Category $entry */
foreach ($set as $entry) {
$count++;
$name = $entry->name;
$entry->name = $name;
$entry->save();
}
unset($set, $entry, $name);
return $count;
}
/**
* @return int
*/
protected function encryptPiggiesAndJournals()
{
$count = 0;
// encrypt piggy bank name
$set = PiggyBank::where('encrypted', 0)->take(5)->get();
/** @var PiggyBank $entry */
foreach ($set as $entry) {
$count++;
$name = $entry->name;
$entry->name = $name;
$entry->save();
}
unset($set, $entry, $name);
// encrypt transaction journal description
$set = TransactionJournal::where('encrypted', 0)->take(5)->get();
/** @var TransactionJournal $entry */
foreach ($set as $entry) {
$count++;
$description = $entry->description;
$entry->description = $description;
$entry->save();
}
unset($set, $entry, $description);
return $count;
}
/**
* @return int
*/
protected function encryptRemindersAndPreferences()
{
$count = 0;
// encrypt reminder metadata
$set = Reminder::where('encrypted', 0)->take(5)->get();
/** @var Reminder $entry */
foreach ($set as $entry) {
$count++;
$metadata = $entry->metadata;
$entry->metadata = $metadata;
$entry->save();
}
unset($set, $entry, $metadata);
//encrypt preference name
$set = Preference::whereNull('name_encrypted')->take(5)->get();
/** @var Preference $entry */
foreach ($set as $entry) {
$count++;
$name = $entry->name;
$entry->name = $name;
$entry->save();
}
unset($set, $entry, $name);
//encrypt preference data
$set = Preference::whereNull('data_encrypted')->take(5)->get();
/** @var Preference $entry */
foreach ($set as $entry) {
$count++;
$data = $entry->data;
$entry->data = $data;
$entry->save();
}
unset($set, $entry, $data);
return $count;
}
}

View File

@@ -1,72 +0,0 @@
<?php
namespace FireflyIII\Http\Middleware;
use App;
use Closure;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
/**
* Class PiggyBanks
*
* @package FireflyIII\Http\Middleware
*/
class PiggyBanks
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
if ($this->auth->check() && !$request->isXmlHttpRequest()) {
// get piggy banks without a repetition:
/** @var Collection $set */
$set = $this->auth->user()->piggybanks()
->leftJoin('piggy_bank_repetitions', 'piggy_banks.id', '=', 'piggy_bank_repetitions.piggy_bank_id')
->whereNull('piggy_bank_repetitions.id')
->get(['piggy_banks.id', 'piggy_banks.startdate', 'piggy_banks.targetdate']);
if ($set->count() > 0) {
/** @var PiggyBank $partialPiggy */
foreach ($set as $partialPiggy) {
$repetition = new PiggyBankRepetition;
$repetition->piggyBank()->associate($partialPiggy);
$repetition->startdate = is_null($partialPiggy->startdate) ? null : $partialPiggy->startdate;
$repetition->targetdate = is_null($partialPiggy->targetdate) ? null : $partialPiggy->targetdate;
$repetition->currentamount = 0;
$repetition->save();
}
}
unset($partialPiggy, $set, $repetition);
}
return $next($request);
}
}

View File

@@ -43,6 +43,7 @@ class Range
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Closure $theNext * @param \Closure $theNext
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* *
* @return mixed * @return mixed
*/ */
@@ -54,18 +55,15 @@ class Range
if (!Session::has('start') && !Session::has('end')) { if (!Session::has('start') && !Session::has('end')) {
/** @var \FireflyIII\Models\Preference $viewRange */ /** @var \FireflyIII\Models\Preference $viewRange */
$viewRange = Preferences::get('viewRange', '1M'); $viewRange = Preferences::get('viewRange', '1M')->data;
$start = new Carbon; $start = new Carbon;
$start = Navigation::updateStartDate($viewRange->data, $start); $start = Navigation::updateStartDate($viewRange, $start);
$end = Navigation::updateEndDate($viewRange->data, $start); $end = Navigation::updateEndDate($viewRange, $start);
Session::put('start', $start); Session::put('start', $start);
Session::put('end', $end); Session::put('end', $end);
} }
if (!Session::has('first')) { if (!Session::has('first')) {
/**
* Get helper thing.
*/
/** @var \FireflyIII\Repositories\Journal\JournalRepositoryInterface $repository */ /** @var \FireflyIII\Repositories\Journal\JournalRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Journal\JournalRepositoryInterface'); $repository = App::make('FireflyIII\Repositories\Journal\JournalRepositoryInterface');
$journal = $repository->first(); $journal = $repository->first();
@@ -75,16 +73,12 @@ class Range
Session::put('first', Carbon::now()->startOfYear()); Session::put('first', Carbon::now()->startOfYear());
} }
} }
$current = Carbon::now()->formatLocalized('%B %Y');
// set current / next / prev month. $next = Carbon::now()->endOfMonth()->addDay()->formatLocalized('%B %Y');
$current = Carbon::now()->format('F Y'); $prev = Carbon::now()->startOfMonth()->subDay()->formatLocalized('%B %Y');
$next = Carbon::now()->endOfMonth()->addDay()->format('F Y');
$prev = Carbon::now()->startOfMonth()->subDay()->format('F Y');
View::share('currentMonthName', $current); View::share('currentMonthName', $current);
View::share('previousMonthName', $prev); View::share('previousMonthName', $prev);
View::share('nextMonthName', $next); View::share('nextMonthName', $next);
} }
return $theNext($request); return $theNext($request);

View File

@@ -7,6 +7,7 @@ use Carbon\Carbon;
use Closure; use Closure;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Reminder; use FireflyIII\Models\Reminder;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use View; use View;
@@ -48,41 +49,33 @@ class Reminders
{ {
if ($this->auth->check() && !$request->isXmlHttpRequest()) { if ($this->auth->check() && !$request->isXmlHttpRequest()) {
// do reminders stuff. // do reminders stuff.
$piggyBanks = $this->auth->user()->piggyBanks()->where('remind_me', 1)->get(); $reminders = [];
$today = new Carbon; if ($this->auth->user() instanceof User) {
/** @var \FireflyIII\Helpers\Reminders\ReminderHelperInterface $helper */ $piggyBanks = $this->auth->user()->piggyBanks()->where('remind_me', 1)->get();
$helper = App::make('FireflyIII\Helpers\Reminders\ReminderHelperInterface'); /** @var \FireflyIII\Helpers\Reminders\ReminderHelperInterface $helper */
$helper = App::make('FireflyIII\Helpers\Reminders\ReminderHelperInterface');
/** @var PiggyBank $piggyBank */ /** @var PiggyBank $piggyBank */
foreach ($piggyBanks as $piggyBank) { foreach ($piggyBanks as $piggyBank) {
$ranges = $helper->getReminderRanges($piggyBank); $helper->createReminders($piggyBank, new Carbon);
}
// delete invalid reminders
// this is a construction SQLITE cannot handle :(
if (env('DB_CONNECTION') != 'sqlite') {
Reminder::whereUserId($this->auth->user()->id)
->leftJoin('piggy_banks', 'piggy_banks.id', '=', 'remindersable_id')
->whereNull('piggy_banks.id')
->delete();
}
foreach ($ranges as $range) { // get and list active reminders:
if ($today < $range['end'] && $today > $range['start']) { $reminders = $this->auth->user()->reminders()->today()->get();
// create a reminder here! $reminders->each(
$helper->createReminder($piggyBank, $range['start'], $range['end']); function (Reminder $reminder) use ($helper) {
// stop looping, we're done. $reminder->description = $helper->getReminderText($reminder);
break;
} }
);
}
} }
// delete invalid reminders
$set = $this->auth->user()->reminders()->leftJoin('piggy_banks', 'piggy_banks.id', '=', 'remindersable_id')->whereNull('piggy_banks.id')->get(
['reminders.id']
);
foreach ($set as $reminder) {
$reminder->delete();
}
// get and list active reminders:
$reminders = $this->auth->user()->reminders()->today()->get();
$reminders->each(
function (Reminder $reminder) use ($helper) {
$reminder->description = $helper->getReminderText($reminder);
}
);
View::share('reminders', $reminders); View::share('reminders', $reminders);
} }

View File

@@ -2,6 +2,7 @@
namespace FireflyIII\Http\Requests; namespace FireflyIII\Http\Requests;
use App;
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
@@ -50,12 +51,11 @@ class JournalFormRequest extends Request
/** /**
* @return array * @return array
* @throws Exception * @throws Exception
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/ */
public function rules() public function rules()
{ {
// can we switch on the "what"? $what = Input::get('what');
$what = Input::get('what');
$rules = [ $rules = [
'description' => 'required|min:1,max:255', 'description' => 'required|min:1,max:255',
'what' => 'required|in:withdrawal,deposit,transfer', 'what' => 'required|in:withdrawal,deposit,transfer',
@@ -74,8 +74,6 @@ class JournalFormRequest extends Request
if (intval(Input::get('budget_id')) != 0) { if (intval(Input::get('budget_id')) != 0) {
$rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets'; $rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets';
} }
break; break;
case 'deposit': case 'deposit':
$rules['category'] = 'between:1,255'; $rules['category'] = 'between:1,255';
@@ -88,12 +86,10 @@ class JournalFormRequest extends Request
$rules['category'] = 'between:1,255'; $rules['category'] = 'between:1,255';
break; break;
default: default:
throw new Exception('Cannot handle ' . $what); App::abort(500, 'Cannot handle ' . $what);
break; break;
} }
return $rules; return $rules;
} }
} }

View File

@@ -1,11 +1,4 @@
<?php <?php
/**
* Created by PhpStorm.
* User: sander
* Date: 27/04/15
* Time: 12:50
*/
namespace FireflyIII\Http\Requests; namespace FireflyIII\Http\Requests;
use Auth; use Auth;
@@ -48,6 +41,7 @@ class TagFormRequest extends Request
'date' => 'date', 'date' => 'date',
'latitude' => 'numeric|min:-90|max:90', 'latitude' => 'numeric|min:-90|max:90',
'longitude' => 'numeric|min:-90|max:90', 'longitude' => 'numeric|min:-90|max:90',
'zoomLevel' => 'numeric|min:0|max:80',
'tagMode' => 'required|in:nothing,balancingAct,advancePayment' 'tagMode' => 'required|in:nothing,balancingAct,advancePayment'
]; ];
} }

View File

@@ -1,7 +1,6 @@
<?php <?php
use Carbon\Carbon; use Carbon\Carbon;
use DaveJamesMiller\Breadcrumbs\Generator; use DaveJamesMiller\Breadcrumbs\Generator;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
@@ -18,107 +17,104 @@ use FireflyIII\Models\TransactionJournal;
*/ */
Breadcrumbs::register( Breadcrumbs::register(
'home', 'home',
function (Generator $breadcrumbs) { function(Generator $breadcrumbs) {
$breadcrumbs->push('Home', route('index')); $breadcrumbs->push(trans('breadcrumbs.home'), route('index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'index', 'index',
function (Generator $breadcrumbs) { function(Generator $breadcrumbs) {
$breadcrumbs->push('Home', route('index')); $breadcrumbs->push(trans('breadcrumbs.home'), route('index'));
} }
); );
//trans('breadcrumbs.')
// accounts // accounts
Breadcrumbs::register( Breadcrumbs::register(
'accounts.index', function (Generator $breadcrumbs, $what) { 'accounts.index', function(Generator $breadcrumbs, $what) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(ucfirst(e($what)) . ' accounts', route('accounts.index', $what)); $breadcrumbs->push(trans('breadcrumbs.' . strtolower(e($what)) . '_accounts'), route('accounts.index', [$what]));
}
);
Breadcrumbs::register(
'accounts.show', function (Generator $breadcrumbs, Account $account) {
switch ($account->accountType->type) {
default:
throw new FireflyException('Cannot handle account type "' . e($account->accountType->type) . '"');
break;
case 'Default account':
case 'Asset account':
$what = 'asset';
break;
case 'Cash account':
$what = 'cash';
break;
case 'Expense account':
case 'Beneficiary account':
$what = 'expense';
break;
case 'Revenue account':
$what = 'revenue';
break;
}
$breadcrumbs->parent('accounts.index', $what);
$breadcrumbs->push(e($account->name), route('accounts.show', $account->id));
}
);
Breadcrumbs::register(
'accounts.delete', function (Generator $breadcrumbs, Account $account) {
$breadcrumbs->parent('accounts.show', $account);
$breadcrumbs->push('Delete ' . e($account->name), route('accounts.delete', $account->id));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'accounts.edit', function (Generator $breadcrumbs, Account $account) { 'accounts.create', function(Generator $breadcrumbs, $what) {
$breadcrumbs->parent('accounts.index', $what);
$breadcrumbs->push(trans('breadcrumbs.new_' . strtolower(e($what)) . '_account'), route('accounts.create', [$what]));
}
);
Breadcrumbs::register(
'accounts.show', function(Generator $breadcrumbs, Account $account) {
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
$breadcrumbs->parent('accounts.index', $what);
$breadcrumbs->push(e($account->name), route('accounts.show', [$account->id]));
}
);
Breadcrumbs::register(
'accounts.delete', function(Generator $breadcrumbs, Account $account) {
$breadcrumbs->parent('accounts.show', $account); $breadcrumbs->parent('accounts.show', $account);
$breadcrumbs->push('Edit ' . e($account->name), route('accounts.edit', $account->id)); $breadcrumbs->push(trans('breadcrumbs.delete_account', ['name' => e($account->name)]), route('accounts.delete', [$account->id]));
}
);
Breadcrumbs::register(
'accounts.edit', function(Generator $breadcrumbs, Account $account) {
$breadcrumbs->parent('accounts.show', $account);
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
$breadcrumbs->push(trans('breadcrumbs.edit_' . $what . '_account', ['name' => e($account->name)]), route('accounts.edit', [$account->id]));
} }
); );
// budgets. // budgets.
Breadcrumbs::register( Breadcrumbs::register(
'budgets.index', function (Generator $breadcrumbs) { 'budgets.index', function(Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Budgets', route('budgets.index')); $breadcrumbs->push(trans('breadcrumbs.budgets'), route('budgets.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'budgets.create', function (Generator $breadcrumbs) { 'budgets.create', function(Generator $breadcrumbs) {
$breadcrumbs->parent('budgets.index'); $breadcrumbs->parent('budgets.index');
$breadcrumbs->push('Create new budget', route('budgets.create')); $breadcrumbs->push(trans('breadcrumbs.newBudget'), route('budgets.create'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'budgets.edit', function (Generator $breadcrumbs, Budget $budget) { 'budgets.edit', function(Generator $breadcrumbs, Budget $budget) {
$breadcrumbs->parent('budgets.show', $budget); $breadcrumbs->parent('budgets.show', $budget);
$breadcrumbs->push('Edit ' . e($budget->name), route('budgets.edit', $budget->id)); $breadcrumbs->push(trans('breadcrumbs.edit_budget', ['name' => e($budget->name)]), route('budgets.edit', [$budget->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'budgets.delete', function (Generator $breadcrumbs, Budget $budget) { 'budgets.delete', function(Generator $breadcrumbs, Budget $budget) {
$breadcrumbs->parent('budgets.show', $budget); $breadcrumbs->parent('budgets.show', $budget);
$breadcrumbs->push('Delete ' . e($budget->name), route('budgets.delete', $budget->id)); $breadcrumbs->push(trans('breadcrumbs.delete_budget', ['name' => e($budget->name)]), route('budgets.delete', [$budget->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'budgets.noBudget', function (Generator $breadcrumbs, $subTitle) { 'budgets.noBudget', function(Generator $breadcrumbs, $subTitle) {
$breadcrumbs->parent('budgets.index'); $breadcrumbs->parent('budgets.index');
$breadcrumbs->push($subTitle, route('budgets.noBudget')); $breadcrumbs->push($subTitle, route('budgets.noBudget'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'budgets.show', function (Generator $breadcrumbs, Budget $budget, LimitRepetition $repetition = null) { 'budgets.show', function(Generator $breadcrumbs, Budget $budget, LimitRepetition $repetition = null) {
$breadcrumbs->parent('budgets.index'); $breadcrumbs->parent('budgets.index');
$breadcrumbs->push(e($budget->name), route('budgets.show', $budget->id)); $breadcrumbs->push(e($budget->name), route('budgets.show', [$budget->id]));
if (!is_null($repetition) && !is_null($repetition->id)) { if (!is_null($repetition) && !is_null($repetition->id)) {
$breadcrumbs->push( $breadcrumbs->push(
Navigation::periodShow($repetition->startdate, $repetition->budgetlimit->repeat_freq), route('budgets.show', $budget->id, $repetition->id) Navigation::periodShow($repetition->startdate, $repetition->budgetLimit->repeat_freq), route('budgets.show', [$budget->id, $repetition->id])
); );
} }
} }
@@ -126,41 +122,41 @@ Breadcrumbs::register(
// categories // categories
Breadcrumbs::register( Breadcrumbs::register(
'categories.index', function (Generator $breadcrumbs) { 'categories.index', function(Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Categories', route('categories.index')); $breadcrumbs->push(trans('breadcrumbs.categories'), route('categories.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'categories.create', function (Generator $breadcrumbs) { 'categories.create', function(Generator $breadcrumbs) {
$breadcrumbs->parent('categories.index'); $breadcrumbs->parent('categories.index');
$breadcrumbs->push('Create new category', route('categories.create')); $breadcrumbs->push(trans('breadcrumbs.newCategory'), route('categories.create'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'categories.edit', function (Generator $breadcrumbs, Category $category) { 'categories.edit', function(Generator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.show', $category); $breadcrumbs->parent('categories.show', $category);
$breadcrumbs->push('Edit ' . e($category->name), route('categories.edit', $category->id)); $breadcrumbs->push(trans('breadcrumbs.edit_category', ['name' => e($category->name)]), route('categories.edit', [$category->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'categories.delete', function (Generator $breadcrumbs, Category $category) { 'categories.delete', function(Generator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.show', $category); $breadcrumbs->parent('categories.show', $category);
$breadcrumbs->push('Delete ' . e($category->name), route('categories.delete', $category->id)); $breadcrumbs->push(trans('breadcrumbs.delete_category', ['name' => e($category->name)]), route('categories.delete', [$category->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'categories.show', function (Generator $breadcrumbs, Category $category) { 'categories.show', function(Generator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.index'); $breadcrumbs->parent('categories.index');
$breadcrumbs->push(e($category->name), route('categories.show', $category->id)); $breadcrumbs->push(e($category->name), route('categories.show', [$category->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'categories.noCategory', function (Generator $breadcrumbs, $subTitle) { 'categories.noCategory', function(Generator $breadcrumbs, $subTitle) {
$breadcrumbs->parent('categories.index'); $breadcrumbs->parent('categories.index');
$breadcrumbs->push($subTitle, route('categories.noCategory')); $breadcrumbs->push($subTitle, route('categories.noCategory'));
} }
@@ -168,135 +164,135 @@ Breadcrumbs::register(
// currencies. // currencies.
Breadcrumbs::register( Breadcrumbs::register(
'currency.index', function (Generator $breadcrumbs) { 'currency.index', function(Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Currencies', route('currency.index')); $breadcrumbs->push(trans('breadcrumbs.currencies'), route('currency.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'currency.edit', function (Generator $breadcrumbs, TransactionCurrency $currency) { 'currency.edit', function(Generator $breadcrumbs, TransactionCurrency $currency) {
$breadcrumbs->parent('currency.index'); $breadcrumbs->parent('currency.index');
$breadcrumbs->push('Edit ' . $currency->name, route('currency.edit', $currency->id)); $breadcrumbs->push(trans('breadcrumbs.edit_currency', ['name' => e($currency->name)]), route('currency.edit', [$currency->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'currency.delete', function (Generator $breadcrumbs, TransactionCurrency $currency) { 'currency.delete', function(Generator $breadcrumbs, TransactionCurrency $currency) {
$breadcrumbs->parent('currency.index'); $breadcrumbs->parent('currency.index');
$breadcrumbs->push('Delete ' . $currency->name, route('currency.delete', $currency->id)); $breadcrumbs->push(trans('breadcrumbs.delete_currency', ['name' => e($currency->name)]), route('currency.delete', [$currency->id]));
} }
); );
// piggy banks // piggy banks
Breadcrumbs::register( Breadcrumbs::register(
'piggy-banks.index', function (Generator $breadcrumbs) { 'piggy-banks.index', function(Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Piggy banks', route('piggy-banks.index')); $breadcrumbs->push(trans('breadcrumbs.piggyBanks'), route('piggy-banks.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'piggy-banks.create', function (Generator $breadcrumbs) { 'piggy-banks.create', function(Generator $breadcrumbs) {
$breadcrumbs->parent('piggy-banks.index'); $breadcrumbs->parent('piggy-banks.index');
$breadcrumbs->push('Create new piggy bank', route('piggy-banks.create')); $breadcrumbs->push(trans('breadcrumbs.newPiggyBank'), route('piggy-banks.create'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'piggy-banks.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) { 'piggy-banks.edit', function(Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.show', $piggyBank); $breadcrumbs->parent('piggy-banks.show', $piggyBank);
$breadcrumbs->push('Edit ' . e($piggyBank->name), route('piggy-banks.edit', $piggyBank->id)); $breadcrumbs->push(trans('breadcrumbs.edit_piggyBank', ['name' => e($piggyBank->name)]), route('piggy-banks.edit', [$piggyBank->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'piggy-banks.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) { 'piggy-banks.delete', function(Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.show', $piggyBank); $breadcrumbs->parent('piggy-banks.show', $piggyBank);
$breadcrumbs->push('Delete ' . e($piggyBank->name), route('piggy-banks.delete', $piggyBank->id)); $breadcrumbs->push(trans('breadcrumbs.delete_piggyBank', ['name' => e($piggyBank->name)]), route('piggy-banks.delete', [$piggyBank->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'piggy-banks.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) { 'piggy-banks.show', function(Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.index'); $breadcrumbs->parent('piggy-banks.index');
$breadcrumbs->push(e($piggyBank->name), route('piggy-banks.show', $piggyBank->id)); $breadcrumbs->push(e($piggyBank->name), route('piggy-banks.show', [$piggyBank->id]));
} }
); );
// preferences // preferences
Breadcrumbs::register( Breadcrumbs::register(
'preferences', function (Generator $breadcrumbs) { 'preferences', function(Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Preferences', route('preferences')); $breadcrumbs->push(trans('breadcrumbs.preferences'), route('preferences'));
} }
); );
// profile // profile
Breadcrumbs::register( Breadcrumbs::register(
'profile', function (Generator $breadcrumbs) { 'profile', function(Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Profile', route('profile')); $breadcrumbs->push(trans('breadcrumbs.profile'), route('profile'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'change-password', function (Generator $breadcrumbs) { 'change-password', function(Generator $breadcrumbs) {
$breadcrumbs->parent('profile'); $breadcrumbs->parent('profile');
$breadcrumbs->push('Change your password', route('change-password')); $breadcrumbs->push(trans('breadcrumbs.changePassword'), route('change-password'));
} }
); );
// bills // bills
Breadcrumbs::register( Breadcrumbs::register(
'bills.index', function (Generator $breadcrumbs) { 'bills.index', function(Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Bills', route('bills.index')); $breadcrumbs->push(trans('breadcrumbs.bills'), route('bills.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'bills.create', function (Generator $breadcrumbs) { 'bills.create', function(Generator $breadcrumbs) {
$breadcrumbs->parent('bills.index'); $breadcrumbs->parent('bills.index');
$breadcrumbs->push('Create new bill', route('bills.create')); $breadcrumbs->push(trans('breadcrumbs.newBill'), route('bills.create'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'bills.edit', function (Generator $breadcrumbs, Bill $bill) { 'bills.edit', function(Generator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.show', $bill); $breadcrumbs->parent('bills.show', $bill);
$breadcrumbs->push('Edit ' . e($bill->name), route('bills.edit', $bill->id)); $breadcrumbs->push(trans('breadcrumbs.edit_bill', ['name' => e($bill->name)]), route('bills.edit', [$bill->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'bills.delete', function (Generator $breadcrumbs, Bill $bill) { 'bills.delete', function(Generator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.show', $bill); $breadcrumbs->parent('bills.show', $bill);
$breadcrumbs->push('Delete ' . e($bill->name), route('bills.delete', $bill->id)); $breadcrumbs->push(trans('breadcrumbs.delete_bill', ['name' => e($bill->name)]), route('bills.delete', [$bill->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'bills.show', function (Generator $breadcrumbs, Bill $bill) { 'bills.show', function(Generator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.index'); $breadcrumbs->parent('bills.index');
$breadcrumbs->push(e($bill->name), route('bills.show', $bill->id)); $breadcrumbs->push(e($bill->name), route('bills.show', [$bill->id]));
} }
); );
// reminders // reminders
Breadcrumbs::register( Breadcrumbs::register(
'reminders.index', function (Generator $breadcrumbs) { 'reminders.index', function(Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Reminders', route('reminders.index')); $breadcrumbs->push(trans('breadcrumbs.reminders'), route('reminders.index'));
} }
); );
// reminders // reminders
Breadcrumbs::register( Breadcrumbs::register(
'reminders.show', function (Generator $breadcrumbs, Reminder $reminder) { 'reminders.show', function(Generator $breadcrumbs, Reminder $reminder) {
$breadcrumbs->parent('reminders.index'); $breadcrumbs->parent('reminders.index');
$breadcrumbs->push('Reminder #' . $reminder->id, route('reminders.show', $reminder->id)); $breadcrumbs->push(trans('breadcrumbs.reminder', ['id' => e($reminder->id)]), route('reminders.show', [$reminder->id]));
} }
); );
@@ -304,115 +300,115 @@ Breadcrumbs::register(
// reports // reports
Breadcrumbs::register( Breadcrumbs::register(
'reports.index', function (Generator $breadcrumbs) { 'reports.index', function(Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Reports', route('reports.index')); $breadcrumbs->push(trans('breadcrumbs.reports'), route('reports.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'reports.year', function (Generator $breadcrumbs, Carbon $date) { 'reports.year', function(Generator $breadcrumbs, Carbon $date, $shared) {
$breadcrumbs->parent('reports.index'); $breadcrumbs->parent('reports.index');
$breadcrumbs->push($date->year, route('reports.year', $date->year)); if ($shared) {
$title = trans('breadcrumbs.yearly_report_shared', ['date' => $date->year]);
} else {
$title = trans('breadcrumbs.yearly_report', ['date' => $date->year]);
}
$breadcrumbs->push($title, route('reports.year', [$date->year]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'reports.month', function (Generator $breadcrumbs, Carbon $date) { 'reports.month', function(Generator $breadcrumbs, Carbon $date, $shared) {
$breadcrumbs->parent('reports.year', $date); $breadcrumbs->parent('reports.year', $date, $shared);
$breadcrumbs->push('Monthly report for ' . $date->format('F Y'), route('reports.month', [$date->year, $date->month]));
}
);
Breadcrumbs::register( if ($shared) {
'reports.budget', function (Generator $breadcrumbs, Carbon $date) { $title = trans('breadcrumbs.monthly_report_shared', ['date' => $date->year]);
$breadcrumbs->parent('reports.index'); } else {
$breadcrumbs->push('Budget report for ' . $date->format('F Y'), route('reports.budget', [$date->year, $date->month])); $title = trans('breadcrumbs.monthly_report', ['date' => $date->year]);
}
$breadcrumbs->push($title, route('reports.month', [$date->year, $date->month]));
} }
); );
// search // search
Breadcrumbs::register( Breadcrumbs::register(
'search', function (Generator $breadcrumbs, $query) { 'search', function(Generator $breadcrumbs, $query) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Search for "' . e($query) . '"', route('search')); $breadcrumbs->push(trans('breadcrumbs.searchResult', ['query' => e($query)]), route('search'));
} }
); );
// transactions // transactions
Breadcrumbs::register( Breadcrumbs::register(
'transactions.index', function (Generator $breadcrumbs, $what) { 'transactions.index', function(Generator $breadcrumbs, $what) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.' . $what . '_list'), route('transactions.index', [$what]));
switch ($what) {
case 'expenses':
case 'withdrawal':
$subTitle = 'Expenses';
break;
case 'revenue':
case 'deposit':
$subTitle = 'Revenue, income and deposits';
break;
case 'transfer':
case 'transfers':
$subTitle = 'Transfers';
break;
case 'opening balance':
$subTitle = 'Opening balances';
break;
default:
throw new FireflyException('Cannot handle $what "' . e($what) . '" in bread crumbs');
}
$breadcrumbs->push($subTitle, route('transactions.index', $what));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'transactions.create', function (Generator $breadcrumbs, $what) { 'transactions.create', function(Generator $breadcrumbs, $what) {
$breadcrumbs->parent('transactions.index', $what); $breadcrumbs->parent('transactions.index', $what);
$breadcrumbs->push('Create new ' . e($what), route('transactions.create', $what)); $breadcrumbs->push(trans('breadcrumbs.create_' . e($what)), route('transactions.create', [$what]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'transactions.edit', function (Generator $breadcrumbs, TransactionJournal $journal) { 'transactions.edit', function(Generator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.show', $journal); $breadcrumbs->parent('transactions.show', $journal);
$breadcrumbs->push('Edit ' . e($journal->description), route('transactions.edit', $journal->id)); $breadcrumbs->push(trans('breadcrumbs.edit_journal', ['description' => $journal->description]), route('transactions.edit', [$journal->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'transactions.delete', function (Generator $breadcrumbs, TransactionJournal $journal) { 'transactions.delete', function(Generator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.show', $journal); $breadcrumbs->parent('transactions.show', $journal);
$breadcrumbs->push('Delete ' . e($journal->description), route('transactions.delete', $journal->id)); $breadcrumbs->push(trans('breadcrumbs.delete_journal', ['description' => e($journal->description)]), route('transactions.delete', [$journal->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'transactions.show', function (Generator $breadcrumbs, TransactionJournal $journal) { 'transactions.show', function(Generator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.index', strtolower($journal->transactionType->type)); $breadcrumbs->parent('transactions.index', strtolower($journal->transactionType->type));
$breadcrumbs->push(e($journal->description), route('transactions.show', $journal->id)); $breadcrumbs->push($journal->description, route('transactions.show', [$journal->id]));
} }
); );
// tags // tags
Breadcrumbs::register( Breadcrumbs::register(
'tags.index', function (Generator $breadcrumbs) { 'tags.index', function(Generator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push('Tags', route('tags.index')); $breadcrumbs->push(trans('breadcrumbs.tags'), route('tags.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'tags.create', function (Generator $breadcrumbs) { 'tags.create', function(Generator $breadcrumbs) {
$breadcrumbs->parent('tags.index'); $breadcrumbs->parent('tags.index');
$breadcrumbs->push('Create tag', route('tags.create')); $breadcrumbs->push(trans('breadcrumbs.createTag'), route('tags.create'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'tags.show', function (Generator $breadcrumbs, Tag $tag) { 'tags.edit', function(Generator $breadcrumbs, Tag $tag) {
$breadcrumbs->parent('tags.index'); $breadcrumbs->parent('tags.show', $tag);
$breadcrumbs->push(e($tag->tag), route('tags.show', $tag->id)); $breadcrumbs->push(trans('breadcrumbs.edit_tag', ['tag' => e($tag->tag)]), route('tags.edit', [$tag->id]));
}
);
Breadcrumbs::register(
'tags.delete', function(Generator $breadcrumbs, Tag $tag) {
$breadcrumbs->parent('tags.show', $tag);
$breadcrumbs->push(trans('breadcrumbs.delete_tag', ['tag' => e($tag->tag)]), route('tags.delete', [$tag->id]));
}
);
Breadcrumbs::register(
'tags.show', function(Generator $breadcrumbs, Tag $tag) {
$breadcrumbs->parent('tags.index');
$breadcrumbs->push(e($tag->tag), route('tags.show', [$tag->id]));
} }
); );

View File

@@ -13,16 +13,15 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
// models // models
/** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'account', 'account',
function ($value, $route) { function($value) {
if (Auth::check()) { if (Auth::check()) {
$object = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id') $object = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.editable', 1) ->where('account_types.editable', 1)
->where('accounts.id', $value) ->where('accounts.id', $value)
->where('user_id', Auth::user()->id) ->where('user_id', Auth::user()->id)
->first(['accounts.*']); ->first(['accounts.*']);
if ($object) { if ($object) {
return $object; return $object;
} }
@@ -31,9 +30,8 @@ Route::bind(
} }
); );
/** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'tj', function ($value, $route) { 'tj', function($value) {
if (Auth::check()) { if (Auth::check()) {
$object = TransactionJournal::where('id', $value)->where('user_id', Auth::user()->id)->first(); $object = TransactionJournal::where('id', $value)->where('user_id', Auth::user()->id)->first();
if ($object) { if ($object) {
@@ -45,9 +43,8 @@ Route::bind(
} }
); );
/** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'currency', function ($value, $route) { 'currency', function($value) {
if (Auth::check()) { if (Auth::check()) {
$object = TransactionCurrency::find($value); $object = TransactionCurrency::find($value);
if ($object) { if ($object) {
@@ -58,9 +55,8 @@ Route::bind(
} }
); );
/** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'bill', function ($value, $route) { 'bill', function($value) {
if (Auth::check()) { if (Auth::check()) {
$object = Bill::where('id', $value)->where('user_id', Auth::user()->id)->first(); $object = Bill::where('id', $value)->where('user_id', Auth::user()->id)->first();
if ($object) { if ($object) {
@@ -72,9 +68,8 @@ Route::bind(
} }
); );
/** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'budget', function ($value, $route) { 'budget', function($value) {
if (Auth::check()) { if (Auth::check()) {
$object = Budget::where('id', $value)->where('user_id', Auth::user()->id)->first(); $object = Budget::where('id', $value)->where('user_id', Auth::user()->id)->first();
if ($object) { if ($object) {
@@ -86,9 +81,8 @@ Route::bind(
} }
); );
/** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'reminder', function ($value, $route) { 'reminder', function($value) {
if (Auth::check()) { if (Auth::check()) {
$object = Reminder::where('id', $value)->where('user_id', Auth::user()->id)->first(); $object = Reminder::where('id', $value)->where('user_id', Auth::user()->id)->first();
if ($object) { if ($object) {
@@ -100,15 +94,14 @@ Route::bind(
} }
); );
/** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'limitrepetition', function ($value, $route) { 'limitrepetition', function($value) {
if (Auth::check()) { if (Auth::check()) {
$object = LimitRepetition::where('limit_repetitions.id', $value) $object = LimitRepetition::where('limit_repetitions.id', $value)
->leftjoin('budget_limits', 'budget_limits.id', '=', 'limit_repetitions.budget_limit_id') ->leftjoin('budget_limits', 'budget_limits.id', '=', 'limit_repetitions.budget_limit_id')
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') ->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->where('budgets.user_id', Auth::user()->id) ->where('budgets.user_id', Auth::user()->id)
->first(['limit_repetitions.*']); ->first(['limit_repetitions.*']);
if ($object) { if ($object) {
return $object; return $object;
} }
@@ -118,14 +111,13 @@ Route::bind(
} }
); );
/** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'piggyBank', function ($value, $route) { 'piggyBank', function($value) {
if (Auth::check()) { if (Auth::check()) {
$object = PiggyBank::where('piggy_banks.id', $value) $object = PiggyBank::where('piggy_banks.id', $value)
->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') ->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')
->where('accounts.user_id', Auth::user()->id) ->where('accounts.user_id', Auth::user()->id)
->first(['piggy_banks.*']); ->first(['piggy_banks.*']);
if ($object) { if ($object) {
return $object; return $object;
} }
@@ -135,9 +127,8 @@ Route::bind(
} }
); );
/** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'category', function ($value, $route) { 'category', function($value) {
if (Auth::check()) { if (Auth::check()) {
$object = Category::where('id', $value)->where('user_id', Auth::user()->id)->first(); $object = Category::where('id', $value)->where('user_id', Auth::user()->id)->first();
if ($object) { if ($object) {
@@ -151,7 +142,7 @@ Route::bind(
/** @noinspection PhpUnusedParameterInspection */ /** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'reminder', function ($value, $route) { 'reminder', function($value) {
if (Auth::check()) { if (Auth::check()) {
/** @var \FireflyIII\Models\Reminder $object */ /** @var \FireflyIII\Models\Reminder $object */
$object = Reminder::find($value); $object = Reminder::find($value);
@@ -166,9 +157,8 @@ Route::bind(
} }
); );
/** @noinspection PhpUnusedParameterInspection */
Route::bind( Route::bind(
'tag', function ($value, $route) { 'tag', function($value) {
if (Auth::check()) { if (Auth::check()) {
$object = Tag::where('id', $value)->where('user_id', Auth::user()->id)->first(); $object = Tag::where('id', $value)->where('user_id', Auth::user()->id)->first();
if ($object) { if ($object) {
@@ -193,13 +183,14 @@ Route::controllers(
] ]
); );
Route::get('/routes', ['uses' => 'HomeController@routes', 'as' => 'routes']);
/** /**
* Home Controller * Home Controller
*/ */
Route::group( Route::group(
['middleware' => ['auth', 'range', 'reminders', 'piggybanks']], function () { ['middleware' => ['auth', 'range', 'reminders']], function() {
Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']); Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index', 'middleware' => 'cleanup']);
Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']); Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']);
Route::post('/daterange', ['uses' => 'HomeController@dateRange', 'as' => 'daterange']); Route::post('/daterange', ['uses' => 'HomeController@dateRange', 'as' => 'daterange']);
Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']); Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']);
@@ -223,7 +214,6 @@ Route::group(
Route::get('/bills/rescan/{bill}', ['uses' => 'BillController@rescan', 'as' => 'bills.rescan']); # rescan for matching. Route::get('/bills/rescan/{bill}', ['uses' => 'BillController@rescan', 'as' => 'bills.rescan']); # rescan for matching.
Route::get('/bills/create', ['uses' => 'BillController@create', 'as' => 'bills.create']); Route::get('/bills/create', ['uses' => 'BillController@create', 'as' => 'bills.create']);
Route::get('/bills/edit/{bill}', ['uses' => 'BillController@edit', 'as' => 'bills.edit']); Route::get('/bills/edit/{bill}', ['uses' => 'BillController@edit', 'as' => 'bills.edit']);
Route::get('/bills/add/{bill}', ['uses' => 'BillController@add', 'as' => 'bills.add']);
Route::get('/bills/delete/{bill}', ['uses' => 'BillController@delete', 'as' => 'bills.delete']); Route::get('/bills/delete/{bill}', ['uses' => 'BillController@delete', 'as' => 'bills.delete']);
Route::get('/bills/show/{bill}', ['uses' => 'BillController@show', 'as' => 'bills.show']); Route::get('/bills/show/{bill}', ['uses' => 'BillController@show', 'as' => 'bills.show']);
Route::post('/bills/store', ['uses' => 'BillController@store', 'as' => 'bills.store']); Route::post('/bills/store', ['uses' => 'BillController@store', 'as' => 'bills.store']);
@@ -273,22 +263,41 @@ Route::group(
/** /**
* Google Chart Controller * ALL CHART Controllers
*/ */
Route::get('/chart/home/account', ['uses' => 'GoogleChartController@allAccountsBalanceChart']); // accounts:
Route::get('/chart/home/budgets', ['uses' => 'GoogleChartController@allBudgetsHomeChart']); Route::get('/chart/account/frontpage', ['uses' => 'Chart\AccountController@frontpage']);
Route::get('/chart/home/categories', ['uses' => 'GoogleChartController@allCategoriesHomeChart']); Route::get('/chart/account/month/{year}/{month}/{shared?}', ['uses' => 'Chart\AccountController@all'])->where(
Route::get('/chart/home/bills', ['uses' => 'GoogleChartController@billsOverview']); ['year' => '[0-9]{4}', 'month' => '[0-9]{1,2}', 'shared' => 'shared']
Route::get('/chart/account/{account}/{view?}', ['uses' => 'GoogleChartController@accountBalanceChart']); );
Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']); Route::get('/chart/account/{account}', ['uses' => 'Chart\AccountController@single']);
Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending'])->where(['year' => '[0-9]+']);
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']);
Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']); // bills:
Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']); Route::get('/chart/bill/frontpage', ['uses' => 'Chart\BillController@frontpage']);
Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']); Route::get('/chart/bill/{bill}', ['uses' => 'Chart\BillController@single']);
Route::get('/chart/piggy-history/{piggyBank}', ['uses' => 'GoogleChartController@piggyBankHistory']);
Route::get('/chart/category/{category}/period', ['uses' => 'GoogleChartController@categoryPeriodChart']); // budgets:
Route::get('/chart/category/{category}/overview', ['uses' => 'GoogleChartController@categoryOverviewChart']); Route::get('/chart/budget/frontpage', ['uses' => 'Chart\BudgetController@frontpage']);
Route::get('/chart/budget/year/{year}/{shared?}', ['uses' => 'Chart\BudgetController@year'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']);
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'Chart\BudgetController@budgetLimit']);
Route::get('/chart/budget/{budget}', ['uses' => 'Chart\BudgetController@budget']);
// categories:
Route::get('/chart/category/frontpage', ['uses' => 'Chart\CategoryController@frontpage']);
Route::get('/chart/category/year/{year}/{shared?}', ['uses' => 'Chart\CategoryController@year'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']);
Route::get('/chart/category/{category}/month', ['uses' => 'Chart\CategoryController@month']); // should be period.
Route::get('/chart/category/{category}/all', ['uses' => 'Chart\CategoryController@all']);
// piggy banks:
Route::get('/chart/piggyBank/{piggyBank}', ['uses' => 'Chart\PiggyBankController@history']);
// reports:
Route::get('/chart/report/in-out/{year}/{shared?}', ['uses' => 'Chart\ReportController@yearInOut'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']);
Route::get('/chart/report/in-out-sum/{year}/{shared?}', ['uses' => 'Chart\ReportController@yearInOutSummarized'])->where(
['year' => '[0-9]{4}', 'shared' => 'shared']
);
/** /**
* Help Controller * Help Controller
@@ -306,10 +315,7 @@ Route::group(
Route::get('/json/box/out', ['uses' => 'JsonController@boxOut', 'as' => 'json.box.out']); Route::get('/json/box/out', ['uses' => 'JsonController@boxOut', 'as' => 'json.box.out']);
Route::get('/json/box/bills-unpaid', ['uses' => 'JsonController@boxBillsUnpaid', 'as' => 'json.box.paid']); Route::get('/json/box/bills-unpaid', ['uses' => 'JsonController@boxBillsUnpaid', 'as' => 'json.box.paid']);
Route::get('/json/box/bills-paid', ['uses' => 'JsonController@boxBillsPaid', 'as' => 'json.box.unpaid']); Route::get('/json/box/bills-paid', ['uses' => 'JsonController@boxBillsPaid', 'as' => 'json.box.unpaid']);
Route::get('/json/show-shared-reports', 'JsonController@showSharedReports');
Route::get('/json/transaction-journals/{what}', 'JsonController@transactionJournals'); Route::get('/json/transaction-journals/{what}', 'JsonController@transactionJournals');
Route::get('/json/show-shared-reports/set', 'JsonController@setSharedReports');
/** /**
* Piggy Bank Controller * Piggy Bank Controller
@@ -355,19 +361,12 @@ Route::group(
* Report Controller * Report Controller
*/ */
Route::get('/reports', ['uses' => 'ReportController@index', 'as' => 'reports.index']); Route::get('/reports', ['uses' => 'ReportController@index', 'as' => 'reports.index']);
Route::get('/reports/{year}', ['uses' => 'ReportController@year', 'as' => 'reports.year']); Route::get('/reports/{year}/{shared?}', ['uses' => 'ReportController@year', 'as' => 'reports.year'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']);
Route::get('/reports/{year}/{month}', ['uses' => 'ReportController@month', 'as' => 'reports.month']); Route::get('/reports/{year}/{month}/{shared?}', ['uses' => 'ReportController@month', 'as' => 'reports.month'])->where(
Route::get('/reports/budget/{year}/{month}', ['uses' => 'ReportController@budget', 'as' => 'reports.budget']); ['year' => '[0-9]{4}', 'month' => '[0-9]{1,2}', 'shared' => 'shared']
);
// pop ups for budget report: // pop ups for budget report:
Route::get('/reports/modal/{account}/{year}/{month}/no-budget', ['uses' => 'ReportController@modalNoBudget', 'as' => 'reports.no-budget']);
Route::get(
'/reports/modal/{account}/{year}/{month}/balanced-transfers',
['uses' => 'ReportController@modalBalancedTransfers', 'as' => 'reports.balanced-transfers']
);
Route::get(
'/reports/modal/{account}/{year}/{month}/left-unbalanced', ['uses' => 'ReportController@modalLeftUnbalanced', 'as' => 'reports.left-unbalanced']
);
/** /**
* Search Controller * Search Controller

View File

@@ -1,6 +1,5 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use App;
use Crypt; use Crypt;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@@ -12,12 +11,50 @@ use Watson\Validating\ValidatingTrait;
* Class Account * Class Account
* *
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
* @property integer $user_id
* @property integer $account_type_id
* @property string $name
* @property boolean $active
* @property boolean $encrypted
* @property float $virtual_balance
* @property string $virtual_balance_encrypted
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\AccountMeta[] $accountMeta
* @property-read \FireflyIII\Models\AccountType $accountType
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBank[] $piggyBanks
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Transaction[] $transactions
* @property-read \FireflyIII\User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereAccountTypeId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereActive($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereEncrypted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereVirtualBalance($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereVirtualBalanceEncrypted($value)
* @method static \FireflyIII\Models\Account accountTypeIn($types)
* @method static \FireflyIII\Models\Account hasMetaValue($name, $value)
* @property boolean joinedAccountTypes
* @property mixed startBalance
* @property mixed endBalance
* @property mixed lastActivityDate
* @property mixed piggyBalance
* @property mixed difference
* @propery mixed percentage
*
*/ */
class Account extends Model class Account extends Model
{ {
use SoftDeletes, ValidatingTrait; use SoftDeletes, ValidatingTrait;
protected $fillable = ['user_id', 'account_type_id', 'name', 'active', 'virtual_balance']; protected $fillable = ['user_id', 'account_type_id', 'name', 'active', 'virtual_balance'];
protected $hidden = ['virtual_balance_encrypted', 'encrypted'];
protected $rules protected $rules
= [ = [
'user_id' => 'required|exists:users,id', 'user_id' => 'required|exists:users,id',
@@ -28,7 +65,7 @@ class Account extends Model
/** /**
* @param array $fields * @param array $fields
* * @SuppressWarnings(PHPMD.CyclomaticComplexity)
* *
* @return Account|null * @return Account|null
*/ */
@@ -50,12 +87,6 @@ class Account extends Model
} }
// create it! // create it!
$account = Account::create($fields); $account = Account::create($fields);
if (is_null($account->id)) {
// could not create account:
App::abort(500, 'Could not create new account with data: ' . json_encode($fields) . ' because ' . json_encode($account->getErrors()));
}
return $account; return $account;
@@ -106,7 +137,7 @@ class Account extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @return array * @return string[]
*/ */
public function getDates() public function getDates()
{ {
@@ -115,7 +146,9 @@ class Account extends Model
/** /**
* *
* @param $fieldName * @param string $fieldName
*
* @codeCoverageIgnore
* *
* @return string|null * @return string|null
*/ */
@@ -133,6 +166,7 @@ class Account extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $value * @param $value
* *
* @return string * @return string
@@ -144,9 +178,7 @@ class Account extends Model
return Crypt::decrypt($value); return Crypt::decrypt($value);
} }
// @codeCoverageIgnoreStart
return $value; return $value;
// @codeCoverageIgnoreEnd
} }
/** /**
@@ -160,6 +192,7 @@ class Account extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param EloquentBuilder $query * @param EloquentBuilder $query
* @param array $types * @param array $types
*/ */
@@ -174,6 +207,7 @@ class Account extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param EloquentBuilder $query * @param EloquentBuilder $query
* @param string $name * @param string $name
* @param string $value * @param string $value
@@ -182,7 +216,7 @@ class Account extends Model
{ {
$joinName = str_replace('.', '_', $name); $joinName = str_replace('.', '_', $name);
$query->leftJoin( $query->leftJoin(
'account_meta as ' . $joinName, function (JoinClause $join) use ($joinName, $name) { 'account_meta as ' . $joinName, function(JoinClause $join) use ($joinName, $name) {
$join->on($joinName . '.account_id', '=', 'accounts.id')->where($joinName . '.name', '=', $name); $join->on($joinName . '.account_id', '=', 'accounts.id')->where($joinName . '.name', '=', $name);
} }
); );
@@ -191,6 +225,7 @@ class Account extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $value * @param $value
*/ */
public function setNameAttribute($value) public function setNameAttribute($value)
@@ -199,6 +234,16 @@ class Account extends Model
$this->attributes['encrypted'] = true; $this->attributes['encrypted'] = true;
} }
/**
* @param $value
*
* @codeCoverageIgnore
*/
public function setVirtualBalanceAttribute($value)
{
$this->attributes['virtual_balance'] = strval(round($value, 2));
}
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\HasMany * @return \Illuminate\Database\Eloquent\Relations\HasMany

View File

@@ -8,6 +8,19 @@ use Watson\Validating\ValidatingTrait;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $account_id
* @property string $name
* @property string $data
* @property-read \FireflyIII\Models\Account $account
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountMeta whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountMeta whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountMeta whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountMeta whereAccountId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountMeta whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountMeta whereData($value)
*/ */
class AccountMeta extends Model class AccountMeta extends Model
{ {
@@ -20,7 +33,7 @@ class AccountMeta extends Model
'name' => 'required|between:1,100', 'name' => 'required|between:1,100',
'data' => 'required' 'data' => 'required'
]; ];
protected $table = 'account_meta'; protected $table = 'account_meta';
/** /**
* *

View File

@@ -7,6 +7,17 @@ use Illuminate\Database\Eloquent\Model;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $type
* @property boolean $editable
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Account[] $accounts
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountType whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountType whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountType whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountType whereType($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\AccountType whereEditable($value)
*/ */
class AccountType extends Model class AccountType extends Model
{ {

View File

@@ -4,15 +4,56 @@ use Crypt;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
* Class Bill * FireflyIII\Models\Bill
* *
* @codeCoverageIgnore Class Bill
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $user_id
* @property string $name
* @property string $match
* @property float $amount_min
* @property string $amount_min_encrypted
* @property float $amount_max
* @property string $amount_max_encrypted
* @property \Carbon\Carbon $date
* @property boolean $active
* @property boolean $automatch
* @property string $repeat_freq
* @property integer $skip
* @property boolean $name_encrypted
* @property boolean $match_encrypted
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals
* @property-read \FireflyIII\User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereMatch($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereAmountMin($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereAmountMinEncrypted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereAmountMax($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereAmountMaxEncrypted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereDate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereActive($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereAutomatch($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereRepeatFreq($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereSkip($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereNameEncrypted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Bill whereMatchEncrypted($value)
* @property mixed nextExpectedMatch
* @property mixed lastFoundMatch
*/ */
class Bill extends Model class Bill extends Model
{ {
protected $fillable protected $fillable
= ['name', 'match', 'amount_min', 'match_encrypted', 'name_encrypted', 'user_id', 'amount_max', 'date', 'repeat_freq', 'skip', 'automatch', 'active',]; = ['name', 'match', 'amount_min', 'match_encrypted', 'name_encrypted', 'user_id', 'amount_max', 'date', 'repeat_freq', 'skip', 'automatch', 'active', ];
protected $hidden = ['amount_min_encrypted', 'amount_max_encrypted', 'name_encrypted', 'match_encrypted'];
/** /**
* @return array * @return array
@@ -34,9 +75,7 @@ class Bill extends Model
return Crypt::decrypt($value); return Crypt::decrypt($value);
} }
// @codeCoverageIgnoreStart
return $value; return $value;
// @codeCoverageIgnoreEnd
} }
/** /**
@@ -51,9 +90,23 @@ class Bill extends Model
return Crypt::decrypt($value); return Crypt::decrypt($value);
} }
// @codeCoverageIgnoreStart
return $value; return $value;
// @codeCoverageIgnoreEnd }
/**
* @param $value
*/
public function setAmountMaxAttribute($value)
{
$this->attributes['amount_max'] = strval(round($value, 2));
}
/**
* @param $value
*/
public function setAmountMinAttribute($value)
{
$this->attributes['amount_min'] = strval(round($value, 2));
} }
/** /**

View File

@@ -9,13 +9,33 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
* @property string $name
* @property integer $user_id
* @property boolean $active
* @property boolean $encrypted
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\BudgetLimit[] $budgetlimits
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals
* @property-read \FireflyIII\User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Budget whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Budget whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Budget whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Budget whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Budget whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Budget whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Budget whereActive($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Budget whereEncrypted($value)
*/ */
class Budget extends Model class Budget extends Model
{ {
use SoftDeletes; use SoftDeletes;
protected $fillable = ['user_id', 'name']; protected $fillable = ['user_id', 'name', 'active'];
protected $hidden = ['encrypted'];
/** /**
* *
@@ -46,9 +66,7 @@ class Budget extends Model
return Crypt::decrypt($value); return Crypt::decrypt($value);
} }
// @codeCoverageIgnoreStart
return $value; return $value;
// @codeCoverageIgnoreEnd
} }
/** /**

View File

@@ -7,10 +7,32 @@ use Illuminate\Database\Eloquent\Model;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $budget_id
* @property \Carbon\Carbon $startdate
* @property float $amount
* @property string $amount_encrypted
* @property boolean $repeats
* @property string $repeat_freq
* @property-read \FireflyIII\Models\Budget $budget
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\LimitRepetition[] $limitrepetitions
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\BudgetLimit whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\BudgetLimit whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\BudgetLimit whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\BudgetLimit whereBudgetId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\BudgetLimit whereStartdate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\BudgetLimit whereAmount($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\BudgetLimit whereAmountEncrypted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\BudgetLimit whereRepeats($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\BudgetLimit whereRepeatFreq($value)
*/ */
class BudgetLimit extends Model class BudgetLimit extends Model
{ {
protected $hidden = ['amount_encrypted'];
/** /**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/ */
@@ -35,4 +57,12 @@ class BudgetLimit extends Model
return $this->hasMany('FireflyIII\Models\LimitRepetition'); return $this->hasMany('FireflyIII\Models\LimitRepetition');
} }
/**
* @param $value
*/
public function setAmountAttribute($value)
{
$this->attributes['amount'] = strval(round($value, 2));
}
} }

View File

@@ -1,6 +1,5 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use App;
use Crypt; use Crypt;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@@ -8,37 +7,38 @@ use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* Class Category * Class Category
* *
*
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
* @property string $name
* @property integer $user_id
* @property boolean $encrypted
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals
* @property-read \FireflyIII\User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Category whereEncrypted($value)
* @property mixed spent
* @property mixed lastActivity
*/ */
class Category extends Model class Category extends Model
{ {
use SoftDeletes; use SoftDeletes;
protected $fillable = ['user_id', 'name']; protected $fillable = ['user_id', 'name'];
protected $hidden = ['encrypted'];
/**
* @codeCoverageIgnore
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'deleted_at'];
}
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function transactionjournals()
{
return $this->belongsToMany('FireflyIII\Models\TransactionJournal', 'category_transaction_journal', 'category_id');
}
/** /**
* @param array $fields * @param array $fields
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* *
* @return Account|null * @return Category
*/ */
public static function firstOrCreateEncrypted(array $fields) public static function firstOrCreateEncrypted(array $fields)
{ {
@@ -58,11 +58,6 @@ class Category extends Model
} }
// create it! // create it!
$category = Category::create($fields); $category = Category::create($fields);
if (is_null($category->id)) {
// could not create account:
App::abort(500, 'Could not create new category with data: ' . json_encode($fields));
}
return $category; return $category;
@@ -70,25 +65,16 @@ class Category extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo * @return string[]
*/ */
public function user() public function getDates()
{ {
return $this->belongsTo('FireflyIII\User'); return ['created_at', 'updated_at', 'deleted_at'];
}
/**
* @codeCoverageIgnore
* @param $value
*/
public function setNameAttribute($value)
{
$this->attributes['name'] = Crypt::encrypt($value);
$this->attributes['encrypted'] = true;
} }
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $value * @param $value
* *
* @return string * @return string
@@ -103,4 +89,33 @@ class Category extends Model
return $value; return $value;
} }
/**
* @codeCoverageIgnore
*
* @param $value
*/
public function setNameAttribute($value)
{
$this->attributes['name'] = Crypt::encrypt($value);
$this->attributes['encrypted'] = true;
}
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function transactionjournals()
{
return $this->belongsToMany('FireflyIII\Models\TransactionJournal', 'category_transaction_journal', 'category_id');
}
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('FireflyIII\User');
}
} }

View File

@@ -8,6 +8,20 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
* @property string $name
* @property integer $user_id
* @property string $class
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Component whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Component whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Component whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Component whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Component whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Component whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Component whereClass($value)
*/ */
class Component extends Model class Component extends Model
{ {

View File

@@ -1,19 +1,36 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Auth;
use DB;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
* Class LimitRepetition * Class LimitRepetition
* *
* @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $budget_limit_id
* @property \Carbon\Carbon $startdate
* @property \Carbon\Carbon $enddate
* @property float $amount
* @property string $amount_encrypted
* @property-read \FireflyIII\Models\BudgetLimit $budgetLimit
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\LimitRepetition whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\LimitRepetition whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\LimitRepetition whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\LimitRepetition whereBudgetLimitId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\LimitRepetition whereStartdate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\LimitRepetition whereEnddate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\LimitRepetition whereAmount($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\LimitRepetition whereAmountEncrypted($value)
*/ */
class LimitRepetition extends Model class LimitRepetition extends Model
{ {
protected $hidden = ['amount_encrypted'];
/** /**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/ */
public function budgetLimit() public function budgetLimit()
@@ -22,7 +39,6 @@ class LimitRepetition extends Model
} }
/** /**
* @codeCoverageIgnore
* @return array * @return array
*/ */
public function getDates() public function getDates()
@@ -31,24 +47,11 @@ class LimitRepetition extends Model
} }
/** /**
* @return float * @param $value
*/ */
public function spentInRepetition() public function setAmountAttribute($value)
{ {
$sum = DB::table('transactions') $this->attributes['amount'] = strval(round($value, 2));
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budget_transaction_journal.budget_id')
->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->where('transaction_journals.date', '>=', $this->startdate->format('Y-m-d'))
->where('transaction_journals.date', '<=', $this->enddate->format('Y-m-d'))
->where('transaction_journals.user_id', Auth::user()->id)
->whereNull('transactions.deleted_at')
->where('transactions.amount', '>', 0)
->where('limit_repetitions.id', '=', $this->id)
->sum('transactions.amount');
return floatval($sum);
} }
} }

14
app/Models/Permission.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
namespace FireflyIII\Models;
use Zizaco\Entrust\EntrustPermission;
/**
* Class Permission
*
* @package FireflyIII\Models
*/
class Permission extends EntrustPermission
{
}

View File

@@ -7,17 +7,53 @@ use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* Class PiggyBank * Class PiggyBank
* *
* @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
* @property integer $account_id
* @property string $name
* @property float $targetamount
* @property string $targetamount_encrypted
* @property \Carbon\Carbon $startdate
* @property \Carbon\Carbon $targetdate
* @property string $reminder
* @property integer $reminder_skip
* @property boolean $remind_me
* @property integer $order
* @property boolean $encrypted
* @property-read \FireflyIII\Models\Account $account
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBankRepetition[] $piggyBankRepetitions
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBankEvent[] $piggyBankEvents
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Reminder[] $reminders
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereAccountId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereTargetamount($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereTargetamountEncrypted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereStartdate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereTargetdate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereReminder($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereReminderSkip($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereRemindMe($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereOrder($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereEncrypted($value)
* @property PiggyBankRepetition currentRep
*/ */
class PiggyBank extends Model class PiggyBank extends Model
{ {
use SoftDeletes; use SoftDeletes;
protected $fillable protected $fillable
= ['name', 'account_id', 'order', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder', 'remind_me']; = ['name', 'account_id', 'order', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder', 'remind_me'];
protected $hidden = ['targetamount_encrypted', 'encrypted'];
/** /**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/ */
public function account() public function account()
@@ -45,7 +81,6 @@ class PiggyBank extends Model
} }
/** /**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\HasMany * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/ */
public function piggyBankRepetitions() public function piggyBankRepetitions()
@@ -54,8 +89,7 @@ class PiggyBank extends Model
} }
/** /**
* @codeCoverageIgnore * @return string[]
* @return array
*/ */
public function getDates() public function getDates()
{ {
@@ -63,46 +97,7 @@ class PiggyBank extends Model
} }
/** /**
* @codeCoverageIgnore
* @param $value
* *
* @return int
*/
public function getRemindMeAttribute($value)
{
return intval($value) == 1;
}
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function piggyBankEvents()
{
return $this->hasMany('FireflyIII\Models\PiggyBankEvent');
}
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function reminders()
{
return $this->morphMany('FireflyIII\Models\Reminder', 'remindersable');
}
/**
* @codeCoverageIgnore
* @param $value
*/
public function setNameAttribute($value)
{
$this->attributes['name'] = Crypt::encrypt($value);
$this->attributes['encrypted'] = true;
}
/**
* @codeCoverageIgnore
* @param $value * @param $value
* *
* @return string * @return string
@@ -114,8 +109,51 @@ class PiggyBank extends Model
return Crypt::decrypt($value); return Crypt::decrypt($value);
} }
// @codeCoverageIgnoreStart
return $value; return $value;
// @codeCoverageIgnoreEnd }
/**
*
* @param $value
*
* @return boolean
*/
public function getRemindMeAttribute($value)
{
return intval($value) == 1;
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function piggyBankEvents()
{
return $this->hasMany('FireflyIII\Models\PiggyBankEvent');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function reminders()
{
return $this->morphMany('FireflyIII\Models\Reminder', 'remindersable');
}
/**
*
* @param $value
*/
public function setNameAttribute($value)
{
$this->attributes['name'] = Crypt::encrypt($value);
$this->attributes['encrypted'] = true;
}
/**
* @param $value
*/
public function setTargetamountAttribute($value)
{
$this->attributes['targetamount'] = strval(round($value, 2));
} }
} }

View File

@@ -7,11 +7,30 @@ use Illuminate\Database\Eloquent\Model;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $piggy_bank_id
* @property integer $transaction_journal_id
* @property \Carbon\Carbon $date
* @property float $amount
* @property string $amount_encrypted
* @property-read \FireflyIII\Models\PiggyBank $piggyBank
* @property-read \FireflyIII\Models\TransactionJournal $transactionJournal
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankEvent whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankEvent whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankEvent whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankEvent wherePiggyBankId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankEvent whereTransactionJournalId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankEvent whereDate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankEvent whereAmount($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankEvent whereAmountEncrypted($value)
*/ */
class PiggyBankEvent extends Model class PiggyBankEvent extends Model
{ {
protected $fillable = ['piggy_bank_id', 'transaction_journal_id', 'date', 'amount']; protected $fillable = ['piggy_bank_id', 'transaction_journal_id', 'date', 'amount'];
protected $hidden = ['amount_encrypted'];
/** /**
* @return array * @return array
@@ -29,6 +48,14 @@ class PiggyBankEvent extends Model
return $this->belongsTo('FireflyIII\Models\PiggyBank'); return $this->belongsTo('FireflyIII\Models\PiggyBank');
} }
/**
* @param $value
*/
public function setAmountAttribute($value)
{
$this->attributes['amount'] = strval(round($value, 2));
}
/** /**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/ */

View File

@@ -9,11 +9,31 @@ use Illuminate\Database\Eloquent\Model;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $piggy_bank_id
* @property \Carbon\Carbon $startdate
* @property \Carbon\Carbon $targetdate
* @property float $currentamount
* @property string $currentamount_encrypted
* @property-read \FireflyIII\Models\PiggyBank $piggyBank
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition wherePiggyBankId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition whereStartdate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition whereTargetdate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition whereCurrentamount($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition whereCurrentamountEncrypted($value)
* @method static \FireflyIII\Models\PiggyBankRepetition onDates($start, $target)
* @method static \FireflyIII\Models\PiggyBankRepetition relevantOnDate($date)
*/ */
class PiggyBankRepetition extends Model class PiggyBankRepetition extends Model
{ {
protected $fillable = ['piggy_bank_id', 'startdate', 'targetdate', 'currentamount']; protected $fillable = ['piggy_bank_id', 'startdate', 'targetdate', 'currentamount'];
protected $hidden = ['currentamount_encrypted'];
/** /**
* @return array * @return array
@@ -57,13 +77,21 @@ class PiggyBankRepetition extends Model
$q->orWhereNull('startdate'); $q->orWhereNull('startdate');
} }
) )
->where( ->where(
function (EloquentBuilder $q) use ($date) { function (EloquentBuilder $q) use ($date) {
$q->where('targetdate', '>=', $date->format('Y-m-d 00:00:00')); $q->where('targetdate', '>=', $date->format('Y-m-d 00:00:00'));
$q->orWhereNull('targetdate'); $q->orWhereNull('targetdate');
} }
); );
}
/**
* @param $value
*/
public function setCurrentamountAttribute($value)
{
$this->attributes['currentamount'] = strval(round($value, 2));
} }
} }

View File

@@ -1,5 +1,6 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Crypt;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
@@ -7,11 +8,29 @@ use Illuminate\Database\Eloquent\Model;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $user_id
* @property string $name
* @property string $name_encrypted
* @property string $data
* @property string $data_encrypted
* @property-read \FireflyIII\User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Preference whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Preference whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Preference whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Preference whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Preference whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Preference whereNameEncrypted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Preference whereData($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Preference whereDataEncrypted($value)
*/ */
class Preference extends Model class Preference extends Model
{ {
protected $fillable = ['user_id', 'data', 'name']; protected $fillable = ['user_id', 'data', 'name'];
protected $hidden = ['data_encrypted', 'name_encrypted'];
/** /**
* @param $value * @param $value
@@ -20,7 +39,12 @@ class Preference extends Model
*/ */
public function getDataAttribute($value) public function getDataAttribute($value)
{ {
return json_decode($value); if (is_null($this->data_encrypted)) {
return json_decode($value);
}
$data = Crypt::decrypt($this->data_encrypted);
return json_decode($data);
} }
/** /**
@@ -31,12 +55,37 @@ class Preference extends Model
return ['created_at', 'updated_at']; return ['created_at', 'updated_at'];
} }
/**
* @param $value
*
* @return float|int
*/
public function getNameAttribute($value)
{
if (is_null($this->name_encrypted)) {
return $value;
}
$value = Crypt::decrypt($this->name_encrypted);
return $value;
}
/** /**
* @param $value * @param $value
*/ */
public function setDataAttribute($value) public function setDataAttribute($value)
{ {
$this->attributes['data'] = json_encode($value); $this->attributes['data'] = '';
$this->attributes['data_encrypted'] = Crypt::encrypt(json_encode($value));
}
/**
* @param $value
*/
public function setNameAttribute($value)
{
$this->attributes['name_encrypted'] = Crypt::encrypt($value);
$this->attributes['name'] = $value;
} }
/** /**

View File

@@ -8,16 +8,47 @@ use Illuminate\Database\Eloquent\Model;
/** /**
* Class Reminder * Class Reminder
* *
* @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property integer $user_id
* @property \Carbon\Carbon $startdate
* @property \Carbon\Carbon $enddate
* @property boolean $active
* @property boolean $notnow
* @property integer $remindersable_id
* @property string $remindersable_type
* @property string $metadata
* @property boolean $encrypted
* @property-read \ $remindersable
* @property-read \FireflyIII\User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereStartdate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereEnddate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereActive($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereNotnow($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereRemindersableId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereRemindersableType($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereMetadata($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Reminder whereEncrypted($value)
* @method static \FireflyIII\Models\Reminder onDates($start, $end)
* @method static \FireflyIII\Models\Reminder today()
* @property string description
*/ */
class Reminder extends Model class Reminder extends Model
{ {
protected $fillable = ['user_id', 'startdate', 'metadata', 'enddate', 'active', 'notnow', 'remindersable_id', 'remindersable_type',]; protected $fillable = ['user_id', 'startdate', 'metadata', 'enddate', 'active', 'notnow', 'remindersable_id', 'remindersable_type', ];
protected $hidden = ['encrypted'];
/** /**
* @codeCoverageIgnore *
* @param $value * @param $value
* *
* @return int * @return int
@@ -28,7 +59,6 @@ class Reminder extends Model
} }
/** /**
* @codeCoverageIgnore
* @return array * @return array
*/ */
public function getDates() public function getDates()
@@ -37,7 +67,7 @@ class Reminder extends Model
} }
/** /**
* @codeCoverageIgnore *
* @param $value * @param $value
* *
* @return mixed * @return mixed
@@ -52,7 +82,7 @@ class Reminder extends Model
} }
/** /**
* @codeCoverageIgnore *
* @param $value * @param $value
* *
* @return bool * @return bool
@@ -63,7 +93,6 @@ class Reminder extends Model
} }
/** /**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\MorphTo * @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/ */
public function remindersable() public function remindersable()
@@ -72,7 +101,7 @@ class Reminder extends Model
} }
/** /**
* @codeCoverageIgnore *
* @param EloquentBuilder $query * @param EloquentBuilder $query
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
@@ -85,7 +114,7 @@ class Reminder extends Model
} }
/** /**
* @codeCoverageIgnore *
* @param EloquentBuilder $query * @param EloquentBuilder $query
* *
* @return $this * @return $this
@@ -95,11 +124,11 @@ class Reminder extends Model
$today = new Carbon; $today = new Carbon;
return $query->where('startdate', '<=', $today->format('Y-m-d 00:00:00'))->where('enddate', '>=', $today->format('Y-m-d 00:00:00'))->where('active', 1) return $query->where('startdate', '<=', $today->format('Y-m-d 00:00:00'))->where('enddate', '>=', $today->format('Y-m-d 00:00:00'))->where('active', 1)
->where('notnow', 0); ->where('notnow', 0);
} }
/** /**
* @codeCoverageIgnore *
* @param $value * @param $value
*/ */
public function setMetadataAttribute($value) public function setMetadataAttribute($value)
@@ -109,7 +138,6 @@ class Reminder extends Model
} }
/** /**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/ */
public function user() public function user()

14
app/Models/Role.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
namespace FireflyIII\Models;
use Zizaco\Entrust\EntrustRole;
/**
* Class Role
*
* @package FireflyIII\Models
*/
class Role extends EntrustRole
{
}

View File

@@ -2,7 +2,6 @@
namespace FireflyIII\Models; namespace FireflyIII\Models;
use App;
use Crypt; use Crypt;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
@@ -11,6 +10,32 @@ use Watson\Validating\ValidatingTrait;
* Class Tag * Class Tag
* *
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $deleted_at
* @property integer $user_id
* @property string $tag
* @property string $tagMode
* @property \Carbon\Carbon $date
* @property string $description
* @property float $latitude
* @property float $longitude
* @property integer $zoomLevel
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals
* @property-read \FireflyIII\User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereTag($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereTagMode($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereDate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereDescription($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereLatitude($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereLongitude($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Tag whereZoomLevel($value)
*/ */
class Tag extends Model class Tag extends Model
{ {
@@ -29,6 +54,8 @@ class Tag extends Model
/** /**
* @param array $fields * @param array $fields
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* *
* @return Tag|null * @return Tag|null
*/ */
@@ -55,12 +82,6 @@ class Tag extends Model
$fields['tagMode'] = 'nothing'; $fields['tagMode'] = 'nothing';
$fields['description'] = isset($fields['description']) && !is_null($fields['description']) ? $fields['description'] : ''; $fields['description'] = isset($fields['description']) && !is_null($fields['description']) ? $fields['description'] : '';
$tag = Tag::create($fields); $tag = Tag::create($fields);
if (is_null($tag->id)) {
// could not create account:
App::abort(500, 'Could not create new tag with data: ' . json_encode($fields) . ' because ' . json_encode($tag->getErrors()));
}
return $tag; return $tag;
@@ -68,7 +89,7 @@ class Tag extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @return array * @return string[]
*/ */
public function getDates() public function getDates()
{ {
@@ -77,6 +98,7 @@ class Tag extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $value * @param $value
* *
* @return string * @return string
@@ -88,6 +110,7 @@ class Tag extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $value * @param $value
* *
* @return string * @return string
@@ -99,6 +122,7 @@ class Tag extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $value * @param $value
*/ */
public function setDescriptionAttribute($value) public function setDescriptionAttribute($value)
@@ -108,6 +132,7 @@ class Tag extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $value * @param $value
*/ */
public function setTagAttribute($value) public function setTagAttribute($value)

View File

@@ -11,11 +11,36 @@ use Watson\Validating\ValidatingTrait;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
* @property integer $account_id
* @property integer $transaction_journal_id
* @property string $description
* @property float $amount
* @property string $amount_encrypted
* @property-read \FireflyIII\Models\Account $account
* @property-read \FireflyIII\Models\TransactionJournal $transactionJournal
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereAccountId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereTransactionJournalId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereDescription($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereAmount($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereAmountEncrypted($value)
* @method static \FireflyIII\Models\Transaction after($date)
* @method static \FireflyIII\Models\Transaction before($date)
* @property mixed before
* @property mixed after
*/ */
class Transaction extends Model class Transaction extends Model
{ {
protected $fillable = ['account_id', 'transaction_journal_id', 'description', 'amount']; protected $fillable = ['account_id', 'transaction_journal_id', 'description', 'amount'];
protected $hidden = ['encrypted'];
protected $rules protected $rules
= [ = [
'account_id' => 'required|exists:accounts,id', 'account_id' => 'required|exists:accounts,id',
@@ -33,6 +58,24 @@ class Transaction extends Model
return $this->belongsTo('FireflyIII\Models\Account'); return $this->belongsTo('FireflyIII\Models\Account');
} }
/**
* @param $value
*
* @return float|int
*/
public function getAmountAttribute($value)
{
return $value;
}
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'deleted_at'];
}
/** /**
* @param EloquentBuilder $query * @param EloquentBuilder $query
* @param Carbon $date * @param Carbon $date
@@ -56,11 +99,11 @@ class Transaction extends Model
} }
/** /**
* @return array * @param $value
*/ */
public function getDates() public function setAmountAttribute($value)
{ {
return ['created_at', 'updated_at', 'deleted_at']; $this->attributes['amount'] = strval(round($value, 2));
} }
/** /**

View File

@@ -4,11 +4,25 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
*
* Class TransactionCurrency * Class TransactionCurrency
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
* @property string $code
* @property string $name
* @property string $symbol
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionJournals
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionCurrency whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionCurrency whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionCurrency whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionCurrency whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionCurrency whereCode($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionCurrency whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionCurrency whereSymbol($value)
*/ */
class TransactionCurrency extends Model class TransactionCurrency extends Model
{ {

View File

@@ -8,6 +8,20 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
* @property integer $user_id
* @property string $relation
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals
* @property-read \FireflyIII\User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionGroup whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionGroup whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionGroup whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionGroup whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionGroup whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionGroup whereRelation($value)
*/ */
class TransactionGroup extends Model class TransactionGroup extends Model
{ {

View File

@@ -12,15 +12,70 @@ use Watson\Validating\ValidatingTrait;
* Class TransactionJournal * Class TransactionJournal
* *
* @package FireflyIII\Models * @package FireflyIII\Models
* @SuppressWarnings (PHPMD.TooManyMethods)
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
* @property integer $user_id
* @property integer $transaction_type_id
* @property integer $bill_id
* @property integer $transaction_currency_id
* @property string $description
* @property boolean $completed
* @property \Carbon\Carbon $date
* @property boolean $encrypted
* @property integer $order
* @property-read \FireflyIII\Models\Bill $bill
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Category[] $categories
* @property-read mixed $actual_amount
* @property-read mixed $amount
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Tag[] $tags
* @property-read mixed $asset_account
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Transaction[] $transactions
* @property-read mixed $corrected_actual_amount
* @property-read mixed $destination_account
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBankEvent[] $piggyBankEvents
* @property-read \FireflyIII\Models\TransactionCurrency $transactionCurrency
* @property-read \FireflyIII\Models\TransactionType $transactionType
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionGroup[] $transactiongroups
* @property-read \FireflyIII\User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereTransactionTypeId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereBillId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereTransactionCurrencyId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereDescription($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereCompleted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereDate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereEncrypted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereOrder($value)
* @method static \FireflyIII\Models\TransactionJournal accountIs($account)
* @method static \FireflyIII\Models\TransactionJournal after($date)
* @method static \FireflyIII\Models\TransactionJournal before($date)
* @method static \FireflyIII\Models\TransactionJournal onDate($date)
* @method static \FireflyIII\Models\TransactionJournal transactionTypes($types)
* @method static \FireflyIII\Models\TransactionJournal withRelevantData()
* @property-read mixed $expense_account
* @property string account_encrypted
* @property bool joinedTransactions
* @property bool joinedTransactionTypes
* @property mixed account_id
* @property mixed name
* @property mixed symbol
*/ */
class TransactionJournal extends Model class TransactionJournal extends Model
{ {
use SoftDeletes, ValidatingTrait; use SoftDeletes, ValidatingTrait;
protected $fillable = ['user_id', 'transaction_type_id', 'bill_id', 'transaction_currency_id', 'description', 'completed', 'date', 'encrypted']; protected $fillable = ['user_id', 'transaction_type_id', 'bill_id', 'transaction_currency_id', 'description', 'completed', 'date', 'encrypted'];
protected $hidden = ['encrypted'];
protected $rules protected $rules
= [ = [
'user_id' => 'required|exists:users,id', 'user_id' => 'required|exists:users,id',
'transaction_type_id' => 'required|exists:transaction_types,id', 'transaction_type_id' => 'required|exists:transaction_types,id',
'bill_id' => 'exists:bills,id', 'bill_id' => 'exists:bills,id',
@@ -58,42 +113,110 @@ class TransactionJournal extends Model
return $this->belongsToMany('FireflyIII\Models\Category'); return $this->belongsToMany('FireflyIII\Models\Category');
} }
/**
* @return string
*/
public function getActualAmountAttribute()
{
$amount = '0';
/** @var Transaction $t */
foreach ($this->transactions as $t) {
if ($t->amount > 0) {
$amount = $t->amount;
}
}
return $amount;
}
/** /**
* @return float * @return float
*/ */
public function getAmountAttribute() public function getAmountAttribute()
{ {
$amount = '0';
bcscale(2);
/** @var Transaction $t */ /** @var Transaction $t */
foreach ($this->transactions as $t) { foreach ($this->transactions as $t) {
if ($t->amount > 0) { if ($t->amount > 0) {
return floatval($t->amount); $amount = $t->amount;
} }
} }
return 0; /*
* If the journal has tags, it gets complicated.
*/
if ($this->tags->count() == 0) {
return $amount;
}
// if journal is part of advancePayment AND journal is a withdrawal,
// then journal is being repaid by other journals, so the actual amount will lower:
/** @var Tag $advancePayment */
$advancePayment = $this->tags()->where('tagMode', 'advancePayment')->first();
if ($advancePayment && $this->transactionType->type == 'Withdrawal') {
// loop other deposits, remove from our amount.
$others = $advancePayment->transactionJournals()->transactionTypes(['Deposit'])->get();
foreach ($others as $other) {
$amount = bcsub($amount, $other->actual_amount);
}
return $amount;
}
// if this journal is part of an advancePayment AND the journal is a deposit,
// then the journal amount is correcting a withdrawal, and the amount is zero:
if ($advancePayment && $this->transactionType->type == 'Deposit') {
return '0';
}
// is balancing act?
$balancingAct = $this->tags()->where('tagMode', 'balancingAct')->first();
if ($balancingAct) {
// this is the expense:
if ($this->transactionType->type == 'Withdrawal') {
$transfer = $balancingAct->transactionJournals()->transactionTypes(['Transfer'])->first();
if ($transfer) {
$amount = bcsub($amount, $transfer->actual_amount);
return $amount;
}
} // @codeCoverageIgnore
} // @codeCoverageIgnore
return $amount;
} }
/** /**
* @return Account|mixed * @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function tags()
{
return $this->belongsToMany('FireflyIII\Models\Tag');
}
/**
* @return Account
*/ */
public function getAssetAccountAttribute() public function getAssetAccountAttribute()
{ {
$positive = true; // the asset account is in the transaction with the positive amount. // if it's a deposit, it's the one thats positive
if ($this->transactionType->type === 'Withdrawal') { // if it's a withdrawal, it's the one thats negative
$positive = false; // otherwise, it's either (return first one):
}
/** @var Transaction $transaction */ switch ($this->transactionType->type) {
foreach ($this->transactions()->get() as $transaction) { case 'Deposit':
if (floatval($transaction->amount) > 0 && $positive === true) { return $this->transactions()->where('amount', '>', 0)->first()->account;
return $transaction->account; case 'Withdrawal':
} return $this->transactions()->where('amount', '<', 0)->first()->account;
if (floatval($transaction->amount) < 0 && $positive === false) {
return $transaction->account;
}
} }
return $this->transactions()->first(); return $this->transactions()->first()->account;
} }
/** /**
@@ -107,7 +230,7 @@ class TransactionJournal extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @return array * @return string[]
*/ */
public function getDates() public function getDates()
{ {
@@ -116,6 +239,7 @@ class TransactionJournal extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $value * @param $value
* *
* @return string * @return string
@@ -129,6 +253,42 @@ class TransactionJournal extends Model
return $value; return $value;
} }
/**
* @return Account
*/
public function getDestinationAccountAttribute()
{
/** @var Transaction $transaction */
foreach ($this->transactions()->get() as $transaction) {
if (floatval($transaction->amount) > 0) {
return $transaction->account;
}
}
return $this->transactions()->first()->account;
}
/**
* @return Account
*/
public function getExpenseAccountAttribute()
{
// if it's a deposit, it's the one thats negative
// if it's a withdrawal, it's the one thats positive
// otherwise, it's either (return first one):
switch ($this->transactionType->type) {
case 'Deposit':
return $this->transactions()->where('amount', '<', 0)->first()->account;
case 'Withdrawal':
return $this->transactions()->where('amount', '>', 0)->first()->account;
}
return $this->transactions()->first()->account;
}
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\HasMany * @return \Illuminate\Database\Eloquent\Relations\HasMany
@@ -140,6 +300,7 @@ class TransactionJournal extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param EloquentBuilder $query * @param EloquentBuilder $query
* @param Account $account * @param Account $account
*/ */
@@ -154,10 +315,11 @@ class TransactionJournal extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param EloquentBuilder $query * @param EloquentBuilder $query
* @param Carbon $date * @param Carbon $date
* *
* @return mixed * @return EloquentBuilder
*/ */
public function scopeAfter(EloquentBuilder $query, Carbon $date) public function scopeAfter(EloquentBuilder $query, Carbon $date)
{ {
@@ -166,10 +328,11 @@ class TransactionJournal extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param EloquentBuilder $query * @param EloquentBuilder $query
* @param Carbon $date * @param Carbon $date
* *
* @return mixed * @return EloquentBuilder
*/ */
public function scopeBefore(EloquentBuilder $query, Carbon $date) public function scopeBefore(EloquentBuilder $query, Carbon $date)
{ {
@@ -178,27 +341,11 @@ class TransactionJournal extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @param EloquentBuilder $query *
* @param $amount
*/
public function scopeLessThan(EloquentBuilder $query, $amount)
{
if (is_null($this->joinedTransactions)) {
$query->leftJoin(
'transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id'
);
$this->joinedTransactions = true;
}
$query->where('transactions.amount', '<=', $amount);
}
/**
* @codeCoverageIgnore
* @param EloquentBuilder $query * @param EloquentBuilder $query
* @param Carbon $date * @param Carbon $date
* *
* @return mixed * @return EloquentBuilder
*/ */
public function scopeOnDate(EloquentBuilder $query, Carbon $date) public function scopeOnDate(EloquentBuilder $query, Carbon $date)
{ {
@@ -207,6 +354,7 @@ class TransactionJournal extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param EloquentBuilder $query * @param EloquentBuilder $query
* @param array $types * @param array $types
*/ */
@@ -231,7 +379,7 @@ class TransactionJournal extends Model
public function scopeWithRelevantData(EloquentBuilder $query) public function scopeWithRelevantData(EloquentBuilder $query)
{ {
$query->with( $query->with(
['transactions' => function (HasMany $q) { ['transactions' => function(HasMany $q) {
$q->orderBy('amount', 'ASC'); $q->orderBy('amount', 'ASC');
}, 'transactiontype', 'transactioncurrency', 'budgets', 'categories', 'transactions.account.accounttype', 'bill', 'budgets', 'categories'] }, 'transactiontype', 'transactioncurrency', 'budgets', 'categories', 'transactions.account.accounttype', 'bill', 'budgets', 'categories']
); );
@@ -239,6 +387,7 @@ class TransactionJournal extends Model
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param $value * @param $value
*/ */
public function setDescriptionAttribute($value) public function setDescriptionAttribute($value)
@@ -247,15 +396,6 @@ class TransactionJournal extends Model
$this->attributes['encrypted'] = true; $this->attributes['encrypted'] = true;
} }
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function tags()
{
return $this->belongsToMany('FireflyIII\Models\Tag');
}
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo * @return \Illuminate\Database\Eloquent\Relations\BelongsTo

View File

@@ -8,6 +8,17 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @package FireflyIII\Models * @package FireflyIII\Models
* @property integer $id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
* @property string $type
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionJournals
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionType whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionType whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionType whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionType whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionType whereType($value)
*/ */
class TransactionType extends Model class TransactionType extends Model
{ {

View File

@@ -6,6 +6,8 @@ use Illuminate\Support\ServiceProvider;
* Class AppServiceProvider * Class AppServiceProvider
* *
* @package FireflyIII\Providers * @package FireflyIII\Providers
*
* @codeCoverageIgnore
*/ */
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
{ {

View File

@@ -6,6 +6,8 @@ use Illuminate\Support\ServiceProvider;
/** /**
* Class BusServiceProvider * Class BusServiceProvider
* *
* @codeCoverageIgnore
*
* @package FireflyIII\Providers * @package FireflyIII\Providers
*/ */
class BusServiceProvider extends ServiceProvider class BusServiceProvider extends ServiceProvider
@@ -21,7 +23,7 @@ class BusServiceProvider extends ServiceProvider
public function boot(Dispatcher $dispatcher) public function boot(Dispatcher $dispatcher)
{ {
$dispatcher->mapUsing( $dispatcher->mapUsing(
function ($command) { function($command) {
return Dispatcher::simpleMapping( return Dispatcher::simpleMapping(
$command, 'FireflyIII\Commands', 'FireflyIII\Handlers\Commands' $command, 'FireflyIII\Commands', 'FireflyIII\Handlers\Commands'
); );

View File

@@ -6,6 +6,8 @@ use Illuminate\Support\ServiceProvider;
* Class ConfigServiceProvider * Class ConfigServiceProvider
* *
* @package FireflyIII\Providers * @package FireflyIII\Providers
* @codeCoverageIgnore
*
*/ */
class ConfigServiceProvider extends ServiceProvider class ConfigServiceProvider extends ServiceProvider
{ {
@@ -17,235 +19,13 @@ class ConfigServiceProvider extends ServiceProvider
* to overwrite any "vendor" or package configuration that you may want to * to overwrite any "vendor" or package configuration that you may want to
* modify before the application handles the incoming request / command. * modify before the application handles the incoming request / command.
* *
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @return void * @return void
*/ */
public function register() public function register()
{ {
config(
[
'twigbridge' => [
'twig' => [
/*
|--------------------------------------------------------------------------
| Extension
|--------------------------------------------------------------------------
|
| File extension for Twig view files.
|
*/
'extension' => 'twig',
/*
|--------------------------------------------------------------------------
| Accepts all Twig environment configuration options
|--------------------------------------------------------------------------
|
| http://twig.sensiolabs.org/doc/api.html#environment-options
|
*/
'environment' => [
// When set to true, the generated templates have a __toString() method
// that you can use to display the generated nodes.
// default: false
'debug' => config('app.debug', false),
// The charset used by the templates.
// default: utf-8
'charset' => 'utf-8',
// The base template class to use for generated templates.
// default: TwigBridge\Twig\Template
'base_template_class' => 'TwigBridge\Twig\Template',
// An absolute path where to store the compiled templates, or false to disable caching. If null
// then the cache file path is used.
// default: cache file storage path
'cache' => null,
// When developing with Twig, it's useful to recompile the template
// whenever the source code changes. If you don't provide a value
// for the auto_reload option, it will be determined automatically based on the debug value.
'auto_reload' => true,
// If set to false, Twig will silently ignore invalid variables
// (variables and or attributes/methods that do not exist) and
// replace them with a null value. When set to true, Twig throws an exception instead.
// default: false
'strict_variables' => false,
// If set to true, auto-escaping will be enabled by default for all templates.
// default: true
'autoescape' => true,
// A flag that indicates which optimizations to apply
// (default to -1 -- all optimizations are enabled; set it to 0 to disable)
'optimizations' => -1,
],
/*
|--------------------------------------------------------------------------
| Global variables
|--------------------------------------------------------------------------
|
| These will always be passed in and can be accessed as Twig variables.
| NOTE: these will be overwritten if you pass data into the view with the same key.
|
*/
'globals' => [],
],
'extensions' => [
/*
|--------------------------------------------------------------------------
| Extensions
|--------------------------------------------------------------------------
|
| Enabled extensions.
|
| `Twig_Extension_Debug` is enabled automatically if twig.debug is TRUE.
|
*/
'enabled' => [
'TwigBridge\Extension\Loader\Facades',
'TwigBridge\Extension\Loader\Filters',
'TwigBridge\Extension\Loader\Functions',
'TwigBridge\Extension\Laravel\Auth',
'TwigBridge\Extension\Laravel\Config',
'TwigBridge\Extension\Laravel\Dump',
'TwigBridge\Extension\Laravel\Input',
'TwigBridge\Extension\Laravel\Session',
'TwigBridge\Extension\Laravel\String',
'TwigBridge\Extension\Laravel\Translator',
'TwigBridge\Extension\Laravel\Url',
// 'TwigBridge\Extension\Laravel\Form',
// 'TwigBridge\Extension\Laravel\Html',
// 'TwigBridge\Extension\Laravel\Legacy\Facades',
],
/*
|--------------------------------------------------------------------------
| Facades
|--------------------------------------------------------------------------
|
| Available facades. Access like `{{ Config.get('foo.bar') }}`.
|
| Each facade can take an optional array of options. To mark the whole facade
| as safe you can set the option `'is_safe' => true`. Setting the facade as
| safe means that any HTML returned will not be escaped.
|
| It is advisable to not set the whole facade as safe and instead mark the
| each appropriate method as safe for security reasons. You can do that with
| the following syntax:
|
| <code>
| 'Form' => [
| 'is_safe' => [
| 'open'
| ]
| ]
| </code>
|
| The values of the `is_safe` array must match the called method on the facade
| in order to be marked as safe.
|
*/
'facades' => [
'Breadcrumbs' => [
'is_safe' => [
'renderIfExists'
]
],
'Session',
'Route',
'Auth',
'URL',
'Config',
'ExpandedForm' => [
'is_safe' => [
'date', 'text', 'select', 'balance', 'optionsList', 'checkbox', 'amount', 'tags', 'integer', 'textarea', 'location',
'multiRadio'
]
],
'Form' => [
'is_safe' => [
'input', 'select', 'checkbox', 'model', 'open', 'radio', 'textarea'
]
],
],
/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
|
| Available functions. Access like `{{ secure_url(...) }}`.
|
| Each function can take an optional array of options. These options are
| passed directly to `Twig_SimpleFunction`.
|
| So for example, to mark a function as safe you can do the following:
|
| <code>
| 'link_to' => [
| 'is_safe' => ['html']
| ]
| </code>
|
| The options array also takes a `callback` that allows you to name the
| function differently in your Twig templates than what it's actually called.
|
| <code>
| 'link' => [
| 'callback' => 'link_to'
| ]
| </code>
|
*/
'functions' => [
'elixir',
'head',
'last',
'old'
],
/*
|--------------------------------------------------------------------------
| Filters
|--------------------------------------------------------------------------
|
| Available filters. Access like `{{ variable|filter }}`.
|
| Each filter can take an optional array of options. These options are
| passed directly to `Twig_SimpleFilter`.
|
| So for example, to mark a filter as safe you can do the following:
|
| <code>
| 'studly_case' => [
| 'is_safe' => ['html']
| ]
| </code>
|
| The options array also takes a `callback` that allows you to name the
| filter differently in your Twig templates than what is actually called.
|
| <code>
| 'snake' => [
| 'callback' => 'snake_case'
| ]
| </code>
|
*/
'filters' => [],
],
]
]
);
} }
} }

View File

@@ -49,65 +49,16 @@ class EventServiceProvider extends ServiceProvider
public function boot(DispatcherContract $events) public function boot(DispatcherContract $events)
{ {
parent::boot($events); parent::boot($events);
$this->registerDeleteEvents();
TransactionJournal::deleted( $this->registerCreateEvents();
function (TransactionJournal $journal) {
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
$transaction->delete();
}
}
);
PiggyBank::deleting(
function (PiggyBank $piggyBank) {
$reminders = $piggyBank->reminders()->get();
/** @var Reminder $reminder */
foreach ($reminders as $reminder) {
$reminder->delete();
}
}
);
Account::deleted(
function (Account $account) {
/** @var Transaction $transaction */
foreach ($account->transactions()->get() as $transaction) {
$journal = $transaction->transactionJournal()->first();
$journal->delete();
}
}
);
// move this routine to a filter
// in case of repeated piggy banks and/or other problems.
PiggyBank::created(
function (PiggyBank $piggyBank) {
$repetition = new PiggyBankRepetition;
$repetition->piggyBank()->associate($piggyBank);
$repetition->startdate = is_null($piggyBank->startdate) ? null : $piggyBank->startdate;
$repetition->targetdate = is_null($piggyBank->targetdate) ? null : $piggyBank->targetdate;
$repetition->currentamount = 0;
$repetition->save();
}
);
BudgetLimit::saved( BudgetLimit::saved(
function (BudgetLimit $budgetLimit) { function(BudgetLimit $budgetLimit) {
$end = Navigation::addPeriod(clone $budgetLimit->startdate, $budgetLimit->repeat_freq, 0); $end = Navigation::addPeriod(clone $budgetLimit->startdate, $budgetLimit->repeat_freq, 0);
$end->subDay(); $end->subDay();
$set = $budgetLimit->limitrepetitions()->where('startdate', $budgetLimit->startdate->format('Y-m-d'))->where('enddate', $end->format('Y-m-d')) $set = $budgetLimit->limitrepetitions()->where('startdate', $budgetLimit->startdate->format('Y-m-d'))->where('enddate', $end->format('Y-m-d'))
->get(); ->get();
/*
* Create new LimitRepetition:
*/
if ($set->count() == 0) { if ($set->count() == 0) {
$repetition = new LimitRepetition; $repetition = new LimitRepetition;
$repetition->startdate = $budgetLimit->startdate; $repetition->startdate = $budgetLimit->startdate;
$repetition->enddate = $end; $repetition->enddate = $end;
@@ -122,9 +73,6 @@ class EventServiceProvider extends ServiceProvider
} }
} else { } else {
if ($set->count() == 1) { if ($set->count() == 1) {
/*
* Update existing one.
*/
$repetition = $set->first(); $repetition = $set->first();
$repetition->amount = $budgetLimit->amount; $repetition->amount = $budgetLimit->amount;
$repetition->save(); $repetition->save();
@@ -137,4 +85,61 @@ class EventServiceProvider extends ServiceProvider
} }
/**
*
*/
protected function registerDeleteEvents()
{
TransactionJournal::deleted(
function(TransactionJournal $journal) {
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
$transaction->delete();
}
}
);
PiggyBank::deleting(
function(PiggyBank $piggyBank) {
$reminders = $piggyBank->reminders()->get();
/** @var Reminder $reminder */
foreach ($reminders as $reminder) {
$reminder->delete();
}
}
);
Account::deleted(
function(Account $account) {
/** @var Transaction $transaction */
foreach ($account->transactions()->get() as $transaction) {
$journal = $transaction->transactionJournal()->first();
$journal->delete();
}
}
);
}
/**
*
*/
protected function registerCreateEvents()
{
// move this routine to a filter
// in case of repeated piggy banks and/or other problems.
PiggyBank::created(
function(PiggyBank $piggyBank) {
$repetition = new PiggyBankRepetition;
$repetition->piggyBank()->associate($piggyBank);
$repetition->startdate = is_null($piggyBank->startdate) ? null : $piggyBank->startdate;
$repetition->targetdate = is_null($piggyBank->targetdate) ? null : $piggyBank->targetdate;
$repetition->currentamount = 0;
$repetition->save();
}
);
}
} }

View File

@@ -10,9 +10,9 @@ use FireflyIII\Support\Preferences;
use FireflyIII\Support\Steam; use FireflyIII\Support\Steam;
use FireflyIII\Support\Twig\Budget; use FireflyIII\Support\Twig\Budget;
use FireflyIII\Support\Twig\General; use FireflyIII\Support\Twig\General;
use FireflyIII\Support\Twig\Translation;
use FireflyIII\Support\Twig\Journal; use FireflyIII\Support\Twig\Journal;
use FireflyIII\Support\Twig\PiggyBank; use FireflyIII\Support\Twig\PiggyBank;
use FireflyIII\Support\Twig\Translation;
use FireflyIII\Validation\FireflyValidator; use FireflyIII\Validation\FireflyValidator;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Twig; use Twig;
@@ -23,13 +23,14 @@ use Validator;
* Class FireflyServiceProvider * Class FireflyServiceProvider
* *
* @package FireflyIII\Providers * @package FireflyIII\Providers
* @codeCoverageIgnore
*/ */
class FireflyServiceProvider extends ServiceProvider class FireflyServiceProvider extends ServiceProvider
{ {
public function boot() public function boot()
{ {
Validator::resolver( Validator::resolver(
function ($translator, $data, $rules, $messages) { function($translator, $data, $rules, $messages) {
return new FireflyValidator($translator, $data, $rules, $messages); return new FireflyValidator($translator, $data, $rules, $messages);
} }
); );
@@ -46,33 +47,36 @@ class FireflyServiceProvider extends ServiceProvider
Twig::addExtension(new Translation); Twig::addExtension(new Translation);
} }
/**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function register() public function register()
{ {
$this->app->bind( $this->app->bind(
'preferences', function () { 'preferences', function() {
return new Preferences; return new Preferences;
} }
); );
$this->app->bind( $this->app->bind(
'navigation', function () { 'navigation', function() {
return new Navigation; return new Navigation;
} }
); );
$this->app->bind( $this->app->bind(
'amount', function () { 'amount', function() {
return new Amount; return new Amount;
} }
); );
$this->app->bind( $this->app->bind(
'steam', function () { 'steam', function() {
return new Steam; return new Steam;
} }
); );
$this->app->bind( $this->app->bind(
'expandedform', function () { 'expandedform', function() {
return new ExpandedForm; return new ExpandedForm;
} }
); );

View File

@@ -7,6 +7,7 @@ use Illuminate\Routing\Router;
* Class RouteServiceProvider * Class RouteServiceProvider
* *
* @package FireflyIII\Providers * @package FireflyIII\Providers
* @codeCoverageIgnore
*/ */
class RouteServiceProvider extends ServiceProvider class RouteServiceProvider extends ServiceProvider
{ {
@@ -43,7 +44,7 @@ class RouteServiceProvider extends ServiceProvider
public function map(Router $router) public function map(Router $router)
{ {
$router->group( $router->group(
['namespace' => $this->namespace], function ($router) { ['namespace' => $this->namespace], function($router) {
/** @noinspection PhpIncludeInspection */ /** @noinspection PhpIncludeInspection */
require app_path('Http/routes.php'); require app_path('Http/routes.php');
} }

View File

@@ -8,6 +8,7 @@ use Illuminate\Support\ServiceProvider;
/** /**
* Class TestingServiceProvider * Class TestingServiceProvider
* *
* @codeCoverageIgnore
* @package FireflyIII\Providers * @package FireflyIII\Providers
*/ */
class TestingServiceProvider extends ServiceProvider class TestingServiceProvider extends ServiceProvider

View File

@@ -25,6 +25,8 @@ use Steam;
/** /**
* @SuppressWarnings(PHPMD.TooManyMethods)
*
* Class AccountRepository * Class AccountRepository
* *
* @package FireflyIII\Repositories\Account * @package FireflyIII\Repositories\Account
@@ -62,7 +64,7 @@ class AccountRepository implements AccountRepositoryInterface
public function getAccounts(array $types) public function getAccounts(array $types)
{ {
$result = Auth::user()->accounts()->with( $result = Auth::user()->accounts()->with(
['accountmeta' => function (HasMany $query) { ['accountmeta' => function(HasMany $query) {
$query->where('name', 'accountRole'); $query->where('name', 'accountRole');
}] }]
)->accountTypeIn($types)->orderBy('accounts.name', 'ASC')->get(['accounts.*'])->sortBy('name'); )->accountTypeIn($types)->orderBy('accounts.name', 'ASC')->get(['accounts.*'])->sortBy('name');
@@ -77,15 +79,15 @@ class AccountRepository implements AccountRepositoryInterface
public function getCreditCards() public function getCreditCards()
{ {
return Auth::user()->accounts() return Auth::user()->accounts()
->hasMetaValue('accountRole', 'ccAsset') ->hasMetaValue('accountRole', 'ccAsset')
->hasMetaValue('ccType', 'monthlyFull') ->hasMetaValue('ccType', 'monthlyFull')
->get( ->get(
[ [
'accounts.*', 'accounts.*',
'ccType.data as ccType', 'ccType.data as ccType',
'accountRole.data as accountRole' 'accountRole.data as accountRole'
] ]
); );
} }
/** /**
@@ -130,18 +132,18 @@ class AccountRepository implements AccountRepositoryInterface
public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end) public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end)
{ {
return Auth::user() return Auth::user()
->transactionjournals() ->transactionjournals()
->with(['transactions']) ->with(['transactions'])
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id) ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id)
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transaction_journals.transaction_currency_id') ->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transaction_journals.transaction_currency_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->before($end) ->before($end)
->after($start) ->after($start)
->orderBy('transaction_journals.date', 'DESC') ->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC') ->orderBy('transaction_journals.id', 'DESC')
->take(10) ->take(10)
->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']); ->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']);
} }
/** /**
@@ -154,16 +156,14 @@ class AccountRepository implements AccountRepositoryInterface
{ {
$offset = ($page - 1) * 50; $offset = ($page - 1) * 50;
$query = Auth::user() $query = Auth::user()
->transactionJournals() ->transactionJournals()
->withRelevantData() ->withRelevantData()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id) ->where('transactions.account_id', $account->id)
->orderBy('transaction_journals.date', 'DESC') ->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC') ->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC'); ->orderBy('transaction_journals.id', 'DESC');
$query->before(Session::get('end', Carbon::now()->endOfMonth()));
$query->after(Session::get('start', Carbon::now()->startOfMonth()));
$count = $query->count(); $count = $query->count();
$set = $query->take(50)->offset($offset)->get(['transaction_journals.*']); $set = $query->take(50)->offset($offset)->get(['transaction_journals.*']);
$paginator = new LengthAwarePaginator($set, $count, 50, $page); $paginator = new LengthAwarePaginator($set, $count, 50, $page);
@@ -213,7 +213,7 @@ class AccountRepository implements AccountRepositoryInterface
} }
$accounts->each( $accounts->each(
function (Account $account) use ($start, $end) { function(Account $account) use ($start, $end) {
$account->startBalance = Steam::balance($account, $start, true); $account->startBalance = Steam::balance($account, $start, true);
$account->endBalance = Steam::balance($account, $end, true); $account->endBalance = Steam::balance($account, $end, true);
$account->piggyBalance = 0; $account->piggyBalance = 0;
@@ -251,7 +251,7 @@ class AccountRepository implements AccountRepositoryInterface
$end = clone Session::get('end', new Carbon); $end = clone Session::get('end', new Carbon);
$accounts->each( $accounts->each(
function (Account $account) use ($start, $end) { function(Account $account) use ($start, $end) {
$account->startBalance = Steam::balance($account, $start); $account->startBalance = Steam::balance($account, $start);
$account->endBalance = Steam::balance($account, $end); $account->endBalance = Steam::balance($account, $end);
@@ -289,31 +289,42 @@ class AccountRepository implements AccountRepositoryInterface
*/ */
public function getTransfersInRange(Account $account, Carbon $start, Carbon $end) public function getTransfersInRange(Account $account, Carbon $start, Carbon $end)
{ {
return TransactionJournal::whereIn( $set = TransactionJournal::whereIn(
'id', function (Builder $q) use ($account, $start, $end) { 'id', function(Builder $q) use ($account, $start, $end) {
$q->select('transaction_journals.id') $q->select('transaction_journals.id')
->from('transactions') ->from('transactions')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id') ->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->where('transactions.account_id', $account->id) ->where('transactions.account_id', $account->id)
->where('transaction_journals.user_id', Auth::user()->id) ->where('transaction_journals.user_id', Auth::user()->id)
->where('transaction_journals.date', '>=', $start->format('Y-m-d')) ->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d')) ->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transactions.amount', '>', 0) ->where('transaction_types.type', 'Transfer');
->where('transaction_types.type', 'Transfer');
} }
)->get(); )->get();
$filtered = $set->filter(
function(TransactionJournal $journal) use ($account) {
if ($journal->destination_account->id == $account->id) {
return $journal;
}
return null;
}
);
return $filtered;
} }
/** /**
* @param Account $account * @param Account $account
* @param Carbon $date
* *
* @return float * @return float
*/ */
public function leftOnAccount(Account $account) public function leftOnAccount(Account $account, Carbon $date)
{ {
$balance = Steam::balance($account, null, true);
$balance = Steam::balance($account, $date, true);
/** @var PiggyBank $p */ /** @var PiggyBank $p */
foreach ($account->piggybanks()->get() as $p) { foreach ($account->piggybanks()->get() as $p) {
$balance -= $p->currentRelevantRep()->currentamount; $balance -= $p->currentRelevantRep()->currentamount;
@@ -331,15 +342,15 @@ class AccountRepository implements AccountRepositoryInterface
public function openingBalanceTransaction(Account $account) public function openingBalanceTransaction(Account $account)
{ {
return TransactionJournal::accountIs($account) return TransactionJournal::accountIs($account)
->orderBy('transaction_journals.date', 'ASC') ->orderBy('transaction_journals.date', 'ASC')
->orderBy('created_at', 'ASC') ->orderBy('created_at', 'ASC')
->first(['transaction_journals.*']); ->first(['transaction_journals.*']);
} }
/** /**
* @param array $data * @param array $data
* *
* @return Account; * @return Account
*/ */
public function store(array $data) public function store(array $data)
{ {
@@ -357,7 +368,7 @@ class AccountRepository implements AccountRepositoryInterface
'name' => $data['name'] . ' initial balance', 'name' => $data['name'] . ' initial balance',
'active' => false, 'active' => false,
]; ];
$opposing = $this->storeAccount($opposingData); $opposing = $this->storeAccount($opposingData);
$this->storeInitialBalance($newAccount, $opposing, $data); $this->storeInitialBalance($newAccount, $opposing, $data);
} }
@@ -390,7 +401,6 @@ class AccountRepository implements AccountRepositoryInterface
// update meta data: // update meta data:
$this->updateMetadata($account, $data); $this->updateMetadata($account, $data);
$openingBalance = $this->openingBalanceTransaction($account); $openingBalance = $this->openingBalanceTransaction($account);
// if has openingbalance? // if has openingbalance?
@@ -408,15 +418,13 @@ class AccountRepository implements AccountRepositoryInterface
'name' => $data['name'] . ' initial balance', 'name' => $data['name'] . ' initial balance',
'active' => false, 'active' => false,
]; ];
$opposing = $this->storeAccount($opposingData); $opposing = $this->storeAccount($opposingData);
$this->storeInitialBalance($account, $opposing, $data); $this->storeInitialBalance($account, $opposing, $data);
} }
} else { } else {
// opening balance is zero, should we delete it? if ($openingBalance) { // opening balance is zero, should we delete it?
if ($openingBalance) { $openingBalance->delete(); // delete existing opening balance.
// delete existing opening balance.
$openingBalance->delete();
} }
} }
@@ -443,7 +451,7 @@ class AccountRepository implements AccountRepositoryInterface
if (!$newAccount->isValid()) { if (!$newAccount->isValid()) {
// does the account already exist? // does the account already exist?
$searchData = [ $searchData = [
'user_id' => $data['user'], 'user_id' => $data['user'],
'account_type_id' => $accountType->id, 'account_type_id' => $accountType->id,
'name' => $data['name'] 'name' => $data['name']

View File

@@ -115,10 +115,11 @@ interface AccountRepositoryInterface
/** /**
* @param Account $account * @param Account $account
* @param Carbon $date
* *
* @return float * @return float
*/ */
public function leftOnAccount(Account $account); public function leftOnAccount(Account $account, Carbon $date);
/** /**
* @param Account $account * @param Account $account

View File

@@ -5,14 +5,10 @@ namespace FireflyIII\Repositories\Bill;
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use DB; use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Log;
use Navigation; use Navigation;
/** /**
@@ -22,6 +18,27 @@ use Navigation;
*/ */
class BillRepository implements BillRepositoryInterface class BillRepository implements BillRepositoryInterface
{ {
/**
* Returns the sum of all payments connected to this bill between the dates.
*
* @param Bill $bill
* @param Carbon $start
* @param Carbon $end
*
* @return integer
*/
public function billPaymentsInRange(Bill $bill, Carbon $start, Carbon $end)
{
$amount = 0;
$journals = $bill->transactionjournals()->before($end)->after($start)->get();
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$amount += $journal->amount;
}
return $amount;
}
/** /**
* Create a fake bill to help the chart controller. * Create a fake bill to help the chart controller.
* *
@@ -50,7 +67,7 @@ class BillRepository implements BillRepositoryInterface
/** /**
* @param Bill $bill * @param Bill $bill
* *
* @return mixed * @return boolean|null
*/ */
public function destroy(Bill $bill) public function destroy(Bill $bill)
{ {
@@ -87,16 +104,10 @@ class BillRepository implements BillRepositoryInterface
public function getJournals(Bill $bill) public function getJournals(Bill $bill)
{ {
return $bill->transactionjournals()->withRelevantData() return $bill->transactionjournals()->withRelevantData()
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.amount', '>', 0);
}
)
->orderBy('transaction_journals.date', 'DESC') ->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC') ->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC') ->orderBy('transaction_journals.id', 'DESC')
->get(['transaction_journals.*', 'transactions.amount']); ->get(['transaction_journals.*']);
} }
/** /**
@@ -198,7 +209,7 @@ class BillRepository implements BillRepositoryInterface
/** /**
* @param Bill $bill * @param Bill $bill
* *
* @return Carbon * @return \Carbon\Carbon
*/ */
public function nextExpectedMatch(Bill $bill) public function nextExpectedMatch(Bill $bill)
{ {
@@ -230,7 +241,7 @@ class BillRepository implements BillRepositoryInterface
$end = Navigation::endOfPeriod(clone $start, $bill->repeat_freq); $end = Navigation::endOfPeriod(clone $start, $bill->repeat_freq);
$journalCount = $bill->transactionjournals()->before($end)->after($start)->count(); $journalCount = $bill->transactionjournals()->before($end)->after($start)->count();
if ($journalCount == 0) { if ($journalCount == 0) {
$finalDate = clone $start; $finalDate = new Carbon($start->format('Y-m-d'));
break; break;
} }
} }
@@ -247,37 +258,15 @@ class BillRepository implements BillRepositoryInterface
* @param Bill $bill * @param Bill $bill
* @param TransactionJournal $journal * @param TransactionJournal $journal
* *
* @return bool * @return boolean|null
*/ */
public function scan(Bill $bill, TransactionJournal $journal) public function scan(Bill $bill, TransactionJournal $journal)
{ {
/* $amountMatch = false;
* Match words.
*/
$wordMatch = false; $wordMatch = false;
$matches = explode(',', $bill->match); $matches = explode(',', $bill->match);
$description = strtolower($journal->description); $description = strtolower($journal->description) . ' ' . strtolower($journal->expense_account->name);
Log::debug('Now scanning ' . $description); $count = 0;
/*
* Attach expense account to description for more narrow matching.
*/
$transactions = $journal->transactions()->get();
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
/** @var Account $account */
$account = $transaction->account()->first();
/** @var AccountType $type */
$type = $account->accountType()->first();
if ($type->type == 'Expense account' || $type->type == 'Beneficiary account') {
$description .= ' ' . strtolower($account->name);
}
}
Log::debug('Final description: ' . $description);
Log::debug('Matches searched: ' . join(':', $matches));
$count = 0;
foreach ($matches as $word) { foreach ($matches as $word) {
if (!(strpos($description, strtolower($word)) === false)) { if (!(strpos($description, strtolower($word)) === false)) {
$count++; $count++;
@@ -285,38 +274,24 @@ class BillRepository implements BillRepositoryInterface
} }
if ($count >= count($matches)) { if ($count >= count($matches)) {
$wordMatch = true; $wordMatch = true;
Log::debug('word match is true');
} else {
Log::debug('Count: ' . $count . ', count(matches): ' . count($matches));
} }
/* /*
* Match amount. * Match amount.
*/ */
if ($journal->amount >= $bill->amount_min && $journal->amount <= $bill->amount_max) {
$amountMatch = false; $amountMatch = true;
if (count($transactions) > 1) {
$amount = max(floatval($transactions[0]->amount), floatval($transactions[1]->amount));
$min = floatval($bill->amount_min);
$max = floatval($bill->amount_max);
if ($amount >= $min && $amount <= $max) {
$amountMatch = true;
Log::debug('Amount match is true!');
}
} }
/* /*
* If both, update! * If both, update!
*/ */
if ($wordMatch && $amountMatch) { if ($wordMatch && $amountMatch) {
Log::debug('TOTAL match is true!');
$journal->bill()->associate($bill); $journal->bill()->associate($bill);
$journal->save(); $journal->save();
} else { } else {
if ((!$wordMatch || !$amountMatch) && $bill->id == $journal->bill_id) { if ($bill->id == $journal->bill_id) {
// if no match, but bill used to match, remove it: // if no match, but bill used to match, remove it:
$journal->bill_id = null; $journal->bill_id = null;
$journal->save(); $journal->save();
@@ -356,7 +331,7 @@ class BillRepository implements BillRepositoryInterface
* @param Bill $bill * @param Bill $bill
* @param array $data * @param array $data
* *
* @return Bill|static * @return Bill
*/ */
public function update(Bill $bill, array $data) public function update(Bill $bill, array $data)
{ {

View File

@@ -15,6 +15,17 @@ use Illuminate\Support\Collection;
interface BillRepositoryInterface interface BillRepositoryInterface
{ {
/**
* Returns the sum of all payments connected to this bill between the dates.
*
* @param Bill $bill
* @param Carbon $start
* @param Carbon $end
*
* @return float
*/
public function billPaymentsInRange(Bill $bill, Carbon $start, Carbon $end);
/** /**
* Create a fake bill to help the chart controller. * Create a fake bill to help the chart controller.
* *
@@ -92,7 +103,7 @@ interface BillRepositoryInterface
/** /**
* @param Bill $bill * @param Bill $bill
* *
* @return Carbon|null * @return \Carbon\Carbon
*/ */
public function nextExpectedMatch(Bill $bill); public function nextExpectedMatch(Bill $bill);

View File

@@ -8,6 +8,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\LimitRepetition;
use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Input; use Input;
@@ -48,9 +49,11 @@ class BudgetRepository implements BudgetRepositoryInterface
* *
* @return float * @return float
*/ */
public function expensesOnDay(Budget $budget, Carbon $date) public function expensesOnDayCorrected(Budget $budget, Carbon $date)
{ {
return floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($date)->sum('amount')); $sum = floatval($budget->transactionjournals()->transactionTypes(['Withdrawal'])->onDate($date)->get(['transaction_journals.*'])->sum('amount'));
return $sum * -1;
} }
/** /**
@@ -76,10 +79,10 @@ class BudgetRepository implements BudgetRepositoryInterface
/** @var Collection $repetitions */ /** @var Collection $repetitions */
return LimitRepetition:: return LimitRepetition::
leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00')) ->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00'))
->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00')) ->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00'))
->where('budget_limits.budget_id', $budget->id) ->where('budget_limits.budget_id', $budget->id)
->get(['limit_repetitions.*']); ->get(['limit_repetitions.*']);
} }
/** /**
@@ -98,7 +101,6 @@ class BudgetRepository implements BudgetRepositoryInterface
public function getBudgets() public function getBudgets()
{ {
$budgets = Auth::user()->budgets()->get(); $budgets = Auth::user()->budgets()->get();
$budgets->sortBy('name');
return $budgets; return $budgets;
} }
@@ -144,7 +146,7 @@ class BudgetRepository implements BudgetRepositoryInterface
* @param LimitRepetition $repetition * @param LimitRepetition $repetition
* @param int $take * @param int $take
* *
* @return \Illuminate\Pagination\Paginator * @return LengthAwarePaginator
*/ */
public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50) public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50)
{ {
@@ -152,9 +154,9 @@ class BudgetRepository implements BudgetRepositoryInterface
$setQuery = $budget->transactionJournals()->withRelevantData()->take($take)->offset($offset) $setQuery = $budget->transactionJournals()->withRelevantData()->take($take)->offset($offset)
->orderBy('transaction_journals.date', 'DESC') ->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC') ->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC'); ->orderBy('transaction_journals.id', 'DESC');
$countQuery = $budget->transactionJournals(); $countQuery = $budget->transactionJournals();
@@ -194,9 +196,9 @@ class BudgetRepository implements BudgetRepositoryInterface
public function getLimitAmountOnDate(Budget $budget, Carbon $date) public function getLimitAmountOnDate(Budget $budget, Carbon $date)
{ {
$repetition = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') $repetition = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->where('limit_repetitions.startdate', $date->format('Y-m-d 00:00:00')) ->where('limit_repetitions.startdate', $date->format('Y-m-d 00:00:00'))
->where('budget_limits.budget_id', $budget->id) ->where('budget_limits.budget_id', $budget->id)
->first(['limit_repetitions.*']); ->first(['limit_repetitions.*']);
if ($repetition) { if ($repetition) {
return floatval($repetition->amount); return floatval($repetition->amount);
@@ -214,58 +216,76 @@ class BudgetRepository implements BudgetRepositoryInterface
public function getWithoutBudget(Carbon $start, Carbon $end) public function getWithoutBudget(Carbon $start, Carbon $end)
{ {
return Auth::user() return Auth::user()
->transactionjournals() ->transactionjournals()
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->whereNull('budget_transaction_journal.id') ->whereNull('budget_transaction_journal.id')
->before($end) ->before($end)
->after($start) ->after($start)
->orderBy('transaction_journals.date', 'DESC') ->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC') ->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC') ->orderBy('transaction_journals.id', 'DESC')
->get(['transaction_journals.*']); ->get(['transaction_journals.*']);
} }
/** /**
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @return mixed * @return double
*/ */
public function getWithoutBudgetSum(Carbon $start, Carbon $end) public function getWithoutBudgetSum(Carbon $start, Carbon $end)
{ {
$noBudgetSet = Auth::user() $noBudgetSet = Auth::user()
->transactionjournals() ->transactionjournals()
->whereNotIn( ->whereNotIn(
'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) { 'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) {
$query $query
->select('transaction_journals.id') ->select('transaction_journals.id')
->from('transaction_journals') ->from('transaction_journals')
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id') ->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00')) ->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00')) ->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'))
->whereNotNull('budget_transaction_journal.budget_id'); ->whereNotNull('budget_transaction_journal.budget_id');
} }
) )
->after($start) ->after($start)
->before($end) ->before($end)
->lessThan(0) ->transactionTypes(['Withdrawal'])
->transactionTypes(['Withdrawal']) ->get(['transaction_journals.*'])->sum('amount');
->sum('transactions.amount');
return floatval($noBudgetSet) * -1; return floatval($noBudgetSet) * -1;
} }
/** /**
* @param Budget $budget * @param Budget $budget
* @param Carbon $date * @param Carbon $start
* @param Carbon $end
* @param bool $shared
* *
* @return float * @return float
*/ */
public function spentInMonth(Budget $budget, Carbon $date) public function spentInPeriodCorrected(Budget $budget, Carbon $start, Carbon $end, $shared = true)
{ {
$end = clone $date; if ($shared === true) {
$date->startOfMonth(); // get everything:
$end->endOfMonth(); $sum = floatval($budget->transactionjournals()->before($end)->after($start)->get(['transaction_journals.*'])->sum('amount'));
$sum = floatval($budget->transactionjournals()->before($end)->after($date)->lessThan(0)->sum('amount')) * -1; } else {
// get all journals in this month where the asset account is NOT shared.
$sum = $budget->transactionjournals()
->before($end)
->after($start)
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->where('account_meta.data', '!=', '"sharedAsset"')
->get(['transaction_journals.*'])
->sum('amount');
$sum = floatval($sum);
}
return $sum; return $sum;
} }
@@ -288,17 +308,6 @@ class BudgetRepository implements BudgetRepositoryInterface
return $newBudget; return $newBudget;
} }
/**
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return float
*/
public function sumBudgetExpensesInPeriod(Budget $budget, $start, $end)
{
return floatval($budget->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
}
/** /**
* @param Budget $budget * @param Budget $budget
@@ -321,7 +330,7 @@ class BudgetRepository implements BudgetRepositoryInterface
* @param Carbon $date * @param Carbon $date
* @param $amount * @param $amount
* *
* @return LimitRepetition|null * @return BudgetLimit
*/ */
public function updateLimitAmount(Budget $budget, Carbon $date, $amount) public function updateLimitAmount(Budget $budget, Carbon $date, $amount)
{ {

View File

@@ -5,6 +5,7 @@ namespace FireflyIII\Repositories\Budget;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\LimitRepetition;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**
@@ -27,12 +28,14 @@ interface BudgetRepositoryInterface
public function destroy(Budget $budget); public function destroy(Budget $budget);
/** /**
* Takes tags into account.
*
* @param Budget $budget * @param Budget $budget
* @param Carbon $date * @param Carbon $date
* *
* @return float * @return float
*/ */
public function expensesOnDay(Budget $budget, Carbon $date); public function expensesOnDayCorrected(Budget $budget, Carbon $date);
/** /**
* @return Collection * @return Collection
@@ -87,7 +90,7 @@ interface BudgetRepositoryInterface
* @param LimitRepetition $repetition * @param LimitRepetition $repetition
* @param int $take * @param int $take
* *
* @return \Illuminate\Pagination\Paginator * @return LengthAwarePaginator
*/ */
public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50); public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50);
@@ -123,12 +126,17 @@ interface BudgetRepositoryInterface
public function getWithoutBudgetSum(Carbon $start, Carbon $end); public function getWithoutBudgetSum(Carbon $start, Carbon $end);
/** /**
* @param Budget $budget *
* @param Carbon $date * Same as ::spentInPeriod but corrects journals for their amount (tags).
*
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
* @param boolean $shared
* *
* @return float * @return float
*/ */
public function spentInMonth(Budget $budget, Carbon $date); public function spentInPeriodCorrected(Budget $budget, Carbon $start, Carbon $end, $shared = true);
/** /**
* @param array $data * @param array $data
@@ -137,15 +145,6 @@ interface BudgetRepositoryInterface
*/ */
public function store(array $data); public function store(array $data);
/**
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return float
*/
public function sumBudgetExpensesInPeriod(Budget $budget, $start, $end);
/** /**
* @param Budget $budget * @param Budget $budget
* @param array $data * @param array $data

Some files were not shown because too many files have changed in this diff Show More