Compare commits

...

312 Commits
3.5.3 ... 3.6.1

Author SHA1 Message Date
James Cole
dfc95cee45 Merge branch 'release/3.6.1' 2016-01-09 14:31:25 +01:00
James Cole
fdca234721 New composer lock file. 2016-01-09 14:31:17 +01:00
James Cole
cf5cc626d7 Important bug fix. 2016-01-09 14:27:35 +01:00
James Cole
358d9aac7d New version. 2016-01-09 14:27:17 +01:00
James Cole
feef6a1756 Merge branch 'release/3.6.0' into develop 2016-01-07 10:22:18 +01:00
James Cole
5f299b895b Merge branch 'release/3.6.0' 2016-01-07 10:22:17 +01:00
James Cole
4e1bb5fbac Update read me, composer 2016-01-07 10:21:57 +01:00
James Cole
47ccc513ad New version. 2016-01-07 10:11:37 +01:00
James Cole
cce1a01936 Update composer.lock 2016-01-07 10:10:52 +01:00
James Cole
6f2b1a6a76 The Sendgrid cron does not belong in Firefly. 2016-01-06 15:20:21 +01:00
James Cole
8526907f50 Expand multi-year report. 2016-01-05 21:23:58 +01:00
James Cole
bc192a8e54 Merge pull request #138 from leander091/develop
String is a reserved class name in php 7.
2016-01-03 20:25:34 +01:00
leander091
9ff6f8fc52 String is a reserved class name in php7 changed to Str according to the upstream project 2016-01-03 15:52:12 +01:00
James Cole
6573bd6b4b Code cleanup according to PHPStorm. 2016-01-02 19:33:44 +01:00
James Cole
9dc3f614af Localised date 2016-01-02 16:59:36 +01:00
James Cole
3888b8cceb Code cleanup according to PHPStorm. 2016-01-02 16:57:31 +01:00
James Cole
294df4a2b3 Simplified some code. 2016-01-02 16:32:08 +01:00
James Cole
265dd37212 Cleanup and add various warnings. 2016-01-02 16:31:14 +01:00
James Cole
eb7c79ad27 Can be written to. 2016-01-02 09:47:01 +01:00
James Cole
de111c7100 Fix broken route. 2016-01-01 21:59:19 +01:00
James Cole
e892c9a824 Followed up on some inspections. 2016-01-01 21:49:27 +01:00
James Cole
5eb0e18cae Cleaning up 2016-01-01 21:15:03 +01:00
James Cole
27cabb398e More queries filtered. 2016-01-01 21:07:15 +01:00
James Cole
64dbb14241 Method no longer used. 2016-01-01 20:05:14 +01:00
James Cole
bb4e2be9eb Method no longer used. 2016-01-01 20:04:44 +01:00
James Cole
7d1de0da17 Method no longer used. 2016-01-01 20:02:01 +01:00
James Cole
bf16c9a42b Method no longer used. 2016-01-01 20:01:07 +01:00
James Cole
1a7b1ce499 Method no longer used. 2016-01-01 20:00:20 +01:00
James Cole
efc9bc71a7 Method no longer used. 2016-01-01 19:58:31 +01:00
James Cole
fc5b315af0 Method no longer used. 2016-01-01 19:58:05 +01:00
James Cole
7a4a78628d Method no longer used. 2016-01-01 19:57:23 +01:00
James Cole
d16fb30a62 Method no longer used. 2016-01-01 19:56:23 +01:00
James Cole
2d177e660e Method no longer used. 2016-01-01 19:55:47 +01:00
James Cole
2f131dc170 Method no longer used. 2016-01-01 19:55:00 +01:00
James Cole
94810e371a Enable bill report. 2016-01-01 19:52:55 +01:00
James Cole
59731878f6 Month report optimised. 2016-01-01 19:46:12 +01:00
James Cole
54ede8aa18 Code cleanup. 2016-01-01 13:54:23 +01:00
James Cole
b415b6b043 Some code cleanup. 2016-01-01 12:41:00 +01:00
James Cole
70c922cdc5 Code cleanup. 2016-01-01 11:32:08 +01:00
James Cole
068fc32cb2 Some query cleaning up. 2015-12-31 20:12:49 +01:00
James Cole
3dcdacc3b8 Cleared lots of queries. In some cases, from 1400 back to 300. And those 300 have a different cause which is next. 2015-12-31 17:46:34 +01:00
James Cole
a6594358d8 Use a lot less queries 2015-12-31 17:20:54 +01:00
James Cole
f98921da46 Optimised summary chart. 2015-12-31 08:36:01 +01:00
James Cole
25747fbcf2 And optimised another chart. Amounts are slightly different. Will investigate 2015-12-31 08:31:28 +01:00
James Cole
aac5c2b13c Optimised another chart. 2015-12-31 08:26:04 +01:00
James Cole
cc810a5b6f Renamed a chart to be more consistent with the others. 2015-12-31 07:54:11 +01:00
James Cole
1b3592d959 Optimise chart. 2015-12-31 07:49:19 +01:00
James Cole
d75614e9a7 Optimised two charts, cleaned up some code. 2015-12-30 16:42:09 +01:00
James Cole
08703e282f Fix array. 2015-12-30 09:30:06 +01:00
James Cole
2904baf44e From 1100+ queries to a steady 6. 2015-12-30 09:17:29 +01:00
James Cole
f99e46bf75 Removed for-loop in favour of "pluck()" aka: RTFM. 2015-12-30 09:17:14 +01:00
James Cole
9f87890ead Removed for-loop in favour of "pluck()" aka: RTFM. 2015-12-30 09:17:05 +01:00
James Cole
638184cf66 Removed for-loop in favour of "pluck()" aka: RTFM. 2015-12-30 09:16:58 +01:00
James Cole
03babfe75c Removed for-loop in favour of "pluck()" aka: RTFM. 2015-12-30 09:16:53 +01:00
James Cole
238ed3c788 Rename a method. 2015-12-30 08:25:38 +01:00
James Cole
6a9d931ba3 More code cleanup. 2015-12-30 08:21:11 +01:00
James Cole
a3d2a9e00b Some cleaning up, and I hope simplification. 2015-12-30 08:15:04 +01:00
James Cole
39b88e8207 Added an alias to make methods more readable. 2015-12-30 08:00:52 +01:00
James Cole
449c6dfde5 Bind new class. 2015-12-29 22:51:31 +01:00
James Cole
7cc47ca0b1 Some cleaning up. 2015-12-29 22:48:55 +01:00
James Cole
95f4a83f41 Split category repository into two repositories. One for database calls for single categories, the other pertaining all categories. 2015-12-29 22:44:13 +01:00
James Cole
35154dc7a3 Another chart optimised 2015-12-29 18:55:30 +01:00
James Cole
0fd0d7d080 Less queries for category frontpage chart. 2015-12-29 10:08:40 +01:00
James Cole
658265c938 Optimised whole budget chart to use less queries. 2015-12-29 08:45:43 +01:00
James Cole
38fe9e7e1c Optimised chart. 2015-12-29 08:27:13 +01:00
James Cole
77056dcf8d Cleanup. 2015-12-29 08:27:05 +01:00
James Cole
026683a8e1 Made reportType camelCase. 2015-12-28 20:04:54 +01:00
James Cole
6ab6dd6ac3 First attempt at optimised query for multi-year budget chart. 2015-12-28 19:56:28 +01:00
James Cole
83de3482ce Optimised budget year chart. 2015-12-28 17:57:03 +01:00
James Cole
919a35aed3 Merge branch 'release/3.5.6.1' 2015-12-28 16:53:45 +01:00
James Cole
ad3defb071 Merge branch 'release/3.5.6.1' into develop 2015-12-28 16:53:45 +01:00
James Cole
9c929ecd1b New release. 2015-12-28 16:53:30 +01:00
James Cole
f79c9f7cf1 Cleanup. 2015-12-28 16:52:28 +01:00
James Cole
8e75c345d9 Found a bug that requires a new release of FF3 to fix. 2015-12-28 16:52:21 +01:00
James Cole
44886d9aad Merge branch 'release/3.5.6' into develop 2015-12-28 08:07:44 +01:00
James Cole
c2d444347d Merge branch 'release/3.5.6' 2015-12-28 08:07:43 +01:00
James Cole
5cb497596d New release. 2015-12-28 08:07:26 +01:00
James Cole
1857469d2f Removed unused parameters 2015-12-28 08:00:42 +01:00
James Cole
ea71b4843d Formatting fix in chart. 2015-12-28 07:58:40 +01:00
James Cole
97727e2e3d Some code cleanup courtesy of phpstorm. 2015-12-28 07:55:09 +01:00
James Cole
f81e7da8bb Code cleanup. 2015-12-28 07:49:27 +01:00
James Cole
8e827bf83b Removed parameter. 2015-12-28 07:43:57 +01:00
James Cole
9e1fa284ca Update php doc. 2015-12-28 07:43:05 +01:00
James Cole
3bf800be6e null check. 2015-12-28 07:41:44 +01:00
James Cole
635b9f9dba instance check. 2015-12-28 07:39:48 +01:00
James Cole
52a0d7cf7b Clean up code. 2015-12-28 07:38:02 +01:00
James Cole
a34516932b Rename include advised by scrutinizer. 2015-12-28 07:35:09 +01:00
James Cole
929a2a30a2 Fix TODO. 2015-12-28 07:31:48 +01:00
James Cole
ffa88eeb08 Made deleted piggy banks for piggy bank events visible. 2015-12-28 07:27:16 +01:00
James Cole
51b45b4ed4 Code cleanup. 2015-12-28 07:12:47 +01:00
James Cole
f263844793 Fix a bug where you cannot edit transactions. Will warrant a new release of FF. 2015-12-28 07:12:12 +01:00
James Cole
18c46df9aa Fix negative amounts and chart names. 2015-12-27 21:26:44 +01:00
James Cole
15846e157b From 200+ queries back to ~17. 2015-12-27 21:17:04 +01:00
James Cole
bc59f2db0d Optimised queries. 2015-12-27 20:07:49 +01:00
James Cole
cd2be8c1a4 Activate caching. 2015-12-27 19:51:20 +01:00
James Cole
f958115c50 Update composer file. 2015-12-27 17:57:32 +01:00
James Cole
e7d677bfb6 Add rounding, so the number will be a float. 2015-12-27 17:34:31 +01:00
James Cole
3e80ffc52b Huge change to bills and paid/unpaid/cc boxes. 2015-12-27 17:29:41 +01:00
James Cole
d0c7a5c076 Optimised query. 2015-12-27 09:44:12 +01:00
James Cole
f3f4e6b354 Stops date from skipping ahead slowly. 2015-12-27 09:40:28 +01:00
James Cole
5a45b25614 Merge branch 'hotfix/chart-fix' 2015-12-27 09:35:41 +01:00
James Cole
0b5ee1edfc Merge branch 'hotfix/chart-fix' into develop 2015-12-27 09:35:41 +01:00
James Cole
da3dc599f9 Fix chart call. 2015-12-27 09:35:24 +01:00
James Cole
f013b435ab Merge branch 'release/3.5.5' 2015-12-27 08:58:36 +01:00
James Cole
5f6975a113 Merge branch 'release/3.5.5' into develop 2015-12-27 08:58:36 +01:00
James Cole
c5dee29e4b New version. 2015-12-27 08:58:25 +01:00
James Cole
633ee02f13 Remove old Google references 2015-12-27 08:57:51 +01:00
James Cole
6b750c909a Fix forgotten call in bill repository. 2015-12-27 08:39:41 +01:00
James Cole
5f8b6640a9 A lot less queries thanks to efficient query. 2015-12-27 08:39:29 +01:00
James Cole
dd42d8437c Removed code for unused chart. 2015-12-27 08:12:46 +01:00
James Cole
67a178591d Some query optimisations. 2015-12-27 07:59:00 +01:00
James Cole
f5e5659c1f Code cleanup. 2015-12-26 09:40:24 +01:00
James Cole
8b0f0fb615 Optimise queries. 2015-12-26 09:39:35 +01:00
James Cole
209116e766 Query optimisations. 2015-12-26 09:21:45 +01:00
James Cole
79392ab656 Add caching to various queries and lists. 2015-12-26 08:44:34 +01:00
James Cole
3ca1207231 #135 2015-12-26 08:24:41 +01:00
James Cole
cec1b147f2 #135 2015-12-26 08:23:52 +01:00
James Cole
46cfcfa3e7 Update admin template. 2015-12-26 08:22:48 +01:00
James Cole
b833e8dfa2 #135 2015-12-26 08:16:30 +01:00
James Cole
77b843efd8 #135 2015-12-26 08:15:22 +01:00
James Cole
db72ad7c60 Issue #135 2015-12-26 08:12:51 +01:00
James Cole
eadc630fcb #135 2015-12-26 08:12:44 +01:00
James Cole
170c1793cc #135 2015-12-26 08:06:34 +01:00
James Cole
9f7c6c2d0c Extra cache. 2015-12-25 17:11:55 +01:00
James Cole
72d054c55c Add support for virtual balance currency, even though it cannot be stored yet. 2015-12-25 17:10:04 +01:00
James Cole
524edfe7c2 Better formatting (will take currency into account). 2015-12-25 16:40:27 +01:00
James Cole
c25c5623d2 Fixed the currency dropdown when multiple fields present on single page. 2015-12-25 16:38:53 +01:00
James Cole
4f38b77ef6 Better caching. 2015-12-25 09:34:37 +01:00
James Cole
5862803434 This saves some queries. 2015-12-25 09:34:23 +01:00
James Cole
5b3beded39 I can't believe I left this here all this time. 2015-12-25 07:58:19 +01:00
James Cole
c61fb7a598 Marked some unused stuff as deprecated. 2015-12-25 07:52:56 +01:00
James Cole
33d9148029 Make sure charts are cached. 2015-12-25 07:43:34 +01:00
James Cole
63969f5a33 Same routine but for money spent on accounts. 2015-12-25 07:42:00 +01:00
James Cole
edde18aeef Remove old chart. 2015-12-25 07:32:56 +01:00
James Cole
657116d361 Display new chart. 2015-12-25 07:32:03 +01:00
James Cole
e16269daa8 Collect data for new chart. 2015-12-25 07:31:54 +01:00
James Cole
c07591ff5c New method, earnedForAccounts 2015-12-25 07:31:43 +01:00
James Cole
75a478ad54 New chart, earned in period. 2015-12-25 07:31:29 +01:00
James Cole
8dae8b1a7f More code. Forgot to push. 2015-12-24 16:59:38 +01:00
James Cole
15fd8cf486 Completed the renaming of some methods. 2015-12-24 10:27:45 +01:00
James Cole
55333156ac Better cache control for some charts. 2015-12-24 10:14:01 +01:00
James Cole
8cdcba3231 Original fix in place. #133 2015-12-24 09:50:28 +01:00
James Cole
8bab9e84e2 Should not have edited that code. #133 2015-12-24 09:50:16 +01:00
James Cole
2faae83912 Include empty budgets. #133 2015-12-24 09:47:44 +01:00
James Cole
5a61a11a61 Attempt to fix bug #133 2015-12-24 09:45:21 +01:00
James Cole
a6d71988f2 Replaced some language calls. 2015-12-24 08:35:08 +01:00
James Cole
7069e242ae Removed useless entry. 2015-12-24 08:20:59 +01:00
James Cole
56ee830558 Moved locale information from the language to the translation files. 2015-12-24 08:20:47 +01:00
James Cole
6dd12729e6 Small disclaimer in readme. 2015-12-24 08:20:19 +01:00
James Cole
14a48303cb Cleanup. 2015-12-23 11:32:50 +01:00
James Cole
72cf6c9c0f Removed old route. 2015-12-23 11:32:41 +01:00
James Cole
144ee6b8ca Updated read me. 2015-12-23 10:38:42 +01:00
James Cole
8967d86da6 Updated language files. 2015-12-23 09:34:23 +01:00
James Cole
18c6edbb5d Update language files. 2015-12-23 09:09:51 +01:00
James Cole
53de3c4717 Merge branch 'develop' of https://github.com/JC5/firefly-iii into develop
* 'develop' of https://github.com/JC5/firefly-iii:
  Fix a bug where the frontpage would not honor transaction order.
  Fix a bug where the report page would mess up the session dates.
2015-12-22 20:46:52 +01:00
James Cole
ad577e4e81 Expand language files. 2015-12-22 20:46:16 +01:00
James Cole
44811a3e7c Fix a bug where the frontpage would not honor transaction order. 2015-12-21 11:30:58 +01:00
James Cole
1ab3f05b3a Fix a bug where the report page would mess up the session dates. 2015-12-21 10:25:57 +01:00
James Cole
5e76488ae7 Better localisation in charts. 2015-12-20 08:40:58 +01:00
James Cole
32771fe7e1 Add Português do Brasil 2015-12-20 08:20:50 +01:00
James Cole
9b40cc6881 Fix locale setting for Carbon. 2015-12-20 08:19:26 +01:00
James Cole
2e35260bbb Add some translations. 2015-12-20 07:34:10 +01:00
James Cole
a067704277 Move stuff around. 2015-12-20 07:34:01 +01:00
James Cole
de281818ac Add language 2015-12-19 21:16:09 +01:00
James Cole
c49bfad38d Move languages. 2015-12-19 20:54:59 +01:00
James Cole
c1ba591b26 Rename languages. 2015-12-19 20:54:27 +01:00
James Cole
719af38a61 Cleanup. 2015-12-18 18:42:56 +01:00
James Cole
ac61dfae6b File reformatting. 2015-12-18 16:38:50 +01:00
James Cole
813fb679a7 File reformatting. 2015-12-18 16:37:45 +01:00
James Cole
e7562781f7 File reformatting. 2015-12-18 16:37:27 +01:00
James Cole
56d36b7f53 Remove Google references. 2015-12-18 16:37:02 +01:00
James Cole
53b3f7f821 Merge branch 'release/3.5.4' 2015-12-18 08:13:28 +01:00
James Cole
08a53156bd Merge branch 'release/3.5.4' into develop 2015-12-18 08:13:28 +01:00
James Cole
8985cd6309 New composer for 3.5.4. 2015-12-18 08:13:19 +01:00
James Cole
3833da7410 Add something about security. 2015-12-18 08:11:05 +01:00
James Cole
4210cd10db Cleanup. 2015-12-18 08:10:41 +01:00
James Cole
a7bd1c6892 Merge branch 'develop' of https://github.com/JC5/firefly-iii into develop
* 'develop' of https://github.com/JC5/firefly-iii:
  First attempt cleaning up chart money formatting.
2015-12-18 07:32:03 +01:00
James Cole
52b0111afa Expanded text in register dialog. 2015-12-18 07:31:49 +01:00
James Cole
7921d128e4 Cleanup routine that checks for blocked domains. 2015-12-18 07:31:36 +01:00
James Cole
d7e838701a Blocked domains now in .env file. 2015-12-18 07:31:14 +01:00
James Cole
289bcb22aa First attempt cleaning up chart money formatting. 2015-12-17 15:03:47 +01:00
James Cole
3fe57b7983 Report remembers budgets and categories. 2015-12-16 16:19:15 +01:00
James Cole
32e92c2a16 Committed some dev stuff. 2015-12-16 13:10:49 +01:00
James Cole
1b3d208540 First attempt at functional category chart. 2015-12-16 13:08:26 +01:00
James Cole
6a8bf0aa62 Fixed the "undefined" error. 2015-12-16 12:13:01 +01:00
James Cole
56715556ed Second attempt. 2015-12-16 10:54:56 +01:00
James Cole
838330b909 First attempt at multi-year budget chart. 2015-12-16 10:17:15 +01:00
James Cole
69553b138b First calculations for multi-year budget chart. 2015-12-15 12:52:42 +01:00
James Cole
36d7a02994 Some refactoring. 2015-12-15 12:46:40 +01:00
James Cole
301528e2d2 Quick links. 2015-12-15 12:38:18 +01:00
James Cole
0303b45707 First code for multi year budget chart. 2015-12-15 12:37:55 +01:00
James Cole
ba722e8ed5 Expanded error message. 2015-12-15 08:19:16 +01:00
James Cole
289e5a5442 Add new blocked domain. 2015-12-15 08:19:07 +01:00
James Cole
fdad96e2bc Replaced route. 2015-12-14 21:14:34 +01:00
James Cole
af994e4dae Included first multi-year chart. 2015-12-14 21:12:10 +01:00
James Cole
006d68e279 Expand chart generation. 2015-12-14 21:11:57 +01:00
James Cole
29dc122ad3 New charts (slight variations of previous charts) 2015-12-14 21:11:26 +01:00
James Cole
cf4a8c6204 New translations. 2015-12-14 21:11:12 +01:00
James Cole
3c73fe92bf Lower threshold. 2015-12-14 20:58:23 +01:00
James Cole
6637590797 Empty placeholder for multi-year report. 2015-12-14 20:54:19 +01:00
James Cole
b8bab11acd Fix bread crumbs, clean up routes. 2015-12-14 20:45:12 +01:00
James Cole
a2f600feac Nice clean code. 2015-12-14 20:37:38 +01:00
James Cole
80dd62ef0a Refer to correct translations. 2015-12-14 20:34:08 +01:00
James Cole
827b1c9cd8 Fix some translations. 2015-12-14 20:33:57 +01:00
James Cole
2e4fcf803d Fix JS references. 2015-12-14 20:33:50 +01:00
James Cole
d00d95fc6f Cleanup JS 2015-12-14 20:33:10 +01:00
James Cole
3e3ab9bd25 Move some JS around. 2015-12-14 20:25:48 +01:00
James Cole
6eecc7722d Merge branch 'develop' of https://github.com/JC5/firefly-iii into develop
* 'develop' of https://github.com/JC5/firefly-iii:
  Fix for left unbalanced field in report.
2015-12-14 20:22:47 +01:00
James Cole
ada4aaf69a This will generate buttloads of test data. 2015-12-14 20:21:24 +01:00
James Cole
93244c1f78 Fix for left unbalanced field in report. 2015-12-14 12:35:52 +01:00
James Cole
be056cea6b Update some queries. 2015-12-13 20:41:35 +01:00
James Cole
659ca8be14 Update some queries. 2015-12-13 20:40:41 +01:00
James Cole
ea9af8366d Update some queries. 2015-12-13 20:39:26 +01:00
James Cole
80edd47d36 First attempts at building a multi-year report. 2015-12-13 17:31:25 +01:00
James Cole
d7746b3649 Support multi-year, not implemented yet. 2015-12-13 10:18:25 +01:00
James Cole
c4c4fbc34c Refactor 2015-12-13 10:05:13 +01:00
James Cole
59f57c96e9 Refactor names. 2015-12-13 09:41:22 +01:00
James Cole
a2f852fecf Clean up code. 2015-12-13 09:35:58 +01:00
James Cole
ad114ed329 Remove unused methods. 2015-12-13 09:30:02 +01:00
James Cole
c4c3d0f07f Some refactoring. 2015-12-13 09:01:17 +01:00
James Cole
6cf8102de5 Update version for coming release. 2015-12-12 22:32:19 +01:00
James Cole
e7e4aa2218 Update composer.lock. 2015-12-12 22:32:04 +01:00
James Cole
6d84f4b6c1 Update screenshots. 2015-12-12 22:31:34 +01:00
James Cole
ce3e9ffd11 Better cache control. 2015-12-12 21:20:20 +01:00
James Cole
3ada260e0e This will keep history. 2015-12-12 20:59:29 +01:00
James Cole
8fdd0cb795 Fixed some yearly charts. 2015-12-12 20:56:07 +01:00
James Cole
913e05a2e6 Really, reversed. 2015-12-12 20:20:18 +01:00
James Cole
fa1f703ef6 Some negative sums were failing regarding transfers. 2015-12-12 20:19:40 +01:00
James Cole
4004c53e1b Fix negative amount thing. 2015-12-12 20:16:30 +01:00
James Cole
4838670649 Transfer fix. 2015-12-12 20:13:07 +01:00
James Cole
a985e09282 Fix query. 2015-12-12 20:10:52 +01:00
James Cole
9bd1503cb4 Expand query to catch all expenses. 2015-12-12 20:07:33 +01:00
James Cole
a2ccbf7844 Jump to year report if the period is too long. 2015-12-12 19:04:30 +01:00
James Cole
61bbe8a905 Don't need this file. 2015-12-12 17:51:40 +01:00
James Cole
59bc5d22d1 Clean up some urls 2015-12-12 17:51:07 +01:00
James Cole
1423d5b314 Expand query, let's see what happens. 2015-12-12 12:36:36 +01:00
James Cole
152d0eb1d0 Cleanup and translations. 2015-12-12 12:29:54 +01:00
James Cole
6426d1df06 Fix the report chart. 2015-12-12 10:41:51 +01:00
James Cole
9284eb3fe9 First attempt at account specific bill report. 2015-12-12 10:33:19 +01:00
James Cole
afdae8bc1e Fix a sum for #129 2015-12-12 08:26:12 +01:00
James Cole
2a7085e593 Experimental budget lines. #129 2015-12-12 08:25:08 +01:00
James Cole
2408fb3ed4 Experimental budget lines. #129 2015-12-12 08:24:17 +01:00
James Cole
8316afb176 Experimental budget lines. #129 2015-12-12 08:21:46 +01:00
James Cole
e59fd098a3 Spent amount / withdrawals are negative, #129. 2015-12-12 08:15:14 +01:00
James Cole
e044199693 Spent amount / withdrawals are negative, #129. 2015-12-12 08:14:17 +01:00
James Cole
8f8e29fc22 Fix a sum. 2015-12-12 08:12:27 +01:00
James Cole
8de5384158 Spent amount / withdrawals are negative, #129. 2015-12-12 08:11:30 +01:00
James Cole
216c659335 Spent amount / withdrawals are negative, #129. 2015-12-12 08:07:25 +01:00
James Cole
041ca8a5d3 Amount reversal for #129 2015-12-12 08:05:10 +01:00
James Cole
fe4f1b306d Fix a sum for #129 2015-12-11 18:52:21 +01:00
James Cole
a0972d99fb Made a negative amount a positive as per #129 2015-12-11 18:49:07 +01:00
James Cole
e332bfef7c First attempt at budgets (split by account). 2015-12-11 18:45:39 +01:00
James Cole
cba5e226d8 Fix display of amount. 2015-12-11 18:36:19 +01:00
James Cole
5aff0c4943 Some fixes for #129 2015-12-11 18:35:49 +01:00
James Cole
cb49c00f4d Fix another JS error 2015-12-11 18:33:47 +01:00
James Cole
e26d797d57 Fix JS error. 2015-12-11 18:32:57 +01:00
James Cole
938581527e Fix sorting. 2015-12-11 18:31:15 +01:00
James Cole
c38ae09735 Negative expenses, as per #129 2015-12-11 18:30:28 +01:00
James Cole
28c3cfe084 Fix display of amount. See issue #129 2015-12-11 18:15:37 +01:00
James Cole
4a2823bcba Reverse sort. 2015-12-11 18:05:07 +01:00
James Cole
18eba02026 Expanded report for categories. 2015-12-11 18:03:13 +01:00
James Cole
d4690ce580 Fix date in budget report 2015-12-11 17:54:52 +01:00
James Cole
a785c450b1 First attempt at including a budget report. 2015-12-11 17:53:17 +01:00
James Cole
7480dc4a19 Fix a query. 2015-12-11 16:39:33 +01:00
James Cole
ad01891a67 First attempt at including expense report. 2015-12-11 16:36:40 +01:00
James Cole
67fe35d564 Small query fix. 2015-12-11 11:32:22 +01:00
James Cole
7f19b6957a Expanded new report a bit. Mainly copy/paste work. Will have to see how it pans out. 2015-12-11 09:39:17 +01:00
James Cole
0a54caf202 Tweak more translations. 2015-12-11 08:48:07 +01:00
James Cole
4b4c1c7f8f Moved some translations to see if they will still be picked up by Laravel. 2015-12-11 08:40:45 +01:00
James Cole
d071f3947e Merge pull request #127 from tonicospinelli/demeter-law
applying Demeter law for Transaction Type. Looking good!
2015-12-11 08:36:03 +01:00
Antonio Spinelli
b3d99cd210 apply demeter law for transaction type calls
- adds contants for transaction type names
- demeter law = never speaks with strangers
2015-12-10 16:53:48 -02:00
James Cole
90e696f82c Period is a month 2015-12-07 14:42:28 +01:00
James Cole
958fcd1cfa Report IP address 2015-12-07 14:41:04 +01:00
James Cole
8f57c7dcb3 Some fixes to amounts. 2015-12-06 13:17:00 +01:00
James Cole
77262f52a4 First functional view of default report. 2015-12-06 13:11:43 +01:00
James Cole
16bfbc8a12 Some JS to process the report form beforehand. 2015-12-06 08:42:04 +01:00
James Cole
1fd375b875 Better redirect after logout. 2015-12-05 17:45:33 +01:00
James Cole
46131ad39d Updated view for new reports. 2015-12-04 06:57:08 +01:00
James Cole
0b5c5b2ae9 Some mediocre Javascript for report thing. 2015-12-04 06:56:59 +01:00
James Cole
55be174037 Method to find an account. 2015-12-04 06:56:45 +01:00
James Cole
a17b7025f1 New function to build URL report. 2015-12-04 06:56:35 +01:00
James Cole
170cf7fd77 New routes for new reports. 2015-12-04 06:56:03 +01:00
James Cole
23cdb4d326 Expand month list for new reports. 2015-12-04 06:55:54 +01:00
James Cole
cbbe529572 Show bill if one is connected. 2015-12-04 06:16:19 +01:00
James Cole
0b382426e9 First experimental report generator / choice thing. 2015-12-03 14:52:10 +01:00
James Cole
1cbbf9baa4 Added a missing translation. 2015-12-03 11:46:05 +01:00
James Cole
8d41ff7b79 Prev should be next. Duh. 2015-12-03 11:41:06 +01:00
James Cole
e3b6057bf8 Catch Swift exceptions and do a log only (instead of crashing) because the email message isn't actually critical. 2015-12-03 11:30:43 +01:00
James Cole
66a4042cad Updated composer file. 2015-12-03 11:25:12 +01:00
James Cole
56c08d8302 Can block certain domains from registering, such as ten-minute-mail services. Two example domains provided in configuration. 2015-12-03 11:17:48 +01:00
James Cole
d4e759754d Make password reset impossible for blocked users. 2015-12-02 13:28:11 +01:00
James Cole
a96e171cbf Update composer. 2015-12-02 13:26:58 +01:00
James Cole
bd4a8c8397 Fixed "under" column 2015-12-02 09:03:34 +01:00
James Cole
04f71b3b43 Removed old code. 2015-12-02 09:01:40 +01:00
James Cole
d124de51db Shouldn't be like this? 2015-12-02 09:00:28 +01:00
James Cole
d87d12a0f5 Better query. See if works. 2015-12-02 08:58:40 +01:00
James Cole
f2b08346d0 Log. 2015-12-02 08:50:28 +01:00
James Cole
d3682a6727 Another fix in reports. 2015-12-02 08:46:03 +01:00
James Cole
371bbd9508 Some cosmetic fixes to reports 2015-12-02 08:44:23 +01:00
James Cole
a8a28f442f Also show "zero" amounts. 2015-12-02 08:38:57 +01:00
James Cole
65ddd8a736 One 'equals' sign too many! 2015-12-02 08:37:35 +01:00
James Cole
8bb27de233 More report subtleties. 2015-12-02 08:37:08 +01:00
James Cole
37e2f097ba To make budget report more clear, add spent amount to "spent" column. 2015-12-02 08:35:15 +01:00
James Cole
1966d87ce6 Small formatting fixes in reports. 2015-12-02 08:33:22 +01:00
James Cole
7b8c86e1e3 Only get active piggy banks. 2015-12-02 08:25:38 +01:00
unknown
de634da513 Only get active savings accounts. 2015-12-02 08:22:25 +01:00
James Cole
96836e2d6c Update read me. 2015-11-28 16:04:30 +01:00
James Cole
8a9d576f61 Allow change to default currency. issue #121 2015-11-22 11:30:06 +01:00
James Cole
791d12fbb4 Fix for issue #123 2015-11-22 11:25:15 +01:00
James Cole
d1329be2fa Bill scan routine should not grab transfers and income. 2015-11-20 20:13:10 +01:00
James Cole
3ed6561702 Updated all packages. 2015-11-13 07:16:23 +01:00
James Cole
0fe682bfe6 Merge branch 'release/3.5.3' into develop 2015-11-13 07:01:29 +01:00
217 changed files with 8357 additions and 4921 deletions

View File

@@ -2,6 +2,7 @@ APP_ENV=production
APP_DEBUG=false APP_DEBUG=false
APP_KEY=SomeRandomStringOf32CharsExactly APP_KEY=SomeRandomStringOf32CharsExactly
DB_CONNECTION=mysql DB_CONNECTION=mysql
DB_HOST=localhost DB_HOST=localhost
DB_DATABASE=homestead DB_DATABASE=homestead
@@ -11,14 +12,19 @@ DB_PASSWORD=secret
CACHE_DRIVER=file CACHE_DRIVER=file
SESSION_DRIVER=file SESSION_DRIVER=file
DEFAULT_CURRENCY=EUR
DEFAULT_LANGUAGE=en_US
EMAIL_SMTP= EMAIL_SMTP=
EMAIL_DRIVER=smtp EMAIL_DRIVER=smtp
EMAIL_USERNAME= EMAIL_USERNAME=
EMAIL_PASSWORD= EMAIL_PASSWORD=
ANALYTICS_ID=
EMAIL_PRETEND=false EMAIL_PRETEND=false
SHOW_INCOMPLETE_TRANSLATIONS=false
ANALYTICS_ID=
RUNCLEANUP=true RUNCLEANUP=true
SITE_OWNER=mail@example.com SITE_OWNER=mail@example.com
SENDGRID_USERNAME= BLOCKED_DOMAINS=
SENDGRID_PASSWORD=

2
.gitignore vendored
View File

@@ -5,7 +5,7 @@ Thumbs.db
.idea/ .idea/
tests/_output/* tests/_output/*
_ide_helper.php _ide_helper.php
/build/logs/clover.xml /build/logs
index.html* index.html*
app/storage/firefly-export* app/storage/firefly-export*
.vagrant .vagrant

View File

@@ -10,6 +10,9 @@ install:
- composer update - composer update
- php artisan env - php artisan env
- mv -v .env.testing .env - mv -v .env.testing .env
- touch storage/database/testing.db
- php artisan migrate --env=testing
- php artisan migrate --seed --env=testing
script: script:
- phpunit - phpunit

View File

@@ -11,15 +11,12 @@
"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
household accounts and savings accounts! It's pretty fancy. You should use it to save and organise money. household accounts and savings accounts! It's pretty fancy. You should use it to save and organise money.
_Firefly is a system you'll have install yourself on webhosting of your choosing._
Personal financial management is pretty difficult, and everybody has their own approach to it. Some people Personal financial management is pretty difficult, and everybody has their own approach to it. Some people
make budgets, other people limit their cashflow by throwing away their credit cards, others try to increase make budgets, other people limit their cashflow by throwing away their credit cards, others try to increase
their current cashflow. There are tons of ways to save and earn money. their current cashflow. There are tons of ways to save and earn money.
Firefly works on the principle that if you know where you're money is going, you can stop it from going there. Firefly works on the principle that if you know where you're money is going, you can stop it from going there.
To get to know Firefly, and to see if it fits you, check out these resources: To get to know Firefly, and to see if it fits you, check out these resources:
- The screenshots below on this very page. - The screenshots below on this very page.
@@ -27,6 +24,11 @@ To get to know Firefly, and to see if it fits you, check out these resources:
- The [full description](https://github.com/JC5/firefly-iii/wiki/full-description), which will tell you how Firefly works, - The [full description](https://github.com/JC5/firefly-iii/wiki/full-description), which will tell you how Firefly works,
and the philosophy behind it. and the philosophy behind it.
#### A quick technical overview
Firefly is a system you'll have install yourself on webhosting of your choosing. It needs PHP and MySQL. The current version of Firefly III requires PHP 5.6.4 or
higher. Soon, this will be PHP 7.0.0 or higher.
#### About the name (should you care) #### About the name (should you care)
@@ -61,19 +63,19 @@ Everything is organised:
_Please note that everything in these screenshots is fictional and may not be realistic._ _Please note that everything in these screenshots is fictional and may not be realistic._
![Index](https://i.nder.be/c6hz06d3) ![Index](https://i.nder.be/hmp5mhw5)
![Accounts](https://i.nder.be/gzxxyz6n) ![Accounts](https://i.nder.be/hf5k02g9)
![Budgets](https://i.nder.be/hhu3krqk) ![Budgets](https://i.nder.be/gzv635mz)
![Reports 1](https://i.nder.be/cc3yspf6) ![Reports 1](https://i.nder.be/g0w698s3)
![Reports 2](https://i.nder.be/h6fp7xkb) ![Reports 2](https://i.nder.be/cr77nyxq)
![Bills](https://i.nder.be/c30zkcpv) ![Bills](https://i.nder.be/c7sugsz5)
![Piggy banks](https://i.nder.be/g20k0mdq) ![Piggy banks](https://i.nder.be/gy2nk0y4)
## Running and installing ## Running and installing
@@ -82,7 +84,19 @@ If you're still interested please read [the installation guide](https://github.c
and the **[first use guide](https://github.com/JC5/firefly-iii/wiki/First-use)**. 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/). 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. Accounts on the demo sites will stop working after one week. 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. Accounts on the demo sites will stop working after one month. It's a trial.
## Security
You should always run Firefly III on a site with TLS enabled (https://). Please note that although some parts of the
database are encrypted (transaction descriptions, names, etc.) some parts are _not_ (amounts, dates, etc). If you need
more security, you must enable transparent database encryption or a comparable technology. Please remember that this
is open source software under active development, and it is in no way guaranteed to be safe or secure.
## Translations
Firefly III is currently available in Dutch and English. Support for other languages is being worked on. I could use
your help. Checkout [Crowdin](https://crowdin.com/project/firefly-iii) for more information.
## Credits ## Credits

View File

@@ -1,25 +0,0 @@
<?php namespace FireflyIII\Events;
use Illuminate\Queue\SerializesModels;
/**
* Class JournalDeleted
*
* @codeCoverageIgnore
* @package FireflyIII\Events
*/
class JournalDeleted extends Event
{
use SerializesModels;
/**
* Create a new event instance.
*
*/
public function __construct()
{
//
}
}

View File

@@ -14,15 +14,6 @@ use Illuminate\Support\Collection;
interface AccountChartGenerator interface AccountChartGenerator
{ {
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function all(Collection $accounts, Carbon $start, Carbon $end);
/** /**
* @param Collection $accounts * @param Collection $accounts
* @param Carbon $start * @param Carbon $start

View File

@@ -3,10 +3,8 @@
namespace FireflyIII\Generator\Chart\Account; namespace FireflyIII\Generator\Chart\Account;
use Carbon\Carbon; use Carbon\Carbon;
use Config;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Preferences;
use Steam; use Steam;
/** /**
@@ -17,21 +15,6 @@ use Steam;
class ChartJsAccountChartGenerator implements AccountChartGenerator class ChartJsAccountChartGenerator implements AccountChartGenerator
{ {
/**
* @codeCoverageIgnore
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function all(Collection $accounts, Carbon $start, Carbon $end)
{
return $this->frontpage($accounts, $start, $end);
}
/** /**
* @param Collection $accounts * @param Collection $accounts
* @param Carbon $start * @param Carbon $start
@@ -105,8 +88,7 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
public function frontpage(Collection $accounts, Carbon $start, Carbon $end) public function frontpage(Collection $accounts, Carbon $start, Carbon $end)
{ {
// language: // language:
$language = Preferences::get('language', 'en')->data; $format = trans('config.month_and_day');
$format = Config::get('firefly.monthAndDay.' . $language);
$data = [ $data = [
'count' => 0, 'count' => 0,
'labels' => [], 'labels' => [],
@@ -118,6 +100,7 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
$current->addDay(); $current->addDay();
} }
foreach ($accounts as $account) { foreach ($accounts as $account) {
$set = [ $set = [
'label' => $account->name, 'label' => $account->name,
@@ -130,8 +113,14 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
'data' => [], 'data' => [],
]; ];
$current = clone $start; $current = clone $start;
$range = Steam::balanceInRange($account, $start, clone $end);
$previous = array_values($range)[0];
while ($current <= $end) { while ($current <= $end) {
$set['data'][] = Steam::balance($account, $current); $format = $current->format('Y-m-d');
$balance = isset($range[$format]) ? $range[$format] : $previous;
$set['data'][] = $balance;
$previous = $balance;
$current->addDay(); $current->addDay();
} }
$data['datasets'][] = $set; $data['datasets'][] = $set;
@@ -151,8 +140,7 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
public function single(Account $account, Carbon $start, Carbon $end) public function single(Account $account, Carbon $start, Carbon $end)
{ {
// language: // language:
$language = Preferences::get('language', 'en')->data; $format = trans('config.month_and_day');
$format = Config::get('firefly.monthAndDay.' . $language);
$data = [ $data = [
'count' => 1, 'count' => 1,
@@ -164,12 +152,17 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
] ]
], ],
]; ];
$range = Steam::balanceInRange($account, $start, $end);
$current = clone $start; $current = clone $start;
$previous = array_values($range)[0];
while ($end >= $current) { while ($end >= $current) {
$theDate = $current->format('Y-m-d');
$balance = isset($range[$theDate]) ? $range[$theDate] : $previous;
$data['labels'][] = $current->formatLocalized($format); $data['labels'][] = $current->formatLocalized($format);
$data['datasets'][0]['data'][] = Steam::balance($account, $current); $data['datasets'][0]['data'][] = $balance;
$previous = $balance;
$current->addDay(); $current->addDay();
} }

View File

@@ -14,12 +14,12 @@ interface BillChartGenerator
{ {
/** /**
* @param Collection $paid * @param string $paid
* @param Collection $unpaid * @param string $unpaid
* *
* @return array * @return array
*/ */
public function frontpage(Collection $paid, Collection $unpaid); public function frontpage($paid, $unpaid);
/** /**
* @param Bill $bill * @param Bill $bill

View File

@@ -2,11 +2,9 @@
namespace FireflyIII\Generator\Chart\Bill; namespace FireflyIII\Generator\Chart\Bill;
use Config;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Preferences;
/** /**
* Class ChartJsBillChartGenerator * Class ChartJsBillChartGenerator
@@ -17,42 +15,23 @@ class ChartJsBillChartGenerator implements BillChartGenerator
{ {
/** /**
* @param Collection $paid * @param string $paid
* @param Collection $unpaid * @param string $unpaid
* *
* @return array * @return array
*/ */
public function frontpage(Collection $paid, Collection $unpaid) public function frontpage($paid, $unpaid)
{ {
$paidDescriptions = [];
$paidAmount = 0;
$unpaidDescriptions = [];
$unpaidAmount = 0;
bcscale(2); bcscale(2);
/** @var TransactionJournal $entry */
foreach ($paid as $entry) { // loop paid and create single entry:
$paidDescriptions[] = $entry->description;
$paidAmount = bcadd($paidAmount, $entry->amount_positive);
}
/** @var Bill $entry */
foreach ($unpaid as $entry) { // loop unpaid:
$description = $entry[0]->name . ' (' . $entry[1]->format('jS M Y') . ')';
$amount = bcdiv(bcadd($entry[0]->amount_max, $entry[0]->amount_min), 2);
$unpaidDescriptions[] = $description;
$unpaidAmount = bcadd($unpaidAmount, $amount);
unset($amount, $description);
}
$data = [ $data = [
[ [
'value' => $unpaidAmount, 'value' => round($unpaid, 2),
'color' => 'rgba(53, 124, 165,0.7)', 'color' => 'rgba(53, 124, 165,0.7)',
'highlight' => 'rgba(53, 124, 165,0.9)', 'highlight' => 'rgba(53, 124, 165,0.9)',
'label' => trans('firefly.unpaid'), 'label' => trans('firefly.unpaid'),
], ],
[ [
'value' => $paidAmount, 'value' => round($paid * -1, 2), // paid is negative, must be positive.
'color' => 'rgba(0, 141, 76, 0.7)', 'color' => 'rgba(0, 141, 76, 0.7)',
'highlight' => 'rgba(0, 141, 76, 0.9)', 'highlight' => 'rgba(0, 141, 76, 0.9)',
'label' => trans('firefly.paid'), 'label' => trans('firefly.paid'),
@@ -70,28 +49,24 @@ class ChartJsBillChartGenerator implements BillChartGenerator
*/ */
public function single(Bill $bill, Collection $entries) public function single(Bill $bill, Collection $entries)
{ {
// language: $format = trans('config.month');
$language = Preferences::get('language', 'en')->data;
$format = Config::get('firefly.month.' . $language);
$data = [ $data = [
'count' => 3, 'count' => 3,
'labels' => [], 'labels' => [],
'datasets' => [], 'datasets' => [],
]; ];
// dataset: max amount
// dataset: min amount
// dataset: actual amount
$minAmount = []; $minAmount = [];
$maxAmount = []; $maxAmount = [];
$actualAmount = []; $actualAmount = [];
/** @var TransactionJournal $entry */
foreach ($entries as $entry) { foreach ($entries as $entry) {
$data['labels'][] = $entry->date->formatLocalized($format); $data['labels'][] = $entry->date->formatLocalized($format);
$minAmount[] = round($bill->amount_min, 2); $minAmount[] = round($bill->amount_min, 2);
$maxAmount[] = round($bill->amount_max, 2); $maxAmount[] = round($bill->amount_max, 2);
$actualAmount[] = round(($entry->amount * -1), 2); /*
* journalAmount has been collected in BillRepository::getJournals
*/
$actualAmount[] = round(($entry->journalAmount * -1), 2);
} }
$data['datasets'][] = [ $data['datasets'][] = [

View File

@@ -32,6 +32,13 @@ interface BudgetChartGenerator
*/ */
public function frontpage(Collection $entries); public function frontpage(Collection $entries);
/**
* @param Collection $entries
*
* @return array
*/
public function multiYear(Collection $entries);
/** /**
* @param Collection $budgets * @param Collection $budgets
* @param Collection $entries * @param Collection $entries

View File

@@ -24,7 +24,7 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
public function budget(Collection $entries, $dateFormat = 'month') public function budget(Collection $entries, $dateFormat = 'month')
{ {
// language: // language:
$language = Preferences::get('language', 'en')->data; $language = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US'))->data;
$format = Config::get('firefly.' . $dateFormat . '.' . $language); $format = Config::get('firefly.' . $dateFormat . '.' . $language);
$data = [ $data = [
@@ -33,7 +33,7 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
[ [
'label' => 'Amount', 'label' => 'Amount',
'data' => [], 'data' => [],
] ],
], ],
]; ];
@@ -73,19 +73,19 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
'labels' => [], 'labels' => [],
'datasets' => [], 'datasets' => [],
]; ];
// dataset: left
// dataset: spent
// dataset: overspent
$left = []; $left = [];
$spent = []; $spent = [];
$overspent = []; $overspent = [];
foreach ($entries as $entry) { $filtered = $entries->filter(
if ($entry[1] != 0 || $entry[2] != 0 || $entry[3] != 0) { function ($entry) {
return ($entry[1] != 0 || $entry[2] != 0 || $entry[3] != 0);
}
);
foreach ($filtered as $entry) {
$data['labels'][] = $entry[0]; $data['labels'][] = $entry[0];
$left[] = round($entry[1], 2); $left[] = round($entry[1], 2);
$spent[] = round($entry[2], 2); $spent[] = round($entry[2] * -1, 2); // spent is coming in negative, must be positive
$overspent[] = round($entry[3], 2); $overspent[] = round($entry[3] * -1, 2); // same
}
} }
$data['datasets'][] = [ $data['datasets'][] = [
@@ -115,8 +115,7 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
public function year(Collection $budgets, Collection $entries) public function year(Collection $budgets, Collection $entries)
{ {
// language: // language:
$language = Preferences::get('language', 'en')->data; $format = trans('config.month');
$format = Config::get('firefly.month.' . $language);
$data = [ $data = [
'labels' => [], 'labels' => [],
@@ -141,4 +140,37 @@ class ChartJsBudgetChartGenerator implements BudgetChartGenerator
return $data; return $data;
} }
/**
* @param Collection $entries
*
* @return array
*/
public function multiYear(Collection $entries)
{
// dataset:
$data = [
'count' => 0,
'labels' => [],
'datasets' => [],
];
// get labels from one of the budgets (assuming there's at least one):
$first = $entries->first();
foreach ($first['budgeted'] as $year => $noInterest) {
$data['labels'][] = strval($year);
}
// then, loop all entries and create datasets:
foreach ($entries as $entry) {
$name = $entry['name'];
$spent = $entry['spent'];
$budgeted = $entry['budgeted'];
$data['datasets'][] = ['label' => 'Spent on ' . $name, 'data' => array_values($spent)];
$data['datasets'][] = ['label' => 'Budgeted for ' . $name, 'data' => array_values($budgeted)];
}
$data['count'] = count($data['datasets']);
return $data;
}
} }

View File

@@ -19,6 +19,14 @@ interface CategoryChartGenerator
*/ */
public function all(Collection $entries); public function all(Collection $entries);
/**
* @param Collection $categories
* @param Collection $entries
*
* @return array
*/
public function earnedInPeriod(Collection $categories, Collection $entries);
/** /**
* @param Collection $entries * @param Collection $entries
* *
@@ -26,6 +34,13 @@ interface CategoryChartGenerator
*/ */
public function frontpage(Collection $entries); public function frontpage(Collection $entries);
/**
* @param Collection $entries
*
* @return array
*/
public function multiYear(Collection $entries);
/** /**
* @param Collection $entries * @param Collection $entries
* *
@@ -33,20 +48,11 @@ interface CategoryChartGenerator
*/ */
public function period(Collection $entries); public function period(Collection $entries);
/** /**
* @param Collection $categories * @param Collection $categories
* @param Collection $entries * @param Collection $entries
* *
* @return array * @return array
*/ */
public function spentInYear(Collection $categories, Collection $entries); public function spentInPeriod(Collection $categories, Collection $entries);
/**
* @param Collection $categories
* @param Collection $entries
*
* @return array
*/
public function earnedInYear(Collection $categories, Collection $entries);
} }

View File

@@ -2,9 +2,7 @@
namespace FireflyIII\Generator\Chart\Category; namespace FireflyIII\Generator\Chart\Category;
use Config;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Preferences;
/** /**
@@ -51,6 +49,39 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
return $data; return $data;
} }
/**
* @param Collection $categories
* @param Collection $entries
*
* @return array
*/
public function earnedInPeriod(Collection $categories, Collection $entries)
{
// language:
$format = trans('config.month');
$data = [
'count' => 0,
'labels' => [],
'datasets' => [],
];
foreach ($categories as $category) {
$data['labels'][] = $category->name;
}
foreach ($entries as $entry) {
$date = $entry[0]->formatLocalized($format);
array_shift($entry);
$data['count']++;
$data['datasets'][] = ['label' => $date, 'data' => $entry];
}
return $data;
}
/** /**
* @param Collection $entries * @param Collection $entries
* *
@@ -69,15 +100,52 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
], ],
]; ];
foreach ($entries as $entry) { foreach ($entries as $entry) {
if ($entry['sum'] != 0) { if ($entry->spent != 0) {
$data['labels'][] = $entry['name']; $data['labels'][] = $entry->name;
$data['datasets'][0]['data'][] = round(($entry['sum'] * -1), 2); $data['datasets'][0]['data'][] = round(($entry->spent * -1), 2);
} }
} }
return $data; return $data;
} }
/**
* @param Collection $entries
*
* @return array
*/
public function multiYear(Collection $entries)
{
// dataset:
$data = [
'count' => 0,
'labels' => [],
'datasets' => [],
];
// get labels from one of the categories (assuming there's at least one):
$first = $entries->first();
foreach ($first['spent'] as $year => $noInterest) {
$data['labels'][] = strval($year);
}
// then, loop all entries and create datasets:
foreach ($entries as $entry) {
$name = $entry['name'];
$spent = $entry['spent'];
$earned = $entry['earned'];
if (array_sum(array_values($spent)) != 0) {
$data['datasets'][] = ['label' => 'Spent in category ' . $name, 'data' => array_values($spent)];
}
if (array_sum(array_values($earned)) != 0) {
$data['datasets'][] = ['label' => 'Earned in category ' . $name, 'data' => array_values($earned)];
}
}
$data['count'] = count($data['datasets']);
return $data;
}
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* *
@@ -97,46 +165,11 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
* *
* @return array * @return array
*/ */
public function spentInYear(Collection $categories, Collection $entries) public function spentInPeriod(Collection $categories, Collection $entries)
{ {
// language: // language:
$language = Preferences::get('language', 'en')->data; $format = trans('config.month');
$format = Config::get('firefly.month.' . $language);
$data = [
'count' => 0,
'labels' => [],
'datasets' => [],
];
foreach ($categories as $category) {
$data['labels'][] = $category->name;
}
foreach ($entries as $entry) {
$date = $entry[0]->formatLocalized($format);
array_shift($entry);
$data['count']++;
$data['datasets'][] = ['label' => $date, 'data' => $entry];
}
return $data;
}
/**
* @param Collection $categories
* @param Collection $entries
*
* @return array
*/
public function earnedInYear(Collection $categories, Collection $entries)
{
// language:
$language = Preferences::get('language', 'en')->data;
$format = Config::get('firefly.month.' . $language);
$data = [ $data = [
'count' => 0, 'count' => 0,

View File

@@ -3,9 +3,7 @@
namespace FireflyIII\Generator\Chart\PiggyBank; namespace FireflyIII\Generator\Chart\PiggyBank;
use Carbon\Carbon; use Carbon\Carbon;
use Config;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Preferences;
/** /**
@@ -25,8 +23,7 @@ class ChartJsPiggyBankChartGenerator implements PiggyBankChartGenerator
{ {
// language: // language:
$language = Preferences::get('language', 'en')->data; $format = trans('config.month_and_day');
$format = Config::get('firefly.monthAndDay.' . $language);
$data = [ $data = [
'count' => 1, 'count' => 1,

View File

@@ -2,9 +2,7 @@
namespace FireflyIII\Generator\Chart\Report; namespace FireflyIII\Generator\Chart\Report;
use Config;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Preferences;
/** /**
* Class ChartJsReportChartGenerator * Class ChartJsReportChartGenerator
@@ -14,6 +12,70 @@ use Preferences;
class ChartJsReportChartGenerator implements ReportChartGenerator class ChartJsReportChartGenerator implements ReportChartGenerator
{ {
/**
* Same as above but other translations.
*
* @param Collection $entries
*
* @return array
*/
public function multiYearInOut(Collection $entries)
{
$data = [
'count' => 2,
'labels' => [],
'datasets' => [
[
'label' => trans('firefly.income'),
'data' => []
],
[
'label' => trans('firefly.expenses'),
'data' => []
]
],
];
foreach ($entries as $entry) {
$data['labels'][] = $entry[0]->formatLocalized('%Y');
$data['datasets'][0]['data'][] = round($entry[1], 2);
$data['datasets'][1]['data'][] = round($entry[2], 2);
}
return $data;
}
/**
* @param string $income
* @param string $expense
* @param int $count
*
* @return array
*/
public function multiYearInOutSummarized($income, $expense, $count)
{
$data = [
'count' => 2,
'labels' => [trans('firefly.sum_of_years'), trans('firefly.average_of_years')],
'datasets' => [
[
'label' => trans('firefly.income'),
'data' => []
],
[
'label' => trans('firefly.expenses'),
'data' => []
]
],
];
$data['datasets'][0]['data'][] = round($income, 2);
$data['datasets'][1]['data'][] = round($expense, 2);
$data['datasets'][0]['data'][] = round(($income / $count), 2);
$data['datasets'][1]['data'][] = round(($expense / $count), 2);
return $data;
}
/** /**
* @param Collection $entries * @param Collection $entries
* *
@@ -22,8 +84,7 @@ class ChartJsReportChartGenerator implements ReportChartGenerator
public function yearInOut(Collection $entries) public function yearInOut(Collection $entries)
{ {
// language: // language:
$language = Preferences::get('language', 'en')->data; $format = trans('config.month');
$format = Config::get('firefly.month.' . $language);
$data = [ $data = [
'count' => 2, 'count' => 2,

View File

@@ -12,6 +12,22 @@ use Illuminate\Support\Collection;
interface ReportChartGenerator interface ReportChartGenerator
{ {
/**
* @param Collection $entries
*
* @return array
*/
public function multiYearInOut(Collection $entries);
/**
* @param string $income
* @param string $expense
* @param int $count
*
* @return array
*/
public function multiYearInOutSummarized($income, $expense, $count);
/** /**
* @param Collection $entries * @param Collection $entries
* *

View File

@@ -28,8 +28,6 @@ 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

View File

@@ -67,8 +67,10 @@ class AttachmentHelper implements AttachmentHelperInterface
} }
} }
} else { } else {
if (!is_null($files)) {
$this->processFile($files, $model); $this->processFile($files, $model);
} }
}
return true; return true;
} }

View File

@@ -3,7 +3,6 @@
namespace FireflyIII\Helpers\Collection; namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Budget as BudgetModel; use FireflyIII\Models\Budget as BudgetModel;
use FireflyIII\Models\LimitRepetition;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**
@@ -26,9 +25,6 @@ class BalanceLine
/** @var BudgetModel */ /** @var BudgetModel */
protected $budget; protected $budget;
/** @var LimitRepetition */
protected $repetition;
protected $role = self::ROLE_DEFAULTROLE; protected $role = self::ROLE_DEFAULTROLE;
/** /**
@@ -48,24 +44,19 @@ class BalanceLine
} }
/** /**
* @return string * @return Collection
*/ */
public function getTitle() public function getBalanceEntries()
{ {
if ($this->getBudget() instanceof BudgetModel) { return $this->balanceEntries;
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 ''; /**
* @param Collection $balanceEntries
*/
public function setBalanceEntries($balanceEntries)
{
$this->balanceEntries = $balanceEntries;
} }
/** /**
@@ -100,6 +91,27 @@ class BalanceLine
$this->role = $role; $this->role = $role;
} }
/**
* @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 '';
}
/** /**
* If a BalanceLine has a budget/repetition, each BalanceEntry in this BalanceLine * 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 * should have a "spent" value, which is the amount of money that has been spent
@@ -110,7 +122,7 @@ class BalanceLine
*/ */
public function leftOfRepetition() public function leftOfRepetition()
{ {
$start = $this->getRepetition() ? $this->getRepetition()->amount : 0; $start = isset($this->budget->amount) ? $this->budget->amount : 0;
/** @var BalanceEntry $balanceEntry */ /** @var BalanceEntry $balanceEntry */
foreach ($this->getBalanceEntries() as $balanceEntry) { foreach ($this->getBalanceEntries() as $balanceEntry) {
$start += $balanceEntry->getSpent(); $start += $balanceEntry->getSpent();
@@ -118,56 +130,4 @@ class BalanceLine
return $start; return $start;
} }
/**
* @return LimitRepetition
*/
public function getRepetition()
{
return $this->repetition;
}
/**
* @param LimitRepetition $repetition
*/
public function setRepetition($repetition)
{
$this->repetition = $repetition;
}
/**
* @return Collection
*/
public function getBalanceEntries()
{
return $this->balanceEntries;
}
/**
* @param Collection $balanceEntries
*/
public function setBalanceEntries($balanceEntries)
{
$this->balanceEntries = $balanceEntries;
}
/**
* If the BalanceEntries for a BalanceLine have a "left" value, the amount
* of money left in the entire BalanceLine is returned here:
*
* @return float
*/
public function sumOfLeft()
{
$sum = '0';
bcscale(2);
/** @var BalanceEntry $balanceEntry */
foreach ($this->getBalanceEntries() as $balanceEntry) {
$sum = bcadd($sum, $balanceEntry->getLeft());
}
return $sum;
}
} }

View File

@@ -37,6 +37,7 @@ class Category
// spent is minus zero for an expense report: // spent is minus zero for an expense report:
if ($category->spent < 0) { if ($category->spent < 0) {
$this->categories->push($category); $this->categories->push($category);
$this->addTotal($category->spent);
} }
} }
@@ -55,7 +56,7 @@ class Category
*/ */
public function getCategories() public function getCategories()
{ {
$set = $this->categories->sortByDesc( $set = $this->categories->sortBy(
function (CategoryModel $category) { function (CategoryModel $category) {
return $category->spent; return $category->spent;
} }

View File

@@ -2,6 +2,7 @@
namespace FireflyIII\Helpers\Collection; namespace FireflyIII\Helpers\Collection;
use Crypt;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use stdClass; use stdClass;
@@ -33,18 +34,24 @@ class Expense
*/ */
public function addOrCreateExpense(TransactionJournal $entry) public function addOrCreateExpense(TransactionJournal $entry)
{ {
bcscale(2);
$accountId = $entry->account_id; $accountId = $entry->account_id;
$amount = strval(round($entry->journalAmount, 2));
if (bccomp('0', $amount) === -1) {
$amount = bcmul($amount, '-1');
}
if (!$this->expenses->has($accountId)) { if (!$this->expenses->has($accountId)) {
$newObject = new stdClass; $newObject = new stdClass;
$newObject->amount = strval(round($entry->amount_positive, 2)); $newObject->amount = $amount;
$newObject->name = $entry->name; $newObject->name = Crypt::decrypt($entry->account_name);
$newObject->count = 1; $newObject->count = 1;
$newObject->id = $accountId; $newObject->id = $accountId;
$this->expenses->put($accountId, $newObject); $this->expenses->put($accountId, $newObject);
} else { } else {
bcscale(2);
$existing = $this->expenses->get($accountId); $existing = $this->expenses->get($accountId);
$existing->amount = bcadd($existing->amount, $entry->amount_positive); $existing->amount = bcadd($existing->amount, $amount);
$existing->count++; $existing->count++;
$this->expenses->put($accountId, $existing); $this->expenses->put($accountId, $existing);
} }
@@ -55,8 +62,18 @@ class Expense
*/ */
public function addToTotal($add) public function addToTotal($add)
{ {
$add = strval(round($add, 2));
bcscale(2); bcscale(2);
$add = strval(round($add, 2));
if (bccomp('0', $add) === -1) {
$add = bcmul($add, '-1');
}
// if amount is positive, the original transaction
// was a transfer. But since this is an expense report,
// that amount must be negative.
$this->total = bcadd($this->total, $add); $this->total = bcadd($this->total, $add);
} }
@@ -65,7 +82,7 @@ class Expense
*/ */
public function getExpenses() public function getExpenses()
{ {
$set = $this->expenses->sortByDesc( $set = $this->expenses->sortBy(
function (stdClass $object) { function (stdClass $object) {
return $object->amount; return $object->amount;
} }

View File

@@ -2,6 +2,7 @@
namespace FireflyIII\Helpers\Collection; namespace FireflyIII\Helpers\Collection;
use Crypt;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use stdClass; use stdClass;
@@ -38,15 +39,15 @@ class Income
$accountId = $entry->account_id; $accountId = $entry->account_id;
if (!$this->incomes->has($accountId)) { if (!$this->incomes->has($accountId)) {
$newObject = new stdClass; $newObject = new stdClass;
$newObject->amount = strval(round($entry->amount_positive, 2)); $newObject->amount = strval(round($entry->journalAmount, 2));
$newObject->name = $entry->name; $newObject->name = Crypt::decrypt($entry->account_name);
$newObject->count = 1; $newObject->count = 1;
$newObject->id = $accountId; $newObject->id = $accountId;
$this->incomes->put($accountId, $newObject); $this->incomes->put($accountId, $newObject);
} else { } else {
bcscale(2); bcscale(2);
$existing = $this->incomes->get($accountId); $existing = $this->incomes->get($accountId);
$existing->amount = bcadd($existing->amount, $entry->amount_positive); $existing->amount = bcadd($existing->amount, $entry->journalAmount);
$existing->count++; $existing->count++;
$this->incomes->put($accountId, $existing); $this->incomes->put($accountId, $existing);
} }

View File

@@ -17,7 +17,8 @@ class Date extends BasicConverter implements ConverterInterface
{ {
/** /**
* @return Carbon * @return static
* @throws FireflyException
*/ */
public function convert() public function convert()
{ {

View File

@@ -296,7 +296,7 @@ class Importer
// some debug info: // some debug info:
$journalId = $journal->id; $journalId = $journal->id;
$type = $journal->transactionType->type; $type = $journal->getTransactionType();
/** @var Account $asset */ /** @var Account $asset */
$asset = $this->importData['asset-account-object']; $asset = $this->importData['asset-account-object'];
/** @var Account $opposing */ /** @var Account $opposing */
@@ -314,13 +314,13 @@ class Importer
*/ */
protected function getTransactionType() protected function getTransactionType()
{ {
$transactionType = TransactionType::where('type', 'Deposit')->first(); $transactionType = TransactionType::where('type', TransactionType::DEPOSIT)->first();
if ($this->importData['amount'] < 0) { if ($this->importData['amount'] < 0) {
$transactionType = TransactionType::where('type', 'Withdrawal')->first(); $transactionType = TransactionType::where('type', TransactionType::WITHDRAWAL)->first();
} }
if (in_array($this->importData['opposing-account-object']->accountType->type, ['Asset account', 'Default account'])) { if (in_array($this->importData['opposing-account-object']->accountType->type, ['Asset account', 'Default account'])) {
$transactionType = TransactionType::where('type', 'Transfer')->first(); $transactionType = TransactionType::where('type', TransactionType::TRANSFER)->first();
} }
return $transactionType; return $transactionType;

View File

@@ -24,7 +24,7 @@ class Currency implements PostProcessorInterface
// fix currency // fix currency
if (is_null($this->data['currency'])) { if (is_null($this->data['currency'])) {
$currencyPreference = Preferences::get('currencyPreference', 'EUR'); $currencyPreference = Preferences::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR'));
$this->data['currency'] = TransactionCurrency::whereCode($currencyPreference->data)->first(); $this->data['currency'] = TransactionCurrency::whereCode($currencyPreference->data)->first();
} }

View File

@@ -29,6 +29,22 @@ class RabobankDescription
} }
/**
* @param array $data
*/
public function setData($data)
{
$this->data = $data;
}
/**
* @param array $row
*/
public function setRow($row)
{
$this->row = $row;
}
/** /**
* Fixes Rabobank specific thing. * Fixes Rabobank specific thing.
*/ */
@@ -46,21 +62,5 @@ class RabobankDescription
} }
/**
* @param array $data
*/
public function setData($data)
{
$this->data = $data;
}
/**
* @param array $row
*/
public function setRow($row)
{
$this->row = $row;
}
} }

View File

@@ -3,6 +3,7 @@
namespace FireflyIII\Helpers\Report; namespace FireflyIII\Helpers\Report;
use Carbon\Carbon; use Carbon\Carbon;
use DB;
use FireflyIII\Helpers\Collection\Account as AccountCollection; use FireflyIII\Helpers\Collection\Account as AccountCollection;
use FireflyIII\Helpers\Collection\Balance; use FireflyIII\Helpers\Collection\Balance;
use FireflyIII\Helpers\Collection\BalanceEntry; use FireflyIII\Helpers\Collection\BalanceEntry;
@@ -19,6 +20,9 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget as BudgetModel; use FireflyIII\Models\Budget as BudgetModel;
use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\Tag;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Support\Collection;
/** /**
* Class ReportHelper * Class ReportHelper
@@ -43,48 +47,150 @@ class ReportHelper implements ReportHelperInterface
} }
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return CategoryCollection
*/
public function getCategoryReport(Carbon $start, Carbon $end, Collection $accounts)
{
$object = new CategoryCollection;
/**
* GET CATEGORIES:
*/
/** @var \FireflyIII\Repositories\Category\CategoryRepositoryInterface $repository */
$repository = app('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
$set = $repository->spentForAccountsPerMonth($accounts, $start, $end);
foreach ($set as $category) {
$object->addCategory($category);
}
return $object;
}
/**
* @param Carbon $date
*
* @return array
*/
public function listOfMonths(Carbon $date)
{
$start = clone $date;
$end = Carbon::now();
$months = [];
while ($start <= $end) {
$year = $start->year;
if (!isset($months[$year])) {
$months[$year] = [
'start' => Carbon::createFromDate($year, 1, 1)->format('Y-m-d'),
'end' => Carbon::createFromDate($year, 12, 31)->format('Y-m-d'),
'months' => [],
];
}
$currentEnd = clone $start;
$currentEnd->endOfMonth();
$months[$year]['months'][] = [
'formatted' => $start->formatLocalized('%B %Y'),
'start' => $start->format('Y-m-d'),
'end' => $currentEnd->format('Y-m-d'),
'month' => $start->month,
'year' => $year,
];
$start->addMonth();
}
return $months;
}
/** /**
* This method generates a full report for the given period on all * This method generates a full report for the given period on all
* the users asset and cash accounts. * given accounts
* *
* @param Carbon $date * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param $shared * @param Collection $accounts
* *
* @return AccountCollection * @return AccountCollection
*/ */
public function getAccountReport(Carbon $date, Carbon $end, $shared) public function getAccountReport(Carbon $start, Carbon $end, Collection $accounts)
{ {
$startAmount = '0';
$endAmount = '0';
$accounts = $this->query->getAllAccounts($date, $end, $shared);
$start = '0';
$end = '0';
$diff = '0'; $diff = '0';
$ids = $accounts->pluck('id')->toArray();
$yesterday = clone $start;
$yesterday->subDay();
bcscale(2); bcscale(2);
// remove cash account, if any: // get balances for start.
$accounts = $accounts->filter( $startSet = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
function (Account $account) { ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
if ($account->accountType->type != 'Cash account') { ->whereIn('accounts.id', $ids)
return $account; ->whereNull('transaction_journals.deleted_at')
->whereNull('transactions.deleted_at')
->where('transaction_journals.date', '<=', $yesterday->format('Y-m-d'))
->groupBy('accounts.id')
->get(['accounts.id', DB::Raw('SUM(`transactions`.`amount`) as `balance`')]);
// and for end:
$endSet = Account::leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->whereIn('accounts.id', $ids)
->whereNull('transaction_journals.deleted_at')
->whereNull('transactions.deleted_at')
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->groupBy('accounts.id')
->get(['accounts.id', DB::Raw('SUM(`transactions`.`amount`) as `balance`')]);
$accounts->each(
function (Account $account) use ($startSet, $endSet) {
/**
* The balance for today always incorporates transactions
* made on today. So to get todays "start" balance, we sub one
* day.
*/
//
$currentStart = $startSet->filter(
function (Account $entry) use ($account) {
return $account->id == $entry->id;
}
);
if ($currentStart->first()) {
$account->startBalance = $currentStart->first()->balance;
} }
return null; $currentEnd = $endSet->filter(
function (Account $entry) use ($account) {
return $account->id == $entry->id;
}
);
if ($currentEnd->first()) {
$account->endBalance = $currentEnd->first()->balance;
}
} }
); );
// summarize: // summarize:
foreach ($accounts as $account) { foreach ($accounts as $account) {
$start = bcadd($start, $account->startBalance); $startAmount = bcadd($startAmount, $account->startBalance);
$end = bcadd($end, $account->endBalance); $endAmount = bcadd($endAmount, $account->endBalance);
$diff = bcadd($diff, bcsub($account->endBalance, $account->startBalance)); $diff = bcadd($diff, bcsub($account->endBalance, $account->startBalance));
} }
$object = new AccountCollection; $object = new AccountCollection;
$object->setStart($start); $object->setStart($startAmount);
$object->setEnd($end); $object->setEnd($endAmount);
$object->setDifference($diff); $object->setDifference($diff);
$object->setAccounts($accounts); $object->setAccounts($accounts);
@@ -92,37 +198,149 @@ class ReportHelper implements ReportHelperInterface
} }
/** /**
* * Get a full report on the users incomes during the period for the given accounts.
* 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 $start
* @param Carbon $end * @param Carbon $end
* @param boolean $shared * @param Collection $accounts
*
* @return Income
*/
public function getIncomeReport($start, $end, Collection $accounts)
{
$object = new Income;
$set = $this->query->income($accounts, $start, $end);
foreach ($set as $entry) {
$object->addToTotal($entry->journalAmount);
$object->addOrCreateIncome($entry);
}
return $object;
}
/**
* Get a full report on the users expenses during the period for a list of accounts.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Expense
*/
public function getExpenseReport($start, $end, Collection $accounts)
{
$object = new Expense;
$set = $this->query->expense($accounts, $start, $end);
foreach ($set as $entry) {
$object->addToTotal($entry->journalAmount); // can be positive, if it's a transfer
$object->addOrCreateExpense($entry);
}
return $object;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return BudgetCollection
*/
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts)
{
$object = new BudgetCollection;
/** @var \FireflyIII\Repositories\Budget\BudgetRepositoryInterface $repository */
$repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$set = $repository->getBudgets();
$allRepetitions = $repository->getAllBudgetLimitRepetitions($start, $end);
$allTotalSpent = $repository->spentAllPerDayForAccounts($accounts, $start, $end);
bcscale(2);
foreach ($set as $budget) {
$repetitions = $allRepetitions->filter(
function (LimitRepetition $rep) use ($budget) {
return $rep->budget_id == $budget->id;
}
);
$totalSpent = isset($allTotalSpent[$budget->id]) ? $allTotalSpent[$budget->id] : [];
// no repetition(s) for this budget:
if ($repetitions->count() == 0) {
$spent = array_sum($totalSpent);
$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 = $this->getSumOfRange($start, $end, $totalSpent);
// 200 en -100 is 100, vergeleken met 0 === 1
// 200 en -200 is 0, vergeleken met 0 === 0
// 200 en -300 is -100, vergeleken met 0 === -1
$left = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? bcadd($repetition->amount, $expenses) : 0;
$spent = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? $expenses : '0';
$overspent = bccomp(bcadd($repetition->amount, $expenses), '0') === 1 ? '0' : bcadd($expenses, $repetition->amount);
$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);
$budgetLine->setSpent($noBudget);
$object->addOverspent($noBudget);
$object->addBudgetLine($budgetLine);
return $object;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* *
* @return Balance * @return Balance
*/ */
public function getBalanceReport(Carbon $start, Carbon $end, $shared) public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts)
{ {
/** @var \FireflyIII\Repositories\Budget\BudgetRepositoryInterface $repository */
$repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); $repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
/** @var \FireflyIII\Repositories\Tag\TagRepositoryInterface $tagRepository */
$tagRepository = app('FireflyIII\Repositories\Tag\TagRepositoryInterface'); $tagRepository = app('FireflyIII\Repositories\Tag\TagRepositoryInterface');
$balance = new Balance; $balance = new Balance;
// build a balance header: // build a balance header:
$header = new BalanceHeader; $header = new BalanceHeader;
$budgets = $repository->getBudgetsAndLimitsInRange($start, $end);
$accounts = $this->query->getAllAccounts($start, $end, $shared); $spentData = $repository->spentPerBudgetPerAccount($budgets, $accounts, $start, $end);
$budgets = $repository->getBudgets();
foreach ($accounts as $account) { foreach ($accounts as $account) {
$header->addAccount($account); $header->addAccount($account);
} }
@@ -132,18 +350,21 @@ class ReportHelper implements ReportHelperInterface
$line = new BalanceLine; $line = new BalanceLine;
$line->setBudget($budget); $line->setBudget($budget);
// get budget amount for current period:
$rep = $repository->getCurrentRepetition($budget, $start, $end);
$line->setRepetition($rep);
// loop accounts: // loop accounts:
foreach ($accounts as $account) { foreach ($accounts as $account) {
$balanceEntry = new BalanceEntry; $balanceEntry = new BalanceEntry;
$balanceEntry->setAccount($account); $balanceEntry->setAccount($account);
// get spent: // get spent:
$spent = $this->query->spentInBudgetCorrected($account, $budget, $start, $end); // I think shared is irrelevant. $entry = $spentData->filter(
function (TransactionJournal $model) use ($budget, $account) {
return $model->account_id == $account->id && $model->budget_id == $budget->id;
}
);
$spent = 0;
if (!is_null($entry->first())) {
$spent = $entry->first()->spent;
}
$balanceEntry->setSpent($spent); $balanceEntry->setSpent($spent);
$line->addBalanceEntry($balanceEntry); $line->addBalanceEntry($balanceEntry);
} }
@@ -153,18 +374,36 @@ class ReportHelper implements ReportHelperInterface
// then a new line for without budget. // then a new line for without budget.
// and one for the tags: // and one for the tags:
// and one for "left unbalanced".
$empty = new BalanceLine; $empty = new BalanceLine;
$tags = new BalanceLine; $tags = new BalanceLine;
$diffLine = new BalanceLine; $diffLine = new BalanceLine;
$tagsLeft = $tagRepository->allCoveredByBalancingActs($accounts, $start, $end);
$tags->setRole(BalanceLine::ROLE_TAGROLE); $tags->setRole(BalanceLine::ROLE_TAGROLE);
$diffLine->setRole(BalanceLine::ROLE_DIFFROLE); $diffLine->setRole(BalanceLine::ROLE_DIFFROLE);
foreach ($accounts as $account) { foreach ($accounts as $account) {
$spent = $this->query->spentNoBudget($account, $start, $end); $entry = $spentData->filter(
$left = $tagRepository->coveredByBalancingActs($account, $start, $end); function (TransactionJournal $model) use ($account) {
return $model->account_id == $account->id && is_null($model->budget_id);
}
);
$spent = 0;
if (!is_null($entry->first())) {
$spent = $entry->first()->spent;
}
$leftEntry = $tagsLeft->filter(
function (Tag $tag) use ($account) {
return $tag->account_id == $account->id;
}
);
$left = 0;
if (!is_null($leftEntry->first())) {
$left = $leftEntry->first()->sum;
}
bcscale(2); bcscale(2);
$diff = bcsub($spent, $left); $diff = bcadd($spent, $left);
// budget // budget
$budgetEntry = new BalanceEntry; $budgetEntry = new BalanceEntry;
@@ -199,16 +438,20 @@ class ReportHelper implements ReportHelperInterface
* This method generates a full report for the given period on all * This method generates a full report for the given period on all
* the users bills and their payments. * the users bills and their payments.
* *
* Excludes bills which have not had a payment on the mentioned accounts.
*
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param Collection $accounts
* *
* @return BillCollection * @return BillCollection
*/ */
public function getBillReport(Carbon $start, Carbon $end) public function getBillReport(Carbon $start, Carbon $end, Collection $accounts)
{ {
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */ /** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
$repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface'); $repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface');
$bills = $repository->getBills(); $bills = $repository->getBillsForAccounts($accounts);
$journals = $repository->getAllJournalsInRange($bills, $start, $end);
$collection = new BillCollection; $collection = new BillCollection;
/** @var Bill $bill */ /** @var Bill $bill */
@@ -221,16 +464,17 @@ class ReportHelper implements ReportHelperInterface
// is hit in period? // is hit in period?
bcscale(2); bcscale(2);
$set = $repository->getJournalsInRange($bill, $start, $end);
if ($set->count() == 0) { $entry = $journals->filter(
$billLine->setHit(false); function (TransactionJournal $journal) use ($bill) {
} else { return $journal->bill_id == $bill->id;
$billLine->setHit(true);
$amount = '0';
foreach ($set as $entry) {
$amount = bcadd($amount, $entry->amount);
} }
$billLine->setAmount($amount); );
if (!is_null($entry->first())) {
$billLine->setAmount($entry->first()->journalAmount);
$billLine->setHit(true);
} else {
$billLine->setHit(false);
} }
$collection->addBill($billLine); $collection->addBill($billLine);
@@ -238,168 +482,33 @@ class ReportHelper implements ReportHelperInterface
} }
return $collection; return $collection;
} }
/** /**
* Take the array as returned by SingleCategoryRepositoryInterface::spentPerDay and SingleCategoryRepositoryInterface::earnedByDay
* and sum up everything in the array in the given range.
*
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param boolean $shared * @param array $array
* *
* @return BudgetCollection * @return string
*/ */
public function getBudgetReport(Carbon $start, Carbon $end, $shared) protected function getSumOfRange(Carbon $start, Carbon $end, array $array)
{ {
$object = new BudgetCollection;
/** @var \FireflyIII\Repositories\Budget\BudgetRepositoryInterface $repository */
$repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$set = $repository->getBudgets();
bcscale(2); bcscale(2);
$sum = '0';
$currentStart = clone $start; // to not mess with the original one
$currentEnd = clone $end; // to not mess with the original one
foreach ($set as $budget) { while ($currentStart <= $currentEnd) {
$date = $currentStart->format('Y-m-d');
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end); if (isset($array[$date])) {
$sum = bcadd($sum, $array[$date]);
// no repetition(s) for this budget: }
if ($repetitions->count() == 0) { $currentStart->addDay();
$spent = $repository->balanceInPeriod($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: return $sum;
/** @var LimitRepetition $repetition */
foreach ($repetitions as $repetition) {
$budgetLine = new BudgetLine;
$budgetLine->setBudget($budget);
$budgetLine->setRepetition($repetition);
$expenses = $repository->balanceInPeriod($budget, $repetition->startdate, $repetition->enddate, $shared);
$expenses = $expenses * -1;
$left = $expenses < $repetition->amount ? bcsub($repetition->amount, $expenses) : 0;
$spent = $expenses > $repetition->amount ? 0 : $expenses;
$overspent = $expenses > $repetition->amount ? bcsub($expenses, $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('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
$set = $repository->getCategories();
foreach ($set as $category) {
$spent = $repository->balanceInPeriod($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_positive);
$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_positive);
$object->addOrCreateIncome($entry);
}
return $object;
}
/**
* @param Carbon $date
*
* @return array
*/
public function listOfMonths(Carbon $date)
{
$start = clone $date;
$end = Carbon::now();
$months = [];
while ($start <= $end) {
$year = $start->year;
$months[$year][] = [
'formatted' => $start->formatLocalized('%B %Y'),
'month' => $start->month,
'year' => $year,
];
$start->addMonth();
}
return $months;
} }
} }

View File

@@ -10,6 +10,7 @@ use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
use FireflyIII\Helpers\Collection\Category as CategoryCollection; use FireflyIII\Helpers\Collection\Category as CategoryCollection;
use FireflyIII\Helpers\Collection\Expense; use FireflyIII\Helpers\Collection\Expense;
use FireflyIII\Helpers\Collection\Income; use FireflyIII\Helpers\Collection\Income;
use Illuminate\Support\Collection;
/** /**
* Interface ReportHelperInterface * Interface ReportHelperInterface
@@ -21,75 +22,78 @@ interface ReportHelperInterface
/** /**
* This method generates a full report for the given period on all * This method generates a full report for the given period on all
* the users asset and cash accounts. * given accounts
* *
* @param Carbon $date * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param boolean $shared * @param Collection $accounts
* *
* @return AccountCollection * @return AccountCollection
*/ */
public function getAccountReport(Carbon $date, Carbon $end, $shared); public function getAccountReport(Carbon $start, Carbon $end, Collection $accounts);
/** /**
* This method generates a full report for the given period on all * This method generates a full report for the given period on all
* the users bills and their payments. * the users bills and their payments.
* *
* Excludes bills which have not had a payment on the mentioned accounts.
*
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param Collection $accounts
* *
* @return BillCollection * @return BillCollection
*/ */
public function getBillReport(Carbon $start, Carbon $end); public function getBillReport(Carbon $start, Carbon $end, Collection $accounts);
/** /**
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param boolean $shared * @param Collection $accounts
* *
* @return Balance * @return Balance
*/ */
public function getBalanceReport(Carbon $start, Carbon $end, $shared); public function getBalanceReport(Carbon $start, Carbon $end, Collection $accounts);
/** /**
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param boolean $shared * @param Collection $accounts
* *
* @return BudgetCollection * @return BudgetCollection
*/ */
public function getBudgetReport(Carbon $start, Carbon $end, $shared); public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts);
/** /**
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param boolean $shared * @param Collection $accounts
* *
* @return CategoryCollection * @return CategoryCollection
*/ */
public function getCategoryReport(Carbon $start, Carbon $end, $shared); public function getCategoryReport(Carbon $start, Carbon $end, Collection $accounts);
/** /**
* Get a full report on the users expenses during the period. * Get a full report on the users expenses during the period for a list of accounts.
* *
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param boolean $shared * @param Collection $accounts
* *
* @return Expense * @return Expense
*/ */
public function getExpenseReport($start, $end, $shared); public function getExpenseReport($start, $end, Collection $accounts);
/** /**
* Get a full report on the users incomes during the period. * Get a full report on the users incomes during the period for the given accounts.
* *
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param boolean $shared * @param Collection $accounts
* *
* @return Income * @return Income
*/ */
public function getIncomeReport($start, $end, $shared); public function getIncomeReport($start, $end, Collection $accounts);
/** /**
* @param Carbon $date * @param Carbon $date

View File

@@ -4,14 +4,10 @@ namespace FireflyIII\Helpers\Report;
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Crypt; use DB;
use FireflyIII\Models\Account; use FireflyIII\Models\TransactionType;
use FireflyIII\Models\Budget;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Steam;
/** /**
* Class ReportQuery * Class ReportQuery
@@ -20,260 +16,163 @@ use Steam;
*/ */
class ReportQuery implements ReportQueryInterface class ReportQuery implements ReportQueryInterface
{ {
/**
* See ReportQueryInterface::incomeInPeriodCorrected.
*
* This method's length is caused mainly by the query build stuff. Therefor:
*
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @param Carbon $start
* @param Carbon $end
* @param bool $includeShared
*
* @return Collection
*
*/
public function expenseInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false)
{
$query = $this->queryJournalsWithTransactions($start, $end);
if ($includeShared === false) {
$query->where(
function (Builder $query) {
$query->where(
function (Builder $q) { // only get withdrawals not from a shared account
$q->where('transaction_types.type', 'Withdrawal');
$q->where('acm_from.data', '!=', '"sharedAsset"');
}
);
$query->orWhere(
function (Builder $q) { // and transfers from a shared account.
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_to.data', '=', '"sharedAsset"');
$q->where('acm_from.data', '!=', '"sharedAsset"');
}
);
}
);
} else {
$query->where('transaction_types.type', 'Withdrawal'); // any withdrawal is fine.
}
$query->orderBy('transaction_journals.date');
$data = $query->get( // get everything
['transaction_journals.*', 'transaction_types.type', 'ac_to.name as name', 'ac_to.id as account_id', 'ac_to.encrypted as account_encrypted']
);
$data->each(
function (TransactionJournal $journal) {
if (intval($journal->account_encrypted) == 1) {
$journal->name = Crypt::decrypt($journal->name);
}
}
);
return $data;
}
/** /**
* Get a users accounts combined with various meta-data related to the start and end date. * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers)
* grouped by month like so: "2015-01" => '123.45'
* *
* @param Collection $accounts
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $includeShared
* *
* @return Collection * @return array
*/ */
public function getAllAccounts(Carbon $start, Carbon $end, $includeShared = false) public function spentPerMonth(Collection $accounts, Carbon $start, Carbon $end)
{ {
$query = Auth::user()->accounts()->orderBy('accounts.name', 'ASC') $ids = $accounts->pluck('id')->toArray();
->accountTypeIn(['Default account', 'Asset account', 'Cash account']); $query = Auth::user()->transactionjournals()
if ($includeShared === false) { ->leftJoin(
$query->leftJoin( 'transactions AS t_from', function (JoinClause $join) {
'account_meta', function (JoinClause $join) { $join->on('transaction_journals.id', '=', 't_from.transaction_journal_id')->where('t_from.amount', '<', 0);
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
} }
) )
->where( ->leftJoin(
function (Builder $query) { 'transactions AS t_to', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 't_to.transaction_journal_id')->where('t_to.amount', '>', 0);
$query->where('account_meta.data', '!=', '"sharedAsset"');
$query->orWhereNull('account_meta.data');
} }
)
->whereIn('t_from.account_id', $ids)
->whereNotIn('t_to.account_id', $ids)
->after($start)
->before($end)
->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE])
->groupBy('dateFormatted')
->get(
[
DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") AS `dateFormatted`'),
DB::Raw('SUM(`t_from`.`amount`) AS `sum`')
]
); );
} $array = [];
$set = $query->get(['accounts.*']); foreach ($query as $result) {
$set->each( $array[$result->dateFormatted] = $result->sum;
function (Account $account) use ($start, $end) {
/**
* The balance for today always incorporates transactions
* made on today. So to get todays "start" balance, we sub one
* day.
*/
$yesterday = clone $start;
$yesterday->subDay();
/** @noinspection PhpParamsInspection */
$account->startBalance = Steam::balance($account, $yesterday);
$account->endBalance = Steam::balance($account, $end);
}
);
return $set;
} }
return $array;
}
/** /**
* This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers)
* will simply list the transaction journals only. This should allow any follow up counting to be accurate with * grouped by month like so: "2015-01" => '123.45'
* regards to tags.
*
* This method returns all "income" journals in a certain period, which are both transfers from a shared account
* and "ordinary" deposits. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
* not group and returns different fields.
* *
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedPerMonth(Collection $accounts, Carbon $start, Carbon $end)
{
$ids = $accounts->pluck('id')->toArray();
$query = Auth::user()->transactionjournals()
->leftJoin(
'transactions AS t_from', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 't_from.transaction_journal_id')->where('t_from.amount', '<', 0);
}
)
->leftJoin(
'transactions AS t_to', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 't_to.transaction_journal_id')->where('t_to.amount', '>', 0);
}
)
->whereIn('t_to.account_id', $ids)
->whereNotIn('t_from.account_id', $ids)
->after($start)
->before($end)
->transactionTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE])
->groupBy('dateFormatted')
->get(
[
DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") AS `dateFormatted`'),
DB::Raw('SUM(`t_to`.`amount`) AS `sum`')
]
);
$array = [];
foreach ($query as $result) {
$array[$result->dateFormatted] = $result->sum;
}
return $array;
}
/**
* This method returns all the "in" transaction journals for the given account and given period. The amount
* is stored in "journalAmount".
*
* @param Collection $accounts
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $includeShared
* *
* @return Collection * @return Collection
*/ */
public function incomeInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false) public function income(Collection $accounts, Carbon $start, Carbon $end)
{ {
$query = $this->queryJournalsWithTransactions($start, $end); $ids = $accounts->pluck('id')->toArray();
if ($includeShared === false) { $set = Auth::user()->transactionjournals()
// only get deposits not to a shared account ->leftJoin(
// and transfers to a shared account.
$query->where(
function (Builder $query) {
$query->where(
function (Builder $q) {
$q->where('transaction_types.type', 'Deposit');
$q->where('acm_to.data', '!=', '"sharedAsset"');
}
);
$query->orWhere(
function (Builder $q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_from.data', '=', '"sharedAsset"');
$q->where('acm_to.data','!=','"sharedAsset"');
}
);
}
);
} else {
// any deposit is fine.
$query->where('transaction_types.type', 'Deposit');
}
$query->orderBy('transaction_journals.date');
// get everything
$data = $query->get(
['transaction_journals.*', 'transaction_types.type', 'ac_from.name as name', 'ac_from.id as account_id', 'ac_from.encrypted as account_encrypted']
);
$data->each(
function (TransactionJournal $journal) {
if (intval($journal->account_encrypted) == 1) {
$journal->name = Crypt::decrypt($journal->name);
}
}
);
$data = $data->filter(
function (TransactionJournal $journal) {
if ($journal->amount != 0) {
return $journal;
}
return null;
}
);
return $data;
}
/**
* Covers tags
*
* @param Account $account
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return float
*/
public function spentInBudgetCorrected(Account $account, Budget $budget, Carbon $start, Carbon $end)
{
bcscale(2);
return bcmul(
Auth::user()->transactionjournals()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->transactionTypes(['Withdrawal'])
->where('transactions.account_id', $account->id)
->before($end)
->after($start)
->where('budget_transaction_journal.budget_id', $budget->id)
->get(['transaction_journals.*'])->sum('amount'), -1
);
}
/**
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return string
*/
public function spentNoBudget(Account $account, Carbon $start, Carbon $end)
{
return
Auth::user()->transactionjournals()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->transactionTypes(['Withdrawal'])
->where('transactions.account_id', $account->id)
->before($end)
->after($start)
->whereNull('budget_transaction_journal.budget_id')->get(['transaction_journals.*'])->sum('amount');
}
/**
* @param Carbon $start
* @param Carbon $end
*
* @return Builder
*/
protected function queryJournalsWithTransactions(Carbon $start, Carbon $end)
{
$query = TransactionJournal::
leftJoin(
'transactions as t_from', function (JoinClause $join) { '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(
'account_meta as acm_from', function (JoinClause $join) {
$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', 't_from.account_id', '=', 'accounts.id')
->transactionTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE])
->before($end)
->after($start)
->whereIn('t_to.account_id', $ids)
->whereNotIn('t_from.account_id', $ids)
->get(['transaction_journals.*', 't_to.amount as journalAmount', 'accounts.id as account_id', 'accounts.name as account_name']);
return $set;
}
/**
* This method returns all the "out" transaction journals for the given account and given period. The amount
* is stored in "journalAmount".
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function expense(Collection $accounts, Carbon $start, Carbon $end)
{
$ids = $accounts->pluck('id')->toArray();
$set = Auth::user()->transactionjournals()
->leftJoin( ->leftJoin(
'account_meta as acm_to', function (JoinClause $join) { 'transactions as t_from', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole'); $join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
} }
) )
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id'); ->leftJoin(
$query->before($end)->after($start)->where('transaction_journals.user_id', Auth::user()->id); 'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('accounts', 't_to.account_id', '=', 'accounts.id')
->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE])
->before($end)
->after($start)
->whereIn('t_from.account_id', $ids)
->whereNotIn('t_to.account_id', $ids)
->get(['transaction_journals.*', 't_from.amount as journalAmount', 'accounts.id as account_id', 'accounts.name as account_name']);
return $query; return $set;
} }
} }

View File

@@ -3,8 +3,6 @@
namespace FireflyIII\Helpers\Report; namespace FireflyIII\Helpers\Report;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**
@@ -16,65 +14,52 @@ interface ReportQueryInterface
{ {
/** /**
* See ReportQueryInterface::incomeInPeriodCorrected * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers)
* * grouped by month like so: "2015-01" => '123.45'
* 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 Collection $accounts
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $includeShared
*
* @return Collection
* *
* @return array
*/ */
public function expenseInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false); public function earnedPerMonth(Collection $accounts, Carbon $start, Carbon $end);
/** /**
* Get a users accounts combined with various meta-data related to the start and end date. * This method returns all the "out" transaction journals for the given account and given period. The amount
* is stored in "journalAmount".
* *
* @param Collection $accounts
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $includeShared
* *
* @return Collection * @return Collection
*/ */
public function getAllAccounts(Carbon $start, Carbon $end, $includeShared = false); public function expense(Collection $accounts, Carbon $start, Carbon $end);
/** /**
* This method works the same way as ReportQueryInterface::incomeInPeriod does, but instead of returning results * This method returns all the "in" transaction journals for the given account and given period. The amount
* will simply list the transaction journals only. This should allow any follow up counting to be accurate with * is stored in "journalAmount".
* regards to tags.
* *
* @param Collection $accounts
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $includeShared
* *
* @return Collection * @return Collection
*/ */
public function incomeInPeriodCorrected(Carbon $start, Carbon $end, $includeShared = false); public function income(Collection $accounts, Carbon $start, Carbon $end);
/** /**
* Covers tags as well. * Returns an array of the amount of money spent in the given accounts (on withdrawals, opening balances and transfers)
* grouped by month like so: "2015-01" => '123.45'
* *
* @param Account $account * @param Collection $accounts
* @param Budget $budget
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @return float * @return array
*/ */
public function spentInBudgetCorrected(Account $account, Budget $budget, Carbon $start, Carbon $end); public function spentPerMonth(Collection $accounts, Carbon $start, Carbon $end);
/**
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return string
*/
public function spentNoBudget(Account $account, Carbon $start, Carbon $end);
} }

View File

@@ -6,7 +6,7 @@ use Config;
use ExpandedForm; use ExpandedForm;
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 as ARI;
use Input; use Input;
use Preferences; use Preferences;
use Session; use Session;
@@ -38,6 +38,8 @@ 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 = trans('firefly.make_new_' . $what . '_account'); $subTitle = trans('firefly.make_new_' . $what . '_account');
@@ -54,11 +56,12 @@ class AccountController extends Controller
} }
/** /**
* @param ARI $repository
* @param Account $account * @param Account $account
* *
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function delete(AccountRepositoryInterface $repository, Account $account) public function delete(ARI $repository, Account $account)
{ {
$typeName = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type); $typeName = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
$subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]); $subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]);
@@ -74,12 +77,12 @@ class AccountController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* @param Account $account * @param Account $account
* *
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function destroy(AccountRepositoryInterface $repository, Account $account) public function destroy(ARI $repository, Account $account)
{ {
$type = $account->accountType->type; $type = $account->accountType->type;
$typeName = Config::get('firefly.shortNamesByFullName.' . $type); $typeName = Config::get('firefly.shortNamesByFullName.' . $type);
@@ -95,12 +98,12 @@ class AccountController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* @param Account $account * @param Account $account
* *
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function edit(AccountRepositoryInterface $repository, Account $account) public function edit(ARI $repository, Account $account)
{ {
$what = Config::get('firefly.shortNamesByFullName')[$account->accountType->type]; $what = Config::get('firefly.shortNamesByFullName')[$account->accountType->type];
@@ -140,40 +143,31 @@ class AccountController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* @param $what * @param $what
* *
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function index(AccountRepositoryInterface $repository, $what) public function index(ARI $repository, $what)
{ {
$subTitle = trans('firefly.' . $what . '_accounts'); $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);
// last activity:
/**
* HERE WE ARE
*/
$start = clone Session::get('start', Carbon::now()->startOfMonth()); $start = clone Session::get('start', Carbon::now()->startOfMonth());
$end = clone Session::get('end', Carbon::now()->endOfMonth()); $end = clone Session::get('end', Carbon::now()->endOfMonth());
$start->subDay(); $start->subDay();
// start balances: $ids = $accounts->pluck('id')->toArray();
$ids = [];
foreach ($accounts as $account) {
$ids[] = $account->id;
}
$startBalances = Steam::balancesById($ids, $start); $startBalances = Steam::balancesById($ids, $start);
$endBalances = Steam::balancesById($ids, $end); $endBalances = Steam::balancesById($ids, $end);
$activities = Steam::getLastActivities($ids); $activities = Steam::getLastActivities($ids);
$accounts->each( $accounts->each(
function (Account $account) use ($activities, $startBalances, $endBalances) { function (Account $account) use ($activities, $startBalances, $endBalances) {
$account->lastActivityDate = isset($activities[$account->id]) ? $activities[$account->id] : null; $account->lastActivityDate = $this->isInArray($activities, $account->id);
$account->startBalance = isset($startBalances[$account->id]) ? $startBalances[$account->id] : null; $account->startBalance = $this->isInArray($startBalances, $account->id);
$account->endBalance = isset($endBalances[$account->id]) ? $endBalances[$account->id] : null; $account->endBalance = $this->isInArray($endBalances, $account->id);
} }
); );
@@ -181,12 +175,12 @@ class AccountController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* @param Account $account * @param Account $account
* *
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function show(AccountRepositoryInterface $repository, Account $account) public function show(ARI $repository, Account $account)
{ {
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page')); $page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $account->accountType->type); $subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $account->accountType->type);
@@ -201,23 +195,24 @@ class AccountController extends Controller
/** /**
* @param AccountFormRequest $request * @param AccountFormRequest $request
* @param AccountRepositoryInterface $repository * @param ARI $repository
* *
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function store(AccountFormRequest $request, AccountRepositoryInterface $repository) public function store(AccountFormRequest $request, ARI $repository)
{ {
$accountData = [ $accountData = [
'name' => $request->input('name'), 'name' => $request->input('name'),
'accountType' => $request->input('what'), 'accountType' => $request->input('what'),
'virtualBalance' => round($request->input('virtualBalance'), 2), 'virtualBalance' => round($request->input('virtualBalance'), 2),
'virtualBalanceCurrency' => intval($request->input('amount_currency_id_virtualBalance')),
'active' => true, 'active' => true,
'user' => Auth::user()->id, 'user' => Auth::user()->id,
'iban' => $request->input('iban'), 'iban' => $request->input('iban'),
'accountRole' => $request->input('accountRole'), 'accountRole' => $request->input('accountRole'),
'openingBalance' => round($request->input('openingBalance'), 2), 'openingBalance' => round($request->input('openingBalance'), 2),
'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')), 'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')),
'openingBalanceCurrency' => intval($request->input('balance_currency_id')), 'openingBalanceCurrency' => intval($request->input('amount_currency_id_openingBalance')),
]; ];
@@ -239,12 +234,12 @@ class AccountController extends Controller
/** /**
* @param AccountFormRequest $request * @param AccountFormRequest $request
* @param AccountRepositoryInterface $repository * @param ARI $repository
* @param Account $account * @param Account $account
* *
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function update(AccountFormRequest $request, AccountRepositoryInterface $repository, Account $account) public function update(AccountFormRequest $request, ARI $repository, Account $account)
{ {
$accountData = [ $accountData = [
@@ -279,4 +274,20 @@ class AccountController extends Controller
} }
/**
* @param array $array
* @param $entryId
*
* @return null|mixed
*/
protected function isInArray(array $array, $entryId)
{
if (isset($array[$entryId])) {
return $array[$entryId];
}
return null;
}
} }

View File

@@ -91,6 +91,7 @@ class AttachmentController extends Controller
/** /**
* @param Attachment $attachment * @param Attachment $attachment
* @param AttachmentHelperInterface $helper
*/ */
public function download(Attachment $attachment, AttachmentHelperInterface $helper) public function download(Attachment $attachment, AttachmentHelperInterface $helper)
{ {

View File

@@ -1,6 +1,7 @@
<?php namespace FireflyIII\Http\Controllers\Auth; <?php namespace FireflyIII\Http\Controllers\Auth;
use Auth; use Auth;
use Config;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Role; use FireflyIII\Models\Role;
use FireflyIII\User; use FireflyIII\User;
@@ -8,12 +9,12 @@ use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Foundation\Auth\ThrottlesLogins; use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Mail\Message; use Illuminate\Mail\Message;
use Log;
use Mail; use Mail;
use Request as Rq; use Request as Rq;
use Session; use Session;
use Twig; use Twig;
use Validator; use Validator;
use Log;
/** /**
* Class AuthController * Class AuthController
@@ -32,9 +33,8 @@ class AuthController extends Controller
public function getLogout() public function getLogout()
{ {
Auth::logout(); Auth::logout();
Log::debug('Logout and redirect to root.');
return redirect('/login'); return redirect('/auth/login');
} }
/** /**
@@ -58,15 +58,7 @@ class AuthController extends Controller
*/ */
public function postLogin(Request $request) public function postLogin(Request $request)
{ {
$this->validate( $this->validate($request, [$this->loginUsername() => 'required', 'password' => 'required',]);
$request, [
$this->loginUsername() => 'required', 'password' => 'required',
]
);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
$throttles = $this->isUsingThrottlesLoginsTrait(); $throttles = $this->isUsingThrottlesLoginsTrait();
if ($throttles && $this->hasTooManyLoginAttempts($request)) { if ($throttles && $this->hasTooManyLoginAttempts($request)) {
@@ -80,10 +72,7 @@ class AuthController extends Controller
return $this->handleUserWasAuthenticated($request, $throttles); return $this->handleUserWasAuthenticated($request, $throttles);
} }
// default error message:
$message = $this->getFailedLoginMessage(); $message = $this->getFailedLoginMessage();
// try to find a blocked user with this email address.
/** @var User $foundUser */ /** @var User $foundUser */
$foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first(); $foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first();
if (!is_null($foundUser)) { if (!is_null($foundUser)) {
@@ -95,22 +84,13 @@ class AuthController extends Controller
$message = trans('firefly.' . $code . '_error', ['email' => $credentials['email']]); $message = trans('firefly.' . $code . '_error', ['email' => $credentials['email']]);
} }
// try
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
if ($throttles) { if ($throttles) {
$this->incrementLoginAttempts($request); $this->incrementLoginAttempts($request);
} }
return redirect($this->loginPath()) return redirect($this->loginPath())
->withInput($request->only($this->loginUsername(), 'remember')) ->withInput($request->only($this->loginUsername(), 'remember'))
->withErrors( ->withErrors([$this->loginUsername() => $message,]);
[
$this->loginUsername() => $message,
]
);
} }
@@ -160,21 +140,35 @@ class AuthController extends Controller
} }
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
$data = $request->all(); $data = $request->all();
$data['password'] = bcrypt($data['password']); $data['password'] = bcrypt($data['password']);
// is user email domain blocked?
if ($this->isBlockedDomain($data['email'])) {
$validator->getMessageBag()->add('email', trans('validation.invalid_domain'));
$this->throwValidationException(
$request, $validator
);
}
Auth::login($this->create($data)); Auth::login($this->create($data));
// get the email address // get the email address
if (Auth::user() instanceof User) { if (Auth::user() instanceof User) {
$email = Auth::user()->email; $email = Auth::user()->email;
$address = route('index'); $address = route('index');
$ipAddress = $request->ip();
// send email. // send email.
try {
Mail::send( Mail::send(
['emails.registered-html', 'emails.registered'], ['address' => $address], function (Message $message) use ($email) { ['emails.registered-html', 'emails.registered'], ['address' => $address, 'ip' => $ipAddress], function (Message $message) use ($email) {
$message->to($email, $email)->subject('Welcome to Firefly III! '); $message->to($email, $email)->subject('Welcome to Firefly III! ');
} }
); );
} catch (\Swift_TransportException $e) {
Log::error($e->getMessage());
}
// set flash message // set flash message
Session::flash('success', 'You have registered successfully!'); Session::flash('success', 'You have registered successfully!');
@@ -197,6 +191,40 @@ class AuthController extends Controller
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
} }
/**
* @return array
*/
protected function getBlockedDomains()
{
$set = Config::get('mail.blocked_domains');
$domains = [];
foreach ($set as $entry) {
$domain = trim($entry);
if (strlen($domain) > 0) {
$domains[] = $domain;
}
}
return $domains;
}
/**
* @param $email
*
* @return bool
*/
protected function isBlockedDomain($email)
{
$parts = explode('@', $email);
$blocked = $this->getBlockedDomains();
if (isset($parts[1]) && in_array($parts[1], $blocked)) {
return true;
}
return false;
}
/** /**
* Get a validator for an incoming registration request. * Get a validator for an incoming registration request.
* *

View File

@@ -1,7 +1,11 @@
<?php namespace FireflyIII\Http\Controllers\Auth; <?php namespace FireflyIII\Http\Controllers\Auth;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\User;
use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request;
use Illuminate\Mail\Message;
use Illuminate\Support\Facades\Password;
/** /**
* Class PasswordController * Class PasswordController
@@ -41,4 +45,41 @@ class PasswordController extends Controller
$this->middleware('guest'); $this->middleware('guest');
} }
/**
* Send a reset link to the given user.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
public function postEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
$user = User::whereEmail($request->get('email'))->first();
if (!is_null($user) && intval($user->blocked) === 1) {
$response = 'passwords.blocked';
} else {
$response = Password::sendResetLink(
$request->only('email'), function (Message $message) {
$message->subject($this->getEmailSubject());
}
);
}
switch ($response) {
case Password::RESET_LINK_SENT:
return redirect()->back()->with('status', trans($response));
case Password::INVALID_USER:
case 'passwords.blocked':
return redirect()->back()->withErrors(['email' => trans($response)]);
}
abort(404);
return '';
}
} }

View File

@@ -6,7 +6,9 @@ use Carbon\Carbon;
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;
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Illuminate\Support\Collection;
use Input; use Input;
use Navigation; use Navigation;
use Preferences; use Preferences;
@@ -19,7 +21,6 @@ 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
{ {
@@ -133,9 +134,11 @@ class BudgetController extends Controller
/** /**
* @param BudgetRepositoryInterface $repository * @param BudgetRepositoryInterface $repository
* *
* @param ARI $accountRepository
*
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function index(BudgetRepositoryInterface $repository) public function index(BudgetRepositoryInterface $repository, ARI $accountRepository)
{ {
$budgets = $repository->getActiveBudgets(); $budgets = $repository->getActiveBudgets();
$inactive = $repository->getInactiveBudgets(); $inactive = $repository->getInactiveBudgets();
@@ -147,6 +150,8 @@ class BudgetController extends Controller
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd'); $key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
$budgetIncomeTotal = Preferences::get($key, 1000)->data; $budgetIncomeTotal = Preferences::get($key, 1000)->data;
$period = Navigation::periodShow($start, $range); $period = Navigation::periodShow($start, $range);
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
bcscale(2); bcscale(2);
/** /**
* Do some cleanup: * Do some cleanup:
@@ -156,7 +161,7 @@ class BudgetController extends Controller
// loop the budgets: // loop the budgets:
/** @var Budget $budget */ /** @var Budget $budget */
foreach ($budgets as $budget) { foreach ($budgets as $budget) {
$budget->spent = $repository->balanceInPeriod($budget, $start, $end); $budget->spent = $repository->balanceInPeriod($budget, $start, $end, $accounts);
$budget->currentRep = $repository->getCurrentRepetition($budget, $start, $end); $budget->currentRep = $repository->getCurrentRepetition($budget, $start, $end);
if ($budget->currentRep) { if ($budget->currentRep) {
$budgeted = bcadd($budgeted, $budget->currentRep->amount); $budgeted = bcadd($budgeted, $budget->currentRep->amount);
@@ -227,13 +232,26 @@ class BudgetController extends Controller
$journals = $repository->getJournals($budget, $repetition); $journals = $repository->getJournals($budget, $repetition);
if (is_null($repetition->id)) { if (is_null($repetition->id)) {
$limits = $repository->getBudgetLimits($budget); $start = $repository->firstActivity($budget);
$end = new Carbon;
$set = $budget->limitrepetitions()->orderBy('startdate', 'DESC')->get();
$subTitle = e($budget->name); $subTitle = e($budget->name);
} else { } else {
$limits = [$repetition->budgetLimit]; $start = $repetition->startdate;
$end = $repetition->enddate;
$set = new Collection([$repetition]);
$subTitle = trans('firefly.budget_in_month', ['name' => $budget->name, 'month' => $repetition->startdate->formatLocalized($this->monthFormat)]); $subTitle = trans('firefly.budget_in_month', ['name' => $budget->name, 'month' => $repetition->startdate->formatLocalized($this->monthFormat)]);
} }
$spentArray = $repository->spentPerDay($budget, $start, $end);
$limits = new Collection();
/** @var LimitRepetition $entry */
foreach ($set as $entry) {
$entry->spent = $this->getSumOfRange($entry->startdate, $entry->enddate, $spentArray);
$limits->push($entry);
}
$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'));
@@ -279,7 +297,7 @@ class BudgetController extends Controller
{ {
$budgetData = [ $budgetData = [
'name' => $request->input('name'), 'name' => $request->input('name'),
'active' => intval($request->input('active')) == 1 'active' => intval($request->input('active')) == 1,
]; ];
$repository->update($budget, $budgetData); $repository->update($budget, $budgetData);

View File

@@ -4,7 +4,8 @@ use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Http\Requests\CategoryFormRequest; use FireflyIII\Http\Requests\CategoryFormRequest;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface as CRI;
use FireflyIII\Repositories\Category\SingleCategoryRepositoryInterface as SCRI;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -68,12 +69,12 @@ class CategoryController extends Controller
} }
/** /**
* @param CategoryRepositoryInterface $repository * @param SCRI $repository
* @param Category $category * @param Category $category
* *
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function destroy(CategoryRepositoryInterface $repository, Category $category) public function destroy(SCRI $repository, Category $category)
{ {
$name = $category->name; $name = $category->name;
@@ -107,17 +108,18 @@ class CategoryController extends Controller
} }
/** /**
* @param CategoryRepositoryInterface $repository * @param CRI $repository
* @param SCRI $singleRepository
* *
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function index(CategoryRepositoryInterface $repository) public function index(CRI $repository, SCRI $singleRepository)
{ {
$categories = $repository->getCategories(); $categories = $repository->listCategories();
$categories->each( $categories->each(
function (Category $category) use ($repository) { function (Category $category) use ($singleRepository) {
$category->lastActivity = $repository->getLatestActivity($category); $category->lastActivity = $singleRepository->getLatestActivity($category);
} }
); );
@@ -125,15 +127,15 @@ class CategoryController extends Controller
} }
/** /**
* @param CategoryRepositoryInterface $repository * @param CRI $repository
* *
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function noCategory(CategoryRepositoryInterface $repository) public function noCategory(CRI $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->getWithoutCategory($start, $end); $list = $repository->listNoCategory($start, $end);
$subTitle = trans( $subTitle = trans(
'firefly.without_category_between', 'firefly.without_category_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)] ['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
@@ -143,12 +145,14 @@ class CategoryController extends Controller
} }
/** /**
* @param CategoryRepositoryInterface $repository * @param SCRI $repository
* @param Category $category * @param Category $category
* *
* @param $date
*
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function showWithDate(CategoryRepositoryInterface $repository, Category $category, $date) public function showWithDate(SCRI $repository, Category $category, $date)
{ {
$carbon = new Carbon($date); $carbon = new Carbon($date);
$range = Preferences::get('viewRange', '1M')->data; $range = Preferences::get('viewRange', '1M')->data;
@@ -168,12 +172,12 @@ class CategoryController extends Controller
} }
/** /**
* @param CategoryRepositoryInterface $repository * @param SCRI $repository
* @param Category $category * @param Category $category
* *
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function show(CategoryRepositoryInterface $repository, Category $category) public function show(SCRI $repository, Category $category)
{ {
$hideCategory = true; // used in list. $hideCategory = true; // used in list.
$page = intval(Input::get('page')); $page = intval(Input::get('page'));
@@ -198,6 +202,12 @@ class CategoryController extends Controller
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty('category-show'); $cache->addProperty('category-show');
$cache->addProperty($category->id); $cache->addProperty($category->id);
// get all spent and earned data:
// get amount earned in period, grouped by day.
$spentArray = $repository->spentPerDay($category, $start, $end);
$earnedArray = $repository->earnedPerDay($category, $start, $end);
if ($cache->has()) { if ($cache->has()) {
$entries = $cache->get(); $entries = $cache->get();
} else { } else {
@@ -206,9 +216,9 @@ class CategoryController extends Controller
$end = Navigation::startOfPeriod($end, $range); $end = Navigation::startOfPeriod($end, $range);
$currentEnd = Navigation::endOfPeriod($end, $range); $currentEnd = Navigation::endOfPeriod($end, $range);
// here do something. // get data from spentArray:
$spent = $repository->spentInPeriod($category, $end, $currentEnd); $spent = $this->getSumOfRange($end, $currentEnd, $spentArray);
$earned = $repository->earnedInPeriod($category, $end, $currentEnd); $earned = $this->getSumOfRange($end, $currentEnd, $earnedArray);
$dateStr = $end->format('Y-m-d'); $dateStr = $end->format('Y-m-d');
$dateName = Navigation::periodShow($end, $range); $dateName = Navigation::periodShow($end, $range);
$entries->push([$dateStr, $dateName, $spent, $earned]); $entries->push([$dateStr, $dateName, $spent, $earned]);
@@ -224,11 +234,11 @@ class CategoryController extends Controller
/** /**
* @param CategoryFormRequest $request * @param CategoryFormRequest $request
* @param CategoryRepositoryInterface $repository * @param SCRI $repository
* *
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function store(CategoryFormRequest $request, CategoryRepositoryInterface $repository) public function store(CategoryFormRequest $request, SCRI $repository)
{ {
$categoryData = [ $categoryData = [
'name' => $request->input('name'), 'name' => $request->input('name'),
@@ -251,12 +261,12 @@ class CategoryController extends Controller
/** /**
* @param CategoryFormRequest $request * @param CategoryFormRequest $request
* @param CategoryRepositoryInterface $repository * @param SCRI $repository
* @param Category $category * @param Category $category
* *
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function update(CategoryFormRequest $request, CategoryRepositoryInterface $repository, Category $category) public function update(CategoryFormRequest $request, SCRI $repository, Category $category)
{ {
$categoryData = [ $categoryData = [
'name' => $request->input('name'), 'name' => $request->input('name'),

View File

@@ -5,7 +5,7 @@ namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Preferences; use Preferences;
@@ -35,45 +35,32 @@ class AccountController extends Controller
/** /**
* Shows the balances for all the user's accounts. * Shows the balances for a given set of dates and accounts.
* *
* @param AccountRepositoryInterface $repository * @param $reportType
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* *
* @param $year * @return \Illuminate\Http\JsonResponse
* @param $month
* @param bool $shared
*
* @return \Symfony\Component\HttpFoundation\Response
*/ */
public function all(AccountRepositoryInterface $repository, $year, $month, $shared = false) public function report($reportType, Carbon $start, Carbon $end, Collection $accounts)
{ {
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
// chart properties for cache: // chart properties for cache:
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty('all'); $cache->addProperty('all');
$cache->addProperty('accounts'); $cache->addProperty('accounts');
$cache->addProperty('default');
$cache->addProperty($reportType);
$cache->addProperty($accounts);
if ($cache->has()) { if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
/** @var Collection $accounts */
$accounts = $repository->getAccounts(['Default account', 'Asset account']);
if ($shared === false) {
/** @var Account $account */
foreach ($accounts as $index => $account) {
if ($account->getMeta('accountRole') == 'sharedAsset') {
$accounts->forget($index);
}
}
}
// make chart: // make chart:
$data = $this->generator->all($accounts, $start, $end); $data = $this->generator->frontpage($accounts, $start, $end);
$cache->store($data); $cache->store($data);
return Response::json($data); return Response::json($data);
@@ -82,11 +69,11 @@ class AccountController extends Controller
/** /**
* Shows the balances for all the user's expense accounts. * Shows the balances for all the user's expense accounts.
* *
* @param AccountRepositoryInterface $repository * @param ARI $repository
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
public function expenseAccounts(AccountRepositoryInterface $repository) public function expenseAccounts(ARI $repository)
{ {
$start = clone Session::get('start', Carbon::now()->startOfMonth()); $start = clone Session::get('start', Carbon::now()->startOfMonth());
$end = clone Session::get('end', Carbon::now()->endOfMonth()); $end = clone Session::get('end', Carbon::now()->endOfMonth());
@@ -112,11 +99,11 @@ class AccountController extends Controller
/** /**
* Shows the balances for all the user's frontpage accounts. * Shows the balances for all the user's frontpage accounts.
* *
* @param AccountRepositoryInterface $repository * @param ARI $repository
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
public function frontpage(AccountRepositoryInterface $repository) public function frontpage(ARI $repository)
{ {
$frontPage = Preferences::get('frontPageAccounts', []); $frontPage = Preferences::get('frontPageAccounts', []);
$start = clone Session::get('start', Carbon::now()->startOfMonth()); $start = clone Session::get('start', Carbon::now()->startOfMonth());

View File

@@ -33,7 +33,7 @@ class BillController extends Controller
} }
/** /**
* Shows all bills and whether or not theyve been paid this month (pie chart). * Shows all bills and whether or not they've been paid this month (pie chart).
* *
* @param BillRepositoryInterface $repository * @param BillRepositoryInterface $repository
* *
@@ -43,26 +43,22 @@ class BillController 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());
$cache = new CacheProperties(); // chart properties for cache: $paid = $repository->getBillsPaidInRange($start, $end); // will be a negative amount.
$cache->addProperty($start); $unpaid = $repository->getBillsUnpaidInRange($start, $end); // will be a positive amount.
$cache->addProperty($end); $creditCardDue = $repository->getCreditCardBill($start, $end);
$cache->addProperty('bills');
$cache->addProperty('frontpage'); if ($creditCardDue < 0) {
if ($cache->has()) { // expenses are negative (bill not yet paid),
return Response::json($cache->get()); // @codeCoverageIgnore $creditCardDue = bcmul($creditCardDue, '-1');
$unpaid = bcadd($unpaid, $creditCardDue);
} else {
// if more than zero, the bill has been paid: (transfer = positive).
// amount must be negative to be added to $paid:
$paid = bcadd($paid, $creditCardDue);
} }
$set = $repository->getBillsForChart($start, $end);
// optionally expand this set with credit card data
$set = $repository->getCreditCardInfoForChart($set, $start, $end);
$paid = $set->get('paid');
$unpaid = $set->get('unpaid');
// build chart: // build chart:
$data = $this->generator->frontpage($paid, $unpaid); $data = $this->generator->frontpage($paid, $unpaid);
$cache->store($data);
return Response::json($data); return Response::json($data);
} }

View File

@@ -6,6 +6,7 @@ use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\LimitRepetition;
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -35,6 +36,86 @@ class BudgetController extends Controller
$this->generator = app('FireflyIII\Generator\Chart\Budget\BudgetChartGenerator'); $this->generator = app('FireflyIII\Generator\Chart\Budget\BudgetChartGenerator');
} }
/**
* TODO expand with no budget chart.
*
* @param BudgetRepositoryInterface $repository
* @param $reportType
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* @param Collection $budgets
*
* @return \Illuminate\Http\JsonResponse
*/
public function multiYear(BudgetRepositoryInterface $repository, $reportType, Carbon $start, Carbon $end, Collection $accounts, Collection $budgets)
{
// chart properties for cache:
$cache = new CacheProperties();
$cache->addProperty($reportType);
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($accounts);
$cache->addProperty($budgets);
$cache->addProperty('multiYearBudget');
if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore
}
/*
* Get the budgeted amounts for each budgets in each year.
*/
$budgetedSet = $repository->getBudgetedPerYear($budgets, $start, $end);
$budgetedArray = [];
/** @var Budget $entry */
foreach ($budgetedSet as $entry) {
$budgetedArray[$entry->id][$entry->dateFormatted] = $entry->budgeted;
}
$set = $repository->getBudgetsAndExpensesPerYear($budgets, $accounts, $start, $end);
$entries = new Collection;
// go by budget, not by year.
/** @var Budget $budget */
foreach ($budgets as $budget) {
$entry = ['name' => '', 'spent' => [], 'budgeted' => []];
$id = $budget->id;
$currentStart = clone $start;
while ($currentStart < $end) {
// fix the date:
$currentEnd = clone $currentStart;
$currentEnd->endOfYear();
// save to array:
$year = $currentStart->year;
$entry['name'] = $budget->name;
$spent = 0;
$budgeted = 0;
if (isset($set[$id]['entries'][$year])) {
$spent = $set[$id]['entries'][$year] * -1;
}
if (isset($budgetedArray[$id][$year])) {
$budgeted = round($budgetedArray[$id][$year], 2);
}
$entry['spent'][$year] = $spent;
$entry['budgeted'][$year] = $budgeted;
// jump to next year.
$currentStart = clone $currentEnd;
$currentStart->addDay();
}
$entries->push($entry);
}
// generate chart with data:
$data = $this->generator->multiYear($entries);
$cache->store($data);
return Response::json($data);
}
/** /**
* @param BudgetRepositoryInterface $repository * @param BudgetRepositoryInterface $repository
* @param Budget $budget * @param Budget $budget
@@ -48,9 +129,6 @@ class BudgetController extends Controller
$first = $repository->getFirstBudgetLimitDate($budget); $first = $repository->getFirstBudgetLimitDate($budget);
$range = Preferences::get('viewRange', '1M')->data; $range = Preferences::get('viewRange', '1M')->data;
$last = Session::get('end', new Carbon); $last = Session::get('end', new Carbon);
$final = clone $last;
$final->addYears(2);
$last = Navigation::endOfX($last, $range, $final);
// chart properties for cache: // chart properties for cache:
$cache = new CacheProperties(); $cache = new CacheProperties();
@@ -58,18 +136,29 @@ class BudgetController extends Controller
$cache->addProperty($last); $cache->addProperty($last);
$cache->addProperty('budget'); $cache->addProperty('budget');
if ($cache->has()) { if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$final = clone $last;
$final->addYears(2);
$last = Navigation::endOfX($last, $range, $final);
$entries = new Collection; $entries = new Collection;
// get all expenses:
$set = $repository->getExpensesPerMonth($budget, $first, $last); // TODO
while ($first < $last) { while ($first < $last) {
$end = Navigation::addPeriod($first, $range, 0); $monthFormatted = $first->format('Y-m');
$end->subDay();
$chartDate = clone $end; $filtered = $set->filter(
$chartDate->startOfMonth(); function (Budget $obj) use ($monthFormatted) {
$spent = $repository->balanceInPeriod($budget, $first, $end) * -1; return $obj->dateFormatted == $monthFormatted;
$entries->push([$chartDate, $spent]); }
);
$spent = is_null($filtered->first()) ? '0' : $filtered->first()->monthlyAmount;
$entries->push([$first, round(($spent * -1), 2)]);
$first = Navigation::addPeriod($first, $range, 0); $first = Navigation::addPeriod($first, $range, 0);
} }
@@ -106,15 +195,24 @@ class BudgetController extends Controller
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$set = $repository->getExpensesPerDay($budget, $start, $end);
$entries = new Collection; $entries = new Collection;
$amount = $repetition->amount; $amount = $repetition->amount;
// get sum (har har)!
while ($start <= $end) { while ($start <= $end) {
$formatted = $start->format('Y-m-d');
$filtered = $set->filter(
function (Budget $obj) use ($formatted) {
return $obj->date == $formatted;
}
);
$sum = is_null($filtered->first()) ? '0' : $filtered->first()->dailyAmount;
/* /*
* Sum of expenses on this day: * Sum of expenses on this day:
*/ */
$sum = $repository->expensesOnDayCorrected($budget, $start); $amount = round(bcadd($amount, $sum), 2);
$amount = bcadd($amount, $sum);
$entries->push([clone $start, $amount]); $entries->push([clone $start, $amount]);
$start->addDay(); $start->addDay();
} }
@@ -131,14 +229,14 @@ class BudgetController extends Controller
* *
* @param BudgetRepositoryInterface $repository * @param BudgetRepositoryInterface $repository
* *
* @param ARI $accountRepository
*
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
public function frontpage(BudgetRepositoryInterface $repository) public function frontpage(BudgetRepositoryInterface $repository, ARI $accountRepository)
{ {
$budgets = $repository->getBudgets();
$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());
$allEntries = new Collection;
// chart properties for cache: // chart properties for cache:
$cache = new CacheProperties(); $cache = new CacheProperties();
@@ -150,98 +248,104 @@ class BudgetController extends Controller
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$budgets = $repository->getBudgetsAndLimitsInRange($start, $end);
$allEntries = new Collection;
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
bcscale(2); bcscale(2);
/** @var Budget $budget */ /** @var Budget $budget */
foreach ($budgets as $budget) { foreach ($budgets as $budget) {
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end); // we already have amount, startdate and enddate.
if ($repetitions->count() == 0) { // if this "is" a limit repetition (as opposed to a budget without one entirely)
$expenses = $repository->balanceInPeriod($budget, $start, $end, true) * -1; // depends on whether startdate and enddate are null.
$allEntries->push([$budget->name, 0, 0, $expenses, 0, 0]);
continue;
}
/** @var LimitRepetition $repetition */
foreach ($repetitions as $repetition) {
$expenses = $repository->balanceInPeriod($budget, $repetition->startdate, $repetition->enddate, true) * -1;
// $left can be less than zero.
// $overspent can be more than zero ( = overspending)
$left = max(bcsub($repetition->amount, $expenses), 0); // limited at zero.
$overspent = max(bcsub($expenses, $repetition->amount), 0); // limited at zero.
$name = $budget->name; $name = $budget->name;
if (is_null($budget->startdate) && is_null($budget->enddate)) {
// $spent is maxed to the repetition amount: $currentStart = clone $start;
$spent = $expenses > $repetition->amount ? $repetition->amount : $expenses; $currentEnd = clone $end;
$expenses = $repository->balanceInPeriod($budget, $currentStart, $currentEnd, $accounts);
$amount = 0;
$allEntries->push([$name, $left, $spent, $overspent, $repetition->amount, $expenses]); $left = 0;
} $spent = $expenses;
$overspent = 0;
} else {
$currentStart = clone $budget->startdate;
$currentEnd = clone $budget->enddate;
$expenses = $repository->balanceInPeriod($budget, $currentStart, $currentEnd, $accounts);
$amount = $budget->amount;
// smaller than 1 means spent MORE than budget allows.
$left = bccomp(bcadd($budget->amount, $expenses), '0') < 1 ? 0 : bcadd($budget->amount, $expenses);
$spent = bccomp(bcadd($budget->amount, $expenses), '0') < 1 ? ($amount * -1) : $expenses;
$overspent = bccomp(bcadd($budget->amount, $expenses), '0') < 1 ? bcadd($budget->amount, $expenses) : 0;
} }
$noBudgetExpenses = $repository->getWithoutBudgetSum($start, $end) * -1; $allEntries->push([$name, $left, $spent, $overspent, $amount, $expenses]);
}
$noBudgetExpenses = $repository->getWithoutBudgetSum($start, $end);
$allEntries->push([trans('firefly.noBudget'), 0, 0, $noBudgetExpenses, 0, 0]); $allEntries->push([trans('firefly.noBudget'), 0, 0, $noBudgetExpenses, 0, 0]);
$data = $this->generator->frontpage($allEntries); $data = $this->generator->frontpage($allEntries);
$cache->store($data); $cache->store($data);
return Response::json($data); return Response::json($data);
} }
/** /**
* Show a yearly overview for a budget. * TODO expand with no budget chart.
* *
* @param BudgetRepositoryInterface $repository * @param BudgetRepositoryInterface $repository
* @param $year * @param $reportType
* @param bool $shared * @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Illuminate\Http\JsonResponse
*/ */
public function year(BudgetRepositoryInterface $repository, $year, $shared = false) public function year(BudgetRepositoryInterface $repository, $reportType, Carbon $start, Carbon $end, Collection $accounts)
{ {
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
$shared = $shared == 'shared' ? true : false;
$allBudgets = $repository->getBudgets();
$budgets = new Collection;
// chart properties for cache: // chart properties for cache:
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty($reportType);
$cache->addProperty($accounts);
$cache->addProperty('budget'); $cache->addProperty('budget');
$cache->addProperty('year'); $cache->addProperty('year');
if ($cache->has()) { if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
// filter empty budgets: $budgetInformation = $repository->getBudgetsAndExpensesPerMonth($accounts, $start, $end);
$budgets = new Collection;
foreach ($allBudgets as $budget) {
$spent = $repository->balanceInPeriod($budget, $start, $end, $shared);
if ($spent != 0) {
$budgets->push($budget);
}
}
$entries = new Collection; $entries = new Collection;
/** @var array $row */
foreach ($budgetInformation as $row) {
$budgets->push($row['budget']);
}
while ($start < $end) { while ($start < $end) {
// month is the current end of the period: // month is the current end of the period:
$month = clone $start; $month = clone $start;
$month->endOfMonth(); $month->endOfMonth();
$row = [clone $start]; $row = [clone $start];
$dateFormatted = $start->format('Y-m');
// each budget, fill the row: // each budget, check if there is an entry for this month:
foreach ($budgets as $budget) { /** @var array $row */
$spent = $repository->balanceInPeriod($budget, $start, $month, $shared); foreach ($budgetInformation as $budgetRow) {
$row[] = $spent * -1; $spent = 0; // nothing spent.
if (isset($budgetRow['entries'][$dateFormatted])) {
$spent = $budgetRow['entries'][$dateFormatted] * -1; // to fit array
}
$row[] = $spent;
} }
$entries->push($row); $entries->push($row);
$start->endOfMonth()->addDay(); $start->endOfMonth()->addDay();
} }
$data = $this->generator->year($allBudgets, $entries); $data = $this->generator->year($budgets, $entries);
$cache->store($data); $cache->store($data);
return Response::json($data); return Response::json($data);

View File

@@ -6,13 +6,15 @@ namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface as CRI;
use FireflyIII\Repositories\Category\SingleCategoryRepositoryInterface as SCRI;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Navigation; use Navigation;
use Preferences; use Preferences;
use Response; use Response;
use Session; use Session;
use stdClass;
/** /**
* Class CategoryController * Class CategoryController
@@ -38,12 +40,12 @@ class CategoryController extends Controller
/** /**
* Show an overview for a category for all time, per month/week/year. * Show an overview for a category for all time, per month/week/year.
* *
* @param CategoryRepositoryInterface $repository * @param SCRI $repository
* @param Category $category * @param Category $category
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
public function all(CategoryRepositoryInterface $repository, Category $category) public function all(SCRI $repository, Category $category)
{ {
// oldest transaction in category: // oldest transaction in category:
$start = $repository->getFirstActivityDate($category); $start = $repository->getFirstActivityDate($category);
@@ -62,11 +64,17 @@ class CategoryController extends Controller
if ($cache->has()) { if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$spentArray = $repository->spentPerDay($category, $start, $end);
$earnedArray = $repository->earnedPerDay($category, $start, $end);
while ($start <= $end) { while ($start <= $end) {
$currentEnd = Navigation::endOfPeriod($start, $range); $currentEnd = Navigation::endOfPeriod($start, $range);
$spent = $repository->spentInPeriod($category, $start, $currentEnd);
$earned = $repository->earnedInPeriod($category, $start, $currentEnd); // get the sum from $spentArray and $earnedArray:
$spent = $this->getSumOfRange($start, $currentEnd, $spentArray);
$earned = $this->getSumOfRange($start, $currentEnd, $earnedArray);
$date = Navigation::periodShow($start, $range); $date = Navigation::periodShow($start, $range);
$entries->push([clone $start, $date, $spent, $earned]); $entries->push([clone $start, $date, $spent, $earned]);
$start = Navigation::addPeriod($start, $range, 0); $start = Navigation::addPeriod($start, $range, 0);
@@ -84,14 +92,15 @@ class CategoryController extends Controller
} }
/** /**
* Show this month's category overview. * Show this month's category overview.
* *
* @param CategoryRepositoryInterface $repository * @param CRI $repository
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
public function frontpage(CategoryRepositoryInterface $repository) public function frontpage(CRI $repository)
{ {
$start = Session::get('start', Carbon::now()->startOfMonth()); $start = Session::get('start', Carbon::now()->startOfMonth());
@@ -107,32 +116,130 @@ class CategoryController extends Controller
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$array = $repository->getCategoriesAndExpensesCorrected($start, $end); // get data for categories (and "no category"):
// sort by callback: $set = $repository->spentForAccountsPerMonth(new Collection, $start, $end);
uasort( $outside = $repository->sumSpentNoCategory(new Collection, $start, $end);
$array,
function ($left, $right) {
if ($left['sum'] == $right['sum']) {
return 0;
}
return ($left['sum'] < $right['sum']) ? -1 : 1; // this is a "fake" entry for the "no category" entry.
} $entry = new stdClass();
); $entry->name = trans('firefly.no_category');
$set = new Collection($array); $entry->spent = $outside;
$set->push($entry);
$set = $set->sortBy('spent');
$data = $this->generator->frontpage($set); $data = $this->generator->frontpage($set);
$cache->store($data);
return Response::json($data); return Response::json($data);
} }
/** /**
* @param CategoryRepositoryInterface $repository * @param $reportType
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* @param Collection $categories
*
* @return \Illuminate\Http\JsonResponse
*/
public function multiYear($reportType, Carbon $start, Carbon $end, Collection $accounts, Collection $categories)
{
/** @var CRI $repository */
$repository = app('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
// chart properties for cache:
$cache = new CacheProperties();
$cache->addProperty($reportType);
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($accounts);
$cache->addProperty($categories);
$cache->addProperty('multiYearCategory');
if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore
}
/**
* category
* year:
* spent: x
* earned: x
* year
* spent: x
* earned: x
*/
$entries = new Collection;
// go by category, not by year.
// given a set of categories and accounts, it should not be difficult to get
// the exact array of data we need.
// then get the data for "no category".
$set = $repository->listMultiYear($categories, $accounts, $start, $end);
/** @var Category $category */
foreach ($categories as $category) {
$entry = ['name' => '', 'spent' => [], 'earned' => []];
$currentStart = clone $start;
while ($currentStart < $end) {
// fix the date:
$year = $currentStart->year;
$currentEnd = clone $currentStart;
$currentEnd->endOfYear();
// get data:
if (is_null($category->id)) {
$name = trans('firefly.noCategory');
$spent = $repository->sumSpentNoCategory($accounts, $currentStart, $currentEnd);
$earned = $repository->sumEarnedNoCategory($accounts, $currentStart, $currentEnd);
} else {
// get from set:
$entrySpent = $set->filter(
function (Category $cat) use ($year, $category) {
return ($cat->type == 'Withdrawal' && $cat->dateFormatted == $year && $cat->id == $category->id);
}
)->first();
$entryEarned = $set->filter(
function (Category $cat) use ($year, $category) {
return ($cat->type == 'Deposit' && $cat->dateFormatted == $year && $cat->id == $category->id);
}
)->first();
$name = $category->name;
$spent = !is_null($entrySpent) ? $entrySpent->sum : 0;
$earned = !is_null($entryEarned) ? $entryEarned->sum : 0;
}
// save to array:
$entry['name'] = $name;
$entry['spent'][$year] = ($spent * -1);
$entry['earned'][$year] = $earned;
// jump to next year.
$currentStart = clone $currentEnd;
$currentStart->addDay();
}
$entries->push($entry);
}
// generate chart with data:
$data = $this->generator->multiYear($entries);
$cache->store($data);
return Response::json($data);
}
/**
* @param SCRI $repository
* @param Category $category * @param Category $category
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
public function currentPeriod(CategoryRepositoryInterface $repository, Category $category) public function currentPeriod(SCRI $repository, Category $category)
{ {
$start = clone Session::get('start', Carbon::now()->startOfMonth()); $start = clone Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth()); $end = Session::get('end', Carbon::now()->endOfMonth());
@@ -143,16 +250,21 @@ class CategoryController extends Controller
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty($category->id); $cache->addProperty($category->id);
$cache->addProperty('category'); $cache->addProperty('category');
$cache->addProperty('currentPeriod'); $cache->addProperty('current-period');
if ($cache->has()) { if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$entries = new Collection; $entries = new Collection;
// get amount earned in period, grouped by day.
// get amount spent in period, grouped by day.
$spentArray = $repository->spentPerDay($category, $start, $end);
$earnedArray = $repository->earnedPerDay($category, $start, $end);
while ($start <= $end) { while ($start <= $end) {
$spent = $repository->spentOnDaySumCorrected($category, $start); $str = $start->format('Y-m-d');
$earned = $repository->earnedOnDaySumCorrected($category, $start); $spent = isset($spentArray[$str]) ? $spentArray[$str] : 0;
$earned = isset($earnedArray[$str]) ? $earnedArray[$str] : 0;
$date = Navigation::periodShow($start, '1D'); $date = Navigation::periodShow($start, '1D');
$entries->push([clone $start, $date, $spent, $earned]); $entries->push([clone $start, $date, $spent, $earned]);
$start->addDay(); $start->addDay();
@@ -162,17 +274,17 @@ class CategoryController extends Controller
$cache->store($data); $cache->store($data);
return Response::json($data); return Response::json($data);
} }
/** /**
* @param CategoryRepositoryInterface $repository * @param SCRI $repository
* @param Category $category * @param Category $category
* *
* @param $date
*
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
public function specificPeriod(CategoryRepositoryInterface $repository, Category $category, $date) public function specificPeriod(SCRI $repository, Category $category, $date)
{ {
$carbon = new Carbon($date); $carbon = new Carbon($date);
$range = Preferences::get('viewRange', '1M')->data; $range = Preferences::get('viewRange', '1M')->data;
@@ -192,12 +304,17 @@ class CategoryController extends Controller
} }
$entries = new Collection; $entries = new Collection;
// get amount earned in period, grouped by day.
$spentArray = $repository->spentPerDay($category, $start, $end);
$earnedArray = $repository->earnedPerDay($category, $start, $end);
// get amount spent in period, grouped by day.
while ($start <= $end) { while ($start <= $end) {
$spent = $repository->spentOnDaySumCorrected($category, $start); $str = $start->format('Y-m-d');
$earned = $repository->earnedOnDaySumCorrected($category, $start); $spent = isset($spentArray[$str]) ? $spentArray[$str] : 0;
$theDate = Navigation::periodShow($start, '1D'); $earned = isset($earnedArray[$str]) ? $earnedArray[$str] : 0;
$entries->push([clone $start, $theDate, $spent, $earned]); $date = Navigation::periodShow($start, '1D');
$entries->push([clone $start, $date, $spent, $earned]);
$start->addDay(); $start->addDay();
} }
@@ -210,120 +327,137 @@ class CategoryController extends Controller
} }
/** /**
* This chart will only show expenses. * Returns a chart of what has been earned in this period in each category
* grouped by month.
* *
* @param CategoryRepositoryInterface $repository * @param CRI $repository
* @param $year * @param $reportType
* @param bool $shared * @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Illuminate\Http\JsonResponse
*/ */
public function spentInYear(CategoryRepositoryInterface $repository, $year, $shared = false) public function earnedInPeriod(CRI $repository, $reportType, Carbon $start, Carbon $end, Collection $accounts)
{ {
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
$cache = new CacheProperties; // chart properties for cache: $cache = new CacheProperties; // chart properties for cache:
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty($reportType);
$cache->addProperty($accounts);
$cache->addProperty('category'); $cache->addProperty('category');
$cache->addProperty('spent-in-year'); $cache->addProperty('earned-in-period');
if ($cache->has()) { if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$shared = $shared == 'shared' ? true : false; $set = $repository->earnedForAccountsPerMonth($accounts, $start, $end);
$allCategories = $repository->getCategories(); $categories = $set->unique('id')->sortBy(
$entries = new Collection; function (Category $category) {
$categories = $allCategories->filter( return $category->name;
function (Category $category) use ($repository, $start, $end, $shared) {
$spent = $repository->balanceInPeriod($category, $start, $end, $shared);
if ($spent < 0) {
return $category;
}
return null;
} }
); );
$entries = new Collection;
while ($start < $end) { while ($start < $end) { // filter the set:
$month = clone $start; // month is the current end of the period $row = [clone $start];
$month->endOfMonth(); // get possibly relevant entries from the big $set
$row = [clone $start]; // make a row: $currentSet = $set->filter(
function (Category $category) use ($start) {
foreach ($categories as $category) { // each budget, fill the row return $category->dateFormatted == $start->format("Y-m");
$spent = $repository->balanceInPeriod($category, $start, $month, $shared); }
if ($spent < 0) { );
$row[] = $spent * -1; // check for each category if its in the current set.
/** @var Category $category */
foreach ($categories as $category) {
// if its in there, use the value.
$entry = $currentSet->filter(
function (Category $cat) use ($category) {
return ($cat->id == $category->id);
}
)->first();
if (!is_null($entry)) {
$row[] = round($entry->earned, 2);
} else { } else {
$row[] = 0; $row[] = 0;
} }
} }
$entries->push($row); $entries->push($row);
$start->addMonth(); $start->addMonth();
} }
$data = $this->generator->spentInYear($categories, $entries); $data = $this->generator->earnedInPeriod($categories, $entries);
$cache->store($data); $cache->store($data);
return Response::json($data); return $data;
} }
/** /**
* This chart will only show income. * Returns a chart of what has been spent in this period in each category
* grouped by month.
* *
* @param CategoryRepositoryInterface $repository * @param CRI $repository
* @param $year * @param $reportType
* @param bool $shared * @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Illuminate\Http\JsonResponse
*/ */
public function earnedInYear(CategoryRepositoryInterface $repository, $year, $shared = false) public function spentInPeriod(CRI $repository, $reportType, Carbon $start, Carbon $end, Collection $accounts)
{ {
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
$cache = new CacheProperties; // chart properties for cache: $cache = new CacheProperties; // chart properties for cache:
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty($reportType);
$cache->addProperty($accounts);
$cache->addProperty('category'); $cache->addProperty('category');
$cache->addProperty('earned-in-year'); $cache->addProperty('spent-in-period');
if ($cache->has()) { if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$shared = $shared == 'shared' ? true : false; $set = $repository->spentForAccountsPerMonth($accounts, $start, $end);
$allCategories = $repository->getCategories(); $categories = $set->unique('id')->sortBy(
$allEntries = new Collection; function (Category $category) {
$categories = $allCategories->filter( return $category->name;
function (Category $category) use ($repository, $start, $end, $shared) {
$spent = $repository->balanceInPeriod($category, $start, $end, $shared);
if ($spent > 0) {
return $category;
}
return null;
} }
); );
$entries = new Collection;
while ($start < $end) { while ($start < $end) { // filter the set:
$month = clone $start; // month is the current end of the period $row = [clone $start];
$month->endOfMonth(); // get possibly relevant entries from the big $set
$row = [clone $start]; // make a row: $currentSet = $set->filter(
function (Category $category) use ($start) {
foreach ($categories as $category) { // each budget, fill the row return $category->dateFormatted == $start->format("Y-m");
$spent = $repository->balanceInPeriod($category, $start, $month, $shared); }
if ($spent > 0) { );
$row[] = $spent; // check for each category if its in the current set.
/** @var Category $category */
foreach ($categories as $category) {
// if its in there, use the value.
$entry = $currentSet->filter(
function (Category $cat) use ($category) {
return ($cat->id == $category->id);
}
)->first();
if (!is_null($entry)) {
$row[] = round(($entry->spent * -1), 2);
} else { } else {
$row[] = 0; $row[] = 0;
} }
} }
$allEntries->push($row);
$entries->push($row);
$start->addMonth(); $start->addMonth();
} }
$data = $this->generator->earnedInYear($categories, $allEntries); $data = $this->generator->spentInPeriod($categories, $entries);
$cache->store($data); $cache->store($data);
return Response::json($data); return $data;
} }
} }

View File

@@ -9,7 +9,6 @@ use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Response; use Response;
use Log;
/** /**
* Class ReportController * Class ReportController
@@ -37,40 +36,39 @@ class ReportController extends Controller
* Summarizes all income and expenses, per month, for a given year. * Summarizes all income and expenses, per month, for a given year.
* *
* @param ReportQueryInterface $query * @param ReportQueryInterface $query
* @param $year * @param $reportType
* @param bool $shared * @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Illuminate\Http\JsonResponse
*/ */
public function yearInOut(ReportQueryInterface $query, $year, $shared = false) public function yearInOut(ReportQueryInterface $query, $reportType, Carbon $start, Carbon $end, Collection $accounts)
{ {
// get start and end of year
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
$shared = $shared == 'shared' ? true : false;
// chart properties for cache: // chart properties for cache:
$cache = new CacheProperties; $cache = new CacheProperties;
$cache->addProperty('yearInOut'); $cache->addProperty('yearInOut');
$cache->addProperty($year); $cache->addProperty($start);
$cache->addProperty($shared); $cache->addProperty($reportType);
$cache->addProperty($accounts);
$cache->addProperty($end);
if ($cache->has()) { if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$entries = new Collection; // spent per month, and earned per month. For a specific set of accounts
while ($start < $end) { // grouped by month
$month = clone $start; $spentArray = $query->spentPerMonth($accounts, $start, $end);
$month->endOfMonth(); $earnedArray = $query->earnedPerMonth($accounts, $start, $end);
// total income and total expenses:
$incomeSum = $query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
$expenseSum = $query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
$entries->push([clone $start, $incomeSum, $expenseSum]); if ($start->diffInMonths($end) > 12) {
$start->addMonth(); // data = method X
$data = $this->multiYearInOut($earnedArray, $spentArray, $start, $end);
} else {
// data = method Y
$data = $this->singleYearInOut($earnedArray, $spentArray, $start, $end);
} }
$data = $this->generator->yearInOut($entries);
$cache->store($data); $cache->store($data);
return Response::json($data); return Response::json($data);
@@ -81,56 +79,170 @@ class ReportController extends Controller
* Summarizes all income and expenses for a given year. Gives a total and an average. * Summarizes all income and expenses for a given year. Gives a total and an average.
* *
* @param ReportQueryInterface $query * @param ReportQueryInterface $query
* @param $year * @param $reportType
* @param bool $shared * @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Illuminate\Http\JsonResponse
*/ */
public function yearInOutSummarized(ReportQueryInterface $query, $year, $shared = false) public function yearInOutSummarized(ReportQueryInterface $query, $reportType, Carbon $start, Carbon $end, Collection $accounts)
{ {
// chart properties for cache: // chart properties for cache:
$cache = new CacheProperties; $cache = new CacheProperties;
$cache->addProperty('yearInOutSummarized'); $cache->addProperty('yearInOutSummarized');
$cache->addProperty($year); $cache->addProperty($start);
$cache->addProperty($shared); $cache->addProperty($end);
$cache->addProperty($reportType);
$cache->addProperty($accounts);
if ($cache->has()) { if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
// spent per month, and earned per month. For a specific set of accounts
// grouped by month
$spentArray = $query->spentPerMonth($accounts, $start, $end);
$earnedArray = $query->earnedPerMonth($accounts, $start, $end);
if ($start->diffInMonths($end) > 12) {
// per year
$data = $this->multiYearInOutSummarized($earnedArray, $spentArray, $start, $end);
} else {
// per month!
$data = $this->singleYearInOutSummarized($earnedArray, $spentArray, $start, $end);
}
$cache->store($data);
$start = new Carbon($year . '-01-01'); return Response::json($data);
$end = new Carbon($year . '-12-31'); }
$shared = $shared == 'shared' ? true : false;
/**
* @param array $earned
* @param array $spent
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
protected function singleYearInOutSummarized(array $earned, array $spent, Carbon $start, Carbon $end)
{
$income = '0'; $income = '0';
$expense = '0'; $expense = '0';
$count = 0; $count = 0;
bcscale(2);
while ($start < $end) { while ($start < $end) {
$month = clone $start; $date = $start->format('Y-m');
$month->endOfMonth(); $currentIncome = isset($earned[$date]) ? $earned[$date] : 0;
// total income and total expenses: $currentExpense = isset($spent[$date]) ? ($spent[$date] * -1) : 0;
$currentIncome = $query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
$currentExpense = $query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
Log::debug('Date ['.$month->format('M Y').']: income = ['.$income.' + '.$currentIncome.'], out = ['.$expense.' + '.$currentExpense.']');
$income = bcadd($income, $currentIncome); $income = bcadd($income, $currentIncome);
$expense = bcadd($expense, $currentExpense); $expense = bcadd($expense, $currentExpense);
$count++; $count++;
$start->addMonth(); $start->addMonth();
} }
$data = $this->generator->yearInOutSummarized($income, $expense, $count); $data = $this->generator->yearInOutSummarized($income, $expense, $count);
$cache->store($data);
return Response::json($data); return $data;
}
/**
* @param array $earned
* @param array $spent
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
protected function multiYearInOutSummarized(array $earned, array $spent, Carbon $start, Carbon $end)
{
$income = '0';
$expense = '0';
$count = 0;
while ($start < $end) {
$currentIncome = $this->pluckFromArray($start->year, $earned);
$currentExpense = $this->pluckFromArray($start->year, $spent) * -1;
$income = bcadd($income, $currentIncome);
$expense = bcadd($expense, $currentExpense);
$count++;
$start->addYear();
}
$data = $this->generator->multiYearInOutSummarized($income, $expense, $count);
return $data;
}
/**
* @param array $earned
* @param array $spent
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
protected function multiYearInOut(array $earned, array $spent, Carbon $start, Carbon $end)
{
$entries = new Collection;
while ($start < $end) {
$incomeSum = $this->pluckFromArray($start->year, $earned);
$expenseSum = $this->pluckFromArray($start->year, $spent) * -1;
$entries->push([clone $start, $incomeSum, $expenseSum]);
$start->addYear();
}
$data = $this->generator->multiYearInOut($entries);
return $data;
}
/**
* @param array $earned
* @param array $spent
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
protected function singleYearInOut(array $earned, array $spent, Carbon $start, Carbon $end)
{
// per month? simply use each month.
$entries = new Collection;
while ($start < $end) {
// total income and total expenses:
$date = $start->format('Y-m');
$incomeSum = isset($earned[$date]) ? $earned[$date] : 0;
$expenseSum = isset($spent[$date]) ? ($spent[$date] * -1) : 0;
$entries->push([clone $start, $incomeSum, $expenseSum]);
$start->addMonth();
}
$data = $this->generator->yearInOut($entries);
return $data;
}
/**
* @param int $year
* @param array $set
*
* @return string
*/
protected function pluckFromArray($year, array $set)
{
bcscale(2);
$sum = '0';
foreach ($set as $date => $amount) {
if (substr($date, 0, 4) == $year) {
$sum = bcadd($sum, $amount);
}
}
return $sum;
} }
} }

View File

@@ -1,7 +1,7 @@
<?php namespace FireflyIII\Http\Controllers; <?php namespace FireflyIII\Http\Controllers;
use Auth; use Auth;
use Config; use Carbon\Carbon;
use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController; use Illuminate\Routing\Controller as BaseController;
@@ -34,14 +34,43 @@ abstract class Controller extends BaseController
View::share('hideTags', false); View::share('hideTags', false);
if (Auth::check()) { if (Auth::check()) {
$pref = Preferences::get('language', 'en'); $pref = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US'));
$lang = $pref->data; $lang = $pref->data;
$this->monthFormat = Config::get('firefly.month.' . $lang); $this->monthFormat = trans('config.month');
$this->monthAndDayFormat = Config::get('firefly.monthAndDay.' . $lang); $this->monthAndDayFormat = trans('config.month_and_day');
View::share('monthFormat', $this->monthFormat); View::share('monthFormat', $this->monthFormat);
View::share('monthAndDayFormat', $this->monthAndDayFormat); View::share('monthAndDayFormat', $this->monthAndDayFormat);
View::share('language', $lang); View::share('language', $lang);
View::share('localeconv', localeconv());
} }
} }
/**
* Take the array as returned by SingleCategoryRepositoryInterface::spentPerDay and SingleCategoryRepositoryInterface::earnedByDay
* and sum up everything in the array in the given range.
*
* @param Carbon $start
* @param Carbon $end
* @param array $array
*
* @return string
*/
protected function getSumOfRange(Carbon $start, Carbon $end, array $array)
{
bcscale(2);
$sum = '0';
$currentStart = clone $start; // to not mess with the original one
$currentEnd = clone $end; // to not mess with the original one
while ($currentStart <= $currentEnd) {
$date = $currentStart->format('Y-m-d');
if (isset($array[$date])) {
$sum = bcadd($sum, $array[$date]);
}
$currentStart->addDay();
}
return $sum;
}
} }

View File

@@ -1,74 +0,0 @@
<?php
namespace FireflyIII\Http\Controllers;
use FireflyIII\User;
/**
* Class WebhookController
*
* @package FireflyIII\Http\Controllers
*/
class CronController extends Controller
{
/**
* Firefly doesn't have anything that should be in the a cron job, except maybe this one, and it's fairly exceptional.
*
* If you use SendGrid like I do, you can detect bounces and thereby check if users gave an invalid address. If they did,
* it's easy to block them and change their password. Optionally, you could notify yourself about it and send them a message.
*
* But thats something not supported right now.
*/
public function sendgrid()
{
if (strlen(env('SENDGRID_USERNAME')) > 0 && strlen(env('SENDGRID_PASSWORD')) > 0) {
$set = [
'blocks' => 'https://api.sendgrid.com/api/blocks.get.json',
'bounces' => 'https://api.sendgrid.com/api/bounces.get.json',
'invalids' => 'https://api.sendgrid.com/api/invalidemails.get.json',
];
echo '<pre>';
foreach ($set as $name => $URL) {
$parameters = [
'api_user' => env('SENDGRID_USERNAME'),
'api_key' => env('SENDGRID_PASSWORD'),
'date' => 1,
'days' => 7
];
$fullURL = $URL . '?' . http_build_query($parameters);
$data = json_decode(file_get_contents($fullURL));
/*
* Loop the result, if any.
*/
if (is_array($data)) {
echo 'Found ' . count($data) . ' entries in the SendGrid ' . $name . ' list.' . "\n";
foreach ($data as $entry) {
$address = $entry->email;
$user = User::where('email', $address)->where('blocked', 0)->first();
if (!is_null($user)) {
echo 'Found a user: ' . $address . ', who is now blocked.' . "\n";
$user->blocked = 1;
$user->blocked_code = 'bounced';
$user->password = 'bounced';
$user->save();
} else {
echo 'Found no user: ' . $address . ', did nothing.' . "\n";
}
}
}
}
echo 'Done!' . "\n";
} else {
echo 'Please fill in SendGrid details.';
}
}
}

View File

@@ -8,7 +8,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Csv\Data; use FireflyIII\Helpers\Csv\Data;
use FireflyIII\Helpers\Csv\Importer; use FireflyIII\Helpers\Csv\Importer;
use FireflyIII\Helpers\Csv\WizardInterface; use FireflyIII\Helpers\Csv\WizardInterface;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Input; use Input;
use Log; use Log;
@@ -146,9 +146,11 @@ class CsvController extends Controller
* *
* STEP ONE * STEP ONE
* *
* @param ARI $repository
*
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function index(AccountRepositoryInterface $repository) public function index(ARI $repository)
{ {
$subTitle = trans('firefly.csv_import'); $subTitle = trans('firefly.csv_import');

View File

@@ -147,7 +147,7 @@ class CurrencyController extends Controller
public function index(CurrencyRepositoryInterface $repository) public function index(CurrencyRepositoryInterface $repository)
{ {
$currencies = $repository->get(); $currencies = $repository->get();
$defaultCurrency = $repository->getCurrencyByPreference(Preferences::get('currencyPreference', 'EUR')); $defaultCurrency = $repository->getCurrencyByPreference(Preferences::get('currencyPreference', env('DEFAULT_CURRENCY', 'EUR')));
if (!Auth::user()->hasRole('owner')) { if (!Auth::user()->hasRole('owner')) {

View File

@@ -1,15 +1,12 @@
<?php namespace FireflyIII\Http\Controllers; <?php namespace FireflyIII\Http\Controllers;
use Artisan; use Artisan;
use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Config; use Config;
use FireflyIII\Models\Tag; use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use Input; use Input;
use Log;
use Preferences; use Preferences;
use Route;
use Session; use Session;
use Steam; use Steam;
@@ -65,11 +62,11 @@ class HomeController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* *
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/ */
public function index(AccountRepositoryInterface $repository) public function index(ARI $repository)
{ {
$types = Config::get('firefly.accountTypesByIdentifier.asset'); $types = Config::get('firefly.accountTypesByIdentifier.asset');
$count = $repository->countAccounts($types); $count = $repository->countAccounts($types);
@@ -120,33 +117,4 @@ class HomeController extends Controller
); );
} }
/**
* @codeCoverageIgnore
* @return \Illuminate\Http\RedirectResponse|string
*/
public function routes()
{
if (!Auth::user()->hasRole('owner')) {
Session::flash('warning', 'This page is broken.');
return redirect(route('index'));
}
Log::debug('Make log.');
// get all routes:
$routeCollection = Route::getRoutes();
/** @var \Illuminate\Routing\Route $value */
foreach ($routeCollection as $value) {
$name = $value->getName();
$methods = $value->getMethods();
$isPost = in_array('POST', $methods);
$index = str_replace('.', '-', $name);
if (strlen($name) > 0 && !$isPost) {
echo "'" . $index . "' => '" . $name . "',<br />";
}
}
return '&nbsp;';
}
} }

View File

@@ -3,19 +3,15 @@
use Amount; use Amount;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Helpers\Report\ReportQueryInterface; use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Models\Account; use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Models\Bill;
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 as CRI;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
use Preferences; use Preferences;
use Response; use Response;
use Session; use Session;
use Steam;
/** /**
* Class JsonController * Class JsonController
@@ -66,109 +62,50 @@ class JsonController extends Controller
/** /**
* @param BillRepositoryInterface $repository * @param BillRepositoryInterface $repository
* *
* @param AccountRepositoryInterface $accountRepository
*
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
public function boxBillsPaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository) public function boxBillsPaid(BillRepositoryInterface $repository)
{ {
$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 = 0;
bcscale(2); bcscale(2);
// works for json too! /*
$cache = new CacheProperties; * Since both this method and the chart use the exact same data, we can suffice
$cache->addProperty($start); * with calling the one method in the bill repository that will get this amount.
$cache->addProperty($end); */
$cache->addProperty('box-bills-paid'); $amount = $repository->getBillsPaidInRange($start, $end); // will be a negative amount.
if ($cache->has()) { $creditCardDue = $repository->getCreditCardBill($start, $end);
return Response::json($cache->get()); // @codeCoverageIgnore if ($creditCardDue >= 0) {
$amount = bcadd($amount, $creditCardDue);
} }
$bills = $repository->getActiveBills(); // these two functions are the same as the chart $amount = $amount * -1;
/** @var Bill $bill */
foreach ($bills as $bill) {
$amount = bcadd($amount, $repository->billPaymentsInRange($bill, $start, $end));
}
unset($bill, $bills);
$amount = $amount * -1; // make the amount positive again.
$creditCards = $accountRepository->getCreditCards(); // Find credit card accounts and possibly unpaid credit card bills.
/** @var Account $creditCard */
foreach ($creditCards as $creditCard) {
$balance = Steam::balance($creditCard, $end, true); // if the balance is not zero, the monthly payment is still underway.
if ($balance == 0) {
// find a transfer TO the credit card which should account for
// anything paid. If not, the CC is not yet used.
$amount = bcadd($amount, $accountRepository->getTransfersInRange($creditCard, $start, $end)->sum('amount'));
}
}
$data = ['box' => 'bills-paid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]; $data = ['box' => 'bills-paid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$cache->store($data);
return Response::json($data); return Response::json($data);
} }
/** /**
* @param BillRepositoryInterface $repository * @param BillRepositoryInterface $repository
* @param AccountRepositoryInterface $accountRepository
* *
* @return \Symfony\Component\HttpFoundation\Response * @return \Illuminate\Http\JsonResponse
*/ */
public function boxBillsUnpaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository) public function boxBillsUnpaid(BillRepositoryInterface $repository)
{ {
$amount = 0; bcscale(2);
$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());
bcscale(2); $amount = $repository->getBillsUnpaidInRange($start, $end); // will be a positive amount.
$creditCardDue = $repository->getCreditCardBill($start, $end);
// works for json too! if ($creditCardDue < 0) {
$cache = new CacheProperties; // expenses are negative (bill not yet paid),
$cache->addProperty($start); $creditCardDue = bcmul($creditCardDue, '-1');
$cache->addProperty($end); $amount = bcadd($amount, $creditCardDue);
$cache->addProperty('box-bills-unpaid');
if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore
}
$bills = $repository->getActiveBills();
$unpaid = new Collection; // bills
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
$journals = $repository->getJournalsInRange($bill, $range['start'], $range['end']);
if ($journals->count() == 0) {
$unpaid->push([$bill, $range['start']]);
}
}
}
unset($bill, $bills, $range, $ranges);
$creditCards = $accountRepository->getCreditCards();
foreach ($creditCards as $creditCard) {
$balance = Steam::balance($creditCard, $end, true);
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
if ($balance < 0) {
// unpaid! create a fake bill that matches the amount.
$description = $creditCard->name;
$fakeAmount = $balance * -1;
$fakeBill = $repository->createFakeBill($description, $date, $fakeAmount);
$unpaid->push([$fakeBill, $date]);
}
}
/** @var Bill $entry */
foreach ($unpaid as $entry) {
$current = bcdiv(bcadd($entry[0]->amount_max, $entry[0]->amount_min), 2);
$amount = bcadd($amount, $current);
} }
$data = ['box' => 'bills-unpaid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]; $data = ['box' => 'bills-unpaid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$cache->store($data);
return Response::json($data); return Response::json($data);
} }
@@ -176,9 +113,11 @@ class JsonController extends Controller
/** /**
* @param ReportQueryInterface $reportQuery * @param ReportQueryInterface $reportQuery
* *
* @param ARI $accountRepository
*
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
public function boxIn(ReportQueryInterface $reportQuery) public function boxIn(ReportQueryInterface $reportQuery, ARI $accountRepository)
{ {
$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());
@@ -191,8 +130,8 @@ class JsonController extends Controller
if ($cache->has()) { if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
$amount = $reportQuery->incomeInPeriodCorrected($start, $end, true)->sum('amount'); $amount = $reportQuery->income($accounts, $start, $end)->sum('journalAmount');
$data = ['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]; $data = ['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$cache->store($data); $cache->store($data);
@@ -203,13 +142,16 @@ class JsonController extends Controller
/** /**
* @param ReportQueryInterface $reportQuery * @param ReportQueryInterface $reportQuery
* *
* @param ARI $accountRepository
*
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
public function boxOut(ReportQueryInterface $reportQuery) public function boxOut(ReportQueryInterface $reportQuery, ARI $accountRepository)
{ {
$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());
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
// works for json too! // works for json too!
$cache = new CacheProperties; $cache = new CacheProperties;
@@ -220,8 +162,7 @@ class JsonController extends Controller
return Response::json($cache->get()); // @codeCoverageIgnore return Response::json($cache->get()); // @codeCoverageIgnore
} }
$amount = $reportQuery->expenseInPeriodCorrected($start, $end, true)->sum('amount'); $amount = $reportQuery->expense($accounts, $start, $end)->sum('journalAmount');
$amount = $amount * -1;
$data = ['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]; $data = ['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$cache->store($data); $cache->store($data);
@@ -232,18 +173,17 @@ class JsonController extends Controller
/** /**
* Returns a list of categories. * Returns a list of categories.
* *
* @param CategoryRepositoryInterface $repository * @param CRI $repository
* *
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function categories(CategoryRepositoryInterface $repository) public function categories(CRI $repository)
{ {
$list = $repository->getCategories(); $list = $repository->listCategories();
$return = []; $return = [];
foreach ($list as $entry) { foreach ($list as $entry) {
$return[] = $entry->name; $return[] = $entry->name;
} }
sort($return);
return Response::json($return); return Response::json($return);
} }
@@ -251,11 +191,11 @@ class JsonController extends Controller
/** /**
* Returns a JSON list of all beneficiaries. * Returns a JSON list of all beneficiaries.
* *
* @param AccountRepositoryInterface $accountRepository * @param ARI $accountRepository
* *
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function expenseAccounts(AccountRepositoryInterface $accountRepository) public function expenseAccounts(ARI $accountRepository)
{ {
$list = $accountRepository->getAccounts(['Expense account', 'Beneficiary account']); $list = $accountRepository->getAccounts(['Expense account', 'Beneficiary account']);
$return = []; $return = [];
@@ -268,11 +208,11 @@ class JsonController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $accountRepository * @param ARI $accountRepository
* *
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function revenueAccounts(AccountRepositoryInterface $accountRepository) public function revenueAccounts(ARI $accountRepository)
{ {
$list = $accountRepository->getAccounts(['Revenue account']); $list = $accountRepository->getAccounts(['Revenue account']);
$return = []; $return = [];

View File

@@ -5,7 +5,7 @@ use Carbon\Carbon;
use Config; use Config;
use FireflyIII\Http\Requests\NewUserFormRequest; use FireflyIII\Http\Requests\NewUserFormRequest;
use FireflyIII\Models\AccountMeta; use FireflyIII\Models\AccountMeta;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use Preferences; use Preferences;
use Session; use Session;
use View; use View;
@@ -20,11 +20,11 @@ class NewUserController extends Controller
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* *
* @@return \Illuminate\Http\RedirectResponse|\Illuminate\View\View * @@return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/ */
public function index(AccountRepositoryInterface $repository) public function index(ARI $repository)
{ {
View::share('title', 'Welcome to Firefly!'); View::share('title', 'Welcome to Firefly!');
View::share('mainTitleIcon', 'fa-fire'); View::share('mainTitleIcon', 'fa-fire');
@@ -43,13 +43,12 @@ class NewUserController extends Controller
/** /**
* @param NewUserFormRequest $request * @param NewUserFormRequest $request
* @param AccountRepositoryInterface $repository * @param ARI $repository
* *
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function submit(NewUserFormRequest $request, AccountRepositoryInterface $repository) public function submit(NewUserFormRequest $request, ARI $repository)
{ {
// create normal asset account: // create normal asset account:
$assetAccount = [ $assetAccount = [
'name' => $request->get('bank_name'), 'name' => $request->get('bank_name'),
@@ -61,7 +60,7 @@ class NewUserController extends Controller
'accountRole' => 'defaultAsset', 'accountRole' => 'defaultAsset',
'openingBalance' => round($request->input('bank_balance'), 2), 'openingBalance' => round($request->input('bank_balance'), 2),
'openingBalanceDate' => new Carbon, 'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => intval($request->input('balance_currency_id')), 'openingBalanceCurrency' => intval($request->input('amount_currency_id_bank_balance')),
]; ];
$repository->store($assetAccount); $repository->store($assetAccount);
@@ -78,7 +77,7 @@ class NewUserController extends Controller
'accountRole' => 'savingAsset', 'accountRole' => 'savingAsset',
'openingBalance' => round($request->input('savings_balance'), 2), 'openingBalance' => round($request->input('savings_balance'), 2),
'openingBalanceDate' => new Carbon, 'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => intval($request->input('balance_currency_id')), 'openingBalanceCurrency' => intval($request->input('amount_currency_id_savings_balance')),
]; ];
$repository->store($savingsAccount); $repository->store($savingsAccount);
} }
@@ -96,7 +95,7 @@ class NewUserController extends Controller
'accountRole' => 'ccAsset', 'accountRole' => 'ccAsset',
'openingBalance' => null, 'openingBalance' => null,
'openingBalanceDate' => null, 'openingBalanceDate' => null,
'openingBalanceCurrency' => intval($request->input('balance_currency_id')), 'openingBalanceCurrency' => intval($request->input('amount_currency_id_credit_card_limit')),
]; ];
$creditCard = $repository->store($creditAccount); $creditCard = $repository->store($creditAccount);

View File

@@ -6,7 +6,7 @@ use Config;
use ExpandedForm; use ExpandedForm;
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 as ARI;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Input; use Input;
@@ -18,7 +18,6 @@ use View;
/** /**
* *
* @SuppressWarnings(PHPMD.TooManyMethods)
* *
* Class PiggyBankController * Class PiggyBankController
* *
@@ -40,12 +39,12 @@ class PiggyBankController extends Controller
/** /**
* Add money to piggy bank * Add money to piggy bank
* *
* @param AccountRepositoryInterface $repository * @param ARI $repository
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* *
* @return $this * @return $this
*/ */
public function add(AccountRepositoryInterface $repository, PiggyBank $piggyBank) public function add(ARI $repository, PiggyBank $piggyBank)
{ {
bcscale(2); bcscale(2);
$date = Session::get('end', Carbon::now()->endOfMonth()); $date = Session::get('end', Carbon::now()->endOfMonth());
@@ -58,11 +57,11 @@ class PiggyBankController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* *
* @return mixed * @return mixed
*/ */
public function create(AccountRepositoryInterface $repository) public function create(ARI $repository)
{ {
$periods = Config::get('firefly.piggy_bank_periods'); $periods = Config::get('firefly.piggy_bank_periods');
@@ -116,12 +115,12 @@ class PiggyBankController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* *
* @return View * @return View
*/ */
public function edit(AccountRepositoryInterface $repository, PiggyBank $piggyBank) public function edit(ARI $repository, PiggyBank $piggyBank)
{ {
$periods = Config::get('firefly.piggy_bank_periods'); $periods = Config::get('firefly.piggy_bank_periods');
@@ -157,12 +156,12 @@ class PiggyBankController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* @param PiggyBankRepositoryInterface $piggyRepository * @param PiggyBankRepositoryInterface $piggyRepository
* *
* @return View * @return View
*/ */
public function index(AccountRepositoryInterface $repository, PiggyBankRepositoryInterface $piggyRepository) public function index(ARI $repository, PiggyBankRepositoryInterface $piggyRepository)
{ {
/** @var Collection $piggyBanks */ /** @var Collection $piggyBanks */
$piggyBanks = $piggyRepository->getPiggyBanks(); $piggyBanks = $piggyRepository->getPiggyBanks();
@@ -219,12 +218,12 @@ class PiggyBankController extends Controller
/** /**
* @param PiggyBankRepositoryInterface $repository * @param PiggyBankRepositoryInterface $repository
* @param AccountRepositoryInterface $accounts * @param ARI $accounts
* @param PiggyBank $piggyBank * @param PiggyBank $piggyBank
* *
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function postAdd(PiggyBankRepositoryInterface $repository, AccountRepositoryInterface $accounts, PiggyBank $piggyBank) public function postAdd(PiggyBankRepositoryInterface $repository, ARI $accounts, PiggyBank $piggyBank)
{ {
bcscale(2); bcscale(2);
$amount = round(Input::get('amount'), 2); $amount = round(Input::get('amount'), 2);

View File

@@ -1,7 +1,7 @@
<?php namespace FireflyIII\Http\Controllers; <?php namespace FireflyIII\Http\Controllers;
use Config; use Config;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use Input; use Input;
use Preferences; use Preferences;
use Session; use Session;
@@ -26,21 +26,23 @@ class PreferencesController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* *
* @return $this|\Illuminate\View\View * @return $this|\Illuminate\View\View
*/ */
public function index(AccountRepositoryInterface $repository) public function index(ARI $repository)
{ {
$accounts = $repository->getAccounts(['Default account', 'Asset account']); $accounts = $repository->getAccounts(['Default account', 'Asset account']);
$viewRangePref = Preferences::get('viewRange', '1M'); $viewRangePref = Preferences::get('viewRange', '1M');
$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; $language = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US'))->data;
$budgetMaximum = $budgetMax->data; $budgetMaximum = $budgetMax->data;
return view('preferences.index', compact('budgetMaximum', 'language', 'accounts', 'frontPageAccounts', 'viewRange')); $showIncomplete = env('SHOW_INCOMPLETE_TRANSLATIONS', 'false') == 'true';
return view('preferences.index', compact('budgetMaximum', 'language', 'accounts', 'frontPageAccounts', 'viewRange', 'showIncomplete'));
} }
/** /**
@@ -70,7 +72,7 @@ class PreferencesController extends Controller
// language: // language:
$lang = Input::get('language'); $lang = Input::get('language');
if (in_array($lang, array_keys(Config::get('firefly.lang')))) { if (in_array($lang, array_keys(Config::get('firefly.languages')))) {
Preferences::set('language', $lang); Preferences::set('language', $lang);
} }

View File

@@ -3,7 +3,8 @@
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Helpers\Report\ReportHelperInterface; use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use Illuminate\Support\Collection;
use Session; use Session;
use View; use View;
@@ -34,118 +35,209 @@ class ReportController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* *
* @return View * @return View
* @internal param ReportHelperInterface $helper * @internal param ReportHelperInterface $helper
*/ */
public function index(AccountRepositoryInterface $repository) public function index(ARI $repository)
{ {
$start = Session::get('first'); $start = Session::get('first');
$months = $this->helper->listOfMonths($start); $months = $this->helper->listOfMonths($start);
$startOfMonth = clone Session::get('start');
$endOfMonth = clone Session::get('start');
$startOfYear = clone Session::get('start');
$endOfYear = clone Session::get('start');
$startOfMonth->startOfMonth();
$endOfMonth->endOfMonth();
$startOfYear->startOfYear();
$endOfYear->endOfYear();
// does the user have shared accounts? // does the user have shared accounts?
$accounts = $repository->getAccounts(['Default account', 'Asset account']); $accounts = $repository->getAccounts(['Default account', 'Asset account']);
$hasShared = false; // get id's for quick links:
$accountIds = [];
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
if ($account->getMeta('accountRole') == 'sharedAsset') { $accountIds [] = $account->id;
$hasShared = true;
} }
} $accountList = join(',', $accountIds);
return view('reports.index', compact('months', 'hasShared'));
}
/**
* @param string $year
* @param string $month
*
* @param bool $shared
*
* @return \Illuminate\View\View
*/
public function month($year = '2014', $month = '1', $shared = false)
{
$start = new Carbon($year . '-' . $month . '-01');
$subTitle = trans('firefly.reportForMonth', ['month' => $start->formatLocalized($this->monthFormat)]);
$subTitleIcon = 'fa-calendar';
$end = clone $start;
$incomeTopLength = 8;
$expenseTopLength = 8;
if ($shared == 'shared') {
$shared = true;
$subTitle = trans('firefly.reportForMonthShared', ['month' => $start->formatLocalized($this->monthFormat)]);
}
$end->endOfMonth();
$accounts = $this->helper->getAccountReport($start, $end, $shared);
$incomes = $this->helper->getIncomeReport($start, $end, $shared);
$expenses = $this->helper->getExpenseReport($start, $end, $shared);
$budgets = $this->helper->getBudgetReport($start, $end, $shared);
$categories = $this->helper->getCategoryReport($start, $end, $shared);
$balance = $this->helper->getBalanceReport($start, $end, $shared);
$bills = $this->helper->getBillReport($start, $end);
Session::flash('gaEventCategory', 'report');
Session::flash('gaEventAction', 'month');
Session::flash('gaEventLabel', $start->format('F Y'));
return view( return view(
'reports.month', 'reports.index', compact(
compact( 'months', 'accounts', 'start', 'accountList',
'start', 'shared', 'startOfMonth', 'endOfMonth', 'startOfYear', 'endOfYear'
'subTitle', 'subTitleIcon',
'accounts',
'incomes', 'incomeTopLength',
'expenses', 'expenseTopLength',
'budgets', 'balance',
'categories',
'bills'
) )
); );
} }
/** /**
* @param $year * @param $reportType
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* *
* @param bool $shared * @return View
*
* @return $this
*/ */
public function year($year, $shared = false) public function defaultYear($reportType, Carbon $start, Carbon $end, Collection $accounts)
{ {
$start = new Carbon('01-01-' . $year);
$end = clone $start;
$subTitle = trans('firefly.reportForYear', ['year' => $year]);
$subTitleIcon = 'fa-bar-chart';
$incomeTopLength = 8; $incomeTopLength = 8;
$expenseTopLength = 8; $expenseTopLength = 8;
if ($shared == 'shared') { $accountReport = $this->helper->getAccountReport($start, $end, $accounts);
$shared = true; $incomes = $this->helper->getIncomeReport($start, $end, $accounts);
$subTitle = trans('firefly.reportForYearShared', ['year' => $year]); $expenses = $this->helper->getExpenseReport($start, $end, $accounts);
}
$end->endOfYear();
$accounts = $this->helper->getAccountReport($start, $end, $shared);
$incomes = $this->helper->getIncomeReport($start, $end, $shared);
$expenses = $this->helper->getExpenseReport($start, $end, $shared);
Session::flash('gaEventCategory', 'report'); Session::flash('gaEventCategory', 'report');
Session::flash('gaEventAction', 'year'); Session::flash('gaEventAction', 'year');
Session::flash('gaEventLabel', $start->format('Y')); Session::flash('gaEventLabel', $start->format('Y'));
// and some id's, joined:
$accountIds = [];
/** @var Account $account */
foreach ($accounts as $account) {
$accountIds[] = $account->id;
}
$accountIds = join(',', $accountIds);
return view( return view(
'reports.year', 'reports.default.year',
compact('start', 'shared', 'accounts', 'incomes', 'expenses', 'subTitle', 'subTitleIcon', 'incomeTopLength', 'expenseTopLength') compact(
'start', 'accountReport', 'incomes', 'reportType', 'accountIds', 'end',
'expenses', 'incomeTopLength', 'expenseTopLength'
)
); );
} }
/**
* @param $reportType
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return View
*/
public function defaultMonth($reportType, Carbon $start, Carbon $end, Collection $accounts)
{
$incomeTopLength = 8;
$expenseTopLength = 8;
// get report stuff!
$accountReport = $this->helper->getAccountReport($start, $end, $accounts); // done (+2)
$incomes = $this->helper->getIncomeReport($start, $end, $accounts); // done (+3)
$expenses = $this->helper->getExpenseReport($start, $end, $accounts); // done (+1)
$budgets = $this->helper->getBudgetReport($start, $end, $accounts); // done (+5)
$categories = $this->helper->getCategoryReport($start, $end, $accounts); // done (+1) (20)
$balance = $this->helper->getBalanceReport($start, $end, $accounts); // +566
$bills = $this->helper->getBillReport($start, $end, $accounts);
// and some id's, joined:
$accountIds = join(',', $accounts->pluck('id')->toArray());
// continue!
return view(
'reports.default.month',
compact(
'start', 'end', 'reportType',
'accountReport',
'incomes', 'incomeTopLength',
'expenses', 'expenseTopLength',
'budgets', 'balance',
'categories',
'bills',
'accountIds', 'reportType'
)
);
}
/**
* @param $reportType
* @param $start
* @param $end
* @param $accounts
*
* @return View
*/
public function defaultMultiYear($reportType, $start, $end, $accounts)
{
$incomeTopLength = 8;
$expenseTopLength = 8;
// list of users stuff:
$budgets = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface')->getActiveBudgets();
$categories = app('FireflyIII\Repositories\Category\CategoryRepositoryInterface')->listCategories();
$accountReport = $this->helper->getAccountReport($start, $end, $accounts); // done (+2)
$incomes = $this->helper->getIncomeReport($start, $end, $accounts); // done (+3)
$expenses = $this->helper->getExpenseReport($start, $end, $accounts); // done (+1)
// and some id's, joined:
$accountIds = [];
/** @var Account $account */
foreach ($accounts as $account) {
$accountIds[] = $account->id;
}
$accountIds = join(',', $accountIds);
return view(
'reports.default.multi-year',
compact(
'budgets', 'accounts', 'categories', 'start', 'end', 'accountIds', 'reportType', 'accountReport', 'incomes', 'expenses',
'incomeTopLength', 'expenseTopLength'
)
);
}
/**
* @param $reportType
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return View
*/
public function report($reportType, Carbon $start, Carbon $end, Collection $accounts)
{
// throw an error if necessary.
if ($end < $start) {
return view('error')->with('message', 'End date cannot be before start date, silly!');
}
// lower threshold
if ($start < Session::get('first')) {
$start = Session::get('first');
}
switch ($reportType) {
default:
case 'default':
View::share(
'subTitle', trans(
'firefly.report_default',
[
'start' => $start->formatLocalized($this->monthFormat),
'end' => $end->formatLocalized($this->monthFormat),
]
)
);
View::share('subTitleIcon', 'fa-calendar');
// more than one year date difference means year report.
if ($start->diffInMonths($end) > 12) {
return $this->defaultMultiYear($reportType, $start, $end, $accounts);
}
// more than two months date difference means year report.
if ($start->diffInMonths($end) > 1) {
return $this->defaultYear($reportType, $start, $end, $accounts);
}
return $this->defaultMonth($reportType, $start, $end, $accounts);
}
}
} }

View File

@@ -10,10 +10,13 @@ use FireflyIII\Events\JournalSaved;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Requests\JournalFormRequest; use FireflyIII\Http\Requests\JournalFormRequest;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Support\Collection;
use Input; use Input;
use Preferences; use Preferences;
use Response; use Response;
@@ -40,13 +43,14 @@ class TransactionController extends Controller
} }
/** /**
* @param AccountRepositoryInterface $repository * @param ARI $repository
* @param string $what * @param string $what
* *
* @return \Illuminate\View\View * @return \Illuminate\View\View
*/ */
public function create(AccountRepositoryInterface $repository, $what = 'deposit') public function create(ARI $repository, $what = TransactionType::DEPOSIT)
{ {
$what = strtolower($what);
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize')); $maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = Steam::phpBytes(ini_get('post_max_size')); $maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
$uploadSize = min($maxFileSize, $maxPostSize); $uploadSize = min($maxFileSize, $maxPostSize);
@@ -95,7 +99,7 @@ class TransactionController extends Controller
*/ */
public function delete(TransactionJournal $journal) public function delete(TransactionJournal $journal)
{ {
$what = strtolower($journal->transactionType->type); $what = strtolower($journal->getTransactionType());
$subTitle = trans('firefly.delete_' . $what, ['description' => $journal->description]); $subTitle = trans('firefly.delete_' . $what, ['description' => $journal->description]);
// put previous url in session // put previous url in session
@@ -129,15 +133,15 @@ class TransactionController extends Controller
/** /**
* Shows the view to edit a transaction. * Shows the view to edit a transaction.
* *
* @param AccountRepositoryInterface $repository * @param ARI $repository
* @param TransactionJournal $journal * @param TransactionJournal $journal
* *
* @return $this * @return $this
*/ */
public function edit(AccountRepositoryInterface $repository, TransactionJournal $journal) public function edit(ARI $repository, TransactionJournal $journal)
{ {
// cannot edit opening balance // cannot edit opening balance
if ($journal->transactionType->type == 'Opening balance') { if ($journal->isOpeningBalance()) {
return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!'); return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!');
} }
@@ -145,7 +149,7 @@ class TransactionController extends Controller
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize')); $maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = Steam::phpBytes(ini_get('post_max_size')); $maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
$uploadSize = min($maxFileSize, $maxPostSize); $uploadSize = min($maxFileSize, $maxPostSize);
$what = strtolower($journal->transactionType->type); $what = strtolower($journal->getTransactionType());
$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] = trans('form.noBudget'); $budgets[0] = trans('form.noBudget');
@@ -159,11 +163,7 @@ class TransactionController extends Controller
'piggy_bank_id' => 0 'piggy_bank_id' => 0
]; ];
// get tags: // get tags:
$tags = []; $preFilled['tags'] = join(',', $journal->tags->pluck('tag')->toArray());
foreach ($journal->tags as $tag) {
$tags[] = $tag->tag;
}
$preFilled['tags'] = join(',', $tags);
$category = $journal->categories()->first(); $category = $journal->categories()->first();
if (!is_null($category)) { if (!is_null($category)) {
@@ -181,7 +181,7 @@ class TransactionController extends Controller
$preFilled['amount'] = $journal->amount_positive; $preFilled['amount'] = $journal->amount_positive;
if ($journal->transactionType->type == 'Withdrawal') { if ($journal->isWithdrawal()) {
$preFilled['account_id'] = $journal->source_account->id; $preFilled['account_id'] = $journal->source_account->id;
$preFilled['expense_account'] = $journal->destination_account->name_for_editform; $preFilled['expense_account'] = $journal->destination_account->name_for_editform;
} else { } else {
@@ -262,6 +262,15 @@ class TransactionController extends Controller
*/ */
public function show(JournalRepositoryInterface $repository, TransactionJournal $journal) public function show(JournalRepositoryInterface $repository, TransactionJournal $journal)
{ {
/** @var Collection $set */
$events = $journal->piggyBankEvents()->get();
$events->each(
function (PiggyBankEvent $event) {
$event->piggyBank = $event->piggyBank()->withTrashed()->first();
}
);
bcscale(2); bcscale(2);
$journal->transactions->each( $journal->transactions->each(
function (Transaction $t) use ($journal, $repository) { function (Transaction $t) use ($journal, $repository) {
@@ -269,16 +278,18 @@ class TransactionController extends Controller
$t->after = bcadd($t->before, $t->amount); $t->after = bcadd($t->before, $t->amount);
} }
); );
$what = strtolower($journal->transactionType->type); $what = strtolower($journal->getTransactionType());
$subTitle = trans('firefly.' . $journal->transactionType->type) . ' "' . e($journal->description) . '"'; $subTitle = trans('firefly.' . $journal->getTransactionType()) . ' "' . e($journal->description) . '"';
return view('transactions.show', compact('journal', 'subTitle', 'what')); return view('transactions.show', compact('journal', 'events', 'subTitle', 'what'));
} }
/** /**
* @param JournalFormRequest $request * @param JournalFormRequest $request
* @param JournalRepositoryInterface $repository * @param JournalRepositoryInterface $repository
* *
* @param AttachmentHelperInterface $att
*
* @return \Illuminate\Http\RedirectResponse * @return \Illuminate\Http\RedirectResponse
*/ */
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att) public function store(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att)
@@ -287,7 +298,7 @@ class TransactionController extends Controller
$journalData = $request->getJournalData(); $journalData = $request->getJournalData();
// if not withdrawal, unset budgetid. // if not withdrawal, unset budgetid.
if ($journalData['what'] != 'withdrawal') { if ($journalData['what'] != strtolower(TransactionType::WITHDRAWAL)) {
$journalData['budget_id'] = 0; $journalData['budget_id'] = 0;
} }
@@ -308,7 +319,7 @@ class TransactionController extends Controller
// rescan journal, UpdateJournalConnection // rescan journal, UpdateJournalConnection
event(new JournalSaved($journal)); event(new JournalSaved($journal));
if ($journal->transactionType->type == 'Transfer' && intval($request->get('piggy_bank_id')) > 0) { if ($journal->isTransfer() && intval($request->get('piggy_bank_id')) > 0) {
event(new JournalCreated($journal, intval($request->get('piggy_bank_id')))); event(new JournalCreated($journal, intval($request->get('piggy_bank_id'))));
} }
@@ -339,8 +350,7 @@ class TransactionController extends Controller
public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att, TransactionJournal $journal) public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att, TransactionJournal $journal)
{ {
// cannot edit opening balance if ($journal->isOpeningBalance()) {
if ($journal->transactionType->type == 'Opening balance') {
return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!'); return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!');
} }

View File

@@ -1,13 +1,14 @@
<?php namespace FireflyIII\Http\Middleware; <?php namespace FireflyIII\Http\Middleware;
use App; use App;
use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Closure; use Closure;
use Config; use FireflyIII\User;
use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Preferences; use Preferences;
use Auth;
/** /**
* Class Authenticate * Class Authenticate
* *
@@ -45,6 +46,7 @@ class Authenticate
*/ */
public function handle(Request $request, Closure $next) public function handle(Request $request, Closure $next)
{ {
if ($this->auth->guest()) { if ($this->auth->guest()) {
if ($request->ajax()) { if ($request->ajax()) {
return response('Unauthorized.', 401); return response('Unauthorized.', 401);
@@ -52,18 +54,23 @@ class Authenticate
return redirect()->guest('auth/login'); return redirect()->guest('auth/login');
} }
} }
/** @var User $user */
if (intval($this->auth->user()->blocked) == 1) { $user = $this->auth->user();
if ($user instanceof User && intval($user->blocked) == 1) {
Auth::logout(); Auth::logout();
return redirect()->route('index'); return redirect()->route('index');
} }
// if logged in, set user language: // if logged in, set user language:
$pref = Preferences::get('language', 'en'); $pref = Preferences::get('language', env('DEFAULT_LANGUAGE', 'en_US'));
App::setLocale($pref->data); App::setLocale($pref->data);
Carbon::setLocale($pref->data); Carbon::setLocale(substr($pref->data, 0, 2));
$locale = explode(',', trans('config.locale'));
$locale = array_map('trim', $locale);
setlocale(LC_TIME, Config::get('firefly.locales.' . $pref->data)); setlocale(LC_TIME, $locale);
setlocale(LC_MONETARY, $locale);
return $next($request); return $next($request);
} }

View File

@@ -42,7 +42,6 @@ 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
*/ */

View File

@@ -51,7 +51,8 @@ class AccountFormRequest extends Request
'active' => 'boolean', 'active' => 'boolean',
'ccType' => 'in:' . $ccPaymentTypes, 'ccType' => 'in:' . $ccPaymentTypes,
'ccMonthlyPaymentDate' => 'date', 'ccMonthlyPaymentDate' => 'date',
'balance_currency_id' => 'exists:transaction_currencies,id', 'amount_currency_id_openingBalance' => 'exists:transaction_currencies,id',
'amount_currency_id_virtualBalance' => 'exists:transaction_currencies,id',
'what' => 'in:' . $types 'what' => 'in:' . $types
]; ];
} }

View File

@@ -32,7 +32,8 @@ class BillFormRequest extends Request
'name' => $this->get('name'), 'name' => $this->get('name'),
'match' => $this->get('match'), 'match' => $this->get('match'),
'amount_min' => round($this->get('amount_min'), 2), 'amount_min' => round($this->get('amount_min'), 2),
'amount_currency_id' => round($this->get('amount_currency_id'), 2), 'amount_currency_id_amount_min' => intval($this->get('amount_currency_id_amount_min')),
'amount_currency_id_amount_max' => intval($this->get('amount_currency_id_amount_max')),
'amount_max' => round($this->get('amount_max'), 2), 'amount_max' => round($this->get('amount_max'), 2),
'date' => new Carbon($this->get('date')), 'date' => new Carbon($this->get('date')),
'user' => Auth::user()->id, 'user' => Auth::user()->id,
@@ -60,7 +61,8 @@ class BillFormRequest extends Request
'match' => $matchRule, 'match' => $matchRule,
'amount_min' => 'required|numeric|min:0.01', 'amount_min' => 'required|numeric|min:0.01',
'amount_max' => 'required|numeric|min:0.01', 'amount_max' => 'required|numeric|min:0.01',
'amount_currency_id' => 'required|exists:transaction_currencies,id', 'amount_currency_id_amount_min' => 'required|exists:transaction_currencies,id',
'amount_currency_id_amount_max' => 'required|exists:transaction_currencies,id',
'date' => 'required|date', 'date' => 'required|date',
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly', 'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
'skip' => 'required|between:0,31', 'skip' => 'required|between:0,31',

View File

@@ -5,6 +5,7 @@ namespace FireflyIII\Http\Requests;
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use FireflyIII\Models\TransactionType;
use Input; use Input;
/** /**
@@ -39,7 +40,7 @@ class JournalFormRequest extends Request
'revenue_account' => $this->get('revenue_account'), 'revenue_account' => $this->get('revenue_account'),
'amount' => round($this->get('amount'), 2), 'amount' => round($this->get('amount'), 2),
'user' => Auth::user()->id, 'user' => Auth::user()->id,
'amount_currency_id' => intval($this->get('amount_currency_id')), 'amount_currency_id_amount' => intval($this->get('amount_currency_id_amount')),
'date' => new Carbon($this->get('date')), 'date' => new Carbon($this->get('date')),
'budget_id' => intval($this->get('budget_id')), 'budget_id' => intval($this->get('budget_id')),
'category' => $this->get('category'), 'category' => $this->get('category'),
@@ -50,7 +51,6 @@ class JournalFormRequest extends Request
/** /**
* @return array * @return array
* @throws Exception * @throws Exception
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/ */
public function rules() public function rules()
{ {
@@ -60,12 +60,12 @@ class JournalFormRequest extends Request
'what' => 'required|in:withdrawal,deposit,transfer', 'what' => 'required|in:withdrawal,deposit,transfer',
'amount' => 'numeric|required|min:0.01', 'amount' => 'numeric|required|min:0.01',
'date' => 'required|date', 'date' => 'required|date',
'amount_currency_id' => 'required|exists:transaction_currencies,id', 'amount_currency_id_amount' => 'required|exists:transaction_currencies,id',
]; ];
switch ($what) { switch ($what) {
case 'withdrawal': case strtolower(TransactionType::WITHDRAWAL):
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts'; $rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
$rules['expense_account'] = 'between:1,255'; $rules['expense_account'] = 'between:1,255';
$rules['category'] = 'between:1,255'; $rules['category'] = 'between:1,255';
@@ -73,12 +73,12 @@ class JournalFormRequest extends Request
$rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets'; $rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets';
} }
break; break;
case 'deposit': case strtolower(TransactionType::DEPOSIT):
$rules['category'] = 'between:1,255'; $rules['category'] = 'between:1,255';
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts'; $rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
$rules['revenue_account'] = 'between:1,255'; $rules['revenue_account'] = 'between:1,255';
break; break;
case 'transfer': case strtolower(TransactionType::TRANSFER):
$rules['account_from_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_to_id'; $rules['account_from_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_to_id';
$rules['account_to_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_from_id'; $rules['account_to_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_from_id';
$rules['category'] = 'between:1,255'; $rules['category'] = 'between:1,255';

View File

@@ -31,7 +31,9 @@ class NewUserFormRequest extends Request
'bank_balance' => 'required|numeric', 'bank_balance' => 'required|numeric',
'savings_balance' => 'numeric', 'savings_balance' => 'numeric',
'credit_card_limit' => 'numeric', 'credit_card_limit' => 'numeric',
'balance_currency_id' => 'exists:transaction_currencies,id', 'amount_currency_id_bank_balance' => 'exists:transaction_currencies,id',
'amount_currency_id_savings_balance' => 'exists:transaction_currencies,id',
'amount_currency_id_credit_card_limit' => 'exists:transaction_currencies,id',
]; ];
} }
} }

View File

@@ -39,7 +39,7 @@ class PiggyBankFormRequest extends Request
'name' => $nameRule, 'name' => $nameRule,
'account_id' => 'required|belongsToUser:accounts', 'account_id' => 'required|belongsToUser:accounts',
'targetamount' => 'required|min:0.01', 'targetamount' => 'required|min:0.01',
'amount_currency_id' => 'exists:transaction_currencies,id', 'amount_currency_id_targetamount' => 'exists:transaction_currencies,id',
'startdate' => 'date', 'startdate' => 'date',
'targetdate' => $targetDateRule, 'targetdate' => $targetDateRule,
'order' => 'integer|min:1', 'order' => 'integer|min:1',

View File

@@ -1,6 +1,6 @@
<?php <?php
use Carbon\Carbon; use Carbon\Carbon;
use DaveJamesMiller\Breadcrumbs\Generator; use DaveJamesMiller\Breadcrumbs\Generator as BreadCrumbGenerator;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
@@ -16,7 +16,7 @@ use FireflyIII\Models\TransactionJournal;
*/ */
Breadcrumbs::register( Breadcrumbs::register(
'home', 'home',
function (Generator $breadcrumbs) { function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->push(trans('breadcrumbs.home'), route('index')); $breadcrumbs->push(trans('breadcrumbs.home'), route('index'));
} }
@@ -24,7 +24,7 @@ Breadcrumbs::register(
Breadcrumbs::register( Breadcrumbs::register(
'index', 'index',
function (Generator $breadcrumbs) { function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->push(trans('breadcrumbs.home'), route('index')); $breadcrumbs->push(trans('breadcrumbs.home'), route('index'));
} }
@@ -33,21 +33,21 @@ Breadcrumbs::register(
// accounts // accounts
Breadcrumbs::register( Breadcrumbs::register(
'accounts.index', function (Generator $breadcrumbs, $what) { 'accounts.index', function (BreadCrumbGenerator $breadcrumbs, $what) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.' . strtolower(e($what)) . '_accounts'), route('accounts.index', [$what])); $breadcrumbs->push(trans('firefly.' . strtolower(e($what)) . '_accounts'), route('accounts.index', [$what]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'accounts.create', function (Generator $breadcrumbs, $what) { 'accounts.create', function (BreadCrumbGenerator $breadcrumbs, $what) {
$breadcrumbs->parent('accounts.index', $what); $breadcrumbs->parent('accounts.index', $what);
$breadcrumbs->push(trans('firefly.new_' . strtolower(e($what)) . '_account'), route('accounts.create', [$what])); $breadcrumbs->push(trans('firefly.new_' . strtolower(e($what)) . '_account'), route('accounts.create', [$what]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'accounts.show', function (Generator $breadcrumbs, Account $account) { 'accounts.show', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type); $what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
@@ -57,7 +57,7 @@ Breadcrumbs::register(
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'accounts.delete', function (Generator $breadcrumbs, Account $account) { 'accounts.delete', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
$breadcrumbs->parent('accounts.show', $account); $breadcrumbs->parent('accounts.show', $account);
$breadcrumbs->push(trans('firefly.delete_account', ['name' => e($account->name)]), route('accounts.delete', [$account->id])); $breadcrumbs->push(trans('firefly.delete_account', ['name' => e($account->name)]), route('accounts.delete', [$account->id]));
} }
@@ -65,7 +65,7 @@ Breadcrumbs::register(
Breadcrumbs::register( Breadcrumbs::register(
'accounts.edit', function (Generator $breadcrumbs, Account $account) { 'accounts.edit', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
$breadcrumbs->parent('accounts.show', $account); $breadcrumbs->parent('accounts.show', $account);
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type); $what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
@@ -75,40 +75,40 @@ Breadcrumbs::register(
// budgets. // budgets.
Breadcrumbs::register( Breadcrumbs::register(
'budgets.index', function (Generator $breadcrumbs) { 'budgets.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.budgets'), route('budgets.index')); $breadcrumbs->push(trans('firefly.budgets'), route('budgets.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'budgets.create', function (Generator $breadcrumbs) { 'budgets.create', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('budgets.index'); $breadcrumbs->parent('budgets.index');
$breadcrumbs->push(trans('firefly.create_new_budget'), route('budgets.create')); $breadcrumbs->push(trans('firefly.create_new_budget'), route('budgets.create'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'budgets.edit', function (Generator $breadcrumbs, Budget $budget) { 'budgets.edit', function (BreadCrumbGenerator $breadcrumbs, Budget $budget) {
$breadcrumbs->parent('budgets.show', $budget); $breadcrumbs->parent('budgets.show', $budget);
$breadcrumbs->push(trans('firefly.edit_budget', ['name' => e($budget->name)]), route('budgets.edit', [$budget->id])); $breadcrumbs->push(trans('firefly.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 (BreadCrumbGenerator $breadcrumbs, Budget $budget) {
$breadcrumbs->parent('budgets.show', $budget); $breadcrumbs->parent('budgets.show', $budget);
$breadcrumbs->push(trans('firefly.delete_budget', ['name' => e($budget->name)]), route('budgets.delete', [$budget->id])); $breadcrumbs->push(trans('firefly.delete_budget', ['name' => e($budget->name)]), route('budgets.delete', [$budget->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'budgets.noBudget', function (Generator $breadcrumbs, $subTitle) { 'budgets.noBudget', function (BreadCrumbGenerator $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 (BreadCrumbGenerator $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)) {
@@ -121,33 +121,33 @@ Breadcrumbs::register(
// categories // categories
Breadcrumbs::register( Breadcrumbs::register(
'categories.index', function (Generator $breadcrumbs) { 'categories.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.categories'), route('categories.index')); $breadcrumbs->push(trans('firefly.categories'), route('categories.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'categories.create', function (Generator $breadcrumbs) { 'categories.create', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('categories.index'); $breadcrumbs->parent('categories.index');
$breadcrumbs->push(trans('firefly.new_category'), route('categories.create')); $breadcrumbs->push(trans('firefly.new_category'), route('categories.create'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'categories.edit', function (Generator $breadcrumbs, Category $category) { 'categories.edit', function (BreadCrumbGenerator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.show', $category); $breadcrumbs->parent('categories.show', $category);
$breadcrumbs->push(trans('firefly.edit_category', ['name' => e($category->name)]), route('categories.edit', [$category->id])); $breadcrumbs->push(trans('firefly.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 (BreadCrumbGenerator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.show', $category); $breadcrumbs->parent('categories.show', $category);
$breadcrumbs->push(trans('firefly.delete_category', ['name' => e($category->name)]), route('categories.delete', [$category->id])); $breadcrumbs->push(trans('firefly.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 (BreadCrumbGenerator $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]));
@@ -155,7 +155,7 @@ Breadcrumbs::register(
); );
Breadcrumbs::register( Breadcrumbs::register(
'categories.show.date', function (Generator $breadcrumbs, Category $category, Carbon $date) { 'categories.show.date', function (BreadCrumbGenerator $breadcrumbs, Category $category, Carbon $date) {
// get current period preference. // get current period preference.
$range = Preferences::get('viewRange', '1M')->data; $range = Preferences::get('viewRange', '1M')->data;
@@ -168,7 +168,7 @@ Breadcrumbs::register(
); );
Breadcrumbs::register( Breadcrumbs::register(
'categories.noCategory', function (Generator $breadcrumbs, $subTitle) { 'categories.noCategory', function (BreadCrumbGenerator $breadcrumbs, $subTitle) {
$breadcrumbs->parent('categories.index'); $breadcrumbs->parent('categories.index');
$breadcrumbs->push($subTitle, route('categories.noCategory')); $breadcrumbs->push($subTitle, route('categories.noCategory'));
} }
@@ -176,35 +176,35 @@ Breadcrumbs::register(
// CSV: // CSV:
Breadcrumbs::register( Breadcrumbs::register(
'csv.index', function (Generator $breadcrumbs) { 'csv.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.csv_index_title'), route('csv.index')); $breadcrumbs->push(trans('firefly.csv_index_title'), route('csv.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'csv.column-roles', function (Generator $breadcrumbs) { 'csv.column-roles', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('csv.index'); $breadcrumbs->parent('csv.index');
$breadcrumbs->push(trans('firefly.csv_define_column_roles'), route('csv.column-roles')); $breadcrumbs->push(trans('firefly.csv_define_column_roles'), route('csv.column-roles'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'csv.map', function (Generator $breadcrumbs) { 'csv.map', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('csv.index'); $breadcrumbs->parent('csv.index');
$breadcrumbs->push(trans('firefly.csv_map_values'), route('csv.map')); $breadcrumbs->push(trans('firefly.csv_map_values'), route('csv.map'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'csv.download-config-page', function (Generator $breadcrumbs) { 'csv.download-config-page', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('csv.index'); $breadcrumbs->parent('csv.index');
$breadcrumbs->push(trans('firefly.csv_download_config'), route('csv.download-config-page')); $breadcrumbs->push(trans('firefly.csv_download_config'), route('csv.download-config-page'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'csv.process', function (Generator $breadcrumbs) { 'csv.process', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('csv.index'); $breadcrumbs->parent('csv.index');
$breadcrumbs->push(trans('firefly.csv_process_title'), route('csv.process')); $breadcrumbs->push(trans('firefly.csv_process_title'), route('csv.process'));
} }
@@ -213,27 +213,27 @@ Breadcrumbs::register(
// currencies. // currencies.
Breadcrumbs::register( Breadcrumbs::register(
'currency.index', function (Generator $breadcrumbs) { 'currency.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.currencies'), route('currency.index')); $breadcrumbs->push(trans('firefly.currencies'), route('currency.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'currency.create', function (Generator $breadcrumbs) { 'currency.create', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('currency.index'); $breadcrumbs->parent('currency.index');
$breadcrumbs->push(trans('firefly.create_currency'), route('currency.create')); $breadcrumbs->push(trans('firefly.create_currency'), route('currency.create'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'currency.edit', function (Generator $breadcrumbs, TransactionCurrency $currency) { 'currency.edit', function (BreadCrumbGenerator $breadcrumbs, TransactionCurrency $currency) {
$breadcrumbs->parent('currency.index'); $breadcrumbs->parent('currency.index');
$breadcrumbs->push(trans('breadcrumbs.edit_currency', ['name' => e($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 (BreadCrumbGenerator $breadcrumbs, TransactionCurrency $currency) {
$breadcrumbs->parent('currency.index'); $breadcrumbs->parent('currency.index');
$breadcrumbs->push(trans('breadcrumbs.delete_currency', ['name' => e($currency->name)]), route('currency.delete', [$currency->id])); $breadcrumbs->push(trans('breadcrumbs.delete_currency', ['name' => e($currency->name)]), route('currency.delete', [$currency->id]));
} }
@@ -242,33 +242,33 @@ Breadcrumbs::register(
// piggy banks // piggy banks
Breadcrumbs::register( Breadcrumbs::register(
'piggy-banks.index', function (Generator $breadcrumbs) { 'piggy-banks.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('firefly.piggyBanks'), route('piggy-banks.index')); $breadcrumbs->push(trans('firefly.piggyBanks'), route('piggy-banks.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'piggy-banks.create', function (Generator $breadcrumbs) { 'piggy-banks.create', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('piggy-banks.index'); $breadcrumbs->parent('piggy-banks.index');
$breadcrumbs->push(trans('breadcrumbs.newPiggyBank'), 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 (BreadCrumbGenerator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.show', $piggyBank); $breadcrumbs->parent('piggy-banks.show', $piggyBank);
$breadcrumbs->push(trans('breadcrumbs.edit_piggyBank', ['name' => 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 (BreadCrumbGenerator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.show', $piggyBank); $breadcrumbs->parent('piggy-banks.show', $piggyBank);
$breadcrumbs->push(trans('firefly.delete_piggy_bank', ['name' => e($piggyBank->name)]), route('piggy-banks.delete', [$piggyBank->id])); $breadcrumbs->push(trans('firefly.delete_piggy_bank', ['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 (BreadCrumbGenerator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.index'); $breadcrumbs->parent('piggy-banks.index');
$breadcrumbs->push(e($piggyBank->name), route('piggy-banks.show', [$piggyBank->id])); $breadcrumbs->push(e($piggyBank->name), route('piggy-banks.show', [$piggyBank->id]));
@@ -277,7 +277,7 @@ Breadcrumbs::register(
// preferences // preferences
Breadcrumbs::register( Breadcrumbs::register(
'preferences', function (Generator $breadcrumbs) { 'preferences', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.preferences'), route('preferences')); $breadcrumbs->push(trans('breadcrumbs.preferences'), route('preferences'));
@@ -286,21 +286,21 @@ Breadcrumbs::register(
// profile // profile
Breadcrumbs::register( Breadcrumbs::register(
'profile', function (Generator $breadcrumbs) { 'profile', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.profile'), route('profile')); $breadcrumbs->push(trans('breadcrumbs.profile'), route('profile'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'profile.change-password', function (Generator $breadcrumbs) { 'profile.change-password', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('profile'); $breadcrumbs->parent('profile');
$breadcrumbs->push(trans('breadcrumbs.changePassword'), route('profile.change-password')); $breadcrumbs->push(trans('breadcrumbs.changePassword'), route('profile.change-password'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'profile.delete-account', function (Generator $breadcrumbs) { 'profile.delete-account', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('profile'); $breadcrumbs->parent('profile');
$breadcrumbs->push(trans('firefly.delete_account'), route('profile.delete-account')); $breadcrumbs->push(trans('firefly.delete_account'), route('profile.delete-account'));
@@ -309,33 +309,33 @@ Breadcrumbs::register(
// bills // bills
Breadcrumbs::register( Breadcrumbs::register(
'bills.index', function (Generator $breadcrumbs) { 'bills.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.bills'), route('bills.index')); $breadcrumbs->push(trans('breadcrumbs.bills'), route('bills.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'bills.create', function (Generator $breadcrumbs) { 'bills.create', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('bills.index'); $breadcrumbs->parent('bills.index');
$breadcrumbs->push(trans('breadcrumbs.newBill'), 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 (BreadCrumbGenerator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.show', $bill); $breadcrumbs->parent('bills.show', $bill);
$breadcrumbs->push(trans('breadcrumbs.edit_bill', ['name' => 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 (BreadCrumbGenerator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.show', $bill); $breadcrumbs->parent('bills.show', $bill);
$breadcrumbs->push(trans('breadcrumbs.delete_bill', ['name' => 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 (BreadCrumbGenerator $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]));
@@ -344,43 +344,26 @@ Breadcrumbs::register(
// reports // reports
Breadcrumbs::register( Breadcrumbs::register(
'reports.index', function (Generator $breadcrumbs) { 'reports.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.reports'), route('reports.index')); $breadcrumbs->push(trans('breadcrumbs.reports'), route('reports.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'reports.year', function (Generator $breadcrumbs, Carbon $date, $shared) { 'reports.report', function (BreadCrumbGenerator $breadcrumbs, Carbon $start, Carbon $end, $reportType, $accountIds) {
$breadcrumbs->parent('reports.index'); $breadcrumbs->parent('reports.index');
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( $monthFormat = trans('config.month_and_day');
'reports.month', function (Generator $breadcrumbs, Carbon $date, $shared) { $title = trans('firefly.report_' . $reportType, ['start' => $start->formatLocalized($monthFormat), 'end' => $end->formatLocalized($monthFormat)]);
$breadcrumbs->parent('reports.year', $date, $shared);
$language = Preferences::get('language', 'en')->data;
$format = Config::get('firefly.month.' . $language);
if ($shared) { $breadcrumbs->push($title, route('reports.report', [$reportType, $start->format('Ymd'), $end->format('Ymd'), $accountIds]));
$title = trans('breadcrumbs.monthly_report_shared', ['date' => $date->formatLocalized($format)]);
} else {
$title = trans('breadcrumbs.monthly_report', ['date' => $date->formatLocalized($format)]);
}
$breadcrumbs->push($title, route('reports.month', [$date->year, $date->month]));
} }
); );
// search // search
Breadcrumbs::register( Breadcrumbs::register(
'search', function (Generator $breadcrumbs, $query) { 'search', function (BreadCrumbGenerator $breadcrumbs, $query) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.searchResult', ['query' => e($query)]), route('search')); $breadcrumbs->push(trans('breadcrumbs.searchResult', ['query' => e($query)]), route('search'));
} }
@@ -388,35 +371,35 @@ Breadcrumbs::register(
// transactions // transactions
Breadcrumbs::register( Breadcrumbs::register(
'transactions.index', function (Generator $breadcrumbs, $what) { 'transactions.index', function (BreadCrumbGenerator $breadcrumbs, $what) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.' . $what . '_list'), route('transactions.index', [$what])); $breadcrumbs->push(trans('breadcrumbs.' . $what . '_list'), route('transactions.index', [$what]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'transactions.create', function (Generator $breadcrumbs, $what) { 'transactions.create', function (BreadCrumbGenerator $breadcrumbs, $what) {
$breadcrumbs->parent('transactions.index', $what); $breadcrumbs->parent('transactions.index', $what);
$breadcrumbs->push(trans('breadcrumbs.create_' . 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 (BreadCrumbGenerator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.show', $journal); $breadcrumbs->parent('transactions.show', $journal);
$breadcrumbs->push(trans('breadcrumbs.edit_journal', ['description' => $journal->description]), route('transactions.edit', [$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 (BreadCrumbGenerator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.show', $journal); $breadcrumbs->parent('transactions.show', $journal);
$breadcrumbs->push(trans('breadcrumbs.delete_journal', ['description' => 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 (BreadCrumbGenerator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.index', strtolower($journal->transactionType->type)); $breadcrumbs->parent('transactions.index', strtolower($journal->getTransactionType()));
$breadcrumbs->push($journal->description, route('transactions.show', [$journal->id])); $breadcrumbs->push($journal->description, route('transactions.show', [$journal->id]));
} }
@@ -424,28 +407,28 @@ Breadcrumbs::register(
// tags // tags
Breadcrumbs::register( Breadcrumbs::register(
'tags.index', function (Generator $breadcrumbs) { 'tags.index', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('home'); $breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.tags'), route('tags.index')); $breadcrumbs->push(trans('breadcrumbs.tags'), route('tags.index'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'tags.create', function (Generator $breadcrumbs) { 'tags.create', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('tags.index'); $breadcrumbs->parent('tags.index');
$breadcrumbs->push(trans('breadcrumbs.createTag'), route('tags.create')); $breadcrumbs->push(trans('breadcrumbs.createTag'), route('tags.create'));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'tags.edit', function (Generator $breadcrumbs, Tag $tag) { 'tags.edit', function (BreadCrumbGenerator $breadcrumbs, Tag $tag) {
$breadcrumbs->parent('tags.show', $tag); $breadcrumbs->parent('tags.show', $tag);
$breadcrumbs->push(trans('breadcrumbs.edit_tag', ['tag' => e($tag->tag)]), route('tags.edit', [$tag->id])); $breadcrumbs->push(trans('breadcrumbs.edit_tag', ['tag' => e($tag->tag)]), route('tags.edit', [$tag->id]));
} }
); );
Breadcrumbs::register( Breadcrumbs::register(
'tags.delete', function (Generator $breadcrumbs, Tag $tag) { 'tags.delete', function (BreadCrumbGenerator $breadcrumbs, Tag $tag) {
$breadcrumbs->parent('tags.show', $tag); $breadcrumbs->parent('tags.show', $tag);
$breadcrumbs->push(trans('breadcrumbs.delete_tag', ['tag' => e($tag->tag)]), route('tags.delete', [$tag->id])); $breadcrumbs->push(trans('breadcrumbs.delete_tag', ['tag' => e($tag->tag)]), route('tags.delete', [$tag->id]));
} }
@@ -453,7 +436,7 @@ Breadcrumbs::register(
Breadcrumbs::register( Breadcrumbs::register(
'tags.show', function (Generator $breadcrumbs, Tag $tag) { 'tags.show', function (BreadCrumbGenerator $breadcrumbs, Tag $tag) {
$breadcrumbs->parent('tags.index'); $breadcrumbs->parent('tags.index');
$breadcrumbs->push(e($tag->tag), route('tags.show', [$tag->id])); $breadcrumbs->push(e($tag->tag), route('tags.show', [$tag->id]));
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
use Carbon\Carbon;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Attachment; use FireflyIII\Models\Attachment;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
@@ -29,6 +30,111 @@ Route::bind(
throw new NotFoundHttpException; throw new NotFoundHttpException;
} }
); );
// accounts
Route::bind(
'accountList',
function ($value) {
if (Auth::check()) {
$ids = explode(',', $value);
/** @var \Illuminate\Support\Collection $object */
$object = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.editable', 1)
->whereIn('accounts.id', $ids)
->where('user_id', Auth::user()->id)
->get(['accounts.*']);
if ($object->count() > 0) {
return $object;
}
}
throw new NotFoundHttpException;
}
);
// budget list
Route::bind(
'budgetList',
function ($value) {
if (Auth::check()) {
$ids = explode(',', $value);
/** @var \Illuminate\Support\Collection $object */
$object = Budget::where('active', 1)
->whereIn('id', $ids)
->where('user_id', Auth::user()->id)
->get();
// add empty budget if applicable.
if (in_array('0', $ids)) {
$object->push(new Budget);
}
if ($object->count() > 0) {
return $object;
}
}
throw new NotFoundHttpException;
}
);
// category list
Route::bind(
'categoryList',
function ($value) {
if (Auth::check()) {
$ids = explode(',', $value);
/** @var \Illuminate\Support\Collection $object */
$object = Category::whereIn('id', $ids)
->where('user_id', Auth::user()->id)
->get();
// add empty budget if applicable.
if (in_array('0', $ids)) {
$object->push(new Category);
}
if ($object->count() > 0) {
return $object;
}
}
throw new NotFoundHttpException;
}
);
// Date
Route::bind(
'start_date',
function ($value) {
if (Auth::check()) {
try {
$date = new Carbon($value);
} catch (Exception $e) {
Log::error('Could not parse date "' . $value . '" for user #' . Auth::user()->id);
throw new NotFoundHttpException;
}
return $date;
}
throw new NotFoundHttpException;
}
);
// Date
Route::bind(
'end_date',
function ($value) {
if (Auth::check()) {
try {
$date = new Carbon($value);
} catch (Exception $e) {
Log::error('Could not parse date "' . $value . '" for user #' . Auth::user()->id);
throw new NotFoundHttpException;
}
return $date;
}
throw new NotFoundHttpException;
}
);
Route::bind( Route::bind(
'tj', function ($value) { 'tj', function ($value) {
@@ -158,7 +264,6 @@ Route::bind(
* Auth\AuthController * Auth\AuthController
*/ */
Route::get('/register', ['uses' => 'Auth\AuthController@getRegister', 'as' => 'register']); Route::get('/register', ['uses' => 'Auth\AuthController@getRegister', 'as' => 'register']);
Route::get('/cron/sendgrid', ['uses' => 'CronController@sendgrid']);
Route::controllers( Route::controllers(
[ [
@@ -178,7 +283,6 @@ Route::group(
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']);
Route::get('/routes', ['uses' => 'HomeController@routes']);
/** /**
* Account Controller * Account Controller
*/ */
@@ -284,9 +388,7 @@ Route::group(
// accounts: // accounts:
Route::get('/chart/account/frontpage', ['uses' => 'Chart\AccountController@frontpage']); Route::get('/chart/account/frontpage', ['uses' => 'Chart\AccountController@frontpage']);
Route::get('/chart/account/expense', ['uses' => 'Chart\AccountController@expenseAccounts']); Route::get('/chart/account/expense', ['uses' => 'Chart\AccountController@expenseAccounts']);
Route::get('/chart/account/month/{year}/{month}/{shared?}', ['uses' => 'Chart\AccountController@all'])->where( Route::get('/chart/account/report/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\AccountController@report']);
['year' => '[0-9]{4}', 'month' => '[0-9]{1,2}', 'shared' => 'shared']
);
Route::get('/chart/account/{account}', ['uses' => 'Chart\AccountController@single']); Route::get('/chart/account/{account}', ['uses' => 'Chart\AccountController@single']);
@@ -296,30 +398,34 @@ Route::group(
// budgets: // budgets:
Route::get('/chart/budget/frontpage', ['uses' => 'Chart\BudgetController@frontpage']); 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']);
// this chart is used in reports:
Route::get('/chart/budget/year/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\BudgetController@year']);
Route::get('/chart/budget/multi-year/{reportType}/{start_date}/{end_date}/{accountList}/{budgetList}', ['uses' => 'Chart\BudgetController@multiYear']);
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'Chart\BudgetController@budgetLimit']); Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'Chart\BudgetController@budgetLimit']);
Route::get('/chart/budget/{budget}', ['uses' => 'Chart\BudgetController@budget']); Route::get('/chart/budget/{budget}', ['uses' => 'Chart\BudgetController@budget']);
// categories: // categories:
Route::get('/chart/category/frontpage', ['uses' => 'Chart\CategoryController@frontpage']); Route::get('/chart/category/frontpage', ['uses' => 'Chart\CategoryController@frontpage']);
Route::get('/chart/category/spent-in-year/{year}/{shared?}', ['uses' => 'Chart\CategoryController@spentInYear'])->where(
['year' => '[0-9]{4}', 'shared' => 'shared'] // these three charts are for reports:
); Route::get('/chart/category/earned-in-period/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\CategoryController@earnedInPeriod']);
Route::get('/chart/category/earned-in-year/{year}/{shared?}', ['uses' => 'Chart\CategoryController@earnedInYear'])->where( Route::get('/chart/category/spent-in-period/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\CategoryController@spentInPeriod']);
['year' => '[0-9]{4}', 'shared' => 'shared'] Route::get(
'/chart/category/multi-year/{reportType}/{start_date}/{end_date}/{accountList}/{categoryList}', ['uses' => 'Chart\CategoryController@multiYear']
); );
Route::get('/chart/category/{category}/period', ['uses' => 'Chart\CategoryController@currentPeriod']); Route::get('/chart/category/{category}/period', ['uses' => 'Chart\CategoryController@currentPeriod']);
Route::get('/chart/category/{category}/period/{date}', ['uses' => 'Chart\CategoryController@specificPeriod']); Route::get('/chart/category/{category}/period/{date}', ['uses' => 'Chart\CategoryController@specificPeriod']);
Route::get('/chart/category/{category}/all', ['uses' => 'Chart\CategoryController@all']); Route::get('/chart/category/{category}/all', ['uses' => 'Chart\CategoryController@all']);
// piggy banks: // piggy banks:
Route::get('/chart/piggyBank/{piggyBank}', ['uses' => 'Chart\PiggyBankController@history']); Route::get('/chart/piggy-bank/{piggyBank}', ['uses' => 'Chart\PiggyBankController@history']);
// reports: // 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/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\ReportController@yearInOut']);
Route::get('/chart/report/in-out-sum/{year}/{shared?}', ['uses' => 'Chart\ReportController@yearInOutSummarized'])->where( Route::get('/chart/report/in-out-sum/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'Chart\ReportController@yearInOutSummarized']);
['year' => '[0-9]{4}', 'shared' => 'shared']
);
/** /**
@@ -385,12 +491,7 @@ 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}/{shared?}', ['uses' => 'ReportController@year', 'as' => 'reports.year'])->where(['year' => '[0-9]{4}', 'shared' => 'shared']); Route::get('/reports/report/{reportType}/{start_date}/{end_date}/{accountList}', ['uses' => 'ReportController@report', 'as' => 'reports.report']);
Route::get('/reports/{year}/{month}/{shared?}', ['uses' => 'ReportController@month', 'as' => 'reports.month'])->where(
['year' => '[0-9]{4}', 'month' => '[0-9]{1,2}', 'shared' => 'shared']
);
// pop ups for budget report:
/** /**
* Search Controller * Search Controller

View File

@@ -1,20 +1,23 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Crypt; use Crypt;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
/** /**
* Class Account * FireflyIII\Models\Account
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property \Carbon\Carbon $deleted_at * @property Carbon $deleted_at
* @property integer $user_id * @property integer $user_id
* @property integer $account_type_id * @property integer $account_type_id
* @property string $name * @property string $name
@@ -22,32 +25,14 @@ use Watson\Validating\ValidatingTrait;
* @property boolean $encrypted * @property boolean $encrypted
* @property float $virtual_balance * @property float $virtual_balance
* @property string $iban * @property string $iban
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\AccountMeta[] $accountMeta * @property-read Collection|AccountMeta[] $accountMeta
* @property-read \FireflyIII\Models\AccountType $accountType * @property-read AccountType $accountType
* @property-read mixed $name_for_editform * @property-read mixed $name_for_editform
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBank[] $piggyBanks * @property-read Collection|PiggyBank[] $piggyBanks
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Transaction[] $transactions * @property-read Collection|Transaction[] $transactions
* @property-read \FireflyIII\User $user * @property-read User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereId($value) * @method static Builder|Account accountTypeIn($types)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account whereCreatedAt($value) * @method static Builder|Account hasMetaValue($name, $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 whereIban($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account accountTypeIn($types)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Account hasMetaValue($name, $value)
* @property-read bool $joinedAccountTypes
* @property float $startBalance
* @property float $endBalance
* @property float $piggyBalance
* @property float $percentage
* @property float $difference
* @property \Carbon\Carbon $lastActivityDate
*/ */
class Account extends Model class Account extends Model
{ {
@@ -65,7 +50,6 @@ class Account extends Model
/** /**
* @param array $fields * @param array $fields
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* *
* @return Account|null * @return Account|null
*/ */

View File

@@ -1,25 +1,19 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
/** /**
* Class AccountMeta * FireflyIII\Models\AccountMeta
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property integer $account_id * @property integer $account_id
* @property string $name * @property string $name
* @property string $data * @property string $data
* @property-read \FireflyIII\Models\Account $account * @property-read 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
{ {

View File

@@ -1,22 +1,18 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
* Class AccountType * FireflyIII\Models\AccountType
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property string $type * @property string $type
* @property boolean $editable * @property boolean $editable
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Account[] $accounts * @property-read Collection|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
{ {
@@ -33,6 +29,7 @@ class AccountType extends Model
/** /**
* @return array * @return array
*/ */
/** @noinspection PhpMissingParentCallCommonInspection */
public function getDates() public function getDates()
{ {
return ['created_at', 'updated_at']; return ['created_at', 'updated_at'];

View File

@@ -2,46 +2,32 @@
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Carbon\Carbon;
use Crypt; use Crypt;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* Class Attachment * FireflyIII\Models\Attachment
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property string $deleted_at * @property string $deleted_at
* @property integer $attachable_id * @property integer $attachable_id
* @property string $attachable_type * @property string $attachable_type
* @property integer $user_id * @property integer $user_id
* @property string $md5 * @property string $md5
* @property string $filename * @property string $filename
* @property string $mime
* @property integer $size
* @property boolean $uploaded
* @property-read \ $attachable
* @property-read \FireflyIII\User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereUpdatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereDeletedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereAttachableId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereAttachableType($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereMd5($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereFilename($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereMime($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereSize($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereUploaded($value)
* @property string $title * @property string $title
* @property string $description * @property string $description
* @property string $notes * @property string $notes
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereTitle($value) * @property string $mime
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereDescription($value) * @property integer $size
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Attachment whereNotes($value) * @property boolean $uploaded
* @property-read Attachment $attachable
* @property-read User $user
*/ */
class Attachment extends Model class Attachment extends Model
{ {

View File

@@ -1,46 +1,31 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Crypt; use Crypt;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
* Class Bill * FireflyIII\Models\Bill
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property integer $user_id * @property integer $user_id
* @property string $name * @property string $name
* @property string $match * @property string $match
* @property float $amount_min * @property float $amount_min
* @property float $amount_max * @property float $amount_max
* @property \Carbon\Carbon $date * @property Carbon $date
* @property boolean $active * @property boolean $active
* @property boolean $automatch * @property boolean $automatch
* @property string $repeat_freq * @property string $repeat_freq
* @property integer $skip * @property integer $skip
* @property boolean $name_encrypted * @property boolean $name_encrypted
* @property boolean $match_encrypted * @property boolean $match_encrypted
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals * @property-read Collection|TransactionJournal[] $transactionjournals
* @property-read \FireflyIII\User $user * @property-read 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 whereAmountMax($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 \Carbon\Carbon $nextExpectedMatch
* @property \Carbon\Carbon $lastFoundMatch
*/ */
class Bill extends Model class Bill extends Model
{ {

View File

@@ -1,32 +1,26 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Crypt; use Crypt;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* Class Budget * FireflyIII\Models\Budget
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property \Carbon\Carbon $deleted_at * @property Carbon $deleted_at
* @property string $name * @property string $name
* @property integer $user_id * @property integer $user_id
* @property boolean $active * @property boolean $active
* @property boolean $encrypted * @property boolean $encrypted
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\BudgetLimit[] $budgetlimits * @property-read Collection|BudgetLimit[] $budgetlimits
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals * @property-read Collection|TransactionJournal[] $transactionjournals
* @property-read \FireflyIII\User $user * @property-read 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
{ {
@@ -78,7 +72,7 @@ class Budget extends Model
*/ */
public function getDates() public function getDates()
{ {
return ['created_at', 'updated_at', 'deleted_at']; return ['created_at', 'updated_at', 'deleted_at', 'startdate', 'enddate'];
} }
/** /**

View File

@@ -1,29 +1,22 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
* Class BudgetLimit * FireflyIII\Models\BudgetLimit
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property integer $budget_id * @property integer $budget_id
* @property \Carbon\Carbon $startdate * @property Carbon $startdate
* @property float $amount * @property float $amount
* @property boolean $repeats * @property boolean $repeats
* @property string $repeat_freq * @property string $repeat_freq
* @property-read \FireflyIII\Models\Budget $budget * @property-read Budget $budget
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\LimitRepetition[] $limitrepetitions * @property-read Collection|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 whereRepeats($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\BudgetLimit whereRepeatFreq($value)
*/ */
class BudgetLimit extends Model class BudgetLimit extends Model
{ {

View File

@@ -1,31 +1,24 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Crypt; use Crypt;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* Class Category * FireflyIII\Models\Category
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property \Carbon\Carbon $deleted_at * @property Carbon $deleted_at
* @property string $name * @property string $name
* @property integer $user_id * @property integer $user_id
* @property boolean $encrypted * @property boolean $encrypted
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals * @property-read Collection|TransactionJournal[] $transactionjournals
* @property-read \FireflyIII\User $user * @property-read 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-read float $spent
* @property \Carbon\Carbon $lastActivity
*/ */
class Category extends Model class Category extends Model
{ {
@@ -36,7 +29,6 @@ class Category extends Model
/** /**
* @param array $fields * @param array $fields
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* *
* @return Category * @return Category
*/ */

View File

@@ -1,26 +1,19 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* Class Component * FireflyIII\Models\Component
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property \Carbon\Carbon $deleted_at * @property Carbon $deleted_at
* @property string $name * @property string $name
* @property integer $user_id * @property integer $user_id
* @property string $class * @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,26 +1,19 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
* Class LimitRepetition * FireflyIII\Models\LimitRepetition
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property integer $budget_limit_id * @property integer $budget_limit_id
* @property \Carbon\Carbon $startdate * @property Carbon $startdate
* @property \Carbon\Carbon $enddate * @property Carbon $enddate
* @property float $amount * @property float $amount
* @property-read \FireflyIII\Models\BudgetLimit $budgetLimit * @property-read 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)
*/ */
class LimitRepetition extends Model class LimitRepetition extends Model
{ {

View File

@@ -2,25 +2,20 @@
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Zizaco\Entrust\EntrustPermission; use Zizaco\Entrust\EntrustPermission;
/** /**
* Class Permission * FireflyIII\Models\Permission
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property string $name * @property string $name
* @property string $display_name * @property string $display_name
* @property string $description * @property string $description
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property-read \Illuminate\Database\Eloquent\Collection|\Config::get('entrust.role[] $roles * @property-read Collection|Role[] $roles
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Permission whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Permission whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Permission whereDisplayName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Permission whereDescription($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Permission whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Permission whereUpdatedAt($value)
*/ */
class Permission extends EntrustPermission class Permission extends EntrustPermission
{ {

View File

@@ -1,45 +1,30 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Crypt; use Crypt;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* Class PiggyBank * FireflyIII\Models\PiggyBank
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property \Carbon\Carbon $deleted_at * @property Carbon $deleted_at
* @property integer $account_id * @property integer $account_id
* @property string $name * @property string $name
* @property float $targetamount * @property float $targetamount
* @property \Carbon\Carbon $startdate * @property Carbon $startdate
* @property \Carbon\Carbon $targetdate * @property Carbon $targetdate
* @property integer $order * @property integer $order
* @property boolean $encrypted * @property boolean $encrypted
* @property boolean $remind_me * @property boolean $remind_me
* @property integer $reminder_skip * @property integer $reminder_skip
* @property-read \FireflyIII\Models\Account $account * @property-read Account $account
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBankRepetition[] $piggyBankRepetitions * @property-read Collection|PiggyBankRepetition[] $piggyBankRepetitions
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBankEvent[] $piggyBankEvents * @property-read Collection|PiggyBankEvent[] $piggyBankEvents
* @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 whereStartdate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereTargetdate($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereOrder($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereEncrypted($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereRemindMe($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereReminderSkip($value)
* @property-read \FireflyIII\Models\PiggyBankRepetition $currentRep
* @property string $reminder
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBank whereReminder($value)
*/ */
class PiggyBank extends Model class PiggyBank extends Model
{ {

View File

@@ -1,27 +1,20 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
* Class PiggyBankEvent * FireflyIII\Models\PiggyBankEvent
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property integer $piggy_bank_id * @property integer $piggy_bank_id
* @property integer $transaction_journal_id * @property integer $transaction_journal_id
* @property \Carbon\Carbon $date * @property Carbon $date
* @property float $amount * @property float $amount
* @property-read \FireflyIII\Models\PiggyBank $piggyBank * @property PiggyBank $piggyBank
* @property-read \FireflyIII\Models\TransactionJournal $transactionJournal * @property-read 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)
*/ */
class PiggyBankEvent extends Model class PiggyBankEvent extends Model
{ {
@@ -32,6 +25,7 @@ class PiggyBankEvent extends Model
/** /**
* @return array * @return array
*/ */
/** @noinspection PhpMissingParentCallCommonInspection */
public function getDates() public function getDates()
{ {
return ['created_at', 'updated_at', 'date']; return ['created_at', 'updated_at', 'date'];

View File

@@ -3,28 +3,21 @@
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Query\Builder;
/** /**
* Class PiggyBankRepetition * FireflyIII\Models\PiggyBankRepetition
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property integer $piggy_bank_id * @property integer $piggy_bank_id
* @property \Carbon\Carbon $startdate * @property Carbon $startdate
* @property \Carbon\Carbon $targetdate * @property Carbon $targetdate
* @property float $currentamount * @property float $currentamount
* @property-read \FireflyIII\Models\PiggyBank $piggyBank * @property-read PiggyBank $piggyBank
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition whereId($value) * @method static Builder|PiggyBankRepetition onDates($start, $target)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition whereCreatedAt($value) * @method static Builder|PiggyBankRepetition relevantOnDate($date)
* @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 onDates($start, $target)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\PiggyBankRepetition relevantOnDate($date)
*/ */
class PiggyBankRepetition extends Model class PiggyBankRepetition extends Model
{ {

View File

@@ -1,29 +1,22 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Crypt; use Crypt;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
/** /**
* Class Preference * FireflyIII\Models\Preference
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property integer $user_id * @property integer $user_id
* @property string $name * @property string $name
* @property string $name_encrypted * @property string $name_encrypted
* @property string $data * @property string $data
* @property string $data_encrypted * @property string $data_encrypted
* @property-read \FireflyIII\User $user * @property-read 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
{ {

View File

@@ -2,26 +2,21 @@
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Zizaco\Entrust\EntrustRole; use Zizaco\Entrust\EntrustRole;
/** /**
* Class Role * FireflyIII\Models\Role
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property string $name * @property string $name
* @property string $display_name * @property string $display_name
* @property string $description * @property string $description
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property-read \Illuminate\Database\Eloquent\Collection|\Config::get('auth.model[] $users * @property-read Collection|\FireflyIII\User[] $users
* @property-read \Illuminate\Database\Eloquent\Collection|\Config::get('entrust.permission[] $perms * @property-read Collection|Permission[] $perms
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Role whereId($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Role whereName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Role whereDisplayName($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Role whereDescription($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Role whereCreatedAt($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Role whereUpdatedAt($value)
*/ */
class Role extends EntrustRole class Role extends EntrustRole
{ {

View File

@@ -2,40 +2,30 @@
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Carbon\Carbon;
use Crypt; use Crypt;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
/** /**
* Class Tag * FireflyIII\Models\Tag
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property string $deleted_at * @property string $deleted_at
* @property integer $user_id * @property integer $user_id
* @property string $tag * @property string $tag
* @property string $tagMode * @property string $tagMode
* @property \Carbon\Carbon $date * @property Carbon $date
* @property string $description * @property string $description
* @property float $latitude * @property float $latitude
* @property float $longitude * @property float $longitude
* @property integer $zoomLevel * @property integer $zoomLevel
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals * @property-read Collection|TransactionJournal[] $transactionjournals
* @property-read \FireflyIII\User $user * @property-read 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
{ {
@@ -54,8 +44,6 @@ class Tag extends Model
/** /**
* @param array $fields * @param array $fields
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* *
* @return Tag|null * @return Tag|null
*/ */

View File

@@ -4,34 +4,24 @@ use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
/** /**
* Class Transaction * FireflyIII\Models\Transaction
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property \Carbon\Carbon $deleted_at * @property Carbon $deleted_at
* @property integer $account_id * @property integer $account_id
* @property integer $transaction_journal_id * @property integer $transaction_journal_id
* @property string $description * @property string $description
* @property float $amount * @property float $amount
* @property-read \FireflyIII\Models\Account $account * @property-read Account $account
* @property-read \FireflyIII\Models\TransactionJournal $transactionJournal * @property-read TransactionJournal $transactionJournal
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereId($value) * @method static Builder|Transaction after($date)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction whereCreatedAt($value) * @method static Builder|Transaction before($date)
* @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 after($date)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\Transaction before($date)
* @property float $before
* @property float $after
*/ */
class Transaction extends Model class Transaction extends Model
{ {

View File

@@ -1,27 +1,21 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* Class TransactionCurrency * FireflyIII\Models\TransactionCurrency
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property \Carbon\Carbon $deleted_at * @property Carbon $deleted_at
* @property string $code * @property string $code
* @property string $name * @property string $name
* @property string $symbol * @property string $symbol
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionJournals * @property-read Collection|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

@@ -1,26 +1,22 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* Class TransactionGroup * FireflyIII\Models\TransactionGroup
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property \Carbon\Carbon $deleted_at * @property Carbon $deleted_at
* @property integer $user_id * @property integer $user_id
* @property string $relation * @property string $relation
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionjournals * @property-read Collection|TransactionJournal[] $transactionjournals
* @property-read \FireflyIII\User $user * @property-read 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

@@ -3,73 +3,53 @@
use Carbon\Carbon; use Carbon\Carbon;
use Crypt; use Crypt;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
/** /**
* Class TransactionJournal * FireflyIII\Models\TransactionJournal
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property \Carbon\Carbon $deleted_at * @property Carbon $deleted_at
* @property integer $user_id * @property integer $user_id
* @property integer $transaction_type_id * @property integer $transaction_type_id
* @property integer $bill_id * @property integer $bill_id
* @property integer $transaction_currency_id * @property integer $transaction_currency_id
* @property string $description * @property string $description
* @property boolean $completed * @property boolean $completed
* @property \Carbon\Carbon $date * @property Carbon $date
* @property boolean $encrypted * @property boolean $encrypted
* @property integer $order * @property integer $order
* @property integer $tag_count * @property integer $tag_count
* @property-read \FireflyIII\Models\Bill $bill * @property-read Bill $bill
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Budget[] $budgets * @property-read Collection|Budget[] $budgets
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Category[] $categories * @property-read Collection|Category[] $categories
* @property-read mixed $actual_amount * @property-read mixed $amount_positive
* @property-read mixed $amount * @property-read mixed $amount
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Tag[] $tags * @property-read Collection|Tag[] $tags
* @property-read mixed $correct_amount * @property-read Collection|Transaction[] $transactions
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Transaction[] $transactions
* @property-read mixed $destination_account * @property-read mixed $destination_account
* @property-read mixed $source_account * @property-read mixed $source_account
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBankEvent[] $piggyBankEvents * @property-read Collection|PiggyBankEvent[] $piggyBankEvents
* @property-read \FireflyIII\Models\TransactionCurrency $transactionCurrency * @property-read Collection|Attachment[] $attachments
* @property-read \FireflyIII\Models\TransactionType $transactionType * @property-read TransactionCurrency $transactionCurrency
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionGroup[] $transactiongroups * @property-read TransactionType $transactionType
* @property-read \FireflyIII\User $user * @property-read Collection|TransactionGroup[] $transactiongroups
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereId($value) * @property-read User $user
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereCreatedAt($value) * @method static Builder|TransactionJournal accountIs($account)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereUpdatedAt($value) * @method static Builder|TransactionJournal after($date)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereDeletedAt($value) * @method static Builder|TransactionJournal before($date)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereUserId($value) * @method static Builder|TransactionJournal onDate($date)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereTransactionTypeId($value) * @method static Builder|TransactionJournal transactionTypes($types)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereBillId($value) * @method static Builder|TransactionJournal withRelevantData()
* @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 \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal whereTagCount($value)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal accountIs($account)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal after($date)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal before($date)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal onDate($date)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal transactionTypes($types)
* @method static \Illuminate\Database\Query\Builder|\FireflyIII\Models\TransactionJournal withRelevantData()
* @property-read bool $account_encrypted
* @property-read bool $joinedTransactions
* @property-read bool $joinedTransactionTypes
* @property-read int $account_id
* @property string $name
* @property-read string $symbol
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\Attachment[] $attachments
* @property-read mixed $amount_positive
*/ */
class TransactionJournal extends Model class TransactionJournal extends Model
{ {
@@ -147,10 +127,9 @@ class TransactionJournal extends Model
} }
bcscale(2); bcscale(2);
$type = $this->transactionType->type;
$transaction = $this->transactions->sortByDesc('amount')->first(); $transaction = $this->transactions->sortByDesc('amount')->first();
$amount = $transaction->amount; $amount = $transaction->amount;
if ($type == 'Withdrawal') { if ($this->isWithdrawal()) {
$amount = $amount * -1; $amount = $amount * -1;
} }
$cache->store($amount); $cache->store($amount);
@@ -167,15 +146,15 @@ class TransactionJournal extends Model
*/ */
protected function amountByTagAdvancePayment(Tag $tag, $amount) protected function amountByTagAdvancePayment(Tag $tag, $amount)
{ {
if ($this->transactionType->type == 'Withdrawal') { if ($this->isWithdrawal()) {
$others = $tag->transactionJournals()->transactionTypes(['Deposit'])->get(); $others = $tag->transactionJournals()->transactionTypes([TransactionType::DEPOSIT])->get();
foreach ($others as $other) { foreach ($others as $other) {
$amount = bcsub($amount, $other->amount_positive); $amount = bcsub($amount, $other->amount_positive);
} }
return $amount; return $amount;
} }
if ($this->transactionType->type == 'Deposit') { if ($this->isDeposit()) {
return '0'; return '0';
} }
@@ -190,8 +169,8 @@ class TransactionJournal extends Model
*/ */
protected function amountByTagBalancingAct($tag, $amount) protected function amountByTagBalancingAct($tag, $amount)
{ {
if ($this->transactionType->type == 'Withdrawal') { if ($this->isWithdrawal()) {
$transfer = $tag->transactionJournals()->transactionTypes(['Transfer'])->first(); $transfer = $tag->transactionJournals()->transactionTypes([TransactionType::TRANSFER])->first();
if ($transfer) { if ($transfer) {
$amount = bcsub($amount, $transfer->amount_positive); $amount = bcsub($amount, $transfer->amount_positive);
@@ -491,4 +470,59 @@ class TransactionJournal extends Model
return $this->belongsTo('FireflyIII\User'); return $this->belongsTo('FireflyIII\User');
} }
/**
* @return string
*/
public function getTransactionType()
{
return $this->transactionType->type;
}
/**
* @return bool
*/
public function isWithdrawal()
{
if (!is_null($this->type)) {
return $this->type == TransactionType::WITHDRAWAL;
}
return $this->transactionType->isWithdrawal();
}
/**
* @return bool
*/
public function isDeposit()
{
if (!is_null($this->type)) {
return $this->type == TransactionType::DEPOSIT;
}
return $this->transactionType->isDeposit();
}
/**
* @return bool
*/
public function isTransfer()
{
if (!is_null($this->type)) {
return $this->type == TransactionType::TRANSFER;
}
return $this->transactionType->isTransfer();
}
/**
* @return bool
*/
public function isOpeningBalance()
{
if (!is_null($this->type)) {
return $this->type == TransactionType::OPENING_BALANCE;
}
return $this->transactionType->isOpeningBalance();
}
} }

View File

@@ -1,21 +0,0 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* Class TransactionRelation
*
* @package FireflyIII\Models
*/
class TransactionRelation extends Model
{
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at'];
}
}

View File

@@ -1,28 +1,29 @@
<?php namespace FireflyIII\Models; <?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
/** /**
* Class TransactionType * FireflyIII\Models\TransactionType
* *
* @package FireflyIII\Models
* @property integer $id * @property integer $id
* @property \Carbon\Carbon $created_at * @property Carbon $created_at
* @property \Carbon\Carbon $updated_at * @property Carbon $updated_at
* @property \Carbon\Carbon $deleted_at * @property Carbon $deleted_at
* @property string $type * @property string $type
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\TransactionJournal[] $transactionJournals * @property-read Collection|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
{ {
use SoftDeletes; use SoftDeletes;
const WITHDRAWAL = 'Withdrawal';
const DEPOSIT = 'Deposit';
const TRANSFER = 'Transfer';
const OPENING_BALANCE = 'Opening balance';
/** /**
* @return array * @return array
*/ */
@@ -31,6 +32,38 @@ class TransactionType extends Model
return ['created_at', 'updated_at', 'deleted_at']; return ['created_at', 'updated_at', 'deleted_at'];
} }
/**
* @return bool
*/
public function isDeposit()
{
return $this->type === TransactionType::DEPOSIT;
}
/**
* @return bool
*/
public function isOpeningBalance()
{
return $this->type === TransactionType::OPENING_BALANCE;
}
/**
* @return bool
*/
public function isTransfer()
{
return $this->type === TransactionType::TRANSFER;
}
/**
* @return bool
*/
public function isWithdrawal()
{
return $this->type === TransactionType::WITHDRAWAL;
}
/** /**
* @return \Illuminate\Database\Eloquent\Relations\HasMany * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/ */

View File

@@ -19,7 +19,6 @@ 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
*/ */

View File

@@ -47,7 +47,7 @@ class FireflyServiceProvider extends ServiceProvider
} }
/** /**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength) *
*/ */
public function register() public function register()
{ {
@@ -83,6 +83,7 @@ class FireflyServiceProvider extends ServiceProvider
$this->app->bind('FireflyIII\Repositories\Account\AccountRepositoryInterface', 'FireflyIII\Repositories\Account\AccountRepository'); $this->app->bind('FireflyIII\Repositories\Account\AccountRepositoryInterface', 'FireflyIII\Repositories\Account\AccountRepository');
$this->app->bind('FireflyIII\Repositories\Budget\BudgetRepositoryInterface', 'FireflyIII\Repositories\Budget\BudgetRepository'); $this->app->bind('FireflyIII\Repositories\Budget\BudgetRepositoryInterface', 'FireflyIII\Repositories\Budget\BudgetRepository');
$this->app->bind('FireflyIII\Repositories\Category\CategoryRepositoryInterface', 'FireflyIII\Repositories\Category\CategoryRepository'); $this->app->bind('FireflyIII\Repositories\Category\CategoryRepositoryInterface', 'FireflyIII\Repositories\Category\CategoryRepository');
$this->app->bind('FireflyIII\Repositories\Category\SingleCategoryRepositoryInterface', 'FireflyIII\Repositories\Category\SingleCategoryRepository');
$this->app->bind('FireflyIII\Repositories\Journal\JournalRepositoryInterface', 'FireflyIII\Repositories\Journal\JournalRepository'); $this->app->bind('FireflyIII\Repositories\Journal\JournalRepositoryInterface', 'FireflyIII\Repositories\Journal\JournalRepository');
$this->app->bind('FireflyIII\Repositories\Bill\BillRepositoryInterface', 'FireflyIII\Repositories\Bill\BillRepository'); $this->app->bind('FireflyIII\Repositories\Bill\BillRepositoryInterface', 'FireflyIII\Repositories\Bill\BillRepository');
$this->app->bind('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface', 'FireflyIII\Repositories\PiggyBank\PiggyBankRepository'); $this->app->bind('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface', 'FireflyIII\Repositories\PiggyBank\PiggyBankRepository');

View File

@@ -39,6 +39,8 @@ class RouteServiceProvider extends ServiceProvider
* *
* @param \Illuminate\Routing\Router $router * @param \Illuminate\Routing\Router $router
* *
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @return void * @return void
*/ */
public function map(Router $router) public function map(Router $router)

View File

@@ -14,9 +14,7 @@ use FireflyIII\Models\Preference;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Support\CacheProperties;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Query\Builder;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Log; use Log;
@@ -25,7 +23,6 @@ use Steam;
/** /**
* @SuppressWarnings(PHPMD.TooManyMethods)
* *
* Class AccountRepository * Class AccountRepository
* *
@@ -41,7 +38,9 @@ class AccountRepository implements AccountRepositoryInterface
*/ */
public function countAccounts(array $types) public function countAccounts(array $types)
{ {
return Auth::user()->accounts()->accountTypeIn($types)->count(); $count = Auth::user()->accounts()->accountTypeIn($types)->count();
return $count;
} }
/** /**
@@ -81,26 +80,40 @@ class AccountRepository implements AccountRepositoryInterface
return strtolower($account->name); return strtolower($account->name);
} }
); );
return $result; return $result;
} }
/** /**
* This method returns the users credit cards, along with some basic information about the
* balance they have on their CC. To be used in the JSON boxes on the front page that say
* how many bills there are still left to pay. The balance will be saved in field "balance".
*
* To get the balance, the field "date" is necessary.
*
* @param Carbon $date
*
* @return Collection * @return Collection
*/ */
public function getCreditCards() public function getCreditCards(Carbon $date)
{ {
return Auth::user()->accounts() $set = Auth::user()->accounts()
->hasMetaValue('accountRole', 'ccAsset') ->hasMetaValue('accountRole', 'ccAsset')
->hasMetaValue('ccType', 'monthlyFull') ->hasMetaValue('ccType', 'monthlyFull')
->leftJoin('transactions', 'transactions.account_id', '=', 'accounts.id')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->whereNull('transactions.deleted_at')
->where('transaction_journals.date', '<=', $date->format('Y-m-d'))
->groupBy('accounts.id')
->get( ->get(
[ [
'accounts.*', 'accounts.*',
'ccType.data as ccType', 'ccType.data as ccType',
'accountRole.data as accountRole' 'accountRole.data as accountRole',
DB::Raw('SUM(`transactions`.`amount`) AS `balance`')
] ]
); );
return $set;
} }
/** /**
@@ -111,8 +124,9 @@ class AccountRepository implements AccountRepositoryInterface
*/ */
public function getFirstTransaction(TransactionJournal $journal, Account $account) public function getFirstTransaction(TransactionJournal $journal, Account $account)
{ {
$transaction = $journal->transactions()->where('account_id', $account->id)->first();
return $journal->transactions()->where('account_id', $account->id)->first(); return $transaction;
} }
/** /**
@@ -122,12 +136,6 @@ class AccountRepository implements AccountRepositoryInterface
*/ */
public function getFrontpageAccounts(Preference $preference) public function getFrontpageAccounts(Preference $preference)
{ {
$cache = new CacheProperties();
$cache->addProperty($preference->data);
$cache->addProperty('frontPageaccounts');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$query = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account']); $query = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account']);
if (count($preference->data) > 0) { if (count($preference->data) > 0) {
@@ -135,9 +143,6 @@ class AccountRepository implements AccountRepositoryInterface
} }
$result = $query->get(['accounts.*']); $result = $query->get(['accounts.*']);
$cache->store($result);
return $result; return $result;
} }
@@ -154,14 +159,6 @@ class AccountRepository implements AccountRepositoryInterface
*/ */
public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end) public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end)
{ {
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty($start);
$cache->addProperty($end);
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$set = Auth::user() $set = Auth::user()
->transactionjournals() ->transactionjournals()
->with(['transactions']) ->with(['transactions'])
@@ -172,11 +169,10 @@ class AccountRepository implements AccountRepositoryInterface
->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.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']);
$cache->store($set);
return $set; return $set;
} }
@@ -214,27 +210,15 @@ class AccountRepository implements AccountRepositoryInterface
*/ */
public function getPiggyBankAccounts() public function getPiggyBankAccounts()
{ {
$ids = [];
$start = clone Session::get('start', new Carbon); $start = clone Session::get('start', new Carbon);
$end = clone Session::get('end', new Carbon); $end = clone Session::get('end', new Carbon);
$accountIds = DB::table('piggy_banks')->distinct()->get(['piggy_banks.account_id']); $collection = new Collection(DB::table('piggy_banks')->distinct()->get(['piggy_banks.account_id']));
$ids = $collection->pluck('account_id')->toArray();
$accounts = new Collection; $accounts = new Collection;
/** @var PiggyBank $id */
foreach ($accountIds as $id) {
$ids[] = intval($id->account_id);
}
$cache = new CacheProperties;
$cache->addProperty($ids);
$cache->addProperty('piggyAccounts');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$ids = array_unique($ids); $ids = array_unique($ids);
if (count($ids) > 0) { if (count($ids) > 0) {
$accounts = Auth::user()->accounts()->whereIn('id', $ids)->get(); $accounts = Auth::user()->accounts()->whereIn('id', $ids)->where('accounts.active', 1)->get();
} }
bcscale(2); bcscale(2);
@@ -257,8 +241,6 @@ class AccountRepository implements AccountRepositoryInterface
} }
); );
$cache->store($accounts);
return $accounts; return $accounts;
} }
@@ -273,6 +255,7 @@ class AccountRepository implements AccountRepositoryInterface
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC') $accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id') ->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
->where('account_meta.name', 'accountRole') ->where('account_meta.name', 'accountRole')
->where('accounts.active', 1)
->where('account_meta.data', '"savingAsset"') ->where('account_meta.data', '"savingAsset"')
->get(['accounts.*']); ->get(['accounts.*']);
$start = clone Session::get('start', new Carbon); $start = clone Session::get('start', new Carbon);
@@ -308,44 +291,6 @@ class AccountRepository implements AccountRepositoryInterface
return $accounts; return $accounts;
} }
/**
* Get all transfers TO this account in this range.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getTransfersInRange(Account $account, Carbon $start, Carbon $end)
{
$set = TransactionJournal::whereIn(
'id', function (Builder $q) use ($account, $start, $end) {
$q->select('transaction_journals.id')
->from('transactions')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->where('transactions.account_id', $account->id)
->where('transaction_journals.user_id', Auth::user()->id)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_types.type', 'Transfer');
}
)->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 * @param Carbon $date
@@ -372,12 +317,14 @@ class AccountRepository implements AccountRepositoryInterface
*/ */
public function openingBalanceTransaction(Account $account) public function openingBalanceTransaction(Account $account)
{ {
return TransactionJournal $journal = TransactionJournal
::orderBy('transaction_journals.date', 'ASC') ::orderBy('transaction_journals.date', 'ASC')
->accountIs($account) ->accountIs($account)
->transactionTypes(['Opening balance']) ->transactionTypes([TransactionType::OPENING_BALANCE])
->orderBy('created_at', 'ASC') ->orderBy('created_at', 'ASC')
->first(['transaction_journals.*']); ->first(['transaction_journals.*']);
return $journal;
} }
/** /**
@@ -548,7 +495,7 @@ class AccountRepository implements AccountRepositoryInterface
*/ */
protected function storeInitialBalance(Account $account, Account $opposing, array $data) protected function storeInitialBalance(Account $account, Account $opposing, array $data)
{ {
$transactionType = TransactionType::whereType('Opening balance')->first(); $transactionType = TransactionType::whereType(TransactionType::OPENING_BALANCE)->first();
$journal = TransactionJournal::create( $journal = TransactionJournal::create(
[ [
'user_id' => $data['user'], 'user_id' => $data['user'],
@@ -588,7 +535,6 @@ class AccountRepository implements AccountRepositoryInterface
* @param Account $account * @param Account $account
* @param array $data * @param array $data
* *
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/ */
protected function updateMetadata(Account $account, array $data) protected function updateMetadata(Account $account, array $data)
{ {
@@ -642,4 +588,16 @@ class AccountRepository implements AccountRepositoryInterface
return $journal; return $journal;
} }
/**
* @deprecated
*
* @param $accountId
*
* @return Account
*/
public function find($accountId)
{
return Auth::user()->accounts()->findOrNew($accountId);
}
} }

View File

@@ -24,6 +24,15 @@ interface AccountRepositoryInterface
*/ */
public function countAccounts(array $types); public function countAccounts(array $types);
/**
* @param $accountId
*
* @deprecated
*
* @return Account
*/
public function find($accountId);
/** /**
* @param Account $account * @param Account $account
* @param Account $moveTo * @param Account $moveTo
@@ -35,7 +44,7 @@ interface AccountRepositoryInterface
/** /**
* @param array $types * @param array $types
* *
* @return mixed * @return Collection
*/ */
public function getAccounts(array $types); public function getAccounts(array $types);
@@ -48,9 +57,17 @@ interface AccountRepositoryInterface
public function getFirstTransaction(TransactionJournal $journal, Account $account); public function getFirstTransaction(TransactionJournal $journal, Account $account);
/** /**
* This method returns the users credit cards, along with some basic information about the
* balance they have on their CC. To be used in the JSON boxes on the front page that say
* how many bills there are still left to pay. The balance will be saved in field "balance".
*
* To get the balance, the field "date" is necessary.
*
* @param Carbon $date
*
* @return Collection * @return Collection
*/ */
public function getCreditCards(); public function getCreditCards(Carbon $date);
/** /**
* Get the accounts of a user that have piggy banks connected to them. * Get the accounts of a user that have piggy banks connected to them.
@@ -59,18 +76,6 @@ interface AccountRepositoryInterface
*/ */
public function getPiggyBankAccounts(); public function getPiggyBankAccounts();
/**
* Get all transfers TO this account in this range.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getTransfersInRange(Account $account, Carbon $start, Carbon $end);
/** /**
* @param Preference $preference * @param Preference $preference
* *

View File

@@ -5,13 +5,16 @@ 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\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Log; use Log;
use Navigation; use Navigation;
use Steam;
/** /**
* Class BillRepository * Class BillRepository
@@ -20,52 +23,6 @@ use Steam;
*/ */
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.
*
* @param string $description
* @param Carbon $date
* @param float $amount
*
* @return Bill
*/
public function createFakeBill($description, Carbon $date, $amount)
{
$bill = new Bill;
$bill->name = $description;
$bill->match = $description;
$bill->amount_min = $amount;
$bill->amount_max = $amount;
$bill->date = $date;
$bill->repeat_freq = 'monthly';
$bill->skip = 0;
$bill->automatch = false;
$bill->active = false;
return $bill;
}
/** /**
* @param Bill $bill * @param Bill $bill
@@ -78,16 +35,40 @@ class BillRepository implements BillRepositoryInterface
} }
/** /**
* Returns all journals connected to these bills in the given range. Amount paid
* is stored in "journalAmount" as a negative number.
*
* @param Collection $bills
* @param Carbon $start
* @param Carbon $end
*
* @return Collection * @return Collection
*/ */
public function getActiveBills() public function getAllJournalsInRange(Collection $bills, Carbon $start, Carbon $end)
{ {
/** @var Collection $set */ $ids = $bills->pluck('id')->toArray();
$set = Auth::user()->bills()->orderBy('name', 'ASC')->where('active', 1)->get()->sortBy('name');
$set = Auth::user()->transactionjournals()
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0);
}
)
->whereIn('bill_id', $ids)
->before($end)
->after($start)
->groupBy('transaction_journals.bill_id')
->get(
[
'transaction_journals.bill_id',
DB::Raw('SUM(`transactions`.`amount`) as `journalAmount`')
]
);
return $set; return $set;
} }
/** /**
* @return Collection * @return Collection
*/ */
@@ -109,22 +90,70 @@ class BillRepository implements BillRepositoryInterface
} }
/** /**
* @param Collection $accounts
*
* @return Collection
*/
public function getBillsForAccounts(Collection $accounts)
{
$ids = $accounts->pluck('id')->toArray();
$set = Auth::user()->bills()
->leftJoin(
'transaction_journals', function (JoinClause $join) {
$join->on('transaction_journals.bill_id', '=', 'bills.id')->whereNull('transaction_journals.deleted_at');
}
)
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
}
)
->whereIn('transactions.account_id', $ids)
->whereNull('transaction_journals.deleted_at')
->groupBy('bills.id')
->get(['bills.*']);
$set = $set->sortBy(
function (Bill $bill) {
$int = $bill->active == 1 ? 0 : 1;
return $int . strtolower($bill->name);
}
);
return $set;
}
/**
* This method also returns the amount of the journal in "journalAmount"
* for easy access.
*
* @param Bill $bill * @param Bill $bill
* *
* @return Collection * @return Collection
*/ */
public function getJournals(Bill $bill) public function getJournals(Bill $bill)
{ {
return $bill->transactionjournals()->withRelevantData() $set = $bill->transactionjournals()
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('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.*']); ->get(['transaction_journals.*', 'transactions.amount as journalAmount']);
return $set;
} }
/** /**
* Get all journals that were recorded on this bill between these dates. * Get all journals that were recorded on this bill between these dates.
* *
* @deprecated
*
* @param Bill $bill * @param Bill $bill
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
@@ -146,15 +175,11 @@ class BillRepository implements BillRepositoryInterface
$set = DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)->get( $set = DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)->get(
['transaction_journal_id'] ['transaction_journal_id']
); );
$ids = []; $ids = $set->pluck('transaction_journal_id')->toArray();
/** @var Transaction $entry */
foreach ($set as $entry) {
$ids[] = intval($entry->transaction_journal_id);
}
$journals = new Collection; $journals = new Collection;
if (count($ids) > 0) { if (count($ids) > 0) {
$journals = Auth::user()->transactionjournals()->transactionTypes(['Withdrawal'])->whereIn('transaction_journals.id', $ids)->get( $journals = Auth::user()->transactionjournals()->transactionTypes([TransactionType::WITHDRAWAL])->whereIn('transaction_journals.id', $ids)->get(
['transaction_journals.*'] ['transaction_journals.*']
); );
} }
@@ -276,12 +301,21 @@ class BillRepository implements BillRepositoryInterface
*/ */
public function scan(Bill $bill, TransactionJournal $journal) public function scan(Bill $bill, TransactionJournal $journal)
{ {
/*
* Can only support withdrawals.
*/
if (false === $journal->isWithdrawal()) {
return false;
}
$matches = explode(',', $bill->match); $matches = explode(',', $bill->match);
$description = strtolower($journal->description) . ' ' . strtolower($journal->destination_account->name); $description = strtolower($journal->description) . ' ' . strtolower($journal->destination_account->name);
$wordMatch = $this->doWordMatch($matches, $description); $wordMatch = $this->doWordMatch($matches, $description);
$amountMatch = $this->doAmountMatch($journal->amount_positive, $bill->amount_min, $bill->amount_max); $amountMatch = $this->doAmountMatch($journal->amount_positive, $bill->amount_min, $bill->amount_max);
Log::debug('Journal #' . $journal->id . ' has description "' . $description . '"'); Log::debug('Journal #' . $journal->id . ' has description "' . $description . '"');
/* /*
* If both, update! * If both, update!
*/ */
@@ -396,82 +430,141 @@ class BillRepository implements BillRepositoryInterface
} }
/** /**
* Gets a collection of paid bills and a collection of unpaid bills to be used * Get the total amount of money paid for the users active bills in the date range given.
* in the pie chart on the front page. * This amount will be negative (they're expenses).
* *
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @return Collection * @return string
*/ */
public function getBillsForChart(Carbon $start, Carbon $end) public function getBillsPaidInRange(Carbon $start, Carbon $end)
{ {
$paid = new Collection; $amount = '0';
$unpaid = new Collection;
$bills = $this->getActiveBills(); $bills = $this->getActiveBills();
/** @var Bill $bill */ /** @var Bill $bill */
foreach ($bills as $bill) { foreach ($bills as $bill) {
$ranges = $this->getRanges($bill, $start, $end); $ranges = $this->getRanges($bill, $start, $end);
foreach ($ranges as $range) { foreach ($ranges as $range) {
// paid a bill in this range? $paid = $bill->transactionjournals()
$journals = $this->getJournalsInRange($bill, $range['start'], $range['end']); ->before($range['end'])
if ($journals->count() == 0) { ->after($range['start'])
$unpaid->push([$bill, $range['start']]); ->leftJoin(
} else { 'transactions', function (JoinClause $join) {
$paid = $paid->merge($journals); $join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0);
} }
)
->first([DB::Raw('SUM(`transactions`.`amount`) as `sum_amount`')]);
$amount = bcadd($amount, $paid->sum_amount);
} }
} }
$set = new Collection; return $amount;
$set->put('paid', $paid);
$set->put('unpaid', $unpaid);
return $set;
} }
/** /**
* Takes the paid/unpaid bills collection set up before and expands it using
* credit cards the user might have.
*
* @param Collection $set
* @param Carbon $start
* @param Carbon $end
*
* @return Collection * @return Collection
*/ */
public function getCreditCardInfoForChart(Collection $set, Carbon $start, Carbon $end) public function getActiveBills()
{ {
/** @var Collection $set */
$accounts = app('FireflyIII\Repositories\Account\AccountRepositoryInterface'); $set = Auth::user()->bills()
$creditCards = $accounts->getCreditCards(); ->where('active', 1)
$paid = $set->get('paid'); ->get(
$unpaid = $set->get('unpaid'); [
'bills.*',
foreach ($creditCards as $creditCard) { DB::Raw('(`bills`.`amount_min` + `bills`.`amount_max` / 2) as `expectedAmount`')
$balance = Steam::balance($creditCard, $end, true); ]
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate')); )->sortBy('name');
if ($balance < 0) {
// unpaid! create a fake bill that matches the amount.
$description = $creditCard->name;
$amount = $balance * -1;
$fakeBill = $this->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);
}
}
$set = new Collection;
$set->put('paid', $paid);
$set->put('unpaid', $unpaid);
return $set; return $set;
} }
/**
* Get the total amount of money due for the users active bills in the date range given. This amount will be positive.
*
* @param Carbon $start
* @param Carbon $end
*
* @return string
*/
public function getBillsUnpaidInRange(Carbon $start, Carbon $end)
{
$amount = '0';
$bills = $this->getActiveBills();
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $this->getRanges($bill, $start, $end);
$paidBill = '0';
foreach ($ranges as $range) {
$paid = $bill->transactionjournals()
->before($range['end'])
->after($range['start'])
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '>', 0);
}
)
->first([DB::Raw('SUM(`transactions`.`amount`) as `sum_amount`')]);
$paidBill = bcadd($paid->sum_amount, $paidBill);
}
if ($paidBill == 0) {
$amount = bcadd($amount, $bill->expectedAmount);
}
}
return $amount;
}
/**
* This method will tell you if you still have a CC bill to pay. Amount will be positive if the amount
* has been paid, otherwise it will be negative.
*
* @param Carbon $start
* @param Carbon $end
*
* @return string
*/
public function getCreditCardBill(Carbon $start, Carbon $end)
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app('FireflyIII\Repositories\Account\AccountRepositoryInterface');
$amount = '0';
$creditCards = $accountRepository->getCreditCards($end); // Find credit card accounts and possibly unpaid credit card bills.
/** @var Account $creditCard */
foreach ($creditCards as $creditCard) {
if ($creditCard->balance == 0) {
// find a transfer TO the credit card which should account for
// anything paid. If not, the CC is not yet used.
$set = TransactionJournal::whereIn(
'transaction_journals.id', function (Builder $q) use ($creditCard, $start, $end) {
$q->select('transaction_journals.id')
->from('transactions')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->where('transactions.account_id', $creditCard->id)
->where('transactions.amount', '>', 0)// this makes the filter unnecessary.
->where('transaction_journals.user_id', Auth::user()->id)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_types.type', TransactionType::TRANSFER);
}
)->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '>', 0);
}
)->first([DB::Raw('SUM(`transactions`.`amount`) as `sum_amount`')]);
$amount = bcadd($amount, $set->sum_amount);
} else {
$amount = bcadd($amount, $creditCard->balance);
}
}
return $amount;
}
} }

View File

@@ -16,49 +16,41 @@ interface BillRepositoryInterface
{ {
/** /**
* Takes the paid/unpaid bills collection set up before and expands it using * This method will tell you if you still have a CC bill to pay. Amount will be negative if the amount
* credit cards the user might have. * has been paid
* *
* @param Collection $set
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @return string
*/
public function getCreditCardBill(Carbon $start, Carbon $end);
/**
* Get the total amount of money paid for the users active bills in the date range given.
*
* @param Carbon $start
* @param Carbon $end
*
* @return string
*/
public function getBillsPaidInRange(Carbon $start, Carbon $end);
/**
* Get the total amount of money due for the users active bills in the date range given.
*
* @param Carbon $start
* @param Carbon $end
*
* @return string
*/
public function getBillsUnpaidInRange(Carbon $start, Carbon $end);
/**
* @return Collection * @return Collection
*/ */
public function getCreditCardInfoForChart(Collection $set, Carbon $start, Carbon $end); public function getActiveBills();
/**
* Gets a collection of paid bills and a collection of unpaid bills to be used
* in the pie chart on the front page.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getBillsForChart(Carbon $start, Carbon $end);
/**
* 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.
*
* @param string $description
* @param Carbon $date
* @param float $amount
*
* @return Bill
*/
public function createFakeBill($description, Carbon $date, $amount);
/** /**
* @param Bill $bill * @param Bill $bill
@@ -68,15 +60,32 @@ interface BillRepositoryInterface
public function destroy(Bill $bill); public function destroy(Bill $bill);
/** /**
* Returns all journals connected to these bills in the given range. Amount paid
* is stored in "journalAmount" as a negative number.
*
* @param Collection $bills
* @param Carbon $start
* @param Carbon $end
*
* @return Collection * @return Collection
*/ */
public function getActiveBills(); public function getAllJournalsInRange(Collection $bills, Carbon $start, Carbon $end);
/** /**
* @return Collection * @return Collection
*/ */
public function getBills(); public function getBills();
/**
* Gets the bills which have some kind of relevance to the accounts mentioned.
*
* @param Collection $accounts
*
* @return Collection
*/
public function getBillsForAccounts(Collection $accounts);
/** /**
* @param Bill $bill * @param Bill $bill
* *
@@ -105,7 +114,7 @@ interface BillRepositoryInterface
/** /**
* Every bill repeats itself weekly, monthly or yearly (or whatever). This method takes a date-range (usually the view-range of Firefly itself) * Every bill repeats itself weekly, monthly or yearly (or whatever). This method takes a date-range (usually the view-range of Firefly itself)
* and returns date ranges that fall within the given range; those ranges are the bills expected. When a bill is due on the 14th of the month and * and returns date ranges that fall within the given range; those ranges are the bills expected. When a bill is due on the 14th of the month and
* you give 1st and the 31st of that month as argument, you'll get one response, matching the range of your bill. * you give 1st and the 31st of that month as argument, you'll get one response, matching the range of your bill (from the 14th to the 31th).
* *
* @param Bill $bill * @param Bill $bill
* @param Carbon $start * @param Carbon $start

View File

@@ -4,12 +4,15 @@ namespace FireflyIII\Repositories\Budget;
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use DB;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\LimitRepetition; use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Shared\ComponentRepository; use FireflyIII\Repositories\Shared\ComponentRepository;
use FireflyIII\Support\CacheProperties; use Illuminate\Database\Eloquent\Builder;
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;
@@ -32,6 +35,67 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
} }
/**
* Returns the expenses for this budget grouped per day, with the date
* in "date" (a string, not a Carbon) and the amount in "dailyAmount".
*
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getExpensesPerDay(Budget $budget, Carbon $start, Carbon $end)
{
$set = Auth::user()->budgets()
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.budget_id', '=', 'budgets.id')
->leftJoin('transaction_journals', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->whereNull('transaction_journals.deleted_at')
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('budgets.id', $budget->id)
->where('transactions.amount', '<', 0)
->groupBy('transaction_journals.date')
->orderBy('transaction_journals.date')
->get(['transaction_journals.date', DB::Raw('SUM(`transactions`.`amount`) as `dailyAmount`')]);
return $set;
}
/**
* Returns the expenses for this budget grouped per month, with the date
* in "dateFormatted" (a string, not a Carbon) and the amount in "dailyAmount".
*
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getExpensesPerMonth(Budget $budget, Carbon $start, Carbon $end)
{
$set = Auth::user()->budgets()
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.budget_id', '=', 'budgets.id')
->leftJoin('transaction_journals', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->whereNull('transaction_journals.deleted_at')
->where('budgets.id', $budget->id)
->where('transactions.amount', '<', 0)
->groupBy('dateFormatted')
->orderBy('transaction_journals.date')
->get(
[
DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y-%m") AS `dateFormatted`'),
DB::Raw('SUM(`transactions`.`amount`) as `monthlyAmount`')
]
);
return $set;
}
/** /**
* @param Budget $budget * @param Budget $budget
* *
@@ -44,20 +108,6 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
return true; return true;
} }
/**
* @param Budget $budget
* @param Carbon $date
*
* @return float
*/
public function expensesOnDayCorrected(Budget $budget, Carbon $date)
{
bcscale(2);
$sum = $budget->transactionjournals()->transactionTypes(['Withdrawal'])->onDate($date)->get(['transaction_journals.*'])->sum('amount');
return $sum;
}
/** /**
* @return Collection * @return Collection
*/ */
@@ -76,31 +126,113 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
} }
/** /**
* @param Budget $budget * Returns a list of budgets, budget limits and limit repetitions
* (doubling any of them in a left join)
*
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @return Collection * @return Collection
*/ */
public function getBudgetLimitRepetitions(Budget $budget, Carbon $start, Carbon $end) public function getBudgetsAndLimitsInRange(Carbon $start, Carbon $end)
{ {
/** @var Collection $repetitions */ /** @var Collection $set */
return LimitRepetition:: $set = Auth::user()
leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id') ->budgets()
->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00')) ->leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budgets.id')
->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00')) ->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->where('budget_limits.budget_id', $budget->id) ->where(
->get(['limit_repetitions.*']); function (Builder $query) use ($start, $end) {
$query->where(
function (Builder $query) use ($start, $end) {
$query->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d'));
$query->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d'));
}
);
$query->orWhere(
function (Builder $query) {
$query->whereNull('limit_repetitions.startdate');
$query->whereNull('limit_repetitions.enddate');
}
);
}
)
->get(['budgets.*', 'limit_repetitions.startdate', 'limit_repetitions.enddate', 'limit_repetitions.amount']);
$set = $set->sortBy(
function (Budget $budget) {
return strtolower($budget->name);
}
);
return $set;
} }
/** /**
* @param Budget $budget * @param Budget $budget
* *
* @return Carbon
*/
public function firstActivity(Budget $budget)
{
$first = $budget->transactionjournals()->orderBy('date', 'ASC')->first();
if ($first) {
return $first->date;
}
return new Carbon;
}
/**
* @param Carbon $start
* @param Carbon $end
*
* @return Collection * @return Collection
*/ */
public function getBudgetLimits(Budget $budget) public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end)
{ {
return $budget->budgetLimits()->orderBy('startdate', 'DESC')->get(); /** @var Collection $repetitions */
return LimitRepetition::
leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->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('budgets.user_id', Auth::user()->id)
->get(['limit_repetitions.*', 'budget_limits.budget_id']);
}
/**
* Returns an array with the following key:value pairs:
*
* yyyy-mm-dd:<amount>
*
* Where yyyy-mm-dd is the date and <amount> is the money spent using DEPOSITS in the $budget
* from all the users accounts.
*
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentPerDay(Budget $budget, Carbon $start, Carbon $end)
{
/** @var Collection $query */
$query = $budget->transactionJournals()
->transactionTypes([TransactionType::WITHDRAWAL])
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.amount', '<', 0)
->before($end)
->after($start)
->groupBy('dateFormatted')->get(['transaction_journals.date as dateFormatted', DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
$return = [];
foreach ($query->toArray() as $entry) {
$return[$entry['dateFormatted']] = $entry['sum'];
}
return $return;
} }
/** /**
@@ -129,21 +261,10 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
*/ */
public function getCurrentRepetition(Budget $budget, Carbon $start, Carbon $end) public function getCurrentRepetition(Budget $budget, Carbon $start, Carbon $end)
{ {
$cache = new CacheProperties;
$cache->addProperty($budget->id);
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('getCurrentRepetition');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$data = $budget->limitrepetitions() $data = $budget->limitrepetitions()
->where('limit_repetitions.startdate', $start) ->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00'))
->where('limit_repetitions.enddate', $end) ->where('limit_repetitions.enddate', $end->format('Y-m-d 00:00:00'))
->first(['limit_repetitions.*']); ->first(['limit_repetitions.*']);
$cache->store($data);
return $data; return $data;
} }
@@ -162,6 +283,64 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
return Carbon::now()->startOfYear(); return Carbon::now()->startOfYear();
} }
/**
* Returns an array with every budget in it and the expenses for each budget
* per month.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getBudgetsAndExpensesPerMonth(Collection $accounts, Carbon $start, Carbon $end)
{
$ids = $accounts->pluck('id')->toArray();
/** @var Collection $set */
$set = Auth::user()->budgets()
->leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0);
}
)
->groupBy('budgets.id')
->groupBy('dateFormatted')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->whereIn('transactions.account_id', $ids)
->get(
[
'budgets.*',
DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y-%m") AS `dateFormatted`'),
DB::Raw('SUM(`transactions`.`amount`) AS `sumAmount`')
]
);
$set = $set->sortBy(
function (Budget $budget) {
return strtolower($budget->name);
}
);
$return = [];
foreach ($set as $budget) {
$id = $budget->id;
if (!isset($return[$id])) {
$return[$id] = [
'budget' => $budget,
'entries' => [],
];
}
// store each entry:
$return[$id]['entries'][$budget->dateFormatted] = $budget->sumAmount;
}
return $return;
}
/** /**
* @return Collection * @return Collection
*/ */
@@ -190,17 +369,6 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
*/ */
public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50) public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50)
{ {
$cache = new CacheProperties;
$cache->addProperty($budget->id);
if ($repetition) {
$cache->addProperty($repetition->id);
}
$cache->addProperty($take);
$cache->addProperty('getJournals');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$offset = intval(Input::get('page')) > 0 ? intval(Input::get('page')) * $take : 0; $offset = intval(Input::get('page')) > 0 ? intval(Input::get('page')) * $take : 0;
$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')
@@ -220,46 +388,10 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
$paginator = new LengthAwarePaginator($set, $count, $take, $offset); $paginator = new LengthAwarePaginator($set, $count, $take, $offset);
$cache->store($paginator);
return $paginator; return $paginator;
} }
/**
* @param Budget $budget
*
* @return Carbon
*/
public function getLastBudgetLimitDate(Budget $budget)
{
$limit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first();
if ($limit) {
return $limit->startdate;
}
return Carbon::now()->startOfYear();
}
/**
* @param Budget $budget
* @param Carbon $date
*
* @return float|null
*/
public function getLimitAmountOnDate(Budget $budget, Carbon $date)
{
$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('budget_limits.budget_id', $budget->id)
->first(['limit_repetitions.*']);
if ($repetition) {
return $repetition->amount;
}
return null;
}
/** /**
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
@@ -288,7 +420,7 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
*/ */
public function getWithoutBudgetSum(Carbon $start, Carbon $end) public function getWithoutBudgetSum(Carbon $start, Carbon $end)
{ {
$noBudgetSet = Auth::user() $entry = Auth::user()
->transactionjournals() ->transactionjournals()
->whereNotIn( ->whereNotIn(
'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) { 'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) {
@@ -303,25 +435,28 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
) )
->after($start) ->after($start)
->before($end) ->before($end)
->transactionTypes(['Withdrawal']) ->leftJoin(
->get(['transaction_journals.*'])->sum('amount'); 'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0);
}
)
->transactionTypes([TransactionType::WITHDRAWAL])
->first([DB::Raw('SUM(`transactions`.`amount`) as `journalAmount`')]);
bcscale(2); return $entry->journalAmount;
return bcmul($noBudgetSet, -1);
} }
/** /**
* @param Budget $budget * @param Budget $budget
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param bool $shared * @param Collection $accounts
* *
* @return string * @return string
*/ */
public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, $shared = true) public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, Collection $accounts)
{ {
return $this->commonBalanceInPeriod($budget, $start, $end, $shared); return $this->commonBalanceInPeriod($budget, $start, $end, $accounts);
} }
/** /**
@@ -395,7 +530,197 @@ class BudgetRepository extends ComponentRepository implements BudgetRepositoryIn
} }
return $limit; return $limit;
}
/**
* Get the budgeted amounts for each budgets in each year.
*
* @param Collection $budgets
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getBudgetedPerYear(Collection $budgets, Carbon $start, Carbon $end)
{
$budgetIds = $budgets->pluck('id')->toArray();
$set = Auth::user()->budgets()
->leftJoin('budget_limits', 'budgets.id', '=', 'budget_limits.budget_id')
->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d'))
->where('limit_repetitions.enddate', '<=', $end->format('Y-m-d'))
->groupBy('budgets.id')
->groupBy('dateFormatted')
->whereIn('budgets.id', $budgetIds)
->get(
[
'budgets.*',
DB::Raw('DATE_FORMAT(`limit_repetitions`.`startdate`,"%Y") as `dateFormatted`'),
DB::Raw('SUM(`limit_repetitions`.`amount`) as `budgeted`')
]
);
return $set;
}
/**
* Returns an array with every budget in it and the expenses for each budget
* per year for.
*
* @param Collection $budgets
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getBudgetsAndExpensesPerYear(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end)
{
$ids = $accounts->pluck('id')->toArray();
$budgetIds = $budgets->pluck('id')->toArray();
/** @var Collection $set */
$set = Auth::user()->budgets()
->leftJoin('budget_transaction_journal', 'budgets.id', '=', 'budget_transaction_journal.budget_id')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0);
}
)
->groupBy('budgets.id')
->groupBy('dateFormatted')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->whereIn('transactions.account_id', $ids)
->whereIn('budgets.id', $budgetIds)
->get(
[
'budgets.*',
DB::Raw('DATE_FORMAT(`transaction_journals`.`date`, "%Y") AS `dateFormatted`'),
DB::Raw('SUM(`transactions`.`amount`) AS `sumAmount`')
]
);
$set = $set->sortBy(
function (Budget $budget) {
return strtolower($budget->name);
}
);
$return = [];
foreach ($set as $budget) {
$id = $budget->id;
if (!isset($return[$id])) {
$return[$id] = [
'budget' => $budget,
'entries' => [],
];
}
// store each entry:
$return[$id]['entries'][$budget->dateFormatted] = $budget->sumAmount;
}
return $return;
}
/**
* Returns an array with the following key:value pairs:
*
* yyyy-mm-dd:<array>
*
* That array contains:
*
* budgetid:<amount>
*
* Where yyyy-mm-dd is the date and <amount> is the money spent using WITHDRAWALS in the $budget
* from the given users accounts..
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentAllPerDayForAccounts(Collection $accounts, Carbon $start, Carbon $end)
{
$ids = $accounts->pluck('id')->toArray();
/** @var Collection $query */
$query = Auth::user()->transactionJournals()
->transactionTypes([TransactionType::WITHDRAWAL])
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budget_transaction_journal', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id')
->whereIn('transactions.account_id', $ids)
->where('transactions.amount', '<', 0)
->before($end)
->after($start)
->groupBy('budget_id')
->groupBy('dateFormatted')
->get(
['transaction_journals.date as dateFormatted', 'budget_transaction_journal.budget_id',
DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]
);
$return = [];
foreach ($query->toArray() as $entry) {
$budgetId = $entry['budget_id'];
if (!isset($return[$budgetId])) {
$return[$budgetId] = [];
}
$return[$budgetId][$entry['dateFormatted']] = $entry['sum'];
}
return $return;
}
/**
* Returns a list of expenses (in the field "spent", grouped per budget per account.
*
* @param Collection $budgets
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function spentPerBudgetPerAccount(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end)
{
$accountIds = $accounts->pluck('id')->toArray();
$budgetIds = $budgets->pluck('id')->toArray();
$set = Auth::user()->transactionjournals()
->leftJoin(
'transactions AS t_from', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 't_from.transaction_journal_id')->where('t_from.amount', '<', 0);
}
)
->leftJoin(
'transactions AS t_to', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 't_to.transaction_journal_id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('budget_transaction_journal', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id')
->whereIn('t_from.account_id', $accountIds)
->whereNotIn('t_to.account_id', $accountIds)
->where(
function (Builder $q) use ($budgetIds) {
$q->whereIn('budget_transaction_journal.budget_id', $budgetIds);
$q->orWhereNull('budget_transaction_journal.budget_id');
}
)
->after($start)
->before($end)
->groupBy('t_from.account_id')
->groupBy('budget_transaction_journal.budget_id')
->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE])
->get(
[
't_from.account_id', 'budget_transaction_journal.budget_id',
DB::Raw('SUM(`t_from`.`amount`) AS `spent`')
]
);
return $set;
} }
} }

View File

@@ -15,11 +15,93 @@ use Illuminate\Support\Collection;
*/ */
interface BudgetRepositoryInterface interface BudgetRepositoryInterface
{ {
/** /**
* @return void * @return void
*/ */
public function cleanupBudgets(); public function cleanupBudgets();
/**
* Returns the expenses for this budget grouped per day, with the date
* in "date" (a string, not a Carbon) and the amount in "dailyAmount".
*
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getExpensesPerDay(Budget $budget, Carbon $start, Carbon $end);
/**
* @param Budget $budget
*
* @return Carbon
*/
public function firstActivity(Budget $budget);
/**
* Returns the expenses for this budget grouped per month, with the date
* in "date" (a string, not a Carbon) and the amount in "dailyAmount".
*
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getExpensesPerMonth(Budget $budget, Carbon $start, Carbon $end);
/**
* Returns a list of expenses (in the field "spent", grouped per budget per account.
*
* @param Collection $budgets
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function spentPerBudgetPerAccount(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end);
/**
* Returns an array with the following key:value pairs:
*
* yyyy-mm-dd:<amount>
*
* Where yyyy-mm-dd is the date and <amount> is the money spent using WITHDRAWALS in the $budget
* from all the users accounts.
*
* @param Budget $budget
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentPerDay(Budget $budget, Carbon $start, Carbon $end);
/**
* Returns an array with the following key:value pairs:
*
* yyyy-mm-dd:<array>
*
* That array contains:
*
* budgetid:<amount>
*
* Where yyyy-mm-dd is the date and <amount> is the money spent using WITHDRAWALS in the $budget
* from the given users accounts..
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentAllPerDayForAccounts(Collection $accounts, Carbon $start, Carbon $end);
/** /**
* @param Budget $budget * @param Budget $budget
* *
@@ -28,14 +110,29 @@ interface BudgetRepositoryInterface
public function destroy(Budget $budget); public function destroy(Budget $budget);
/** /**
* Takes tags into account. * Returns an array with every budget in it and the expenses for each budget
* per month.
* *
* @param Budget $budget * @param Collection $accounts
* @param Carbon $date * @param Carbon $start
* @param Carbon $end
* *
* @return float * @return array
*/ */
public function expensesOnDayCorrected(Budget $budget, Carbon $date); public function getBudgetsAndExpensesPerMonth(Collection $accounts, Carbon $start, Carbon $end);
/**
* Returns an array with every budget in it and the expenses for each budget
* per year for.
*
* @param Collection $budgets
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getBudgetsAndExpensesPerYear(Collection $budgets, Collection $accounts, Carbon $start, Carbon $end);
/** /**
* @return Collection * @return Collection
@@ -43,26 +140,40 @@ interface BudgetRepositoryInterface
public function getActiveBudgets(); public function getActiveBudgets();
/** /**
* @param Budget $budget * Get the budgeted amounts for each budgets in each year.
*
* @param Collection $budgets
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @return Collection * @return Collection
*/ */
public function getBudgetLimitRepetitions(Budget $budget, Carbon $start, Carbon $end); public function getBudgetedPerYear(Collection $budgets, Carbon $start, Carbon $end);
/** /**
* @param Budget $budget * @param Carbon $start
* @param Carbon $end
* *
* @return Collection * @return Collection
*/ */
public function getBudgetLimits(Budget $budget); public function getAllBudgetLimitRepetitions(Carbon $start, Carbon $end);
/** /**
* @return Collection * @return Collection
*/ */
public function getBudgets(); public function getBudgets();
/**
* Returns a list of budgets, budget limits and limit repetitions
* (doubling any of them in a left join)
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getBudgetsAndLimitsInRange(Carbon $start, Carbon $end);
/** /**
* @param Budget $budget * @param Budget $budget
* @param Carbon $start * @param Carbon $start
@@ -95,21 +206,6 @@ interface BudgetRepositoryInterface
*/ */
public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50); public function getJournals(Budget $budget, LimitRepetition $repetition = null, $take = 50);
/**
* @param Budget $budget
*
* @return Carbon
*/
public function getLastBudgetLimitDate(Budget $budget);
/**
* @param Budget $budget
* @param Carbon $date
*
* @return float
*/
public function getLimitAmountOnDate(Budget $budget, Carbon $date);
/** /**
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
@@ -128,16 +224,16 @@ interface BudgetRepositoryInterface
/** /**
* *
* Same as ::spentInPeriod but corrects journals for their amount (tags). * Same as ::spentInPeriod but corrects journals for a set of accounts
* *
* @param Budget $budget * @param Budget $budget
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* @param boolean $shared * @param Collection $accounts
* *
* @return string * @return string
*/ */
public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, $shared = true); public function balanceInPeriod(Budget $budget, Carbon $start, Carbon $end, Collection $accounts);
/** /**
* @param array $data * @param array $data

View File

@@ -4,11 +4,11 @@ namespace FireflyIII\Repositories\Category;
use Auth; use Auth;
use Carbon\Carbon; use Carbon\Carbon;
use Crypt; use DB;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Shared\ComponentRepository; use FireflyIII\Sql\Query;
use FireflyIII\Support\CacheProperties; use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**
@@ -16,36 +16,15 @@ use Illuminate\Support\Collection;
* *
* @package FireflyIII\Repositories\Category * @package FireflyIII\Repositories\Category
*/ */
class CategoryRepository extends ComponentRepository implements CategoryRepositoryInterface class CategoryRepository implements CategoryRepositoryInterface
{ {
/** /**
* @param Category $category * Returns a list of all the categories belonging to a user.
* *
* @return int
*/
public function countJournals(Category $category)
{
return $category->transactionJournals()->count();
}
/**
* @param Category $category
*
* @return boolean
*/
public function destroy(Category $category)
{
$category->delete();
return true;
}
/**
* @return Collection * @return Collection
*/ */
public function getCategories() public function listCategories()
{ {
/** @var Collection $set */ /** @var Collection $set */
$set = Auth::user()->categories()->orderBy('name', 'ASC')->get(); $set = Auth::user()->categories()->orderBy('name', 'ASC')->get();
@@ -58,111 +37,16 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
return $set; return $set;
} }
/** /**
* Returns a list of transaction journals in the range (all types, all accounts) that have no category
* associated to them.
* *
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getCategoriesAndExpensesCorrected(Carbon $start, Carbon $end)
{
$set = Auth::user()->transactionjournals()
->leftJoin(
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
)
->leftJoin('categories', 'categories.id', '=', 'category_transaction_journal.category_id')
->before($end)
->where('categories.user_id', Auth::user()->id)
->after($start)
->transactionTypes(['Withdrawal'])
->get(['categories.id as category_id', 'categories.encrypted as category_encrypted', 'categories.name', 'transaction_journals.*']);
bcscale(2);
$result = [];
foreach ($set as $entry) {
$categoryId = intval($entry->category_id);
if (isset($result[$categoryId])) {
$result[$categoryId]['sum'] = bcadd($result[$categoryId]['sum'], $entry->amount);
} else {
$isEncrypted = intval($entry->category_encrypted) === 1 ? true : false;
$name = strlen($entry->name) === 0 ? trans('firefly.no_category') : $entry->name;
$name = $isEncrypted ? Crypt::decrypt($name) : $name;
$result[$categoryId] = [
'name' => $name,
'sum' => $entry->amount,
];
}
}
return $result;
}
/**
* @param Category $category
*
* @return Carbon
*/
public function getFirstActivityDate(Category $category)
{
/** @var TransactionJournal $first */
$first = $category->transactionjournals()->orderBy('date', 'ASC')->first();
if ($first) {
return $first->date;
}
return new Carbon;
}
/**
* @param Category $category
* @param int $page
*
* @return Collection
*/
public function getJournals(Category $category, $page)
{
$offset = $page > 0 ? $page * 50 : 0;
return $category->transactionJournals()->withRelevantData()->take(50)->offset($offset)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->get(
['transaction_journals.*']
);
}
/**
* @param Category $category
*
* @return Carbon|null
*/
public function getLatestActivity(Category $category)
{
$latest = $category->transactionjournals()
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->first();
if ($latest) {
return $latest->date;
}
return null;
}
/**
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @return Collection * @return Collection
*/ */
public function getWithoutCategory(Carbon $start, Carbon $end) public function listNoCategory(Carbon $start, Carbon $end)
{ {
return Auth::user() return Auth::user()
->transactionjournals() ->transactionjournals()
@@ -177,196 +61,239 @@ class CategoryRepository extends ComponentRepository implements CategoryReposito
} }
/** /**
* @param Category $category * This method returns a very special collection for each category:
*
* category, year, expense/earned, amount
*
* categories can be duplicated.
*
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @param bool $shared
*
* @return string
*/
public function balanceInPeriod(Category $category, Carbon $start, Carbon $end, $shared = false)
{
return $this->commonBalanceInPeriod($category, $start, $end, $shared);
}
/**
* Corrected for tags
*
* @param Category $category
* @param Carbon $date
*
* @return string
*/
public function spentOnDaySumCorrected(Category $category, Carbon $date)
{
return $category->transactionjournals()->transactionTypes(['Withdrawal'])->onDate($date)->get(['transaction_journals.*'])->sum('amount');
}
/**
* @param array $data
*
* @return Category
*/
public function store(array $data)
{
$newCategory = new Category(
[
'user_id' => $data['user'],
'name' => $data['name'],
]
);
$newCategory->save();
return $newCategory;
}
/**
* @param Category $category
* @param array $data
*
* @return Category
*/
public function update(Category $category, array $data)
{
// update the account:
$category->name = $data['name'];
$category->save();
return $category;
}
/**
* This method returns the sum of the journals in the category, optionally
* limited by a start or end date.
*
* @param Category $category
* @param Carbon $start
* @param Carbon $end
*
* @return string
*/
public function journalsSum(Category $category, Carbon $start = null, Carbon $end = null)
{
$query = $category->transactionJournals()
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC');
if (!is_null($start)) {
$query->after($start);
}
if (!is_null($end)) {
$query->before($end);
}
return $query->get(['transaction_journals.*'])->sum('amount');
}
/**
* @param Category $category
* @param \Carbon\Carbon $start
* @param \Carbon\Carbon $end
*
* @param bool $shared
*
* @return string
*/
public function spentInPeriod(Category $category, Carbon $start, Carbon $end)
{
$cache = new CacheProperties; // we must cache this.
$cache->addProperty($category->id);
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('spentInPeriod');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$sum = $category->transactionjournals()->transactionTypes(['Withdrawal'])->before($end)->after($start)->get(['transaction_journals.*'])->sum(
'amount'
);
$cache->store($sum);
return $sum;
}
/**
* @param Category $category
* @param \Carbon\Carbon $start
* @param \Carbon\Carbon $end
*
* @param bool $shared
*
* @return string
*/
public function earnedInPeriod(Category $category, Carbon $start, Carbon $end)
{
$cache = new CacheProperties; // we must cache this.
$cache->addProperty($category->id);
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('earnedInPeriod');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
$sum = $category->transactionjournals()->transactionTypes(['Deposit'])->before($end)->after($start)->get(['transaction_journals.*'])->sum(
'amount'
);
$cache->store($sum);
return $sum;
}
/**
* @param Category $category
* @param int $page
*
* @return Collection * @return Collection
*/ */
public function getJournalsInRange(Category $category, $page, Carbon $start, Carbon $end) public function listMultiYear(Collection $categories, Collection $accounts, Carbon $start, Carbon $end)
{ {
$offset = $page > 0 ? $page * 50 : 0; /*
* select categories.id, DATE_FORMAT(transaction_journals.date,"%Y") as dateFormatted, transaction_types.type, SUM(amount) as sum from categories
return $category->transactionJournals() left join category_transaction_journal ON category_transaction_journal.category_id = categories.id
->after($start) left join transaction_journals ON transaction_journals.id = category_transaction_journal.transaction_journal_id
->before($end) left join transaction_types ON transaction_types.id = transaction_journals.transaction_type_id
->withRelevantData()->take(50)->offset($offset) left join transactions ON transactions.transaction_journal_id = transaction_journals.id
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC') where
categories.user_id =1
and transaction_types.type in ("Withdrawal","Deposit")
and transactions.account_id IN (2,4,6,10,11,610,725,879,1248)
group by categories.id, transaction_types.type, dateFormatted
*/
$set = Auth::user()->categories()
->leftJoin('category_transaction_journal', 'category_transaction_journal.category_id', '=', 'categories.id')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'category_transaction_journal.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->whereIn('transaction_types.type', [TransactionType::DEPOSIT, TransactionType::WITHDRAWAL])
->whereIn('transactions.account_id', $accounts->pluck('id')->toArray())
->whereIn('categories.id', $categories->pluck('id')->toArray())
->groupBy('categories.id')
->groupBy('transaction_types.type')
->groupBy('dateFormatted')
->get( ->get(
['transaction_journals.*'] [
'categories.*',
DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y") as `dateFormatted`'),
'transaction_types.type',
DB::Raw('SUM(`amount`) as `sum`')
]
); );
return $set;
}
/**
* Returns a collection of Categories appended with the amount of money that has been earned
* in these categories, based on the $accounts involved, in period X, grouped per month.
* The amount earned in category X in period X is saved in field "earned".
*
* @param $accounts
* @param $start
* @param $end
*
* @return Collection
*/
public function earnedForAccountsPerMonth(Collection $accounts, Carbon $start, Carbon $end)
{
$collection = Auth::user()->categories()
->leftJoin('category_transaction_journal', 'category_transaction_journal.category_id', '=', 'categories.id')
->leftJoin('transaction_journals', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin(
'transactions AS t_src', function (JoinClause $join) {
$join->on('t_src.transaction_journal_id', '=', 'transaction_journals.id')->where('t_src.amount', '<', 0);
}
)
->leftJoin(
'transactions AS t_dest', function (JoinClause $join) {
$join->on('t_dest.transaction_journal_id', '=', 'transaction_journals.id')->where('t_dest.amount', '>', 0);
}
)
->whereIn('t_dest.account_id', $accounts->pluck('id')->toArray())// to these accounts (earned)
->whereNotIn('t_src.account_id', $accounts->pluck('id')->toArray())//-- but not from these accounts
->whereIn(
'transaction_types.type', [TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]
)
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->groupBy('categories.id')
->groupBy('dateFormatted')
->get(
[
'categories.*',
DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") as `dateFormatted`'),
DB::Raw('SUM(`t_dest`.`amount`) AS `earned`')
]
);
return $collection;
} }
/** /**
* @param Category $category * Returns a collection of Categories appended with the amount of money that has been spent
* in these categories, based on the $accounts involved, in period X, grouped per month.
* The amount spent in category X in period X is saved in field "spent".
* *
* @return int * @param $accounts
* @param $start
* @param $end
*
* @return Collection
*/ */
public function countJournalsInRange(Category $category, Carbon $start, Carbon $end) public function spentForAccountsPerMonth(Collection $accounts, Carbon $start, Carbon $end)
{ {
return $category->transactionJournals()->before($end)->after($start)->count(); $accountIds = $accounts->pluck('id')->toArray();
$query = Auth::user()->categories()
->leftJoin('category_transaction_journal', 'category_transaction_journal.category_id', '=', 'categories.id')
->leftJoin('transaction_journals', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin(
'transactions AS t_src', function (JoinClause $join) {
$join->on('t_src.transaction_journal_id', '=', 'transaction_journals.id')->where('t_src.amount', '<', 0);
}
)
->leftJoin(
'transactions AS t_dest', function (JoinClause $join) {
$join->on('t_dest.transaction_journal_id', '=', 'transaction_journals.id')->where('t_dest.amount', '>', 0);
}
)
->whereIn(
'transaction_types.type', [TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]
)// spent on these things.
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->groupBy('categories.id')
->groupBy('dateFormatted');
if (count($accountIds) > 0) {
$query->whereIn('t_src.account_id', $accountIds)// from these accounts (spent)
->whereNotIn('t_dest.account_id', $accountIds);//-- but not from these accounts (spent internally)
}
$collection = $query->get(
[
'categories.*',
DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y-%m") as `dateFormatted`'),
DB::Raw('SUM(`t_src`.`amount`) AS `spent`')
]
);
return $collection;
}
/**
* Returns the total amount of money related to transactions without any category connected to
* it. Returns either the spent amount.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return string
*/
public function sumSpentNoCategory(Collection $accounts, Carbon $start, Carbon $end)
{
return $this->sumNoCategory($accounts, $start, $end, Query::SPENT);
} }
/** /**
* Returns the total amount of money related to transactions without any category connected to
* it. Returns either the earned amount.
* *
* Corrected for tags. * @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* *
* @param Category $category * @return string
* @param Carbon $date
*
* @return float
*/ */
public function earnedOnDaySumCorrected(Category $category, Carbon $date) public function sumEarnedNoCategory(Collection $accounts, Carbon $start, Carbon $end)
{ {
return $category->transactionjournals()->transactionTypes(['Deposit'])->onDate($date)->get(['transaction_journals.*'])->sum('amount'); return $this->sumNoCategory($accounts, $start, $end, Query::EARNED);
}
/**
* Returns the total amount of money related to transactions without any category connected to
* it. Returns either the earned or the spent amount.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* @param int $group
*
* @return string
*/
protected function sumNoCategory(Collection $accounts, Carbon $start, Carbon $end, $group = Query::EARNED)
{
$accountIds = $accounts->pluck('id')->toArray();
if ($group == Query::EARNED) {
$types = [TransactionType::DEPOSIT];
} else {
$types = [TransactionType::WITHDRAWAL];
}
// is withdrawal or transfer AND account_from is in the list of $accounts
$query = Auth::user()
->transactionjournals()
->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->whereNull('category_transaction_journal.id')
->before($end)
->after($start)
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->transactionTypes($types);
if (count($accountIds) > 0) {
$query->whereIn('transactions.account_id', $accountIds);
}
$single = $query->first(
[
DB::Raw('SUM(`transactions`.`amount`) as `sum`')
]
);
if (!is_null($single)) {
return $single->sum;
}
return '0';
} }
} }

View File

@@ -3,7 +3,6 @@
namespace FireflyIII\Repositories\Category; namespace FireflyIII\Repositories\Category;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Models\Category;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**
@@ -13,162 +12,90 @@ use Illuminate\Support\Collection;
*/ */
interface CategoryRepositoryInterface interface CategoryRepositoryInterface
{ {
/**
* @param Category $category
*
* @return int
*/
public function countJournals(Category $category);
/** /**
* @param Category $category * Returns a collection of Categories appended with the amount of money that has been earned
* in these categories, based on the $accounts involved, in period X, grouped per month.
* The amount earned in category X in period X is saved in field "earned".
* *
* @return int * @param $accounts
*/ * @param $start
public function countJournalsInRange(Category $category, Carbon $start, Carbon $end); * @param $end
/**
* @param Category $category
*
* @return boolean
*/
public function destroy(Category $category);
/**
* @return Collection
*/
public function getCategories();
/**
* Corrected for tags.
*
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function getCategoriesAndExpensesCorrected(Carbon $start, Carbon $end);
/**
* @param Category $category
*
* @return Carbon
*/
public function getFirstActivityDate(Category $category);
/**
* @param Category $category
* @param int $page
* *
* @return Collection * @return Collection
*/ */
public function getJournals(Category $category, $page); public function earnedForAccountsPerMonth(Collection $accounts, Carbon $start, Carbon $end);
/** /**
* @param Category $category * Returns a list of all the categories belonging to a user.
* @param int $page
* *
* @return Collection * @return Collection
*/ */
public function getJournalsInRange(Category $category, $page, Carbon $start, Carbon $end); public function listCategories();
/** /**
* This method returns the sum of the journals in the category, optionally * This method returns a very special collection for each category:
* limited by a start or end date.
* *
* @param Category $category * category, year, expense/earned, amount
* @param Carbon $start
* @param Carbon $end
* *
* @return string * categories can be duplicated.
*/
public function journalsSum(Category $category, Carbon $start = null, Carbon $end = null);
/**
* @param Category $category
* *
* @return Carbon|null * @param Collection $categories
*/ * @param Collection $accounts
public function getLatestActivity(Category $category);
/**
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* *
* @return Collection * @return Collection
*/ */
public function getWithoutCategory(Carbon $start, Carbon $end); public function listMultiYear(Collection $categories, Collection $accounts, Carbon $start, Carbon $end);
/** /**
* Corrected for tags. * Returns a list of transaction journals in the range (all types, all accounts) that have no category
* associated to them.
* *
* @param Category $category * @param Carbon $start
* @param \Carbon\Carbon $start * @param Carbon $end
* @param \Carbon\Carbon $end
* *
* @param bool $shared * @return Collection
*/
public function listNoCategory(Carbon $start, Carbon $end);
/**
* Returns a collection of Categories appended with the amount of money that has been spent
* in these categories, based on the $accounts involved, in period X, grouped per month.
* The amount earned in category X in period X is saved in field "spent".
*
* @param $accounts
* @param $start
* @param $end
*
* @return Collection
*/
public function spentForAccountsPerMonth(Collection $accounts, Carbon $start, Carbon $end);
/**
* Returns the total amount of money related to transactions without any category connected to
* it. Returns either the earned amount.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* *
* @return string * @return string
*/ */
public function balanceInPeriod(Category $category, Carbon $start, Carbon $end, $shared = false); public function sumEarnedNoCategory(Collection $accounts, Carbon $start, Carbon $end);
/** /**
* @param Category $category * Returns the total amount of money related to transactions without any category connected to
* @param \Carbon\Carbon $start * it. Returns either the spent amount.
* @param \Carbon\Carbon $end
* *
* @param bool $shared * @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* *
* @return string * @return string
*/ */
public function spentInPeriod(Category $category, Carbon $start, Carbon $end); public function sumSpentNoCategory(Collection $accounts, Carbon $start, Carbon $end);
/**
* @param Category $category
* @param \Carbon\Carbon $start
* @param \Carbon\Carbon $end
*
* @param bool $shared
*
* @return string
*/
public function earnedInPeriod(Category $category, Carbon $start, Carbon $end);
/**
*
* Corrected for tags.
*
* @param Category $category
* @param Carbon $date
*
* @return float
*/
public function spentOnDaySumCorrected(Category $category, Carbon $date);
/**
*
* Corrected for tags.
*
* @param Category $category
* @param Carbon $date
*
* @return float
*/
public function earnedOnDaySumCorrected(Category $category, Carbon $date);
/**
* @param array $data
*
* @return Category
*/
public function store(array $data);
/**
* @param Category $category
* @param array $data
*
* @return Category
*/
public function update(Category $category, array $data);
} }

View File

@@ -0,0 +1,238 @@
<?php
namespace FireflyIII\Repositories\Category;
use Carbon\Carbon;
use DB;
use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Shared\ComponentRepository;
use Illuminate\Support\Collection;
/**
* Class SingleCategoryRepository
*
* @package FireflyIII\Repositories\Category
*/
class SingleCategoryRepository extends ComponentRepository implements SingleCategoryRepositoryInterface
{
/**
* @param Category $category
*
* @return int
*/
public function countJournals(Category $category)
{
return $category->transactionJournals()->count();
}
/**
* @param Category $category
*
* @param Carbon $start
* @param Carbon $end
*
* @return int
*/
public function countJournalsInRange(Category $category, Carbon $start, Carbon $end)
{
return $category->transactionJournals()->before($end)->after($start)->count();
}
/**
* @param Category $category
*
* @return boolean
*/
public function destroy(Category $category)
{
$category->delete();
return true;
}
/**
* Returns an array with the following key:value pairs:
*
* yyyy-mm-dd:<amount>
*
* Where yyyy-mm-dd is the date and <amount> is the money earned using DEPOSITS in the $category
* from all the users $accounts.
*
* @param Category $category
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedPerDay(Category $category, Carbon $start, Carbon $end)
{
/** @var Collection $query */
$query = $category->transactionJournals()
->transactionTypes([TransactionType::DEPOSIT])
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.amount', '>', 0)
->before($end)
->after($start)
->groupBy('date')->get(['transaction_journals.date as dateFormatted', DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
$return = [];
foreach ($query->toArray() as $entry) {
$return[$entry['dateFormatted']] = $entry['sum'];
}
return $return;
}
/**
* @param Category $category
*
* @return Carbon
*/
public function getFirstActivityDate(Category $category)
{
/** @var TransactionJournal $first */
$first = $category->transactionjournals()->orderBy('date', 'ASC')->first();
if ($first) {
return $first->date;
}
return new Carbon;
}
/**
* @param Category $category
* @param int $page
*
* @return Collection
*/
public function getJournals(Category $category, $page)
{
$offset = $page > 0 ? $page * 50 : 0;
return $category->transactionJournals()->withRelevantData()->take(50)->offset($offset)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->get(
['transaction_journals.*']
);
}
/**
* @param Category $category
* @param int $page
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getJournalsInRange(Category $category, $page, Carbon $start, Carbon $end)
{
$offset = $page > 0 ? $page * 50 : 0;
return $category->transactionJournals()
->after($start)
->before($end)
->withRelevantData()->take(50)->offset($offset)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->get(
['transaction_journals.*']
);
}
/**
* @param Category $category
*
* @return Carbon|null
*/
public function getLatestActivity(Category $category)
{
$latest = $category->transactionjournals()
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC')
->first();
if ($latest) {
return $latest->date;
}
return null;
}
/**
* Returns an array with the following key:value pairs:
*
* yyyy-mm-dd:<amount>
*
* Where yyyy-mm-dd is the date and <amount> is the money spent using DEPOSITS in the $category
* from all the users accounts.
*
* @param Category $category
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentPerDay(Category $category, Carbon $start, Carbon $end)
{
/** @var Collection $query */
$query = $category->transactionJournals()
->transactionTypes([TransactionType::WITHDRAWAL])
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.amount', '<', 0)
->before($end)
->after($start)
->groupBy('date')->get(['transaction_journals.date as dateFormatted', DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
$return = [];
foreach ($query->toArray() as $entry) {
$return[$entry['dateFormatted']] = $entry['sum'];
}
return $return;
}
/**
* @param array $data
*
* @return Category
*/
public function store(array $data)
{
$newCategory = new Category(
[
'user_id' => $data['user'],
'name' => $data['name'],
]
);
$newCategory->save();
return $newCategory;
}
/**
* @param Category $category
* @param array $data
*
* @return Category
*/
public function update(Category $category, array $data)
{
// update the account:
$category->name = $data['name'];
$category->save();
return $category;
}
}

View File

@@ -0,0 +1,122 @@
<?php
namespace FireflyIII\Repositories\Category;
use Carbon\Carbon;
use FireflyIII\Models\Category;
use Illuminate\Support\Collection;
/**
* Interface SingleCategoryRepositoryInterface
*
* @package FireflyIII\Repositories\Category
*/
interface SingleCategoryRepositoryInterface
{
/**
* @param Category $category
*
* @return int
*/
public function countJournals(Category $category);
/**
* @param Category $category
*
* @param Carbon $start
* @param Carbon $end
*
* @return int
*/
public function countJournalsInRange(Category $category, Carbon $start, Carbon $end);
/**
* @param Category $category
*
* @return boolean
*/
public function destroy(Category $category);
/**
* Returns an array with the following key:value pairs:
*
* yyyy-mm-dd:<amount>
*
* Where yyyy-mm-dd is the date and <amount> is the money earned using DEPOSITS in the $category
* from all the users accounts.
*
* @param Category $category
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedPerDay(Category $category, Carbon $start, Carbon $end);
/**
* @param Category $category
*
* @return Carbon
*/
public function getFirstActivityDate(Category $category);
/**
* @param Category $category
* @param int $page
*
* @return Collection
*/
public function getJournals(Category $category, $page);
/**
* @param Category $category
* @param int $page
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getJournalsInRange(Category $category, $page, Carbon $start, Carbon $end);
/**
* @param Category $category
*
* @return Carbon|null
*/
public function getLatestActivity(Category $category);
/**
* Returns an array with the following key:value pairs:
*
* yyyy-mm-dd:<amount>
*
* Where yyyy-mm-dd is the date and <amount> is the money spent using WITHDRAWALS in the $category
* from all the users accounts.
*
* @param Category $category
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentPerDay(Category $category, Carbon $start, Carbon $end);
/**
* @param array $data
*
* @return Category
*/
public function store(array $data);
/**
* @param Category $category
* @param array $data
*
* @return Category
*/
public function update(Category $category, array $data);
}

View File

@@ -44,7 +44,9 @@ class JournalRepository implements JournalRepositoryInterface
*/ */
public function first() public function first()
{ {
return Auth::user()->transactionjournals()->orderBy('date', 'ASC')->first(['transaction_journals.*']); $entry = Auth::user()->transactionjournals()->orderBy('date', 'ASC')->first(['transaction_journals.*']);
return $entry;
} }
/** /**
@@ -164,7 +166,7 @@ class JournalRepository implements JournalRepositoryInterface
[ [
'user_id' => $data['user'], 'user_id' => $data['user'],
'transaction_type_id' => $transactionType->id, 'transaction_type_id' => $transactionType->id,
'transaction_currency_id' => $data['amount_currency_id'], 'transaction_currency_id' => $data['amount_currency_id_amount'],
'description' => $data['description'], 'description' => $data['description'],
'completed' => 0, 'completed' => 0,
'date' => $data['date'], 'date' => $data['date'],
@@ -226,7 +228,7 @@ class JournalRepository implements JournalRepositoryInterface
public function update(TransactionJournal $journal, array $data) public function update(TransactionJournal $journal, array $data)
{ {
// update actual journal. // update actual journal.
$journal->transaction_currency_id = $data['amount_currency_id']; $journal->transaction_currency_id = $data['amount_currency_id_amount'];
$journal->description = $data['description']; $journal->description = $data['description'];
$journal->date = $data['date']; $journal->date = $data['date'];
@@ -327,15 +329,15 @@ class JournalRepository implements JournalRepositoryInterface
$fromAccount = null; $fromAccount = null;
$toAccount = null; $toAccount = null;
switch ($type->type) { switch ($type->type) {
case 'Withdrawal': case TransactionType::WITHDRAWAL:
list($fromAccount, $toAccount) = $this->storeWithdrawalAccounts($data); list($fromAccount, $toAccount) = $this->storeWithdrawalAccounts($data);
break; break;
case 'Deposit': case TransactionType::DEPOSIT:
list($fromAccount, $toAccount) = $this->storeDepositAccounts($data); list($fromAccount, $toAccount) = $this->storeDepositAccounts($data);
break; break;
case 'Transfer': case TransactionType::TRANSFER:
$fromAccount = Account::find($data['account_from_id']); $fromAccount = Account::find($data['account_from_id']);
$toAccount = Account::find($data['account_to_id']); $toAccount = Account::find($data['account_to_id']);
break; break;

View File

@@ -1,149 +0,0 @@
<?php
namespace FireflyIII\Repositories\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Models\PiggyBankRepetition;
/**
* Class PiggyBankPart
*
* @codeCoverageIgnore
* @package FireflyIII\Collection
*/
class PiggyBankPart
{
/** @var float */
public $amountPerBar;
/** @var float */
public $cumulativeAmount;
/** @var float */
public $currentamount;
/** @var PiggyBankRepetition */
public $repetition;
/** @var Carbon */
public $startdate;
/** @var Carbon */
public $targetdate;
/**
* @return PiggyBankRepetition
*/
public function getRepetition()
{
return $this->repetition;
}
/**
* @param PiggyBankRepetition $repetition
*/
public function setRepetition($repetition)
{
$this->repetition = $repetition;
}
/**
* @return Carbon
*/
public function getStartdate()
{
return $this->startdate;
}
/**
* @param Carbon $startdate
*/
public function setStartdate($startdate)
{
$this->startdate = $startdate;
}
/**
* @return Carbon
*/
public function getTargetdate()
{
return $this->targetdate;
}
/**
* @param Carbon $targetdate
*/
public function setTargetdate($targetdate)
{
$this->targetdate = $targetdate;
}
/**
* @return float|int
*/
public function percentage()
{
bcscale(2);
if ($this->getCurrentamount() < $this->getCumulativeAmount()) {
$pct = 0;
// calculate halfway point?
if (bcsub($this->getCumulativeAmount(), $this->getCurrentamount()) < $this->getAmountPerBar()) {
$left = $this->getCurrentamount() % $this->getAmountPerBar();
$pct = round($left / $this->getAmountPerBar() * 100);
}
return $pct;
} else {
return 100;
}
}
/**
* @return float
*/
public function getCurrentamount()
{
return $this->currentamount;
}
/**
* @param float $currentamount
*/
public function setCurrentamount($currentamount)
{
$this->currentamount = $currentamount;
}
/**
* @return float
*/
public function getCumulativeAmount()
{
return $this->cumulativeAmount;
}
/**
* @param float $cumulativeAmount
*/
public function setCumulativeAmount($cumulativeAmount)
{
$this->cumulativeAmount = $cumulativeAmount;
}
/**
* @return float
*/
public function getAmountPerBar()
{
return $this->amountPerBar;
}
/**
* @param float $amountPerBar
*/
public function setAmountPerBar($amountPerBar)
{
$this->amountPerBar = $amountPerBar;
}
}

View File

@@ -3,8 +3,9 @@
namespace FireflyIII\Repositories\Shared; namespace FireflyIII\Repositories\Shared;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Support\CacheProperties; use DB;
use Illuminate\Database\Query\JoinClause; use FireflyIII\Models\TransactionType;
use Illuminate\Support\Collection;
/** /**
* Class ComponentRepository * Class ComponentRepository
@@ -14,49 +15,29 @@ use Illuminate\Database\Query\JoinClause;
class ComponentRepository class ComponentRepository
{ {
/** /**
* @param $object * @param $object
* @param Carbon $start * @param Carbon $start
* @param Carbon $end * @param Carbon $end
* * @param Collection $accounts
* @param bool $shared
* *
* @return string * @return string
*/ */
protected function commonBalanceInPeriod($object, Carbon $start, Carbon $end, $shared = false) protected function commonBalanceInPeriod($object, Carbon $start, Carbon $end, Collection $accounts)
{ {
$cache = new CacheProperties; // we must cache this. $ids = $accounts->pluck('id')->toArray();
$cache->addProperty($object->id);
$cache->addProperty(get_class($object));
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($shared);
$cache->addProperty('balanceInPeriod');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
if ($shared === true) { // shared is true: always ignore transfers between accounts! $entry = $object->transactionjournals()
$sum = $object->transactionjournals()->transactionTypes(['Withdrawal', 'Deposit', 'Opening balance'])->before($end)->after($start) ->transactionTypes([TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE])
->get(['transaction_journals.*'])->sum('amount'); ->before($end)
} else {
// do something else, SEE budgets.
// get all journals in this month where the asset account is NOT shared.
$sum = $object->transactionjournals()->before($end)->after($start)
->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') ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->transactionTypes(['Withdrawal', 'Deposit', 'Opening balance']) ->whereIn('accounts.id', $ids)
->leftJoin( ->after($start)
'account_meta', function (JoinClause $join) { ->first([DB::Raw('SUM(`transactions`.`amount`) as `journalAmount`')]);
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole'); $amount = $entry->journalAmount;
}
)->where('account_meta.data', '!=', '"sharedAsset"')->get(['transaction_journals.*'])->sum('amount');
}
$cache->store($sum); return $amount;
return $sum;
} }
} }

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