Compare commits

...

262 Commits
3.4.7 ... 3.5.2

Author SHA1 Message Date
James Cole
8b9607f9b5 Merge branch 'release/3.5.2' 2015-10-30 07:23:42 +01:00
James Cole
af107ad5e8 New release. 2015-10-30 07:23:33 +01:00
James Cole
8926d62165 Remake of: Merge pull request #111 from colinodell/patch-1
Loosen league/commonmark version
2015-10-30 07:22:39 +01:00
James Cole
45344ee347 Fixed a bug where budget chart would come up negative on overspent amounts. 2015-10-30 07:16:15 +01:00
James Cole
b7dab817f2 Merge pull request #111 from colinodell/patch-1
Loosen league/commonmark version
2015-10-27 12:17:25 +01:00
James Cole
2c966a1234 Fixed ambiguous column. 2015-10-19 15:21:17 +02:00
James Cole
143ea69c0d Fixed the fix (fixeption). 2015-10-19 15:20:18 +02:00
James Cole
8a02ead013 Blind validator update. 2015-10-19 15:16:30 +02:00
James Cole
930d5ab941 Better fix. 2015-10-17 21:15:16 +02:00
James Cole
e54a56d3a8 Experimental chart fix. 2015-10-17 21:14:25 +02:00
James Cole
f5216c0d85 Fixed absolute uri 2015-10-05 20:30:57 +02:00
James Cole
ebc77540b9 Fix some reports. 2015-10-03 22:49:12 +02:00
James Cole
28d2583c10 Remove multiplication. 2015-10-03 22:34:25 +02:00
James Cole
b0988a7b00 Fix zero division. 2015-10-03 22:32:36 +02:00
James Cole
2c4920db2d Fix amount thing. 2015-10-03 22:31:55 +02:00
James Cole
8321663815 Some amount fixes. 2015-10-03 22:29:34 +02:00
James Cole
ac0280d460 Fixed some amounts. 2015-10-03 22:23:42 +02:00
James Cole
ba6f4268f0 Get correct fields. 2015-10-03 17:55:08 +02:00
James Cole
0bd18f94ac Fix ambiguous id. 2015-10-03 17:54:15 +02:00
James Cole
66fb63661f Less journals. 2015-10-03 17:53:13 +02:00
James Cole
d9b16beb0a Added some debug. 2015-10-03 17:51:13 +02:00
James Cole
6a01a9bdfd Fix bill scan. 2015-10-01 07:48:50 +02:00
James Cole
b81b34a706 Fixed amount in bill chart. 2015-10-01 07:46:47 +02:00
James Cole
3750a00b5f Fix amount, make it positive. 2015-09-30 19:43:02 +02:00
James Cole
05ddcc169d Fix amount thing. 2015-09-30 19:41:21 +02:00
James Cole
f571a5f1bd Merge branch 'develop' of https://github.com/JC5/firefly-iii into develop
* 'develop' of https://github.com/JC5/firefly-iii:
  Fixed the other chart too.
  Trying to fix chart.
  New code. Debug.
2015-09-30 19:32:58 +02:00
James Cole
48b786adea Some fixes for amounts. 2015-09-30 19:31:21 +02:00
James Cole
d691fa9b4d Fixed the other chart too. 2015-09-29 09:29:28 +02:00
James Cole
da50f9e419 Trying to fix chart. 2015-09-29 09:28:16 +02:00
James Cole
103de5e18a New code. Debug. 2015-09-29 09:20:50 +02:00
James Cole
dac6efd98b Fix amount in box. 2015-09-28 21:45:11 +02:00
James Cole
46aa7f81b2 Fixed a method call. 2015-09-28 20:41:53 +02:00
James Cole
0683c7cd67 Fixed chart 2015-09-28 14:43:08 +02:00
James Cole
50d7aa7b6a Fix so chart will not display negatives. 2015-09-28 14:32:12 +02:00
James Cole
b781215d0a Date range fixes. 2015-09-27 17:45:01 +02:00
James Cole
866bc2f3bd Cleanup in budgets. 2015-09-27 17:44:49 +02:00
James Cole
49d4705014 Chart was negative. 2015-09-27 09:52:02 +02:00
James Cole
9163fcfccb Quicker amount thing. 2015-09-27 09:47:13 +02:00
James Cole
7e10641461 Organized some category charts. Still needs some translating 2015-09-26 07:18:12 +02:00
James Cole
cdc0e3cfd8 Some cleaning up. 2015-09-25 20:40:24 +02:00
James Cole
466e81d56a Fixed some sorting. 2015-09-25 20:25:22 +02:00
James Cole
5953f691d1 More should fit. 2015-09-25 20:15:38 +02:00
James Cole
e2790ca6c1 Try to limit the collection returned to the user. 2015-09-25 20:13:43 +02:00
James Cole
66dbd48b76 Fix something with the dates. 2015-09-25 19:36:03 +02:00
James Cole
73cfbbd2ba Fix some things so the date range has a better display. 2015-09-25 19:28:39 +02:00
James Cole
38bc38bf26 Add some period things. 2015-09-25 17:28:42 +02:00
James Cole
e12d13c838 Fixed a negative chart. 2015-09-25 16:43:34 +02:00
James Cole
fcc3af6136 Fixed something. 2015-09-25 16:38:36 +02:00
James Cole
491298e1cb Some fixes in titles and bread crumbs. 2015-09-25 16:33:45 +02:00
James Cole
72b5895217 Added a subtitle to the category view. 2015-09-25 16:25:17 +02:00
James Cole
0a8f4017bd Fix some chart things. Again. 2015-09-25 16:18:50 +02:00
James Cole
cb985f5897 Make sure the month chart can show the spent / earned. 2015-09-25 16:08:10 +02:00
James Cole
968ec0853f Fixed the chart. Forgot an argument. 2015-09-25 16:06:06 +02:00
James Cole
0bde72d3df Spent should not be negative for the chart. 2015-09-25 16:04:22 +02:00
James Cole
45293fbd42 Fixes for #109. 2015-09-25 16:00:14 +02:00
Colin O'Dell
72997065f0 Loosen league/commonmark version
See https://github.com/thephpleague/commonmark#versioning
2015-09-19 10:49:55 -04:00
James Cole
a838dc163d I need unit tests again. #109 2015-09-14 17:22:31 +02:00
James Cole
3d15a4ca6d I need unit tests again. #109 2015-09-14 17:20:20 +02:00
James Cole
51c7d4fb1b Properly show spent and earned. #109 2015-09-13 07:40:37 +02:00
James Cole
fa586dba7e Also include all types. 2015-09-13 07:35:53 +02:00
James Cole
8ad40389f2 Corrected the field used for bug #109 2015-09-13 07:34:58 +02:00
James Cole
b3333cc2d3 Experimental fix for issue #109. 2015-09-13 07:32:39 +02:00
James Cole
3699a7ba9a Some cleaning up. 2015-09-08 19:38:04 +02:00
James Cole
204e521ba4 Fixed sorting for contracts. 2015-09-08 19:36:54 +02:00
James Cole
c9bab3e5c3 Tag list show sum. 2015-08-29 08:43:18 +02:00
James Cole
3d00e20238 Fixed a translation. 2015-08-29 08:35:11 +02:00
James Cole
c3958ed3c4 Fixed some bugs that caused inconsistencies in the monthly reports. 2015-08-29 07:20:53 +02:00
James Cole
e5b88be5fa Fix a bug where an transfer to and from a shared asset would count as an expense/income. 2015-08-29 06:48:12 +02:00
James Cole
425552988a Fix month report so transfers from a shared account to another shared account do not count as income. 2015-08-28 06:19:50 +02:00
James Cole
a81dd8abe5 Send search engine spiders away, as suggested in issue #105 2015-08-24 20:11:04 +02:00
James Cole
bac8154a5b Merge branch 'release/3.5.1' 2015-08-23 07:43:02 +02:00
James Cole
737d15fa0e Merge branch 'release/3.5.1' into develop 2015-08-23 07:43:02 +02:00
James Cole
5f2317af7f New version 2015-08-23 07:42:32 +02:00
James Cole
2bd1f783e5 Cleaned up some translations. 2015-08-23 07:41:12 +02:00
James Cole
d6c0c9f963 Cleanup composer. 2015-08-23 07:10:02 +02:00
James Cole
21b6ad7a41 More checks in the bounce cron job. 2015-08-19 19:21:39 +02:00
James Cole
a65d609fdc Fixed bug #104 2015-08-16 21:18:12 +02:00
James Cole
04e676b936 Fix bug #103 2015-08-16 20:27:25 +02:00
James Cole
be8eaaffdf Some code cleanup. 2015-08-16 20:26:11 +02:00
James Cole
28c753523f Caught a nasty bug thanks to an alert Tweakers.net user. This fix will make the account-edit screen inconsistent for a select number of users. This will be detailed on the wiki. 2015-08-15 21:45:29 +02:00
James Cole
7fbd0b2ffc Fixed some inconsistencies in the delete-form. 2015-08-15 21:44:29 +02:00
James Cole
7ffb48a87a New translations 2015-08-15 21:42:45 +02:00
James Cole
d485270e1f Merge branch 'release/3.5.0' 2015-08-13 17:37:55 +02:00
James Cole
5fd688b266 Merge branch 'release/3.5.0' into develop 2015-08-13 17:37:55 +02:00
James Cole
3716668e0c Updated read me. 2015-08-13 17:37:45 +02:00
James Cole
ae7fd18c34 New composer file. 2015-08-13 17:35:48 +02:00
James Cole
4f59b1d32f No Google thing when no Analytics ID present. 2015-08-13 17:35:41 +02:00
James Cole
90cb3279df Better example env file. 2015-08-13 17:34:08 +02:00
James Cole
cf0c7ef6b2 New version. 2015-08-13 17:32:22 +02:00
James Cole
47c23781d9 Fixed password reset. 2015-08-13 17:32:15 +02:00
James Cole
e258c050f7 Merge branch 'release/3.4.11' 2015-08-10 20:13:38 +02:00
James Cole
57801b2f34 Merge branch 'release/3.4.11' into develop 2015-08-10 20:13:38 +02:00
James Cole
710e9c9423 new version. 2015-08-10 20:13:33 +02:00
James Cole
deefef83bd Added sum for the current period, see issue #99 2015-08-09 17:01:12 +02:00
James Cole
51e30aed66 Added a sum of the current page and the sum of the entire category, in reference to issue #99. 2015-08-09 16:56:38 +02:00
James Cole
8d109a3cfe Fixed a null pointer exception. 2015-08-09 13:54:58 +02:00
James Cole
3424e019b5 Removed animation, again [skip ci] 2015-08-06 16:39:53 +02:00
James Cole
c6b4bceb67 Animation test [skip ci] 2015-08-06 16:39:06 +02:00
James Cole
afb4155015 Remove animation thing. [skip ci] 2015-08-06 16:37:53 +02:00
James Cole
8d99baf38a Update charts.js 2015-08-05 09:02:33 +02:00
James Cole
b91cb60328 Fix translations [skip ci] 2015-08-02 09:01:13 +02:00
James Cole
c0d62237fc Made the date thing throw a FF error. 2015-08-02 08:53:34 +02:00
James Cole
223ea80860 Fixed some embarrassing spelling errors in the CSV importer. [skip ci] 2015-08-02 08:53:19 +02:00
James Cole
5a77bef494 Sort chart and code cleanup [skip ci] 2015-08-02 07:41:47 +02:00
James Cole
80c0efe821 Small rearrangement of front page boxes. [skip ci] 2015-08-02 07:35:09 +02:00
James Cole
8044d89557 Display correct amount [skip ci] 2015-08-02 07:08:47 +02:00
James Cole
4f0ed97410 Fixed a bug where the category list in a monthly report would be empty. 2015-08-02 07:04:43 +02:00
James Cole
af7952f204 Removed old references to Google [skip ci] 2015-08-01 07:22:48 +02:00
James Cole
d8dcae856b Remove log. 2015-08-01 07:12:34 +02:00
James Cole
7296796ed9 Fix chart. 2015-08-01 07:12:03 +02:00
James Cole
a2c2bb4948 Forgot a dot [skip ci] 2015-08-01 07:09:51 +02:00
James Cole
72ebfdc20e Debug log. 2015-08-01 07:09:12 +02:00
James Cole
16b95ea78a New chart. 2015-08-01 07:04:41 +02:00
James Cole
c04f08dfd8 Filter empty budgets. 2015-07-31 18:18:54 +02:00
James Cole
a30793e818 Fix chart. Related to #99 2015-07-31 18:14:24 +02:00
James Cole
e39e1eaf21 Included opening balance. 2015-07-31 18:10:55 +02:00
James Cole
ab22d2cbaa Fixed the overview chart for categories, so it will properly reflect income and expenses. See bug #99 2015-07-31 14:26:22 +02:00
James Cole
96ddbe7227 Reorganized the category charts in the year report to properly reflect income and expenses. Necessary to facilitate the changes needed for bug #99 2015-07-31 14:20:18 +02:00
James Cole
4d09235aef Update composer.lock 2015-07-31 14:17:49 +02:00
James Cole
136b8975e3 Sort piggy bank list. 2015-07-31 13:44:56 +02:00
James Cole
e21b1eca17 Remove script. 2015-07-31 07:31:05 +02:00
James Cole
244b90b1d4 Fix bug #98 2015-07-30 21:32:58 +02:00
James Cole
b318f3f940 Merge branch 'release/3.4.10' 2015-07-27 21:23:20 +02:00
James Cole
e211c9812e Fixed some math things. 2015-07-26 19:42:28 +02:00
James Cole
eef28d96f4 Code cleanup [skip ci] 2015-07-26 19:13:06 +02:00
James Cole
c8227e09ee id was ambiguous. 2015-07-26 19:10:31 +02:00
James Cole
3e05fd91d9 Lots of cleaning up. 2015-07-26 19:07:02 +02:00
James Cole
450baba56a Removed some dead code and fixed some other. 2015-07-26 17:03:05 +02:00
James Cole
17a8c4918c Code cleanup. 2015-07-26 15:51:07 +02:00
James Cole
0e2419d61a New translations [skip ci] 2015-07-26 09:44:31 +02:00
James Cole
79b1a2ca6d Gave cron controller a new line. [skip ci] 2015-07-26 07:42:34 +02:00
James Cole
2213c68155 Added a missing breadcrumb. 2015-07-26 07:41:10 +02:00
James Cole
2492b1fa96 Expanded the message a user may get when his credentials do not work. 2015-07-26 07:39:21 +02:00
James Cole
6c6598dac5 Lots of new translations. 2015-07-26 07:39:04 +02:00
James Cole
a137112e66 New read me. 2015-07-25 19:28:19 +02:00
James Cole
8642ae8180 New version. 2015-07-25 19:27:14 +02:00
James Cole
894c4dc5a7 New composer.lock. 2015-07-25 19:24:07 +02:00
James Cole
d96063ea6e Also expand interface. 2015-07-25 19:23:00 +02:00
James Cole
c3dc193f3e First attempt at new last activity thing. 2015-07-25 19:22:41 +02:00
James Cole
3c2952009e Some new stuff. 2015-07-25 19:04:39 +02:00
James Cole
f4ade470df Remove if statements. 2015-07-25 18:48:48 +02:00
James Cole
2e33b43389 CSS and invalid account warning. 2015-07-25 18:40:45 +02:00
James Cole
92799699bc Better attachment handling. 2015-07-25 18:33:19 +02:00
James Cole
7ab0508167 Some new translations. 2015-07-25 18:31:05 +02:00
James Cole
3c65c28936 Some translations. 2015-07-25 16:48:32 +02:00
James Cole
43892da07e may edit fields [skip ci] 2015-07-25 07:05:27 +02:00
James Cole
7c436920a4 Some formatting and translations. [skip ci] 2015-07-25 07:04:09 +02:00
James Cole
89d565e63b Check for block code. [skip ci] 2015-07-25 07:03:50 +02:00
James Cole
150b6fe5b6 Add block code [skip ci] 2015-07-25 07:03:42 +02:00
James Cole
0e77574c26 Also give block code. [skip ci] 2015-07-25 07:03:35 +02:00
James Cole
df23863443 Remove bounce error thing. 2015-07-24 22:08:38 +02:00
James Cole
581bf11b21 Fixed a translation [skip ci] 2015-07-24 13:34:22 +02:00
James Cole
d602d4b429 Add some debug logging. 2015-07-24 13:26:42 +02:00
James Cole
d1d4a52934 Catch empty send grid credentials. 2015-07-24 13:23:02 +02:00
James Cole
375d113769 Find users not already blocked only. 2015-07-24 13:20:09 +02:00
James Cole
9b83974bff Improve the cron controller. Force blocked users to logout. 2015-07-24 13:17:47 +02:00
James Cole
3c68c99bd5 Fixed some translations. 2015-07-24 09:03:40 +02:00
James Cole
ec4b37c596 Updated chart. 2015-07-24 08:36:49 +02:00
James Cole
ba9601d21c Better display for piggy bank events. 2015-07-24 08:34:30 +02:00
James Cole
50c13fd469 Clear cache. 2015-07-22 22:13:40 +02:00
James Cole
7af072b8fc Show message. 2015-07-22 19:35:39 +02:00
James Cole
faa128d41e Made a cron controller. 2015-07-22 19:09:17 +02:00
James Cole
868fe46932 Some more debug stuff. 2015-07-22 18:44:51 +02:00
James Cole
e9e4307ce5 Better debug. 2015-07-22 18:09:14 +02:00
James Cole
774d4844a9 Another try to fix csrf 2015-07-22 17:58:06 +02:00
James Cole
586c53e670 Remove CSRF check. 2015-07-22 17:52:55 +02:00
James Cole
68e073fbff A new controller that can be used in combination with SendGrid. 2015-07-22 17:50:02 +02:00
James Cole
8101dc37b1 New route for attachment preview. 2015-07-19 22:19:36 +02:00
James Cole
63f16c458d Small fixes for piggy banks data seed. 2015-07-19 22:19:26 +02:00
James Cole
821e007e95 If zero, other thing. 2015-07-19 18:39:06 +02:00
James Cole
1656a2f11a Experimenting with a preview for attachments. 2015-07-19 18:37:29 +02:00
James Cole
4dbc135dce Added max file size for uploads. 2015-07-19 14:30:20 +02:00
James Cole
fc886f6bc1 Seed some tags. 2015-07-19 13:46:41 +02:00
James Cole
f93e480466 Better notifications. 2015-07-19 13:46:34 +02:00
James Cole
fe807e23f8 Fixed sorting in tags. 2015-07-19 13:46:20 +02:00
James Cole
ecf61c31f1 Add new line to file. 2015-07-19 12:23:27 +02:00
James Cole
4feff18af5 Fix test data. 2015-07-19 12:21:51 +02:00
James Cole
a07c52e0d8 Fix some route names. 2015-07-19 12:21:38 +02:00
James Cole
7bb07d7f55 Add non-breaking space to fix issue #95. 2015-07-19 12:20:35 +02:00
James Cole
f12dfc8a14 Icons for attachments. 2015-07-19 11:47:56 +02:00
James Cole
be030f15c4 New composer.lock. 2015-07-19 09:57:26 +02:00
James Cole
f5fb6c063b Also delete attachments. 2015-07-19 09:53:58 +02:00
James Cole
fb722f06b9 Some added newlines. 2015-07-19 09:38:44 +02:00
James Cole
c0ea19e15e Test data no longer runs into the future. 2015-07-19 09:37:52 +02:00
James Cole
cdeb1ad87c Some model updates. 2015-07-19 09:37:37 +02:00
James Cole
0dbe4e94fa Allow to edit an attachment. 2015-07-19 09:37:28 +02:00
James Cole
b5e2e8aa1d Edit attachment page. 2015-07-18 23:51:51 +02:00
James Cole
9502010248 Some new routes. 2015-07-18 23:06:51 +02:00
James Cole
fea0557b47 Going to allow edit of attachment. 2015-07-18 22:49:27 +02:00
James Cole
ed4fcc9011 Some optimisation. 2015-07-18 22:17:31 +02:00
James Cole
ed12ea7cfb Check for double files and some code clean up. 2015-07-18 21:46:16 +02:00
James Cole
73e526645e Uncomment providers. 2015-07-18 21:33:52 +02:00
James Cole
72aeafb2b5 Some model code block updates 2015-07-18 21:33:10 +02:00
James Cole
cc1af60cb4 Basic attachment download function. 2015-07-18 21:32:31 +02:00
James Cole
359fab315f A fix in the model and a simple view for attachments. 2015-07-18 21:12:34 +02:00
James Cole
6a9574bab9 Allow jpeg and PDF. 2015-07-18 19:49:35 +02:00
James Cole
83d6158483 Basic upload working. 2015-07-18 09:49:59 +02:00
James Cole
63ef89b6cc Basic interface for upload. 2015-07-18 09:49:29 +02:00
James Cole
b0beab4cd3 Attachment model and database changes. 2015-07-18 09:49:19 +02:00
James Cole
a34782575f Fix form and upload thing. 2015-07-18 08:59:33 +02:00
James Cole
142bdc9430 Add attachment thing to upload form. 2015-07-17 21:45:58 +02:00
James Cole
14b79cb0a4 Fixed a bug where deposits and/or transfers would be assigned budgets if you had selected a budget at the withdrawal screen earlier. 2015-07-17 21:03:13 +02:00
James Cole
ce5beeaf2c Better compare for amounts because floatval can be inaccurate. 2015-07-17 17:35:04 +02:00
James Cole
31114a2ca5 Fixed a bug where tags would be recreated instead of "found". 2015-07-17 17:34:49 +02:00
James Cole
32528094ad Updated composer file. 2015-07-16 20:39:20 +02:00
James Cole
0a2a01c44c Code reformat. 2015-07-15 21:06:26 +02:00
James Cole
c1888dc3ac Merge branch 'release/3.4.9' 2015-07-15 21:02:36 +02:00
James Cole
4d76afbe01 Merge branch 'release/3.4.9' into develop 2015-07-15 21:02:36 +02:00
James Cole
76d7a97f93 New release with all changes so far. Change log coming soon. 2015-07-15 21:02:27 +02:00
James Cole
8b1366b20a Merge pull request #93 from RonaldvanMeer/master
fix issue #91
2015-07-15 21:00:29 +02:00
RonaldvanMeer
e0f9685578 Spacing fixes 2015-07-15 12:29:11 +02:00
RonaldvanMeer
5235657954 Fixing missing IBAN field on Create New User request 2015-07-15 12:25:09 +02:00
James Cole
a15fbc8094 Now committing to correct branch. 2015-07-14 22:48:34 +02:00
James Cole
546f1d9c50 Revert "Some login and session updates."
This reverts commit 74231f552a.
2015-07-14 22:45:14 +02:00
James Cole
74231f552a Some login and session updates. 2015-07-14 22:45:00 +02:00
James Cole
b250a10e3c Merge branch 'release/3.4.8'
Conflicts:
	resources/twig/auth/login.twig
	resources/twig/auth/password.twig
	resources/twig/auth/register.twig
2015-07-12 22:45:37 +02:00
James Cole
a9f1b31dd6 New version. 2015-07-12 22:43:43 +02:00
James Cole
7fe393acaf Updated composer.lock. 2015-07-12 22:43:01 +02:00
James Cole
04faba4db5 Fix URL things. 2015-07-12 22:37:05 +02:00
James Cole
91bba40c20 Cleanup code. 2015-07-12 17:59:13 +02:00
James Cole
79e39f7de8 Code cleanup. 2015-07-12 17:36:38 +02:00
James Cole
9c09353559 Some improvements in tour 2015-07-12 12:45:41 +02:00
James Cole
50752a5bfe Implemented a short tour. 2015-07-11 10:01:13 +02:00
James Cole
d59879db7d Add bootstrap tour references. 2015-07-11 08:37:21 +02:00
James Cole
aab125da27 Add bootstrap tour files. 2015-07-11 08:36:46 +02:00
James Cole
74fc731f96 Full Bootstrap. 2015-07-11 08:35:51 +02:00
James Cole
bd0050fec2 Fix balance display. 2015-07-10 20:59:20 +02:00
James Cole
aa5e313b92 Save transactions by moving them. 2015-07-10 20:48:45 +02:00
James Cole
e89d613b7e Removed confidential data from logging routine. [skip ci] 2015-07-10 20:25:17 +02:00
James Cole
8757929ead Make log [skip ci] 2015-07-10 20:19:31 +02:00
James Cole
e0a9b19802 Some new translations and what-not. 2015-07-10 20:17:17 +02:00
James Cole
308da6dc6e Clean up some lists [skip ci] 2015-07-10 07:39:59 +02:00
James Cole
b6960fb0e5 Small layout and translation fixes [skip ci] 2015-07-10 05:39:35 +02:00
James Cole
137208c3fd Typical. 2015-07-09 21:59:02 +02:00
James Cole
d7a9a62a1d Should fix some scrutinyizer problems. 2015-07-09 21:48:05 +02:00
James Cole
075315bdaa Added some model thingies so scrutinizer will stop whining. 2015-07-09 21:29:30 +02:00
James Cole
3948fcd614 Added newlines to files. 2015-07-09 21:26:40 +02:00
James Cole
8e61e129ab More debug, some bug fixes. 2015-07-09 19:36:14 +02:00
James Cole
20cffd0502 Fixed Rabo importer. 2015-07-09 19:23:49 +02:00
James Cole
5df09dab09 Put specifix in json. 2015-07-09 19:05:59 +02:00
James Cole
7446b911e5 Logging in Rabo specifix. 2015-07-09 19:03:39 +02:00
James Cole
f15267c1ab Better import feedback. 2015-07-09 18:38:15 +02:00
James Cole
9c9fc2b5dc Some fixes in csv importer. 2015-07-09 18:33:09 +02:00
James Cole
28f601b54b Import fix asset account. 2015-07-09 16:37:42 +02:00
James Cole
18b8a05014 Extra logging. 2015-07-09 16:07:05 +02:00
James Cole
910c995ed8 Log account id. [skip ci] 2015-07-09 16:03:47 +02:00
James Cole
498468aa2c Display error. [skip ci] 2015-07-09 15:39:41 +02:00
James Cole
637aebcb34 Bug fix for importer. [skip ci] 2015-07-09 15:36:56 +02:00
James Cole
9afd5cb277 Fix specific [skip ci] 2015-07-09 15:27:40 +02:00
James Cole
bc525e7272 Date format in config downloader. [skip ci] 2015-07-09 15:25:24 +02:00
James Cole
a80180780d Use log [skip ci] 2015-07-09 15:21:34 +02:00
James Cole
0d73086c37 More logging [skip ci] 2015-07-09 15:20:55 +02:00
James Cole
02ae39238d Forgot one iban key. 2015-07-09 14:04:01 +02:00
James Cole
43d6b51d42 Some cleaning up [skip ci] 2015-07-09 11:13:38 +02:00
James Cole
84566310de Cleaned up model comments. 2015-07-09 09:42:09 +02:00
James Cole
6a6ec9fbe4 Cleaned up some bill related code. 2015-07-09 09:41:54 +02:00
James Cole
84a7f825d7 Some small code optimisations. 2015-07-09 06:13:39 +02:00
James Cole
0372c1aaf1 Small fix to make account journal list sortable. [skip ci] 2015-07-08 20:18:51 +02:00
James Cole
c9fff197f7 Some improved sorting. 2015-07-08 13:11:51 +02:00
James Cole
6900392e43 Fixed some sorting. 2015-07-08 13:05:33 +02:00
James Cole
c00bcd78cc Some dependency clean up. 2015-07-07 19:09:45 +02:00
James Cole
3de57c668f Merge branch 'release/3.4.7' into develop 2015-07-07 11:12:30 +02:00
266 changed files with 6967 additions and 5351 deletions

View File

@@ -1 +1 @@
src_dir: .
src_dir: .

View File

@@ -1,6 +1,6 @@
APP_ENV=production
APP_DEBUG=false
APP_KEY=SomeRandomString
APP_KEY=SomeRandomStringOf32CharsExactly
DB_CONNECTION=mysql
DB_HOST=localhost
@@ -18,4 +18,7 @@ EMAIL_PASSWORD=
ANALYTICS_ID=
EMAIL_PRETEND=false
RUNCLEANUP=true
SITE_OWNER=mail@example.com
SITE_OWNER=mail@example.com
SENDGRID_USERNAME=
SENDGRID_PASSWORD=

2
.gitignore vendored
View File

@@ -33,4 +33,4 @@ addNewLines.php
.env.local
tests/_output/*
tests/_output/*
tests/_output/*

View File

@@ -1,3 +1,3 @@
# .scrutinizer.yml
tools:
external_code_coverage: false
external_code_coverage: false

View File

@@ -82,7 +82,7 @@ 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)**.
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.
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.
## Credits
@@ -90,6 +90,7 @@ Firefly III uses the following libraries and tools:
* The AdminLTE template by [Almsaseed Studio](https://almsaeedstudio.com/)
* The [Google charts](https://developers.google.com/chart/) library.
* [Chart.js](http://www.chartjs.org/)
* [Bootstrap](http://getbootstrap.com/)
* [Laravel](http://laravel.com/)
* [Twig](http://twig.sensiolabs.org/)

View File

@@ -40,4 +40,13 @@ interface AccountChartGenerator
* @return array
*/
public function single(Account $account, Carbon $start, Carbon $end);
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end);
}

View File

@@ -32,6 +32,69 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
return $this->frontpage($accounts, $start, $end);
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function expenseAccounts(Collection $accounts, Carbon $start, Carbon $end)
{
$data = [
'count' => 1,
'labels' => [], 'datasets' => [[
'label' => trans('firefly.spent'),
'data' => []]]];
bcscale(2);
$start->subDay();
$ids = $this->getIdsFromCollection($accounts);
$startBalances = Steam::balancesById($ids, $start);
$endBalances = Steam::balancesById($ids, $end);
$accounts->each(
function (Account $account) use ($startBalances, $endBalances) {
$id = $account->id;
$startBalance = $this->isInArray($startBalances, $id);
$endBalance = $this->isInArray($endBalances, $id);
$diff = bcsub($endBalance, $startBalance);
$account->difference = round($diff, 2);
}
);
$accounts = $accounts->sortByDesc(
function (Account $account) {
return $account->difference;
}
);
foreach ($accounts as $account) {
if ($account->difference > 0) {
$data['labels'][] = $account->name;
$data['datasets'][0]['data'][] = $account->difference;
}
}
return $data;
}
/**
* @param $array
* @param $entryId
*
* @return string
*/
protected function isInArray($array, $entryId)
{
if (isset($array[$entryId])) {
return $array[$entryId];
}
return '0';
}
/**
* @param Collection $accounts
* @param Carbon $start
@@ -112,4 +175,20 @@ class ChartJsAccountChartGenerator implements AccountChartGenerator
return $data;
}
/**
* @param Collection $collection
*
* @return array
*/
protected function getIdsFromCollection(Collection $collection)
{
$ids = [];
foreach ($collection as $entry) {
$ids[] = $entry->id;
}
return array_unique($ids);
}
}

View File

@@ -1,97 +0,0 @@
<?php
namespace FireflyIII\Generator\Chart\Account;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
use Steam;
/**
* Class GoogleAccountChartGenerator
*
* @package FireflyIII\Generator\Chart\Account
*/
class GoogleAccountChartGenerator implements AccountChartGenerator
{
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function all(Collection $accounts, Carbon $start, Carbon $end)
{
// make chart (original code):
$chart = new GChart;
$chart->addColumn(trans('firefly.dayOfMonth'), 'date');
$index = 1;
/** @var Account $account */
foreach ($accounts as $account) {
$chart->addColumn(trans('firefly.balanceFor', ['name' => $account->name]), 'number');
$chart->addCertainty($index);
$index++;
}
$current = clone $start;
$current->subDay();
$today = Carbon::now();
while ($end >= $current) {
$row = [clone $current];
$certain = $current < $today;
foreach ($accounts as $account) {
$row[] = Steam::balance($account, $current);
$row[] = $certain;
}
$chart->addRowArray($row);
$current->addDay();
}
$chart->generate();
return $chart->getData();
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function frontpage(Collection $accounts, Carbon $start, Carbon $end)
{
return $this->all($accounts, $start, $end);
}
/**
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function single(Account $account, Carbon $start, Carbon $end)
{
$current = clone $start;
$today = new Carbon;
$chart = new GChart;
$chart->addColumn(trans('firefly.dayOfMonth'), 'date');
$chart->addColumn(trans('firefly.balanceFor', ['name' => $account->name]), 'number');
$chart->addCertainty(1);
while ($end >= $current) {
$certain = $current < $today;
$chart->addRow(clone $current, Steam::balance($account, $current), $certain);
$current->addDay();
}
$chart->generate();
return $chart->getData();
}
}

View File

@@ -33,12 +33,12 @@ class ChartJsBillChartGenerator implements BillChartGenerator
/** @var TransactionJournal $entry */
foreach ($paid as $entry) { // loop paid and create single entry:
$paidDescriptions[] = $entry->description;
$paidAmount = bcadd($paidAmount, $entry->amount);
$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 = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
$amount = bcdiv(bcadd($entry[0]->amount_max, $entry[0]->amount_min), 2);
$unpaidDescriptions[] = $description;
$unpaidAmount = bcadd($unpaidAmount, $amount);
unset($amount, $description);
@@ -91,7 +91,7 @@ class ChartJsBillChartGenerator implements BillChartGenerator
$data['labels'][] = $entry->date->formatLocalized($format);
$minAmount[] = round($bill->amount_min, 2);
$maxAmount[] = round($bill->amount_max, 2);
$actualAmount[] = round($entry->amount, 2);
$actualAmount[] = round(($entry->amount * -1), 2);
}
$data['datasets'][] = [

View File

@@ -1,93 +0,0 @@
<?php
namespace FireflyIII\Generator\Chart\Bill;
use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionJournal;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
/**
* Class GoogleBillChartGenerator
*
* @package FireflyIII\Generator\Chart\Bill
*/
class GoogleBillChartGenerator implements BillChartGenerator
{
/**
* @param Collection $paid
* @param Collection $unpaid
*
* @return array
*/
public function frontpage(Collection $paid, Collection $unpaid)
{
// loop paid and create single entry:
$paidDescriptions = [];
$paidAmount = 0;
$unpaidDescriptions = [];
$unpaidAmount = 0;
bcscale(2);
/** @var TransactionJournal $entry */
foreach ($paid as $entry) {
$paidDescriptions[] = $entry->description;
$paidAmount = bcadd($paidAmount, $entry->amount);
}
// loop unpaid:
/** @var Bill $entry */
foreach ($unpaid as $entry) {
$description = $entry[0]->name . ' (' . $entry[1]->format('jS M Y') . ')';
$amount = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
$unpaidDescriptions[] = $description;
$unpaidAmount = bcadd($unpaidAmount, $amount);
unset($amount, $description);
}
$chart = new GChart;
$chart->addColumn(trans('firefly.name'), 'string');
$chart->addColumn(trans('firefly.amount'), 'number');
$chart->addRow(trans('firefly.unpaid') . ': ' . join(', ', $unpaidDescriptions), $unpaidAmount);
$chart->addRow(trans('firefly.paid') . ': ' . join(', ', $paidDescriptions), $paidAmount);
$chart->generate();
return $chart->getData();
}
/**
* @param Bill $bill
* @param Collection $entries
*
* @return mixed
*/
public function single(Bill $bill, Collection $entries)
{
// make chart:
$chart = new GChart;
$chart->addColumn(trans('firefly.date'), 'date');
$chart->addColumn(trans('firefly.maxAmount'), 'number');
$chart->addColumn(trans('firefly.minAmount'), 'number');
$chart->addColumn(trans('firefly.billEntry'), 'number');
/** @var TransactionJournal $result */
foreach ($entries as $result) {
$chart->addRow(
clone $result->date,
floatval($bill->amount_max),
floatval($bill->amount_min),
floatval($result->amount));
}
$chart->generate();
return $chart->getData();
}
}

View File

@@ -1,102 +0,0 @@
<?php
namespace FireflyIII\Generator\Chart\Budget;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
/**
* Class GoogleBudgetChartGenerator
*
* @package FireflyIII\Generator\Chart\Budget
*/
class GoogleBudgetChartGenerator implements BudgetChartGenerator
{
/**
* @param Collection $entries
*
* @return array
*/
public function budget(Collection $entries)
{
$chart = new GChart;
$chart->addColumn(trans('firefly.period'), 'date');
$chart->addColumn(trans('firefly.spent'), 'number');
/** @var array $entry */
foreach ($entries as $entry) {
$chart->addRow($entry[0], $entry[1]);
}
$chart->generate();
return $chart->getData();
}
/**
* @codeCoverageIgnore
*
* @param Collection $entries
*
* @return array
*/
public function budgetLimit(Collection $entries)
{
return $this->budget($entries);
}
/**
* @param Collection $entries
*
* @return array
*/
public function frontpage(Collection $entries)
{
$chart = new GChart;
$chart->addColumn(trans('firefly.budget'), 'string');
$chart->addColumn(trans('firefly.left'), 'number');
$chart->addColumn(trans('firefly.spent'), 'number');
$chart->addColumn(trans('firefly.overspent'), 'number');
/** @var array $entry */
foreach ($entries as $entry) {
if ($entry[1] != 0 || $entry[2] != 0 || $entry[3] != 0) {
$chart->addRow($entry[0], $entry[1], $entry[2], $entry[3]);
}
}
$chart->generate();
return $chart->getData();
}
/**
* @param Collection $budgets
* @param Collection $entries
*
* @return array
*/
public function year(Collection $budgets, Collection $entries)
{
$chart = new GChart;
// add columns:
$chart->addColumn(trans('firefly.month'), 'date');
foreach ($budgets as $budget) {
$chart->addColumn($budget->name, 'number');
}
/** @var array $entry */
foreach ($entries as $entry) {
$chart->addRowArray($entry);
}
$chart->generate();
return $chart->getData();
}
}

View File

@@ -31,7 +31,7 @@ interface CategoryChartGenerator
*
* @return array
*/
public function month(Collection $entries);
public function period(Collection $entries);
/**
@@ -40,5 +40,13 @@ interface CategoryChartGenerator
*
* @return array
*/
public function year(Collection $categories, Collection $entries);
public function spentInYear(Collection $categories, Collection $entries);
/**
* @param Collection $categories
* @param Collection $entries
*
* @return array
*/
public function earnedInYear(Collection $categories, Collection $entries);
}

View File

@@ -17,31 +17,35 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
/**
* @param Collection $entries
* @param string $dateFormat
*
* @return array
*/
public function all(Collection $entries, $dateFormat = 'month')
public function all(Collection $entries)
{
// language:
$language = Preferences::get('language', 'en')->data;
$format = Config::get('firefly.' . $dateFormat . '.' . $language);
$data = [
'count' => 1,
'count' => 2,
'labels' => [],
'datasets' => [
[
'label' => trans('firefly.spent'),
'data' => []
],
[
'label' => trans('firefly.earned'),
'data' => []
]
],
];
foreach ($entries as $entry) {
$data['labels'][] = $entry[0]->formatLocalized($format);
$data['datasets'][0]['data'][] = round($entry[1], 2);
$data['labels'][] = $entry[1];
$spent = round($entry[2], 2);
$earned = round($entry[3], 2);
$data['datasets'][0]['data'][] = $spent == 0 ? null : $spent * -1;
$data['datasets'][1]['data'][] = $earned == 0 ? null : $earned;
}
return $data;
@@ -67,7 +71,7 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
foreach ($entries as $entry) {
if ($entry['sum'] != 0) {
$data['labels'][] = $entry['name'];
$data['datasets'][0]['data'][] = round($entry['sum'], 2);
$data['datasets'][0]['data'][] = round(($entry['sum'] * -1), 2);
}
}
@@ -81,9 +85,9 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
*
* @return array
*/
public function month(Collection $entries)
public function period(Collection $entries)
{
return $this->all($entries, 'monthAndDay');
return $this->all($entries);
}
@@ -93,7 +97,41 @@ class ChartJsCategoryChartGenerator implements CategoryChartGenerator
*
* @return array
*/
public function year(Collection $categories, Collection $entries)
public function spentInYear(Collection $categories, Collection $entries)
{
// language:
$language = Preferences::get('language', 'en')->data;
$format = Config::get('firefly.month.' . $language);
$data = [
'count' => 0,
'labels' => [],
'datasets' => [],
];
foreach ($categories as $category) {
$data['labels'][] = $category->name;
}
foreach ($entries as $entry) {
$date = $entry[0]->formatLocalized($format);
array_shift($entry);
$data['count']++;
$data['datasets'][] = ['label' => $date, 'data' => $entry];
}
return $data;
}
/**
* @param Collection $categories
* @param Collection $entries
*
* @return array
*/
public function earnedInYear(Collection $categories, Collection $entries)
{
// language:

View File

@@ -1,106 +0,0 @@
<?php
namespace FireflyIII\Generator\Chart\Category;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
/**
* Class GoogleCategoryChartGenerator
*
* @package FireflyIII\Generator\Chart\Category
*/
class GoogleCategoryChartGenerator implements CategoryChartGenerator
{
/**
* @param Collection $entries
*
* @return array
*/
public function all(Collection $entries)
{
$chart = new GChart;
$chart->addColumn(trans('firefly.period'), 'date');
$chart->addColumn(trans('firefly.spent'), 'number');
/** @var array $entry */
foreach ($entries as $entry) {
$chart->addRow($entry[0], $entry[1]);
}
$chart->generate();
return $chart->getData();
}
/**
* @param Collection $entries
*
* @return array
*/
public function frontpage(Collection $entries)
{
$chart = new GChart;
$chart->addColumn(trans('firefly.category'), 'string');
$chart->addColumn(trans('firefly.spent'), 'number');
/** @var array $entry */
foreach ($entries as $entry) {
$sum = $entry['sum'];
if ($sum != 0) {
$chart->addRow($entry['name'], $sum);
}
}
$chart->generate();
return $chart->getData();
}
/**
* @param Collection $entries
*
* @return array
*/
public function month(Collection $entries)
{
$chart = new GChart;
$chart->addColumn(trans('firefly.period'), 'date');
$chart->addColumn(trans('firefly.spent'), 'number');
/** @var array $entry */
foreach ($entries as $entry) {
$chart->addRow($entry[0], $entry[1]);
}
$chart->generate();
return $chart->getData();
}
/**
* @param Collection $categories
* @param Collection $entries
*
* @return array
*/
public function year(Collection $categories, Collection $entries)
{
$chart = new GChart;
$chart->addColumn(trans('firefly.month'), 'date');
foreach ($categories as $category) {
$chart->addColumn($category->name, 'number');
}
/** @var array $entry */
foreach ($entries as $entry) {
$chart->addRowArray($entry);
}
$chart->generate();
return $chart->getData();
}
}

View File

@@ -9,7 +9,7 @@ use Preferences;
/**
* Class GooglePiggyBankChartGenerator
* Class ChartJsPiggyBankChartGenerator
*
* @package FireflyIII\Generator\Chart\PiggyBank
*/
@@ -26,7 +26,7 @@ class ChartJsPiggyBankChartGenerator implements PiggyBankChartGenerator
// language:
$language = Preferences::get('language', 'en')->data;
$format = Config::get('firefly.month.' . $language);
$format = Config::get('firefly.monthAndDay.' . $language);
$data = [
'count' => 1,

View File

@@ -1,41 +0,0 @@
<?php
namespace FireflyIII\Generator\Chart\PiggyBank;
use Carbon\Carbon;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
/**
* Class GooglePiggyBankChartGenerator
*
* @package FireflyIII\Generator\Chart\PiggyBank
*/
class GooglePiggyBankChartGenerator implements PiggyBankChartGenerator
{
/**
* @param Collection $set
*
* @return array
*/
public function history(Collection $set)
{
$chart = new GChart;
$chart->addColumn(trans('firefly.date'), 'date');
$chart->addColumn(trans('firefly.balance'), 'number');
$sum = '0';
bcscale(2);
foreach ($set as $entry) {
$sum = bcadd($sum, $entry->sum);
$chart->addRow(new Carbon($entry->date), $sum);
}
$chart->generate();
return $chart->getData();
}
}

View File

@@ -7,7 +7,7 @@ use Illuminate\Support\Collection;
use Preferences;
/**
* Class GoogleReportChartGenerator
* Class ChartJsReportChartGenerator
*
* @package FireflyIII\Generator\Chart\Report
*/
@@ -61,7 +61,7 @@ class ChartJsReportChartGenerator implements ReportChartGenerator
$data = [
'count' => 2,
'labels' => [],
'labels' => [trans('firefly.sum_of_year'), trans('firefly.average_of_year')],
'datasets' => [
[
'label' => trans('firefly.income'),
@@ -74,9 +74,9 @@ class ChartJsReportChartGenerator implements ReportChartGenerator
],
];
$data['datasets'][0]['data'][] = round($income, 2);
$data['datasets'][1]['data'][] = round($expense, 2);
$data['datasets'][1]['data'][] = round( $expense, 2);
$data['datasets'][0]['data'][] = round(($income / $count), 2);
$data['datasets'][1]['data'][] = round(($expense / $count), 2);
$data['datasets'][1]['data'][] = round(( $expense / $count), 2);
return $data;
}

View File

@@ -1,58 +0,0 @@
<?php
namespace FireflyIII\Generator\Chart\Report;
use Grumpydictator\Gchart\GChart;
use Illuminate\Support\Collection;
/**
* Class GoogleReportChartGenerator
*
* @package FireflyIII\Generator\Chart\Report
*/
class GoogleReportChartGenerator implements ReportChartGenerator
{
/**
* @param Collection $entries
*
* @return array
*/
public function yearInOut(Collection $entries)
{
$chart = new GChart;
$chart->addColumn(trans('firefly.month'), 'date');
$chart->addColumn(trans('firefly.income'), 'number');
$chart->addColumn(trans('firefly.expenses'), 'number');
/** @var array $entry */
foreach ($entries as $entry) {
$chart->addRowArray($entry);
}
$chart->generate();
return $chart->getData();
}
/**
* @param string $income
* @param string $expense
* @param int $count
*
* @return array
*/
public function yearInOutSummarized($income, $expense, $count)
{
$chart = new GChart;
$chart->addColumn(trans('firefly.summary'), 'string');
$chart->addColumn(trans('firefly.income'), 'number');
$chart->addColumn(trans('firefly.expenses'), 'number');
$chart->addRow(trans('firefly.sum'), $income, $expense);
$chart->addRow(trans('firefly.average'), ($income / $count), ($expense / $count));
$chart->generate();
return $chart->getData();
}
}

View File

@@ -53,7 +53,7 @@ class ConnectJournalToPiggyBank
}
bcscale(2);
$amount = $journal->actual_amount;
$amount = $journal->amount_positive;
// if piggy account matches source account, the amount is positive
if ($piggyBank->account_id == $journal->source_account->id) {
$amount = $amount * -1;

View File

@@ -1,6 +1,5 @@
<?php namespace FireflyIII\Handlers\Events;
use App;
use FireflyIII\Events\JournalSaved;
use Log;
@@ -36,7 +35,7 @@ class RescanJournal
Log::debug('Triggered saved event for journal #' . $journal->id . ' (' . $journal->description . ')');
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Bill\BillRepositoryInterface');
$repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface');
$list = $journal->user->bills()->where('active', 1)->where('automatch', 1)->get();
Log::debug('Found ' . $list->count() . ' bills to check.');

View File

@@ -49,10 +49,12 @@ class UpdateJournalConnection
if (is_null($repetition)) {
return;
}
$amount = $journal->amount;
$diff = $amount - $event->amount; // update current repetition
bcscale(2);
$repetition->currentamount += $diff;
$amount = $journal->amount;
$diff = bcsub($amount, $event->amount); // update current repetition
$repetition->currentamount = bcadd($repetition->currentamount, $diff);
$repetition->save();

View File

@@ -0,0 +1,222 @@
<?php
namespace FireflyIII\Helpers\Attachments;
use Auth;
use Config;
use Crypt;
use FireflyIII\Models\Attachment;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\MessageBag;
use Input;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* Class AttachmentHelper
*
* @package FireflyIII\Helpers\Attachments
*/
class AttachmentHelper implements AttachmentHelperInterface
{
/** @var int */
protected $maxUploadSize;
/** @var array */
protected $allowedMimes;
/** @var MessageBag */
public $errors;
/** @var MessageBag */
public $messages;
/**
*
*/
public function __construct()
{
$this->maxUploadSize = Config::get('firefly.maxUploadSize');
$this->allowedMimes = Config::get('firefly.allowedMimes');
$this->errors = new MessageBag;
$this->messages = new MessageBag;
}
/**
* @param Attachment $attachment
*
* @return string
*/
public function getAttachmentLocation(Attachment $attachment)
{
$path = storage_path('upload') . DIRECTORY_SEPARATOR . 'at-' . $attachment->id . '.data';
return $path;
}
/**
* @param Model $model
*
* @return bool
*/
public function saveAttachmentsForModel(Model $model)
{
$files = Input::file('attachments');
if (is_array($files)) {
foreach ($files as $entry) {
if (!is_null($entry)) {
$this->processFile($entry, $model);
}
}
} else {
$this->processFile($files, $model);
}
return true;
}
/**
* @param UploadedFile $file
* @param Model $model
*
* @return bool
*/
protected function hasFile(UploadedFile $file, Model $model)
{
$md5 = md5_file($file->getRealPath());
$name = $file->getClientOriginalName();
$class = get_class($model);
$count = Auth::user()->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
if ($count > 0) {
$msg = trans('validation.file_already_attached', ['name' => $name]);
$this->errors->add('attachments', $msg);
return true;
}
return false;
}
/**
* @param UploadedFile $file
* @param Model $model
*
* @return bool
*/
protected function validateUpload(UploadedFile $file, Model $model)
{
if (!$this->validMime($file)) {
return false;
}
if (!$this->validSize($file)) {
return false;
}
if ($this->hasFile($file, $model)) {
return false;
}
return true;
}
/**
* @param UploadedFile $file
* @param Model $model
*
* @return bool|Attachment
*/
protected function processFile(UploadedFile $file, Model $model)
{
$validation = $this->validateUpload($file, $model);
if ($validation === false) {
return false;
}
$attachment = new Attachment; // create Attachment object.
$attachment->user()->associate(Auth::user());
$attachment->attachable()->associate($model);
$attachment->md5 = md5_file($file->getRealPath());
$attachment->filename = $file->getClientOriginalName();
$attachment->mime = $file->getMimeType();
$attachment->size = $file->getSize();
$attachment->uploaded = 0;
$attachment->save();
$path = $file->getRealPath(); // encrypt and move file to storage.
$content = file_get_contents($path);
$encrypted = Crypt::encrypt($content);
// store it:
$upload = $this->getAttachmentLocation($attachment);
if (is_writable(dirname($upload))) {
file_put_contents($upload, $encrypted);
}
$attachment->uploaded = 1; // update attachment
$attachment->save();
$name = e($file->getClientOriginalName()); // add message:
$msg = trans('validation.file_attached', ['name' => $name]);
$this->messages->add('attachments', $msg);
// return it.
return $attachment;
}
/**
* @param UploadedFile $file
*
* @return bool
*/
protected function validMime(UploadedFile $file)
{
$mime = e($file->getMimeType());
$name = e($file->getClientOriginalName());
if (!in_array($mime, $this->allowedMimes)) {
$msg = trans('validation.file_invalid_mime', ['name' => $name, 'mime' => $mime]);
$this->errors->add('attachments', $msg);
return false;
}
return true;
}
/**
* @param UploadedFile $file
*
* @return bool
*/
protected function validSize(UploadedFile $file)
{
$size = $file->getSize();
$name = e($file->getClientOriginalName());
if ($size > $this->maxUploadSize) {
$msg = trans('validation.file_too_large', ['name' => $name]);
$this->errors->add('attachments', $msg);
return false;
}
return true;
}
/**
* @return MessageBag
*/
public function getErrors()
{
return $this->errors;
}
/**
* @return MessageBag
*/
public function getMessages()
{
return $this->messages;
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace FireflyIII\Helpers\Attachments;
use FireflyIII\Models\Attachment;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\MessageBag;
/**
* Interface AttachmentHelperInterface
*
* @package FireflyIII\Helpers\Attachments
*/
interface AttachmentHelperInterface
{
/**
* @param Model $model
*
* @return bool
*/
public function saveAttachmentsForModel(Model $model);
/**
* @return MessageBag
*/
public function getErrors();
/**
* @return MessageBag
*/
public function getMessages();
/**
* @param Attachment $attachment
*
* @return mixed
*/
public function getAttachmentLocation(Attachment $attachment);
}

View File

@@ -34,7 +34,8 @@ class Category
*/
public function addCategory(CategoryModel $category)
{
if ($category->spent > 0) {
// spent is minus zero for an expense report:
if ($category->spent < 0) {
$this->categories->push($category);
}
}

View File

@@ -33,11 +33,10 @@ class Expense
*/
public function addOrCreateExpense(TransactionJournal $entry)
{
$accountId = $entry->account_id;
if (!$this->expenses->has($accountId)) {
$newObject = new stdClass;
$newObject->amount = strval(round($entry->amount, 2));
$newObject->amount = strval(round($entry->amount_positive, 2));
$newObject->name = $entry->name;
$newObject->count = 1;
$newObject->id = $accountId;
@@ -45,7 +44,7 @@ class Expense
} else {
bcscale(2);
$existing = $this->expenses->get($accountId);
$existing->amount = bcadd($existing->amount, $entry->amount);
$existing->amount = bcadd($existing->amount, $entry->amount_positive);
$existing->count++;
$this->expenses->put($accountId, $existing);
}

View File

@@ -38,7 +38,7 @@ class Income
$accountId = $entry->account_id;
if (!$this->incomes->has($accountId)) {
$newObject = new stdClass;
$newObject->amount = strval(round($entry->amount, 2));
$newObject->amount = strval(round($entry->amount_positive, 2));
$newObject->name = $entry->name;
$newObject->count = 1;
$newObject->id = $accountId;
@@ -46,7 +46,7 @@ class Income
} else {
bcscale(2);
$existing = $this->incomes->get($accountId);
$existing->amount = bcadd($existing->amount, $entry->amount);
$existing->amount = bcadd($existing->amount, $entry->amount_positive);
$existing->count++;
$this->incomes->put($accountId, $existing);
}

View File

@@ -3,6 +3,7 @@ namespace FireflyIII\Helpers\Csv\Converter;
use Auth;
use FireflyIII\Models\Account;
use Log;
/**
* Class AccountId
@@ -19,11 +20,19 @@ class AccountId extends BasicConverter implements ConverterInterface
{
// is mapped? Then it's easy!
if (isset($this->mapped[$this->index][$this->value])) {
/** @var Account $account */
$account = Auth::user()->accounts()->find($this->mapped[$this->index][$this->value]);
} else {
/** @var Account $account */
$account = Auth::user()->accounts()->find($this->value);
if (!is_null($account)) {
Log::debug('Found ' . $account->accountType->type . ' named "******" with ID: ' . $this->value . ' (not mapped) ');
}
}
return $account;
}
}
}

View File

@@ -23,4 +23,4 @@ class Amount extends BasicConverter implements ConverterInterface
return 0;
}
}
}

View File

@@ -65,4 +65,4 @@ class AssetAccountIban extends BasicConverter implements ConverterInterface
return null;
}
}
}

View File

@@ -48,4 +48,4 @@ class AssetAccountName extends BasicConverter implements ConverterInterface
return $account;
}
}
}

View File

@@ -119,4 +119,4 @@ class BasicConverter
}
}
}

View File

@@ -27,4 +27,4 @@ class BillId extends BasicConverter implements ConverterInterface
return $bill;
}
}
}

View File

@@ -35,4 +35,4 @@ class BillName extends BasicConverter implements ConverterInterface
return $bill;
}
}
}

View File

@@ -26,4 +26,4 @@ class BudgetId extends BasicConverter implements ConverterInterface
return $budget;
}
}
}

View File

@@ -32,4 +32,4 @@ class BudgetName extends BasicConverter implements ConverterInterface
return $budget;
}
}
}

View File

@@ -26,4 +26,4 @@ class CategoryId extends BasicConverter implements ConverterInterface
return $category;
}
}
}

View File

@@ -31,4 +31,4 @@ class CategoryName extends BasicConverter implements ConverterInterface
return $category;
}
}
}

View File

@@ -46,4 +46,4 @@ interface ConverterInterface
*/
public function setValue($value);
}
}

View File

@@ -25,4 +25,4 @@ class CurrencyCode extends BasicConverter implements ConverterInterface
return $currency;
}
}
}

View File

@@ -25,4 +25,4 @@ class CurrencyId extends BasicConverter implements ConverterInterface
return $currency;
}
}
}

View File

@@ -25,4 +25,4 @@ class CurrencyName extends BasicConverter implements ConverterInterface
return $currency;
}
}
}

View File

@@ -25,4 +25,4 @@ class CurrencySymbol extends BasicConverter implements ConverterInterface
return $currency;
}
}
}

View File

@@ -3,6 +3,9 @@
namespace FireflyIII\Helpers\Csv\Converter;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use InvalidArgumentException;
use Log;
use Session;
/**
@@ -19,9 +22,17 @@ class Date extends BasicConverter implements ConverterInterface
public function convert()
{
$format = Session::get('csv-date-format');
try {
$date = Carbon::createFromFormat($format, $this->value);
} catch (InvalidArgumentException $e) {
Log::error('Date conversion error: ' . $e->getMessage() . '. Value was "' . $this->value . '", format was "' . $format . '".');
$message = trans('firefly.csv_date_parse_error', ['format' => $format, 'value' => $this->value]);
throw new FireflyException($message);
}
$date = Carbon::createFromFormat($format, $this->value);
return $date;
}
}
}

View File

@@ -18,4 +18,4 @@ class Description extends BasicConverter implements ConverterInterface
{
return trim($this->data['description'] . ' ' . $this->value);
}
}
}

View File

@@ -19,4 +19,4 @@ class Ignore extends BasicConverter implements ConverterInterface
{
return null;
}
}
}

View File

@@ -46,7 +46,7 @@ class OpposingAccountIban extends BasicConverter implements ConverterInterface
/** @var Account $account */
foreach ($set as $account) {
if ($account->iban == $this->value) {
Log::debug('OpposingAccountIban::convert found an Account (#' . $account->id . ': ' . $account->name . ') with IBAN ' . $this->value);
Log::debug('OpposingAccountIban::convert found an Account (#' . $account->id . ': ******) with IBAN ******');
return $account;
}
@@ -54,4 +54,4 @@ class OpposingAccountIban extends BasicConverter implements ConverterInterface
return null;
}
}
}

View File

@@ -29,4 +29,4 @@ class OpposingAccountId extends BasicConverter implements ConverterInterface
return $account;
}
}
}

View File

@@ -28,4 +28,4 @@ class OpposingAccountName extends BasicConverter implements ConverterInterface
return $this->value;
}
}
}
}

View File

@@ -23,4 +23,4 @@ class RabobankDebetCredit extends BasicConverter implements ConverterInterface
return 1;
}
}
}

View File

@@ -37,4 +37,4 @@ class TagsComma extends BasicConverter implements ConverterInterface
return $tags;
}
}
}

View File

@@ -37,4 +37,4 @@ class TagsSpace extends BasicConverter implements ConverterInterface
return $tags;
}
}
}

View File

@@ -25,16 +25,19 @@ class Data
protected $hasHeaders;
/** @var array */
protected $map;
protected $map = [];
/** @var array */
protected $mapped;
protected $mapped = [];
/** @var Reader */
protected $reader;
/** @var array */
protected $roles;
protected $roles = [];
/** @var array */
protected $specifix;
protected $specifix = [];
/** @var int */
protected $importAccount = 0;
/**
*
@@ -48,6 +51,7 @@ class Data
$this->sessionRoles();
$this->sessionMapped();
$this->sessionSpecifix();
$this->sessionImportAccount();
}
protected function sessionHasHeaders()
@@ -57,6 +61,13 @@ class Data
}
}
protected function sessionImportAccount()
{
if (Session::has('csv-import-account')) {
$this->importAccount = intval(Session::get('csv-import-account'));
}
}
protected function sessionDateFormat()
{
if (Session::has('csv-date-format')) {
@@ -116,6 +127,15 @@ class Data
$this->dateFormat = $dateFormat;
}
/**
* @param int $importAccount
*/
public function setImportAccount($importAccount)
{
Session::put('csv-import-account', $importAccount);
$this->importAccount = $importAccount;
}
/**
* @return bool
*/
@@ -247,7 +267,7 @@ class Data
*/
public function getSpecifix()
{
return $this->specifix;
return is_array($this->specifix) ? $this->specifix : [];
}
/**
@@ -260,4 +280,4 @@ class Data
}
}
}

View File

@@ -2,16 +2,17 @@
namespace FireflyIII\Helpers\Csv;
use App;
use Auth;
use Config;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Csv\Converter\ConverterInterface;
use FireflyIII\Helpers\Csv\PostProcessing\PostProcessorInterface;
use FireflyIII\Helpers\Csv\Specifix\SpecifixInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
use Log;
@@ -42,7 +43,10 @@ class Importer
/** @var int */
protected $rows = 0;
/** @var array */
protected $specifix;
protected $specifix = [];
/** @var Collection */
protected $journals;
/**
* Used by CsvController.
@@ -74,6 +78,15 @@ class Importer
return $this->rows;
}
/**
* @return Collection
*/
public function getJournals()
{
return $this->journals;
}
/**
* @throws FireflyException
*/
@@ -81,6 +94,7 @@ class Importer
{
set_time_limit(0);
$this->journals = new Collection;
$this->map = $this->data->getMap();
$this->roles = $this->data->getRoles();
$this->mapped = $this->data->getMapped();
@@ -88,14 +102,17 @@ class Importer
foreach ($this->data->getReader() as $index => $row) {
if ($this->parseRow($index)) {
Log::debug('--- Importing row ' . $index);
$this->rows++;
$result = $this->importRow($row);
if (!($result === true)) {
if (!($result instanceof TransactionJournal)) {
Log::error('Caught error at row #' . $index . ': ' . $result);
$this->errors[$index] = $result;
} else {
$this->imported++;
$this->journals->push($result);
}
Log::debug('---');
}
}
}
@@ -107,7 +124,7 @@ class Importer
*/
protected function parseRow($index)
{
return (($this->data->hasHeaders() && $index > 1) || !$this->data->hasHeaders());
return (($this->data->hasHeaders() && $index >= 1) || !$this->data->hasHeaders());
}
/**
@@ -118,14 +135,17 @@ class Importer
*/
protected function importRow($row)
{
$data = $this->getFiller(); // These fields are necessary to create a new transaction journal. Some are optional
foreach ($row as $index => $value) {
$role = isset($this->roles[$index]) ? $this->roles[$index] : '_ignore';
$class = Config::get('csv.roles.' . $role . '.converter');
$field = Config::get('csv.roles.' . $role . '.field');
Log::debug('Column #' . $index . ' (role: ' . $role . ') : converter ' . $class . ' stores its data into field ' . $field . ':');
/** @var ConverterInterface $converter */
$converter = App::make('FireflyIII\Helpers\Csv\Converter\\' . $class);
$converter = app('FireflyIII\Helpers\Csv\Converter\\' . $class);
$converter->setData($data); // the complete array so far.
$converter->setField($field);
$converter->setIndex($index);
@@ -133,7 +153,6 @@ class Importer
$converter->setValue($value);
$converter->setRole($role);
$data[$field] = $converter->convert();
}
// move to class vars.
$this->importData = $data;
@@ -147,11 +166,8 @@ class Importer
return $result; // return error.
}
$journal = $this->createTransactionJournal();
if ($journal instanceof TransactionJournal) {
return true;
}
return false;
return $journal;
}
/**
@@ -169,6 +185,7 @@ class Importer
// some extra's:
$filler['bill-id'] = null;
$filler['opposing-account-object'] = null;
$filler['asset-account-object'] = null;
$filler['amount-modifier'] = '1';
return $filler;
@@ -186,9 +203,10 @@ class Importer
foreach ($this->getSpecifix() as $className) {
/** @var SpecifixInterface $specifix */
$specifix = App::make('FireflyIII\Helpers\Csv\Specifix\\' . $className);
$specifix = app('FireflyIII\Helpers\Csv\Specifix\\' . $className);
$specifix->setData($this->importData);
$specifix->setRow($this->importRow);
Log::debug('Now post-process specifix named ' . $className . ':');
$this->importData = $specifix->fix();
}
@@ -196,8 +214,9 @@ class Importer
$set = Config::get('csv.post_processors');
foreach ($set as $className) {
/** @var PostProcessorInterface $postProcessor */
$postProcessor = App::make('FireflyIII\Helpers\Csv\PostProcessing\\' . $className);
$postProcessor = app('FireflyIII\Helpers\Csv\PostProcessing\\' . $className);
$postProcessor->setData($this->importData);
Log::debug('Now post-process processor named ' . $className . ':');
$this->importData = $postProcessor->process();
}
@@ -208,7 +227,7 @@ class Importer
*/
public function getSpecifix()
{
return $this->specifix;
return is_array($this->specifix) ? $this->specifix : [];
}
/**
@@ -224,6 +243,10 @@ class Importer
return 'Opposing account is null';
}
if (!($this->importData['asset-account-object'] instanceof Account)) {
return 'No asset account to import into.';
}
return true;
}
@@ -238,6 +261,8 @@ class Importer
if (is_null($this->importData['date'])) {
$date = $this->importData['date-rent'];
}
$transactionType = $this->getTransactionType(); // defaults to deposit
$errors = new MessageBag;
$journal = TransactionJournal::create(
@@ -245,10 +270,13 @@ class Importer
'description' => $this->importData['description'], 'completed' => 0, 'date' => $date, 'bill_id' => $this->importData['bill-id'],]
);
if ($journal->getErrors()->count() == 0) {
$accountId = $this->importData['asset-account']->id; // create first transaction:
// first transaction
$accountId = $this->importData['asset-account-object']->id; // create first transaction:
$amount = $this->importData['amount'];
$transaction = Transaction::create(['transaction_journal_id' => $journal->id, 'account_id' => $accountId, 'amount' => $amount]);
$errors = $transaction->getErrors();
// second transaction
$accountId = $this->importData['opposing-account-object']->id; // create second transaction:
$amount = bcmul($this->importData['amount'], -1);
$transaction = Transaction::create(['transaction_journal_id' => $journal->id, 'account_id' => $accountId, 'amount' => $amount]);
@@ -266,6 +294,18 @@ class Importer
$this->saveCategory($journal);
$this->saveTags($journal);
// some debug info:
$journalId = $journal->id;
$type = $journal->transactionType->type;
/** @var Account $asset */
$asset = $this->importData['asset-account-object'];
/** @var Account $opposing */
$opposing = $this->importData['opposing-account-object'];
Log::info('Created journal #' . $journalId . ' of type ' . $type . '!');
Log::info('Asset account ****** (#' . $asset->id . ') lost/gained: ' . $this->importData['amount']);
Log::info($opposing->accountType->type . ' ****** (#' . $opposing->id . ') lost/gained: ' . bcmul($this->importData['amount'], -1));
return $journal;
}
@@ -328,4 +368,4 @@ class Importer
$this->data = $data;
}
}
}

View File

@@ -27,8 +27,8 @@ class AnyAccount implements MapperInterface
}
asort($list);
array_unshift($list, trans('firefly.csv_do_not_map'));
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}
}

View File

@@ -38,8 +38,8 @@ class AssetAccount implements MapperInterface
asort($list);
array_unshift($list, trans('firefly.csv_do_not_map'));
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}
}

View File

@@ -27,8 +27,8 @@ class Bill implements MapperInterface
}
asort($list);
array_unshift($list, trans('firefly.csv_do_not_map'));
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}
}

View File

@@ -27,8 +27,8 @@ class Budget implements MapperInterface
}
asort($list);
array_unshift($list, trans('firefly.csv_do_not_map'));
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}
}

View File

@@ -27,8 +27,8 @@ class Category implements MapperInterface
}
asort($list);
array_unshift($list, trans('firefly.csv_do_not_map'));
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}
}

View File

@@ -13,4 +13,4 @@ interface MapperInterface
* @return array
*/
public function getMap();
}
}

View File

@@ -27,8 +27,8 @@ class Tag implements MapperInterface
}
asort($list);
array_unshift($list, trans('firefly.csv_do_not_map'));
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}
}

View File

@@ -25,8 +25,8 @@ class TransactionCurrency implements MapperInterface
asort($list);
array_unshift($list, trans('firefly.csv_do_not_map'));
$list = [0 => trans('firefly.csv_do_not_map')] + $list;
return $list;
}
}
}

View File

@@ -32,4 +32,4 @@ class Amount implements PostProcessorInterface
{
$this->data = $data;
}
}
}

View File

@@ -0,0 +1,185 @@
<?php
namespace FireflyIII\Helpers\Csv\PostProcessing;
use Auth;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use Log;
use Validator;
/**
* Class AssetAccount
*
* @package FireflyIII\Helpers\Csv\PostProcessing
*/
class AssetAccount implements PostProcessorInterface
{
/** @var array */
protected $data;
/**
* @return array
*/
public function process()
{
$result = $this->checkIdNameObject(); // has object in ID or Name?
if (!is_null($result)) {
return $result;
}
$result = $this->checkIbanString();
if (!is_null($result)) {
return $result;
}
$result = $this->checkNameString();
if (!is_null($result)) {
return $result;
}
return null;
}
/**
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* @return array
*/
protected function checkIdNameObject()
{
if ($this->data['asset-account-id'] instanceof Account) { // first priority. try to find the account based on ID, if any
$this->data['asset-account-object'] = $this->data['asset-account-id'];
return $this->data;
}
if ($this->data['asset-account-iban'] instanceof Account) { // second: try to find the account based on IBAN, if any.
$this->data['asset-account-object'] = $this->data['asset-account-iban'];
return $this->data;
}
return null;
}
/**
* @return array|null
*/
protected function checkIbanString()
{
$rules = ['iban' => 'iban'];
$check = ['iban' => $this->data['asset-account-iban']];
$validator = Validator::make($check, $rules);
if (!$validator->fails()) {
$this->data['asset-account-object'] = $this->parseIbanString();
return $this->data;
}
return null;
}
/**
* @return Account|null
*/
protected function parseIbanString()
{
// create by name and/or iban.
$accounts = Auth::user()->accounts()->get();
foreach ($accounts as $entry) {
if ($entry->iban == $this->data['asset-account-iban']) {
return $entry;
}
}
$account = $this->createAccount();
return $account;
}
/**
* @return Account|null
*/
protected function createAccount()
{
$accountType = $this->getAccountType();
// create if not exists:
$name = is_string($this->data['asset-account-name']) && strlen($this->data['asset-account-name']) > 0 ? $this->data['asset-account-name']
: $this->data['asset-account-iban'];
$account = Account::firstOrCreateEncrypted(
[
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'name' => $name,
'iban' => $this->data['asset-account-iban'],
'active' => true,
]
);
return $account;
}
/**
*
* @return AccountType
*/
protected function getAccountType()
{
return AccountType::where('type', 'Asset account')->first();
}
/**
* @return array|null
*/
protected function checkNameString()
{
if ($this->data['asset-account-name'] instanceof Account) { // third: try to find account based on name, if any.
$this->data['asset-account-object'] = $this->data['asset-account-name'];
return $this->data;
}
if (is_string($this->data['asset-account-name'])) {
$this->data['asset-account-object'] = $this->parseNameString();
return $this->data;
}
return null;
}
/**
* @return Account|null
*/
protected function parseNameString()
{
$accountType = $this->getAccountType();
$accounts = Auth::user()->accounts()->where('account_type_id', $accountType->id)->get();
foreach ($accounts as $entry) {
if ($entry->name == $this->data['asset-account-name']) {
Log::debug('Found an asset account with this name (#' . $entry->id . ': ******)');
return $entry;
}
}
// create if not exists:
$account = Account::firstOrCreateEncrypted(
[
'user_id' => Auth::user()->id,
'account_type_id' => $accountType->id,
'name' => $this->data['asset-account-name'],
'iban' => '',
'active' => true,
]
);
return $account;
}
}

View File

@@ -34,4 +34,4 @@ class Bill implements PostProcessorInterface
{
$this->data = $data;
}
}
}

View File

@@ -38,4 +38,4 @@ class Currency implements PostProcessorInterface
{
$this->data = $data;
}
}
}

View File

@@ -35,4 +35,4 @@ class Description implements PostProcessorInterface
$this->data = $data;
}
}
}

View File

@@ -24,6 +24,10 @@ class OpposingAccount implements PostProcessorInterface
*/
public function process()
{
// three values:
// opposing-account-id, opposing-account-iban, opposing-account-name
$result = $this->checkIdNameObject();
if (!is_null($result)) {
return $result;
@@ -56,11 +60,13 @@ class OpposingAccount implements PostProcessorInterface
protected function checkIdNameObject()
{
if ($this->data['opposing-account-id'] instanceof Account) { // first priority. try to find the account based on ID, if any
Log::debug('OpposingAccountPostProcession: opposing-account-id is an Account.');
$this->data['opposing-account-object'] = $this->data['opposing-account-id'];
return $this->data;
}
if ($this->data['opposing-account-iban'] instanceof Account) { // second: try to find the account based on IBAN, if any.
Log::debug('OpposingAccountPostProcession: opposing-account-iban is an Account.');
$this->data['opposing-account-object'] = $this->data['opposing-account-iban'];
return $this->data;
@@ -75,9 +81,12 @@ class OpposingAccount implements PostProcessorInterface
protected function checkIbanString()
{
$rules = ['iban' => 'iban'];
$check = ['iban' => $this->data['opposing-account-iban']];
$iban = $this->data['opposing-account-iban'];
$check = ['iban' => $iban];
$validator = Validator::make($check, $rules);
if (!$validator->fails()) {
if (is_string($iban) && strlen($iban) > 0 && !$validator->fails()) {
Log::debug('OpposingAccountPostProcession: opposing-account-iban is a string (******).');
$this->data['opposing-account-object'] = $this->parseIbanString();
return $this->data;
@@ -95,12 +104,14 @@ class OpposingAccount implements PostProcessorInterface
$accounts = Auth::user()->accounts()->get();
foreach ($accounts as $entry) {
if ($entry->iban == $this->data['opposing-account-iban']) {
Log::debug('OpposingAccountPostProcession: opposing-account-iban matches an Account.');
return $entry;
}
}
$account = $this->createAccount();
return $account;
}
@@ -123,6 +134,7 @@ class OpposingAccount implements PostProcessorInterface
'active' => true,
]
);
Log::debug('OpposingAccountPostProcession: created a new account.');
return $account;
}
@@ -153,11 +165,13 @@ class OpposingAccount implements PostProcessorInterface
protected function checkNameString()
{
if ($this->data['opposing-account-name'] instanceof Account) { // third: try to find account based on name, if any.
Log::debug('OpposingAccountPostProcession: opposing-account-name is an Account.');
$this->data['opposing-account-object'] = $this->data['opposing-account-name'];
return $this->data;
}
if (is_string($this->data['opposing-account-name'])) {
$this->data['opposing-account-object'] = $this->parseNameString();
return $this->data;
@@ -175,7 +189,7 @@ class OpposingAccount implements PostProcessorInterface
$accounts = Auth::user()->accounts()->where('account_type_id', $accountType->id)->get();
foreach ($accounts as $entry) {
if ($entry->name == $this->data['opposing-account-name']) {
Log::debug('Found an account with this name (#' . $entry->id . ': ' . $entry->name . ')');
Log::debug('Found an account with this name (#' . $entry->id . ': ******)');
return $entry;
}
@@ -193,4 +207,4 @@ class OpposingAccount implements PostProcessorInterface
return $account;
}
}
}

View File

@@ -26,4 +26,4 @@ interface PostProcessorInterface
* @param array $data
*/
public function setData(array $data);
}
}

View File

@@ -42,4 +42,4 @@ class Dummy
}
}
}

View File

@@ -2,6 +2,8 @@
namespace FireflyIII\Helpers\Csv\Specifix;
use Log;
/**
* Class RabobankDescription
*
@@ -32,10 +34,16 @@ class RabobankDescription
*/
protected function rabobankFixEmptyOpposing()
{
if (strlen($this->data['opposing-account-name']) == 0) {
Log::debug('RaboSpecifix: Opposing account name is "******".');
if (is_string($this->data['opposing-account-name']) && strlen($this->data['opposing-account-name']) == 0) {
Log::debug('RaboSpecifix: opp-name is zero length, changed to: "******"');
$this->data['opposing-account-name'] = $this->row[10];
Log::debug('Description was: "******".');
$this->data['description'] = trim(str_replace($this->row[10], '', $this->data['description']));
Log::debug('Description is now: "******".');
}
$this->data['description'] = trim(str_replace($this->row[10], '', $this->data['description']));
}
/**
@@ -55,4 +63,4 @@ class RabobankDescription
}
}
}

View File

@@ -22,4 +22,4 @@ interface SpecifixInterface
* @param array $row
*/
public function setRow($row);
}
}

View File

@@ -1,13 +1,13 @@
<?php
namespace FireflyIII\Helpers\Csv;
use App;
use Auth;
use Config;
use Crypt;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Csv\Mapper\MapperInterface;
use League\Csv\Reader;
use Log;
use ReflectionException;
use Session;
@@ -45,9 +45,7 @@ class Wizard implements WizardInterface
/*
* Make each one unique.
*/
foreach ($values as $column => $found) {
$values[$column] = array_unique($found);
}
$values = $this->uniqueRecursive($values);
return $values;
}
@@ -112,6 +110,8 @@ class Wizard implements WizardInterface
{
foreach ($fields as $field) {
if (!Session::has($field)) {
Log::error('Session is missing field: ' . $field);
return false;
}
}
@@ -137,7 +137,7 @@ class Wizard implements WizardInterface
$class = 'FireflyIII\Helpers\Csv\Mapper\\' . $mapper;
try {
/** @var MapperInterface $mapObject */
$mapObject = App::make($class);
$mapObject = app($class);
} catch (ReflectionException $e) {
throw new FireflyException('Column "' . $columnRole . '" cannot be mapped because class ' . $mapper . ' does not exist.');
}
@@ -177,4 +177,18 @@ class Wizard implements WizardInterface
{
return ($hasHeaders && $index > 1) || !$hasHeaders;
}
}
/**
* @param array $array
*
* @return array
*/
protected function uniqueRecursive(array $array)
{
foreach ($array as $column => $found) {
$array[$column] = array_unique($found);
}
return $array;
}
}

View File

@@ -56,4 +56,4 @@ interface WizardInterface
*/
public function storeCsvFile($path);
}
}

View File

@@ -2,7 +2,6 @@
namespace FireflyIII\Helpers\Report;
use App;
use Carbon\Carbon;
use FireflyIII\Helpers\Collection\Account as AccountCollection;
use FireflyIII\Helpers\Collection\Balance;
@@ -80,7 +79,7 @@ class ReportHelper implements ReportHelperInterface
foreach ($accounts as $account) {
$start = bcadd($start, $account->startBalance);
$end = bcadd($end, $account->endBalance);
$diff = bcadd($diff, ($account->endBalance - $account->startBalance));
$diff = bcadd($diff, bcsub($account->endBalance, $account->startBalance));
}
$object = new AccountCollection;
@@ -115,8 +114,8 @@ class ReportHelper implements ReportHelperInterface
*/
public function getBalanceReport(Carbon $start, Carbon $end, $shared)
{
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$tagRepository = App::make('FireflyIII\Repositories\Tag\TagRepositoryInterface');
$repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$tagRepository = app('FireflyIII\Repositories\Tag\TagRepositoryInterface');
$balance = new Balance;
// build a balance header:
@@ -134,7 +133,7 @@ class ReportHelper implements ReportHelperInterface
$line->setBudget($budget);
// get budget amount for current period:
$rep = $repository->getCurrentRepetition($budget, $start);
$rep = $repository->getCurrentRepetition($budget, $start, $end);
$line->setRepetition($rep);
// loop accounts:
@@ -200,15 +199,15 @@ class ReportHelper implements ReportHelperInterface
* This method generates a full report for the given period on all
* the users bills and their payments.
*
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return BillCollection
*/
public function getBillReport(Carbon $start, Carbon $end)
{
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Bill\BillRepositoryInterface');
$repository = app('FireflyIII\Repositories\Bill\BillRepositoryInterface');
$bills = $repository->getBills();
$collection = new BillCollection;
@@ -253,16 +252,18 @@ class ReportHelper implements ReportHelperInterface
{
$object = new BudgetCollection;
/** @var \FireflyIII\Repositories\Budget\BudgetRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$repository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$set = $repository->getBudgets();
bcscale(2);
foreach ($set as $budget) {
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
// no repetition(s) for this budget:
if ($repetitions->count() == 0) {
$spent = $repository->spentInPeriodCorrected($budget, $start, $end, $shared);
$spent = $repository->balanceInPeriod($budget, $start, $end, $shared);
$budgetLine = new BudgetLine;
$budgetLine->setBudget($budget);
$budgetLine->setOverspent($spent);
@@ -277,10 +278,11 @@ class ReportHelper implements ReportHelperInterface
$budgetLine = new BudgetLine;
$budgetLine->setBudget($budget);
$budgetLine->setRepetition($repetition);
$expenses = $repository->spentInPeriodCorrected($budget, $repetition->startdate, $repetition->enddate, $shared);
$left = $expenses < floatval($repetition->amount) ? floatval($repetition->amount) - $expenses : 0;
$spent = $expenses > floatval($repetition->amount) ? 0 : $expenses;
$overspent = $expenses > floatval($repetition->amount) ? $expenses - floatval($repetition->amount) : 0;
$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);
@@ -323,10 +325,10 @@ class ReportHelper implements ReportHelperInterface
* GET CATEGORIES:
*/
/** @var \FireflyIII\Repositories\Category\CategoryRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
$repository = app('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
$set = $repository->getCategories();
foreach ($set as $category) {
$spent = $repository->spentInPeriodCorrected($category, $start, $end, $shared);
$spent = $repository->balanceInPeriod($category, $start, $end, $shared);
$category->spent = $spent;
$object->addCategory($category);
$object->addTotal($spent);
@@ -349,7 +351,7 @@ class ReportHelper implements ReportHelperInterface
$object = new Expense;
$set = $this->query->expenseInPeriodCorrected($start, $end, $shared);
foreach ($set as $entry) {
$object->addToTotal($entry->amount);
$object->addToTotal($entry->amount_positive);
$object->addOrCreateExpense($entry);
}
@@ -370,7 +372,7 @@ class ReportHelper implements ReportHelperInterface
$object = new Income;
$set = $this->query->incomeInPeriodCorrected($start, $end, $shared);
foreach ($set as $entry) {
$object->addToTotal($entry->amount);
$object->addToTotal($entry->amount_positive);
$object->addOrCreateIncome($entry);
}

View File

@@ -35,8 +35,8 @@ interface ReportHelperInterface
* This method generates a full report for the given period on all
* the users bills and their payments.
*
* @param Carbon $start
* @param Carbon $end
* @param Carbon $start
* @param Carbon $end
*
* @return BillCollection
*/

View File

@@ -21,7 +21,11 @@ use Steam;
class ReportQuery implements ReportQueryInterface
{
/**
* See ReportQueryInterface::incomeInPeriodCorrected
* 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
@@ -46,6 +50,7 @@ class ReportQuery implements ReportQueryInterface
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"');
}
);
}
@@ -65,15 +70,6 @@ class ReportQuery implements ReportQueryInterface
}
}
);
$data = $data->filter(
function (TransactionJournal $journal) {
if ($journal->amount != 0) {
return $journal;
}
return null;
}
);
return $data;
}
@@ -160,6 +156,7 @@ class ReportQuery implements ReportQueryInterface
function (Builder $q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_from.data', '=', '"sharedAsset"');
$q->where('acm_to.data','!=','"sharedAsset"');
}
);
}
@@ -208,17 +205,19 @@ class ReportQuery implements ReportQueryInterface
public function spentInBudgetCorrected(Account $account, Budget $budget, Carbon $start, Carbon $end)
{
return floatval(
Auth::user()->transactionjournals()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->transactionTypes(['Withdrawal'])
->where('transactions.account_id', $account->id)
->before($end)
->after($start)
->where('budget_transaction_journal.budget_id', $budget->id)
->get(['transaction_journals.*'])->sum('amount')
) * -1;
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
);
}
/**

View File

@@ -3,6 +3,7 @@
use Auth;
use Carbon\Carbon;
use Config;
use ExpandedForm;
use FireflyIII\Http\Requests\AccountFormRequest;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -57,17 +58,19 @@ class AccountController extends Controller
*
* @return \Illuminate\View\View
*/
public function delete(Account $account)
public function delete(AccountRepositoryInterface $repository, Account $account)
{
$typeName = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
$subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]);
$typeName = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
$subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]);
$accountList = Expandedform::makeSelectList($repository->getAccounts([$account->accountType->type]), true);
unset($accountList[$account->id]);
// put previous url in session
Session::put('accounts.delete.url', URL::previous());
Session::flash('gaEventCategory', 'accounts');
Session::flash('gaEventAction', 'delete-' . $typeName);
return view('accounts.delete', compact('account', 'subTitle'));
return view('accounts.delete', compact('account', 'subTitle', 'accountList'));
}
/**
@@ -78,12 +81,12 @@ class AccountController extends Controller
*/
public function destroy(AccountRepositoryInterface $repository, Account $account)
{
$type = $account->accountType->type;
$typeName = Config::get('firefly.shortNamesByFullName.' . $type);
$name = $account->name;
$moveTo = Auth::user()->accounts()->find(intval(Input::get('move_account_before_delete')));
$repository->destroy($account);
$repository->destroy($account, $moveTo);
Session::flash('success', trans('firefly.' . $typeName . '_deleted', ['name' => $name]));
Preferences::mark();
@@ -127,7 +130,7 @@ class AccountController extends Controller
'ccMonthlyPaymentDate' => $account->getMeta('ccMonthlyPaymentDate'),
'openingBalanceDate' => $openingBalance ? $openingBalance->date->format('Y-m-d') : null,
'openingBalance' => $openingBalanceAmount,
'virtualBalance' => floatval($account->virtual_balance)
'virtualBalance' => round($account->virtual_balance, 2)
];
Session::flash('preFilled', $preFilled);
Session::flash('gaEventCategory', 'accounts');
@@ -153,12 +156,24 @@ class AccountController extends Controller
* HERE WE ARE
*/
$start = clone Session::get('start', Carbon::now()->startOfMonth());
$end = clone Session::get('end', Carbon::now()->endOfMonth());
$start->subDay();
// start balances:
$ids = [];
foreach ($accounts as $account) {
$ids[] = $account->id;
}
$startBalances = Steam::balancesById($ids, $start);
$endBalances = Steam::balancesById($ids, $end);
$activities = Steam::getLastActivities($ids);
$accounts->each(
function (Account $account) use ($start, $repository) {
$account->lastActivityDate = $repository->getLastActivity($account);
$account->startBalance = Steam::balance($account, $start);
$account->endBalance = Steam::balance($account, clone Session::get('end', Carbon::now()->endOfMonth()));
function (Account $account) use ($activities, $startBalances, $endBalances) {
$account->lastActivityDate = isset($activities[$account->id]) ? $activities[$account->id] : null;
$account->startBalance = isset($startBalances[$account->id]) ? $startBalances[$account->id] : null;
$account->endBalance = isset($endBalances[$account->id]) ? $endBalances[$account->id] : null;
}
);
@@ -195,12 +210,12 @@ class AccountController extends Controller
$accountData = [
'name' => $request->input('name'),
'accountType' => $request->input('what'),
'virtualBalance' => floatval($request->input('virtualBalance')),
'virtualBalance' => round($request->input('virtualBalance'), 2),
'active' => true,
'user' => Auth::user()->id,
'iban' => $request->input('iban'),
'accountRole' => $request->input('accountRole'),
'openingBalance' => floatval($request->input('openingBalance')),
'openingBalance' => round($request->input('openingBalance'), 2),
'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')),
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
@@ -238,8 +253,8 @@ class AccountController extends Controller
'user' => Auth::user()->id,
'iban' => $request->input('iban'),
'accountRole' => $request->input('accountRole'),
'virtualBalance' => floatval($request->input('virtualBalance')),
'openingBalance' => floatval($request->input('openingBalance')),
'virtualBalance' => round($request->input('virtualBalance'), 2),
'openingBalance' => round($request->input('openingBalance'), 2),
'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')),
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
'ccType' => $request->input('ccType'),

View File

@@ -0,0 +1,173 @@
<?php
namespace FireflyIII\Http\Controllers;
use Crypt;
use File;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Requests\AttachmentFormRequest;
use FireflyIII\Models\Attachment;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use Input;
use Preferences;
use Response;
use Session;
use URL;
use View;
/**
* Class AttachmentController
*
* @package FireflyIII\Http\Controllers
*/
class AttachmentController extends Controller
{
/**
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
View::share('mainTitleIcon', 'fa-paperclip');
View::share('title', trans('firefly.attachments'));
}
/**
* @param Attachment $attachment
*
* @return \Illuminate\View\View
*/
public function edit(Attachment $attachment)
{
$subTitleIcon = 'fa-pencil';
$subTitle = trans('firefly.edit_attachment', ['name' => $attachment->filename]);
// put previous url in session if not redirect from store (not "return_to_edit").
if (Session::get('attachments.edit.fromUpdate') !== true) {
Session::put('attachments.edit.url', URL::previous());
}
Session::forget('attachments.edit.fromUpdate');
return view('attachments.edit', compact('attachment', 'subTitleIcon', 'subTitle'));
}
/**
* @param Attachment $attachment
*
* @return \Illuminate\View\View
*/
public function delete(Attachment $attachment)
{
$subTitle = trans('firefly.delete_attachment', ['name' => $attachment->filename]);
// put previous url in session
Session::put('attachments.delete.url', URL::previous());
Session::flash('gaEventCategory', 'attachments');
Session::flash('gaEventAction', 'delete-attachment');
return view('attachments.delete', compact('attachment', 'subTitle'));
}
/**
* @param AttachmentRepositoryInterface $repository
* @param Attachment $attachment
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(AttachmentRepositoryInterface $repository, Attachment $attachment)
{
$name = $attachment->filename;
$repository->destroy($attachment);
Session::flash('success', trans('firefly.attachment_deleted', ['name' => $name]));
Preferences::mark();
return redirect(Session::get('attachments.delete.url'));
}
/**
* @param Attachment $attachment
*/
public function download(Attachment $attachment, AttachmentHelperInterface $helper)
{
$file = $helper->getAttachmentLocation($attachment);
if (file_exists($file)) {
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $quoted);
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $attachment->size);
echo Crypt::decrypt(file_get_contents($file));
} else {
abort(404);
}
}
/**
* @param Attachment $attachment
*
* @return \Illuminate\Http\Response
*/
public function preview(Attachment $attachment)
{
if ($attachment->mime == 'application/pdf') {
$file = public_path('images/page_white_acrobat.png');
} else {
$file = public_path('images/page_green.png');
}
$response = Response::make(File::get($file));
$response->header('Content-Type', 'image/png');
return $response;
}
/**
* @param AttachmentFormRequest $request
* @param AttachmentRepositoryInterface $repository
* @param Attachment $attachment
*
* @return \Illuminate\Http\RedirectResponse
*/
public function update(AttachmentFormRequest $request, AttachmentRepositoryInterface $repository, Attachment $attachment)
{
$attachmentData = [
'title' => $request->input('title'),
'description' => $request->input('description'),
'notes' => $request->input('notes'),
];
$repository->update($attachment, $attachmentData);
Session::flash('success', 'Attachment "' . $attachment->filename . '" updated.');
Preferences::mark();
if (intval(Input::get('return_to_edit')) === 1) {
// set value so edit routine will not overwrite URL:
Session::put('attachments.edit.fromUpdate', true);
return redirect(route('attachments.edit', [$attachment->id]))->withInput(['return_to_edit' => 1]);
}
// redirect to previous URL.
return redirect(Session::get('attachments.edit.url'));
}
}

View File

@@ -1,14 +1,15 @@
<?php namespace FireflyIII\Http\Controllers\Auth;
use App;
use Auth;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Role;
use FireflyIII\User;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Http\Request;
use Illuminate\Mail\Message;
use Mail;
use Request as Rq;
use Session;
use Twig;
use Validator;
@@ -20,19 +21,81 @@ use Validator;
*/
class AuthController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
/*
|--------------------------------------------------------------------------
| Registration & Login Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it?
|
*/
/**
* Show the application registration form.
*
* @return \Illuminate\Http\Response
*/
public function getRegister()
{
$host = Rq::getHttpHost();
return view('auth.register', compact('host'));
}
/**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
public function postLogin(Request $request)
{
$this->validate(
$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();
if ($throttles && $this->hasTooManyLoginAttempts($request)) {
return $this->sendLockoutResponse($request);
}
$credentials = $this->getCredentials($request);
$credentials['blocked'] = 0; // most not be blocked.
if (Auth::attempt($credentials, $request->has('remember'))) {
return $this->handleUserWasAuthenticated($request, $throttles);
}
// default error message:
$message = $this->getFailedLoginMessage();
// try to find a blocked user with this email address.
/** @var User $foundUser */
$foundUser = User::where('email', $credentials['email'])->where('blocked', 1)->first();
if (!is_null($foundUser)) {
// if it exists, show message:
$code = $foundUser->blocked_code;
$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) {
$this->incrementLoginAttempts($request);
}
return redirect($this->loginPath())
->withInput($request->only($this->loginUsername(), 'remember'))
->withErrors(
[
$this->loginUsername() => $message,
]
);
}
use AuthenticatesAndRegistersUsers;
public $redirectTo = '/';
@@ -44,6 +107,8 @@ class AuthController extends Controller
*/
public function __construct()
{
parent::__construct();
$this->middleware('guest', ['except' => 'getLogout']);
}
@@ -109,7 +174,7 @@ class AuthController extends Controller
return redirect($this->redirectPath());
}
// @codeCoverageIgnoreStart
App::abort(500, 'Not a user!');
abort(500, 'Not a user!');
return redirect('/');
// @codeCoverageIgnoreEnd

View File

@@ -36,6 +36,7 @@ class PasswordController extends Controller
*/
public function __construct()
{
parent::__construct();
$this->middleware('guest');
}

View File

@@ -8,6 +8,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Input;
use Navigation;
use Preferences;
use Response;
use Session;
@@ -136,24 +137,27 @@ class BudgetController extends Controller
*/
public function index(BudgetRepositoryInterface $repository)
{
$budgets = $repository->getActiveBudgets();
$inactive = $repository->getInactiveBudgets();
$spent = '0';
$budgeted = '0';
$budgets = $repository->getActiveBudgets();
$inactive = $repository->getInactiveBudgets();
$spent = '0';
$budgeted = '0';
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod(Session::get('start', new Carbon), $range);
$end = Navigation::endOfPeriod($start, $range);
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
$budgetIncomeTotal = Preferences::get($key, 1000)->data;
$period = Navigation::periodShow($start, $range);
bcscale(2);
/**
* Do some cleanup:
*/
$repository->cleanupBudgets();
// loop the budgets:
/** @var Budget $budget */
foreach ($budgets as $budget) {
$date = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$budget->spent = $repository->spentInPeriodCorrected($budget, $date, $end);
$budget->currentRep = $repository->getCurrentRepetition($budget, $date);
$budget->spent = $repository->balanceInPeriod($budget, $start, $end);
$budget->currentRep = $repository->getCurrentRepetition($budget, $start, $end);
if ($budget->currentRep) {
$budgeted = bcadd($budgeted, $budget->currentRep->amount);
}
@@ -161,13 +165,12 @@ class BudgetController extends Controller
}
$dateAsString = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
$budgetIncomeTotal = Preferences::get('budgetIncomeTotal' . $dateAsString, 1000)->data;
$budgetMaximum = Preferences::get('budgetMaximum', 1000)->data;
$defaultCurrency = Amount::getDefaultCurrency();
$budgetMaximum = Preferences::get('budgetMaximum', 1000)->data;
$defaultCurrency = Amount::getDefaultCurrency();
return view(
'budgets.index', compact('budgetMaximum', 'budgetIncomeTotal', 'defaultCurrency', 'inactive', 'budgets', 'spent', 'budgeted')
'budgets.index', compact('budgetMaximum','period', 'range', 'budgetIncomeTotal', 'defaultCurrency', 'inactive', 'budgets', 'spent', 'budgeted')
);
}
@@ -178,8 +181,9 @@ class BudgetController extends Controller
*/
public function noBudget(BudgetRepositoryInterface $repository)
{
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->startOfMonth());
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod(Session::get('start', new Carbon), $range);
$end = Navigation::endOfPeriod($start, $range);
$list = $repository->getWithoutBudget($start, $end);
$subTitle = trans(
'firefly.without_budget_between',
@@ -194,9 +198,12 @@ class BudgetController extends Controller
*/
public function postUpdateIncome()
{
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod(Session::get('start', new Carbon), $range);
$end = Navigation::endOfPeriod($start, $range);
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
Preferences::set('budgetIncomeTotal' . $date, intval(Input::get('amount')));
Preferences::set($key, intval(Input::get('amount')));
Preferences::mark();
return redirect(route('budgets.index'));
@@ -297,8 +304,11 @@ class BudgetController extends Controller
*/
public function updateIncome()
{
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
$amount = Preferences::get('budgetIncomeTotal' . $date, 1000);
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod(Session::get('start', new Carbon), $range);
$end = Navigation::endOfPeriod($start, $range);
$key = 'budgetIncomeTotal' . $start->format('Ymd') . $end->format('Ymd');
$amount = Preferences::get($key, 1000);
return view('budgets.income', compact('amount'));
}

View File

@@ -5,8 +5,11 @@ use Carbon\Carbon;
use FireflyIII\Http\Requests\CategoryFormRequest;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Input;
use Navigation;
use Preferences;
use Session;
use URL;
@@ -139,6 +142,31 @@ class CategoryController extends Controller
return view('categories.noCategory', compact('list', 'subTitle'));
}
/**
* @param CategoryRepositoryInterface $repository
* @param Category $category
*
* @return \Illuminate\View\View
*/
public function showWithDate(CategoryRepositoryInterface $repository, Category $category, $date)
{
$carbon = new Carbon($date);
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($carbon, $range);
$end = Navigation::endOfPeriod($carbon, $range);
$subTitle = $category->name;
$hideCategory = true; // used in list.
$page = intval(Input::get('page'));
$set = $repository->getJournalsInRange($category, $page, $start, $end);
$count = $repository->countJournalsInRange($category, $start, $end);
$journals = new LengthAwarePaginator($set, $count, 50, $page);
$journals->setPath('categories/show/' . $category->id . '/' . $date);
return view('categories.show_with_date', compact('category', 'journals', 'hideCategory', 'subTitle', 'carbon'));
}
/**
* @param CategoryRepositoryInterface $repository
* @param Category $category
@@ -151,10 +179,47 @@ class CategoryController extends Controller
$page = intval(Input::get('page'));
$set = $repository->getJournals($category, $page);
$count = $repository->countJournals($category);
$subTitle = $category->name;
$journals = new LengthAwarePaginator($set, $count, 50, $page);
$journals->setPath('categories/show/' . $category->id);
return view('categories.show', compact('category', 'journals', 'hideCategory'));
// list of ranges for list of periods:
// oldest transaction in category:
$start = $repository->getFirstActivityDate($category);
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfX(new Carbon, $range);
$entries = new Collection;
// chart properties for cache:
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('category-show');
$cache->addProperty($category->id);
if ($cache->has()) {
$entries = $cache->get();
} else {
while ($end >= $start) {
$end = Navigation::startOfPeriod($end, $range);
$currentEnd = Navigation::endOfPeriod($end, $range);
// here do something.
$spent = $repository->spentInPeriod($category, $end, $currentEnd);
$earned = $repository->earnedInPeriod($category, $end, $currentEnd);
$dateStr = $end->format('Y-m-d');
$dateName = Navigation::periodShow($end, $range);
$entries->push([$dateStr, $dateName, $spent, $earned]);
$end = Navigation::subtractPeriod($end, $range, 1);
}
$cache->store($entries);
}
return view('categories.show', compact('category', 'journals', 'entries', 'hideCategory', 'subTitle'));
}
/**

View File

@@ -2,7 +2,6 @@
namespace FireflyIII\Http\Controllers\Chart;
use App;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
@@ -31,7 +30,7 @@ class AccountController extends Controller
{
parent::__construct();
// create chart generator:
$this->generator = App::make('FireflyIII\Generator\Chart\Account\AccountChartGenerator');
$this->generator = app('FireflyIII\Generator\Chart\Account\AccountChartGenerator');
}
@@ -80,6 +79,36 @@ class AccountController extends Controller
return Response::json($data);
}
/**
* Shows the balances for all the user's expense accounts.
*
* @param AccountRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function expenseAccounts(AccountRepositoryInterface $repository)
{
$start = clone Session::get('start', Carbon::now()->startOfMonth());
$end = clone Session::get('end', Carbon::now()->endOfMonth());
$accounts = $repository->getAccounts(['Expense account', 'Beneficiary account']);
// chart properties for cache:
$cache = new CacheProperties();
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('expenseAccounts');
$cache->addProperty('accounts');
if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore
}
$data = $this->generator->expenseAccounts($accounts, $start, $end);
$cache->store($data);
return Response::json($data);
}
/**
* Shows the balances for all the user's frontpage accounts.
*

View File

@@ -2,18 +2,14 @@
namespace FireflyIII\Http\Controllers\Chart;
use App;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
use Response;
use Session;
use Steam;
/**
* Class BillController
@@ -33,26 +29,21 @@ class BillController extends Controller
{
parent::__construct();
// create chart generator:
$this->generator = App::make('FireflyIII\Generator\Chart\Bill\BillChartGenerator');
$this->generator = app('FireflyIII\Generator\Chart\Bill\BillChartGenerator');
}
/**
* Shows all bills and whether or not theyve been paid this month (pie chart).
*
* @param BillRepositoryInterface $repository
* @param AccountRepositoryInterface $accounts
* @param BillRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function frontpage(BillRepositoryInterface $repository, AccountRepositoryInterface $accounts)
public function frontpage(BillRepositoryInterface $repository)
{
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
// chart properties for cache:
$cache = new CacheProperties();
$cache = new CacheProperties(); // chart properties for cache:
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('bills');
@@ -61,46 +52,13 @@ class BillController extends Controller
return Response::json($cache->get()); // @codeCoverageIgnore
}
$bills = $repository->getActiveBills();
$paid = new Collection; // journals.
$unpaid = new Collection; // bills
$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');
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$journals = $repository->getJournalsInRange($bill, $range['start'], $range['end']);
if ($journals->count() == 0) {
$unpaid->push([$bill, $range['start']]);
} else {
$paid = $paid->merge($journals);
}
}
}
$creditCards = $accounts->getCreditCards();
foreach ($creditCards as $creditCard) {
$balance = Steam::balance($creditCard, $end, true);
$date = new Carbon($creditCard->getMeta('ccMonthlyPaymentDate'));
if ($balance < 0) {
// unpaid! create a fake bill that matches the amount.
$description = $creditCard->name;
$amount = $balance * -1;
$fakeBill = $repository->createFakeBill($description, $date, $amount);
unset($description, $amount);
$unpaid->push([$fakeBill, $date]);
}
if ($balance == 0) {
// find transfer(s) TO the credit card which should account for
// anything paid. If not, the CC is not yet used.
$journals = $accounts->getTransfersInRange($creditCard, $start, $end);
$paid = $paid->merge($journals);
}
}
// build chart:
$data = $this->generator->frontpage($paid, $unpaid);

View File

@@ -2,7 +2,6 @@
namespace FireflyIII\Http\Controllers\Chart;
use App;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Budget;
@@ -33,7 +32,7 @@ class BudgetController extends Controller
{
parent::__construct();
// create chart generator:
$this->generator = App::make('FireflyIII\Generator\Chart\Budget\BudgetChartGenerator');
$this->generator = app('FireflyIII\Generator\Chart\Budget\BudgetChartGenerator');
}
/**
@@ -69,7 +68,7 @@ class BudgetController extends Controller
$end->subDay();
$chartDate = clone $end;
$chartDate->startOfMonth();
$spent = $repository->spentInPeriodCorrected($budget, $first, $end);
$spent = $repository->balanceInPeriod($budget, $first, $end) * -1;
$entries->push([$chartDate, $spent]);
$first = Navigation::addPeriod($first, $range, 0);
}
@@ -157,13 +156,13 @@ class BudgetController extends Controller
foreach ($budgets as $budget) {
$repetitions = $repository->getBudgetLimitRepetitions($budget, $start, $end);
if ($repetitions->count() == 0) {
$expenses = $repository->spentInPeriodCorrected($budget, $start, $end, true);
$expenses = $repository->balanceInPeriod($budget, $start, $end, true) * -1;
$allEntries->push([$budget->name, 0, 0, $expenses, 0, 0]);
continue;
}
/** @var LimitRepetition $repetition */
foreach ($repetitions as $repetition) {
$expenses = $repository->spentInPeriodCorrected($budget, $repetition->startdate, $repetition->enddate, true);
$expenses = $repository->balanceInPeriod($budget, $repetition->startdate, $repetition->enddate, true) * -1;
// $left can be less than zero.
// $overspent can be more than zero ( = overspending)
@@ -200,10 +199,11 @@ class BudgetController extends Controller
*/
public function year(BudgetRepositoryInterface $repository, $year, $shared = false)
{
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
$shared = $shared == 'shared' ? true : false;
$budgets = $repository->getBudgets();
$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:
$cache = new CacheProperties();
@@ -215,6 +215,15 @@ class BudgetController extends Controller
return Response::json($cache->get()); // @codeCoverageIgnore
}
// filter empty budgets:
foreach ($allBudgets as $budget) {
$spent = $repository->balanceInPeriod($budget, $start, $end, $shared);
if ($spent != 0) {
$budgets->push($budget);
}
}
$entries = new Collection;
while ($start < $end) {
@@ -225,14 +234,14 @@ class BudgetController extends Controller
// each budget, fill the row:
foreach ($budgets as $budget) {
$spent = $repository->spentInPeriodCorrected($budget, $start, $month, $shared);
$row[] = $spent;
$spent = $repository->balanceInPeriod($budget, $start, $month, $shared);
$row[] = $spent * -1;
}
$entries->push($row);
$start->endOfMonth()->addDay();
}
$data = $this->generator->year($budgets, $entries);
$data = $this->generator->year($allBudgets, $entries);
$cache->store($data);
return Response::json($data);

View File

@@ -3,7 +3,6 @@
namespace FireflyIII\Http\Controllers\Chart;
use App;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Category;
@@ -32,7 +31,7 @@ class CategoryController extends Controller
{
parent::__construct();
// create chart generator:
$this->generator = App::make('FireflyIII\Generator\Chart\Category\CategoryChartGenerator');
$this->generator = app('FireflyIII\Generator\Chart\Category\CategoryChartGenerator');
}
@@ -47,11 +46,10 @@ class CategoryController extends Controller
public function all(CategoryRepositoryInterface $repository, Category $category)
{
// oldest transaction in category:
$start = $repository->getFirstActivityDate($category);
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($start, $range);
$end = new Carbon;
$start = $repository->getFirstActivityDate($category);
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($start, $range);
$end = new Carbon;
$entries = new Collection;
@@ -67,11 +65,16 @@ class CategoryController extends Controller
while ($start <= $end) {
$currentEnd = Navigation::endOfPeriod($start, $range);
$spent = $repository->spentInPeriodCorrected($category, $start, $currentEnd);
$entries->push([clone $start, $spent]);
$spent = $repository->spentInPeriod($category, $start, $currentEnd);
$earned = $repository->earnedInPeriod($category, $start, $currentEnd);
$date = Navigation::periodShow($start, $range);
$entries->push([clone $start, $date, $spent, $earned]);
$start = Navigation::addPeriod($start, $range, 0);
}
// limit the set to the last 40:
$entries = $entries->reverse();
$entries = $entries->slice(0, 48);
$entries = $entries->reverse();
$data = $this->generator->all($entries);
$cache->store($data);
@@ -113,7 +116,7 @@ class CategoryController extends Controller
return 0;
}
return ($left['sum'] < $right['sum']) ? 1 : -1;
return ($left['sum'] < $right['sum']) ? -1 : 1;
}
);
$set = new Collection($array);
@@ -129,7 +132,7 @@ class CategoryController extends Controller
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function month(CategoryRepositoryInterface $repository, Category $category)
public function currentPeriod(CategoryRepositoryInterface $repository, Category $category)
{
$start = clone Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
@@ -140,7 +143,7 @@ class CategoryController extends Controller
$cache->addProperty($end);
$cache->addProperty($category->id);
$cache->addProperty('category');
$cache->addProperty('month');
$cache->addProperty('currentPeriod');
if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore
}
@@ -148,13 +151,57 @@ class CategoryController extends Controller
while ($start <= $end) {
$spent = $repository->spentOnDaySumCorrected($category, $start);
$entries->push([clone $start, $spent]);
$spent = $repository->spentOnDaySumCorrected($category, $start);
$earned = $repository->earnedOnDaySumCorrected($category, $start);
$date = Navigation::periodShow($start, '1D');
$entries->push([clone $start, $date, $spent, $earned]);
$start->addDay();
}
$data = $this->generator->month($entries);
$data = $this->generator->period($entries);
$cache->store($data);
return Response::json($data);
}
/**
* @param CategoryRepositoryInterface $repository
* @param Category $category
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function specificPeriod(CategoryRepositoryInterface $repository, Category $category, $date)
{
$carbon = new Carbon($date);
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($carbon, $range);
$end = Navigation::endOfPeriod($carbon, $range);
// chart properties for cache:
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty($category->id);
$cache->addProperty('category');
$cache->addProperty('specificPeriod');
$cache->addProperty($date);
if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore
}
$entries = new Collection;
while ($start <= $end) {
$spent = $repository->spentOnDaySumCorrected($category, $start);
$earned = $repository->earnedOnDaySumCorrected($category, $start);
$theDate = Navigation::periodShow($start, '1D');
$entries->push([clone $start, $theDate, $spent, $earned]);
$start->addDay();
}
$data = $this->generator->period($entries);
$cache->store($data);
return Response::json($data);
@@ -171,7 +218,7 @@ class CategoryController extends Controller
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function year(CategoryRepositoryInterface $repository, $year, $shared = false)
public function spentInYear(CategoryRepositoryInterface $repository, $year, $shared = false)
{
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
@@ -180,14 +227,24 @@ class CategoryController extends Controller
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('category');
$cache->addProperty('year');
$cache->addProperty('spent-in-year');
if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore
}
$shared = $shared == 'shared' ? true : false;
$categories = $repository->getCategories();
$entries = new Collection;
$shared = $shared == 'shared' ? true : false;
$allCategories = $repository->getCategories();
$entries = new Collection;
$categories = $allCategories->filter(
function (Category $category) use ($repository, $start, $end, $shared) {
$spent = $repository->balanceInPeriod($category, $start, $end, $shared);
if ($spent < 0) {
return $category;
}
return null;
}
);
while ($start < $end) {
$month = clone $start; // month is the current end of the period
@@ -195,15 +252,76 @@ class CategoryController extends Controller
$row = [clone $start]; // make a row:
foreach ($categories as $category) { // each budget, fill the row
$spent = $repository->spentInPeriodCorrected($category, $start, $month, $shared);
$row[] = $spent;
$spent = $repository->balanceInPeriod($category, $start, $month, $shared);
if ($spent < 0) {
$row[] = $spent * -1;
} else {
$row[] = 0;
}
}
$entries->push($row);
$start->addMonth();
}
$data = $this->generator->spentInYear($categories, $entries);
$cache->store($data);
$data = $this->generator->year($categories, $entries);
return Response::json($data);
}
/**
* This chart will only show income.
*
* @param CategoryRepositoryInterface $repository
* @param $year
* @param bool $shared
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function earnedInYear(CategoryRepositoryInterface $repository, $year, $shared = false)
{
$start = new Carbon($year . '-01-01');
$end = new Carbon($year . '-12-31');
$cache = new CacheProperties; // chart properties for cache:
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('category');
$cache->addProperty('earned-in-year');
if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore
}
$shared = $shared == 'shared' ? true : false;
$allCategories = $repository->getCategories();
$allEntries = new Collection;
$categories = $allCategories->filter(
function (Category $category) use ($repository, $start, $end, $shared) {
$spent = $repository->balanceInPeriod($category, $start, $end, $shared);
if ($spent > 0) {
return $category;
}
return null;
}
);
while ($start < $end) {
$month = clone $start; // month is the current end of the period
$month->endOfMonth();
$row = [clone $start]; // make a row:
foreach ($categories as $category) { // each budget, fill the row
$spent = $repository->balanceInPeriod($category, $start, $month, $shared);
if ($spent > 0) {
$row[] = $spent;
} else {
$row[] = 0;
}
}
$allEntries->push($row);
$start->addMonth();
}
$data = $this->generator->earnedInYear($categories, $allEntries);
$cache->store($data);
return Response::json($data);

View File

@@ -2,7 +2,6 @@
namespace FireflyIII\Http\Controllers\Chart;
use App;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
@@ -29,7 +28,7 @@ class PiggyBankController extends Controller
{
parent::__construct();
// create chart generator:
$this->generator = App::make('FireflyIII\Generator\Chart\PiggyBank\PiggyBankChartGenerator');
$this->generator = app('FireflyIII\Generator\Chart\PiggyBank\PiggyBankChartGenerator');
}
/**

View File

@@ -3,13 +3,13 @@
namespace FireflyIII\Http\Controllers\Chart;
use App;
use Carbon\Carbon;
use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
use Response;
use Log;
/**
* Class ReportController
@@ -29,7 +29,7 @@ class ReportController extends Controller
{
parent::__construct();
// create chart generator:
$this->generator = App::make('FireflyIII\Generator\Chart\Report\ReportChartGenerator');
$this->generator = app('FireflyIII\Generator\Chart\Report\ReportChartGenerator');
}
@@ -63,8 +63,8 @@ class ReportController extends Controller
$month = clone $start;
$month->endOfMonth();
// total income and total expenses:
$incomeSum = $query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount');
$expenseSum = $query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount');
$incomeSum = $query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
$expenseSum = $query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount_positive');
$entries->push([clone $start, $incomeSum, $expenseSum]);
$start->addMonth();
@@ -111,8 +111,18 @@ class ReportController extends Controller
$month = clone $start;
$month->endOfMonth();
// total income and total expenses:
$income = bcadd($income, $query->incomeInPeriodCorrected($start, $month, $shared)->sum('amount'));
$expense = bcadd($expense, $query->expenseInPeriodCorrected($start, $month, $shared)->sum('amount'));
$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);
$expense = bcadd($expense, $currentExpense);
$count++;
$start->addMonth();
}

View File

@@ -0,0 +1,74 @@
<?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

@@ -2,12 +2,13 @@
namespace FireflyIII\Http\Controllers;
use App;
use Config;
use ExpandedForm;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Csv\Data;
use FireflyIII\Helpers\Csv\Importer;
use FireflyIII\Helpers\Csv\WizardInterface;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Http\Request;
use Input;
use Log;
@@ -41,8 +42,8 @@ class CsvController extends Controller
throw new FireflyException('CSV Import is not enabled.');
}
$this->wizard = App::make('FireflyIII\Helpers\Csv\WizardInterface');
$this->data = App::make('FireflyIII\Helpers\Csv\Data');
$this->wizard = app('FireflyIII\Helpers\Csv\WizardInterface');
$this->data = app('FireflyIII\Helpers\Csv\Data');
}
@@ -56,7 +57,7 @@ class CsvController extends Controller
public function columnRoles()
{
$fields = ['csv-file', 'csv-date-format', 'csv-has-headers'];
$fields = ['csv-file', 'csv-date-format', 'csv-has-headers', 'csv-import-account'];
if (!$this->wizard->sessionHasValues($fields)) {
Session::flash('warning', 'Could not recover upload.');
@@ -103,7 +104,7 @@ class CsvController extends Controller
return redirect(route('csv.index'));
}
$data = [
'date-format' => Session::get('date-format'),
'date-format' => Session::get('csv-date-format'),
'has-headers' => Session::get('csv-has-headers')
];
if (Session::has('csv-map')) {
@@ -116,6 +117,10 @@ class CsvController extends Controller
$data['mapped'] = Session::get('csv-mapped');
}
if (Session::has('csv-specifix')) {
$data['specifix'] = Session::get('csv-specifix');
}
$result = json_encode($data, JSON_PRETTY_PRINT);
$name = 'csv-configuration-' . date('Y-m-d') . '.json';
@@ -143,13 +148,14 @@ class CsvController extends Controller
*
* @return \Illuminate\View\View
*/
public function index()
public function index(AccountRepositoryInterface $repository)
{
$subTitle = trans('firefly.csv_import');
Session::forget('csv-date-format');
Session::forget('csv-has-headers');
Session::forget('csv-file');
Session::forget('csv-import-account');
Session::forget('csv-map');
Session::forget('csv-roles');
Session::forget('csv-mapped');
@@ -161,11 +167,14 @@ class CsvController extends Controller
$specifix[$entry] = trans('firefly.csv_specifix_' . $entry);
}
// get a list of asset accounts:
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Asset account', 'Default account']));
// can actually upload?
$uploadPossible = is_writable(storage_path('upload'));
$path = storage_path('upload');
return view('csv.index', compact('subTitle', 'uploadPossible', 'path', 'specifix'));
return view('csv.index', compact('subTitle', 'uploadPossible', 'path', 'specifix', 'accounts'));
}
/**
@@ -297,12 +306,13 @@ class CsvController extends Controller
$rows = $importer->getRows();
$errors = $importer->getErrors();
$imported = $importer->getImported();
$journals = $importer->getJournals();
Preferences::mark();
$subTitle = trans('firefly.csv_process_title');
return view('csv.process', compact('rows', 'errors', 'imported', 'subTitle'));
return view('csv.process', compact('rows', 'errors', 'imported', 'subTitle', 'journals'));
}
@@ -367,19 +377,17 @@ class CsvController extends Controller
return redirect(route('csv.index'));
}
$fullPath = $this->wizard->storeCsvFile($request->file('csv')->getRealPath());
$settings = [];
$settings['date-format'] = Input::get('date_format');
$settings['has-headers'] = intval(Input::get('has_headers')) === 1;
$settings['specifix'] = Input::get('specifix');
$settings['map'] = [];
$settings['mapped'] = [];
$settings['roles'] = [];
$fullPath = $this->wizard->storeCsvFile($request->file('csv')->getRealPath());
$settings = [];
$settings['date-format'] = Input::get('date_format');
$settings['has-headers'] = intval(Input::get('has_headers')) === 1;
$settings['specifix'] = Input::get('specifix');
$settings['import-account'] = intval(Input::get('csv_import_account'));
$settings['map'] = [];
$settings['mapped'] = [];
$settings['roles'] = [];
/*
* Process config file if present.
*/
if ($request->hasFile('csv_config')) {
if ($request->hasFile('csv_config')) { // Process config file if present.
$data = file_get_contents($request->file('csv_config')->getRealPath());
$json = json_decode($data, true);
if (is_array($json)) {
@@ -394,8 +402,9 @@ class CsvController extends Controller
$this->data->setMapped($settings['mapped']);
$this->data->setRoles($settings['roles']);
$this->data->setSpecifix($settings['specifix']);
$this->data->setImportAccount($settings['import-account']);
return redirect(route('csv.column-roles'));
}
}
}

View File

@@ -1,11 +1,13 @@
<?php namespace FireflyIII\Http\Controllers;
use Artisan;
use Auth;
use Carbon\Carbon;
use Config;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Input;
use Log;
use Preferences;
use Route;
use Session;
@@ -57,6 +59,7 @@ class HomeController extends Controller
Session::clear();
Artisan::call('cache:clear');
return redirect(route('index'));
}
@@ -72,22 +75,20 @@ class HomeController extends Controller
$count = $repository->countAccounts($types);
bcscale(2);
if ($count == 0) {
return redirect(route('new-user.index'));
}
$title = 'Firefly';
$subTitle = trans('firefly.welcomeBack');
$mainTitleIcon = 'fa-fire';
$transactions = [];
$frontPage = Preferences::get('frontPageAccounts', []);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$accounts = $repository->getFrontpageAccounts($frontPage);
$savings = $repository->getSavingsAccounts();
$title = 'Firefly';
$subTitle = trans('firefly.welcomeBack');
$mainTitleIcon = 'fa-fire';
$transactions = [];
$frontPage = Preferences::get('frontPageAccounts', []);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$showTour = Preferences::get('tour', true)->data;
$accounts = $repository->getFrontpageAccounts($frontPage);
$savings = $repository->getSavingsAccounts();
$piggyBankAccounts = $repository->getPiggyBankAccounts();
@@ -114,7 +115,9 @@ class HomeController extends Controller
}
}
return view('index', compact('count', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions', 'savingsTotal', 'piggyBankAccounts'));
return view(
'index', compact('count', 'showTour', 'title', 'savings', 'subTitle', 'mainTitleIcon', 'transactions', 'savingsTotal', 'piggyBankAccounts')
);
}
/**
@@ -128,6 +131,7 @@ class HomeController extends Controller
return redirect(route('index'));
}
Log::debug('Make log.');
// get all routes:
$routeCollection = Route::getRoutes();

View File

@@ -12,6 +12,7 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;
use Preferences;
use Response;
use Session;
use Steam;
@@ -24,6 +25,43 @@ use Steam;
class JsonController extends Controller
{
/**
* @return \Illuminate\Http\JsonResponse
*/
public function endTour()
{
Preferences::set('tour', false);
return Response::json('true');
}
/**
*
*/
public function tour()
{
$pref = Preferences::get('tour', true);
if (!$pref) {
abort(404);
}
$headers = ['main-content', 'sidebar-toggle', 'account-menu', 'budget-menu', 'report-menu', 'transaction-menu', 'option-menu', 'main-content-end'];
$steps = [];
foreach ($headers as $header) {
$steps[] = [
'element' => '#' . $header,
'title' => trans('help.' . $header . '-title'),
'content' => trans('help.' . $header . '-text'),
];
}
$steps[0]['orphan'] = true;// orphan and backdrop for first element.
$steps[0]['backdrop'] = true;
$steps[1]['placement'] = 'left';// sidebar position left:
$steps[7]['orphan'] = true; // final in the center again.
$steps[7]['backdrop'] = true;
$template = view('json.tour')->render();
return Response::json(['steps' => $steps, 'template' => $template]);
}
/**
* @param BillRepositoryInterface $repository
@@ -34,8 +72,9 @@ class JsonController extends Controller
*/
public function boxBillsPaid(BillRepositoryInterface $repository, AccountRepositoryInterface $accountRepository)
{
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$amount = 0;
bcscale(2);
// works for json too!
@@ -46,12 +85,7 @@ class JsonController extends Controller
if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore
}
$amount = 0;
// these two functions are the same as the chart
$bills = $repository->getActiveBills();
$bills = $repository->getActiveBills(); // these two functions are the same as the chart
/** @var Bill $bill */
foreach ($bills as $bill) {
@@ -59,14 +93,12 @@ class JsonController extends Controller
}
unset($bill, $bills);
/**
* Find credit card accounts and possibly unpaid credit card bills.
*/
$creditCards = $accountRepository->getCreditCards();
// if the balance is not zero, the monthly payment is still underway.
$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);
$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.
@@ -76,7 +108,6 @@ class JsonController extends Controller
$data = ['box' => 'bills-paid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$cache->store($data);
return Response::json($data);
}
@@ -132,8 +163,8 @@ class JsonController extends Controller
}
/** @var Bill $entry */
foreach ($unpaid as $entry) {
$current = ($entry[0]->amount_max + $entry[0]->amount_min) / 2;
$amount = bcadd($amount, $current);
$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];
@@ -190,6 +221,7 @@ class JsonController extends Controller
}
$amount = $reportQuery->expenseInPeriodCorrected($start, $end, true)->sum('amount');
$amount = $amount * -1;
$data = ['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$cache->store($data);

View File

@@ -53,12 +53,13 @@ class NewUserController extends Controller
// create normal asset account:
$assetAccount = [
'name' => $request->get('bank_name'),
'iban' => null,
'accountType' => 'asset',
'virtualBalance' => 0,
'active' => true,
'user' => Auth::user()->id,
'accountRole' => 'defaultAsset',
'openingBalance' => floatval($request->input('bank_balance')),
'openingBalance' => round($request->input('bank_balance'), 2),
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
];
@@ -69,12 +70,13 @@ class NewUserController extends Controller
if (strlen($request->get('savings_balance') > 0)) {
$savingsAccount = [
'name' => $request->get('bank_name') . ' savings account',
'iban' => null,
'accountType' => 'asset',
'virtualBalance' => 0,
'active' => true,
'user' => Auth::user()->id,
'accountRole' => 'savingAsset',
'openingBalance' => floatval($request->input('savings_balance')),
'openingBalance' => round($request->input('savings_balance'), 2),
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
];
@@ -86,8 +88,9 @@ class NewUserController extends Controller
if (strlen($request->get('credit_card_limit') > 0)) {
$creditAccount = [
'name' => 'Credit card',
'iban' => null,
'accountType' => 'asset',
'virtualBalance' => floatval($request->get('credit_card_limit')),
'virtualBalance' => round($request->get('credit_card_limit'), 2),
'active' => true,
'user' => Auth::user()->id,
'accountRole' => 'ccAsset',

View File

@@ -47,10 +47,11 @@ class PiggyBankController extends Controller
*/
public function add(AccountRepositoryInterface $repository, PiggyBank $piggyBank)
{
bcscale(2);
$date = Session::get('end', Carbon::now()->endOfMonth());
$leftOnAccount = $repository->leftOnAccount($piggyBank->account, $date);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = $piggyBank->targetamount - $savedSoFar;
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
$maxAmount = min($leftOnAccount, $leftToSave);
return view('piggy-banks.add', compact('piggyBank', 'maxAmount'));
@@ -66,7 +67,7 @@ class PiggyBankController extends Controller
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
$subTitle = trans('firefly.create_new_piggybank');
$subTitle = trans('firefly.new_piggy_bank');
$subTitleIcon = 'fa-plus';
// put previous url in session if not redirect from store (not "create another").
@@ -171,9 +172,9 @@ class PiggyBankController extends Controller
$accounts = [];
/** @var PiggyBank $piggyBank */
foreach ($piggyBanks as $piggyBank) {
$piggyBank->savedSoFar = floatval($piggyBank->currentRelevantRep()->currentamount);
$piggyBank->savedSoFar = round($piggyBank->currentRelevantRep()->currentamount, 2);
$piggyBank->percentage = $piggyBank->savedSoFar != 0 ? intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100) : 0;
$piggyBank->leftToSave = $piggyBank->targetamount - $piggyBank->savedSoFar;
$piggyBank->leftToSave = bcsub($piggyBank->targetamount, $piggyBank->savedSoFar);
/*
* Fill account information:
@@ -185,7 +186,7 @@ class PiggyBankController extends Controller
'balance' => Steam::balance($account, $end, true),
'leftForPiggyBanks' => $repository->leftOnAccount($account, $end),
'sumOfSaved' => $piggyBank->savedSoFar,
'sumOfTargets' => floatval($piggyBank->targetamount),
'sumOfTargets' => round($piggyBank->targetamount, 2),
'leftToSave' => $piggyBank->leftToSave
];
} else {
@@ -211,7 +212,7 @@ class PiggyBankController extends Controller
if (is_array($data)) {
foreach ($data as $order => $id) {
$repository->setOrder(intval($id), (intval($order) + 1));
$repository->setOrder(intval($id), ($order + 1));
}
}
}
@@ -225,13 +226,13 @@ class PiggyBankController extends Controller
*/
public function postAdd(PiggyBankRepositoryInterface $repository, AccountRepositoryInterface $accounts, PiggyBank $piggyBank)
{
$amount = round(floatval(Input::get('amount')), 2);
bcscale(2);
$amount = round(Input::get('amount'), 2);
$date = Session::get('end', Carbon::now()->endOfMonth());
$leftOnAccount = $accounts->leftOnAccount($piggyBank->account, $date);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = $piggyBank->targetamount - $savedSoFar;
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
$maxAmount = round(min($leftOnAccount, $leftToSave), 2);
bcscale(2);
if ($amount <= $maxAmount) {
$repetition = $piggyBank->currentRelevantRep();
@@ -258,7 +259,7 @@ class PiggyBankController extends Controller
*/
public function postRemove(PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
{
$amount = floatval(Input::get('amount'));
$amount = round(Input::get('amount'), 2);
bcscale(2);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
@@ -319,7 +320,7 @@ class PiggyBankController extends Controller
'name' => $request->get('name'),
'startdate' => new Carbon,
'account_id' => intval($request->get('account_id')),
'targetamount' => floatval($request->get('targetamount')),
'targetamount' => round($request->get('targetamount'), 2),
'remind_me' => false,
'reminder_skip' => 0,
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
@@ -354,7 +355,7 @@ class PiggyBankController extends Controller
'name' => $request->get('name'),
'startdate' => is_null($piggyBank->startdate) ? $piggyBank->created_at : $piggyBank->startdate,
'account_id' => intval($request->get('account_id')),
'targetamount' => floatval($request->get('targetamount')),
'targetamount' => round($request->get('targetamount'), 2),
'remind_me' => false,
'reminder_skip' => 0,
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,

View File

@@ -4,6 +4,7 @@ use Auth;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\DeleteAccountFormRequest;
use FireflyIII\Http\Requests\ProfileFormRequest;
use FireflyIII\User;
use Hash;
use Session;
@@ -20,7 +21,7 @@ class ProfileController extends Controller
*/
public function changePassword()
{
return view('profile.change-password')->with('title', Auth::user()->email)->with('subTitle', 'Change your password')->with(
return view('profile.change-password')->with('title', Auth::user()->email)->with('subTitle', trans('firefly.change_your_password'))->with(
'mainTitleIcon', 'fa-user'
);
}
@@ -30,7 +31,7 @@ class ProfileController extends Controller
*/
public function deleteAccount()
{
return view('profile.delete-account')->with('title', Auth::user()->email)->with('subTitle', 'Delete account')->with(
return view('profile.delete-account')->with('title', Auth::user()->email)->with('subTitle', trans('firefly.delete_account'))->with(
'mainTitleIcon', 'fa-user'
);
}
@@ -41,7 +42,7 @@ class ProfileController extends Controller
*/
public function index()
{
return view('profile.index')->with('title', 'Profile')->with('subTitle', Auth::user()->email)->with('mainTitleIcon', 'fa-user');
return view('profile.index')->with('title', trans('firefly.profile'))->with('subTitle', Auth::user()->email)->with('mainTitleIcon', 'fa-user');
}
/**
@@ -53,7 +54,7 @@ class ProfileController extends Controller
{
// old, new1, new2
if (!Hash::check($request->get('current_password'), Auth::user()->password)) {
Session::flash('error', 'Invalid current password!');
Session::flash('error', trans('firefly.invalid_current_password'));
return redirect(route('profile.change-password'));
}
@@ -68,7 +69,7 @@ class ProfileController extends Controller
Auth::user()->password = $request->get('new_password');
Auth::user()->save();
Session::flash('success', 'Password changed!');
Session::flash('success', trans('firefly.password_changed'));
return redirect(route('profile'));
}
@@ -83,7 +84,7 @@ class ProfileController extends Controller
protected function validatePassword($old, $new1)
{
if ($new1 == $old) {
return 'The idea is to change your password.';
return trans('firefly.should_change');
}
return true;
@@ -100,17 +101,28 @@ class ProfileController extends Controller
{
// old, new1, new2
if (!Hash::check($request->get('password'), Auth::user()->password)) {
Session::flash('error', 'Invalid password!');
Session::flash('error', trans('firefly.invalid_password'));
return redirect(route('profile.delete-account'));
}
// DELETE!
$email = Auth::user()->email;
Auth::user()->delete();
Session::flush();
Session::flash('gaEventCategory', 'user');
Session::flash('gaEventAction', 'delete-account');
// create a new user with the same email address so re-registration is blocked.
User::create(
[
'email' => $email,
'password' => 'deleted',
'blocked' => 1,
'blocked_code' => 'deleted'
]
);
return redirect(route('index'));
}

View File

@@ -8,6 +8,7 @@ use FireflyIII\Http\Requests\TagFormRequest;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use Illuminate\Support\Collection;
use Input;
use Preferences;
use Response;
@@ -43,9 +44,9 @@ class TagController extends Controller
View::share('mainTitleIcon', 'fa-tags');
View::share('hideTags', true);
$this->tagOptions = [
'nothing' => 'Just a regular tag.',
'balancingAct' => 'The tag takes at most two transactions; an expense and a transfer. They\'ll balance each other out.',
'advancePayment' => 'The tag accepts one expense and any number of deposits aimed to repay the original expense.',
'nothing' => trans('firefly.regular_tag'),
'balancingAct' => trans('firefly.balancing_act'),
'advancePayment' => trans('firefly.advance_payment'),
];
View::share('tagOptions', $this->tagOptions);
}
@@ -184,16 +185,28 @@ class TagController extends Controller
// loop each types and get the tags, group them by year.
$collection = [];
foreach ($types as $type) {
/** @var Collection $tags */
$tags = Auth::user()->tags()->where('tagMode', $type)->orderBy('date', 'ASC')->get();
$tags = $tags->sortBy(
function (Tag $tag) {
$date = !is_null($tag->date) ? $tag->date->format('Ymd') : '000000';
return strtolower($date . $tag->tag);
}
);
/** @var Tag $tag */
foreach ($tags as $tag) {
$year = is_null($tag->date) ? trans('firefly.no_year') : $tag->date->year;
$month = is_null($tag->date) ? trans('firefly.no_month') : $tag->date->formatLocalized($this->monthFormat);
$collection[$type][$year][$month][] = $tag;
$year = is_null($tag->date) ? trans('firefly.no_year') : $tag->date->year;
$monthFormatted = is_null($tag->date) ? trans('firefly.no_month') : $tag->date->formatLocalized($this->monthFormat);
$collection[$type][$year][$monthFormatted][] = $tag;
}
}
return view('tags.index', compact('title', 'mainTitleIcon', 'types', 'helpHidden', 'collection'));
}

View File

@@ -1,12 +1,15 @@
<?php namespace FireflyIII\Http\Controllers;
use Amount;
use Auth;
use Carbon\Carbon;
use Config;
use ExpandedForm;
use FireflyIII\Events\JournalCreated;
use FireflyIII\Events\JournalSaved;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Requests\JournalFormRequest;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -15,6 +18,7 @@ use Input;
use Preferences;
use Response;
use Session;
use Steam;
use URL;
use View;
@@ -43,10 +47,21 @@ class TransactionController extends Controller
*/
public function create(AccountRepositoryInterface $repository, $what = 'deposit')
{
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = trans('form.noBudget');
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
$uploadSize = min($maxFileSize, $maxPostSize);
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = trans('form.noBudget');
// piggy bank list:
$piggyBanks = Auth::user()->piggyBanks()->orderBy('order', 'ASC')->get();
/** @var PiggyBank $piggy */
foreach ($piggyBanks as $piggy) {
$piggy->name = $piggy->name . ' (' . Amount::format($piggy->currentRelevantRep()->currentamount, false) . ')';
}
$piggies = ExpandedForm::makeSelectList($piggyBanks);
$piggies[0] = trans('form.noPiggybank');
$preFilled = Session::has('preFilled') ? Session::get('preFilled') : [];
$respondTo = ['account_id', 'account_from_id'];
@@ -68,7 +83,7 @@ class TransactionController extends Controller
asort($piggies);
return view('transactions.create', compact('accounts', 'budgets', 'what', 'piggies', 'subTitle'));
return view('transactions.create', compact('accounts', 'uploadSize', 'budgets', 'what', 'piggies', 'subTitle'));
}
/**
@@ -121,14 +136,23 @@ class TransactionController extends Controller
*/
public function edit(AccountRepositoryInterface $repository, TransactionJournal $journal)
{
$what = strtolower($journal->transactionType->type);
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = trans('form.noBudget');
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
$piggies[0] = trans('form.noPiggybank');
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
$preFilled = [
// cannot edit opening balance
if ($journal->transactionType->type == 'Opening balance') {
return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!');
}
$maxFileSize = Steam::phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = Steam::phpBytes(ini_get('post_max_size'));
$uploadSize = min($maxFileSize, $maxPostSize);
$what = strtolower($journal->transactionType->type);
$accounts = ExpandedForm::makeSelectList($repository->getAccounts(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = trans('form.noBudget');
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
$piggies[0] = trans('form.noPiggybank');
$subTitle = trans('breadcrumbs.edit_journal', ['description' => $journal->description]);
$preFilled = [
'date' => $journal->date->format('Y-m-d'),
'category' => '',
'budget_id' => 0,
@@ -155,7 +179,7 @@ class TransactionController extends Controller
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->orderBy('date', 'DESC')->first()->piggy_bank_id;
}
$preFilled['amount'] = $journal->actual_amount;
$preFilled['amount'] = $journal->amount_positive;
if ($journal->transactionType->type == 'Withdrawal') {
$preFilled['account_id'] = $journal->source_account->id;
@@ -179,7 +203,7 @@ class TransactionController extends Controller
Session::forget('transactions.edit.fromUpdate');
return View::make('transactions.edit', compact('journal', 'accounts', 'what', 'budgets', 'piggies', 'subTitle'))->with('data', $preFilled);
return view('transactions.edit', compact('journal', 'uploadSize', 'accounts', 'what', 'budgets', 'piggies', 'subTitle'))->with('data', $preFilled);
}
/**
@@ -238,10 +262,11 @@ class TransactionController extends Controller
*/
public function show(JournalRepositoryInterface $repository, TransactionJournal $journal)
{
bcscale(2);
$journal->transactions->each(
function (Transaction $t) use ($journal, $repository) {
$t->before = $repository->getAmountBefore($journal, $t);
$t->after = $t->before + $t->amount;
$t->after = bcadd($t->before, $t->amount);
}
);
$what = strtolower($journal->transactionType->type);
@@ -256,15 +281,33 @@ class TransactionController extends Controller
*
* @return \Illuminate\Http\RedirectResponse
*/
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository)
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att)
{
$journalData = $request->getJournalData();
$journal = $repository->store($journalData);
// if not withdrawal, unset budgetid.
if ($journalData['what'] != 'withdrawal') {
$journalData['budget_id'] = 0;
}
$journal = $repository->store($journalData);
// save attachments:
$att->saveAttachmentsForModel($journal);
// flash errors
if (count($att->getErrors()->get('attachments')) > 0) {
Session::flash('error', $att->getErrors()->get('attachments'));
}
// flash messages
if (count($att->getMessages()->get('attachments')) > 0) {
Session::flash('info', $att->getMessages()->get('attachments'));
}
// rescan journal, UpdateJournalConnection
event(new JournalSaved($journal));
// ConnectJournalToPiggyBank
if ($journal->transactionType->type == 'Transfer' && intval($request->get('piggy_bank_id')) > 0) {
event(new JournalCreated($journal, intval($request->get('piggy_bank_id'))));
}
@@ -288,16 +331,34 @@ class TransactionController extends Controller
/**
* @param JournalFormRequest $request
* @param JournalRepositoryInterface $repository
* @param AttachmentHelperInterface $att
* @param TransactionJournal $journal
*
* @return \Illuminate\Http\RedirectResponse
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, TransactionJournal $journal)
public function update(JournalFormRequest $request, JournalRepositoryInterface $repository, AttachmentHelperInterface $att, TransactionJournal $journal)
{
// cannot edit opening balance
if ($journal->transactionType->type == 'Opening balance') {
return view('error')->with('message', 'Cannot edit this transaction. Edit the account instead!');
}
$journalData = $request->getJournalData();
$repository->update($journal, $journalData);
// save attachments:
$att->saveAttachmentsForModel($journal);
// flash errors
if (count($att->getErrors()->get('attachments')) > 0) {
Session::flash('error', $att->getErrors()->get('attachments'));
}
// flash messages
if (count($att->getMessages()->get('attachments')) > 0) {
Session::flash('info', $att->getMessages()->get('attachments'));
}
event(new JournalSaved($journal));
// update, get events by date and sort DESC

View File

@@ -52,6 +52,11 @@ class Authenticate
return redirect()->guest('auth/login');
}
}
if (intval($this->auth->user()->blocked) == 1) {
return redirect()->route('logout');
}
// if logged in, set user language:
$pref = Preferences::get('language', 'en');
App::setLocale($pref->data);

View File

@@ -3,7 +3,6 @@
namespace FireflyIII\Http\Middleware;
use App;
use Carbon\Carbon;
use Closure;
use Illuminate\Contracts\Auth\Guard;
@@ -65,7 +64,7 @@ class Range
}
if (!Session::has('first')) {
/** @var \FireflyIII\Repositories\Journal\JournalRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Journal\JournalRepositoryInterface');
$repository = app('FireflyIII\Repositories\Journal\JournalRepositoryInterface');
$journal = $repository->first();
if ($journal) {
Session::put('first', $journal->date);

View File

@@ -24,5 +24,4 @@ class VerifyCsrfToken extends BaseVerifier
{
return parent::handle($request, $next);
}
}

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