Compare commits

...

265 Commits
3.2.5 ... 3.3.3

Author SHA1 Message Date
James Cole
fcc22c692a Merge branch 'release/3.3.3' 2015-03-27 09:36:03 +01:00
James Cole
a876e8005c New version. 2015-03-27 09:35:52 +01:00
James Cole
2288e3705a Fixed order view. 2015-03-27 09:29:14 +01:00
James Cole
e8b58154e0 Bug fix. 2015-03-27 09:24:26 +01:00
James Cole
4393475af3 Remove debug. 2015-03-27 09:22:08 +01:00
James Cole
3fc560597c Validation bug. 2015-03-27 09:21:09 +01:00
James Cole
9f9af0b693 Moved to account list. 2015-03-27 08:11:13 +01:00
James Cole
a83fe2caea Correct ordering (everywhere). 2015-03-27 07:32:06 +01:00
James Cole
30c5376217 Fix order. 2015-03-27 07:29:01 +01:00
James Cole
6dddd6629d Thing with order and should fix Travis. 2015-03-27 07:20:32 +01:00
James Cole
f80de12cb5 Fix sorting. 2015-03-26 22:53:34 +01:00
James Cole
544ffca3a5 Sortable transactions. 2015-03-26 22:52:49 +01:00
James Cole
e0730c7b39 Fixed double named accounts. 2015-03-26 18:05:23 +01:00
James Cole
3d59d141c4 Push! 2015-03-26 17:46:08 +01:00
James Cole
ccddc2623d Merge branch 'develop' of github.com:JC5/firefly-iii into develop 2015-03-26 17:45:58 +01:00
James Cole
fcc47b58b4 Return to edit / create screen when user indicates. 2015-03-26 17:45:03 +01:00
James Cole
f67ac2e25e Update AccountController.php 2015-03-26 14:50:49 +01:00
James Cole
26127c9ccf Update AccountController.php 2015-03-26 14:49:02 +01:00
James Cole
d624efa799 Fix registration bug. 2015-03-25 22:30:36 +01:00
James Cole
ed3d40a4e0 Whoops. 2015-03-25 22:29:32 +01:00
James Cole
6e90ce5496 Cant dismiss reminders again. 2015-03-25 19:12:33 +01:00
James Cole
ab851b1be4 Fixed transfers 2015-03-25 17:44:06 +01:00
James Cole
340de53825 Use normal logging. 2015-03-25 17:42:33 +01:00
James Cole
a867b60af0 Update CategoryController.php 2015-03-25 16:14:28 +01:00
James Cole
26eafb0bd2 Update CategoryController.php 2015-03-25 16:13:39 +01:00
James Cole
0dbe44764b Update GoogleChartController.php 2015-03-25 16:00:06 +01:00
James Cole
2159df6802 Update GoogleChartController.php
Fixed chart.
2015-03-25 15:58:37 +01:00
James Cole
23389b9f17 Update FireflyValidator.php
Update uniqueForUser.
2015-03-25 15:56:32 +01:00
James Cole
6d3e3b894a Update AccountFormRequest.php
Update rules to include belongsToUser.
2015-03-25 15:55:39 +01:00
James Cole
55340aefa3 Remove code. 2015-03-24 21:06:45 +01:00
James Cole
94bc751e41 Sum starts at 0. 2015-03-24 21:05:15 +01:00
James Cole
89259c11e2 Fix chart. 2015-03-24 21:04:53 +01:00
James Cole
6bbaf1523c Fixed a bug in relevantOnDate 2015-03-24 21:00:42 +01:00
James Cole
fa3f18b60f Expand log for event. 2015-03-24 20:56:58 +01:00
James Cole
3dc794002f This should catch the missing piggy bank events. 2015-03-24 20:54:25 +01:00
James Cole
f50b133f2e Cleaned up some icons, improved routine for repeated expenses. 2015-03-21 21:33:52 +01:00
James Cole
1d6f6d28c9 Update font in calendar. 2015-03-21 10:29:25 +01:00
James Cole
c913de3c8b Fix percentage. 2015-03-21 08:56:24 +01:00
James Cole
bbc7b54a38 Catch 0 start balance. 2015-03-21 08:55:55 +01:00
James Cole
05fa1b40d1 Support > 100% 2015-03-21 08:53:43 +01:00
James Cole
6a88c8634d Added a block with savings. 2015-03-21 08:51:34 +01:00
James Cole
8ae1efa230 Added type savings account. 2015-03-20 23:17:59 +01:00
James Cole
ab8df4c8ab Fixed css reference. 2015-03-20 22:50:50 +01:00
James Cole
c259a46ed3 Clean up sql codes. 2015-03-20 22:39:07 +01:00
James Cole
5dc0677599 Fixed search sort 2015-03-20 18:30:17 +01:00
James Cole
7ed662ecc2 Fixed search in encrypted entries. 2015-03-20 18:21:14 +01:00
James Cole
4361cc69d4 Update font options in charts. 2015-03-20 15:54:40 +01:00
James Cole
461cbcbc28 Update to use Roboto font. 2015-03-20 13:34:59 +01:00
James Cole
09ae6c488b Fixed a bug where the session date would be edited by a chart. 2015-03-20 08:16:16 +01:00
James Cole
271a0ade26 Add code coverage to phpunit. 2015-03-18 22:24:54 +01:00
James Cole
4b076d227a Touch db so it can be created. 2015-03-18 22:17:18 +01:00
James Cole
3c4e7158a1 Config for test database. 2015-03-18 22:16:00 +01:00
James Cole
0b16765f37 Add sudo: false to enable container based builds. 2015-03-18 21:51:56 +01:00
James Cole
20c2ff3443 Add debug output to phpunit. 2015-03-18 21:43:19 +01:00
James Cole
96f2e598f4 Better position for titles. 2015-03-16 19:03:52 +01:00
James Cole
7374f0f9dd Removed Material Design. 2015-03-16 18:02:52 +01:00
James Cole
ccc44a74a0 Removed debug information. 2015-03-15 19:02:33 +01:00
James Cole
66cd63a68d Fixed a bug. 2015-03-15 18:08:52 +01:00
James Cole
decf7e5485 Set order in title. 2015-03-15 18:02:40 +01:00
James Cole
063c8025aa Allow piggy banks to be ordered. 2015-03-15 18:00:33 +01:00
James Cole
2fa7d2bd56 Add some text alignments. 2015-03-15 14:24:25 +01:00
James Cole
e55e7bce74 Misspelled a class name. 2015-03-15 14:23:26 +01:00
James Cole
f572445a65 Small updates. 2015-03-15 09:34:57 +01:00
James Cole
8b4f656d90 Switched to Google Material design line charts. 2015-03-15 08:38:12 +01:00
James Cole
6c1e093ebd Merge branch 'release/3.3.2' into develop 2015-03-14 22:06:12 +01:00
James Cole
6dd1b4537a Merge branch 'release/3.3.2' 2015-03-14 22:06:11 +01:00
James Cole
39ca9bea72 Update read me. 2015-03-14 22:06:01 +01:00
James Cole
999103277e Updated composer. 2015-03-14 22:05:36 +01:00
James Cole
3cc57ab89c Remove hash routine from user model. 2015-03-14 22:00:57 +01:00
James Cole
4e830079de New icon. 2015-03-14 17:31:17 +01:00
James Cole
ea7231e9fe Update mail config. 2015-03-14 17:25:35 +01:00
James Cole
ddfaca6d0c Cleanup and added some icons. 2015-03-14 17:21:43 +01:00
James Cole
3b11bd0593 Fixed some basic tests. 2015-03-13 08:44:07 +01:00
James Cole
3f89057528 Fixed a bug where the home budget chart would not actually list transactions without a budget. 2015-03-13 07:10:26 +01:00
James Cole
2f1073712f Merge pull request #63 from niekvanderkooy/fix-migrations
Fix migrations
2015-03-13 07:00:55 +01:00
James Cole
678e504c48 Fix charts to match report. 2015-03-10 20:26:52 +01:00
James Cole
e69545fd95 Include shared accounts. 2015-03-10 20:07:02 +01:00
James Cole
a7ed025cd6 Fine tune query. 2015-03-10 20:05:27 +01:00
James Cole
3d8e1f2484 Forgot the javascript. 2015-03-10 20:03:44 +01:00
James Cole
c38c9608da Fine tune query. 2015-03-10 20:01:49 +01:00
James Cole
2396b75e3c Fine tune income. 2015-03-10 20:00:43 +01:00
James Cole
e5c19b7562 Small fixes. 2015-03-10 19:58:05 +01:00
James Cole
114788567d More code for previous. 2015-03-10 19:57:20 +01:00
James Cole
17ae4b7d2a See if we can easily generate reports with shared accounts. 2015-03-10 19:51:24 +01:00
Niek van der Kooy
12d652bd0e We cannot entirely drop the foreign key constraint, since it is originally created (and dropped) in v3.2.1. 2015-03-10 18:25:23 +01:00
Niek van der Kooy
ff1bed97b8 We need to include models we use
Probably some left over L5 migration stuff, since you wouldn't notice it until reversing a migration
2015-03-10 18:24:28 +01:00
Niek van der Kooy
56490f0e84 Fix error when reverting changed migration.
When reverting changed migration, the down would fail because the foreign key constraint has to be dropped before you are able to rename the column.
2015-03-10 18:04:31 +01:00
James Cole
0b028a8923 Correctly order account names. 2015-03-10 17:26:31 +01:00
James Cole
43ac541cb8 Add reminders to top right menu. 2015-03-08 20:27:07 +01:00
James Cole
5218443678 Can now successfully act on reminders. 2015-03-08 20:20:58 +01:00
James Cole
d9028ed9b7 Small optimizations to the reminders 2015-03-08 09:00:04 +01:00
James Cole
9b9bd11ebb Small fix to table fix. 2015-03-07 19:42:45 +01:00
James Cole
07011ec5f7 Tiny chart improvement because I said so 2015-03-07 19:41:56 +01:00
James Cole
c3990ac32f Small updates to icons and code. 2015-03-07 12:34:03 +01:00
James Cole
081ff3ff55 View single reminder. 2015-03-07 09:29:43 +01:00
James Cole
93996ada96 Expanded reminders. 2015-03-07 09:21:06 +01:00
James Cole
a60671d4c1 First stuff for acting on reminders. 2015-03-06 20:33:23 +01:00
James Cole
3f716cc369 First new display of piggy bank reminders. 2015-03-06 17:23:29 +01:00
James Cole
9f23cffd1b Clean up code. 2015-03-06 15:26:21 +01:00
James Cole
07c416cfbf Fix set reminder. 2015-03-06 15:24:36 +01:00
James Cole
389fcc1c8d Update reminder in database. 2015-03-06 15:21:44 +01:00
James Cole
fa07811375 Add logging for debug purposes. 2015-03-06 15:18:07 +01:00
James Cole
fc91a50979 Reimplemented a routine that creates reminders. Cannot act on them yet. 2015-03-06 15:12:07 +01:00
James Cole
f9c518f321 Smaller font for boxes. 2015-03-06 10:10:07 +01:00
James Cole
015b439f0d New icons. 2015-03-06 08:30:15 +01:00
James Cole
0675622508 Experiment with boxes. 2015-03-06 08:20:27 +01:00
James Cole
e9969bdd5f Update the ranges to reflect the current dates. 2015-03-05 21:13:38 +01:00
James Cole
1139f950ed Fixed some views. 2015-03-04 21:11:47 +01:00
James Cole
284732c7a6 Better list for bills. 2015-03-04 20:58:57 +01:00
James Cole
0cb0720d8b No popup when the amount is zero. 2015-03-04 20:57:40 +01:00
James Cole
8ad1ede0c5 Popups in the reports as we've always promised. 2015-03-04 20:47:00 +01:00
James Cole
a349aac8a4 Fix balance thing. 2015-03-04 19:09:57 +01:00
James Cole
83b169c6ef Search related transfers, cleanup. 2015-03-04 16:04:17 +01:00
James Cole
49c37baac5 Update to related manager. 2015-03-04 15:30:44 +01:00
James Cole
8d62088576 Order bills. 2015-03-04 09:44:48 +01:00
James Cole
f5437a17f8 Lots of changes. 2015-03-04 09:42:47 +01:00
James Cole
92af4e5c96 Layout tweaks. 2015-03-04 05:12:05 +01:00
James Cole
0619adb0cd Support any bill in any range. 2015-03-03 17:40:17 +01:00
James Cole
65a5107854 Small layout updates. 2015-03-03 09:35:06 +01:00
James Cole
0fcc1e252b Mail user registration confirmation. 2015-03-03 09:29:02 +01:00
James Cole
4b7f817475 Removed panel for table. 2015-03-03 09:19:16 +01:00
James Cole
0439599971 Layout update. 2015-03-03 09:15:28 +01:00
James Cole
fa344d5308 Do not update when no event connected. 2015-03-03 08:46:14 +01:00
James Cole
f0316f09ed Do not over / undercorrect 2015-03-02 20:29:10 +01:00
James Cole
b1af6bab28 Cleaning up and bug fixing. 2015-03-02 20:05:28 +01:00
James Cole
ad2aebb54d Sort account list. 2015-03-02 15:46:31 +01:00
James Cole
23fc652092 Table border. 2015-03-02 15:45:24 +01:00
James Cole
f0a5756f25 Add a panel-body for the layout. 2015-03-02 15:45:00 +01:00
James Cole
14c7ad201a Paginated the account list. 2015-03-02 15:44:06 +01:00
James Cole
08ca3c89d3 Expanded account view. 2015-03-02 15:27:36 +01:00
James Cole
edda470bf8 Add everything range 2015-03-02 13:19:13 +01:00
James Cole
7183d72e5c Update chart to include other budget repetitions. 2015-03-02 12:50:51 +01:00
James Cole
5e38ebfce5 Merge branch 'feature/date-range' into develop 2015-03-02 12:35:34 +01:00
James Cole
56e36847a5 New code for new date range thing. 2015-03-02 12:35:14 +01:00
James Cole
6dba916d02 New code & css for date range. 2015-03-02 12:04:40 +01:00
James Cole
fd57086ffd Better mostly report lists. 2015-03-02 11:54:20 +01:00
James Cole
d98d366eea Some small bug fixes in the account views. 2015-03-02 11:42:27 +01:00
James Cole
b261b0b447 Shared expense should of course be shared asset. 2015-03-02 11:27:46 +01:00
James Cole
c6042a9053 Try to fix modal dialog for piggy banks. 2015-03-01 19:47:42 +01:00
James Cole
ae1245abec Fixed update transactions. 2015-03-01 19:31:00 +01:00
James Cole
e26d2376fc Fixed piggy bank delete routine. 2015-03-01 19:26:30 +01:00
James Cole
bb36ad64a7 Moved the form. 2015-03-01 13:39:16 +01:00
James Cole
262d4f92d4 Fixed a bug where consecutive payments from one source would not be summed up. 2015-03-01 10:55:20 +01:00
James Cole
675530458c Account show didn't show anything. 2015-03-01 10:44:10 +01:00
James Cole
19e34b460f Update event. 2015-03-01 08:34:59 +01:00
James Cole
dddb8cdbc0 This loops. 2015-03-01 08:25:12 +01:00
James Cole
0d0df5f143 Scan bills when editing and creating journals. 2015-03-01 08:15:24 +01:00
James Cole
d1cf683f57 Some layout and content updates 2015-03-01 07:50:26 +01:00
James Cole
d099c33e5b No more code climate for now. 2015-02-27 21:40:49 +01:00
James Cole
21fb41545b Now with son_path variable. 2015-02-27 21:24:14 +01:00
James Cole
4c56814785 Do code coverage from phpunit. 2015-02-27 21:15:21 +01:00
James Cole
cffe05e22b Add coveralls to composer.json 2015-02-27 21:01:18 +01:00
James Cole
4237850299 Restoring code coverage 2015-02-27 20:52:49 +01:00
James Cole
b5fc36a8e1 Clean up test stuff. 2015-02-27 20:46:39 +01:00
James Cole
4586c1ef52 Removed all test cases. 2015-02-27 20:45:17 +01:00
James Cole
2722f0b749 Merge branch 'release/3.3.1' 2015-02-27 20:42:12 +01:00
James Cole
d6cf7c4872 Merge branch 'release/3.3.1' into develop 2015-02-27 20:42:12 +01:00
James Cole
3aedfed432 Updated version. 2015-02-27 20:42:04 +01:00
James Cole
edeaf13259 New CSS / JS code. 2015-02-27 18:05:40 +01:00
James Cole
c1290c4e9b Forgot to commit one view. 2015-02-27 16:53:06 +01:00
James Cole
b2c1527b17 Lost a lot of stuff along the way. 2015-02-27 16:48:33 +01:00
James Cole
a4a65ea56e Merge branch 'release/3.3' into develop 2015-02-27 16:15:30 +01:00
James Cole
ccf0e1875e Merge branch 'release/3.3' 2015-02-27 16:15:29 +01:00
James Cole
9c009aceaf Updated the readme. 2015-02-27 16:15:16 +01:00
James Cole
da4b1c7276 Merge branch 'laravel5' into develop
Conflicts:
	resources/views/reports/month.blade.php

Upgraded to Laravel 5.
2015-02-27 16:13:36 +01:00
James Cole
add098d5c0 Update example environment file and composer lock. 2015-02-27 16:09:00 +01:00
James Cole
aca096548c Fixed user login and authentication. 2015-02-27 16:08:46 +01:00
James Cole
75aa3abcae Update and create transactions. 2015-02-27 14:27:04 +01:00
James Cole
e685d262cc Sub/addDay routine to fix the account list. 2015-02-27 12:55:24 +01:00
James Cole
d2599d6ef9 Removed a subDay() call that ruined some reports. 2015-02-27 12:54:24 +01:00
James Cole
cd5223d98d Removed a group clause that broke the budget report. 2015-02-27 12:15:58 +01:00
James Cole
7b68d9047d Order budgets by name. 2015-02-27 12:02:14 +01:00
James Cole
9a7ea06d66 Order budgets by name 2015-02-27 11:58:49 +01:00
James Cole
c69ef34ac9 Order accounts by name. 2015-02-27 11:57:47 +01:00
James Cole
021999d05f Ignore .env file. 2015-02-27 11:46:07 +01:00
James Cole
6054430a5e Remove default .env file. 2015-02-27 11:45:47 +01:00
James Cole
8f578ed95a Search controller. 2015-02-27 11:09:23 +01:00
James Cole
fc5c339e27 Repeated expenses. 2015-02-27 11:02:08 +01:00
James Cole
defad3d820 More code. 2015-02-25 21:19:06 +01:00
James Cole
c0f96aa948 Piggy banks 2015-02-25 19:32:33 +01:00
James Cole
f2eae2fc98 Implemented the help. 2015-02-25 16:10:02 +01:00
James Cole
0e4f786978 Fixed currencies. 2015-02-25 15:57:43 +01:00
James Cole
d36b2318fd New code for bills. 2015-02-25 15:19:14 +01:00
James Cole
d83b508bbc Add and remove transactions. 2015-02-24 22:53:38 +01:00
James Cole
5b9c2cdc13 Newly converted code. 2015-02-24 21:10:25 +01:00
James Cole
49066c282a Updates 2015-02-23 21:55:52 +01:00
James Cole
3e28c0c00a Extra report and cleanup. 2015-02-23 21:19:16 +01:00
James Cole
220d689f69 Reports! 2015-02-23 20:25:48 +01:00
James Cole
5a0a28a04c Stuff for categories. 2015-02-22 16:19:32 +01:00
James Cole
b44e69e09b Fixed tests. 2015-02-22 15:45:32 +01:00
James Cole
fcbe10f5ec New code. 2015-02-22 15:40:13 +01:00
James Cole
182fe170fd Up to budgets now! 2015-02-22 09:46:21 +01:00
James Cole
184e9bdaf6 Fixed even more tests! 2015-02-22 08:38:46 +01:00
James Cole
0096f50cde Update month.blade.php
Add decryption routine.
2015-02-21 12:20:42 +01:00
James Cole
460f14deca Some new code. 2015-02-21 12:16:41 +01:00
James Cole
910ad45bee Update test [skip ci] 2015-02-14 17:35:45 +01:00
James Cole
74e319855d Updated the test to be more dynamic. 2015-02-14 17:31:51 +01:00
James Cole
9af0fb4cd5 Update tests 2015-02-14 16:22:33 +01:00
James Cole
185f5cce29 environment files. 2015-02-14 16:13:28 +01:00
James Cole
aca1174566 New git ignore. 2015-02-14 16:11:20 +01:00
James Cole
e791f7fde2 Fixed test. 2015-02-14 15:53:56 +01:00
James Cole
7bba7fcf66 Should fix the test. 2015-02-14 14:31:43 +01:00
James Cole
1d78f98ec8 This should complete the account handler. 2015-02-14 14:25:29 +01:00
James Cole
7ed2e03654 Merge pull request #62 from kilya11/master
Handle foreign keys
2015-02-11 14:29:19 +01:00
Ilya Kil
549e0f3477 Handle foreign keys
Installation fails without these changes
2015-02-11 13:19:24 +01:00
James Cole
7785ec0222 Code cleanup. 2015-02-11 07:35:10 +01:00
James Cole
ca504965f9 Should allow to store new accounts. 2015-02-09 07:56:24 +01:00
James Cole
3841259779 First attempt at storing an account. 2015-02-09 07:23:39 +01:00
James Cole
169d1065cc Removed debug 2015-02-08 09:45:00 +01:00
James Cole
e864f5507a No exit is kind of cheating. 2015-02-08 09:35:09 +01:00
James Cole
434b4ded4a Reimplemented forms, added an overdue fix. 2015-02-08 01:15:15 +01:00
James Cole
3d01669cea Reinstated soft deletes, added first steps for account controller. 2015-02-07 23:19:28 +01:00
James Cole
1499b2cd40 Login and some routes fixed. 2015-02-07 22:50:47 +01:00
James Cole
6b54ef8398 More code. 2015-02-07 13:15:40 +01:00
James Cole
07ad43f7a2 Updated models and tests to match. 2015-02-07 12:15:53 +01:00
James Cole
72e72c60c2 Laravel 4 > Laravel 5 2015-02-07 12:00:31 +01:00
James Cole
f9a242d33e Updated codeception config. 2015-02-07 11:05:56 +01:00
James Cole
b0f43eaa07 Moved C3 handler. 2015-02-07 11:01:47 +01:00
James Cole
b02046b884 Moar packages! 2015-02-07 10:52:51 +01:00
James Cole
864c931ee9 Fixed factory muffin 2015-02-07 10:46:14 +01:00
James Cole
5cd8da6d91 Added factory muffin. 2015-02-07 10:42:40 +01:00
James Cole
4a4671c2ae Add debug info to codeception 2015-02-07 10:39:36 +01:00
James Cole
8de142cd9a Add c3 code coverage. 2015-02-07 10:38:27 +01:00
James Cole
1a42bec51c Database in the right spot. 2015-02-07 10:32:15 +01:00
James Cole
577e38759e Try again. 2015-02-07 10:30:41 +01:00
James Cole
9cdf43a2c9 Commit new env files. 2015-02-07 10:24:54 +01:00
James Cole
62d43c2cb2 Lets see fit his works. 2015-02-07 10:16:14 +01:00
James Cole
2dc67d1674 Added all the old test things. 2015-02-07 08:42:20 +01:00
James Cole
fb1c78c657 Chart re-implemented and added coveralls and other instructions, which will probably not work at all. 2015-02-07 08:23:44 +01:00
James Cole
37e58ac13a Fixed more of the index. 2015-02-07 06:49:24 +01:00
James Cole
de715c14be Some new stuffs. 2015-02-06 21:23:14 +01:00
James Cole
c4d8a0da05 Fixed the range thing 2015-02-06 20:43:19 +01:00
James Cole
1b54b14671 All kinds of new stuff. 2015-02-06 19:33:31 +01:00
James Cole
a92efbc55f Exceptions. 2015-02-06 19:31:38 +01:00
James Cole
1bd02529e0 New resources mostly. 2015-02-06 07:23:26 +01:00
James Cole
bc16298b6e Some updates. 2015-02-06 05:35:00 +01:00
James Cole
804a97cad7 References 2015-02-06 05:14:27 +01:00
James Cole
ab52bdec15 Not changed much 2015-02-06 05:05:40 +01:00
James Cole
ddc3e82c14 Update references 2015-02-06 05:04:06 +01:00
James Cole
57691471bb Updated models and imports. 2015-02-06 05:01:24 +01:00
James Cole
c502dd445b New and old code. 2015-02-06 04:52:16 +01:00
James Cole
ed475b1b9c Database & seeds. 2015-02-06 04:41:00 +01:00
James Cole
df165a817c Fresh L5 installation. 2015-02-06 04:39:52 +01:00
James Cole
d16015d625 Moved all old code for Laravel 5. 2015-02-06 04:27:37 +01:00
James Cole
a4b3bf3ef4 Moved to hidden "stash" directory. 2015-02-06 04:22:46 +01:00
James Cole
6b006853e6 Stash is a directory which will hold pretty much all code before it's implemented into Laravel 5. 2015-02-06 04:21:22 +01:00
James Cole
6001180e29 Capitalisation for code coverage. 2015-02-04 06:25:19 +01:00
James Cole
662fbed1d0 Added a "valid" email address so certain tests go through. 2015-02-04 06:15:14 +01:00
James Cole
19c7e08c5d Code coverage. 2015-02-03 19:40:13 +01:00
James Cole
72f04aaedc Some cleaning up. 2015-02-01 17:20:51 +01:00
James Cole
2998382969 Check if entries have an encrypted description and act accordingly. 2015-02-01 14:56:25 +01:00
James Cole
37fe79944f Reorder bills [skip ci] 2015-02-01 14:52:40 +01:00
James Cole
536735519a Fixed related transaction tests. 2015-02-01 12:31:11 +01:00
James Cole
6b0a711395 Expanded test coverage. 2015-02-01 12:07:06 +01:00
James Cole
13d3d40376 More code cleanup [skip ci] 2015-02-01 09:30:27 +01:00
James Cole
6873336aca More cleanup [skip ci] 2015-02-01 09:08:39 +01:00
James Cole
c2d2eb53e8 Some code cleanup. 2015-02-01 08:51:27 +01:00
James Cole
210d597a48 Close issue #46 2015-01-31 21:10:00 +01:00
James Cole
e41ede0a6b Forgot the return statement 2015-01-31 17:30:41 +01:00
James Cole
4a8b17ac7c Fixed the search for related transfers. 2015-01-31 17:24:26 +01:00
James Cole
1f5f515d72 Cleanup JS. 2015-01-31 15:10:07 +01:00
James Cole
1e6242b89f Updated composer.lock 2015-01-31 15:10:00 +01:00
James Cole
dde09f9f89 Various code cleanup things inspired by Code Climate [skip ci] 2015-01-31 08:51:40 +01:00
James Cole
916d85c3fe Simplified the account opening balance code. 2015-01-31 08:32:00 +01:00
James Cole
70d28bbf6e Merge branch 'release/3.2.5' into develop 2015-01-31 06:35:37 +01:00
721 changed files with 40456 additions and 24976 deletions

View File

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

16
.env.example Normal file
View File

@@ -0,0 +1,16 @@
APP_ENV=local
APP_DEBUG=true
APP_KEY=SomeRandomString
DB_CONNECTION=mysql
DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
CACHE_DRIVER=file
SESSION_DRIVER=file
EMAIL_SMTP=
EMAIL_USERNAME=
EMAIL_PASSWORD=

13
.env.testing Normal file
View File

@@ -0,0 +1,13 @@
APP_ENV=testing
APP_DEBUG=true
APP_KEY=SomeRandomString
DB_CONNECTION=sqlite
DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
CACHE_DRIVER=file
SESSION_DRIVER=file

6
.gitignore vendored
View File

@@ -1,8 +1,6 @@
/bootstrap/compiled.php
/vendor
composer.phar
.env.*.php
.env.php
Thumbs.db
.idea/
tests/_output/*
@@ -25,3 +23,7 @@ tests/_data/dump.sql
db.sqlite_snapshot
c3.php
db.sqlite-journal
tests/_output/*
.env
clover.xml
node_modules/

View File

@@ -1,4 +1,6 @@
language: php
sudo: false
php:
- 5.5
@@ -11,14 +13,13 @@ addons:
install:
- rm composer.lock
- composer install
- php artisan env
- mv -v .env.testing .env
- touch tests/database/db.sqlite
- php artisan migrate --seed
script:
- ./tests/_data/db.sh
- php vendor/bin/codecept build
- php vendor/bin/codecept run --coverage --coverage-xml
- phpunit --debug
after_script:
- cp -v tests/_output/coverage.xml build/logs/clover.xml
- php vendor/bin/coveralls
- vendor/bin/test-reporter --stdout > codeclimate.json
- "curl -X POST -d @codeclimate.json -H 'Content-Type: application/json' -H 'User-Agent: Code Climate (PHP Test Reporter v0.1.1)' https://codeclimate.com/test_reports"

View File

@@ -1,9 +1,8 @@
Firefly III (v3.2.5)
Firefly III (v3.3.3)
===========
[![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=develop)](https://travis-ci.org/JC5/firefly-iii)
[![Project Status](http://stillmaintained.com/JC5/firefly-iii.png?a=b)](http://stillmaintained.com/JC5/firefly-iii)
[![Coverage Status](https://coveralls.io/repos/JC5/firefly-iii/badge.png?branch=master)](https://coveralls.io/r/JC5/firefly-iii?branch=master)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102/mini.png)](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102)
[![Code Climate](https://codeclimate.com/github/JC5/firefly-iii/badges/gpa.svg)](https://codeclimate.com/github/JC5/firefly-iii)
[![Test Coverage](https://codeclimate.com/github/JC5/firefly-iii/badges/coverage.svg)](https://codeclimate.com/github/JC5/firefly-iii)
@@ -13,7 +12,7 @@ Firefly III (v3.2.5)
[![Latest Unstable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/unstable.svg)](https://packagist.org/packages/grumpydictator/firefly-iii)
[![License](https://poser.pugx.org/grumpydictator/firefly-iii/license.svg)](https://packagist.org/packages/grumpydictator/firefly-iii)
Firefly II is a tool to help you manage your finances. Please read the full description [in the wiki](https://github.com/JC5/firefly-iii/wiki/full-description).
Firefly III is a tool to help you manage your finances. Please read the full description [in the wiki](https://github.com/JC5/firefly-iii/wiki/full-description).
Firefly Mark III is a new version of Firefly built upon best practices and lessons learned
from building [Firefly](https://github.com/JC5/Firefly). It's Mark III since the original Firefly never made it outside of my

View File

@@ -1,606 +0,0 @@
# ************************************************************
# Sequel Pro SQL dump
# Version 4096
#
# http://www.sequelpro.com/
# http://code.google.com/p/sequel-pro/
#
# Host: 127.0.0.1 (MySQL 5.6.19-0ubuntu0.14.04.1)
# Database: homestead
# Generation Time: 2015-01-02 19:01:30 +0000
# ************************************************************
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
# Dump of table account_meta
# ------------------------------------------------------------
DROP TABLE IF EXISTS `account_meta`;
CREATE TABLE `account_meta` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`account_id` int(10) unsigned NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`data` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `account_meta_account_id_name_unique` (`account_id`,`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table account_types
# ------------------------------------------------------------
DROP TABLE IF EXISTS `account_types`;
CREATE TABLE `account_types` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`type` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
`editable` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `account_types_type_unique` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `account_types` WRITE;
/*!40000 ALTER TABLE `account_types` DISABLE KEYS */;
INSERT INTO `account_types` (`id`, `created_at`, `updated_at`, `type`, `editable`)
VALUES
(1,'2015-01-02 19:00:13','2015-01-02 19:00:13','Default account',1),
(2,'2015-01-02 19:00:13','2015-01-02 19:00:13','Cash account',0),
(3,'2015-01-02 19:00:13','2015-01-02 19:00:13','Asset account',1),
(4,'2015-01-02 19:00:13','2015-01-02 19:00:13','Expense account',1),
(5,'2015-01-02 19:00:13','2015-01-02 19:00:13','Revenue account',1),
(6,'2015-01-02 19:00:13','2015-01-02 19:00:13','Initial balance account',0),
(7,'2015-01-02 19:00:13','2015-01-02 19:00:13','Beneficiary account',1),
(8,'2015-01-02 19:00:13','2015-01-02 19:00:13','Import account',0);
/*!40000 ALTER TABLE `account_types` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table accounts
# ------------------------------------------------------------
DROP TABLE IF EXISTS `accounts`;
CREATE TABLE `accounts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`user_id` int(10) unsigned NOT NULL,
`account_type_id` int(10) unsigned NOT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`active` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `accounts_user_id_account_type_id_name_unique` (`user_id`,`account_type_id`,`name`),
KEY `accounts_account_type_id_foreign` (`account_type_id`),
CONSTRAINT `accounts_account_type_id_foreign` FOREIGN KEY (`account_type_id`) REFERENCES `account_types` (`id`) ON DELETE CASCADE,
CONSTRAINT `accounts_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table bills
# ------------------------------------------------------------
DROP TABLE IF EXISTS `bills`;
CREATE TABLE `bills` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(10) unsigned NOT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`match` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`amount_min` decimal(10,2) NOT NULL,
`amount_max` decimal(10,2) NOT NULL,
`date` date NOT NULL,
`active` tinyint(1) NOT NULL,
`automatch` tinyint(1) NOT NULL,
`repeat_freq` enum('daily','weekly','monthly','quarterly','half-year','yearly') COLLATE utf8_unicode_ci NOT NULL,
`skip` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uid_name_unique` (`user_id`,`name`),
CONSTRAINT `bills_uid_for` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table budget_limits
# ------------------------------------------------------------
DROP TABLE IF EXISTS `budget_limits`;
CREATE TABLE `budget_limits` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`budget_id` int(10) unsigned DEFAULT NULL,
`startdate` date NOT NULL,
`amount` decimal(10,2) NOT NULL,
`repeats` tinyint(1) NOT NULL,
`repeat_freq` enum('daily','weekly','monthly','quarterly','half-year','yearly') COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_ci_combi` (`startdate`,`repeat_freq`),
UNIQUE KEY `unique_bl_combi` (`budget_id`,`startdate`,`repeat_freq`),
CONSTRAINT `bid_foreign` FOREIGN KEY (`budget_id`) REFERENCES `budgets` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table budget_transaction_journal
# ------------------------------------------------------------
DROP TABLE IF EXISTS `budget_transaction_journal`;
CREATE TABLE `budget_transaction_journal` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`budget_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `budid_tjid_unique` (`budget_id`,`transaction_journal_id`),
KEY `budget_transaction_journal_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `budget_transaction_journal_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE,
CONSTRAINT `budget_transaction_journal_budget_id_foreign` FOREIGN KEY (`budget_id`) REFERENCES `budgets` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table budgets
# ------------------------------------------------------------
DROP TABLE IF EXISTS `budgets`;
CREATE TABLE `budgets` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `budgets_user_id_name_unique` (`user_id`,`name`),
CONSTRAINT `budgets_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table categories
# ------------------------------------------------------------
DROP TABLE IF EXISTS `categories`;
CREATE TABLE `categories` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `categories_user_id_name_unique` (`user_id`,`name`),
CONSTRAINT `categories_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table category_transaction_journal
# ------------------------------------------------------------
DROP TABLE IF EXISTS `category_transaction_journal`;
CREATE TABLE `category_transaction_journal` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`category_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `catid_tjid_unique` (`category_id`,`transaction_journal_id`),
KEY `category_transaction_journal_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `category_transaction_journal_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE,
CONSTRAINT `category_transaction_journal_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table components
# ------------------------------------------------------------
DROP TABLE IF EXISTS `components`;
CREATE TABLE `components` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(10) unsigned NOT NULL,
`class` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `components_user_id_class_name_unique` (`user_id`,`class`,`name`),
CONSTRAINT `components_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table limit_repetitions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `limit_repetitions`;
CREATE TABLE `limit_repetitions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`budget_limit_id` int(10) unsigned NOT NULL,
`startdate` date NOT NULL,
`enddate` date NOT NULL,
`amount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `limit_repetitions_limit_id_startdate_enddate_unique` (`budget_limit_id`,`startdate`,`enddate`),
CONSTRAINT `limit_repetitions_limit_id_foreign` FOREIGN KEY (`budget_limit_id`) REFERENCES `budget_limits` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table migrations
# ------------------------------------------------------------
DROP TABLE IF EXISTS `migrations`;
CREATE TABLE `migrations` (
`migration` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`batch` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `migrations` WRITE;
/*!40000 ALTER TABLE `migrations` DISABLE KEYS */;
INSERT INTO `migrations` (`migration`, `batch`)
VALUES
('2014_06_27_163032_create_users_table',1),
('2014_06_27_163145_create_account_types_table',1),
('2014_06_27_163259_create_accounts_table',1),
('2014_06_27_163817_create_components_table',1),
('2014_06_27_163818_create_piggybanks_table',1),
('2014_06_27_164042_create_transaction_currencies_table',1),
('2014_06_27_164512_create_transaction_types_table',1),
('2014_06_27_164619_create_recurring_transactions_table',1),
('2014_06_27_164620_create_transaction_journals_table',1),
('2014_06_27_164836_create_transactions_table',1),
('2014_06_27_165344_create_component_transaction_table',1),
('2014_07_05_171326_create_component_transaction_journal_table',1),
('2014_07_06_123842_create_preferences_table',1),
('2014_07_09_204843_create_session_table',1),
('2014_07_17_183717_create_limits_table',1),
('2014_07_19_055011_create_limit_repeat_table',1),
('2014_08_06_044416_create_component_recurring_transaction_table',1),
('2014_08_12_173919_create_piggybank_repetitions_table',1),
('2014_08_18_100330_create_piggybank_events_table',1),
('2014_08_23_113221_create_reminders_table',1),
('2014_11_10_172053_create_account_meta_table',1),
('2014_11_29_135749_create_transaction_groups_table',1),
('2014_11_29_140217_create_transaction_group_transaction_journal_table',1),
('2014_12_13_190730_changes_for_v321',1),
('2014_12_24_191544_changes_for_v322',1);
/*!40000 ALTER TABLE `migrations` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table piggy_bank_events
# ------------------------------------------------------------
DROP TABLE IF EXISTS `piggy_bank_events`;
CREATE TABLE `piggy_bank_events` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`piggy_bank_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned DEFAULT NULL,
`date` date NOT NULL,
`amount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
KEY `piggybank_events_piggybank_id_foreign` (`piggy_bank_id`),
KEY `piggybank_events_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `piggybank_events_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE SET NULL,
CONSTRAINT `piggybank_events_piggybank_id_foreign` FOREIGN KEY (`piggy_bank_id`) REFERENCES `piggy_banks` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table piggy_bank_repetitions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `piggy_bank_repetitions`;
CREATE TABLE `piggy_bank_repetitions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`piggy_bank_id` int(10) unsigned NOT NULL,
`startdate` date DEFAULT NULL,
`targetdate` date DEFAULT NULL,
`currentamount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `piggybank_repetitions_piggybank_id_startdate_targetdate_unique` (`piggy_bank_id`,`startdate`,`targetdate`),
CONSTRAINT `piggybank_repetitions_piggybank_id_foreign` FOREIGN KEY (`piggy_bank_id`) REFERENCES `piggy_banks` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table piggy_banks
# ------------------------------------------------------------
DROP TABLE IF EXISTS `piggy_banks`;
CREATE TABLE `piggy_banks` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`account_id` int(10) unsigned NOT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`targetamount` decimal(10,2) NOT NULL,
`startdate` date DEFAULT NULL,
`targetdate` date DEFAULT NULL,
`repeats` tinyint(1) NOT NULL,
`rep_length` enum('day','week','quarter','month','year') COLLATE utf8_unicode_ci DEFAULT NULL,
`rep_every` smallint(5) unsigned NOT NULL,
`rep_times` smallint(5) unsigned DEFAULT NULL,
`reminder` enum('day','week','quarter','month','year') COLLATE utf8_unicode_ci DEFAULT NULL,
`reminder_skip` smallint(5) unsigned NOT NULL,
`remind_me` tinyint(1) NOT NULL,
`order` int(10) unsigned NOT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `piggybanks_account_id_name_unique` (`account_id`,`name`),
CONSTRAINT `piggybanks_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table preferences
# ------------------------------------------------------------
DROP TABLE IF EXISTS `preferences`;
CREATE TABLE `preferences` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(10) unsigned NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`data` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `preferences_user_id_name_unique` (`user_id`,`name`),
CONSTRAINT `preferences_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table reminders
# ------------------------------------------------------------
DROP TABLE IF EXISTS `reminders`;
CREATE TABLE `reminders` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(10) unsigned NOT NULL,
`startdate` date NOT NULL,
`enddate` date DEFAULT NULL,
`active` tinyint(1) NOT NULL,
`notnow` tinyint(1) NOT NULL DEFAULT '0',
`remindersable_id` int(10) unsigned DEFAULT NULL,
`remindersable_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `reminders_user_id_foreign` (`user_id`),
CONSTRAINT `reminders_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table sessions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `sessions`;
CREATE TABLE `sessions` (
`id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`payload` text COLLATE utf8_unicode_ci NOT NULL,
`last_activity` int(11) NOT NULL,
UNIQUE KEY `sessions_id_unique` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_currencies
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_currencies`;
CREATE TABLE `transaction_currencies` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`code` varchar(3) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(48) COLLATE utf8_unicode_ci DEFAULT NULL,
`symbol` varchar(8) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `transaction_currencies_code_unique` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `transaction_currencies` WRITE;
/*!40000 ALTER TABLE `transaction_currencies` DISABLE KEYS */;
INSERT INTO `transaction_currencies` (`id`, `created_at`, `updated_at`, `deleted_at`, `code`, `name`, `symbol`)
VALUES
(1,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'EUR','Euro','€'),
(2,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'USD','US Dollar','$'),
(3,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'HUF','Hungarian forint','Ft');
/*!40000 ALTER TABLE `transaction_currencies` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table transaction_group_transaction_journal
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_group_transaction_journal`;
CREATE TABLE `transaction_group_transaction_journal` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`transaction_group_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `tt_joined` (`transaction_group_id`,`transaction_journal_id`),
KEY `tr_trj_id` (`transaction_journal_id`),
CONSTRAINT `tr_trj_id` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE,
CONSTRAINT `tr_grp_id` FOREIGN KEY (`transaction_group_id`) REFERENCES `transaction_groups` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_groups
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_groups`;
CREATE TABLE `transaction_groups` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`user_id` int(10) unsigned NOT NULL,
`relation` enum('balance') COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `transaction_groups_user_id_foreign` (`user_id`),
CONSTRAINT `transaction_groups_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_journals
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_journals`;
CREATE TABLE `transaction_journals` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`user_id` int(10) unsigned NOT NULL,
`transaction_type_id` int(10) unsigned NOT NULL,
`bill_id` int(10) unsigned DEFAULT NULL,
`transaction_currency_id` int(10) unsigned NOT NULL,
`description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`completed` tinyint(1) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`id`),
KEY `transaction_journals_user_id_foreign` (`user_id`),
KEY `transaction_journals_transaction_type_id_foreign` (`transaction_type_id`),
KEY `transaction_journals_transaction_currency_id_foreign` (`transaction_currency_id`),
KEY `bill_id_foreign` (`bill_id`),
CONSTRAINT `bill_id_foreign` FOREIGN KEY (`bill_id`) REFERENCES `bills` (`id`) ON DELETE SET NULL,
CONSTRAINT `transaction_journals_transaction_currency_id_foreign` FOREIGN KEY (`transaction_currency_id`) REFERENCES `transaction_currencies` (`id`) ON DELETE CASCADE,
CONSTRAINT `transaction_journals_transaction_type_id_foreign` FOREIGN KEY (`transaction_type_id`) REFERENCES `transaction_types` (`id`) ON DELETE CASCADE,
CONSTRAINT `transaction_journals_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_types
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_types`;
CREATE TABLE `transaction_types` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`type` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `transaction_types_type_unique` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `transaction_types` WRITE;
/*!40000 ALTER TABLE `transaction_types` DISABLE KEYS */;
INSERT INTO `transaction_types` (`id`, `created_at`, `updated_at`, `deleted_at`, `type`)
VALUES
(1,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Withdrawal'),
(2,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Deposit'),
(3,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Transfer'),
(4,'2015-01-02 19:00:13','2015-01-02 19:00:13',NULL,'Opening balance');
/*!40000 ALTER TABLE `transaction_types` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table transactions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transactions`;
CREATE TABLE `transactions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`account_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
`description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`amount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
KEY `transactions_account_id_foreign` (`account_id`),
KEY `transactions_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `transactions_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE,
CONSTRAINT `transactions_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table users
# ------------------------------------------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`reset` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`remember_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

View File

@@ -1,607 +0,0 @@
# ************************************************************
# Sequel Pro SQL dump
# Version 4096
#
# http://www.sequelpro.com/
# http://code.google.com/p/sequel-pro/
#
# Host: 127.0.0.1 (MySQL 5.6.19-0ubuntu0.14.04.1)
# Database: homestead
# Generation Time: 2015-01-31 05:33:30 +0000
# ************************************************************
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
# Dump of table account_meta
# ------------------------------------------------------------
DROP TABLE IF EXISTS `account_meta`;
CREATE TABLE `account_meta` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`account_id` int(10) unsigned NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`data` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `account_meta_account_id_name_unique` (`account_id`,`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table account_types
# ------------------------------------------------------------
DROP TABLE IF EXISTS `account_types`;
CREATE TABLE `account_types` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`type` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
`editable` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `account_types_type_unique` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `account_types` WRITE;
/*!40000 ALTER TABLE `account_types` DISABLE KEYS */;
INSERT INTO `account_types` (`id`, `created_at`, `updated_at`, `type`, `editable`)
VALUES
(1,'2015-01-31 05:33:21','2015-01-31 05:33:21','Default account',1),
(2,'2015-01-31 05:33:21','2015-01-31 05:33:21','Cash account',0),
(3,'2015-01-31 05:33:21','2015-01-31 05:33:21','Asset account',1),
(4,'2015-01-31 05:33:21','2015-01-31 05:33:21','Expense account',1),
(5,'2015-01-31 05:33:21','2015-01-31 05:33:21','Revenue account',1),
(6,'2015-01-31 05:33:21','2015-01-31 05:33:21','Initial balance account',0),
(7,'2015-01-31 05:33:21','2015-01-31 05:33:21','Beneficiary account',1),
(8,'2015-01-31 05:33:21','2015-01-31 05:33:21','Import account',0);
/*!40000 ALTER TABLE `account_types` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table accounts
# ------------------------------------------------------------
DROP TABLE IF EXISTS `accounts`;
CREATE TABLE `accounts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`user_id` int(10) unsigned NOT NULL,
`account_type_id` int(10) unsigned NOT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`active` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `accounts_user_id_account_type_id_name_unique` (`user_id`,`account_type_id`,`name`),
KEY `accounts_account_type_id_foreign` (`account_type_id`),
CONSTRAINT `accounts_account_type_id_foreign` FOREIGN KEY (`account_type_id`) REFERENCES `account_types` (`id`) ON DELETE CASCADE,
CONSTRAINT `accounts_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table bills
# ------------------------------------------------------------
DROP TABLE IF EXISTS `bills`;
CREATE TABLE `bills` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(10) unsigned NOT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`match` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`amount_min` decimal(10,2) NOT NULL,
`amount_max` decimal(10,2) NOT NULL,
`date` date NOT NULL,
`active` tinyint(1) NOT NULL,
`automatch` tinyint(1) NOT NULL,
`repeat_freq` enum('daily','weekly','monthly','quarterly','half-year','yearly') COLLATE utf8_unicode_ci NOT NULL,
`skip` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uid_name_unique` (`user_id`,`name`),
CONSTRAINT `bills_uid_for` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table budget_limits
# ------------------------------------------------------------
DROP TABLE IF EXISTS `budget_limits`;
CREATE TABLE `budget_limits` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`budget_id` int(10) unsigned DEFAULT NULL,
`startdate` date NOT NULL,
`amount` decimal(10,2) NOT NULL,
`repeats` tinyint(1) NOT NULL,
`repeat_freq` enum('daily','weekly','monthly','quarterly','half-year','yearly') COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_bl_combi` (`budget_id`,`startdate`,`repeat_freq`),
CONSTRAINT `bid_foreign` FOREIGN KEY (`budget_id`) REFERENCES `budgets` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table budget_transaction_journal
# ------------------------------------------------------------
DROP TABLE IF EXISTS `budget_transaction_journal`;
CREATE TABLE `budget_transaction_journal` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`budget_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `budid_tjid_unique` (`budget_id`,`transaction_journal_id`),
KEY `budget_transaction_journal_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `budget_transaction_journal_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE,
CONSTRAINT `budget_transaction_journal_budget_id_foreign` FOREIGN KEY (`budget_id`) REFERENCES `budgets` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table budgets
# ------------------------------------------------------------
DROP TABLE IF EXISTS `budgets`;
CREATE TABLE `budgets` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `budgets_user_id_name_unique` (`user_id`,`name`),
CONSTRAINT `budgets_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table categories
# ------------------------------------------------------------
DROP TABLE IF EXISTS `categories`;
CREATE TABLE `categories` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `categories_user_id_name_unique` (`user_id`,`name`),
CONSTRAINT `categories_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table category_transaction_journal
# ------------------------------------------------------------
DROP TABLE IF EXISTS `category_transaction_journal`;
CREATE TABLE `category_transaction_journal` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`category_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `catid_tjid_unique` (`category_id`,`transaction_journal_id`),
KEY `category_transaction_journal_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `category_transaction_journal_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE,
CONSTRAINT `category_transaction_journal_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table components
# ------------------------------------------------------------
DROP TABLE IF EXISTS `components`;
CREATE TABLE `components` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(10) unsigned NOT NULL,
`class` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `components_user_id_class_name_unique` (`user_id`,`class`,`name`),
CONSTRAINT `components_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table limit_repetitions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `limit_repetitions`;
CREATE TABLE `limit_repetitions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`budget_limit_id` int(10) unsigned NOT NULL,
`startdate` date NOT NULL,
`enddate` date NOT NULL,
`amount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `limit_repetitions_limit_id_startdate_enddate_unique` (`budget_limit_id`,`startdate`,`enddate`),
CONSTRAINT `limit_repetitions_limit_id_foreign` FOREIGN KEY (`budget_limit_id`) REFERENCES `budget_limits` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table migrations
# ------------------------------------------------------------
DROP TABLE IF EXISTS `migrations`;
CREATE TABLE `migrations` (
`migration` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`batch` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `migrations` WRITE;
/*!40000 ALTER TABLE `migrations` DISABLE KEYS */;
INSERT INTO `migrations` (`migration`, `batch`)
VALUES
('2014_06_27_163032_create_users_table',1),
('2014_06_27_163145_create_account_types_table',1),
('2014_06_27_163259_create_accounts_table',1),
('2014_06_27_163817_create_components_table',1),
('2014_06_27_163818_create_piggybanks_table',1),
('2014_06_27_164042_create_transaction_currencies_table',1),
('2014_06_27_164512_create_transaction_types_table',1),
('2014_06_27_164619_create_recurring_transactions_table',1),
('2014_06_27_164620_create_transaction_journals_table',1),
('2014_06_27_164836_create_transactions_table',1),
('2014_06_27_165344_create_component_transaction_table',1),
('2014_07_05_171326_create_component_transaction_journal_table',1),
('2014_07_06_123842_create_preferences_table',1),
('2014_07_09_204843_create_session_table',1),
('2014_07_17_183717_create_limits_table',1),
('2014_07_19_055011_create_limit_repeat_table',1),
('2014_08_06_044416_create_component_recurring_transaction_table',1),
('2014_08_12_173919_create_piggybank_repetitions_table',1),
('2014_08_18_100330_create_piggybank_events_table',1),
('2014_08_23_113221_create_reminders_table',1),
('2014_11_10_172053_create_account_meta_table',1),
('2014_11_29_135749_create_transaction_groups_table',1),
('2014_11_29_140217_create_transaction_group_transaction_journal_table',1),
('2014_12_13_190730_changes_for_v321',1),
('2014_12_24_191544_changes_for_v322',1),
('2015_01_18_082406_changes_for_v325',1);
/*!40000 ALTER TABLE `migrations` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table piggy_bank_events
# ------------------------------------------------------------
DROP TABLE IF EXISTS `piggy_bank_events`;
CREATE TABLE `piggy_bank_events` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`piggy_bank_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned DEFAULT NULL,
`date` date NOT NULL,
`amount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
KEY `piggybank_events_piggybank_id_foreign` (`piggy_bank_id`),
KEY `piggybank_events_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `piggybank_events_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE SET NULL,
CONSTRAINT `piggybank_events_piggybank_id_foreign` FOREIGN KEY (`piggy_bank_id`) REFERENCES `piggy_banks` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table piggy_bank_repetitions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `piggy_bank_repetitions`;
CREATE TABLE `piggy_bank_repetitions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`piggy_bank_id` int(10) unsigned NOT NULL,
`startdate` date DEFAULT NULL,
`targetdate` date DEFAULT NULL,
`currentamount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `piggybank_repetitions_piggybank_id_startdate_targetdate_unique` (`piggy_bank_id`,`startdate`,`targetdate`),
CONSTRAINT `piggybank_repetitions_piggybank_id_foreign` FOREIGN KEY (`piggy_bank_id`) REFERENCES `piggy_banks` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table piggy_banks
# ------------------------------------------------------------
DROP TABLE IF EXISTS `piggy_banks`;
CREATE TABLE `piggy_banks` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`account_id` int(10) unsigned NOT NULL,
`name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`targetamount` decimal(10,2) NOT NULL,
`startdate` date DEFAULT NULL,
`targetdate` date DEFAULT NULL,
`repeats` tinyint(1) NOT NULL,
`rep_length` enum('day','week','quarter','month','year') COLLATE utf8_unicode_ci DEFAULT NULL,
`rep_every` smallint(5) unsigned NOT NULL,
`rep_times` smallint(5) unsigned DEFAULT NULL,
`reminder` enum('day','week','quarter','month','year') COLLATE utf8_unicode_ci DEFAULT NULL,
`reminder_skip` smallint(5) unsigned NOT NULL,
`remind_me` tinyint(1) NOT NULL,
`order` int(10) unsigned NOT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `piggybanks_account_id_name_unique` (`account_id`,`name`),
CONSTRAINT `piggybanks_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table preferences
# ------------------------------------------------------------
DROP TABLE IF EXISTS `preferences`;
CREATE TABLE `preferences` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(10) unsigned NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`data` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `preferences_user_id_name_unique` (`user_id`,`name`),
CONSTRAINT `preferences_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table reminders
# ------------------------------------------------------------
DROP TABLE IF EXISTS `reminders`;
CREATE TABLE `reminders` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(10) unsigned NOT NULL,
`startdate` date NOT NULL,
`enddate` date DEFAULT NULL,
`active` tinyint(1) NOT NULL,
`notnow` tinyint(1) NOT NULL DEFAULT '0',
`remindersable_id` int(10) unsigned DEFAULT NULL,
`remindersable_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `reminders_user_id_foreign` (`user_id`),
CONSTRAINT `reminders_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table sessions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `sessions`;
CREATE TABLE `sessions` (
`id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`payload` text COLLATE utf8_unicode_ci NOT NULL,
`last_activity` int(11) NOT NULL,
UNIQUE KEY `sessions_id_unique` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_currencies
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_currencies`;
CREATE TABLE `transaction_currencies` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`code` varchar(3) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(48) COLLATE utf8_unicode_ci DEFAULT NULL,
`symbol` varchar(8) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `transaction_currencies_code_unique` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `transaction_currencies` WRITE;
/*!40000 ALTER TABLE `transaction_currencies` DISABLE KEYS */;
INSERT INTO `transaction_currencies` (`id`, `created_at`, `updated_at`, `deleted_at`, `code`, `name`, `symbol`)
VALUES
(1,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'EUR','Euro','€'),
(2,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'USD','US Dollar','$'),
(3,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'HUF','Hungarian forint','Ft');
/*!40000 ALTER TABLE `transaction_currencies` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table transaction_group_transaction_journal
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_group_transaction_journal`;
CREATE TABLE `transaction_group_transaction_journal` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`transaction_group_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `tt_joined` (`transaction_group_id`,`transaction_journal_id`),
KEY `tr_trj_id` (`transaction_journal_id`),
CONSTRAINT `tr_trj_id` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE,
CONSTRAINT `tr_grp_id` FOREIGN KEY (`transaction_group_id`) REFERENCES `transaction_groups` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_groups
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_groups`;
CREATE TABLE `transaction_groups` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`user_id` int(10) unsigned NOT NULL,
`relation` enum('balance') COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `transaction_groups_user_id_foreign` (`user_id`),
CONSTRAINT `transaction_groups_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_journals
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_journals`;
CREATE TABLE `transaction_journals` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`user_id` int(10) unsigned NOT NULL,
`transaction_type_id` int(10) unsigned NOT NULL,
`bill_id` int(10) unsigned DEFAULT NULL,
`transaction_currency_id` int(10) unsigned NOT NULL,
`description` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL,
`completed` tinyint(1) NOT NULL,
`date` date NOT NULL,
`encrypted` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `transaction_journals_user_id_foreign` (`user_id`),
KEY `transaction_journals_transaction_type_id_foreign` (`transaction_type_id`),
KEY `transaction_journals_transaction_currency_id_foreign` (`transaction_currency_id`),
KEY `bill_id_foreign` (`bill_id`),
CONSTRAINT `bill_id_foreign` FOREIGN KEY (`bill_id`) REFERENCES `bills` (`id`) ON DELETE SET NULL,
CONSTRAINT `transaction_journals_transaction_currency_id_foreign` FOREIGN KEY (`transaction_currency_id`) REFERENCES `transaction_currencies` (`id`) ON DELETE CASCADE,
CONSTRAINT `transaction_journals_transaction_type_id_foreign` FOREIGN KEY (`transaction_type_id`) REFERENCES `transaction_types` (`id`) ON DELETE CASCADE,
CONSTRAINT `transaction_journals_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table transaction_types
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transaction_types`;
CREATE TABLE `transaction_types` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`type` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `transaction_types_type_unique` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
LOCK TABLES `transaction_types` WRITE;
/*!40000 ALTER TABLE `transaction_types` DISABLE KEYS */;
INSERT INTO `transaction_types` (`id`, `created_at`, `updated_at`, `deleted_at`, `type`)
VALUES
(1,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'Withdrawal'),
(2,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'Deposit'),
(3,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'Transfer'),
(4,'2015-01-31 05:33:21','2015-01-31 05:33:21',NULL,'Opening balance');
/*!40000 ALTER TABLE `transaction_types` ENABLE KEYS */;
UNLOCK TABLES;
# Dump of table transactions
# ------------------------------------------------------------
DROP TABLE IF EXISTS `transactions`;
CREATE TABLE `transactions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
`account_id` int(10) unsigned NOT NULL,
`transaction_journal_id` int(10) unsigned NOT NULL,
`description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`amount` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
KEY `transactions_account_id_foreign` (`account_id`),
KEY `transactions_transaction_journal_id_foreign` (`transaction_journal_id`),
CONSTRAINT `transactions_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE,
CONSTRAINT `transactions_transaction_journal_id_foreign` FOREIGN KEY (`transaction_journal_id`) REFERENCES `transaction_journals` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# Dump of table users
# ------------------------------------------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`reset` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`remember_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

11
app/Commands/Command.php Normal file
View File

@@ -0,0 +1,11 @@
<?php namespace FireflyIII\Commands;
/**
* Class Command
*
* @package FireflyIII\Commands
*/
abstract class Command
{
}

View File

@@ -0,0 +1,37 @@
<?php namespace FireflyIII\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Foundation\Inspiring;
/**
* Class Inspire
*
* @package FireflyIII\Console\Commands
*/
class Inspire extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Display an inspiring quote';
/**
* The console command name.
*
* @var string
*/
protected $name = 'inspire';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->comment(PHP_EOL . Inspiring::quote() . PHP_EOL);
}
}

37
app/Console/Kernel.php Normal file
View File

@@ -0,0 +1,37 @@
<?php namespace FireflyIII\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
/**
* Class Kernel
*
* @package FireflyIII\Console
*/
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands
= [
'FireflyIII\Console\Commands\Inspire',
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
*
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('inspire')
->hourly();
}
}

13
app/Events/Event.php Normal file
View File

@@ -0,0 +1,13 @@
<?php namespace FireflyIII\Events;
/**
* Class Event
*
* @package FireflyIII\Events
*/
abstract class Event
{
//
}

View File

@@ -0,0 +1,33 @@
<?php namespace FireflyIII\Events;
use FireflyIII\Events\Event;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Queue\SerializesModels;
/**
* Class JournalCreated
*
* @package FireflyIII\Events
*/
class JournalCreated extends Event {
use SerializesModels;
public $journal;
public $piggyBankId;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(TransactionJournal $journal, $piggyBankId)
{
//
$this->journal = $journal;
$this->piggyBankId = $piggyBankId;
}
}

View File

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

View File

@@ -0,0 +1,25 @@
<?php namespace FireflyIII\Events;
use FireflyIII\Events\Event;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Queue\SerializesModels;
class JournalSaved extends Event {
use SerializesModels;
public $journal;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(TransactionJournal $journal)
{
//
$this->journal = $journal;
}
}

View File

@@ -1,12 +1,12 @@
<?php
namespace FireflyIII\Exception;
namespace FireflyIII\Exceptions;
/**
* Class FireflyException
*
* @package FireflyIII\Exception
* @package FireflyIII\Exceptions
*/
class FireflyException extends \Exception
{

View File

@@ -0,0 +1,56 @@
<?php namespace FireflyIII\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
/**
* Class Handler
*
* @package FireflyIII\Exceptions
*/
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport
= [
'Symfony\Component\HttpKernel\Exception\HttpException'
];
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
*
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
if ($this->isHttpException($e)) {
return $this->renderHttpException($e);
} else {
return parent::render($request, $e);
}
}
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
*
* @return void
*/
public function report(Exception $e)
{
/** @noinspection PhpInconsistentReturnPointsInspection */
return parent::report($e);
}
}

View File

@@ -1,11 +1,11 @@
<?php
namespace FireflyIII\Exception;
namespace FireflyIII\Exceptions;
/**
* Class NotImplementedException
*
* @package FireflyIII\Exception
* @package FireflyIII\Exceptions
*/
class NotImplementedException extends \Exception
{

View File

@@ -1,8 +1,8 @@
<?php
namespace FireflyIII\Exception;
namespace FireflyIII\Exceptions;
/**
* Class ValidationException
* Class ValidationExceptions
*
* @package FireflyIII\Exception
*/

View File

@@ -0,0 +1,89 @@
<?php namespace FireflyIII\Handlers\Events;
use Auth;
use FireflyIII\Events\JournalCreated;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use Log;
/**
* Class ConnectJournalToPiggyBank
*
* @package FireflyIII\Handlers\Events
*/
class ConnectJournalToPiggyBank
{
/**
* Create the event handler.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event when journal is saved.
*
* @param JournalCreated $event
*
* @return void
*/
public function handle(JournalCreated $event)
{
/** @var TransactionJournal $journal */
$journal = $event->journal;
$piggyBankId = $event->piggyBankId;
if(intval($piggyBankId) < 1) {
return;
}
Log::debug('JournalCreated event: ' . $journal->id . ', ' . $piggyBankId);
/** @var PiggyBank $piggyBank */
$piggyBank = Auth::user()->piggybanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
if (is_null($piggyBank) || $journal->transactionType->type != 'Transfer') {
return;
}
Log::debug('Found a piggy bank');
$amount = 0;
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($transaction->account_id === $piggyBank->account_id) {
// this transaction is the relevant one.
$amount = floatval($transaction->amount);
}
}
Log::debug('Amount: ' . $amount);
if ($amount == 0) {
return;
}
// update piggy bank rep for date of transaction journal.
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
if (is_null($repetition)) {
Log::debug('Found no repetition for piggy bank for date '.$journal->date->format('Y M d'));
return;
}
Log::debug('Found rep! ' . $repetition->id);
$repetition->currentamount += $amount;
$repetition->save();
PiggyBankEvent::create(
[
'piggy_bank_id' => $piggyBank->id,
'transaction_journal_id' => $journal->id,
'date' => $journal->date,
'amount' => $amount
]
);
}
}

View File

@@ -0,0 +1,33 @@
<?php namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\JournalDeleted;
use Illuminate\Contracts\Queue\ShouldBeQueued;
use Illuminate\Queue\InteractsWithQueue;
class JournalDeletedHandler
{
/**
* Create the event handler.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param JournalDeleted $event
*
* @return void
*/
public function handle(JournalDeleted $event)
{
//
}
}

View File

@@ -0,0 +1,53 @@
<?php namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\JournalSaved;
use Log;
use App;
/**
* Class RescanJournal
*
* @package FireflyIII\Handlers\Events
*/
class RescanJournal
{
/**
* Create the event handler.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param JournalSaved $event
*
* @return void
*/
public function handle(JournalSaved $event)
{
$journal = $event->journal;
Log::debug('Triggered saved event for journal #' . $journal->id . ' (' . $journal->description . ')');
/** @var \FireflyIII\Repositories\Bill\BillRepositoryInterface $repository */
$repository = App::make('FireflyIII\Repositories\Bill\BillRepositoryInterface');
$list = $journal->user->bills()->where('active', 1)->where('automatch', 1)->get();
Log::debug('Found ' . $list->count() . ' bills to check.');
/** @var Bill $bill */
foreach ($list as $bill) {
Log::debug('Now calling bill #' . $bill->id . ' (' . $bill->name . ')');
$repository->scan($bill, $journal);
}
Log::debug('Done!');
}
}

View File

@@ -0,0 +1,64 @@
<?php namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\JournalSaved;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
class UpdateJournalConnection
{
/**
* Create the event handler.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param JournalSaved $event
*
* @return void
*/
public function handle(JournalSaved $event)
{
$journal = $event->journal;
// get the event connected to this journal:
/** @var PiggyBankEvent $event */
$event = PiggyBankEvent::where('transaction_journal_id', $journal->id)->first();
if(is_null($event)) {
return;
}
$piggyBank = $event->piggyBank()->first();
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
if (is_null($repetition)) {
return;
}
$amount = 0;
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($transaction->account_id === $piggyBank->account_id) {
// this transaction is the relevant one.
$amount = floatval($transaction->amount);
}
}
// update current repetition:
$diff = $amount - $event->amount;
$repetition->currentamount += $diff;
$repetition->save();
$event->amount = $amount;
$event->save();
}
}

View File

@@ -0,0 +1,146 @@
<?php
namespace FireflyIII\Helpers\Reminders;
use Amount;
use Auth;
use Carbon\Carbon;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Reminder;
use Navigation;
/**
* Class ReminderHelper
*
* @package FireflyIII\Helpers\Reminders
*/
class ReminderHelper implements ReminderHelperInterface
{
/**
* @param PiggyBank $piggyBank
* @param Carbon $start
* @param Carbon $end
*
* @return Reminder
*/
public function createReminder(PiggyBank $piggyBank, Carbon $start, Carbon $end)
{
$reminder = Auth::user()->reminders()->where('remindersable_id', $piggyBank->id)->onDates($start, $end)->first();
if (is_null($reminder)) {
if (!is_null($piggyBank->targetdate)) {
// get ranges again, but now for the start date
$ranges = $this->getReminderRanges($piggyBank, $start);
$currentRep = $piggyBank->currentRelevantRep();
$left = $piggyBank->targetamount - $currentRep->currentamount;
$perReminder = $left / count($ranges);
} else {
$perReminder = null;
$ranges = [];
$left = 0;
}
$metaData = [
'perReminder' => $perReminder,
'rangesCount' => count($ranges),
'ranges' => $ranges,
'leftToSave' => $left,
];
// create one:
$reminder = new Reminder;
$reminder->user()->associate(Auth::user());
$reminder->startdate = $start;
$reminder->enddate = $end;
$reminder->active = true;
$reminder->metadata = $metaData;
$reminder->notnow = false;
$reminder->remindersable()->associate($piggyBank);
$reminder->save();
return $reminder;
} else {
return $reminder;
}
}
/**
* This routine will return an array consisting of two dates which indicate the start
* and end date for each reminder that this piggy bank will have, if the piggy bank has
* any reminders. For example:
*
* [12 mar - 15 mar]
* [15 mar - 18 mar]
*
* etcetera.
*
* Array is filled with tiny arrays with Carbon objects in them.
*
* @param PiggyBank $piggyBank
* @param Carbon $date ;
*
* @return array
*/
public function getReminderRanges(PiggyBank $piggyBank, Carbon $date = null)
{
$ranges = [];
if (is_null($date)) {
$date = new Carbon;
}
if ($piggyBank->remind_me === false) {
return $ranges;
}
if (!is_null($piggyBank->targetdate)) {
// count back until now.
// echo 'Count back!<br>';
$start = $piggyBank->targetdate;
$end = $piggyBank->startdate;
while ($start > $end) {
$currentEnd = clone $start;
$start = Navigation::subtractPeriod($start, $piggyBank->reminder, 1);
$currentStart = clone $start;
$ranges[] = ['start' => clone $currentStart, 'end' => clone $currentEnd];
}
} else {
$start = clone $piggyBank->startdate;
while ($start < $date) {
$currentStart = clone $start;
$start = Navigation::addPeriod($start, $piggyBank->reminder, 0);
$currentEnd = clone $start;
$ranges[] = ['start' => clone $currentStart, 'end' => clone $currentEnd];
}
}
return $ranges;
}
/**
* Takes a reminder, finds the piggy bank and tells you what to do now.
* Aka how much money to put in.
*
*
* @param Reminder $reminder
*
* @return string
*/
public function getReminderText(Reminder $reminder)
{
/** @var PiggyBank $piggyBank */
$piggyBank = $reminder->remindersable;
if (is_null($piggyBank)) {
return 'Piggy bank no longer exists.';
}
if (is_null($piggyBank->targetdate)) {
return 'Add money to this piggy bank to reach your target of ' . Amount::format($piggyBank->targetamount);
}
return 'Add ' . Amount::format($reminder->metadata->perReminder) . ' to fill this piggy bank on ' . $piggyBank->targetdate->format('jS F Y');
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace FireflyIII\Helpers\Reminders;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\PiggyBank;
use Carbon\Carbon;
/**
* Interface ReminderHelperInterface
*
* @package FireflyIII\Helpers\Reminders
*/
interface ReminderHelperInterface {
/**
* Takes a reminder, finds the piggy bank and tells you what to do now.
* Aka how much money to put in.
*
* @param Reminder $reminder
*
* @return string
*/
public function getReminderText(Reminder $reminder);
/**
* This routine will return an array consisting of two dates which indicate the start
* and end date for each reminder that this piggy bank will have, if the piggy bank has
* any reminders. For example:
*
* [12 mar - 15 mar]
* [15 mar - 18 mar]
*
* etcetera.
*
* Array is filled with tiny arrays with Carbon objects in them.
*
* @param PiggyBank $piggyBank
*
* @return array
*/
public function getReminderRanges(PiggyBank $piggyBank);
/**
* @param PiggyBank $piggyBank
* @param Carbon $start
* @param Carbon $end
*
* @return Reminder
*/
public function createReminder(PiggyBank $piggyBank, Carbon $start, Carbon $end);
}

View File

@@ -0,0 +1,168 @@
<?php
namespace FireflyIII\Helpers\Report;
use Auth;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Steam;
/**
* Class ReportHelper
*
* @package FireflyIII\Helpers\Report
*/
class ReportHelper implements ReportHelperInterface
{
/**
* This methods fails to take in account transfers FROM shared accounts.
*
* @param Carbon $start
* @param Carbon $end
* @param int $limit
*
* @return Collection
*/
public function expensesGroupedByAccount(Carbon $start, Carbon $end, $limit = 15)
{
$result = $this->_queries->journalsByExpenseAccount($start, $end);
$array = $this->_helper->makeArray($result);
$limited = $this->_helper->limitArray($array, $limit);
return $limited;
}
/**
* This method gets some kind of list for a monthly overview.
*
* @param Carbon $date
*
* @return Collection
*/
public function getBudgetsForMonth(Carbon $date)
{
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
// all budgets
$set = Auth::user()->budgets()
->leftJoin(
'budget_limits', function (JoinClause $join) use ($date) {
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
}
)
->get(['budgets.*', 'budget_limits.amount as amount']);
$budgets = $this->_helper->makeArray($set);
$amountSet = $this->_queries->journalsByBudget($start, $end);
$amounts = $this->_helper->makeArray($amountSet);
$combined = $this->_helper->mergeArrays($budgets, $amounts);
$combined[0]['spent'] = isset($combined[0]['spent']) ? $combined[0]['spent'] : 0.0;
$combined[0]['amount'] = isset($combined[0]['amount']) ? $combined[0]['amount'] : 0.0;
$combined[0]['name'] = 'No budget';
// find transactions to shared expense accounts, which are without a budget by default:
$transfers = $this->_queries->sharedExpenses($start, $end);
foreach ($transfers as $transfer) {
$combined[0]['spent'] += floatval($transfer->amount) * -1;
}
return $combined;
}
/**
* @param Carbon $date
*
* @return array
*/
public function listOfMonths(Carbon $date)
{
$start = clone $date;
$end = Carbon::now();
$months = [];
while ($start <= $end) {
$year = $start->format('Y');
$months[$year][] = [
'formatted' => $start->format('F Y'),
'month' => intval($start->format('m')),
'year' => intval($start->format('Y')),
];
$start->addMonth();
}
return $months;
}
/**
* @param Carbon $date
*
* @return array
*/
public function listOfYears(Carbon $date)
{
$start = clone $date;
$end = Carbon::now();
$years = [];
while ($start <= $end) {
$years[] = $start->format('Y');
$start->addYear();
}
return $years;
}
/**
* @param Carbon $date
* @param bool $showSharedReports
*
* @return array
*/
public function yearBalanceReport(Carbon $date, $showSharedReports = false)
{
$start = clone $date;
$end = clone $date;
$sharedAccounts = [];
if ($showSharedReports === false) {
$sharedCollection = \Auth::user()->accounts()
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
->where('account_meta.name', '=', 'accountRole')
->where('account_meta.data', '=', json_encode('sharedAsset'))
->get(['accounts.id']);
foreach ($sharedCollection as $account) {
$sharedAccounts[] = $account->id;
}
}
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*'])
->filter(
function (Account $account) use ($sharedAccounts) {
if (!in_array($account->id, $sharedAccounts)) {
return $account;
}
return null;
}
);
$report = [];
$start->startOfYear()->subDay();
$end->endOfYear();
foreach ($accounts as $account) {
$report[] = [
'start' => Steam::balance($account, $start),
'end' => Steam::balance($account, $end),
'account' => $account,
'shared' => $account->accountRole == 'sharedAsset'
];
}
return $report;
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
use Illuminate\Support\Collection;
/**
* Interface ReportHelperInterface
*
* @package FireflyIII\Helpers\Report
*/
interface ReportHelperInterface
{
/**
* This methods fails to take in account transfers FROM shared accounts.
*
* @param Carbon $start
* @param Carbon $end
* @param int $limit
*
* @return Collection
*/
public function expensesGroupedByAccount(Carbon $start, Carbon $end, $limit = 15);
/**
* This method gets some kind of list for a monthly overview.
*
* @param Carbon $date
*
* @return Collection
*/
public function getBudgetsForMonth(Carbon $date);
/**
* @param Carbon $date
*
* @return array
*/
public function listOfMonths(Carbon $date);
/**
* @param Carbon $date
*
* @return array
*/
public function listOfYears(Carbon $date);
/**
* @param Carbon $date
* @param bool $showSharedReports
*
* @return array
*/
public function yearBalanceReport(Carbon $date, $showSharedReports = false);
}

View File

@@ -0,0 +1,607 @@
<?php
namespace FireflyIII\Helpers\Report;
use Auth;
use Carbon\Carbon;
use DB;
use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Steam;
/**
* Class ReportQuery
*
* @package FireflyIII\Helpers\Report
*/
class ReportQuery implements ReportQueryInterface
{
/**
* This query retrieves a list of accounts that are active and not shared.
*
* @param bool $showSharedReports
*
* @return Collection
*/
public function accountList($showSharedReports = false)
{
$query = Auth::user()->accounts();
if ($showSharedReports === false) {
$query->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', "accountRole");
}
)->where(
function (Builder $query) {
$query->where('account_meta.data', '!=', '"sharedAsset"');
$query->orWhereNull('account_meta.data');
}
);
}
$query->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', ['Default account', 'Cash account', 'Asset account'])
->where('active', 1)
->orderBy('accounts.name', 'ASC');
return $query->get(['accounts.*']);
}
/**
* This method will get a list of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function balancedTransactionsList(Account $account, Carbon $start, Carbon $end)
{
$set = TransactionJournal::
leftJoin('transaction_group_transaction_journal', 'transaction_group_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin(
'transaction_group_transaction_journal as otherFromGroup', function (JoinClause $join) {
$join->on('otherFromGroup.transaction_group_id', '=', 'transaction_group_transaction_journal.transaction_group_id')
->on('otherFromGroup.transaction_journal_id', '!=', 'transaction_journals.id');
}
)
->leftJoin('transaction_journals as otherJournals', 'otherJournals.id', '=', 'otherFromGroup.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'otherJournals.transaction_type_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0);
}
)
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'otherJournals.id')
->before($end)->after($start)
->where('transaction_types.type', 'Withdrawal')
->where('transaction_journals.user_id', Auth::user()->id)
->whereNull('budget_transaction_journal.budget_id')->whereNull('transaction_journals.deleted_at')
->whereNull('otherJournals.deleted_at')
->where('transactions.account_id', $account->id)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order','ASC')
->orderBy('transaction_journals.id','DESC')
->whereNotNull('transaction_group_transaction_journal.transaction_group_id')
->get(
[
'transaction_journals.*',
'transactions.amount'
]
);
return $set;
}
/**
* This method will get the sum of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function balancedTransactionsSum(Account $account, Carbon $start, Carbon $end)
{
$set = $this->balancedTransactionsList($account, $start, $end);
$sum = 0;
foreach ($set as $entry) {
$sum += floatval($entry->amount);
}
return $sum;
}
/**
* Get a users accounts combined with various meta-data related to the start and end date.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function getAllAccounts(Carbon $start, Carbon $end, $showSharedReports = false)
{
$query = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')
->accountTypeIn(['Default account', 'Asset account', 'Cash account']);
if ($showSharedReports === false) {
$query->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->orderBy('accounts.name', 'ASC')
->where(
function (Builder $query) use ($showSharedReports) {
$query->where('account_meta.data', '!=', '"sharedAsset"');
$query->orWhereNull('account_meta.data');
}
);
}
$set = $query->get(['accounts.*']);
$set->each(
function (Account $account) use ($start, $end) {
/** @noinspection PhpParamsInspection */
$account->startBalance = Steam::balance($account, $start);
$account->endBalance = Steam::balance($account, $end);
}
);
return $set;
}
/**
* Grabs a summary of all expenses grouped by budget, related to the account.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getBudgetSummary(Account $account, Carbon $start, Carbon $end)
{
$set = TransactionJournal::
leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budgets', 'budgets.id', '=', 'budget_transaction_journal.budget_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->before($end)
->after($start)
->where('accounts.id', $account->id)
->where('transaction_journals.user_id', Auth::user()->id)
->where('transaction_types.type', 'Withdrawal')
->groupBy('budgets.id')
->orderBy('budgets.name', 'ASC')
->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) as `amount`')]);
return $set;
}
/**
* Get a list of transaction journals that have no budget, filtered for the specified account
* and the specified date range.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getTransactionsWithoutBudget(Account $account, Carbon $start, Carbon $end)
{
$set = TransactionJournal::
leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budgets', 'budgets.id', '=', 'budget_transaction_journal.budget_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where('transactions.amount', '<', 0);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->before($end)
->after($start)
->where('accounts.id', $account->id)
->where('transaction_journals.user_id', Auth::user()->id)
->where('transaction_types.type', 'Withdrawal')
->whereNull('budgets.id')
->orderBy('transaction_journals.date', 'ASC')
->get(['budgets.name', 'transactions.amount', 'transaction_journals.*']);
return $set;
}
/**
* This method returns all "income" journals in a certain period, which are both transfers from a shared account
* and "ordinary" deposits. The query used is almost equal to ReportQueryInterface::journalsByRevenueAccount but it does
* not group and returns different fields.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function incomeByPeriod(Carbon $start, Carbon $end, $showSharedReports = false)
{
$query = TransactionJournal::
leftJoin(
'transactions as t_from', function (JoinClause $join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
}
)
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin(
'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin(
'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
if ($showSharedReports === false) {
// only get deposits not to a shared account
// and transfers to a shared account.
$query->where(
function ($query) {
$query->where(
function ($q) {
$q->where('transaction_types.type', 'Deposit');
$q->where('acm_to.data', '!=', '"sharedAsset"');
}
);
$query->orWhere(
function ($q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_from.data', '=', '"sharedAsset"');
}
);
}
);
} else {
// any deposit is fine.
$query->where('transaction_types.type', 'Deposit');
}
$query->before($end)->after($start)
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('t_from.account_id')->orderBy('transaction_journals.date');
return $query->get(
['transaction_journals.id',
'transaction_journals.description',
'transaction_journals.encrypted',
'transaction_types.type',
DB::Raw('SUM(`t_to`.`amount`) as `amount`'),
'transaction_journals.date',
't_from.account_id as account_id',
'ac_from.name as name']
);
}
/**
* Gets a list of expenses grouped by the budget they were filed under.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByBudget(Carbon $start, Carbon $end, $showSharedReports = false)
{
$query = Auth::user()->transactionjournals()
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id');
if ($showSharedReports === false) {
$query->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)->where('account_meta.data', '!=', '"sharedAsset"');
}
$query->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_types.type', 'Withdrawal')
->groupBy('budgets.id')
->orderBy('budgets.name', 'ASC');
return $query->get(['budgets.id', 'budgets.name', DB::Raw('SUM(`transactions`.`amount`) AS `spent`')]);
}
/**
* Gets a list of categories and the expenses therein, grouped by the relevant category.
* This result excludes transfers to shared accounts which are expenses, technically.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByCategory(Carbon $start, Carbon $end, $showSharedReports = false)
{
$query = Auth::user()->transactionjournals()
->leftJoin(
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
)
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id');
if ($showSharedReports === false) {
$query->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)->where('account_meta.data', '!=', '"sharedAsset"');
}
$query->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('transaction_types.type', 'Withdrawal')
->groupBy('categories.id')
->orderBy('amount');
return $query->get(['categories.id', 'categories.name', DB::Raw('SUM(`transactions`.`amount`) AS `amount`')]);
}
/**
* Gets a list of expense accounts and the expenses therein, grouped by that expense account.
* This result excludes transfers to shared accounts which are expenses, technically.
*
* So now it will include them!
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByExpenseAccount(Carbon $start, Carbon $end, $showSharedReports = false)
{
$query = TransactionJournal::leftJoin(
'transactions as t_from', function (JoinClause $join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
}
)->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin(
'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin(
'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
if ($showSharedReports === false) {
// get all withdrawals not from a shared accounts
// and all transfers to a shared account
$query->where(
function ($query) {
$query->where(
function ($q) {
$q->where('transaction_types.type', 'Withdrawal');
$q->where('acm_from.data', '!=', '"sharedAsset"');
}
);
$query->orWhere(
function ($q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_to.data', '=', '"sharedAsset"');
}
);
}
);
} else {
// any withdrawal goes:
$query->where('transaction_types.type', 'Withdrawal');
}
$query->before($end)
->after($start)
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('t_to.account_id')
->orderBy('amount', 'DESC');
return $query->get(['t_to.account_id as id', 'ac_to.name as name', DB::Raw('SUM(t_to.amount) as `amount`')]);
}
/**
* This method returns all deposits into asset accounts, grouped by the revenue account,
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByRevenueAccount(Carbon $start, Carbon $end, $showSharedReports = false)
{
$query = TransactionJournal::
leftJoin(
'transactions as t_from', function (JoinClause $join) {
$join->on('t_from.transaction_journal_id', '=', 'transaction_journals.id')->where('t_from.amount', '<', 0);
}
)
->leftJoin('accounts as ac_from', 't_from.account_id', '=', 'ac_from.id')
->leftJoin(
'account_meta as acm_from', function (JoinClause $join) {
$join->on('ac_from.id', '=', 'acm_from.account_id')->where('acm_from.name', '=', 'accountRole');
}
)
->leftJoin(
'transactions as t_to', function (JoinClause $join) {
$join->on('t_to.transaction_journal_id', '=', 'transaction_journals.id')->where('t_to.amount', '>', 0);
}
)
->leftJoin('accounts as ac_to', 't_to.account_id', '=', 'ac_to.id')
->leftJoin(
'account_meta as acm_to', function (JoinClause $join) {
$join->on('ac_to.id', '=', 'acm_to.account_id')->where('acm_to.name', '=', 'accountRole');
}
)
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
if ($showSharedReports === false) {
// show queries where transfer type is deposit, and its not to a shared account
// or where its a transfer and its from a shared account (both count as incomes)
$query->where(
function ($query) {
$query->where(
function ($q) {
$q->where('transaction_types.type', 'Deposit');
$q->where('acm_to.data', '!=', '"sharedAsset"');
}
);
$query->orWhere(
function ($q) {
$q->where('transaction_types.type', 'Transfer');
$q->where('acm_from.data', '=', '"sharedAsset"');
}
);
}
);
} else {
// any deposit goes:
$query->where('transaction_types.type', 'Deposit');
}
$query->before($end)->after($start)
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('t_from.account_id')->orderBy('amount');
return $query->get(['t_from.account_id as account_id', 'ac_from.name as name', DB::Raw('SUM(t_from.amount) as `amount`')]);
}
/**
* With an equally misleading name, this query returns are transfers to shared accounts. These are considered
* expenses.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function sharedExpenses(Carbon $start, Carbon $end)
{
return TransactionJournal::
leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where(
'transactions.amount', '>', 0
);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->where('account_meta.data', '"sharedAsset"')
->after($start)
->before($end)
->where('transaction_types.type', 'Transfer')
->where('transaction_journals.user_id', Auth::user()->id)
->get(
['transaction_journals.id', 'transaction_journals.description', 'transactions.account_id', 'accounts.name',
'transactions.amount']
);
}
/**
* With a slightly misleading name, this query returns all transfers to shared accounts
* which are technically expenses, since it won't be just your money that gets spend.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function sharedExpensesByCategory(Carbon $start, Carbon $end)
{
return TransactionJournal::
leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin(
'transactions', function (JoinClause $join) {
$join->on('transactions.transaction_journal_id', '=', 'transaction_journals.id')->where(
'transactions.amount', '>', 0
);
}
)
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin(
'account_meta', function (JoinClause $join) {
$join->on('account_meta.account_id', '=', 'accounts.id')->where('account_meta.name', '=', 'accountRole');
}
)
->leftJoin(
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
)
->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id')
->where('account_meta.data', '"sharedAsset"')
->after($start)
->before($end)
->where('transaction_types.type', 'Transfer')
->where('transaction_journals.user_id', Auth::user()->id)
->groupBy('categories.name')
->get(
[
'categories.id',
'categories.name as name',
DB::Raw('SUM(`transactions`.`amount`) * -1 AS `amount`')
]
);
}
}

View File

@@ -1,15 +1,15 @@
<?php
namespace FireflyIII\Report;
namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use Illuminate\Support\Collection;
/**
* Interface ReportQueryInterface
*
* @package FireflyIII\Report
* @package FireflyIII\Helpers\Report
*/
interface ReportQueryInterface
{
@@ -17,105 +17,69 @@ interface ReportQueryInterface
/**
* This query retrieves a list of accounts that are active and not shared.
*
* @param bool $showSharedReports
*
* @return Collection
*/
public function accountList();
public function accountList($showSharedReports = false);
/**
* This method will get a list of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function balancedTransactionsList(Account $account, Carbon $start, Carbon $end);
/**
* This method will get the sum of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function balancedTransactionsSum(Account $account, Carbon $start, Carbon $end);
/**
* Get a users accounts combined with various meta-data related to the start and end date.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function getAllAccounts(Carbon $start, Carbon $end);
public function getAllAccounts(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Grabs a summary of all expenses grouped by budget, related to the account.
*
* @param \Account $account
* @param Carbon $start
* @param Carbon $end
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getBudgetSummary(\Account $account, Carbon $start, Carbon $end);
public function getBudgetSummary(Account $account, Carbon $start, Carbon $end);
/**
* This method will sum up all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
* Get a list of transaction journals that have no budget, filtered for the specified account
* and the specified date range.
*
* @param \Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return float
*/
public function balancedTransactionsSum(\Account $account, Carbon $start, Carbon $end);
/**
* This method will get a list of all expenses in a certain time period that have no budget
* and are balanced by a transfer to make up for it.
*
* @param \Account $account
* @param Carbon $start
* @param Carbon $end
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function balancedTransactionsList(\Account $account, Carbon $start, Carbon $end);
/**
* Gets a list of all budgets and if present, the amount of the current BudgetLimit
* as well
*
* @param Carbon $date
*
* @return Collection
*/
public function getAllBudgets(Carbon $date);
/**
* Gets a list of expenses grouped by the budget they were filed under.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function journalsByBudget(Carbon $start, Carbon $end);
/**
* Gets a list of categories and the expenses therein, grouped by the relevant category.
* This result excludes transfers to shared accounts which are expenses, technically.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function journalsByCategory(Carbon $start, Carbon $end);
/**
* Gets a list of expense accounts and the expenses therein, grouped by that expense account.
* This result excludes transfers to shared accounts which are expenses, technically.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function journalsByExpenseAccount(Carbon $start, Carbon $end);
/**
* This method returns all deposits into asset accounts, grouped by the revenue account,
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function journalsByRevenueAccount(Carbon $start, Carbon $end);
public function getTransactionsWithoutBudget(Account $account, Carbon $start, Carbon $end);
/**
* This method returns all "income" journals in a certain period, which are both transfers from a shared account
@@ -124,10 +88,59 @@ interface ReportQueryInterface
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function incomeByPeriod(Carbon $start, Carbon $end);
public function incomeByPeriod(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Gets a list of expenses grouped by the budget they were filed under.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByBudget(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Gets a list of categories and the expenses therein, grouped by the relevant category.
* This result excludes transfers to shared accounts which are expenses, technically.
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByCategory(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* Gets a list of expense accounts and the expenses therein, grouped by that expense account.
* This result excludes transfers to shared accounts which are expenses, technically.
*
* So now it will include them!
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByExpenseAccount(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* This method returns all deposits into asset accounts, grouped by the revenue account,
*
* @param Carbon $start
* @param Carbon $end
* @param bool $showSharedReports
*
* @return Collection
*/
public function journalsByRevenueAccount(Carbon $start, Carbon $end, $showSharedReports = false);
/**
* With an equally misleading name, this query returns are transfers to shared accounts. These are considered
@@ -142,7 +155,7 @@ interface ReportQueryInterface
/**
* With a slightly misleading name, this query returns all transfers to shared accounts
* grouped by category (which are technically expenses, since it won't be just your money that gets spend).
* which are technically expenses, since it won't be just your money that gets spend.
*
* @param Carbon $start
* @param Carbon $end
@@ -150,5 +163,4 @@ interface ReportQueryInterface
* @return Collection
*/
public function sharedExpensesByCategory(Carbon $start, Carbon $end);
}
}

View File

@@ -0,0 +1,238 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use Config;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\AccountFormRequest;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator;
use Input;
use Redirect;
use Session;
use Steam;
use View;
/**
* Class AccountController
*
* @package FireflyIII\Http\Controllers
*/
class AccountController extends Controller
{
/**
*
*/
public function __construct()
{
View::share('mainTitleIcon', 'fa-credit-card');
View::share('title', 'Accounts');
}
/**
* @param string $what
*
* @return \Illuminate\View\View
*/
public function create($what = 'asset')
{
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $what);
$subTitle = 'Create a new ' . e($what) . ' account';
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
}
/**
* @param Account $account
*
* @return \Illuminate\View\View
*/
public function delete(Account $account)
{
$subTitle = 'Delete ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
return view('accounts.delete', compact('account', 'subTitle'));
}
/**
* @param Account $account
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Account $account, AccountRepositoryInterface $repository)
{
$type = $account->accountType->type;
$typeName = Config::get('firefly.shortNamesByFullName.' . $type);
$name = $account->name;
$repository->destroy($account);
Session::flash('success', 'The ' . e($typeName) . ' account "' . e($name) . '" was deleted.');
return Redirect::route('accounts.index', $typeName);
}
/**
* @param Account $account
* @param AccountRepositoryInterface $repository
*
* @return View
*/
public function edit(Account $account, AccountRepositoryInterface $repository)
{
$what = Config::get('firefly.shortNamesByFullName')[$account->accountType->type];
$subTitle = 'Edit ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
$openingBalance = $repository->openingBalanceTransaction($account);
// pre fill some useful values.
// the opening balance is tricky:
$openingBalanceAmount = null;
if ($openingBalance) {
$transaction = $openingBalance->transactions()->where('account_id', $account->id)->first();
$openingBalanceAmount = $transaction->amount;
}
$preFilled = [
'accountRole' => $account->getMeta('accountRole'),
'openingBalanceDate' => $openingBalance ? $openingBalance->date->format('Y-m-d') : null,
'openingBalance' => $openingBalanceAmount
];
Session::flash('preFilled', $preFilled);
return view('accounts.edit', compact('account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what'));
}
/**
* @param string $what
*
* @return View
*/
public function index($what = 'default')
{
$subTitle = Config::get('firefly.subTitlesByIdentifier.' . $what);
$subTitleIcon = Config::get('firefly.subIconsByIdentifier.' . $what);
$types = Config::get('firefly.accountTypesByIdentifier.' . $what);
$size = 50;
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$offset = ($page - 1) * $size;
// move to repository:
$set = Auth::user()->accounts()->with(
['accountmeta' => function ($query) {
$query->where('name', 'accountRole');
}]
)->accountTypeIn($types)->take($size)->offset($offset)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$total = Auth::user()->accounts()->accountTypeIn($types)->count();
// last activity:
$start = clone Session::get('start');
$start->subDay();
$set->each(
function (Account $account) use ($start) {
$lastTransaction = $account->transactions()->leftJoin(
'transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id'
)->orderBy('transaction_journals.date', 'DESC')->first(['transactions.*', 'transaction_journals.date']);
if ($lastTransaction) {
$account->lastActivityDate = $lastTransaction->transactionjournal->date;
} else {
$account->lastActivityDate = null;
}
$account->startBalance = Steam::balance($account, $start);
$account->endBalance = Steam::balance($account, Session::get('end'));
}
);
$accounts = new LengthAwarePaginator($set, $total, $size, $page);
$accounts->setPath(route('accounts.index', $what));
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
}
/**
* @param Account $account
* @param AccountRepositoryInterface $repository
*
* @return View
*/
public function show(Account $account, AccountRepositoryInterface $repository)
{
$page = intval(Input::get('page')) == 0 ? 1 : intval(Input::get('page'));
$subTitleIcon = Config::get('firefly.subTitlesByIdentifier.' . $account->accountType->type);
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
$journals = $repository->getJournals($account, $page);
$subTitle = 'Details for ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
$journals->setPath('accounts/show/'.$account->id);
return view('accounts.show', compact('account', 'what', 'subTitleIcon', 'journals', 'subTitle'));
}
/**
* @param AccountFormRequest $request
* @param AccountRepositoryInterface $repository
*
* @return \Illuminate\Http\RedirectResponse
*/
public function store(AccountFormRequest $request, AccountRepositoryInterface $repository)
{
$accountData = [
'name' => $request->input('name'),
'accountType' => $request->input('what'),
'active' => true,
'user' => Auth::user()->id,
'accountRole' => $request->input('accountRole'),
'openingBalance' => floatval($request->input('openingBalance')),
'openingBalanceDate' => new Carbon($request->input('openingBalanceDate')),
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
];
$account = $repository->store($accountData);
Session::flash('success', 'New account "' . $account->name . '" stored!');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('accounts.create', $request->input('what'))->withInput();
}
return Redirect::route('accounts.index', $request->input('what'));
}
/**
* @param Account $account
* @param AccountFormRequest $request
* @param AccountRepositoryInterface $repository
*
* @return \Illuminate\Http\RedirectResponse
*/
public function update(Account $account, AccountFormRequest $request, AccountRepositoryInterface $repository)
{
$what = Config::get('firefly.shortNamesByFullName.' . $account->accountType->type);
$accountData = [
'name' => $request->input('name'),
'active' => $request->input('active'),
'user' => Auth::user()->id,
'accountRole' => $request->input('accountRole'),
'openingBalance' => floatval($request->input('openingBalance')),
'openingBalanceDate' => new Carbon($request->input('openingBalanceDate')),
'openingBalanceCurrency' => intval($request->input('balance_currency_id')),
];
$repository->update($account, $accountData);
Session::flash('success', 'Account "' . $account->name . '" updated.');
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('accounts.edit', $account->id);
}
return Redirect::route('accounts.index', $what);
}
}

View File

@@ -0,0 +1,88 @@
<?php namespace FireflyIII\Http\Controllers\Auth;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\Registrar;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Http\Request;
use Mail;
use Session;
/**
* Class AuthController
*
* @package FireflyIII\Http\Controllers\Auth
*/
class AuthController extends Controller
{
/*
|--------------------------------------------------------------------------
| 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?
|
*/
use AuthenticatesAndRegistersUsers;
public $redirectTo = '/';
/**
* Create a new authentication controller instance.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
* @param \Illuminate\Contracts\Auth\Registrar $registrar
*
*/
public function __construct(Guard $auth, Registrar $registrar)
{
$this->auth = $auth;
$this->registrar = $registrar;
$this->middleware('guest', ['except' => 'getLogout']);
}
/**
* Handle a registration request for the application.
*
* @param Request $request
*
* @return \Illuminate\Http\Response
*/
public function postRegister(Request $request)
{
$validator = $this->registrar->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$data =$request->all();
$data['password'] = bcrypt($data['password']);
$this->auth->login($this->registrar->create($data));
// get the email address
$email = $this->auth->user()->email;
// send email.
Mail::send(
'emails.registered', [], function ($message) use ($email) {
$message->to($email, $email)->subject('Welcome to Firefly III!');
}
);
// set flash message
Session::flash('success', 'You have registered successfully!');
return redirect($this->redirectPath());
}
}

View File

@@ -0,0 +1,48 @@
<?php namespace FireflyIII\Http\Controllers\Auth;
use FireflyIII\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\PasswordBroker;
use Illuminate\Foundation\Auth\ResetsPasswords;
/**
* Class PasswordController
*
* @package FireflyIII\Http\Controllers\Auth
*/
class PasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
protected $redirectPath = '/';
/**
* Create a new password controller instance.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
* @param \Illuminate\Contracts\Auth\PasswordBroker $passwords
*
*/
public function __construct(Guard $auth, PasswordBroker $passwords)
{
$this->auth = $auth;
$this->passwords = $passwords;
$this->middleware('guest');
}
}

View File

@@ -0,0 +1,220 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\BillFormRequest;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Input;
use Redirect;
use Session;
use URL;
use View;
/**
* Class BillController
*
* @package FireflyIII\Http\Controllers
*/
class BillController extends Controller
{
public function __construct()
{
View::share('title', 'Bills');
View::share('mainTitleIcon', 'fa-calendar-o');
}
/**
* @return $this
*/
public function create()
{
$periods = \Config::get('firefly.periods_to_text');
return view('bills.create')->with('periods', $periods)->with('subTitle', 'Create new');
}
/**
* @param Bill $bill
*
* @return $this
*/
public function delete(Bill $bill)
{
return view('bills.delete')->with('bill', $bill)->with('subTitle', 'Delete "' . e($bill->name) . '"');
}
/**
* @param Bill $bill
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Bill $bill)
{
$bill->delete();
Session::flash('success', 'The bill was deleted.');
return Redirect::route('bills.index');
}
/**
* @param Bill $bill
*
* @return $this
*/
public function edit(Bill $bill)
{
$periods = \Config::get('firefly.periods_to_text');
return view('bills.edit')->with('periods', $periods)->with('bill', $bill)->with('subTitle', 'Edit "' . e($bill->name) . '"');
}
/**
* @param BillRepositoryInterface $repository
*
* @return \Illuminate\View\View
*/
public function index(BillRepositoryInterface $repository)
{
$bills = Auth::user()->bills()->orderBy('name', 'ASC')->get();
$bills->each(
function (Bill $bill) use ($repository) {
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
$last = $bill->transactionjournals()->orderBy('date', 'DESC')->first();
$bill->lastFoundMatch = null;
if ($last) {
$bill->lastFoundMatch = $last->date;
}
}
);
return view('bills.index', compact('bills'));
}
/**
* @param Bill $bill
*
* @return mixed
*/
public function rescan(Bill $bill, BillRepositoryInterface $repository)
{
if (intval($bill->active) == 0) {
Session::flash('warning', 'Inactive bills cannot be scanned.');
return Redirect::intended('/');
}
$set = \DB::table('transactions')->where('amount', '>', 0)->where('amount', '>=', $bill->amount_min)->where('amount', '<=', $bill->amount_max)->get(
['transaction_journal_id']
);
$ids = [];
/** @var Transaction $entry */
foreach ($set as $entry) {
$ids[] = intval($entry->transaction_journal_id);
}
if (count($ids) > 0) {
$journals = Auth::user()->transactionjournals()->whereIn('id', $ids)->get();
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$repository->scan($bill, $journal);
}
}
Session::flash('success', 'Rescanned everything.');
return Redirect::to(URL::previous());
}
/**
* @param Bill $bill
*
* @return mixed
*/
public function show(Bill $bill, BillRepositoryInterface $repository)
{
$journals = $bill->transactionjournals()->withRelevantData()
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order','ASC')
->orderBy('transaction_journals.id','DESC')
->get();
$bill->nextExpectedMatch = $repository->nextExpectedMatch($bill);
$hideBill = true;
return view('bills.show', compact('journals', 'hideBill', 'bill'))->with('subTitle', e($bill->name));
}
/**
* @return $this
*/
public function store(BillFormRequest $request, BillRepositoryInterface $repository)
{
var_dump($request->all());
$billData = [
'name' => $request->get('name'),
'match' => $request->get('match'),
'amount_min' => floatval($request->get('amount_min')),
'amount_currency_id' => floatval($request->get('amount_currency_id')),
'amount_max' => floatval($request->get('amount_max')),
'date' => new Carbon($request->get('date')),
'user' => Auth::user()->id,
'repeat_freq' => $request->get('repeat_freq'),
'skip' => intval($request->get('skip')),
'automatch' => intval($request->get('automatch')) === 1,
'active' => intval($request->get('active')) === 1,
];
$bill = $repository->store($billData);
Session::flash('success', 'Bill "' . e($bill->name) . '" stored.');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('bills.create')->withInput();
}
return Redirect::route('bills.index');
}
/**
* @param Bill $bill
*
* @return $this
*/
public function update(Bill $bill, BillFormRequest $request, BillRepositoryInterface $repository)
{
$billData = [
'name' => $request->get('name'),
'match' => $request->get('match'),
'amount_min' => floatval($request->get('amount_min')),
'amount_currency_id' => floatval($request->get('amount_currency_id')),
'amount_max' => floatval($request->get('amount_max')),
'date' => new Carbon($request->get('date')),
'user' => Auth::user()->id,
'repeat_freq' => $request->get('repeat_freq'),
'skip' => intval($request->get('skip')),
'automatch' => intval($request->get('automatch')) === 1,
'active' => intval($request->get('active')) === 1,
];
$bill = $repository->update($bill, $billData);
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('bills.edit', $bill->id);
}
Session::flash('success', 'Bill "' . e($bill->name) . '" updated.');
return Redirect::route('bills.index');
}
}

View File

@@ -0,0 +1,234 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\BudgetFormRequest;
use FireflyIII\Models\Budget;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Input;
use Preferences;
use Redirect;
use Response;
use Session;
use View;
/**
* Class BudgetController
*
* @package FireflyIII\Http\Controllers
*/
class BudgetController extends Controller
{
public function __construct()
{
View::share('title', 'Budgets');
View::share('mainTitleIcon', 'fa-tasks');
}
/**
* @param Budget $budget
*
* @return \Illuminate\Http\JsonResponse
* @throws Exception
*/
public function amount(Budget $budget, BudgetRepositoryInterface $repository)
{
$amount = intval(Input::get('amount'));
$date = Session::get('start', Carbon::now()->startOfMonth());
$limitRepetition = $repository->updateLimitAmount($budget, $date, $amount);
return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition ? $limitRepetition->id : 0]);
}
/**
* @return $this
*/
public function create()
{
return view('budgets.create')->with('subTitle', 'Create a new budget');
}
/**
* @param Budget $budget
*
* @return \Illuminate\View\View
*/
public function delete(Budget $budget)
{
$subTitle = 'Delete budget' . e($budget->name) . '"';
return view('budgets.delete', compact('budget', 'subTitle'));
}
/**
* @param Budget $budget
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Budget $budget, BudgetRepositoryInterface $repository)
{
$name = $budget->name;
$repository->destroy($budget);
Session::flash('success', 'The budget "' . e($name) . '" was deleted.');
return Redirect::route('budgets.index');
}
/**
* @param Budget $budget
*
* @return $this
*/
public function edit(Budget $budget)
{
$subTitle = 'Edit budget "' . e($budget->name) . '"';
return view('budgets.edit', compact('budget', 'subTitle'));
}
/**
* @return mixed
*/
public function index(BudgetRepositoryInterface $repository)
{
$budgets = Auth::user()->budgets()->get();
// loop the budgets:
$budgets->each(
function (Budget $budget) use ($repository) {
$date = Session::get('start', Carbon::now()->startOfMonth());
$budget->spent = $repository->spentInMonth($budget, $date);
$budget->currentRep = $budget->limitrepetitions()->where('limit_repetitions.startdate', $date)->first(['limit_repetitions.*']);
}
);
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
$spent = $budgets->sum('spent');
$amount = Preferences::get('budgetIncomeTotal' . $date, 1000)->data;
$overspent = $spent > $amount;
$spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100);
$budgetMax = Preferences::get('budgetMaximum', 1000);
$budgetMaximum = $budgetMax->data;
return view('budgets.index', compact('budgetMaximum', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount'));
}
/**
* @return \Illuminate\View\View
*/
public function noBudget()
{
$start = \Session::get('start', Carbon::now()->startOfMonth());
$end = \Session::get('end', Carbon::now()->startOfMonth());
$list = Auth::user()
->transactionjournals()
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->whereNull('budget_transaction_journal.id')
->before($end)
->after($start)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order','ASC')
->orderBy('transaction_journals.id','DESC')
->get(['transaction_journals.*']);
$subTitle = 'Transactions without a budget in ' . $start->format('F Y');
return view('budgets.noBudget', compact('list', 'subTitle'));
}
/**
* @return mixed
*/
public function postUpdateIncome()
{
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
Preferences::set('budgetIncomeTotal' . $date, intval(Input::get('amount')));
return Redirect::route('budgets.index');
}
/**
* @param BudgetFormRequest $request
* @param BudgetRepositoryInterface $repository
*
* @return \Illuminate\Http\RedirectResponse
*/
public function store(BudgetFormRequest $request, BudgetRepositoryInterface $repository)
{
$budgetData = [
'name' => $request->input('name'),
'user' => Auth::user()->id,
];
$budget = $repository->store($budgetData);
Session::flash('success', 'New budget "' . $budget->name . '" stored!');
return Redirect::route('budgets.index');
}
/**
*
* @param Budget $budget
* @param LimitRepetition $repetition
*
* @return \Illuminate\View\View
*/
public function show(Budget $budget, LimitRepetition $repetition = null, BudgetRepositoryInterface $repository)
{
if (!is_null($repetition->id) && $repetition->budgetLimit->budget->id != $budget->id) {
return view('error')->with('message', 'Invalid selection.');
}
$hideBudget = true; // used in transaction list.
$journals = $repository->getJournals($budget, $repetition);
$limits = !is_null($repetition->id) ? [$repetition->budgetLimit] : $budget->budgetLimits()->orderBy('startdate', 'DESC')->get();
$subTitle = !is_null($repetition->id) ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name);
return view('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle', 'hideBudget'));
}
/**
* @param Budget $budget
* @param BudgetFormRequest $request
* @param BudgetRepositoryInterface $repository
*
* @return \Illuminate\Http\RedirectResponse
*/
public function update(Budget $budget, BudgetFormRequest $request, BudgetRepositoryInterface $repository)
{
$budgetData = [
'name' => $request->input('name'),
];
$repository->update($budget, $budgetData);
Session::flash('success', 'Budget "' . $budget->name . '" updated.');
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('budgets.edit', $budget->id);
}
return Redirect::route('budgets.index');
}
/**
* @return $this
*/
public function updateIncome()
{
$date = Session::get('start', Carbon::now()->startOfMonth())->format('FY');
$budgetAmount = Preferences::get('budgetIncomeTotal' . $date, 1000);
return view('budgets.income')->with('amount', $budgetAmount);
}
}

View File

@@ -0,0 +1,208 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\CategoryFormRequest;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator;
use Input;
use Redirect;
use Session;
use View;
/**
* Class CategoryController
*
* @package FireflyIII\Http\Controllers
*/
class CategoryController extends Controller
{
/**
*
*/
public function __construct()
{
View::share('title', 'Categories');
View::share('mainTitleIcon', 'fa-bar-chart');
}
/**
* @return $this
*/
public function create()
{
return view('categories.create')->with('subTitle', 'Create a new category');
}
/**
* @param Category $category
*
* @return \Illuminate\View\View
*/
public function delete(Category $category)
{
$subTitle = 'Delete category' . e($category->name) . '"';
return view('categories.delete', compact('category', 'subTitle'));
}
/**
* @param Category $category
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Category $category, CategoryRepositoryInterface $repository)
{
$name = $category->name;
$repository->destroy($category);
Session::flash('success', 'The category "' . e($name) . '" was deleted.');
return Redirect::route('categories.index');
}
/**
* @param Category $category
*
* @return $this
*/
public function edit(Category $category)
{
$subTitle = 'Edit category "' . e($category->name) . '"';
return view('categories.edit', compact('category', 'subTitle'));
}
/**
* @return $this
*/
public function index()
{
$categories = Auth::user()->categories()->orderBy('name', 'ASC')->get();
$categories->each(
function (Category $category) {
$latest = $category->transactionjournals()
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order','ASC')
->orderBy('transaction_journals.id','DESC')
->first();
if ($latest) {
$category->lastActivity = $latest->date;
}
}
);
return view('categories.index', compact('categories'));
}
/**
* @return \Illuminate\View\View
*/
public function noCategory()
{
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->startOfMonth());
$list = Auth::user()
->transactionjournals()
->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->whereNull('category_transaction_journal.id')
->before($end)
->after($start)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order','ASC')
->orderBy('transaction_journals.id','DESC')
->get(['transaction_journals.*']);
$subTitle = 'Transactions without a category between ' . $start->format('jS F Y') . ' and ' . $end->format('jS F Y');
return view('categories.noCategory', compact('list', 'subTitle'));
}
/**
* @param Category $category
*
* @return $this
*/
public function show(Category $category, CategoryRepositoryInterface $repository)
{
$hideCategory = true; // used in list.
$page = intval(Input::get('page'));
$offset = $page > 0 ? $page * 50 : 0;
$set = $category->transactionJournals()->withRelevantData()->take(50)->offset($offset)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order','ASC')
->orderBy('transaction_journals.id','DESC')
->get(
['transaction_journals.*']
);
$count = $category->transactionJournals()->count();
$journals = new LengthAwarePaginator($set, $count, 50, $page);
return view('categories.show', compact('category', 'journals', 'hideCategory'));
}
/**
* @param CategoryFormRequest $request
* @param CategoryRepositoryInterface $repository
*
* @return mixed
*/
public function store(CategoryFormRequest $request, CategoryRepositoryInterface $repository)
{
$categoryData = [
'name' => $request->input('name'),
'user' => Auth::user()->id,
];
$category = $repository->store($categoryData);
Session::flash('success', 'New category "' . $category->name . '" stored!');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('categories.create')->withInput();
}
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('categories.create');
}
return Redirect::route('categories.index');
}
/**
* @param Category $category
* @param CategoryFormRequest $request
* @param CategoryRepositoryInterface $repository
*
* @return \Illuminate\Http\RedirectResponse
*/
public function update(Category $category, CategoryFormRequest $request, CategoryRepositoryInterface $repository)
{
$categoryData = [
'name' => $request->input('name'),
];
$repository->update($category, $categoryData);
Session::flash('success', 'Category "' . $category->name . '" updated.');
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('categories.edit', $category->id);
}
return Redirect::route('categories.index');
}
}

View File

@@ -0,0 +1,17 @@
<?php namespace FireflyIII\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesCommands;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
/**
* Class Controller
*
* @package FireflyIII\Http\Controllers
*/
abstract class Controller extends BaseController
{
use DispatchesCommands, ValidatesRequests;
}

View File

@@ -0,0 +1,183 @@
<?php namespace FireflyIII\Http\Controllers;
use Cache;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\CurrencyFormRequest;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use Input;
use Preferences;
use Redirect;
use Session;
use View;
/**
* Class CurrencyController
*
* @package FireflyIII\Http\Controllers
*/
class CurrencyController extends Controller
{
/**
*
*/
public function __construct()
{
View::share('title', 'Currencies');
View::share('mainTitleIcon', 'fa-usd');
}
/**
* @return \Illuminate\View\View
*/
public function create()
{
$subTitleIcon = 'fa-plus';
$subTitle = 'Create a new currency';
return view('currency.create', compact('subTitleIcon', 'subTitle'));
}
/**
* @param TransactionCurrency $currency
*
* @return \Illuminate\Http\RedirectResponse
*/
public function defaultCurrency(TransactionCurrency $currency)
{
$currencyPreference = Preferences::get('currencyPreference', 'EUR');
$currencyPreference->data = $currency->code;
$currencyPreference->save();
Session::flash('success', $currency->name . ' is now the default currency.');
Cache::forget('FFCURRENCYSYMBOL');
Cache::forget('FFCURRENCYCODE');
return Redirect::route('currency.index');
}
/**
* @param TransactionCurrency $currency
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/
public function delete(TransactionCurrency $currency)
{
if ($currency->transactionJournals()->count() > 0) {
Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.');
return Redirect::route('currency.index');
}
return view('currency.delete', compact('currency'));
}
/**
* @param TransactionCurrency $currency
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(TransactionCurrency $currency)
{
if ($currency->transactionJournals()->count() > 0) {
Session::flash('error', 'Cannot delete ' . e($currency->name) . ' because there are still transactions attached to it.');
return Redirect::route('currency.index');
}
Session::flash('success', 'Currency "' . e($currency->name) . '" deleted');
$currency->delete();
return Redirect::route('currency.index');
}
/**
* @param TransactionCurrency $currency
*
* @return \Illuminate\View\View
*/
public function edit(TransactionCurrency $currency)
{
$subTitleIcon = 'fa-pencil';
$subTitle = 'Edit currency "' . e($currency->name) . '"';
$currency->symbol = htmlentities($currency->symbol);
return view('currency.edit', compact('currency', 'subTitle', 'subTitleIcon'));
}
/**
* @return \Illuminate\View\View
*/
public function index()
{
$currencies = TransactionCurrency::get();
$currencyPreference = Preferences::get('currencyPreference', 'EUR');
$defaultCurrency = TransactionCurrency::whereCode($currencyPreference->data)->first();
return view('currency.index', compact('currencies', 'defaultCurrency'));
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function store(CurrencyFormRequest $request)
{
// no repository, because the currency controller is relatively simple.
$currency = TransactionCurrency::create(
[
'name' => $request->get('name'),
'code' => $request->get('code'),
'symbol' => $request->get('symbol'),
]
);
Session::flash('success', 'Currency "' . $currency->name . '" created');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('currency.create')->withInput();
}
return Redirect::route('currency.index');
}
/**
* @param TransactionCurrency $currency
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function update(TransactionCurrency $currency, CurrencyFormRequest $request)
{
$currency->code = $request->get('code');
$currency->symbol = $request->get('symbol');
$currency->name = $request->get('name');
$currency->save();
Session::flash('success', 'Currency "' . e($currency->name) . '" updated.');
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('currency.edit', $currency->id);
}
return Redirect::route('currency.index');
}
}

View File

@@ -0,0 +1,666 @@
<?php namespace FireflyIII\Http\Controllers;
use App;
use Auth;
use Carbon\Carbon;
use DB;
use Exception;
use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Http\Requests;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Grumpydictator\Gchart\GChart;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Navigation;
use Preferences;
use Response;
use Session;
use Steam;
/**
* Class GoogleChartController
*
* @package FireflyIII\Http\Controllers
*/
class GoogleChartController extends Controller
{
/**
* @param Account $account
* @param string $view
*
* @return \Illuminate\Http\JsonResponse
*/
public function accountBalanceChart(Account $account, GChart $chart)
{
$chart->addColumn('Day of month', 'date');
$chart->addColumn('Balance for ' . $account->name, 'number');
$chart->addCertainty(1);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$current = clone $start;
while ($end >= $current) {
$chart->addRow(clone $current, Steam::balance($account, $current), false);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function allAccountsBalanceChart(GChart $chart)
{
$chart->addColumn('Day of the month', 'date');
$frontPage = Preferences::get('frontPageAccounts', []);
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
if ($frontPage->data == []) {
$accounts = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*']);
} else {
$accounts = Auth::user()->accounts()->whereIn('id', $frontPage->data)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
}
$index = 1;
/** @var Account $account */
foreach ($accounts as $account) {
$chart->addColumn('Balance for ' . $account->name, 'number');
$chart->addCertainty($index);
$index++;
}
$current = clone $start;
$current->subDay();
$today = Carbon::now();
while ($end >= $current) {
$row = [clone $current];
$certain = $current < $today;
foreach ($accounts as $account) {
$row[] = Steam::balance($account, $current);
$row[] = $certain;
}
$chart->addRowArray($row);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param int $year
*
* @return $this|\Illuminate\Http\JsonResponse
*/
public function allBudgetsAndSpending($year, GChart $chart, BudgetRepositoryInterface $repository)
{
try {
new Carbon('01-01-' . $year);
} catch (Exception $e) {
return view('error')->with('message', 'Invalid year.');
}
$budgets = Auth::user()->budgets()->get();
$budgets->sortBy('name');
$chart->addColumn('Month', 'date');
foreach ($budgets as $budget) {
$chart->addColumn($budget->name, 'number');
}
$start = Carbon::createFromDate(intval($year), 1, 1);
$end = clone $start;
$end->endOfYear();
while ($start <= $end) {
$row = [clone $start];
foreach ($budgets as $budget) {
$spent = $repository->spentInMonth($budget, $start);
$row[] = $spent;
}
$chart->addRowArray($row);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function allBudgetsHomeChart(GChart $chart)
{
$chart->addColumn('Budget', 'string');
$chart->addColumn('Budgeted', 'number');
$chart->addColumn('Spent', 'number');
$budgets = Auth::user()->budgets()->orderBy('name', 'DESC')->get();
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
/** @var Budget $budget */
foreach ($budgets as $budget) {
/** @var Collection $repetitions */
$repetitions = LimitRepetition::
leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->where('limit_repetitions.startdate', '<=', $end->format('Y-m-d 00:00:00'))
->where('limit_repetitions.startdate', '>=', $start->format('Y-m-d 00:00:00'))
->where('budget_limits.budget_id', $budget->id)
->get(['limit_repetitions.*']);
// no results? search entire range for expenses and list those.
if ($repetitions->count() == 0) {
$expenses = floatval($budget->transactionjournals()->before($end)->after($start)->lessThan(0)->sum('amount')) * -1;
if ($expenses > 0) {
$chart->addRow($budget->name, 0, $expenses);
}
} else {
// add with foreach:
/** @var LimitRepetition $repetition */
foreach ($repetitions as $repetition) {
$expenses
=
floatval($budget->transactionjournals()->before($repetition->enddate)->after($repetition->startdate)->lessThan(0)->sum('amount')) * -1;
if ($expenses > 0) {
$chart->addRow($budget->name . ' (' . $repetition->startdate->format('j M Y') . ')', floatval($repetition->amount), $expenses);
}
}
}
}
$noBudgetSet = Auth::user()
->transactionjournals()
->whereNotIn(
'transaction_journals.id', function (QueryBuilder $query) use ($start, $end) {
$query
->select('transaction_journals.id')
->from('transaction_journals')
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d 00:00:00'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d 00:00:00'))
->whereNotNull('budget_transaction_journal.budget_id');
}
)
->before($end)
->after($start)
->lessThan(0)
->transactionTypes(['Withdrawal'])
->get();
$sum = $noBudgetSet->sum('amount') * -1;
$chart->addRow('No budget', 0, $sum);
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function allCategoriesHomeChart(GChart $chart)
{
$chart->addColumn('Category', 'string');
$chart->addColumn('Spent', 'number');
// query!
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$set = TransactionJournal::
where('transaction_journals.user_id',Auth::user()->id)
->leftJoin(
'transactions',
function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('amount', '>', 0);
}
)
->leftJoin(
'category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id'
)
->leftJoin('categories', 'categories.id', '=', 'category_transaction_journal.category_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->before($end)
->where('categories.user_id',Auth::user()->id)
->after($start)
->where('transaction_types.type', 'Withdrawal')
->groupBy('categories.id')
->orderBy('sum', 'DESC')
->get(['categories.id', 'categories.name', \DB::Raw('SUM(`transactions`.`amount`) AS `sum`')]);
foreach ($set as $entry) {
$entry->name = strlen($entry->name) == 0 ? '(no category)' : $entry->name;
$chart->addRow($entry->name, floatval($entry->sum));
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param Bill $bill
*
* @return \Illuminate\Http\JsonResponse
*/
public function billOverview(Bill $bill, GChart $chart)
{
$chart->addColumn('Date', 'date');
$chart->addColumn('Max amount', 'number');
$chart->addColumn('Min amount', 'number');
$chart->addColumn('Current entry', 'number');
// get first transaction or today for start:
$first = $bill->transactionjournals()->orderBy('date', 'ASC')->first();
if ($first) {
$start = $first->date;
} else {
$start = new Carbon;
}
$end = new Carbon;
while ($start <= $end) {
$result = $bill->transactionjournals()->before($end)->after($start)->first();
if ($result) {
/** @var Transaction $tr */
foreach ($result->transactions()->get() as $tr) {
if (floatval($tr->amount) > 0) {
$amount = floatval($tr->amount);
}
}
} else {
$amount = 0;
}
unset($result);
$chart->addRow(clone $start, $bill->amount_max, $bill->amount_min, $amount);
$start = Navigation::addPeriod($start, $bill->repeat_freq, 0);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param GChart $chart
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function billsOverview(GChart $chart, BillRepositoryInterface $repository)
{
$chart->addColumn('Name', 'string');
$chart->addColumn('Amount', 'number');
$paid = ['items' => [], 'amount' => 0];
$unpaid = ['items' => [], 'amount' => 0];
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
$bills = Auth::user()->bills()->where('active', 1)->get();
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
if ($count == 0) {
$unpaid['items'][] = $bill->name . ' (' . $range['start']->format('jS M Y') . ')';
$unpaid['amount'] += ($bill->amount_max + $bill->amount_min / 2);
} else {
$journal = $bill->transactionjournals()->with('transactions')->before($range['end'])->after($range['start'])->first();
$paid['items'][] = $journal->description;
$amount = 0;
foreach ($journal->transactions as $t) {
if (floatval($t->amount) > 0) {
$amount = floatval($t->amount);
}
}
$paid['amount'] += $amount;
}
}
}
$chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
$chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
$chart->generate();
return Response::json($chart->getData());
}
/**
*
* @param Budget $budget
* @param LimitRepetition $repetition
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetLimitSpending(Budget $budget, LimitRepetition $repetition, GChart $chart)
{
$start = clone $repetition->startdate;
$end = $repetition->enddate;
$chart->addColumn('Day', 'date');
$chart->addColumn('Left', 'number');
$amount = $repetition->amount;
while ($start <= $end) {
/*
* Sum of expenses on this day:
*/
$sum = floatval($budget->transactionjournals()->lessThan(0)->transactionTypes(['Withdrawal'])->onDate($start)->sum('amount'));
$amount += $sum;
$chart->addRow(clone $start, $amount);
$start->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
*
* @param Budget $budget
*
* @param int $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetsAndSpending(Budget $budget, $year = 0)
{
$chart = App::make('Grumpydictator\Gchart\GChart');
$repository = App::make('FireflyIII\Repositories\Budget\BudgetRepository');
$chart->addColumn('Month', 'date');
$chart->addColumn('Budgeted', 'number');
$chart->addColumn('Spent', 'number');
if ($year == 0) {
// grab the first budgetlimit ever:
$firstLimit = $budget->budgetlimits()->orderBy('startdate', 'ASC')->first();
if ($firstLimit) {
$start = new Carbon($firstLimit->startdate);
} else {
$start = Carbon::now()->startOfYear();
}
// grab the last budget limit ever:
$lastLimit = $budget->budgetlimits()->orderBy('startdate', 'DESC')->first();
if ($lastLimit) {
$end = new Carbon($lastLimit->startdate);
} else {
$end = Carbon::now()->endOfYear();
}
} else {
$start = Carbon::createFromDate(intval($year), 1, 1);
$end = clone $start;
$end->endOfYear();
}
while ($start <= $end) {
$spent = $repository->spentInMonth($budget, $start);
$repetition = LimitRepetition::leftJoin('budget_limits', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->where('limit_repetitions.startdate', $start->format('Y-m-d 00:00:00'))
->where('budget_limits.budget_id', $budget->id)
->first(['limit_repetitions.*']);
if ($repetition) {
$budgeted = floatval($repetition->amount);
\Log::debug('Found a repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name . '!');
} else {
\Log::debug('No repetition on ' . $start->format('Y-m-d') . ' for budget ' . $budget->name);
$budgeted = null;
}
$chart->addRow(clone $start, $budgeted, $spent);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
*
* @param Category $category
*
* @return \Illuminate\Http\JsonResponse
*/
public function categoryOverviewChart(Category $category, GChart $chart)
{
// oldest transaction in category:
/** @var TransactionJournal $first */
$first = $category->transactionjournals()->orderBy('date', 'ASC')->first();
$start = $first->date;
/** @var Preference $range */
$range = Preferences::get('viewRange', '1M');
// jump to start of week / month / year / etc (TODO).
$start = Navigation::startOfPeriod($start, $range->data);
$chart->addColumn('Period', 'date');
$chart->addColumn('Spent', 'number');
$end = new Carbon;
while ($start <= $end) {
$currentEnd = Navigation::endOfPeriod($start, $range->data);
$spent = floatval($category->transactionjournals()->before($currentEnd)->after($start)->lessThan(0)->sum('amount')) * -1;
$chart->addRow(clone $start, $spent);
$start = Navigation::addPeriod($start, $range->data, 0);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
*
* @param Category $category
*
* @return \Illuminate\Http\JsonResponse
*/
public function categoryPeriodChart(Category $category, GChart $chart)
{
// oldest transaction in category:
/** @var TransactionJournal $first */
$start = clone Session::get('start');
$chart->addColumn('Period', 'date');
$chart->addColumn('Spent', 'number');
$end = Session::get('end');
while ($start <= $end) {
$spent = floatval($category->transactionjournals()->onDate($start)->lessThan(0)->sum('amount')) * -1;
$chart->addRow(clone $start, $spent);
$start->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param PiggyBank $piggyBank
*
* @return \Illuminate\Http\JsonResponse
*/
public function piggyBankHistory(PiggyBank $piggyBank, GChart $chart)
{
$chart->addColumn('Date', 'date');
$chart->addColumn('Balance', 'number');
/** @var Collection $set */
$set = DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
$sum = 0;
foreach ($set as $entry) {
$sum += floatval($entry->sum);
$chart->addRow(new Carbon($entry->date), $sum);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
*
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function yearInExp($year, GChart $chart, ReportQueryInterface $query)
{
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
return view('error')->with('message', 'Invalid year.');
}
$chart->addColumn('Month', 'date');
$chart->addColumn('Income', 'number');
$chart->addColumn('Expenses', 'number');
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
// get report query interface.
$end = clone $start;
$end->endOfYear();
while ($start < $end) {
$currentEnd = clone $start;
$currentEnd->endOfMonth();
// total income:
$income = $query->incomeByPeriod($start, $currentEnd, $showSharedReports);
$incomeSum = 0;
foreach ($income as $entry) {
$incomeSum += floatval($entry->amount);
}
// total expenses:
$expense = $query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports);
$expenseSum = 0;
foreach ($expense as $entry) {
$expenseSum += floatval($entry->amount);
}
$chart->addRow(clone $start, $incomeSum, $expenseSum);
$start->addMonth();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
*
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function yearInExpSum($year, GChart $chart, ReportQueryInterface $query)
{
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
return view('error')->with('message', 'Invalid year.');
}
$chart->addColumn('Summary', 'string');
$chart->addColumn('Income', 'number');
$chart->addColumn('Expenses', 'number');
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
$income = 0;
$expense = 0;
$count = 0;
$end = clone $start;
$end->endOfYear();
while ($start < $end) {
$currentEnd = clone $start;
$currentEnd->endOfMonth();
// total income:
$incomeResult = $query->incomeByPeriod($start, $currentEnd, $showSharedReports);
$incomeSum = 0;
foreach ($incomeResult as $entry) {
$incomeSum += floatval($entry->amount);
}
// total expenses:
$expenseResult = $query->journalsByExpenseAccount($start, $currentEnd, $showSharedReports);
$expenseSum = 0;
foreach ($expenseResult as $entry) {
$expenseSum += floatval($entry->amount);
}
$income += $incomeSum;
$expense += $expenseSum;
$count++;
$start->addMonth();
}
$chart->addRow('Sum', $income, $expense);
$count = $count > 0 ? $count : 1;
$chart->addRow('Average', ($income / $count), ($expense / $count));
$chart->generate();
return Response::json($chart->getData());
}
}

View File

@@ -1,13 +1,20 @@
<?php
<?php namespace FireflyIII\Http\Controllers;
use Cache;
use ErrorException;
use FireflyIII\Http\Requests;
use League\CommonMark\CommonMarkConverter;
use Response;
use Route;
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class HelpController
*
* @package FireflyIII\Http\Controllers
*/
class HelpController extends BaseController
class HelpController extends Controller
{
/**
* @param $route
*
@@ -74,11 +81,12 @@ class HelpController extends BaseController
if (strlen(trim($content['text'])) == 0) {
$content['text'] = '<p>There is no help for this route.</p>';
}
$content['text'] = \Michelf\Markdown::defaultTransform($content['text']);
$converter = new CommonMarkConverter();
$content['text'] = $converter->convertToHtml($content['text']);
return $content;
}
}
}

View File

@@ -0,0 +1,81 @@
<?php namespace FireflyIII\Http\Controllers;
use Cache;
use Carbon\Carbon;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Input;
use Preferences;
use Redirect;
use Session;
/**
* Class HomeController
*
* @package FireflyIII\Http\Controllers
*/
class HomeController extends Controller
{
/**
*
*/
public function __construct()
{
}
public function dateRange()
{
$start = new Carbon(Input::get('start'));
$end = new Carbon(Input::get('end'));
$diff = $start->diffInDays($end);
if ($diff > 50) {
Session::flash('warning', $diff . ' days of data may take a while to load.');
}
Session::put('start', $start);
Session::put('end', $end);
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function flush()
{
Cache::flush();
return Redirect::route('index');
}
/**
* @return \Illuminate\View\View
*/
public function index(AccountRepositoryInterface $repository)
{
$count = $repository->countAssetAccounts();
$title = 'Firefly';
$subTitle = 'What\'s playing?';
$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();
foreach ($accounts as $account) {
$set = $repository->getFrontpageTransactions($account, $start, $end);
if (count($set) > 0) {
$transactions[] = [$set, $account];
}
}
// var_dump($transactions);
return view('index', compact('count', 'title','savings', 'subTitle', 'mainTitleIcon', 'transactions'));
}
}

View File

@@ -0,0 +1,182 @@
<?php namespace FireflyIII\Http\Controllers;
use Amount;
use Auth;
use DB;
use FireflyIII\Http\Requests;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Input;
use Preferences;
use Response;
use Session;
/**
* Class JsonController
*
* @package FireflyIII\Http\Controllers
*/
class JsonController extends Controller
{
/**
*
*/
public function box(BillRepositoryInterface $repository)
{
$amount = 0;
$start = Session::get('start');
$end = Session::get('end');
$box = 'empty';
switch (Input::get('box')) {
case 'in':
$box = Input::get('box');
$in = Auth::user()->transactionjournals()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->before($end)
->after($start)
->transactionTypes(['Deposit'])
->where('transactions.amount', '>', 0)
->first([DB::Raw('SUM(transactions.amount) as `amount`')]);
if (!is_null($in)) {
$amount = floatval($in->amount);
}
break;
case 'out':
$box = Input::get('box');
$in = Auth::user()->transactionjournals()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->before($end)
->after($start)
->transactionTypes(['Withdrawal'])
->where('transactions.amount', '>', 0)
->first([DB::Raw('SUM(transactions.amount) as `amount`')]);
if (!is_null($in)) {
$amount = floatval($in->amount);
}
break;
case 'bills-unpaid':
$box = 'bills-unpaid';
$bills = Auth::user()->bills()->where('active', 1)->get();
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
if ($count == 0) {
$amount += floatval($bill->amount_max + $bill->amount_min / 2);
}
}
}
break;
case 'bills-paid':
$box = 'bills-paid';
// these two functions are the same as the chart TODO
$bills = Auth::user()->bills()->where('active', 1)->get();
/** @var Bill $bill */
foreach ($bills as $bill) {
$ranges = $repository->getRanges($bill, $start, $end);
foreach ($ranges as $range) {
// paid a bill in this range?
$count = $bill->transactionjournals()->before($range['end'])->after($range['start'])->count();
if ($count != 0) {
$journal = $bill->transactionjournals()->with('transactions')->before($range['end'])->after($range['start'])->first();
$paid['items'][] = $journal->description;
$currentAmount = 0;
foreach ($journal->transactions as $t) {
if (floatval($t->amount) > 0) {
$currentAmount = floatval($t->amount);
}
}
$amount += $currentAmount;
}
}
}
}
return Response::json(['box' => $box, 'amount' => Amount::format($amount, false), 'amount_raw' => $amount]);
}
/**
* Returns a list of categories.
*
* @return \Illuminate\Http\JsonResponse
*/
public function categories()
{
$list = Auth::user()->categories()->orderBy('name', 'ASC')->get();
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
}
return Response::json($return);
}
/**
* Returns a JSON list of all beneficiaries.
*
* @return \Illuminate\Http\JsonResponse
*/
public function expenseAccounts()
{
$list = Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Expense account', 'Beneficiary account'])->get();
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
}
return Response::json($return);
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function revenueAccounts()
{
$list = Auth::user()->accounts()->accountTypeIn(['Revenue account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
}
return Response::json($return);
}
/**
* @return \Symfony\Component\HttpFoundation\Response
*/
public function showSharedReports()
{
$pref = Preferences::get('showSharedReports', false);
return Response::json(['value' => $pref->data]);
}
/**
* @return \Symfony\Component\HttpFoundation\Response
*/
public function setSharedReports()
{
$pref = Preferences::get('showSharedReports', false);
$new = !$pref->data;
Preferences::set('showSharedReports', $new);
return Response::json(['value' => $new]);
}
}

View File

@@ -1,30 +1,37 @@
<?php
<?php namespace FireflyIII\Http\Controllers;
use Amount;
use Auth;
use Carbon\Carbon;
use FireflyIII\Database\PiggyBank\PiggyBank as Repository;
use FireflyIII\Exception\FireflyException;
use Config;
use ExpandedForm;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\PiggyBankFormRequest;
use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Support\Collection;
use Input;
use Redirect;
use Session;
use Steam;
use View;
/**
*
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
*
* Class PiggyBankController
*
* @package FireflyIII\Http\Controllers
*/
class PiggyBankController extends BaseController
class PiggyBankController extends Controller
{
/** @var Repository */
protected $_repository;
/**
* @param Repository $repository
*
*/
public function __construct(Repository $repository)
public function __construct()
{
$this->_repository = $repository;
View::share('title', 'Piggy banks');
View::share('mainTitleIcon', 'fa-sort-amount-asc');
}
@@ -36,9 +43,9 @@ class PiggyBankController extends BaseController
*
* @return $this
*/
public function add(PiggyBank $piggyBank)
public function add(PiggyBank $piggyBank, AccountRepositoryInterface $repository)
{
$leftOnAccount = $this->_repository->leftOnAccount($piggyBank->account);
$leftOnAccount = $repository->leftOnAccount($piggyBank->account);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = $piggyBank->targetamount - $savedSoFar;
$maxAmount = min($leftOnAccount, $leftToSave);
@@ -46,7 +53,7 @@ class PiggyBankController extends BaseController
\Log::debug('Now going to view for piggy bank #' . $piggyBank->id . ' (' . $piggyBank->name . ')');
return View::make('piggy_banks.add', compact('piggyBank', 'maxAmount'));
return view('piggy-banks.add', compact('piggyBank', 'maxAmount'));
}
/**
@@ -55,15 +62,14 @@ class PiggyBankController extends BaseController
public function create()
{
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account']));
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
);
$subTitle = 'Create new piggy bank';
$subTitleIcon = 'fa-plus';
return View::make('piggy_banks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon'));
return view('piggy-banks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon'));
}
/**
@@ -75,7 +81,7 @@ class PiggyBankController extends BaseController
{
$subTitle = 'Delete "' . e($piggyBank->name) . '"';
return View::make('piggy_banks.delete', compact('piggyBank', 'subTitle'));
return view('piggy-banks.delete', compact('piggyBank', 'subTitle'));
}
/**
@@ -87,9 +93,9 @@ class PiggyBankController extends BaseController
{
Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.');
$this->_repository->destroy($piggyBank);
$piggyBank->delete();
return Redirect::route('piggy_banks.index');
return Redirect::route('piggy-banks.index');
}
/**
@@ -102,11 +108,10 @@ class PiggyBankController extends BaseController
public function edit(PiggyBank $piggyBank)
{
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = FFForm::makeSelectList($acct->getAccountsByType(['Default account', 'Asset account']));
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
);
$subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"';
$subTitleIcon = 'fa-pencil';
@@ -124,20 +129,20 @@ class PiggyBankController extends BaseController
'targetamount' => $piggyBank->targetamount,
'targetdate' => $targetDate,
'reminder' => $piggyBank->reminder,
'remind_me' => intval($piggyBank->remind_me) == 1 || !is_null($piggyBank->reminder) ? true : false
'remind_me' => intval($piggyBank->remind_me) == 1 && !is_null($piggyBank->reminder) ? true : false
];
Session::flash('preFilled', $preFilled);
return View::make('piggy_banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'accounts', 'periods', 'preFilled'));
return view('piggy-banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'accounts', 'periods', 'preFilled'));
}
/**
* @return $this
*/
public function index()
public function index(AccountRepositoryInterface $repository)
{
/** @var Collection $piggyBanks */
$piggyBanks = $this->_repository->get();
$piggyBanks = Auth::user()->piggyBanks()->where('repeats', 0)->orderBy('order', 'ASC')->get();
$accounts = [];
/** @var PiggyBank $piggyBank */
@@ -154,7 +159,7 @@ class PiggyBankController extends BaseController
$accounts[$account->id] = [
'name' => $account->name,
'balance' => Steam::balance($account),
'leftForPiggyBanks' => $this->_repository->leftOnAccount($account),
'leftForPiggyBanks' => $repository->leftOnAccount($account),
'sumOfSaved' => $piggyBank->savedSoFar,
'sumOfTargets' => floatval($piggyBank->targetamount),
'leftToSave' => $piggyBank->leftToSave
@@ -166,7 +171,24 @@ class PiggyBankController extends BaseController
}
}
return View::make('piggy_banks.index', compact('piggyBanks', 'accounts'));
return view('piggy-banks.index', compact('piggyBanks', 'accounts'));
}
/**
* Allow user to order piggy banks.
*/
public function order(PiggyBankRepositoryInterface $repository)
{
$data = Input::get('order');
// set all users piggy banks to zero:
$repository->reset();
if (is_array($data)) {
foreach ($data as $order => $id) {
$repository->setOrder(intval($id), (intval($order) + 1));
}
}
}
/**
@@ -176,14 +198,10 @@ class PiggyBankController extends BaseController
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postAdd(PiggyBank $piggyBank)
public function postAdd(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository, AccountRepositoryInterface $accounts)
{
$amount = round(floatval(Input::get('amount')), 2);
/** @var \FireflyIII\Database\PiggyBank\PiggyBank $acct */
$piggyRepository = App::make('FireflyIII\Database\PiggyBank\PiggyBank');
$leftOnAccount = $piggyRepository->leftOnAccount($piggyBank->account);
$amount = round(floatval(Input::get('amount')), 2);
$leftOnAccount = $accounts->leftOnAccount($piggyBank->account);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = $piggyBank->targetamount - $savedSoFar;
$maxAmount = round(min($leftOnAccount, $leftToSave), 2);
@@ -193,17 +211,20 @@ class PiggyBankController extends BaseController
$repetition->currentamount += $amount;
$repetition->save();
// create event.
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
/*
* Create event!
*/
Event::fire('piggy_bank.addMoney', [$piggyBank, $amount]); // new and used.
//Event::fire('piggy_bank.addMoney', [$piggyBank, $amount]); // new and used.
Session::flash('success', 'Added ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".');
} else {
Session::flash('error', 'Could not add ' . Amount::format($amount, false) . ' to "' . e($piggyBank->name) . '".');
}
return Redirect::route('piggy_banks.index');
return Redirect::route('piggy-banks.index');
}
/**
@@ -222,17 +243,19 @@ class PiggyBankController extends BaseController
$repetition->currentamount -= $amount;
$repetition->save();
PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount * -1, 'piggy_bank_id' => $piggyBank->id]);
/*
* Create event!
*/
Event::fire('piggy_bank.removeMoney', [$piggyBank, $amount]); // new and used.
//Event::fire('piggy_bank.removeMoney', [$piggyBank, $amount]); // new and used.
Session::flash('success', 'Removed ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".');
} else {
Session::flash('error', 'Could not remove ' . Amount::format($amount, false) . ' from "' . e($piggyBank->name) . '".');
}
return Redirect::route('piggy_banks.index');
return Redirect::route('piggy-banks.index');
}
/**
@@ -244,7 +267,7 @@ class PiggyBankController extends BaseController
*/
public function remove(PiggyBank $piggyBank)
{
return View::make('piggy_banks.remove', compact('piggyBank'));
return view('piggy-banks.remove', compact('piggyBank'));
}
/**
@@ -263,97 +286,75 @@ class PiggyBankController extends BaseController
$subTitle = e($piggyBank->name);
return View::make('piggy_banks.show', compact('piggyBank', 'events', 'subTitle'));
return view('piggy-banks.show', compact('piggyBank', 'events', 'subTitle'));
}
/**
* @param PiggyBankFormRequest $request
* @param PiggyBankRepositoryInterface $repository
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function store()
public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository)
{
$data = Input::all();
$data['repeats'] = 0;
$data['user_id'] = Auth::user()->id;
$data['rep_every'] = 0;
$data['reminder_skip'] = 0;
$data['remind_me'] = intval(Input::get('remind_me'));
$data['order'] = 0;
$piggyBankData = [
'repeats' => false,
'name' => $request->get('name'),
'startdate' => new Carbon,
'account_id' => intval($request->get('account_id')),
'targetamount' => floatval($request->get('targetamount')),
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
'reminder' => $request->get('reminder'),
'remind_me' => $request->get('remind_me'),
];
$piggyBank = $repository->store($piggyBankData);
// always validate:
$messages = $this->_repository->validate($data);
Session::flash('success', 'Stored piggy bank "' . e($piggyBank->name) . '".');
// flash messages:
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
Session::flash('error', 'Could not store piggy bank: ' . $messages['errors']->first());
return Redirect::route('piggy_banks.create')->withInput();
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('piggy-banks.create')->withInput();
}
// return to create screen:
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('piggy_banks.create')->withInput();
}
// store
$piggyBank = $this->_repository->store($data);
Event::fire('piggy_bank.store', [$piggyBank]); // new and used.
Session::flash('success', 'Piggy bank "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('piggy_banks.index');
}
return Redirect::route('piggy_banks.create')->withInput();
return Redirect::route('piggy-banks.index');
}
/**
* @param PiggyBank $piggyBank
*
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @return $this
* @throws FireflyException
*/
public function update(PiggyBank $piggyBank)
public function update(PiggyBank $piggyBank, PiggyBankRepositoryInterface $repository, PiggyBankFormRequest $request)
{
$piggyBankData = [
'repeats' => false,
'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')),
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
'reminder' => $request->get('reminder'),
'remind_me' => $request->get('remind_me')
];
$data = Input::except('_token');
$data['rep_every'] = 0;
$data['reminder_skip'] = 0;
$data['order'] = 0;
$data['remind_me'] = isset($data['remind_me']) ? 1 : 0;
$data['user_id'] = Auth::user()->id;
$data['repeats'] = 0;
// always validate:
$messages = $this->_repository->validate($data);
$piggyBank = $repository->update($piggyBank, $piggyBankData);
Session::flash('warnings', $messages['warnings']);
Session::flash('successes', $messages['successes']);
Session::flash('errors', $messages['errors']);
if ($messages['errors']->count() > 0) {
Session::flash('error', 'Could not update piggy bank: ' . $messages['errors']->first());
return Redirect::route('piggy_banks.edit', $piggyBank->id)->withInput();
Session::flash('success', 'Updated piggy bank "' . e($piggyBank->name) . '".');
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('piggy-banks.edit', $piggyBank->id);
}
// return to update screen:
if ($data['post_submit_action'] == 'validate_only') {
return Redirect::route('piggy_banks.edit', $piggyBank->id)->withInput();
}
// update
$this->_repository->update($piggyBank, $data);
Session::flash('success', 'Piggy bank "' . e($data['name']) . '" updated.');
return Redirect::route('piggy-banks.index');
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('piggy_banks.index');
}
// go back to update screen.
return Redirect::route('piggy_banks.edit', $piggyBank->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
}

View File

@@ -0,0 +1,75 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use FireflyIII\Http\Requests;
use Input;
use Preferences;
use Redirect;
use Session;
use View;
/**
* Class PreferencesController
*
* @package FireflyIII\Http\Controllers
*/
class PreferencesController extends Controller
{
/**
*
*/
public function __construct()
{
View::share('title', 'Preferences');
View::share('mainTitleIcon', 'fa-gear');
}
/**
* @return $this|\Illuminate\View\View
*/
public function index()
{
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
$viewRange = Preferences::get('viewRange', '1M');
$viewRangeValue = $viewRange->data;
$frontPage = Preferences::get('frontPageAccounts', []);
$budgetMax = Preferences::get('budgetMaximum', 1000);
$budgetMaximum = $budgetMax->data;
return view('preferences.index', compact('budgetMaximum'))->with('accounts', $accounts)->with('frontPageAccounts', $frontPage)->with(
'viewRange', $viewRangeValue
);
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function postIndex()
{
// front page accounts
$frontPageAccounts = [];
foreach (Input::get('frontPageAccounts') as $id) {
$frontPageAccounts[] = intval($id);
}
Preferences::set('frontPageAccounts', $frontPageAccounts);
// view range:
Preferences::set('viewRange', Input::get('viewRange'));
// forget session values:
Session::forget('start');
Session::forget('end');
Session::forget('range');
// budget maximum:
$budgetMaximum = intval(Input::get('budgetMaximum'));
Preferences::set('budgetMaximum', $budgetMaximum);
Session::flash('success', 'Preferences saved!');
return Redirect::route('preferences');
}
}

View File

@@ -1,10 +1,18 @@
<?php
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\ProfileFormRequest;
use Hash;
use Redirect;
use Session;
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
* Class ProfileController
*
* @package FireflyIII\Http\Controllers
*/
class ProfileController extends BaseController
class ProfileController extends Controller
{
/**
@@ -12,7 +20,7 @@ class ProfileController extends BaseController
*/
public function changePassword()
{
return View::make('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', 'Change your password')->with(
'mainTitleIcon', 'fa-user'
);
}
@@ -23,32 +31,30 @@ class ProfileController extends BaseController
*/
public function index()
{
return View::make('profile.index')->with('title', 'Profile')->with('subTitle', Auth::user()->email)->with('mainTitleIcon', 'fa-user');
return view('profile.index')->with('title', 'Profile')->with('subTitle', Auth::user()->email)->with('mainTitleIcon', 'fa-user');
}
/**
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
*/
public function postChangePassword()
public function postChangePassword(ProfileFormRequest $request)
{
// old, new1, new2
if (!Hash::check(Input::get('old'), Auth::user()->password)) {
if (!Hash::check($request->get('current_password'), Auth::user()->password)) {
Session::flash('error', 'Invalid current password!');
return View::make('profile.change-password');
return Redirect::route('change-password');
}
$result = $this->_validatePassword(Input::get('old'), Input::get('new1'), Input::get('new2'));
$result = $this->_validatePassword($request->get('current_password'), $request->get('new_password'), $request->get('new_password_confirmation'));
if (!($result === true)) {
Session::flash('error', $result);
return View::make('profile.change-password');
return Redirect::route('change-password');
}
// update the user with the new password.
/** @var \FireflyIII\Database\User\User $repository */
$repository = \App::make('FireflyIII\Database\User\User');
$repository->updatePassword(Auth::user(), Input::get('new1'));
Auth::user()->password = $request->get('new_password');
Auth::user()->save();
Session::flash('success', 'Password changed!');
@@ -81,5 +87,4 @@ class ProfileController extends BaseController
return true;
}
}
}

View File

@@ -1,28 +1,26 @@
<?php
use FireflyIII\Helper\Related\RelatedInterface;
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use FireflyIII\Http\Requests;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Support\Collection;
use Input;
use Redirect;
use Response;
use URL;
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class RelatedController
*
* @package FireflyIII\Http\Controllers
*/
class RelatedController extends BaseController
class RelatedController extends Controller
{
protected $_repository;
/**
* @param RelatedInterface $repository
*/
public function __construct(RelatedInterface $repository)
{
$this->_repository = $repository;
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param TransactionJournal $journal
*
@@ -40,20 +38,54 @@ class RelatedController extends BaseController
}
}
}
$unique = array_unique($ids);
$unique = array_unique($ids);
$journals = new Collection;
if (count($unique) > 0) {
$set = $this->_repository->getJournalsByIds($unique);
$set->each(
$journals = Auth::user()->transactionjournals()->whereIn('id', $unique)->get();
$journals->each(
function (TransactionJournal $journal) {
$journal->amount = Amount::format($journal->getAmount());
/** @var Transaction $t */
foreach ($journal->transactions()->get() as $t) {
if ($t->amount > 0) {
$journal->amount = $t->amount;
}
}
}
);
return Response::json($set->toArray());
} else {
return Response::json((new Collection)->toArray());
}
$parent = $journal;
return view('related.alreadyRelated', compact('parent', 'journals'));
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param TransactionJournal $parentJournal
* @param TransactionJournal $childJournal
*
* @return \Illuminate\Http\JsonResponse
* @throws Exception
*/
public function getRemoveRelation(TransactionJournal $parentJournal, TransactionJournal $childJournal)
{
$groups = $parentJournal->transactiongroups()->get();
/** @var TransactionGroup $group */
foreach ($groups as $group) {
foreach ($group->transactionjournals()->get() as $loopJournal) {
if ($loopJournal->id == $childJournal->id) {
// remove from group:
$group->transactionjournals()->detach($childJournal);
}
}
if ($group->transactionjournals()->count() == 1) {
$group->delete();
}
}
return Redirect::to(URL::previous());
}
/**
@@ -66,7 +98,7 @@ class RelatedController extends BaseController
{
$group = new TransactionGroup;
$group->relation = 'balance';
$group->user_id = $this->_repository->getUser()->id;
$group->user_id = Auth::user()->id;
$group->save();
$group->transactionjournals()->save($parentJournal);
$group->transactionjournals()->save($childJournal);
@@ -94,7 +126,7 @@ class RelatedController extends BaseController
}
}
return View::make('related.relate', compact('journal', 'members'));
return view('related.relate', compact('journal', 'members'));
}
/**
@@ -130,19 +162,16 @@ class RelatedController extends BaseController
*
* @return \Illuminate\Http\JsonResponse
*/
public function search(TransactionJournal $journal)
public function search(TransactionJournal $journal, JournalRepositoryInterface $repository)
{
$search = e(trim(Input::get('searchValue')));
$parent = $journal;
$result = $this->_repository->search($search, $journal);
$result->each(
function (TransactionJournal $j) {
$j->amount = Amount::format($j->getAmount());
}
);
$journals = $repository->searchRelated($search, $journal);
return view('related.searchResult', compact('journals', 'search', 'parent'));
return Response::json($result->toArray());
}
}

View File

@@ -0,0 +1,128 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use FireflyIII\Helpers\Reminders\ReminderHelperInterface;
use FireflyIII\Http\Requests;
use FireflyIII\Models\Reminder;
use Redirect;
use Session;
use URL;
/**
* Class ReminderController
*
* @package FireflyIII\Http\Controllers
*/
class ReminderController extends Controller
{
/**
* @param Reminder $reminder
*/
public function act(Reminder $reminder)
{
$data = [
'description' => 'Money for piggy bank "' . $reminder->remindersable->name . '"',
'amount' => round($reminder->metadata->perReminder, 2),
'account_to_id' => $reminder->remindersable->account_id,
'piggy_bank_id' => $reminder->remindersable_id,
'reminder_id' => $reminder->id,
];
Session::flash('_old_input', $data);
return Redirect::route('transactions.create', 'transfer');
}
/**
* @param Reminder $reminder
*/
public function dismiss(Reminder $reminder)
{
$reminder->notnow = true;
$reminder->save();
return Redirect::to(URL::previous());
}
/**
*
*/
public function index(ReminderHelperInterface $helper)
{
$reminders = Auth::user()->reminders()->get();
$reminders->each(
function (Reminder $reminder) use ($helper) {
$reminder->description = $helper->getReminderText($reminder);
}
);
$today = new Carbon;
// active reminders:
$active = $reminders->filter(
function (Reminder $reminder) use ($today) {
if ($reminder->notnow === false && $reminder->active === true && $reminder->startdate <= $today && $reminder->enddate >= $today) {
return $reminder;
}
}
);
// expired reminders:
$expired = $reminders->filter(
function (Reminder $reminder) use ($today) {
if ($reminder->notnow === false && $reminder->active === true && $reminder->startdate > $today || $reminder->enddate < $today) {
return $reminder;
}
}
);
// inactive reminders
$inactive = $reminders->filter(
function (Reminder $reminder) use ($today) {
if ($reminder->active === false) {
return $reminder;
}
}
);
// dismissed reminders
$dismissed = $reminders->filter(
function (Reminder $reminder) use ($today) {
if ($reminder->notnow === true) {
return $reminder;
}
}
);
$title = 'Reminders';
$mainTitleIcon = 'fa-clock-o';
return view('reminders.index', compact('dismissed', 'expired', 'inactive', 'active', 'title', 'mainTitleIcon'));
}
/**
* @param Reminder $reminder
*/
public function show(Reminder $reminder)
{
$title = 'Reminder';
$mainTitleIcon = 'fa-clock-o';
if ($reminder->notnow === true) {
$subTitle = 'Dismissed reminder';
} else {
$subTitle = 'Reminder';
}
$subTitle .= ' for piggy bank "' . $reminder->remindersable->name . '"';
return view('reminders.show', compact('reminder', 'title', 'subTitle', 'mainTitleIcon'));
}
}

View File

@@ -0,0 +1,217 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use Config;
use ExpandedForm;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\PiggyBankFormRequest;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Redirect;
use Session;
use View;
use Input;
/**
* Class RepeatedExpenseController
*
* @package FireflyIII\Http\Controllers
*/
class RepeatedExpenseController extends Controller
{
/**
*
*/
public function __construct()
{
View::share('title', 'Repeated expenses');
View::share('mainTitleIcon', 'fa-rotate-left');
}
/**
* @return $this
*/
public function create()
{
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
);
return view('repeatedExpense.create', compact('accounts', 'periods'))->with('subTitle', 'Create new repeated expense')->with(
'subTitleIcon', 'fa-plus'
);
}
/**
* @param PiggyBank $repeatedExpense
*
* @return $this
*/
public function delete(PiggyBank $repeatedExpense)
{
$subTitle = 'Delete "' . e($repeatedExpense->name) . '"';
return view('repeatedExpense.delete', compact('repeatedExpense', 'subTitle'));
}
/**
* @param PiggyBank $repeatedExpense
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(PiggyBank $repeatedExpense)
{
Session::flash('success', 'Repeated expense "' . e($repeatedExpense->name) . '" deleted.');
$repeatedExpense->delete();
return Redirect::route('repeated.index');
}
/**
* @param PiggyBank $repeatedExpense
*
* @return $this
*/
public function edit(PiggyBank $repeatedExpense)
{
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->orderBy('accounts.name', 'ASC')->accountTypeIn(['Default account', 'Asset account'])->get(['accounts.*'])
);
$subTitle = 'Edit repeated expense "' . e($repeatedExpense->name) . '"';
$subTitleIcon = 'fa-pencil';
/*
* Flash some data to fill the form.
*/
$preFilled = ['name' => $repeatedExpense->name,
'account_id' => $repeatedExpense->account_id,
'targetamount' => $repeatedExpense->targetamount,
'reminder_skip' => $repeatedExpense->reminder_skip,
'rep_every' => $repeatedExpense->rep_every,
'rep_times' => $repeatedExpense->rep_times,
'targetdate' => $repeatedExpense->targetdate->format('Y-m-d'),
'reminder' => $repeatedExpense->reminder,
'remind_me' => intval($repeatedExpense->remind_me) == 1 || !is_null($repeatedExpense->reminder) ? true : false
];
Session::flash('preFilled', $preFilled);
return view('repeatedExpense.edit', compact('subTitle', 'subTitleIcon', 'repeatedExpense', 'accounts', 'periods', 'preFilled'));
}
/**
* @return \Illuminate\View\View
*/
public function index()
{
$subTitle = 'Overview';
$expenses = Auth::user()->piggyBanks()->where('repeats', 1)->get();
$expenses->each(
function (PiggyBank $piggyBank) {
$piggyBank->currentRelevantRep();
}
);
return view('repeatedExpense.index', compact('expenses', 'subTitle'));
}
/**
* @param PiggyBank $repeatedExpense
*
* @return \Illuminate\View\View
*/
public function show(PiggyBank $repeatedExpense, PiggyBankRepositoryInterface $repository)
{
$subTitle = $repeatedExpense->name;
$today = Carbon::now();
$repetitions = $repeatedExpense->piggyBankRepetitions()->get();
$repetitions->each(
function (PiggyBankRepetition $repetition) use ($repository) {
$repetition->bars = $repository->calculateParts($repetition);
}
);
return view('repeatedExpense.show', compact('repetitions', 'repeatedExpense', 'today', 'subTitle'));
}
/**
* @param PiggyBankFormRequest $request
* @param PiggyBankRepositoryInterface $repository
*
* @return \Illuminate\Http\RedirectResponse
*/
public function store(PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository)
{
$piggyBankData = [
'repeats' => true,
'name' => $request->get('name'),
'startdate' => new Carbon,
'account_id' => intval($request->get('account_id')),
'targetamount' => floatval($request->get('targetamount')),
'targetdate' => new Carbon($request->get('targetdate')),
'reminder' => $request->get('reminder'),
'skip' => intval($request->get('skip')),
'rep_every' => intval($request->get('rep_every')),
'rep_length' => $request->get('rep_length'),
'rep_times' => intval($request->get('rep_times')),
];
$piggyBank = $repository->store($piggyBankData);
Session::flash('success', 'Stored repeated expense "' . e($piggyBank->name) . '".');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('repeated.create', $request->input('what'))->withInput();
}
return Redirect::route('repeated.index');
}
/**
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @param PiggyBank $repeatedExpense
*
* @return $this
*/
public function update(PiggyBank $repeatedExpense, PiggyBankFormRequest $request, PiggyBankRepositoryInterface $repository)
{
$piggyBankData = [
'repeats' => false,
'name' => $request->get('name'),
'account_id' => intval($request->get('account_id')),
'targetamount' => floatval($request->get('targetamount')),
'targetdate' => strlen($request->get('targetdate')) > 0 ? new Carbon($request->get('targetdate')) : null,
'rep_length' => $request->get('rep_length'),
'rep_every' => intval($request->get('rep_every')),
'rep_times' => intval($request->get('rep_times')),
'remind_me' => intval($request->get('remind_me')) == 1 ? true : false,
'reminder' => $request->get('reminder'),
];
$piggyBank = $repository->update($repeatedExpense, $piggyBankData);
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('repeated.edit', $piggyBank->id);
}
Session::flash('success', 'Updated repeated expense "' . e($piggyBank->name) . '".');
return Redirect::route('repeated.index');
}
}

View File

@@ -0,0 +1,388 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use Exception;
use FireflyIII\Helpers\Report\ReportHelperInterface;
use FireflyIII\Helpers\Report\ReportQueryInterface;
use FireflyIII\Http\Requests;
use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Database\Query\JoinClause;
use Preferences;
use Session;
use Steam;
use View;
/**
* Class ReportController
*
* @package FireflyIII\Http\Controllers
*/
class ReportController extends Controller
{
/**
*
*/
public function __construct()
{
View::share('title', 'Reports');
View::share('mainTitleIcon', 'fa-line-chart');
}
/**
* @param string $year
* @param string $month
*
* @return \Illuminate\View\View
*/
public function budget($year = '2014', $month = '1', ReportQueryInterface $query)
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return view('error')->with('message', 'Invalid date');
}
$date = new Carbon($year . '-' . $month . '-01');
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
$start->subDay();
// shared accounts preference:
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
$dayEarly = clone $date;
$subTitle = 'Budget report for ' . $date->format('F Y');
$subTitleIcon = 'fa-calendar';
$dayEarly = $dayEarly->subDay();
$accounts = $query->getAllAccounts($start, $end, $showSharedReports);
$start->addDay();
$accounts->each(
function (Account $account) use ($start, $end, $query) {
$budgets = $query->getBudgetSummary($account, $start, $end);
$balancedAmount = $query->balancedTransactionsSum($account, $start, $end);
$array = [];
foreach ($budgets as $budget) {
$id = intval($budget->id);
$data = $budget->toArray();
$array[$id] = $data;
}
$account->budgetInformation = $array;
$account->balancedAmount = $balancedAmount;
}
);
$start = clone $date;
$start->startOfMonth();
/**
* Start getBudgetsForMonth DONE
*/
$set = Auth::user()->budgets()->orderBy('budgets.name', 'ASC')
->leftJoin(
'budget_limits', function (JoinClause $join) use ($date) {
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
}
)
->get(['budgets.*', 'budget_limits.amount as amount']);
$budgets = Steam::makeArray($set);
$amountSet = $query->journalsByBudget($start, $end, $showSharedReports);
$amounts = Steam::makeArray($amountSet);
$budgets = Steam::mergeArrays($budgets, $amounts);
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
$budgets[0]['amount'] = isset($budgets[0]['amount']) ? $budgets[0]['amount'] : 0.0;
$budgets[0]['name'] = 'No budget';
// find transactions to shared asset accounts, which are without a budget by default:
// which is only relevant when shared asset accounts are hidden.
if ($showSharedReports === false) {
$transfers = $query->sharedExpenses($start, $end);
foreach ($transfers as $transfer) {
$budgets[0]['spent'] += floatval($transfer->amount) * -1;
}
}
/**
* End getBudgetsForMonth DONE
*/
return view('reports.budget', compact('subTitle', 'year', 'month', 'subTitleIcon', 'date', 'accounts', 'budgets', 'dayEarly'));
}
/**
* @param ReportHelperInterface $helper
*
* @return View
*/
public function index(ReportHelperInterface $helper)
{
$start = Session::get('first');
$months = $helper->listOfMonths($start);
$years = $helper->listOfYears($start);
$title = 'Reports';
$mainTitleIcon = 'fa-line-chart';
return view('reports.index', compact('years', 'months', 'title', 'mainTitleIcon'));
}
/**
* @param Account $account
* @param string $year
* @param string $month
*
* @return \Illuminate\View\View
*/
public function modalBalancedTransfers(Account $account, $year = '2014', $month = '1', ReportQueryInterface $query)
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return view('error')->with('message', 'Invalid date');
}
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
$journals = $query->balancedTransactionsList($account, $start, $end);
return view('reports.modal-journal-list', compact('journals'));
}
/**
* @param Account $account
* @param string $year
* @param string $month
* @param ReportQueryInterface $query
*
* @return View
*/
public function modalLeftUnbalanced(Account $account, $year = '2014', $month = '1', ReportQueryInterface $query)
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return view('error')->with('message', 'Invalid date');
}
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
$set = $query->getTransactionsWithoutBudget($account, $start, $end);
$journals = $set->filter(
function (TransactionJournal $journal) {
$count = $journal->transactiongroups()->where('relation', 'balance')->count();
if ($count == 0) {
return $journal;
}
}
);
return view('reports.modal-journal-list', compact('journals'));
}
/**
* @param Account $account
* @param string $year
* @param string $month
*
* @return \Illuminate\View\View
*/
public function modalNoBudget(Account $account, $year = '2014', $month = '1', ReportQueryInterface $query)
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return view('error')->with('message', 'Invalid date');
}
$start = new Carbon($year . '-' . $month . '-01');
$end = clone $start;
$end->endOfMonth();
$journals = $query->getTransactionsWithoutBudget($account, $start, $end);
return view('reports.modal-journal-list', compact('journals'));
}
/**
* @param string $year
* @param string $month
*
* @return \Illuminate\View\View
*/
public function month($year = '2014', $month = '1', ReportQueryInterface $query)
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return view('error')->with('message', 'Invalid date.');
}
$date = new Carbon($year . '-' . $month . '-01');
$subTitle = 'Report for ' . $date->format('F Y');
$subTitleIcon = 'fa-calendar';
$displaySum = true; // to show sums in report.
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
/**
*
* get income for month (date)
*
*/
$start = clone $date;
$start->startOfMonth();
$end = clone $date;
$end->endOfMonth();
/**
* Start getIncomeForMonth DONE
*/
$income = $query->incomeByPeriod($start, $end, $showSharedReports);
/**
* End getIncomeForMonth DONE
*/
/**
* Start getExpenseGroupedForMonth DONE
*/
$set = $query->journalsByExpenseAccount($start, $end, $showSharedReports);
$expenses = Steam::makeArray($set);
$expenses = Steam::sortArray($expenses);
$expenses = Steam::limitArray($expenses, 10);
/**
* End getExpenseGroupedForMonth DONE
*/
/**
* Start getBudgetsForMonth DONE
*/
$set = Auth::user()->budgets()
->leftJoin(
'budget_limits', function (JoinClause $join) use ($date) {
$join->on('budget_limits.budget_id', '=', 'budgets.id')->where('budget_limits.startdate', '=', $date->format('Y-m-d'));
}
)
->get(['budgets.*', 'budget_limits.amount as amount']);
$budgets = Steam::makeArray($set);
$amountSet = $query->journalsByBudget($start, $end, $showSharedReports);
$amounts = Steam::makeArray($amountSet);
$budgets = Steam::mergeArrays($budgets, $amounts);
$budgets[0]['spent'] = isset($budgets[0]['spent']) ? $budgets[0]['spent'] : 0.0;
$budgets[0]['amount'] = isset($budgets[0]['amount']) ? $budgets[0]['amount'] : 0.0;
$budgets[0]['name'] = 'No budget';
// find transactions to shared expense accounts, which are without a budget by default:
if ($showSharedReports === false) {
$transfers = $query->sharedExpenses($start, $end);
foreach ($transfers as $transfer) {
$budgets[0]['spent'] += floatval($transfer->amount) * -1;
}
}
/**
* End getBudgetsForMonth DONE
*/
/**
* Start getCategoriesForMonth DONE
*/
// all categories.
$result = $query->journalsByCategory($start, $end);
$categories = Steam::makeArray($result);
// all transfers
if ($showSharedReports === false) {
$result = $query->sharedExpensesByCategory($start, $end);
$transfers = Steam::makeArray($result);
$merged = Steam::mergeArrays($categories, $transfers);
} else {
$merged = $categories;
}
// sort.
$sorted = Steam::sortNegativeArray($merged);
// limit to $limit:
$categories = Steam::limitArray($sorted, 10);
/**
* End getCategoriesForMonth DONE
*/
/**
* Start getAccountsForMonth
*/
$list = $query->accountList($showSharedReports);
$accounts = [];
/** @var Account $account */
foreach ($list as $account) {
$id = intval($account->id);
/** @noinspection PhpParamsInspection */
$accounts[$id] = [
'name' => $account->name,
'startBalance' => Steam::balance($account, $start),
'endBalance' => Steam::balance($account, $end)
];
$accounts[$id]['difference'] = $accounts[$id]['endBalance'] - $accounts[$id]['startBalance'];
}
/**
* End getAccountsForMonth
*/
return view(
'reports.month',
compact(
'income', 'expenses', 'budgets', 'accounts', 'categories',
'date', 'subTitle', 'displaySum', 'subTitleIcon'
)
);
}
/**
* @param $year
*
* @return $this
*/
public function year($year, ReportHelperInterface $helper, ReportQueryInterface $query)
{
try {
new Carbon('01-01-' . $year);
} catch (Exception $e) {
return view('error')->with('message', 'Invalid date.');
}
$pref = Preferences::get('showSharedReports', false);
$showSharedReports = $pref->data;
$date = new Carbon('01-01-' . $year);
$end = clone $date;
$end->endOfYear();
$title = 'Reports';
$subTitle = $year;
$subTitleIcon = 'fa-bar-chart';
$mainTitleIcon = 'fa-line-chart';
$balances = $helper->yearBalanceReport($date, $showSharedReports);
$groupedIncomes = $query->journalsByRevenueAccount($date, $end, $showSharedReports);
$groupedExpenses = $query->journalsByExpenseAccount($date, $end, $showSharedReports);
//$groupedExpenses = $helper-> expensesGroupedByAccount($date, $end, 15);
return view(
'reports.year', compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon')
);
}
}

View File

@@ -1,19 +1,22 @@
<?php
<?php namespace FireflyIII\Http\Controllers;
use FireflyIII\Http\Requests;
use FireflyIII\Support\Search\SearchInterface;
use Input;
/**
* Class SearchController
*
* @package FireflyIII\Http\Controllers
*/
class SearchController extends BaseController
class SearchController extends Controller
{
/**
* Results always come in the form of an array [results, count, fullCount]
*/
public function index()
public function index(SearchInterface $searcher)
{
/** @var \FireflyIII\Search\Search $searcher */
$searcher = App::make('FireflyIII\Search\Search');
$subTitle = null;
$rawQuery = null;
$result = [];
@@ -31,8 +34,9 @@ class SearchController extends BaseController
}
return View::make('search.index')->with('title', 'Search')->with('subTitle', $subTitle)->with(
return view('search.index')->with('title', 'Search')->with('subTitle', $subTitle)->with(
'mainTitleIcon', 'fa-search'
)->with('query', $rawQuery)->with('result', $result);
}
}

View File

@@ -0,0 +1,357 @@
<?php namespace FireflyIII\Http\Controllers;
use Auth;
use Carbon\Carbon;
use ExpandedForm;
use FireflyIII\Events\JournalCreated;
use FireflyIII\Events\JournalSaved;
use FireflyIII\Http\Requests;
use FireflyIII\Http\Requests\JournalFormRequest;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Pagination\LengthAwarePaginator;
use Input;
use Redirect;
use Session;
use View;
use Response;
/**
* Class TransactionController
*
* @package FireflyIII\Http\Controllers
*/
class TransactionController extends Controller
{
/**
*/
public function __construct()
{
View::share('title', 'Transactions');
View::share('mainTitleIcon', 'fa-repeat');
}
/**
* Shows the view helping the user to create a new transaction journal.
*
* @param string $what
*
* @return \Illuminate\View\View
*/
public function create($what = 'deposit')
{
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->orderBy('name', 'ASC')->where(
'active', 1
)->orderBy('name', 'DESC')->get(['accounts.*'])
);
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = '(no budget)';
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
$piggies[0] = '(no piggy bank)';
$preFilled = Session::has('preFilled') ? Session::get('preFilled') : [];
$respondTo = ['account_id', 'account_from_id'];
$subTitle = 'Add a new ' . e($what);
foreach ($respondTo as $r) {
if (!is_null(Input::get($r))) {
$preFilled[$r] = Input::get($r);
}
}
Session::put('preFilled', $preFilled);
asort($piggies);
return view('transactions.create', compact('accounts', 'budgets', 'what', 'piggies', 'subTitle'));
}
/**
* Shows the form that allows a user to delete a transaction journal.
*
* @param TransactionJournal $journal
*
* @return $this
*/
public function delete(TransactionJournal $journal)
{
$type = strtolower($journal->transactionType->type);
$subTitle = 'Delete ' . e($type) . ' "' . e($journal->description) . '"';
return View::make('transactions.delete', compact('journal', 'subTitle'));
}
/**
* @param TransactionJournal $transactionJournal
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(TransactionJournal $transactionJournal)
{
$type = $transactionJournal->transactionType->type;
$return = 'withdrawal';
Session::flash('success', 'Transaction "' . e($transactionJournal->description) . '" destroyed.');
$transactionJournal->delete();
switch ($type) {
case 'Deposit':
$return = 'deposit';
break;
case 'Transfer':
$return = 'transfers';
break;
}
return Redirect::route('transactions.index', $return);
}
/**
* Shows the view to edit a transaction.
*
* @param TransactionJournal $journal
*
* @return $this
*/
public function edit(TransactionJournal $journal, JournalRepositoryInterface $repository)
{
$what = strtolower($journal->transactiontype->type);
$accounts = ExpandedForm::makeSelectList(
Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->where('active', 1)->orderBy(
'name', 'DESC'
)->get(['accounts.*'])
);
$budgets = ExpandedForm::makeSelectList(Auth::user()->budgets()->get());
$budgets[0] = '(no budget)';
$transactions = $journal->transactions()->orderBy('amount', 'DESC')->get();
$piggies = ExpandedForm::makeSelectList(Auth::user()->piggyBanks()->get());
$piggies[0] = '(no piggy bank)';
$preFilled = [
'date' => $journal->date->format('Y-m-d'),
'category' => '',
'budget_id' => 0,
'piggy_bank_id' => 0
];
$category = $journal->categories()->first();
if (!is_null($category)) {
$preFilled['category'] = $category->name;
}
$budget = $journal->budgets()->first();
if (!is_null($budget)) {
$preFilled['budget_id'] = $budget->id;
}
if ($journal->piggyBankEvents()->count() > 0) {
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->orderBy('date', 'DESC')->first()->piggy_bank_id;
}
$preFilled['amount'] = 0;
/** @var Transaction $t */
foreach ($transactions as $t) {
if (floatval($t->amount) > 0) {
$preFilled['amount'] = floatval($t->amount);
}
}
$preFilled['account_id'] = $repository->getAssetAccount($journal);
$preFilled['expense_account'] = $transactions[0]->account->name;
$preFilled['revenue_account'] = $transactions[1]->account->name;
$preFilled['account_from_id'] = $transactions[1]->account->id;
$preFilled['account_to_id'] = $transactions[0]->account->id;
return View::make('transactions.edit', compact('journal', 'accounts', 'what', 'budgets', 'piggies', 'subTitle'))->with('data', $preFilled);
}
/**
* @param $what
*
* @return $this
*/
public function index($what)
{
switch ($what) {
case 'expenses':
case 'withdrawal':
$subTitleIcon = 'fa-long-arrow-left';
$subTitle = 'Expenses';
$types = ['Withdrawal'];
break;
case 'revenue':
case 'deposit':
$subTitleIcon = 'fa-long-arrow-right';
$subTitle = 'Revenue, income and deposits';
$types = ['Deposit'];
break;
case 'transfer':
case 'transfers':
$subTitleIcon = 'fa-exchange';
$subTitle = 'Transfers';
$types = ['Transfer'];
break;
}
$page = intval(\Input::get('page'));
$offset = $page > 0 ? ($page - 1) * 50 : 0;
$set = Auth::user()->
transactionJournals()->
transactionTypes($types)->
withRelevantData()->take(50)->offset($offset)
->orderBy('date', 'DESC')
->orderBy('order','ASC')
->orderBy('id','DESC')
->get(
['transaction_journals.*']
);
$count = Auth::user()->transactionJournals()->transactionTypes($types)->count();
$journals = new LengthAwarePaginator($set, $count, 50, $page);
$journals->setPath('transactions/' . $what);
return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals'));
}
/**
* Reorder transactions (which all must have the same date)
*/
public function reorder()
{
$ids = Input::get('items');
if (count($ids) > 0) {
$order = 0;
foreach ($ids as $id) {
$journal = Auth::user()->transactionjournals()->where('id', $id)->where('date', Input::get('date'))->first();
if($journal) {
$journal->order = $order;
$order++;
$journal->save();
}
}
}
return Response::json(true);
}
/**
* @param TransactionJournal $journal
*
* @return $this
*/
public function show(TransactionJournal $journal)
{
$journal->transactions->each(
function (Transaction $t) use ($journal) {
$t->before = floatval(
$t->account->transactions()->leftJoin(
'transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id'
)
->where('transaction_journals.date', '<=', $journal->date->format('Y-m-d'))
->where('transaction_journals.order','>=',$journal->order)
->where('transaction_journals.id', '!=', $journal->id)
->sum('transactions.amount')
);
$t->after = $t->before + $t->amount;
}
);
return view('transactions.show', compact('journal'))->with(
'subTitle', e($journal->transactiontype->type) . ' "' . e($journal->description) . '"'
);
}
/**
* @param JournalFormRequest $request
* @param JournalRepositoryInterface $repository
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function store(JournalFormRequest $request, JournalRepositoryInterface $repository)
{
$journalData = [
'what' => $request->get('what'),
'description' => $request->get('description'),
'account_id' => intval($request->get('account_id')),
'account_from_id' => intval($request->get('account_from_id')),
'account_to_id' => intval($request->get('account_to_id')),
'expense_account' => $request->get('expense_account'),
'revenue_account' => $request->get('revenue_account'),
'amount' => floatval($request->get('amount')),
'user' => Auth::user()->id,
'amount_currency_id' => intval($request->get('amount_currency_id')),
'date' => new Carbon($request->get('date')),
'budget_id' => intval($request->get('budget_id')),
'category' => $request->get('category'),
];
$journal = $repository->store($journalData);
event(new JournalSaved($journal));
event(new JournalCreated($journal, intval($request->get('piggy_bank_id'))));
if (intval($request->get('reminder_id')) > 0) {
$reminder = Auth::user()->reminders()->find($request->get('reminder_id'));
$reminder->active = 0;
$reminder->save();
}
Session::flash('success', 'New transaction "' . $journal->description . '" stored!');
if (intval(Input::get('create_another')) === 1) {
return Redirect::route('transactions.create', $request->input('what'))->withInput();
}
return Redirect::route('transactions.index', $request->input('what'));
}
/**
* @param TransactionJournal $journal
*
* @SuppressWarnings("CyclomaticComplexity") // It's exactly 5. So I don't mind.
*
* @return $this
*/
public function update(TransactionJournal $journal, JournalFormRequest $request, JournalRepositoryInterface $repository)
{
$journalData = [
'what' => $request->get('what'),
'description' => $request->get('description'),
'account_id' => intval($request->get('account_id')),
'account_from_id' => intval($request->get('account_from_id')),
'account_to_id' => intval($request->get('account_to_id')),
'expense_account' => $request->get('expense_account'),
'revenue_account' => $request->get('revenue_account'),
'amount' => floatval($request->get('amount')),
'user' => Auth::user()->id,
'amount_currency_id' => intval($request->get('amount_currency_id')),
'date' => new Carbon($request->get('date')),
'budget_id' => intval($request->get('budget_id')),
'category' => $request->get('category'),
];
$repository->update($journal, $journalData);
event(new JournalSaved($journal));
// update, get events by date and sort DESC
Session::flash('success', 'Transaction "' . e($journalData['description']) . '" updated.');
if (intval(Input::get('return_to_edit')) === 1) {
return Redirect::route('transactions.edit', $journal->id);
}
return Redirect::route('transactions.index', $journalData['what']);
}
}

43
app/Http/Kernel.php Normal file
View File

@@ -0,0 +1,43 @@
<?php namespace FireflyIII\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
/**
* Class Kernel
*
* @package FireflyIII\Http
*/
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* @var array
*/
protected $middleware
= [
'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
'Illuminate\Cookie\Middleware\EncryptCookies',
'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
'Illuminate\Session\Middleware\StartSession',
'Illuminate\View\Middleware\ShareErrorsFromSession',
'FireflyIII\Http\Middleware\VerifyCsrfToken',
];
/**
* The application's route middleware.
*
* @var array
*/
protected $routeMiddleware
= [
'auth' => 'FireflyIII\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'FireflyIII\Http\Middleware\RedirectIfAuthenticated',
'range' => 'FireflyIII\Http\Middleware\Range',
'reminders' => 'FireflyIII\Http\Middleware\Reminders',
'piggybanks' => 'FireflyIII\Http\Middleware\PiggyBanks',
];
}

View File

@@ -0,0 +1,53 @@
<?php namespace FireflyIII\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
/**
* Class Authenticate
*
* @package FireflyIII\Http\Middleware
*/
class Authenticate
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('auth/login');
}
}
return $next($request);
}
}

View File

@@ -0,0 +1,141 @@
<?php
namespace FireflyIII\Http\Middleware;
use Carbon\Carbon;
use Closure;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\Reminder;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Navigation;
use Session;
/**
* Class PiggyBanks
*
* @package FireflyIII\Http\Middleware
*/
class PiggyBanks
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->check() && !$request->isXmlHttpRequest()) {
// get piggy banks without a repetition:
/** @var Collection $set */
$set = $this->auth->user()->piggybanks()
->leftJoin('piggy_bank_repetitions', 'piggy_banks.id', '=', 'piggy_bank_repetitions.piggy_bank_id')
->where('piggy_banks.repeats', 0)
->whereNull('piggy_bank_repetitions.id')
->get(['piggy_banks.id', 'piggy_banks.startdate', 'piggy_banks.targetdate']);
if ($set->count() > 0) {
/** @var PiggyBank $partialPiggy */
foreach ($set as $partialPiggy) {
$repetition = new PiggyBankRepetition;
$repetition->piggyBank()->associate($partialPiggy);
$repetition->startdate = is_null($partialPiggy->startdate) ? null : $partialPiggy->startdate;
$repetition->targetdate = is_null($partialPiggy->targetdate) ? null : $partialPiggy->targetdate;
$repetition->currentamount = 0;
$repetition->save();
}
}
unset($partialPiggy, $set, $repetition);
// get repeating piggy banks without a repetition for current time frame.
/** @var Collection $set */
$set = $this->auth->user()->piggybanks()->leftJoin(
'piggy_bank_repetitions', function (JoinClause $join) {
$join->on('piggy_bank_repetitions.piggy_bank_id', '=', 'piggy_banks.id')
->where('piggy_bank_repetitions.targetdate', '>=', Session::get('start')->format('Y-m-d'))
->where('piggy_bank_repetitions.startdate', '<=', Session::get('end')->format('Y-m-d'));
}
)
->where('repeats', 1)
->whereNull('piggy_bank_repetitions.id')
->get(['piggy_banks.*']);
// these piggy banks are missing a repetition. start looping and create them!
if ($set->count() > 0) {
/** @var PiggyBank $piggyBank */
foreach ($set as $piggyBank) {
$start = clone $piggyBank->startdate;
$end = clone $piggyBank->targetdate;
$max = clone $piggyBank->targetdate;
$index = 0;
// first loop: start date to target date.
// then, continue looping until end is > today
while ($start <= $max) {
// first loop fixes this date. or should fix it.
$max = new Carbon;
echo '[#'.$piggyBank->id.', from: '.$start->format('Y-m-d.').' to '.$end->format('Y-m-d.').']';
// create stuff. Or at least, try:
$repetition = $piggyBank->piggyBankRepetitions()->onDates($start, $end)->first();
if(!$repetition) {
$repetition = new PiggyBankRepetition;
$repetition->piggyBank()->associate($piggyBank);
$repetition->startdate = $start;
$repetition->targetdate = $end;
$repetition->currentamount = 0;
// it might exist, catch:
$repetition->save();
}
// start where end 'ended':
$start = clone $end;
// move end.
$end = Navigation::addPeriod($end, $piggyBank->rep_length, 0);
}
// first repetition: from original start to original target.
$repetition = new PiggyBankRepetition;
$repetition->piggyBank()->associate($piggyBank);
$repetition->startdate = is_null($piggyBank->startdate) ? null : $piggyBank->startdate;
$repetition->targetdate = is_null($piggyBank->targetdate) ? null : $piggyBank->targetdate;
$repetition->currentamount = 0;
// it might exist, catch:
//$repetition->save();
// then, loop from original target up to now.
}
}
}
return $next($request);
}
}

View File

@@ -0,0 +1,87 @@
<?php
namespace FireflyIII\Http\Middleware;
use Carbon\Carbon;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Navigation;
use Preferences;
use Session;
use View;
/**
* Class SessionFilter
*
* @package FireflyIII\Http\Middleware
*/
class Range
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $theNext
*
* @return mixed
*/
public function handle($request, Closure $theNext)
{
if ($this->auth->check()) {
// ignore preference. set the range to be the current month:
if (!Session::has('start') && !Session::has('end')) {
/** @var \FireflyIII\Models\Preference $viewRange */
$viewRange = Preferences::get('viewRange', '1M');
$start = Session::has('start') ? Session::get('start') : new Carbon;
$start = Navigation::updateStartDate($viewRange->data, $start);
$end = Navigation::updateEndDate($viewRange->data, $start);
Session::put('start', $start);
Session::put('end', $end);
}
if (!Session::has('first')) {
$journal = $this->auth->user()->transactionjournals()->orderBy('date', 'ASC')->first(['transaction_journals.*']);
if ($journal) {
Session::put('first', $journal->date);
} else {
Session::put('first', Carbon::now());
}
}
// set current / next / prev month.
$current = Carbon::now()->format('F Y');
$next = Carbon::now()->endOfMonth()->addDay()->format('F Y');
$prev = Carbon::now()->startOfMonth()->subDay()->format('F Y');
View::share('currentMonthName', $current);
View::share('previousMonthName', $prev);
View::share('nextMonthName', $next);
}
return $theNext($request);
}
}

View File

@@ -0,0 +1,50 @@
<?php namespace FireflyIII\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\RedirectResponse;
/**
* Class RedirectIfAuthenticated
*
* @package FireflyIII\Http\Middleware
*/
class RedirectIfAuthenticated
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->check()) {
return new RedirectResponse(url('/'));
}
return $next($request);
}
}

View File

@@ -0,0 +1,90 @@
<?php
namespace FireflyIII\Http\Middleware;
use App;
use Carbon\Carbon;
use Closure;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Reminder;
use Illuminate\Contracts\Auth\Guard;
use View;
/**
* Class Reminders
*
* @package FireflyIII\Http\Middleware
*/
class Reminders
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
*
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->check() && !$request->isXmlHttpRequest()) {
// do reminders stuff.
$piggyBanks = $this->auth->user()->piggyBanks()->where('remind_me', 1)->get();
$today = new Carbon;
/** @var \FireflyIII\Helpers\Reminders\ReminderHelperInterface $helper */
$helper = App::make('FireflyIII\Helpers\Reminders\ReminderHelperInterface');
/** @var PiggyBank $piggyBank */
foreach ($piggyBanks as $piggyBank) {
$ranges = $helper->getReminderRanges($piggyBank);
foreach ($ranges as $range) {
if ($today < $range['end'] && $today > $range['start']) {
// create a reminder here!
$helper->createReminder($piggyBank, $range['start'], $range['end']);
// stop looping, we're done.
break;
}
}
}
// delete invalid reminders
$set = $this->auth->user()->reminders()->leftJoin('piggy_banks', 'piggy_banks.id', '=', 'remindersable_id')->whereNull('piggy_banks.id')->get(
['reminders.id']
);
foreach ($set as $reminder) {
$reminder->delete();
}
// get and list active reminders:
$reminders = $this->auth->user()->reminders()->today()->get();
$reminders->each(
function (Reminder $reminder) use ($helper) {
$reminder->description = $helper->getReminderText($reminder);
}
);
View::share('reminders', $reminders);
}
return $next($request);
}
}

View File

@@ -0,0 +1,27 @@
<?php namespace FireflyIII\Http\Middleware;
use Closure;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
/**
* Class VerifyCsrfToken
*
* @package FireflyIII\Http\Middleware
*/
class VerifyCsrfToken extends BaseVerifier
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
return parent::handle($request, $next);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace FireflyIII\Http\Requests;
use Auth;
use Config;
use FireflyIII\Models\Account;
use Input;
/**
* Class AccountFormRequest
*
* @package FireflyIII\Http\Requests
*/
class AccountFormRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
$accountRoles = join(',', array_keys(Config::get('firefly.accountRoles')));
$types = join(',', array_keys(Config::get('firefly.subTitlesByIdentifier')));
$nameRule = 'required|between:1,100|uniqueAccountForUser';
if (Account::find(Input::get('id'))) {
$nameRule = 'required|between:1,100|belongsToUser:accounts|uniqueForUser:'.Input::get('id');
}
return [
'name' => $nameRule,
'openingBalance' => 'numeric',
'openingBalanceDate' => 'date',
'accountRole' => 'in:' . $accountRoles,
'active' => 'boolean',
'balance_currency_id' => 'exists:transaction_currencies,id',
'what' => 'in:' . $types
];
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace FireflyIII\Http\Requests;
use Auth;
use Input;
/**
* Class BillFormRequest
*
* @package FireflyIII\Http\Requests
*/
class BillFormRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
$nameRule = 'required|between:1,255|uniqueForUser:bills,name';
if (intval(Input::get('id')) > 0) {
$nameRule = 'required|between:1,255';
}
$rules = [
'name' => $nameRule,
'match' => 'required|between:1,255',
'amount_min' => 'required|numeric|min:0.01',
'amount_max' => 'required|numeric|min:0.01',
'amount_currency_id' => 'required|exists:transaction_currencies,id',
'date' => 'required|date',
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
'skip' => 'required|between:0,31',
'automatch' => 'in:1',
'active' => 'in:1',
];
return $rules;
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace FireflyIII\Http\Requests;
use Auth;
use FireflyIII\Models\Budget;
use Input;
/**
* Class BudgetFormRequest
*
* @package FireflyIII\Http\Requests
*/
class BudgetFormRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
$nameRule = 'required|between:1,100|uniqueForUser:budgets,name';
if (Budget::find(Input::get('id'))) {
$nameRule = 'required|between:1,100';
}
return [
'name' => $nameRule,
];
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace FireflyIII\Http\Requests;
use Auth;
use FireflyIII\Models\Category;
use Input;
/**
* Class CategoryFormRequest
*
* @package FireflyIII\Http\Requests
*/
class CategoryFormRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
$nameRule = 'required|between:1,100|uniqueForUser:categories,name';
if (Category::find(Input::get('id'))) {
$nameRule = 'required|between:1,100';
}
return [
'name' => $nameRule,
];
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace FireflyIII\Http\Requests;
use Auth;
use Input;
/**
* Class BillFormRequest
*
* @package FireflyIII\Http\Requests
*/
class CurrencyFormRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
$rules = [
'code' => 'required|min:3|max:3|unique:transaction_currencies,code',
'name' => 'required|max:48|min:1|unique:transaction_currencies,name',
'symbol' => 'required|min:1|max:8|unique:transaction_currencies,symbol',
];
if (intval(Input::get('id')) > 0) {
$rules = [
'code' => 'required|min:3|max:3',
'name' => 'required|max:48|min:1',
'symbol' => 'required|min:1|max:8',
];
}
return $rules;
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace FireflyIII\Http\Requests;
use Auth;
use FireflyIII\Models\Account;
use Input;
/**
* Class JournalFormRequest
*
* @package FireflyIII\Http\Requests
*/
class JournalFormRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
// can we switch on the "what"?
$what = Input::get('what');
$rules = [
'description' => 'required|min:1,max:255',
'what' => 'required|in:withdrawal,deposit,transfer|exists:transaction_types,type',
'amount' => 'numeric|required|min:0.01',
'date' => 'required|date',
'reminder_id' => 'numeric|exists:reminders,id',
'amount_currency_id' => 'required|exists:transaction_currencies,id',
];
switch ($what) {
case 'withdrawal':
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
$rules['expense_account'] = 'between:1,255';
$rules['category'] = 'between:1,255';
if (intval(Input::get('budget_id')) != 0) {
$rules['budget_id'] = 'exists:budgets,id|belongsToUser:budgets';
}
break;
case 'deposit':
$rules['category'] = 'between:1,255';
$rules['account_id'] = 'required|exists:accounts,id|belongsToUser:accounts';
$rules['revenue_account'] = 'between:1,255';
break;
case 'transfer':
$rules['account_from_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_to_id';
$rules['account_to_id'] = 'required|exists:accounts,id|belongsToUser:accounts|different:account_from_id';
$rules['category'] = 'between:1,255';
break;
default:
die('Cannot handle ' . $what);
break;
}
return $rules;
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace FireflyIII\Http\Requests;
use Auth;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use Input;
use Navigation;
/**
* Class PiggyBankFormRequest
*
* @package FireflyIII\Http\Requests
*/
class PiggyBankFormRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
$nameRule = 'required|between:1,255|uniqueForUser:piggy_banks,name';
$targetDateRule = 'date';
if (intval(Input::get('id'))) {
$nameRule = 'required|between:1,255';
}
if (intval(Input::get('repeats')) == 1) {
$targetDateRule = 'required|date|after:' . date('Y-m-d');
// switch on rep_every, make sure it's not too far away.
if (!is_null(Input::get('rep_length'))) {
$end = Navigation::addPeriod(new Carbon, Input::get('rep_length'), 0);
$targetDateRule .= '|before:' . $end->format('Y-m-d');
}
}
$rules = [
'repeats' => 'required|boolean',
'name' => $nameRule,
'account_id' => 'required|belongsToUser:accounts',
'targetamount' => 'required|min:0.01',
'amount_currency_id' => 'exists:transaction_currencies,id',
'startdate' => 'date',
'targetdate' => $targetDateRule,
'rep_length' => 'in:day,week,quarter,month,year',
'rep_every' => 'integer|min:0|max:31',
'rep_times' => 'integer|min:0|max:99',
'reminder' => 'in:day,week,quarter,month,year',
'reminder_skip' => 'integer|min:0|max:99',
'remind_me' => 'boolean|piggyBankReminder',
'order' => 'integer|min:1',
];
return $rules;
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace FireflyIII\Http\Requests;
use Auth;
use FireflyIII\Models\Account;
/**
* Class ProfileFormRequest
*
* @package FireflyIII\Http\Requests
*/
class ProfileFormRequest extends Request
{
/**
* @return bool
*/
public function authorize()
{
// Only allow logged in users
return Auth::check();
}
/**
* @return array
*/
public function rules()
{
return [
'current_password' => 'required',
'new_password' => 'required|confirmed',
'new_password_confirmation' => 'required',
];
}
}

View File

@@ -0,0 +1,15 @@
<?php namespace FireflyIII\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
/**
* Class Request
*
* @package FireflyIII\Http\Requests
*/
abstract class Request extends FormRequest
{
//
}

View File

@@ -1,7 +1,15 @@
<?php
use Carbon\Carbon;
use DaveJamesMiller\Breadcrumbs\Generator;
use FireflyIII\Exception\FireflyException;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Category;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank;
/*
* Back home.
@@ -22,7 +30,7 @@ Breadcrumbs::register(
}
);
Breadcrumbs::register(
'accounts.show', function (Generator $breadcrumbs, \Account $account) {
'accounts.show', function (Generator $breadcrumbs, Account $account) {
switch ($account->accountType->type) {
default:
throw new FireflyException('Cannot handle account type "' . e($account->accountType->type) . '"');
@@ -47,14 +55,14 @@ Breadcrumbs::register(
}
);
Breadcrumbs::register(
'accounts.delete', function (Generator $breadcrumbs, \Account $account) {
'accounts.delete', function (Generator $breadcrumbs, Account $account) {
$breadcrumbs->parent('accounts.show', $account);
$breadcrumbs->push('Delete ' . e($account->name), route('accounts.delete', $account->id));
}
);
Breadcrumbs::register(
'accounts.edit', function (Generator $breadcrumbs, \Account $account) {
'accounts.edit', function (Generator $breadcrumbs, Account $account) {
$breadcrumbs->parent('accounts.show', $account);
$breadcrumbs->push('Edit ' . e($account->name), route('accounts.edit', $account->id));
}
@@ -91,9 +99,9 @@ Breadcrumbs::register(
'budgets.show', function (Generator $breadcrumbs, Budget $budget, LimitRepetition $repetition = null) {
$breadcrumbs->parent('budgets.index');
$breadcrumbs->push(e($budget->name), route('budgets.show', $budget->id));
if (!is_null($repetition)) {
if (!is_null($repetition) && !is_null($repetition->id)) {
$breadcrumbs->push(
DateKit::periodShow($repetition->startdate, $repetition->budgetlimit->repeat_freq), route('budgets.show', $budget->id, $repetition->id)
Navigation::periodShow($repetition->startdate, $repetition->budgetlimit->repeat_freq), route('budgets.show', $budget->id, $repetition->id)
);
}
}
@@ -137,35 +145,35 @@ Breadcrumbs::register(
// piggy banks
Breadcrumbs::register(
'piggyBanks.index', function (Generator $breadcrumbs) {
'piggy-banks.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Piggy banks', route('piggyBanks.index'));
$breadcrumbs->push('Piggy banks', route('piggy-banks.index'));
}
);
Breadcrumbs::register(
'piggyBanks.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('piggyBanks.index');
$breadcrumbs->push('Create new piggy bank', route('piggyBanks.create'));
'piggy-banks.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('piggy-banks.index');
$breadcrumbs->push('Create new piggy bank', route('piggy-banks.create'));
}
);
Breadcrumbs::register(
'piggyBanks.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggyBanks.show', $piggyBank);
$breadcrumbs->push('Edit ' . e($piggyBank->name), route('piggyBanks.edit', $piggyBank->id));
'piggy-banks.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.show', $piggyBank);
$breadcrumbs->push('Edit ' . e($piggyBank->name), route('piggy-banks.edit', $piggyBank->id));
}
);
Breadcrumbs::register(
'piggyBanks.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggyBanks.show', $piggyBank);
$breadcrumbs->push('Delete ' . e($piggyBank->name), route('piggyBanks.delete', $piggyBank->id));
'piggy-banks.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.show', $piggyBank);
$breadcrumbs->push('Delete ' . e($piggyBank->name), route('piggy-banks.delete', $piggyBank->id));
}
);
Breadcrumbs::register(
'piggyBanks.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggyBanks.index');
$breadcrumbs->push(e($piggyBank->name), route('piggyBanks.show', $piggyBank->id));
'piggy-banks.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggy-banks.index');
$breadcrumbs->push(e($piggyBank->name), route('piggy-banks.show', $piggyBank->id));
}
);
@@ -232,8 +240,17 @@ Breadcrumbs::register(
// reminders
Breadcrumbs::register(
'reminders.show', function (Generator $breadcrumbs, Reminder $reminder) {
'reminders.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Reminders', route('reminders.index'));
}
);
// reminders
Breadcrumbs::register(
'reminders.show', function (Generator $breadcrumbs, Reminder $reminder) {
$breadcrumbs->parent('reminders.index');
$breadcrumbs->push('Reminder #' . $reminder->id, route('reminders.show', $reminder->id));
}
@@ -342,7 +359,7 @@ Breadcrumbs::register(
Breadcrumbs::register(
'transactions.create', function (Generator $breadcrumbs, $what) {
$breadcrumbs->parent('transactions.index', $what);
$breadcrumbs->push('Create new ' .e($what), route('transactions.create', $what));
$breadcrumbs->push('Create new ' . e($what), route('transactions.create', $what));
}
);

View File

@@ -1,12 +1,21 @@
<?php
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Reminder;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
// models
Route::bind(
'account',
function ($value, $route) {
if (Auth::check()) {
$account = Account::
leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
$account = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->where('account_types.editable', 1)
->where('accounts.id', $value)
->where('user_id', Auth::user()->id)
@@ -20,34 +29,13 @@ Route::bind(
);
Route::bind(
'accountname', function ($value, $route) {
'repeatedExpense', function ($value, $route) {
if (Auth::check()) {
return Account::
leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')->where('account_types.editable', 1)->where('name', $value)->where(
'user_id', Auth::user()->id
)->first();
}
return null;
}
);
Route::bind(
'bill', function ($value, $route) {
if (Auth::check()) {
return Bill::
where('id', $value)->where('user_id', Auth::user()->id)->first();
}
return null;
}
);
Route::bind(
'budget', function ($value, $route) {
if (Auth::check()) {
return Budget::
where('id', $value)->where('user_id', Auth::user()->id)->first();
return PiggyBank::
where('piggy_banks.id', $value)
->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')
->where('accounts.user_id', Auth::user()->id)
->where('repeats', 1)->first(['piggy_banks.*']);
}
return null;
@@ -55,31 +43,9 @@ Route::bind(
);
Route::bind(
'component', function ($value, $route) {
'tjSecond', function ($value, $route) {
if (Auth::check()) {
return Component::
where('id', $value)->where('user_id', Auth::user()->id)->first();
}
return null;
}
);
Route::bind(
'reminder', function ($value, $route) {
if (Auth::check()) {
return Reminder::
where('id', $value)->where('user_id', Auth::user()->id)->first();
}
return null;
}
);
Route::bind(
'category', function ($value, $route) {
if (Auth::check()) {
return Category::
return TransactionJournal::
where('id', $value)->where('user_id', Auth::user()->id)->first();
}
@@ -97,11 +63,17 @@ Route::bind(
return null;
}
);
Route::bind(
'tjSecond', function ($value, $route) {
'currency', function ($value, $route) {
return TransactionCurrency::find($value);
}
);
Route::bind(
'bill', function ($value, $route) {
if (Auth::check()) {
return TransactionJournal::
where('id', $value)->where('user_id', Auth::user()->id)->first();
return Bill::where('id', $value)->where('user_id', Auth::user()->id)->first();
}
return null;
@@ -109,8 +81,22 @@ Route::bind(
);
Route::bind(
'currency', function ($value, $route) {
return TransactionCurrency::find($value);
'budget', function ($value, $route) {
if (Auth::check()) {
return Budget::where('id', $value)->where('user_id', Auth::user()->id)->first();
}
return null;
}
);
Route::bind(
'reminder', function ($value, $route) {
if (Auth::check()) {
return Reminder::where('id', $value)->where('user_id', Auth::user()->id)->first();
}
return null;
}
);
@@ -143,132 +129,54 @@ Route::bind(
);
Route::bind(
'repeatedExpense', function ($value, $route) {
'category', function ($value, $route) {
if (Auth::check()) {
return PiggyBank::
where('piggy_banks.id', $value)
->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')
->where('accounts.user_id', Auth::user()->id)
->where('repeats', 1)->first(['piggy_banks.*']);
return Category::where('id', $value)->where('user_id', Auth::user()->id)->first();
}
return null;
}
);
Route::bind(
'repeated', function ($value, $route) {
if (Auth::check()) {
return PiggyBank::
where('piggy_banks.id', $value)
->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')
->where('accounts.user_id', Auth::user()->id)
->where('repeats', 1)->first(['piggy_banks.*']);
}
return null;
}
/**
* Auth\AuthController
*/
Route::get('/register', ['uses' => 'Auth\AuthController@getRegister', 'as' => 'register']);
Route::controllers(
[
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]
);
// protected routes:
/**
* Home Controller
*/
Route::group(
['before' => 'auth'], function () {
// some date routes used for (well duh) date-based navigation.
Route::get('/prev', ['uses' => 'HomeController@sessionPrev', 'as' => 'sessionPrev']);
Route::get('/next', ['uses' => 'HomeController@sessionNext', 'as' => 'sessionNext']);
Route::get('/jump/{range}', ['uses' => 'HomeController@rangeJump', 'as' => 'rangeJump']);
// account controller:
['middleware' => ['auth', 'range', 'reminders','piggybanks']], function () {
Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']);
Route::get('/home', ['uses' => 'HomeController@index', 'as' => 'home']);
Route::post('/daterange', ['uses' => 'HomeController@dateRange', 'as' => 'daterange']);
Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']);
/**
* Account Controller
*/
Route::get('/accounts/{what}', ['uses' => 'AccountController@index', 'as' => 'accounts.index'])->where('what', 'revenue|asset|expense');
Route::get('/accounts/create/{what}', ['uses' => 'AccountController@create', 'as' => 'accounts.create'])->where('what', 'revenue|asset|expense');
Route::get('/accounts/edit/{account}', ['uses' => 'AccountController@edit', 'as' => 'accounts.edit']);
Route::get('/accounts/delete/{account}', ['uses' => 'AccountController@delete', 'as' => 'accounts.delete']);
Route::get('/accounts/show/{account}/{view?}', ['uses' => 'AccountController@show', 'as' => 'accounts.show']);
Route::post('/accounts/store', ['uses' => 'AccountController@store', 'as' => 'accounts.store']);
Route::post('/accounts/update/{account}', ['uses' => 'AccountController@update', 'as' => 'accounts.update']);
Route::post('/accounts/destroy/{account}', ['uses' => 'AccountController@destroy', 'as' => 'accounts.destroy']);
// budget controller:
Route::get('/budgets', ['uses' => 'BudgetController@index', 'as' => 'budgets.index']);
Route::get('/budgets/income', ['uses' => 'BudgetController@updateIncome', 'as' => 'budgets.income']); # extra.
Route::get('/budgets/create', ['uses' => 'BudgetController@create', 'as' => 'budgets.create']);
Route::get('/budgets/edit/{budget}', ['uses' => 'BudgetController@edit', 'as' => 'budgets.edit']);
Route::get('/budgets/delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'budgets.delete']);
Route::get('/budgets/show/{budget}/{limitrepetition?}', ['uses' => 'BudgetController@show', 'as' => 'budgets.show']);
Route::get('/budgets/list/noBudget', ['uses' => 'BudgetController@noBudget', 'as' => 'budgets.noBudget']);
// category controller:
Route::get('/categories', ['uses' => 'CategoryController@index', 'as' => 'categories.index']);
Route::get('/categories/create', ['uses' => 'CategoryController@create', 'as' => 'categories.create']);
Route::get('/categories/edit/{category}', ['uses' => 'CategoryController@edit', 'as' => 'categories.edit']);
Route::get('/categories/delete/{category}', ['uses' => 'CategoryController@delete', 'as' => 'categories.delete']);
Route::get('/categories/show/{category}', ['uses' => 'CategoryController@show', 'as' => 'categories.show']);
Route::get('/categories/list/noCategory', ['uses' => 'CategoryController@noCategory', 'as' => 'categories.noCategory']);
// currency controller
Route::get('/currency', ['uses' => 'CurrencyController@index', 'as' => 'currency.index']);
Route::get('/currency/create', ['uses' => 'CurrencyController@create', 'as' => 'currency.create']);
Route::get('/currency/edit/{currency}', ['uses' => 'CurrencyController@edit', 'as' => 'currency.edit']);
Route::get('/currency/delete/{currency}', ['uses' => 'CurrencyController@delete', 'as' => 'currency.delete']);
Route::get('/currency/default/{currency}', ['uses' => 'CurrencyController@defaultCurrency', 'as' => 'currency.default']);
// google chart controller
Route::get('/chart/home/account', ['uses' => 'GoogleChartController@allAccountsBalanceChart']);
Route::get('/chart/home/budgets', ['uses' => 'GoogleChartController@allBudgetsHomeChart']);
Route::get('/chart/home/categories', ['uses' => 'GoogleChartController@allCategoriesHomeChart']);
Route::get('/chart/home/bills', ['uses' => 'GoogleChartController@billsOverview']);
Route::get('/chart/account/{account}/{view?}', ['uses' => 'GoogleChartController@accountBalanceChart']);
Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']);
Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']);
Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']);
Route::get('/chart/piggy_history/{piggyBank}', ['uses' => 'GoogleChartController@piggyBankHistory']);
// google chart for components (categories + budgets combined)
Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']);
Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending']);
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']);
Route::get('/chart/category/{category}/spending/{year}', ['uses' => 'GoogleChartController@categoriesAndSpending']);
// help controller
Route::get('/help/{route}', ['uses' => 'HelpController@show', 'as' => 'help.show']);
// home controller
Route::get('/', ['uses' => 'HomeController@index', 'as' => 'index']);
Route::get('/flush', ['uses' => 'HomeController@flush', 'as' => 'flush']); # even though nothing is cached.
// JSON controller
Route::get('/json/expense-accounts', ['uses' => 'JsonController@expenseAccounts', 'as' => 'json.expense-accounts']);
Route::get('/json/revenue-accounts', ['uses' => 'JsonController@revenueAccounts', 'as' => 'json.revenue-accounts']);
Route::get('/json/categories', ['uses' => 'JsonController@categories', 'as' => 'json.categories']);
// piggy bank controller
Route::get('/piggy_banks', ['uses' => 'PiggyBankController@index', 'as' => 'piggy_banks.index']);
Route::get('/piggy_banks/add/{piggyBank}', ['uses' => 'PiggyBankController@add']); # add money
Route::get('/piggy_banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove']); #remove money
Route::get('/piggy_banks/create', ['uses' => 'PiggyBankController@create', 'as' => 'piggy_banks.create']);
Route::get('/piggy_banks/edit/{piggyBank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy_banks.edit']);
Route::get('/piggy_banks/delete/{piggyBank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy_banks.delete']);
Route::get('/piggy_banks/show/{piggyBank}', ['uses' => 'PiggyBankController@show', 'as' => 'piggy_banks.show']);
// preferences controller
Route::get('/preferences', ['uses' => 'PreferencesController@index', 'as' => 'preferences']);
//profile controller
Route::get('/profile', ['uses' => 'ProfileController@index', 'as' => 'profile']);
Route::get('/profile/change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']);
// related controller:
Route::get('/related/alreadyRelated/{tj}', ['uses' => 'RelatedController@alreadyRelated', 'as' => 'related.alreadyRelated']);
Route::post('/related/relate/{tj}/{tjSecond}', ['uses' => 'RelatedController@relate', 'as' => 'related.relate']);
Route::get('/related/removeRelation/{tj}/{tjSecond}', ['uses' => 'RelatedController@removeRelation', 'as' => 'related.removeRelation']);
Route::get('/related/related/{tj}', ['uses' => 'RelatedController@related', 'as' => 'related.related']);
Route::post('/related/search/{tj}', ['uses' => 'RelatedController@search', 'as' => 'related.search']);
// bills controller
/**
* Bills Controller
*/
Route::get('/bills', ['uses' => 'BillController@index', 'as' => 'bills.index']);
Route::get('/bills/rescan/{bill}', ['uses' => 'BillController@rescan', 'as' => 'bills.rescan']); # rescan for matching.
Route::get('/bills/create', ['uses' => 'BillController@create', 'as' => 'bills.create']);
@@ -276,29 +184,173 @@ Route::group(
Route::get('/bills/delete/{bill}', ['uses' => 'BillController@delete', 'as' => 'bills.delete']);
Route::get('/bills/show/{bill}', ['uses' => 'BillController@show', 'as' => 'bills.show']);
// repeated expenses controller:
Route::get('/repeatedexpenses', ['uses' => 'RepeatedExpenseController@index', 'as' => 'repeated.index']);
Route::get('/repeatedexpenses/create', ['uses' => 'RepeatedExpenseController@create', 'as' => 'repeated.create']);
Route::get('/repeatedexpenses/edit/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@edit', 'as' => 'repeated.edit']);
Route::get('/repeatedexpenses/delete/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@delete', 'as' => 'repeated.delete']);
Route::get('/repeatedexpenses/show/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@show', 'as' => 'repeated.show']);
Route::post('/bills/store', ['uses' => 'BillController@store', 'as' => 'bills.store']);
Route::post('/bills/update/{bill}', ['uses' => 'BillController@update', 'as' => 'bills.update']);
Route::post('/bills/destroy/{bill}', ['uses' => 'BillController@destroy', 'as' => 'bills.destroy']);
// report controller:
/**
* Budget Controller
*/
Route::get('/budgets', ['uses' => 'BudgetController@index', 'as' => 'budgets.index']);
Route::get('/budgets/income', ['uses' => 'BudgetController@updateIncome', 'as' => 'budgets.income']); # extra.
Route::get('/budgets/create', ['uses' => 'BudgetController@create', 'as' => 'budgets.create']);
Route::get('/budgets/edit/{budget}', ['uses' => 'BudgetController@edit', 'as' => 'budgets.edit']);
Route::get('/budgets/delete/{budget}', ['uses' => 'BudgetController@delete', 'as' => 'budgets.delete']);
Route::get('/budgets/show/{budget}/{limitrepetition?}', ['uses' => 'BudgetController@show', 'as' => 'budgets.show']);
Route::get('/budgets/list/noBudget', ['uses' => 'BudgetController@noBudget', 'as' => 'budgets.noBudget']);
Route::post('/budgets/income', ['uses' => 'BudgetController@postUpdateIncome', 'as' => 'budgets.postIncome']);
Route::post('/budgets/store', ['uses' => 'BudgetController@store', 'as' => 'budgets.store']);
Route::post('/budgets/update/{budget}', ['uses' => 'BudgetController@update', 'as' => 'budgets.update']);
Route::post('/budgets/destroy/{budget}', ['uses' => 'BudgetController@destroy', 'as' => 'budgets.destroy']);
Route::post('budgets/amount/{budget}', ['uses' => 'BudgetController@amount']);
/**
* Category Controller
*/
Route::get('/categories', ['uses' => 'CategoryController@index', 'as' => 'categories.index']);
Route::get('/categories/create', ['uses' => 'CategoryController@create', 'as' => 'categories.create']);
Route::get('/categories/edit/{category}', ['uses' => 'CategoryController@edit', 'as' => 'categories.edit']);
Route::get('/categories/delete/{category}', ['uses' => 'CategoryController@delete', 'as' => 'categories.delete']);
Route::get('/categories/show/{category}', ['uses' => 'CategoryController@show', 'as' => 'categories.show']);
Route::get('/categories/list/noCategory', ['uses' => 'CategoryController@noCategory', 'as' => 'categories.noCategory']);
Route::post('/categories/store', ['uses' => 'CategoryController@store', 'as' => 'categories.store']);
Route::post('/categories/update/{category}', ['uses' => 'CategoryController@update', 'as' => 'categories.update']);
Route::post('/categories/destroy/{category}', ['uses' => 'CategoryController@destroy', 'as' => 'categories.destroy']);
/**
* Currency Controller
*/
Route::get('/currency', ['uses' => 'CurrencyController@index', 'as' => 'currency.index']);
Route::get('/currency/create', ['uses' => 'CurrencyController@create', 'as' => 'currency.create']);
Route::get('/currency/edit/{currency}', ['uses' => 'CurrencyController@edit', 'as' => 'currency.edit']);
Route::get('/currency/delete/{currency}', ['uses' => 'CurrencyController@delete', 'as' => 'currency.delete']);
Route::get('/currency/default/{currency}', ['uses' => 'CurrencyController@defaultCurrency', 'as' => 'currency.default']);
Route::post('/currency/store', ['uses' => 'CurrencyController@store', 'as' => 'currency.store']);
Route::post('/currency/update/{currency}', ['uses' => 'CurrencyController@update', 'as' => 'currency.update']);
Route::post('/currency/destroy/{currency}', ['uses' => 'CurrencyController@destroy', 'as' => 'currency.destroy']);
/**
* Google Chart Controller
*/
Route::get('/chart/home/account', ['uses' => 'GoogleChartController@allAccountsBalanceChart']);
Route::get('/chart/home/budgets', ['uses' => 'GoogleChartController@allBudgetsHomeChart']);
Route::get('/chart/home/categories', ['uses' => 'GoogleChartController@allCategoriesHomeChart']);
Route::get('/chart/home/bills', ['uses' => 'GoogleChartController@billsOverview']);
Route::get('/chart/account/{account}/{view?}', ['uses' => 'GoogleChartController@accountBalanceChart']);
Route::get('/chart/budget/{budget}/spending/{year?}', ['uses' => 'GoogleChartController@budgetsAndSpending']);
Route::get('/chart/budgets/spending/{year?}', ['uses' => 'GoogleChartController@allBudgetsAndSpending']);
Route::get('/chart/budget/{budget}/{limitrepetition}', ['uses' => 'GoogleChartController@budgetLimitSpending']);
Route::get('/chart/reports/income-expenses/{year}', ['uses' => 'GoogleChartController@yearInExp']);
Route::get('/chart/reports/income-expenses-sum/{year}', ['uses' => 'GoogleChartController@yearInExpSum']);
Route::get('/chart/bills/{bill}', ['uses' => 'GoogleChartController@billOverview']);
Route::get('/chart/piggy-history/{piggyBank}', ['uses' => 'GoogleChartController@piggyBankHistory']);
Route::get('/chart/category/{category}/period', ['uses' => 'GoogleChartController@categoryPeriodChart']);
Route::get('/chart/category/{category}/overview', ['uses' => 'GoogleChartController@categoryOverviewChart']);
/**
* Help Controller
*/
Route::get('/help/{route}', ['uses' => 'HelpController@show', 'as' => 'help.show']);
/**
* JSON Controller
*/
Route::get('/json/expense-accounts', ['uses' => 'JsonController@expenseAccounts', 'as' => 'json.expense-accounts']);
Route::get('/json/revenue-accounts', ['uses' => 'JsonController@revenueAccounts', 'as' => 'json.revenue-accounts']);
Route::get('/json/categories', ['uses' => 'JsonController@categories', 'as' => 'json.categories']);
Route::get('/json/box', ['uses' => 'JsonController@box', 'as' => 'json.box']);
Route::get('/json/show-shared-reports', 'JsonController@showSharedReports');
Route::get('/json/show-shared-reports/set', 'JsonController@setSharedReports');
/**
* Piggy Bank Controller
*/
Route::get('/piggy-banks', ['uses' => 'PiggyBankController@index', 'as' => 'piggy-banks.index']);
Route::get('/piggy-banks/add/{piggyBank}', ['uses' => 'PiggyBankController@add', 'as' => 'piggy-banks.addMoney']); # add money
Route::get('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@remove', 'as' => 'piggy-banks.removeMoney']); #remove money
Route::get('/piggy-banks/create', ['uses' => 'PiggyBankController@create', 'as' => 'piggy-banks.create']);
Route::get('/piggy-banks/edit/{piggyBank}', ['uses' => 'PiggyBankController@edit', 'as' => 'piggy-banks.edit']);
Route::get('/piggy-banks/delete/{piggyBank}', ['uses' => 'PiggyBankController@delete', 'as' => 'piggy-banks.delete']);
Route::get('/piggy-banks/show/{piggyBank}', ['uses' => 'PiggyBankController@show', 'as' => 'piggy-banks.show']);
Route::post('/piggy-banks/store', ['uses' => 'PiggyBankController@store', 'as' => 'piggy-banks.store']);
Route::post('/piggy-banks/update/{piggyBank}', ['uses' => 'PiggyBankController@update', 'as' => 'piggy-banks.update']);
Route::post('/piggy-banks/destroy/{piggyBank}', ['uses' => 'PiggyBankController@destroy', 'as' => 'piggy-banks.destroy']);
Route::post('/piggy-banks/add/{piggyBank}', ['uses' => 'PiggyBankController@postAdd', 'as' => 'piggy-banks.add']); # add money
Route::post('/piggy-banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@postRemove', 'as' => 'piggy-banks.remove']); # remove money.
Route::post('/piggy-banks/sort', ['uses' => 'PiggyBankController@order', 'as' => 'piggy-banks.order']);
/**
* Preferences Controller
*/
Route::get('/preferences', ['uses' => 'PreferencesController@index', 'as' => 'preferences']);
Route::post('/preferences', ['uses' => 'PreferencesController@postIndex']);
/**
* Profile Controller
*/
Route::get('/profile', ['uses' => 'ProfileController@index', 'as' => 'profile']);
Route::get('/profile/change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']);
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword', 'as' => 'change-password-post']);
/**
* Related transactions controller
*/
Route::get('/related/alreadyRelated/{tj}', ['uses' => 'RelatedController@alreadyRelated', 'as' => 'related.alreadyRelated']);
Route::post('/related/relate/{tj}/{tjSecond}', ['uses' => 'RelatedController@relate', 'as' => 'related.relate']);
Route::post('/related/removeRelation/{tj}/{tjSecond}', ['uses' => 'RelatedController@removeRelation', 'as' => 'related.removeRelation']);
Route::get('/related/remove/{tj}/{tjSecond}', ['uses' => 'RelatedController@getRemoveRelation', 'as' => 'related.getRemoveRelation']);
Route::get('/related/related/{tj}', ['uses' => 'RelatedController@related', 'as' => 'related.related']);
Route::post('/related/search/{tj}', ['uses' => 'RelatedController@search', 'as' => 'related.search']);
/**
* Reminder Controller
*/
Route::get('/reminders', ['uses' => 'ReminderController@index', 'as' => 'reminders.index']);
Route::get('/reminder/dismiss/{reminder}', ['uses' => 'ReminderController@dismiss', 'as' => 'reminders.dismiss']);
Route::get('/reminder/act/{reminder}', ['uses' => 'ReminderController@act', 'as' => 'reminders.act']);
Route::get('/reminder/{reminder}', ['uses' => 'ReminderController@show', 'as' => 'reminders.show']);
/**
* Repeated Expenses Controller
*/
Route::get('/repeated-expenses', ['uses' => 'RepeatedExpenseController@index', 'as' => 'repeated.index']);
Route::get('/repeated-expenses/create', ['uses' => 'RepeatedExpenseController@create', 'as' => 'repeated.create']);
Route::get('/repeated-expenses/edit/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@edit', 'as' => 'repeated.edit']);
Route::get('/repeated-expenses/delete/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@delete', 'as' => 'repeated.delete']);
Route::get('/repeated-expenses/show/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@show', 'as' => 'repeated.show']);
Route::post('/repeated-expense/store', ['uses' => 'RepeatedExpenseController@store', 'as' => 'repeated.store']);
Route::post('/repeated-expense/update/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@update', 'as' => 'repeated.update']);
Route::post('/repeated-expense/destroy/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@destroy', 'as' => 'repeated.destroy']);
/**
* Report Controller
*/
Route::get('/reports', ['uses' => 'ReportController@index', 'as' => 'reports.index']);
Route::get('/reports/{year}', ['uses' => 'ReportController@year', 'as' => 'reports.year']);
Route::get('/reports/{year}/{month}', ['uses' => 'ReportController@month', 'as' => 'reports.month']);
Route::get('/reports/budget/{year}/{month}', ['uses' => 'ReportController@budget', 'as' => 'reports.budget']);
// reminder controller
Route::get('/reminders/{reminder}', ['uses' => 'ReminderController@show', 'as' => 'reminders.show']);
Route::get('/reminders/{reminder}/dismiss', ['uses' => 'ReminderController@dismiss', 'as' => 'reminders.dismiss']);
Route::get('/reminders/{reminder}/notNow', ['uses' => 'ReminderController@notNow', 'as' => 'reminders.notNow']);
Route::get('/reminders/{reminder}/act', ['uses' => 'ReminderController@act', 'as' => 'reminders.act']);
// pop ups for budget report:
Route::get('/reports/modal/{account}/{year}/{month}/no-budget', ['uses' => 'ReportController@modalNoBudget', 'as' => 'reports.no-budget']);
Route::get(
'/reports/modal/{account}/{year}/{month}/balanced-transfers',
['uses' => 'ReportController@modalBalancedTransfers', 'as' => 'reports.balanced-transfers']
);
Route::get(
'/reports/modal/{account}/{year}/{month}/left-unbalanced', ['uses' => 'ReportController@modalLeftUnbalanced', 'as' => 'reports.left-unbalanced']
);
// search controller:
/**
* Search Controller
*/
Route::get('/search', ['uses' => 'SearchController@index', 'as' => 'search']);
// transaction controller:
/**
* Transaction Controller
*/
Route::get('/transactions/{what}', ['uses' => 'TransactionController@index', 'as' => 'transactions.index'])->where(
['what' => 'expenses|revenue|withdrawal|deposit|transfer|transfers']
);
@@ -308,101 +360,20 @@ Route::group(
Route::get('/transaction/edit/{tj}', ['uses' => 'TransactionController@edit', 'as' => 'transactions.edit']);
Route::get('/transaction/delete/{tj}', ['uses' => 'TransactionController@delete', 'as' => 'transactions.delete']);
Route::get('/transaction/show/{tj}', ['uses' => 'TransactionController@show', 'as' => 'transactions.show']);
Route::get('/transaction/relate/{tj}', ['uses' => 'TransactionController@relate', 'as' => 'transactions.relate']);
Route::post('/transactions/relatedSearch/{tj}', ['uses' => 'TransactionController@relatedSearch', 'as' => 'transactions.relatedSearch']);
Route::post('/transactions/alreadyRelated/{tj}', ['uses' => 'TransactionController@alreadyRelated', 'as' => 'transactions.alreadyRelated']);
Route::post('/transactions/doRelate', ['uses' => 'TransactionController@doRelate', 'as' => 'transactions.doRelate']);
Route::any('/transactions/unrelate/{tj}', ['uses' => 'TransactionController@unrelate', 'as' => 'transactions.unrelate']);
// user controller
Route::get('/logout', ['uses' => 'UserController@logout', 'as' => 'logout']);
Route::post('budgets/amount/{budget}', ['uses' => 'BudgetController@amount']);
}
);
// protected + csrf routes (POST)
Route::group(
['before' => 'csrf|auth'], function () {
// account controller:
Route::post('/accounts/store', ['uses' => 'AccountController@store', 'as' => 'accounts.store']);
Route::post('/accounts/update/{account}', ['uses' => 'AccountController@update', 'as' => 'accounts.update']);
Route::post('/accounts/destroy/{account}', ['uses' => 'AccountController@destroy', 'as' => 'accounts.destroy']);
// budget controller:
Route::post('/budgets/income', ['uses' => 'BudgetController@postUpdateIncome', 'as' => 'budgets.postIncome']);
Route::post('/budgets/store', ['uses' => 'BudgetController@store', 'as' => 'budgets.store']);
Route::post('/budgets/update/{budget}', ['uses' => 'BudgetController@update', 'as' => 'budgets.update']);
Route::post('/budgets/destroy/{budget}', ['uses' => 'BudgetController@destroy', 'as' => 'budgets.destroy']);
// category controller
Route::post('/categories/store', ['uses' => 'CategoryController@store', 'as' => 'categories.store']);
Route::post('/categories/update/{category}', ['uses' => 'CategoryController@update', 'as' => 'categories.update']);
Route::post('/categories/destroy/{category}', ['uses' => 'CategoryController@destroy', 'as' => 'categories.destroy']);
// currency controller
Route::post('/currency/store', ['uses' => 'CurrencyController@store', 'as' => 'currency.store']);
Route::post('/currency/update/{currency}', ['uses' => 'CurrencyController@update', 'as' => 'currency.update']);
Route::post('/currency/destroy/{currency}', ['uses' => 'CurrencyController@destroy', 'as' => 'currency.destroy']);
// piggy bank controller
Route::post('/piggy_banks/store', ['uses' => 'PiggyBankController@store', 'as' => 'piggy_banks.store']);
Route::post('/piggy_banks/update/{piggyBank}', ['uses' => 'PiggyBankController@update', 'as' => 'piggy_banks.update']);
Route::post('/piggy_banks/destroy/{piggyBank}', ['uses' => 'PiggyBankController@destroy', 'as' => 'piggy_banks.destroy']);
Route::post('/piggy_banks/add/{piggyBank}', ['uses' => 'PiggyBankController@postAdd', 'as' => 'piggy_banks.add']); # add money
Route::post('/piggy_banks/remove/{piggyBank}', ['uses' => 'PiggyBankController@postRemove', 'as' => 'piggy_banks.remove']); # remove money.
// repeated expense controller
Route::post('/repeatedexpense/store', ['uses' => 'RepeatedExpenseController@store', 'as' => 'repeated.store']);
Route::post('/repeatedexpense/update/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@update', 'as' => 'repeated.update']);
Route::post('/repeatedexpense/destroy/{repeatedExpense}', ['uses' => 'RepeatedExpenseController@destroy', 'as' => 'repeated.destroy']);
// preferences controller
Route::post('/preferences', ['uses' => 'PreferencesController@postIndex']);
// profile controller
Route::post('/profile/change-password', ['uses' => 'ProfileController@postChangePassword']);
// bills controller
Route::post('/bills/store', ['uses' => 'BillController@store', 'as' => 'bills.store']);
Route::post('/bills/update/{bill}', ['uses' => 'BillController@update', 'as' => 'bills.update']);
Route::post('/bills/destroy/{bill}', ['uses' => 'BillController@destroy', 'as' => 'bills.destroy']);
// transaction controller:
Route::post('/transactions/store/{what}', ['uses' => 'TransactionController@store', 'as' => 'transactions.store'])->where(
['what' => 'expenses|revenue|withdrawal|deposit|transfer|transfers']
);
Route::post('/transaction/update/{tj}', ['uses' => 'TransactionController@update', 'as' => 'transactions.update']);
Route::post('/transaction/destroy/{tj}', ['uses' => 'TransactionController@destroy', 'as' => 'transactions.destroy']);
Route::post('/transaction/reorder', ['uses' => 'TransactionController@reorder', 'as' => 'transactions.reorder']);
}
);
// guest routes:
Route::group(
['before' => 'guest'], function () {
// user controller
Route::get('/login', ['uses' => 'UserController@login', 'as' => 'login']);
Route::get('/register', ['uses' => 'UserController@register', 'as' => 'register', 'before' => 'allow-register']);
Route::get('/reset/{reset}', ['uses' => 'UserController@reset', 'as' => 'reset']);
Route::get('/remindMe', ['uses' => 'UserController@remindMe', 'as' => 'remindMe']);
Route::get('/oauth2callback', ['uses' => 'HomeController@marauder', 'as' => 'marauder']);
/**
* Auth\Auth Controller
*/
Route::get('/logout', ['uses' => 'Auth\AuthController@getLogout', 'as' => 'logout']);
}
);
// guest + csrf routes:
Route::group(
['before' => 'csrf|guest'], function () {
// user controller
Route::post('/login', ['uses' => 'UserController@postLogin', 'as' => 'login.post']);
Route::post('/register', ['uses' => 'UserController@postRegister', 'as' => 'register.post', 'before' => 'allow-register']);
Route::post('/remindMe', ['uses' => 'UserController@postRemindMe', 'as' => 'remindMe.post']);
}
);

121
app/Models/Account.php Normal file
View File

@@ -0,0 +1,121 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
use Crypt;
/**
* Class Account
*
* @package FireflyIII\Models
*/
class Account extends Model
{
use SoftDeletes, ValidatingTrait;
protected $rules
= [
'user_id' => 'required|exists:users,id',
'account_type_id' => 'required|exists:account_types,id',
'name' => 'required|between:1,1024|uniqueAccountForUser',
'active' => 'required|boolean'
];
protected $fillable = ['user_id', 'account_type_id', 'name', 'active'];
/**
* @param $fieldName
*
* @return string|null
*/
public function getMeta($fieldName)
{
foreach ($this->accountMeta as $meta) {
if ($meta->name == $fieldName) {
return $meta->data;
}
}
return null;
}
/**
* @param $value
*
* @return string
*/
public function getNameAttribute($value)
{
if ($this->encrypted) {
return Crypt::decrypt($value);
}
// @codeCoverageIgnoreStart
return $value;
// @codeCoverageIgnoreEnd
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function accountMeta()
{
return $this->hasMany('FireflyIII\Models\AccountMeta');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function accountType()
{
return $this->belongsTo('FireflyIII\Models\AccountType');
}
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'deleted_at'];
}
/**
* @param EloquentBuilder $query
* @param array $types
*/
public function scopeAccountTypeIn(EloquentBuilder $query, array $types)
{
if (is_null($this->joinedAccountTypes)) {
$query->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id');
$this->joinedAccountTypes = true;
}
$query->whereIn('account_types.type', $types);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function transactions()
{
return $this->hasMany('FireflyIII\Models\Transaction');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('FireflyIII\User');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function piggyBanks()
{
return $this->hasMany('FireflyIII\Models\PiggyBank');
}
}

View File

@@ -1,35 +1,35 @@
<?php
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
use Watson\Validating\ValidatingTrait;
use \Illuminate\Database\Eloquent\Model as Eloquent;
/**
* Class AccountMeta
*
* @package FireflyIII\Models
*/
class AccountMeta extends Eloquent
class AccountMeta extends Model
{
use ValidatingTrait;
/**
* @var array
*/
public static $rules
= [
'account_id' => 'numeric|required|exists:accounts,id',
'name' => 'required|between:1,250',
protected $fillable = ['account_id', 'name', 'data'];
protected $rules
= [
'account_id' => 'required|exists:accounts,id',
'name' => 'required|between:1,100',
'data' => 'required'
];
/**
* @var array
*/
protected $fillable = ['account_id', 'name', 'date'];
protected $table = 'account_meta';
protected $table = 'account_meta';
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function account()
{
return $this->belongsTo('Account');
return $this->belongsTo('FireflyIII\Models\Account');
}
/**
* @param $value
*
@@ -40,6 +40,14 @@ class AccountMeta extends Eloquent
return json_decode($value);
}
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at'];
}
/**
* @param $value
*/
@@ -48,4 +56,4 @@ class AccountMeta extends Eloquent
$this->attributes['data'] = json_encode($value);
}
}
}

View File

@@ -0,0 +1,29 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* Class AccountType
*
* @package FireflyIII\Models
*/
class AccountType extends Model
{
//
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function accounts()
{
return $this->hasMany('FireflyIII\Models\Account');
}
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at'];
}
}

40
app/Models/Bill.php Normal file
View File

@@ -0,0 +1,40 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* Class Bill
*
* @package FireflyIII\Models
*/
class Bill extends Model
{
protected $fillable = ['name', 'match', 'amount_min','user_id', 'amount_max', 'date', 'repeat_freq', 'skip', 'automatch', 'active',];
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'date'];
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function transactionjournals()
{
return $this->hasMany('FireflyIII\Models\TransactionJournal');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('FireflyIII\User');
}
}

59
app/Models/Budget.php Normal file
View File

@@ -0,0 +1,59 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class Budget
*
* @package FireflyIII\Models
*/
class Budget extends Model
{
use SoftDeletes;
protected $fillable = ['user_id', 'name'];
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function budgetlimits()
{
return $this->hasMany('FireflyIII\Models\BudgetLimit');
}
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'deleted_at'];
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
*/
public function limitrepetitions()
{
return $this->hasManyThrough('FireflyIII\Models\LimitRepetition', 'FireflyIII\Models\BudgetLimit', 'budget_id');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function transactionjournals()
{
return $this->belongsToMany('FireflyIII\Models\TransactionJournal', 'budget_transaction_journal', 'budget_id');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('FireflyIII\User');
}
}

View File

@@ -0,0 +1,37 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* Class BudgetLimit
*
* @package FireflyIII\Models
*/
class BudgetLimit extends Model
{
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function budget()
{
return $this->belongsTo('FireflyIII\Models\Budget');
}
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'startdate'];
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function limitrepetitions()
{
return $this->hasMany('FireflyIII\Models\LimitRepetition');
}
}

41
app/Models/Category.php Normal file
View File

@@ -0,0 +1,41 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class Category
*
* @package FireflyIII\Models
*/
class Category extends Model
{
use SoftDeletes;
protected $fillable = ['user_id', 'name'];
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'deleted_at'];
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function transactionjournals()
{
return $this->belongsToMany('FireflyIII\Models\TransactionJournal', 'category_transaction_journal', 'category_id');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('FireflyIII\User');
}
}

24
app/Models/Component.php Normal file
View File

@@ -0,0 +1,24 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class Component
*
* @package FireflyIII\Models
*/
class Component extends Model
{
use SoftDeletes;
protected $fillable = ['user_id', 'name','class'];
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'deleted_at'];
}
}

View File

@@ -0,0 +1,45 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* Class LimitRepetition
*
* @package FireflyIII\Models
*/
class LimitRepetition extends Model
{
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function budgetLimit()
{
return $this->belongsTo('FireflyIII\Models\BudgetLimit');
}
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'startdate', 'enddate'];
}
public function spentInRepetition()
{
$sum = \DB::table('transactions')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('budget_limits', 'budget_limits.budget_id', '=', 'budget_transaction_journal.budget_id')
->leftJoin('limit_repetitions', 'limit_repetitions.budget_limit_id', '=', 'budget_limits.id')
->where('transaction_journals.date', '>=', $this->startdate->format('Y-m-d'))
->where('transaction_journals.date', '<=', $this->enddate->format('Y-m-d'))
->where('transactions.amount', '>', 0)
->where('limit_repetitions.id', '=', $this->id)
->sum('transactions.amount');
return floatval($sum);
}
}

View File

@@ -1,59 +1,48 @@
<?php
<?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Database\Eloquent\SoftDeletingTrait;
use Watson\Validating\ValidatingTrait;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class PiggyBank
*
* @package FireflyIII\Models
*/
class PiggyBank extends Eloquent
class PiggyBank extends Model
{
use ValidatingTrait, SoftDeletingTrait;
public $fillable
= ['account_id', 'name', 'targetamount', 'startdate', 'targetdate', 'repeats', 'rep_length', 'rep_every', 'rep_times', 'reminder', 'reminder_skip',
'remind_me', 'order'];
protected $rules
= ['account_id' => 'required|exists:accounts,id', // link to Account
'name' => 'required|between:1,255', // name
'targetamount' => 'required|min:0.01|numeric', // amount you want to save
'startdate' => 'date', // when you started
'targetdate' => 'date', // when its due
'repeats' => 'required|boolean', // does it repeat?
'rep_length' => 'in:day,week,month,quarter,year', // how long is the period?
'rep_every' => 'required|min:1|max:100', // how often does it repeat? every 3 years.
'rep_times' => 'min:1|max:100', // how many times do you want to save this amount? eg. 3 times
'reminder' => 'in:day,week,quarter,month,year', // want a reminder to put money in this?
'reminder_skip' => 'required|min:0|max:100', // every week? every 2 months?
'remind_me' => 'required|boolean', 'order' => 'required:min:1', // not yet used.
];
use SoftDeletes;
protected $fillable
= ['repeats', 'name', 'account_id', 'rep_every', 'rep_times', 'reminder_skip', 'targetamount', 'startdate', 'targetdate', 'reminder', 'remind_me',
'rep_length'];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function account()
{
return $this->belongsTo('Account');
return $this->belongsTo('FireflyIII\Models\Account');
}
/**
* Grabs the PiggyBankRepetition that's currently relevant / active
*
* @returns \PiggyBankRepetition
* @returns PiggyBankRepetition
*/
public function currentRelevantRep()
{
if ($this->currentRep) {
if (!is_null($this->currentRep)) {
return $this->currentRep;
}
if ($this->repeats == 0) {
if (intval($this->repeats) === 0) {
$rep = $this->piggyBankRepetitions()->first(['piggy_bank_repetitions.*']);
$this->currentRep = $rep;
return $rep;
} else {
$query = $this->piggyBankRepetitions()->where(
$query = $this->piggyBankRepetitions()->where(
function (EloquentBuilder $q) {
$q->where(
@@ -83,9 +72,8 @@ class PiggyBank extends Eloquent
}
)->orderBy('startdate', 'ASC');
$result = $query->first(['piggy_bank_repetitions.*']);
$result = $query->first(['piggy_bank_repetitions.*']);
$this->currentRep = $result;
\Log::debug('Found relevant rep in currentRelevantRep(): ' . $result->id);
return $result;
}
@@ -98,7 +86,7 @@ class PiggyBank extends Eloquent
*/
public function piggyBankRepetitions()
{
return $this->hasMany('PiggyBankRepetition');
return $this->hasMany('FireflyIII\Models\PiggyBankRepetition');
}
/**
@@ -106,7 +94,17 @@ class PiggyBank extends Eloquent
*/
public function getDates()
{
return ['created_at', 'updated_at', 'targetdate', 'startdate'];
return ['created_at', 'updated_at', 'deleted_at', 'startdate', 'targetdate'];
}
/**
* @param $value
*
* @return int
*/
public function getRemindMeAttribute($value)
{
return intval($value) == 1;
}
/**
@@ -114,7 +112,7 @@ class PiggyBank extends Eloquent
*/
public function piggyBankEvents()
{
return $this->hasMany('PiggyBankEvent');
return $this->hasMany('FireflyIII\Models\PiggyBankEvent');
}
/**
@@ -122,6 +120,6 @@ class PiggyBank extends Eloquent
*/
public function reminders()
{
return $this->morphMany('Reminder', 'remindersable');
return $this->morphMany('FireflyIII\Models\Reminder', 'remindersable');
}
}

View File

@@ -0,0 +1,39 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* Class PiggyBankEvent
*
* @package FireflyIII\Models
*/
class PiggyBankEvent extends Model
{
protected $fillable = ['piggy_bank_id', 'transaction_journal_id', 'date', 'amount'];
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'date'];
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function piggyBank()
{
return $this->belongsTo('FireflyIII\Models\PiggyBank');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function transactionJournal()
{
return $this->belongsTo('FireflyIII\Models\TransactionJournal');
}
}

View File

@@ -0,0 +1,63 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Carbon\Carbon;
/**
* Class PiggyBankRepetition
*
* @package FireflyIII\Models
*/
class PiggyBankRepetition extends Model
{
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'startdate', 'targetdate'];
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function piggyBank()
{
return $this->belongsTo('FireflyIII\Models\PiggyBank');
}
/**
* @param EloquentBuilder $query
* @param Carbon $date
*
* @return mixed
*/
public function scopeRelevantOnDate(EloquentBuilder $query, Carbon $date)
{
return $query->where(
function($q) use ($date) {
$q->where('startdate', '<=', $date->format('Y-m-d 00:00:00'));
$q->orWhereNull('startdate');
})
->where(function($q) use ($date) {
$q->where('targetdate', '>=', $date->format('Y-m-d 00:00:00'));
$q->orWhereNull('targetdate');
});
}
/**
* @param EloquentBuilder $query
* @param Carbon $start
* @param Carbon $target
*
* @return $this
*/
public function scopeOnDates(EloquentBuilder $query, Carbon $start, Carbon $target)
{
return $query->where('startdate',$start->format('Y-m-d'))->where('targetdate',$target->format('Y-m-d'));
}
}

View File

@@ -1,16 +1,16 @@
<?php
use Illuminate\Database\Eloquent\Model as Eloquent;
use Watson\Validating\ValidatingTrait;
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* Class Preference
*
* @package FireflyIII\Models
*/
class Preference extends Eloquent
class Preference extends Model
{
use ValidatingTrait;
protected $fillable = ['name', 'data', 'user_id'];
protected $rules
= ['user_id' => 'required|exists:users,id', 'name' => 'required|between:1,255', 'data' => 'required'];
protected $fillable = ['user_id', 'data', 'name'];
/**
* @param $value
@@ -22,6 +22,14 @@ class Preference extends Eloquent
return json_decode($value);
}
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at'];
}
/**
* @param $value
*/
@@ -35,7 +43,7 @@ class Preference extends Eloquent
*/
public function user()
{
return $this->belongsTo('User');
return $this->belongsTo('FireflyIII\User');
}
}
}

100
app/Models/Reminder.php Normal file
View File

@@ -0,0 +1,100 @@
<?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
/**
* Class Reminder
*
* @package FireflyIII\Models
*/
class Reminder extends Model
{
protected $fillable = ['user_id', 'startdate', 'metadata', 'enddate', 'active', 'notnow', 'remindersable_id', 'remindersable_type',];
/**
* @param $value
*
* @return int
*/
public function getActiveAttribute($value)
{
return intval($value) == 1;
}
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'startdate', 'enddate'];
}
/**
* @param $value
*
* @return mixed
*/
public function getMetadataAttribute($value)
{
return json_decode($value);
}
/**
* @param $value
*
* @return bool
*/
public function getNotnowAttribute($value)
{
return intval($value) == 1;
}
/**
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function remindersable()
{
return $this->morphTo();
}
/**
* @param EloquentBuilder $query
* @param Carbon $start
* @param Carbon $end
*
* @return $this
*/
public function scopeOnDates(EloquentBuilder $query, Carbon $start, Carbon $end)
{
return $query->where('reminders.startdate', '=', $start->format('Y-m-d 00:00:00'))->where('reminders.enddate', '=', $end->format('Y-m-d 00:00:00'));
}
public function scopeToday(EloquentBuilder $query)
{
$today = new Carbon;
return $query->where('startdate', '<=', $today->format('Y-m-d 00:00:00'))->where('enddate', '>=', $today->format('Y-m-d 00:00:00'))->where('active', 1)
->where('notnow', 0);
}
/**
* @param $value
*/
public function setMetadataAttribute($value)
{
$this->attributes['metadata'] = json_encode($value);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('FireflyIII\User');
}
}

View File

@@ -0,0 +1,48 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
/**
* Class Transaction
*
* @package FireflyIII\Models
*/
class Transaction extends Model
{
protected $fillable = ['account_id', 'transaction_journal_id', 'description', 'amount'];
protected $rules
= [
'account_id' => 'required|exists:accounts,id',
'transaction_journal_id' => 'required|exists:transaction_journals,id',
'description' => 'between:1,255',
'amount' => 'required|numeric'
];
use SoftDeletes, ValidatingTrait;
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function account()
{
return $this->belongsTo('FireflyIII\Models\Account');
}
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'deleted_at'];
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function transactionJournal()
{
return $this->belongsTo('FireflyIII\Models\TransactionJournal');
}
}

View File

@@ -0,0 +1,33 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class TransactionCurrency
*
* @package FireflyIII\Models
*/
class TransactionCurrency extends Model
{
use SoftDeletes;
protected $fillable = ['name', 'code', 'symbol'];
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'deleted_at'];
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function transactionJournals()
{
return $this->hasMany('FireflyIII\Models\TransactionJournal');
}
}

View File

@@ -0,0 +1,39 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class TransactionGroup
*
* @package FireflyIII\Models
*/
class TransactionGroup extends Model
{
use SoftDeletes;
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'deleted_at'];
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function transactionjournals()
{
return $this->belongsToMany('FireflyIII\Models\TransactionJournal');
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('FireflyIII\User');
}
}

View File

@@ -1,35 +1,42 @@
<?php
<?php namespace FireflyIII\Models;
use Carbon\Carbon;
use Crypt;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletingTrait;
use Illuminate\Database\Eloquent\SoftDeletes;
use Watson\Validating\ValidatingTrait;
/**
* Class TransactionJournal
*
* @package FireflyIII\Models
*/
class TransactionJournal extends Eloquent
class TransactionJournal extends Model
{
use SoftDeletingTrait, ValidatingTrait;
use SoftDeletes, ValidatingTrait;
protected $fillable = ['user_id', 'transaction_type_id', 'bill_id', 'transaction_currency_id', 'description', 'completed', 'date', 'encrypted'];
protected $fillable
= ['transaction_type_id', 'transaction_currency_id', 'user_id',
'description', 'date', 'completed'];
protected $rules
= ['transaction_type_id' => 'required|exists:transaction_types,id',
'transaction_currency_id' => 'required|exists:transaction_currencies,id',
'description' => 'required|between:1,1024',
'date' => 'required|date',
'completed' => 'required|between:0,1'];
= [
'user_id' => 'required|exists:users,id',
'transaction_type_id' => 'required|exists:transaction_types,id',
'bill_id' => 'exists:bills,id',
'transaction_currency_id' => 'required|exists:transaction_currencies,id',
'description' => 'required|between:1,1024',
'completed' => 'required|boolean',
'date' => 'required|date',
'encrypted' => 'required|boolean'
];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function bill()
{
return $this->belongsTo('Bill');
return $this->belongsTo('FireflyIII\Models\Bill');
}
/**
@@ -37,9 +44,7 @@ class TransactionJournal extends Eloquent
*/
public function budgets()
{
return $this->belongsToMany(
'Budget'
);
return $this->belongsToMany('FireflyIII\Models\Budget');
}
/**
@@ -47,31 +52,7 @@ class TransactionJournal extends Eloquent
*/
public function categories()
{
return $this->belongsToMany(
'Category'
);
}
/**
* @param Account $account
*
* @return float
*/
public function getAmount(\Account $account = null)
{
$amount = 0;
foreach ($this->transactions as $t) {
if (!is_null($account) && $account->id == $t->account_id) {
$amount = floatval($t->amount);
break;
}
if (floatval($t->amount) > 0) {
$amount = floatval($t->amount);
break;
}
}
return $amount;
return $this->belongsToMany('FireflyIII\Models\Category');
}
/**
@@ -79,16 +60,23 @@ class TransactionJournal extends Eloquent
*/
public function getDates()
{
return ['created_at', 'updated_at', 'date'];
return ['created_at', 'updated_at', 'date', 'deleted_at'];
}
/**
* @param $value
*
* @return string
*/
public function getDescriptionAttribute($value)
{
if ($this->encrypted) {
return Crypt::decrypt($value);
}
// @codeCoverageIgnoreStart
return $value;
// @codeCoverageIgnoreEnd
}
/**
@@ -96,14 +84,14 @@ class TransactionJournal extends Eloquent
*/
public function piggyBankEvents()
{
return $this->hasMany('PiggyBankEvent');
return $this->hasMany('FireflyIII\Models\PiggyBankEvent');
}
/**
* @param EloquentBuilder $query
* @param Account $account
*/
public function scopeAccountIs(EloquentBuilder $query, \Account $account)
public function scopeAccountIs(EloquentBuilder $query, Account $account)
{
if (!isset($this->joinedTransactions)) {
$query->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id');
@@ -150,22 +138,6 @@ class TransactionJournal extends Eloquent
$query->where('transactions.amount', '<=', $amount);
}
/**
* @param EloquentBuilder $query
* @param $amount
*/
public function scopeMoreThan(EloquentBuilder $query, $amount)
{
if (is_null($this->joinedTransactions)) {
$query->leftJoin(
'transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id'
);
$this->joinedTransactions = true;
}
$query->where('transactions.amount', '>=', $amount);
}
/**
* @param EloquentBuilder $query
* @param Carbon $date
@@ -203,13 +175,16 @@ class TransactionJournal extends Eloquent
$query->with(
['transactions' => function (HasMany $q) {
$q->orderBy('amount', 'ASC');
}, 'transactiontype', 'budgets', 'categories', 'transactions.account.accounttype', 'bill', 'budgets', 'categories']
}, 'transactiontype', 'transactioncurrency', 'budgets', 'categories', 'transactions.account.accounttype', 'bill', 'budgets', 'categories']
);
}
/**
* @param $value
*/
public function setDescriptionAttribute($value)
{
$this->attributes['description'] = Crypt::encrypt($value);
$this->attributes['description'] = \Crypt::encrypt($value);
$this->attributes['encrypted'] = true;
}
@@ -218,7 +193,7 @@ class TransactionJournal extends Eloquent
*/
public function transactionCurrency()
{
return $this->belongsTo('TransactionCurrency');
return $this->belongsTo('FireflyIII\Models\TransactionCurrency');
}
/**
@@ -226,7 +201,7 @@ class TransactionJournal extends Eloquent
*/
public function transactionType()
{
return $this->belongsTo('TransactionType');
return $this->belongsTo('FireflyIII\Models\TransactionType');
}
/**
@@ -234,7 +209,7 @@ class TransactionJournal extends Eloquent
*/
public function transactiongroups()
{
return $this->belongsToMany('TransactionGroup');
return $this->belongsToMany('FireflyIII\Models\TransactionGroup');
}
/**
@@ -242,17 +217,15 @@ class TransactionJournal extends Eloquent
*/
public function transactions()
{
return $this->hasMany('Transaction');
return $this->hasMany('FireflyIII\Models\Transaction');
}
/**
* User
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('User');
return $this->belongsTo('FireflyIII\User');
}
}

View File

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

View File

@@ -0,0 +1,30 @@
<?php namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class TransactionType
*
* @package FireflyIII\Models
*/
class TransactionType extends Model
{
use SoftDeletes;
/**
* @return array
*/
public function getDates()
{
return ['created_at', 'updated_at', 'deleted_at'];
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function transactionJournals()
{
return $this->hasMany('FireflyIII\Models\TransactionJournal');
}
}

View File

@@ -0,0 +1,40 @@
<?php namespace FireflyIII\Providers;
use Illuminate\Support\ServiceProvider;
/**
* Class AppServiceProvider
*
* @package FireflyIII\Providers
*/
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register any application services.
*
* This service provider is a great spot to register your various container
* bindings with the application. As you can see, we are registering our
* "Registrar" implementation here. You can add your own bindings too!
*
* @return void
*/
public function register()
{
$this->app->bind(
'Illuminate\Contracts\Auth\Registrar',
'FireflyIII\Services\Registrar'
);
}
}

View File

@@ -0,0 +1,42 @@
<?php namespace FireflyIII\Providers;
use Illuminate\Bus\Dispatcher;
use Illuminate\Support\ServiceProvider;
/**
* Class BusServiceProvider
*
* @package FireflyIII\Providers
*/
class BusServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @param \Illuminate\Bus\Dispatcher $dispatcher
*
* @return void
*/
public function boot(Dispatcher $dispatcher)
{
$dispatcher->mapUsing(
function ($command) {
return Dispatcher::simpleMapping(
$command, 'FireflyIII\Commands', 'FireflyIII\Handlers\Commands'
);
}
);
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}

View File

@@ -0,0 +1,31 @@
<?php namespace FireflyIII\Providers;
use Illuminate\Support\ServiceProvider;
/**
* Class ConfigServiceProvider
*
* @package FireflyIII\Providers
*/
class ConfigServiceProvider extends ServiceProvider
{
/**
* Overwrite any vendor / package configuration.
*
* This service provider is intended to provide a convenient location for you
* to overwrite any "vendor" or package configuration that you may want to
* modify before the application handles the incoming request / command.
*
* @return void
*/
public function register()
{
config(
[
//
]
);
}
}

View File

@@ -0,0 +1,132 @@
<?php namespace FireflyIII\Providers;
use App;
use FireflyIII\Models\Account;
use FireflyIII\Models\Bill;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\Facades\Navigation;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Log;
/**
* Class EventServiceProvider
*
* @package FireflyIII\Providers
*/
class EventServiceProvider extends ServiceProvider
{
/**
* The event handler mappings for the application.
*
* @var array
*/
protected $listen
= [
'FireflyIII\Events\JournalSaved' => [
'FireflyIII\Handlers\Events\RescanJournal',
'FireflyIII\Handlers\Events\UpdateJournalConnection',
],
'FireflyIII\Events\JournalCreated' => [
'FireflyIII\Handlers\Events\ConnectJournalToPiggyBank',
]
];
/**
* Register any other events for your application.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
*
* @return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
TransactionJournal::deleted(
function (TransactionJournal $journal) {
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
$transaction->delete();
}
}
);
Account::deleted(
function (Account $account) {
/** @var Transaction $transaction */
foreach ($account->transactions()->get() as $transaction) {
$journal = $transaction->transactionJournal()->first();
$journal->delete();
}
}
);
// move this routine to a filter
// in case of repeated piggy banks and/or other problems.
PiggyBank::created(
function (PiggyBank $piggyBank) {
$repetition = new PiggyBankRepetition;
$repetition->piggyBank()->associate($piggyBank);
$repetition->startdate = is_null($piggyBank->startdate) ? null : $piggyBank->startdate;
$repetition->targetdate = is_null($piggyBank->targetdate) ? null : $piggyBank->targetdate;
$repetition->currentamount = 0;
$repetition->save();
}
);
BudgetLimit::saved(
function (BudgetLimit $budgetLimit) {
$end = Navigation::addPeriod(clone $budgetLimit->startdate, $budgetLimit->repeat_freq, 0);
$end->subDay();
$set = $budgetLimit->limitrepetitions()->where('startdate', $budgetLimit->startdate->format('Y-m-d'))->where('enddate', $end->format('Y-m-d'))
->get();
/*
* Create new LimitRepetition:
*/
if ($set->count() == 0) {
$repetition = new LimitRepetition;
$repetition->startdate = $budgetLimit->startdate;
$repetition->enddate = $end;
$repetition->amount = $budgetLimit->amount;
$repetition->budgetLimit()->associate($budgetLimit);
try {
$repetition->save();
} catch (QueryException $e) {
\Log::error('Trying to save new LimitRepetition failed!');
\Log::error($e->getMessage());
}
} else {
if ($set->count() == 1) {
/*
* Update existing one.
*/
$repetition = $set->first();
$repetition->amount = $budgetLimit->amount;
$repetition->save();
}
}
}
);
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace FireflyIII\Providers;
use FireflyIII\Support\Amount;
use FireflyIII\Support\ExpandedForm;
use FireflyIII\Support\Navigation;
use FireflyIII\Support\Preferences;
use FireflyIII\Support\Steam;
use FireflyIII\Validation\FireflyValidator;
use Illuminate\Support\ServiceProvider;
use Validator;
/**
* Class FireflyServiceProvider
*
* @package FireflyIII\Providers
*/
class FireflyServiceProvider extends ServiceProvider
{
public function boot()
{
Validator::resolver(
function ($translator, $data, $rules, $messages) {
return new FireflyValidator($translator, $data, $rules, $messages);
}
);
}
public function register()
{
$this->app->bind(
'preferences', function () {
return new Preferences;
}
);
$this->app->bind(
'navigation', function () {
return new Navigation;
}
);
$this->app->bind(
'amount', function () {
return new Amount;
}
);
$this->app->bind(
'steam', function () {
return new Steam;
}
);
$this->app->bind(
'expandedform', function () {
return new ExpandedForm;
}
);
$this->app->bind('FireflyIII\Repositories\Account\AccountRepositoryInterface', 'FireflyIII\Repositories\Account\AccountRepository');
$this->app->bind('FireflyIII\Repositories\Budget\BudgetRepositoryInterface', 'FireflyIII\Repositories\Budget\BudgetRepository');
$this->app->bind('FireflyIII\Repositories\Category\CategoryRepositoryInterface', 'FireflyIII\Repositories\Category\CategoryRepository');
$this->app->bind('FireflyIII\Repositories\Journal\JournalRepositoryInterface', 'FireflyIII\Repositories\Journal\JournalRepository');
$this->app->bind('FireflyIII\Repositories\Bill\BillRepositoryInterface', 'FireflyIII\Repositories\Bill\BillRepository');
$this->app->bind('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface', 'FireflyIII\Repositories\PiggyBank\PiggyBankRepository');
$this->app->bind('FireflyIII\Support\Search\SearchInterface', 'FireflyIII\Support\Search\Search');
$this->app->bind('FireflyIII\Helpers\Reminders\ReminderHelperInterface', 'FireflyIII\Helpers\Reminders\ReminderHelper');
$this->app->bind('FireflyIII\Helpers\Report\ReportHelperInterface', 'FireflyIII\Helpers\Report\ReportHelper');
$this->app->bind('FireflyIII\Helpers\Report\ReportQueryInterface', 'FireflyIII\Helpers\Report\ReportQuery');
}
}

View File

@@ -0,0 +1,70 @@
<?php namespace FireflyIII\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Routing\Router;
/**
* Class RouteServiceProvider
*
* @package FireflyIII\Providers
*/
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to the controller routes in your routes file.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'FireflyIII\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @param \Illuminate\Routing\Router $router
*
* @return void
*/
public function boot(Router $router)
{
parent::boot($router);
$router->before(
function (Request $request) {
// put IP in session if not already there.
$reminders = [];
if ($request->user()) {
//Filter::setSessionDateRange();
//Reminders::updateReminders();
//Steam::removeEmptyBudgetLimits();
//$reminders = Reminders::getReminders();
}
// View::share('reminders', $reminders);
}
);
}
/**
* Define the routes for the application.
*
* @param \Illuminate\Routing\Router $router
*
* @return void
*/
public function map(Router $router)
{
$router->group(
['namespace' => $this->namespace], function ($router) {
/** @noinspection PhpIncludeInspection */
require app_path('Http/routes.php');
}
);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace FireflyIII\Providers;
use Illuminate\Support\ServiceProvider;
/**
* Class TestingServiceProvider
*
* @package FireflyIII\Providers
*/
class TestingServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
if ($this->app->environment() == 'testing') {
$this->app['config']['session.driver'] = 'native';
}
}
}

View File

@@ -0,0 +1,456 @@
<?php
namespace FireflyIII\Repositories\Account;
use App;
use Auth;
use Carbon\Carbon;
use Config;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Log;
use Session;
use Steam;
/**
* Class AccountRepository
*
* @package FireflyIII\Repositories\Account
*/
class AccountRepository implements AccountRepositoryInterface
{
/**
* @return int
*/
public function countAssetAccounts()
{
return Auth::user()->accounts()->accountTypeIn(['Asset account', 'Default account'])->count();
}
/**
* @param Account $account
*
* @return boolean
*/
public function destroy(Account $account)
{
$account->delete();
return true;
}
/**
* @param Preference $preference
*
* @return Collection
*/
public function getFrontpageAccounts(Preference $preference)
{
if ($preference->data == []) {
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
} else {
$accounts = Auth::user()->accounts()->whereIn('id', $preference->data)->orderBy('accounts.name', 'ASC')->get(['accounts.*']);
}
return $accounts;
}
/**
* This method is used on the front page where (in turn) its viewed journals-tiny.php which (in turn)
* is almost the only place where formatJournal is used. Aka, we can use some custom querying to get some specific.
* fields using left joins.
*
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end)
{
return Auth::user()
->transactionjournals()
->with(['transactions'])
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')->where('accounts.id', $account->id)
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transaction_journals.transaction_currency_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->before($end)
->after($start)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.id', 'DESC')
->take(10)
->get(['transaction_journals.*', 'transaction_currencies.symbol', 'transaction_types.type']);
}
/**
* @param Account $account
* @param int $page
*
* @return mixed
*/
public function getJournals(Account $account, $page)
{
$offset = ($page - 1) * 50;
$query = Auth::user()
->transactionJournals()
->withRelevantData()
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order','ASC')
->orderBy('transaction_journals.id','DESC');
$query->before(Session::get('end', Carbon::now()->endOfMonth()));
$query->after(Session::get('start', Carbon::now()->startOfMonth()));
$count = $query->count();
$set = $query->take(50)->offset($offset)->get(['transaction_journals.*']);
$paginator = new LengthAwarePaginator($set, $count, 50, $page);
return $paginator;
//return Paginator::make($items, $count, 50);
}
/**
* Get savings accounts and the balance difference in the period.
*
* @return Collection
*/
public function getSavingsAccounts()
{
$accounts = Auth::user()->accounts()->accountTypeIn(['Default account', 'Asset account'])->orderBy('accounts.name', 'ASC')
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
->where('account_meta.name', 'accountRole')
->where('account_meta.data', '"savingAsset"')
->get(['accounts.*']);
$start = clone Session::get('start');
$end = clone Session::get('end');
$accounts->each(
function (Account $account) use ($start, $end) {
$account->startBalance = Steam::balance($account, $start);
$account->endBalance = Steam::balance($account, $end);
// diff (negative when lost, positive when gained)
$diff = $account->endBalance - $account->startBalance;
if ($diff < 0 && $account->startBalance > 0) {
// percentage lost compared to start.
$pct = (($diff * -1) / $account->startBalance) * 100;
} else {
if ($diff >= 0 && $account->startBalance > 0) {
$pct = ($diff / $account->startBalance) * 100;
} else {
$pct = 100;
}
}
$pct = $pct > 100 ? 100 : $pct;
$account->difference = $diff;
$account->percentage = round($pct);
}
);
return $accounts;
}
/**
* @param Account $account
*
* @return float
*/
public function leftOnAccount(Account $account)
{
$balance = \Steam::balance($account);
/** @var PiggyBank $p */
foreach ($account->piggybanks()->get() as $p) {
$balance -= $p->currentRelevantRep()->currentamount;
}
return $balance;
}
/**
* @param Account $account
*
* @return TransactionJournal|null
*/
public function openingBalanceTransaction(Account $account)
{
return TransactionJournal::accountIs($account)
->orderBy('transaction_journals.date', 'ASC')
->orderBy('created_at', 'ASC')
->first(['transaction_journals.*']);
}
/**
* @param array $data
*
* @return Account;
*/
public function store(array $data)
{
$newAccount = $this->_store($data);
$this->_storeMetadata($newAccount, $data);
// continue with the opposing account:
if ($data['openingBalance'] != 0) {
$type = $data['openingBalance'] < 0 ? 'expense' : 'revenue';
$opposingData = [
'user' => $data['user'],
'accountType' => $type,
'name' => $data['name'] . ' initial balance',
'active' => false,
];
$opposing = $this->_store($opposingData);
$this->_storeInitialBalance($newAccount, $opposing, $data);
}
return $newAccount;
}
/**
* @param Account $account
* @param array $data
*/
public function update(Account $account, array $data)
{
// update the account:
$account->name = $data['name'];
$account->active = $data['active'] == '1' ? true : false;
$account->save();
// update meta data:
$this->_updateMetadata($account, $data);
$openingBalance = $this->openingBalanceTransaction($account);
// if has openingbalance?
if ($data['openingBalance'] != 0) {
// if opening balance, do an update:
if ($openingBalance) {
// update existing opening balance.
$this->_updateInitialBalance($account, $openingBalance, $data);
} else {
// create new opening balance.
$type = $data['openingBalance'] < 0 ? 'expense' : 'revenue';
$opposingData = [
'user' => $data['user'],
'accountType' => $type,
'name' => $data['name'] . ' initial balance',
'active' => false,
];
$opposing = $this->_store($opposingData);
$this->_storeInitialBalance($account, $opposing, $data);
}
} else {
// opening balance is zero, should we delete it?
if ($openingBalance) {
// delete existing opening balance.
$openingBalance->delete();
}
}
return $account;
}
/**
* @param array $data
*
* @return Account
*/
protected function _store(array $data)
{
$type = Config::get('firefly.accountTypeByIdentifier.' . $data['accountType']);
$accountType = AccountType::whereType($type)->first();
$newAccount = new Account(
[
'user_id' => $data['user'],
'account_type_id' => $accountType->id,
'name' => $data['name'],
'active' => $data['active'] === true ? true : false,
]
);
if (!$newAccount->isValid()) {
// does the account already exist?
$existingAccount = Account::where('user_id', $data['user'])->where('account_type_id', $accountType->id)->where('name', $data['name'])->first();
if (!$existingAccount) {
Log::error('Account create error: ' . $newAccount->getErrors()->toJson());
App::abort(500);
}
$newAccount = $existingAccount;
}
$newAccount->save();
return $newAccount;
}
/**
* @param Account $account
* @param array $data
*/
protected function _storeMetadata(Account $account, array $data)
{
$metaData = new AccountMeta(
[
'account_id' => $account->id,
'name' => 'accountRole',
'data' => $data['accountRole']
]
);
if (!$metaData->isValid()) {
App::abort(500);
}
$metaData->save();
}
/**
* @param Account $account
* @param Account $opposing
* @param array $data
*
* @return TransactionJournal
*/
protected function _storeInitialBalance(Account $account, Account $opposing, array $data)
{
$type = $data['openingBalance'] < 0 ? 'Withdrawal' : 'Deposit';
$transactionType = TransactionType::whereType($type)->first();
$journal = new TransactionJournal(
[
'user_id' => $data['user'],
'transaction_type_id' => $transactionType->id,
'bill_id' => null,
'transaction_currency_id' => $data['openingBalanceCurrency'],
'description' => 'Initial balance for "' . $account->name . '"',
'completed' => true,
'date' => $data['openingBalanceDate'],
'encrypted' => true
]
);
if (!$journal->isValid()) {
App::abort(500);
}
$journal->save();
if ($data['openingBalance'] < 0) {
$firstAccount = $opposing;
$secondAccount = $account;
$firstAmount = $data['openingBalance'] * -1;
$secondAmount = $data['openingBalance'];
} else {
$firstAccount = $account;
$secondAccount = $opposing;
$firstAmount = $data['openingBalance'];
$secondAmount = $data['openingBalance'] * -1;
}
// first transaction: from
$one = new Transaction(
[
'account_id' => $firstAccount->id,
'transaction_journal_id' => $journal->id,
'amount' => $firstAmount
]
);
if (!$one->isValid()) {
App::abort(500);
}
$one->save();
// second transaction: to
$two = new Transaction(
[
'account_id' => $secondAccount->id,
'transaction_journal_id' => $journal->id,
'amount' => $secondAmount
]
);
if (!$two->isValid()) {
App::abort(500);
}
$two->save();
return $journal;
}
/**
* @param Account $account
* @param array $data
*/
protected function _updateMetadata(Account $account, array $data)
{
$metaEntries = $account->accountMeta()->get();
$updated = false;
/** @var AccountMeta $entry */
foreach ($metaEntries as $entry) {
if ($entry->name == 'accountRole') {
$entry->data = $data['accountRole'];
$updated = true;
$entry->save();
}
}
if ($updated === false) {
$metaData = new AccountMeta(
[
'account_id' => $account->id,
'name' => 'accountRole',
'data' => $data['accountRole']
]
);
if (!$metaData->isValid()) {
App::abort(500);
}
$metaData->save();
}
}
/**
* @param Account $account
* @param TransactionJournal $journal
* @param array $data
*
* @return TransactionJournal
*/
protected function _updateInitialBalance(Account $account, TransactionJournal $journal, array $data)
{
$journal->date = $data['openingBalanceDate'];
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
if ($account->id == $transaction->account_id) {
$transaction->amount = $data['openingBalance'];
$transaction->save();
}
if ($account->id != $transaction->account_id) {
$transaction->amount = $data['openingBalance'] * -1;
$transaction->save();
}
}
return $journal;
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace FireflyIII\Repositories\Account;
use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Preference;
use Illuminate\Support\Collection;
use Carbon\Carbon;
/**
* Interface AccountRepositoryInterface
*
* @package FireflyIII\Repositories\Account
*/
interface AccountRepositoryInterface
{
/**
* @param Account $account
*
* @return boolean
*/
public function destroy(Account $account);
/**
* @return int
*/
public function countAssetAccounts();
/**
* @param Preference $preference
*
* @return Collection
*/
public function getFrontpageAccounts(Preference $preference);
/**
* @param Account $account
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getFrontpageTransactions(Account $account, Carbon $start, Carbon $end);
/**
* @param Account $account
* @param string $range
*
* @return mixed
*/
public function getJournals(Account $account, $page);
/**
* @param Account $account
*
* @return TransactionJournal|null
*/
public function openingBalanceTransaction(Account $account);
/**
* @param array $data
*
* @return Account
*/
public function store(array $data);
/**
* @param Account $account
* @param array $data
*
* @return Account
*/
public function update(Account $account, array $data);
/**
* @param Account $account
*
* @return float
*/
public function leftOnAccount(Account $account);
/**
* Get savings accounts and the balance difference in the period.
*
* @return Collection
*/
public function getSavingsAccounts();
}

View File

@@ -0,0 +1,241 @@
<?php
namespace FireflyIII\Repositories\Bill;
use Carbon\Carbon;
use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionJournal;
use Log;
use Navigation;
/**
* Class BillRepository
*
* @package FireflyIII\Repositories\Bill
*/
class BillRepository implements BillRepositoryInterface
{
/**
* Every bill repeats itself weekly, monthly or yearly (or whatever). This method takes a date-range (usually the view-range of Firefly itself)
* and returns date ranges that fall within the given range; those ranges are the bills expected. When a bill is due on the 14th of the month and
* you give 1st and the 31st of that month as argument, you'll get one response, matching the range of your bill.
*
* @param Bill $bill
* @param Carbon $start
* @param Carbon $end
*
* @return mixed
*/
public function getRanges(Bill $bill, Carbon $start, Carbon $end)
{
$startOfBill = $bill->date;
$startOfBill = Navigation::startOfPeriod($startOfBill, $bill->repeat_freq);
// all periods of this bill up until the current period:
$billStarts = [];
while ($startOfBill < $end) {
$endOfBill = Navigation::endOfPeriod($startOfBill, $bill->repeat_freq);
$billStarts[] = [
'start' => clone $startOfBill,
'end' => clone $endOfBill,
];
// actually the next one:
$startOfBill = Navigation::addPeriod($startOfBill, $bill->repeat_freq, $bill->skip);
}
// for each
$validRanges = [];
foreach ($billStarts as $dateEntry) {
if ($dateEntry['end'] > $start && $dateEntry['start'] < $end) {
// count transactions for bill in this range (not relevant yet!):
// $count = $bill->transactionjournals()->before($dateEntry['end'])->after($dateEntry['start'])->count();
// if ($count == 0) {
$validRanges[] = $dateEntry;
// }
}
}
return $validRanges;
// echo $bill->name;
// var_dump($validRanges);
}
/**
* @param Bill $bill
*
* @return Carbon
*/
public function nextExpectedMatch(Bill $bill)
{
$finalDate = null;
if ($bill->active == 0) {
return $finalDate;
}
/*
* $today is the start of the next period, to make sure FF3 won't miss anything
* when the current period has a transaction journal.
*/
$today = Navigation::addPeriod(new Carbon, $bill->repeat_freq, 0);
$skip = $bill->skip + 1;
$start = Navigation::startOfPeriod(new Carbon, $bill->repeat_freq);
/*
* go back exactly one month/week/etc because FF3 does not care about 'next'
* bills if they're too far into the past.
*/
$counter = 0;
while ($start <= $today) {
if (($counter % $skip) == 0) {
// do something.
$end = Navigation::endOfPeriod(clone $start, $bill->repeat_freq);
$journalCount = $bill->transactionjournals()->before($end)->after($start)->count();
if ($journalCount == 0) {
$finalDate = clone $start;
break;
}
}
// add period for next round!
$start = Navigation::addPeriod($start, $bill->repeat_freq, 0);
$counter++;
}
return $finalDate;
}
/**
* @param Bill $bill
* @param TransactionJournal $journal
*
* @return bool
*/
public function scan(Bill $bill, TransactionJournal $journal)
{
/*
* Match words.
*/
$wordMatch = false;
$matches = explode(',', $bill->match);
$description = strtolower($journal->description);
Log::debug('Now scanning ' . $description);
/*
* Attach expense account to description for more narrow matching.
*/
if (count($journal->transactions) < 2) {
$transactions = $journal->transactions()->get();
} else {
$transactions = $journal->transactions;
}
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
/** @var Account $account */
$account = $transaction->account()->first();
/** @var AccountType $type */
$type = $account->accountType()->first();
if ($type->type == 'Expense account' || $type->type == 'Beneficiary account') {
$description .= ' ' . strtolower($account->name);
}
}
Log::debug('Final description: ' . $description);
Log::debug('Matches searched: ' . join(':', $matches));
$count = 0;
foreach ($matches as $word) {
if (!(strpos($description, strtolower($word)) === false)) {
$count++;
}
}
if ($count >= count($matches)) {
$wordMatch = true;
Log::debug('word match is true');
} else {
Log::debug('Count: ' . $count . ', count(matches): ' . count($matches));
}
/*
* Match amount.
*/
$amountMatch = false;
if (count($transactions) > 1) {
$amount = max(floatval($transactions[0]->amount), floatval($transactions[1]->amount));
$min = floatval($bill->amount_min);
$max = floatval($bill->amount_max);
if ($amount >= $min && $amount <= $max) {
$amountMatch = true;
Log::debug('Amount match is true!');
}
}
/*
* If both, update!
*/
if ($wordMatch && $amountMatch) {
Log::debug('TOTAL match is true!');
$journal->bill()->associate($bill);
$journal->save();
}
}
/**
* @param array $data
*
* @return Bill
*/
public function store(array $data)
{
$bill = Bill::create(
[
'name' => $data['name'],
'match' => $data['match'],
'amount_min' => $data['amount_min'],
'user_id' => $data['user'],
'amount_max' => $data['amount_max'],
'date' => $data['date'],
'repeat_freq' => $data['repeat_freq'],
'skip' => $data['skip'],
'automatch' => $data['automatch'],
'active' => $data['active'],
]
);
return $bill;
}
/**
* @param Bill $bill
* @param array $data
*
* @return Bill|static
*/
public function update(Bill $bill, array $data)
{
$bill->name = $data['name'];
$bill->match = $data['match'];
$bill->amount_min = $data['amount_min'];
$bill->amount_max = $data['amount_max'];
$bill->date = $data['date'];
$bill->repeat_freq = $data['repeat_freq'];
$bill->skip = $data['skip'];
$bill->automatch = $data['automatch'];
$bill->active = $data['active'];
$bill->save();
return $bill;
}
}

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