Compare commits

..

503 Commits
3.1.2 ... 3.2.3

Author SHA1 Message Date
James Cole
3011b5074d Merge branch 'release/3.2.3' 2015-01-13 19:08:33 +01:00
James Cole
83190572c7 New composer.lock 2015-01-10 18:07:39 +01:00
James Cole
9cf9e5f865 Added a missing field. 2015-01-05 20:22:39 +01:00
James Cole
5bdef7f1c7 Added a missing field. 2015-01-05 20:22:19 +01:00
James Cole
ba285a2d2d Added a missing field. 2015-01-05 20:21:43 +01:00
James Cole
0dff371e62 Added a missing field. 2015-01-05 20:20:03 +01:00
James Cole
ce4a2a5851 Added a missing field. 2015-01-05 20:19:34 +01:00
James Cole
2c978dc89a Removed experimental routes. 2015-01-05 17:53:38 +01:00
James Cole
4b8b819109 Redirect update. 2015-01-04 20:50:35 +01:00
James Cole
c230b3a806 This broke the tests. 2015-01-03 18:09:44 +01:00
James Cole
df08b9c5c6 Updated composer.lock 2015-01-03 13:46:53 +01:00
James Cole
eca65376a3 Fixed a route. 2015-01-03 09:25:40 +01:00
James Cole
88e3705636 Do some redirection. 2015-01-02 22:47:34 +01:00
James Cole
5476509ef5 Disabled some seeds, updated some routes. 2015-01-02 22:44:25 +01:00
James Cole
0bd6636453 SQL reference file [skip ci] 2015-01-02 20:04:26 +01:00
James Cole
105894e00d Small bug in budget helper [skip ci] 2015-01-02 19:53:09 +01:00
James Cole
230a319510 Removed files no longer used [skip ci] 2015-01-02 18:52:55 +01:00
James Cole
ae16a2b14f Routes and views for transactions without a budget / category [skip ci] 2015-01-02 18:48:06 +01:00
James Cole
da0c0742bf Covered some more lines of code. 2015-01-02 13:57:40 +01:00
James Cole
61d60a9048 Updated read me [skip ci] 2015-01-02 12:56:07 +01:00
James Cole
3e28e9a016 Merge branch 'release/3.2.2' 2015-01-02 12:53:44 +01:00
James Cole
423f9fefa9 Removed todo entries and made issues instead. [skip ci] 2015-01-02 12:42:29 +01:00
James Cole
5707dc7579 Lots of cleaning up. 2015-01-02 12:38:13 +01:00
James Cole
3be1cdb249 Some cleaning up in the reports. [skip ci] 2015-01-02 11:04:51 +01:00
James Cole
426d3d948c Added newlines [skip ci] 2015-01-02 10:55:59 +01:00
James Cole
9a3aed8038 Moved code to relate transfers to another class. Still needs some work. 2015-01-02 10:53:18 +01:00
James Cole
fb58bf1bf5 Cleaned up some todo entries [skip ci] 2015-01-02 10:01:33 +01:00
James Cole
a6dbd912c6 Code cleanup. 2015-01-02 09:06:44 +01:00
James Cole
65ce277a20 Updated models [skip ci] 2015-01-02 08:59:16 +01:00
James Cole
0b2d423c87 Updated ignore file. 2015-01-02 06:26:57 +01:00
James Cole
da056092fb Code cleanup [skip ci] 2015-01-02 06:26:04 +01:00
James Cole
45aa85d690 Added new lines [skip ci] 2015-01-02 06:24:48 +01:00
James Cole
5c35fee0c2 New lines at end of file [skip ci] 2015-01-02 06:16:49 +01:00
James Cole
24bdc319dd Some refactoring [skip ci] 2015-01-02 06:05:40 +01:00
James Cole
f1dcc41e42 Removed invalid composer.json entry [skip ci] 2015-01-02 06:00:14 +01:00
James Cole
550f301ba2 Code cleanup [skip ci] 2015-01-02 05:52:38 +01:00
James Cole
d9bf4d1c0d Removed c3.php from lib. [skip ci] 2015-01-02 05:37:25 +01:00
James Cole
c3c1a6eb22 Changed permissions [skip ci] 2015-01-02 05:36:49 +01:00
James Cole
2c4454418e Remove possible xsrf [skip ci] 2015-01-02 05:36:05 +01:00
James Cole
e44de572f5 Code cleanup [skip ci] 2015-01-01 23:12:12 +01:00
James Cole
f27919f91b Fixed transaction journal test. 2015-01-01 22:57:15 +01:00
James Cole
ba9968bde0 Fixed a bug in "number between" tests. 2015-01-01 22:53:03 +01:00
James Cole
05ea8216ff Fixed transaction coverage. 2015-01-01 22:51:38 +01:00
James Cole
fa1695672a Cleaning up. 2015-01-01 22:32:25 +01:00
James Cole
ac6f98fc47 First attempt to make the year charts and month reports report the same thing [skip ci] 2015-01-01 21:35:05 +01:00
James Cole
1a1f89f555 First attempt to make the year charts and month reports report the same thing [skip ci] 2015-01-01 21:27:51 +01:00
James Cole
6c3262e176 First attempt to make the year charts and month reports report the same thing [skip ci] 2015-01-01 21:26:40 +01:00
James Cole
b4bdb48f1e First attempt to make the year charts and month reports report the same thing [skip ci] 2015-01-01 21:23:12 +01:00
James Cole
823afe877b First attempt to make the year charts and month reports report the same thing [skip ci] 2015-01-01 21:20:41 +01:00
James Cole
cb8e082414 Fixed the bill tests. 2015-01-01 21:06:24 +01:00
James Cole
98c1fcc68f New content and tests ensure the coverage of all code. 2015-01-01 20:53:36 +01:00
James Cole
8c439a2852 Added debug information [skip ci] 2015-01-01 20:02:02 +01:00
James Cole
50c6109be7 Fixed broken tests. 2015-01-01 19:50:36 +01:00
James Cole
6e362663b5 Clean up content seeder and tests. 2015-01-01 19:35:10 +01:00
James Cole
74c9feb53f More tests! 2015-01-01 13:43:34 +01:00
James Cole
402e8588cf Even more tests! 2015-01-01 13:32:31 +01:00
James Cole
778a42bcc0 More unit tests. 2015-01-01 13:12:05 +01:00
James Cole
584f7ced84 New tests and new configuration for tests. 2015-01-01 12:33:07 +01:00
James Cole
8e892e7ea5 New unit tests to cover missed methods. 2015-01-01 12:06:42 +01:00
James Cole
3386c8b455 More spelling checks and small clean ups. 2014-12-31 17:15:59 +01:00
James Cole
6fa73ee28d Complexity cleanup [skip ci] 2014-12-31 16:45:12 +01:00
James Cole
8ec8042045 Some spell checking [skip ci] 2014-12-31 16:17:43 +01:00
James Cole
cddc123539 Removed dead code. 2014-12-31 09:02:36 +01:00
James Cole
4c2938c5cd New content and a fix for the bill controller. 2014-12-31 08:31:18 +01:00
James Cole
6d03ddadcc Covered the final lines. 2014-12-31 08:11:00 +01:00
James Cole
64311da4b4 Full coverage for home controller 2014-12-31 07:43:33 +01:00
James Cole
0cbb50ae9d Full coverage for user controller. 2014-12-31 07:17:33 +01:00
James Cole
7e96054dc2 Covered everything in the user controller except configuration controlled statements. 2014-12-31 00:57:12 +01:00
James Cole
578298580e Last tests for transaction controller. 2014-12-31 00:25:17 +01:00
James Cole
ee5afaa6bc First tests for transaction controller. 2014-12-30 22:25:30 +01:00
James Cole
15b023d116 Updated composer.lock [skip ci] 2014-12-30 21:04:01 +01:00
James Cole
1ef96c0b4d Finally updated the transaction controller to have some more sensible code. 2014-12-30 21:03:42 +01:00
James Cole
8c3ae40de1 Some refactoring. 2014-12-30 18:44:58 +01:00
James Cole
94fcfacec4 Tests for search [skip ci] 2014-12-30 18:44:49 +01:00
James Cole
ba7c01c6bc Fixed the tests. 2014-12-30 18:25:38 +01:00
James Cole
9f92e1b7bd Some tests and a rename. 2014-12-30 17:55:46 +01:00
James Cole
1f0e692ee2 New tests for the repeated expenses. 2014-12-30 17:27:31 +01:00
James Cole
0acd75a24f Updated tests for help controller. 2014-12-30 15:55:21 +01:00
James Cole
eedf27f8a5 Fixed the tests [skip ci] 2014-12-30 15:24:10 +01:00
James Cole
b451e207e2 Finally implemented repeated expenses properly. [skip ci] 2014-12-30 15:17:01 +01:00
James Cole
c0c37eec7b Most views now show the transaction the current journal/transaction is set in, even if it's not the current default currency. See issue #37 2014-12-30 06:30:20 +01:00
James Cole
89363ecfa3 Tests for reminders. 2014-12-29 21:49:43 +01:00
James Cole
593e799ca1 New and matching icon for bills [skip ci] #38 2014-12-29 20:39:27 +01:00
James Cole
8fc055cad9 Renamed a container [skip ci] #38 2014-12-29 20:36:56 +01:00
James Cole
75f86462e2 All code for issue #38. 2014-12-29 20:28:17 +01:00
James Cole
40892ccfa7 Some small updates to piggy banks. 2014-12-28 18:03:35 +01:00
James Cole
87fbf9c1a5 Added the ability to see cash accounts. [skip ci] 2014-12-28 09:00:22 +01:00
James Cole
4944b233b6 Greatly expanded report functionality. 2014-12-28 08:54:53 +01:00
James Cole
9f23462c42 Expanded reports. 2014-12-27 17:21:15 +01:00
James Cole
84a24f0333 Something with migrations. 2014-12-27 05:38:33 +01:00
James Cole
7a885bfc3c Fixed various bugs that made tests fail. 2014-12-26 22:59:13 +01:00
James Cole
3ba0cf1454 Expanded summary [skip ci] 2014-12-26 21:14:45 +01:00
James Cole
2d67a3159d Expanded reports 2014-12-26 21:08:44 +01:00
James Cole
290f25f1a0 First attempt at new month report. 2014-12-25 09:50:01 +01:00
James Cole
1659904f81 Various cleanup and spelling fixes. 2014-12-25 08:07:17 +01:00
James Cole
230bd6e40a Tests for the recurring transaction controller. 2014-12-25 08:00:09 +01:00
James Cole
ce27e97b92 More tests! Yay! 2014-12-25 00:42:31 +01:00
James Cole
18c1223c7b Tests for the profile controller 2014-12-24 22:52:14 +01:00
James Cole
8ef659f5de Tests for preferences controller. 2014-12-24 22:39:23 +01:00
James Cole
037452e525 Spelling errors fixed. 2014-12-24 21:20:47 +01:00
James Cole
e3482011d5 Updated two views. 2014-12-24 21:07:20 +01:00
James Cole
62748fa255 Migrations for future version 3.2.2 2014-12-24 20:56:05 +01:00
James Cole
7a9df05f6b A giant rename action in preparation of v3.2.2 2014-12-24 20:55:42 +01:00
James Cole
335279e728 Renamed lots of "piggybank" to "piggyBank". 2014-12-24 19:13:15 +01:00
James Cole
0332104738 Expanded tests for piggy banks. 2014-12-24 19:00:31 +01:00
James Cole
9f04854902 Merge branch 'release/3.2.1' 2014-12-24 14:34:51 +01:00
James Cole
73008a35fe Clean up tests. 2014-12-24 14:33:02 +01:00
James Cole
eae96cd2af Covered currency controller in tests. 2014-12-24 14:02:21 +01:00
James Cole
cb670bb27d Update, edit and delete currencies. 2014-12-24 12:32:18 +01:00
James Cole
fe1fb23e5b Extend JS to include currency code #37 2014-12-24 06:10:39 +01:00
James Cole
c2dd61e96b Methods to grab the requested currency symbol. #37 2014-12-24 05:58:26 +01:00
James Cole
80f5e61b6b Append default data to current currency table (assuming default entries). 2014-12-24 05:51:18 +01:00
James Cole
dbcae16b75 Made two new columns nullable. #37 2014-12-24 05:43:08 +01:00
James Cole
886dcae822 Route for #37 2014-12-23 22:27:58 +01:00
James Cole
ed495ec600 Menu for #37 2014-12-23 22:27:52 +01:00
James Cole
ddb60ccdc5 New view for #37 2014-12-23 22:27:45 +01:00
James Cole
335e2083af Expand helper for #37 2014-12-23 22:27:29 +01:00
James Cole
7b1d9d4962 First basic controller for #37 2014-12-23 22:27:14 +01:00
James Cole
da6ff9f90a Migrations for #37 2014-12-23 22:27:00 +01:00
James Cole
48f26c7bf1 Added a route for future currency options. 2014-12-23 21:55:30 +01:00
James Cole
3ce317b170 New tests. 2014-12-23 21:55:19 +01:00
James Cole
b741565f57 New test content. 2014-12-23 21:55:08 +01:00
James Cole
d8fea44968 New setting called 'budgetMaximum', see issue #36 2014-12-23 21:14:26 +01:00
James Cole
778300b67e Updated view for setting called 'budgetMaximum', see issue #36 2014-12-23 21:14:17 +01:00
James Cole
cb2b44fef3 New setting called 'budgetMaximum', see issue #36 2014-12-23 21:13:59 +01:00
James Cole
cdb5875d6b Some cleaning up for tests. 2014-12-23 21:13:42 +01:00
James Cole
01c5e15bcd Retrieve the new setting called 'budgetMaximum' which allows you to set the maximum budget. 2014-12-23 21:13:32 +01:00
James Cole
f0babb4be7 Made sure the migrations are reversible and updated the test seeder. 2014-12-22 20:43:38 +01:00
James Cole
10b00da874 Try to fix the tests. 2014-12-22 18:41:16 +01:00
James Cole
e9f391b2eb First tests for piggy bank controller. 2014-12-22 07:10:18 +01:00
James Cole
50be39b054 Fixed a bug where an update to a transaction journal would trigger the wrong response. 2014-12-21 18:43:01 +01:00
James Cole
a94e0bb3da Some cleaning up in prep for tests [skip ci] 2014-12-21 18:40:37 +01:00
James Cole
3f65d5d760 Cover JSON controller. 2014-12-21 18:09:35 +01:00
James Cole
48cb528ae4 Increased test coverage. Also updated read me. 2014-12-21 17:59:47 +01:00
James Cole
e62e0345df Also covered help. 2014-12-21 11:15:37 +01:00
James Cole
441f011fba More coverage. 2014-12-21 10:54:25 +01:00
James Cole
af1349160a Lots of clean up in the Google Chart controller. 2014-12-20 22:38:56 +01:00
James Cole
2072607889 Cleanup, mostly I removed the coding standard ignore instructions. 2014-12-20 22:07:21 +01:00
James Cole
073fd5aa0d 4 instead of 3. 2014-12-20 17:41:33 +01:00
James Cole
7b4703e4ff Category controller covered. 2014-12-20 16:53:32 +01:00
James Cole
1484621300 More tests! 2014-12-20 16:06:25 +01:00
James Cole
40709c8367 +x for execute 2014-12-20 15:33:55 +01:00
James Cole
b6ab5770a2 Lets see if this works. 2014-12-20 15:30:48 +01:00
James Cole
83b7cb4ff9 Test updates. 2014-12-20 15:25:22 +01:00
James Cole
256dba66b2 Standard test database. 2014-12-20 15:04:26 +01:00
James Cole
6ac12f8ffa Updated codeception instructions. 2014-12-20 15:01:09 +01:00
James Cole
82e438d29b Updated tests. 2014-12-20 15:00:53 +01:00
James Cole
e86547645c Small bug fixes. 2014-12-20 07:33:59 +01:00
James Cole
8b901084fe Fixed the tests. 2014-12-19 21:36:53 +01:00
James Cole
1a0cbbdb31 Removed previous warning suppressions. 2014-12-19 21:18:42 +01:00
James Cole
30ac62ffb7 All kinds of code cleanup, mostly to get some mess detection fixed. 2014-12-19 20:47:33 +01:00
James Cole
8ab294e90b Move budget / category save. 2014-12-18 19:53:06 +01:00
James Cole
f5edb15f43 Fix bug in create transaction with cash account. 2014-12-18 19:51:08 +01:00
James Cole
eed6107ce7 Revamp migrations. 2014-12-18 19:01:00 +01:00
James Cole
d49dc599a2 Removed references to components. 2014-12-17 21:32:27 +01:00
James Cole
3c5179f145 Removed repair route [skip ci] 2014-12-17 21:21:08 +01:00
James Cole
067d17c09c New repair route [skip ci] 2014-12-17 21:20:23 +01:00
James Cole
4c88c9af86 Fix. [skip ci] 2014-12-17 20:54:33 +01:00
James Cole
1c84afe186 Temporary repair route to fix stuff [skip ci] 2014-12-17 20:52:08 +01:00
James Cole
9d4c4be468 Removed single table inheritance. 2014-12-17 20:47:46 +01:00
James Cole
de7db8db78 Slightly extended tests. 2014-12-16 21:41:16 +01:00
James Cole
407ba4dd6d Merge branch 'develop' of https://github.com/JC5/firefly-iii into develop 2014-12-16 20:26:51 +01:00
James Cole
5135be3000 Expanded test coverage. 2014-12-16 20:25:24 +01:00
James Cole
b8ab7d1a14 Update README.md 2014-12-16 09:15:04 +01:00
James Cole
6211fd8496 Update README.md
Added new badge.
2014-12-16 09:13:29 +01:00
James Cole
a4f273b48b Updated ignore file [skip ci] 2014-12-16 07:09:08 +01:00
James Cole
68d820a97c Attempt #5 for coveralls. 2014-12-16 07:03:52 +01:00
James Cole
ebadfd6358 Attempt #4, disable phpbrowser. 2014-12-16 06:53:07 +01:00
James Cole
cf93a88adc Attempt #3 2014-12-16 06:48:53 +01:00
James Cole
bd2c4252bb Attempt #2. 2014-12-15 20:56:18 +01:00
James Cole
84e7af04b9 Attempt to fix the tests over at Travis. 2014-12-15 20:38:20 +01:00
James Cole
37c63bc6b5 Add some tests. 2014-12-15 20:24:19 +01:00
James Cole
e7d3716549 Universal database stuff. 2014-12-15 20:01:33 +01:00
James Cole
73bc5372c0 Update migrations to include index. 2014-12-15 19:48:59 +01:00
James Cole
b999a8f0fb Some cleaning up. About to release 3.2.1 2014-12-15 19:39:01 +01:00
James Cole
16678aa5e1 Fixed bugs! 2014-12-15 18:16:48 +01:00
James Cole
f9ab49911d Bug fix where the account's balance would be cached when it shouldn't. 2014-12-15 18:03:16 +01:00
James Cole
3fabe2e9fb Small bug fix. 2014-12-15 07:24:01 +01:00
James Cole
9a8a3e94d6 Fix a chart. 2014-12-14 21:27:13 +01:00
James Cole
32ef2ef801 Renamed a table, added a bug fix. 2014-12-14 21:24:20 +01:00
James Cole
76cd3d35e2 Forgot some routes & filters. 2014-12-14 20:41:43 +01:00
James Cole
900dea2c66 Code cleanup. 2014-12-14 20:40:02 +01:00
James Cole
8e6ca0dd05 Some cleaning up. 2014-12-13 23:40:25 +01:00
James Cole
4b4ad7f1a8 Moved all references. 2014-12-13 22:54:52 +01:00
James Cole
21a0a5d573 Remapped all library classes. 2014-12-13 22:11:51 +01:00
James Cole
3cfa3f3b27 Code cleanup. 2014-12-13 21:59:02 +01:00
James Cole
c77b43458e Removed some charts, removed lots of dead code. 2014-12-13 20:03:44 +01:00
James Cole
9ab0a83f7c Default value for when session is empty. 2014-12-13 13:07:32 +01:00
James Cole
d3cda8811d Added some new tests. 2014-12-13 13:07:12 +01:00
James Cole
55740c0d97 Add c3.php to repository. 2014-12-13 09:54:32 +01:00
James Cole
c0a524c8a3 Add debug info. 2014-12-13 09:51:19 +01:00
James Cole
e51c2d10f0 Generate coverage. 2014-12-13 09:39:11 +01:00
James Cole
7af55b7268 Updated some tests, fixed some bugs. 2014-12-13 09:36:30 +01:00
James Cole
7350b1da1b Cleanup and added todo's 2014-12-12 16:22:16 +01:00
James Cole
136adbe723 Some cleanup and a small bug fix. 2014-12-12 07:42:38 +01:00
James Cole
cb2863eaf3 Cleaned up the budget controller. 2014-12-12 07:13:40 +01:00
James Cole
d054f9b92f Added composer.lock. 2014-12-10 19:15:14 +01:00
James Cole
9c83c18137 Fixed some query-heavy things in the report controller. 2014-12-09 18:24:53 +01:00
James Cole
999a7481e4 Removed references to the field "migrated". 2014-12-09 06:37:36 +01:00
James Cole
a3b684b4ed Merge branch 'release/3.2.0'
Conflicts:
	app/config/app.php
2014-12-08 20:46:23 +01:00
James Cole
cb312ca025 Remove packages only found in development. 2014-12-08 20:44:06 +01:00
James Cole
1335a52db3 Remove packages only found in development. 2014-12-08 20:27:33 +01:00
James Cole
727221e2cb Cleanup migrations. 2014-12-08 06:57:12 +01:00
James Cole
360f286ed3 Some cleanup. 2014-12-07 20:45:52 +01:00
James Cole
6aecd77b77 New stuff! 2014-12-07 15:37:53 +01:00
James Cole
ca85cab6fb Merge branch 'release/3.1.6' 2014-12-06 22:29:17 +01:00
James Cole
742479bb01 Update for coveralls. 2014-12-06 22:12:02 +01:00
James Cole
68e54a9297 Include coveralls. 2014-12-06 22:04:29 +01:00
James Cole
056d83eda4 Fixed the codeception command line 2014-12-06 21:59:03 +01:00
James Cole
42ec55d0db Upgrade to php 5.6 2014-12-06 21:53:09 +01:00
James Cole
c89bd89d9a Include codeception in travis. 2014-12-06 21:52:39 +01:00
James Cole
31a0be5bb4 All kinds of cleanup. 2014-12-06 21:48:23 +01:00
James Cole
07610ae8fb All kinds of new stuff for Codeception, which isn't working at ALL 2014-12-06 19:47:43 +01:00
James Cole
dbc95dd878 Cleanup. 2014-12-06 17:53:25 +01:00
James Cole
792e8a9947 Start with code cleanup. 2014-12-06 17:45:29 +01:00
James Cole
d774cde109 Add soft deletes. 2014-12-06 17:37:05 +01:00
James Cole
cc111d14b0 Lots of cleanup and formatting. 2014-12-06 17:34:39 +01:00
James Cole
bb3ba42ce2 Replaced Ardent with another package. 2014-12-06 12:12:55 +01:00
James Cole
f4ecf2d1aa Some new report data. Also, the report page now uses in excess of 3000 queries. Lol 2014-12-06 09:16:54 +01:00
James Cole
1997666196 Update comment to match methods. 2014-12-05 22:50:26 +01:00
James Cole
3aa9057c5f Small fixes. 2014-12-05 22:06:33 +01:00
James Cole
834f8382e9 Added some todo's. 2014-12-05 21:45:48 +01:00
James Cole
357638a26c Also do some account meta on the create screen. 2014-12-05 21:44:01 +01:00
James Cole
919a0c01e4 Expand views and JS. 2014-12-05 21:39:48 +01:00
James Cole
6ff618e388 Expand models. 2014-12-05 21:39:34 +01:00
James Cole
ac765b7e4c Expand model to get meta data 2014-12-05 21:39:26 +01:00
James Cole
2134e87c31 Method to unrelate transactions. 2014-12-05 21:39:16 +01:00
James Cole
0d37288129 Expand account controller with meta data (edit / update routine). 2014-12-05 21:39:04 +01:00
James Cole
7cbd41137d New configuration. 2014-12-05 21:38:45 +01:00
James Cole
ba43d7063f New route to unrelate transactions. 2014-12-05 21:38:36 +01:00
James Cole
c9b2e29ba0 Manage related transactions. 2014-12-04 20:38:45 +01:00
James Cole
4720519aef Clean up models, fixed a bug. 2014-12-01 06:09:27 +01:00
James Cole
d7b0106e7d Expand code for reports. 2014-12-01 05:57:03 +01:00
James Cole
0a2cbaa047 Some new code, transaction groups among them. 2014-11-30 14:52:17 +01:00
James Cole
3e5f615ffc Expand bread crumbs to include opening balances. 2014-11-28 17:29:05 +01:00
James Cole
00dc73e6d9 Added all bread crumbs. 2014-11-28 16:35:11 +01:00
James Cole
aa5b9a1727 More bread crumbs. 2014-11-28 16:15:30 +01:00
James Cole
f63a287a6c More bread crumbs. 2014-11-28 16:09:18 +01:00
James Cole
b9d4c8dcd6 More bread crumbs. 2014-11-28 16:04:06 +01:00
James Cole
94433f1714 Bread crumbs for categories. 2014-11-28 15:58:54 +01:00
James Cole
a4dd4358b4 Small fix for budget bread crumbs. 2014-11-28 15:53:50 +01:00
James Cole
4e79b43395 More bread crumbs. 2014-11-28 15:52:52 +01:00
James Cole
6bb54bfa85 More bread crumbs. 2014-11-28 15:46:44 +01:00
James Cole
0df6c3a8dc Some work on bread crumbs and reports. 2014-11-28 15:41:32 +01:00
James Cole
dc25086eab Updated composer.json 2014-11-28 14:55:59 +01:00
James Cole
3299188edf New report 2014-11-28 14:41:58 +01:00
James Cole
f6afb46f6f Some new help functions, some cleanup. 2014-11-28 14:12:16 +01:00
James Cole
98993cfa9b Updated hasManyThrough 2014-11-28 07:40:59 +01:00
James Cole
5a920d5efd Fix the view for accounts. 2014-11-28 07:40:04 +01:00
James Cole
935276af88 Updated accounts so actions will trigger cache flush. 2014-11-27 16:20:16 +01:00
James Cole
5a505c8469 Show everything on demand. 2014-11-27 15:42:07 +01:00
James Cole
2c2abe8b8e Fixed a bug where editing an expense account wasn't actually possible. 2014-11-27 15:37:31 +01:00
James Cole
638099d989 Fixed a bug where editing an expense account wasn't actually possible. 2014-11-27 15:36:37 +01:00
James Cole
0f32f6be4c Fixed a bug where editing an expense account wasn't actually possible. 2014-11-27 15:35:51 +01:00
James Cole
1f7c98bdcf Installed codeception. 2014-11-26 21:31:12 +01:00
James Cole
72068a4b78 Fixed the preselected piggy bank 2014-11-26 21:11:13 +01:00
James Cole
c8038e0774 A test to see if transfers and transactions and what-not can be related somehow. 2014-11-26 21:07:14 +01:00
James Cole
6b39beecb4 Expanded the report thing. 2014-11-26 20:46:21 +01:00
James Cole
b1ba64db12 New and updated views. 2014-11-26 17:20:43 +01:00
James Cole
ad53832766 Fixed a ORM thing. 2014-11-26 17:20:32 +01:00
James Cole
d5bffc8ed7 Removed debug messages. 2014-11-26 17:20:23 +01:00
James Cole
69b36ddd1d New methods. 2014-11-26 17:20:18 +01:00
James Cole
9f926394a6 Some new reports. 2014-11-26 17:20:05 +01:00
James Cole
1e7ecbdf9d Removed debug messages. 2014-11-26 17:19:59 +01:00
James Cole
beb8a461cf Some new reports. 2014-11-26 17:19:50 +01:00
James Cole
e235a57e2f Fixed a bug where the paginator for transactions would skip pages. 2014-11-26 09:43:21 +01:00
James Cole
114b27079e Added a routine that will cache stuff that costs a lot of queries. 2014-11-25 22:04:50 +01:00
James Cole
6e19bc01f5 Because this function generates a lot of queries, i've disabled it for now. 2014-11-25 21:15:49 +01:00
James Cole
f9dfdeafb3 Fixed a bug where deposits and withdrawals might show the wrong accounts when editing. 2014-11-25 21:09:52 +01:00
James Cole
f05d626e38 Mostly cleanup and bug fixes. 2014-11-25 21:04:00 +01:00
James Cole
918041258e Removed cleanup method. 2014-11-25 20:47:33 +01:00
James Cole
a5b13aa67f A very simple tool to do some cleanup. 2014-11-25 20:44:46 +01:00
James Cole
1383cbd4d5 Fixed a bug where a null transaction would be used anyway. 2014-11-25 20:22:32 +01:00
James Cole
e9b7e82aea Some visual updates to repeated expenses. 2014-11-24 23:02:08 +01:00
James Cole
fd6e7fc1ab Fixed a bug where the associated total amount for a bar would be too high. 2014-11-24 18:08:20 +01:00
James Cole
743deb4227 More stuff for repeated expenses. 2014-11-24 18:06:21 +01:00
James Cole
b051278d2e Expand repeated expenses. 2014-11-24 17:01:37 +01:00
James Cole
bfda4bc199 Lots of new stuff. 2014-11-24 10:12:34 +01:00
James Cole
4456ef2326 Some expansion on the index of repeated expenses, and the first reference to the show page. 2014-11-23 06:29:29 +01:00
James Cole
7336367eff Duh. Bug fixed. 2014-11-22 23:38:58 +01:00
James Cole
9cb6c7697e Some debug information. 2014-11-22 23:38:08 +01:00
James Cole
cd44f51072 Add some floatvals() just in case. 2014-11-22 23:37:03 +01:00
James Cole
d8976379b1 Some debug information. 2014-11-22 23:35:39 +01:00
James Cole
8aa847c718 Expanded the view. 2014-11-22 23:34:38 +01:00
James Cole
6691b238f7 New routes for repeated expenses. 2014-11-22 23:32:34 +01:00
James Cole
cca2758138 New views for the repeated expenses. 2014-11-22 23:32:24 +01:00
James Cole
4a74e68e31 Cleanup and expansion to accomodate repeated expenses. 2014-11-22 23:32:10 +01:00
James Cole
3d3842b9d6 Reinstated "periodshow" and some other stuff. 2014-11-22 23:31:55 +01:00
James Cole
9d889d05e4 Expanded Events to check on repeated expenses. 2014-11-22 23:31:40 +01:00
James Cole
9f920bcfe3 Expanded the transaction controller to show repeated expenses 2014-11-22 23:31:25 +01:00
James Cole
1bb49fa496 Expanded the repeated expenses. 2014-11-22 23:31:06 +01:00
James Cole
6b1d8d3aaa Added the possibility to save per quarter. 2014-11-22 23:30:58 +01:00
James Cole
c6b6ed7fa8 Removed a bunch of methods and code that wasn't used. Also added a repository for repeated expenses. 2014-11-22 23:30:45 +01:00
James Cole
34454261d2 First view for the return of the repeated expenses. 2014-11-22 17:17:28 +01:00
James Cole
ddf9f52737 Mar cleanup. 2014-11-22 08:21:10 +01:00
James Cole
10b969a074 New cleanup command for artisan 2014-11-22 08:17:37 +01:00
James Cole
5df0634380 Cleanup. 2014-11-22 07:34:08 +01:00
James Cole
f0f965421c Implemented some todo's. 2014-11-22 07:30:46 +01:00
James Cole
6381408fba Remove some often used long calls with shorter ones. 2014-11-21 19:33:09 +01:00
James Cole
43e738cb44 Remove todo 2014-11-21 19:19:06 +01:00
James Cole
6d4303aa3f Clone Carbon. 2014-11-21 19:18:53 +01:00
James Cole
13c2db5378 Removed some todo's 2014-11-21 19:18:44 +01:00
James Cole
36f6bda525 Fixed a namespace bug. 2014-11-21 11:21:48 +01:00
James Cole
78886e7b1f Updated git ignore. 2014-11-21 11:18:02 +01:00
James Cole
3dce194930 Use facades. 2014-11-21 11:12:22 +01:00
James Cole
ec776bb6eb Add some hasManyThrough references 2014-11-21 11:11:52 +01:00
James Cole
243d942a6e Remove unused library 2014-11-21 11:11:14 +01:00
James Cole
ea6aba62c4 Remove unused code. 2014-11-21 11:11:03 +01:00
James Cole
73743721b1 Fixed a bug where a non-matching journal would keep its recurring transaction. 2014-11-20 11:36:53 +01:00
James Cole
61eb5b341d Update piggy banks repetitions when the piggy bank is edited. 2014-11-20 11:19:35 +01:00
James Cole
d758f72393 Better visualisation in the budget charts. 2014-11-20 11:15:00 +01:00
James Cole
1b1367f4c2 Make sure the progress bar has a minimal width to improve readability. 2014-11-20 11:10:42 +01:00
James Cole
07388dd58a Ability to dismiss reminders, added some logic to pre fill transaction form. 2014-11-20 07:51:01 +01:00
James Cole
359c71ef2f Fixed a bug where the reminders would be created inactive. 2014-11-20 07:41:48 +01:00
James Cole
93d4d3df1d Wrong column names. 2014-11-20 07:41:30 +01:00
James Cole
d3a7596be2 A fix for a bug that would prevent both the category and the budget to be updated. 2014-11-20 07:12:41 +01:00
James Cole
114d3812cc Some logging. 2014-11-19 21:22:21 +01:00
James Cole
b2d4dcfbf1 Also catch transaction journal updates. 2014-11-19 21:19:13 +01:00
James Cole
0baf8f6d18 First attempt at testing the home controller. 2014-11-19 21:18:29 +01:00
James Cole
2f8e3a0707 Display bug in recurring transactions. 2014-11-19 21:18:16 +01:00
James Cole
d7a4bf22c6 Scan transaction journals for recurring transactions on store. 2014-11-19 21:18:06 +01:00
James Cole
0c2f9d22b9 With no category, the transaction journal store procedure would fail. 2014-11-19 21:17:21 +01:00
James Cole
e75c5aac49 A fix for the phpunit coverage. 2014-11-19 21:16:48 +01:00
James Cole
77e5024f54 Fixed a display bug. I commented this out, but no idea why. 2014-11-19 21:16:23 +01:00
James Cole
7329c0b200 All of this should contain one working test. 2014-11-18 10:33:38 +01:00
James Cole
0afe3c48a1 Fixed some things so coveralls will fire. 2014-11-18 10:18:50 +01:00
James Cole
1ab5e923bc Removed codeception. 2014-11-18 10:11:31 +01:00
James Cole
90b3bd77e7 Empty tests. 2014-11-18 10:11:18 +01:00
James Cole
9c60443f97 Clean up and added some TODO's. 2014-11-18 09:47:50 +01:00
James Cole
058e5602a3 For consistency, renamed some events. 2014-11-18 09:41:43 +01:00
James Cole
eebac2a66d Some formatting, cleanup, and a new chart. 2014-11-18 09:37:54 +01:00
James Cole
7e8f5c9548 Expanded the selection of reminders. 2014-11-18 01:53:52 +01:00
James Cole
d34b49bd48 Fixed a bug where the end date would be incorrectly calculated. 2014-11-18 01:52:08 +01:00
James Cole
ccffae287d Fixed a bug where the end date would be incorrectly calculated. 2014-11-18 01:51:15 +01:00
James Cole
ad69011ac5 Support 'month' as well as 'monthly'. 2014-11-17 23:09:52 +01:00
James Cole
f8ea0f971d This should fix reminders! 2014-11-17 23:08:36 +01:00
James Cole
9918410954 Implemented a proper way of generating reminders (we hope). 2014-11-17 22:32:55 +01:00
James Cole
4f4e6fac16 Fixed a bug where limits and limit repetitions would not be updated and/or created because of double post calls and missing events. 2014-11-17 21:50:11 +01:00
James Cole
15e99bd672 Removed some old code, added todo's. 2014-11-17 20:55:31 +01:00
James Cole
696e9a6fde Some general cleaning up. 2014-11-17 20:45:55 +01:00
James Cole
36cbb3d71f Added some code for reminders but most of its commented out. 2014-11-17 20:18:14 +01:00
Sander Dorigo
f69598c6aa Lots of work on the reminders. 2014-11-17 16:14:28 +01:00
Sander Dorigo
5fc31f3c1e First attempt at generating and showing reminders. 2014-11-17 10:10:57 +01:00
Sander Dorigo
6581ee0ee0 Fixed some more menu stuff. 2014-11-17 09:40:04 +01:00
James Cole
69e7501d47 Start with cleaning up the menu. 2014-11-17 08:20:05 +01:00
James Cole
314abbea8b Code cleanup. 2014-11-17 07:33:18 +01:00
James Cole
82c9a75578 Expand piggy banks 2014-11-16 22:55:34 +01:00
James Cole
651101912c Route for chart. 2014-11-16 20:05:03 +01:00
James Cole
fb0d463040 Chart for piggy banks 2014-11-16 20:03:53 +01:00
James Cole
8c254554eb Display bug for piggy banks with no reminders. 2014-11-16 10:36:23 +01:00
James Cole
2d9c89375a New chart and lots of stuff for piggy banks 2014-11-16 10:31:19 +01:00
James Cole
61aba29df7 More stuffs. Too lazy to explain. 2014-11-15 11:36:27 +01:00
James Cole
8c949e6190 Events that keep track of piggy bank money add/remove 2014-11-15 09:32:25 +01:00
James Cole
6eb9188690 Cleaned up preferences view. 2014-11-15 09:23:07 +01:00
James Cole
6832f2ebd0 Lots of code cleanup. 2014-11-15 07:46:01 +01:00
James Cole
3e02b50ea1 All kinds of todo items because otherwise I'd forget them. 2014-11-14 19:58:01 +01:00
James Cole
7b7743c03e Fixed some bugs 2014-11-14 19:33:50 +01:00
James Cole
de20563275 Removed all event triggers. 2014-11-14 19:33:40 +01:00
James Cole
9e720c3a38 Some view fixes. 2014-11-14 14:33:41 +01:00
James Cole
54685c1f5f Some new lists for recurring transactions. 2014-11-14 12:54:49 +01:00
James Cole
eb8f8fa935 Expanded on categories. 2014-11-14 11:56:45 +01:00
James Cole
9adbbd872c New chart for budgets. 2014-11-14 11:43:08 +01:00
James Cole
4bd38f97a2 Whoops. But not to worry, changed it already. 2014-11-14 10:41:35 +01:00
James Cole
78ab1e200a Remove transactions now works. 2014-11-14 10:39:34 +01:00
James Cole
11280e473d Catch broken journals. 2014-11-14 10:37:19 +01:00
James Cole
f9750a64f8 Fixed transactions lists. 2014-11-14 10:28:18 +01:00
James Cole
ac2ab65471 Got up to categories with the new tables. 2014-11-14 10:17:12 +01:00
James Cole
0530c0402c First full transaction list (again) and removed some google table references. 2014-11-14 09:34:53 +01:00
James Cole
a58a560bbb Fixed the tables (again) for account and for index. 2014-11-14 09:07:13 +01:00
James Cole
96ab112b22 Removed most, if not all, references to Google Charts (the tables part). 2014-11-14 08:52:58 +01:00
James Cole
b388dcc7d4 First attempt at generating proper paging google tables. However, somehow they are kind of messed up, so I'm probably going to drop this. 2014-11-14 08:40:16 +01:00
James Cole
f511a25c94 Added the input when creating new transactions. 2014-11-13 21:27:50 +01:00
James Cole
58d8b6f95b Fixed the charts, added some todo items. 2014-11-13 21:11:00 +01:00
James Cole
953d68c3a2 Build some transaction handling. 2014-11-13 17:01:09 +01:00
James Cole
9e2f7af59b New route for table. 2014-11-13 16:14:07 +01:00
James Cole
840dfa6696 Expanded recurring transactions. 2014-11-13 16:13:32 +01:00
James Cole
4a20c008ff Implementing recurring transactions. 2014-11-13 11:17:39 +01:00
James Cole
981ffe4194 Added a show piggybank view, removed some others. 2014-11-13 07:50:55 +01:00
James Cole
2597633b0e New migration and code cleanup. 2014-11-13 07:25:47 +01:00
James Cole
71d174d765 Code clean up and reformat. 2014-11-12 22:37:44 +01:00
James Cole
4aa9a04516 Code clean up and reformat. 2014-11-12 22:37:09 +01:00
James Cole
258d6a1688 Code clean up and reformat. 2014-11-12 22:36:02 +01:00
James Cole
2e2c12d6a4 General clean up. 2014-11-12 22:21:48 +01:00
James Cole
44d189d7d3 Fixed a bug where the transaction list was a giant mess. 2014-11-12 21:19:31 +01:00
James Cole
ab508a3d9e Recreated the JSON controller to fix auto-complete forms. 2014-11-12 20:52:34 +01:00
James Cole
4e166c7d2e This should fix the transactions again. 2014-11-12 20:46:55 +01:00
Sander Dorigo
7f175a4870 Some more work on the transactions. 2014-11-12 15:34:32 +01:00
Sander Dorigo
0a627f6f9e More work done for the transaction controller. 2014-11-12 15:22:01 +01:00
Sander Dorigo
d34cc65984 Start cleaning up transactions controller. 2014-11-12 14:38:32 +01:00
Sander Dorigo
78d034d366 There's a giant mix brewing between "old" code, bad code and not implemented exceptions. I suspect the next change will be to cut out all old stuff, throw a lot of NotImplementedExceptions and get going. 2014-11-12 10:54:53 +01:00
James Cole
638fa9005f Excluded more files from the "old" libraries and included new ones instead. This should greatly clean up the code base. 2014-11-12 07:31:48 +01:00
James Cole
5cb9907bf8 Various changes to support the removed old code. 2014-11-11 21:09:56 +01:00
Sander Dorigo
f08fcc36fb Half-way through with some cleaning up. 2014-11-11 18:16:59 +01:00
Sander Dorigo
d231cd9f61 Added the homestead configuration because it's not really secret. 2014-11-11 07:35:00 +01:00
Sander Dorigo
86a586f866 Ignore homestead configuration. 2014-11-11 07:26:16 +01:00
Sander Dorigo
9d4cba1620 Fixed some initial startup bugs when working with Homestead. 2014-11-11 07:20:52 +01:00
Sander Dorigo
e9afd55e9d Updated the default user seeder. 2014-11-10 22:36:25 +01:00
Sander Dorigo
9fa326f630 First attempt at unifying code for categories and budgets, which are basically the same thing. 2014-11-10 21:55:22 +01:00
Sander Dorigo
af9473c126 Fixed some bugs in various controllers and started rebuilding the category controller. 2014-11-10 19:03:03 +01:00
Sander Dorigo
cb08df0770 I broke some stuff but it's fixed again. 2014-11-10 18:39:50 +01:00
Sander Dorigo
d49ca2eb11 Merge branch 'master' of https://github.com/JC5/firefly-iii 2014-11-10 18:39:06 +01:00
Sander Dorigo
a3f8841ec3 I have no idea what's happening! 2014-11-10 18:38:58 +01:00
Sander Dorigo
fd678c286d Some cleanup. 2014-11-10 18:37:25 +01:00
Sander Dorigo
2a3f9b621b Removed unused imports. 2014-11-10 18:36:25 +01:00
Sander Dorigo
359e1b3943 Cleanup all models and migrations. 2014-11-10 18:33:00 +01:00
Sander Dorigo
754336b3cf Merge branch 'develop' of https://github.com/JC5/firefly-iii 2014-11-10 11:40:16 +01:00
James Cole
4918f1c4cb Merge pull request #31 from sonikarc/develop
[Fixes #21] Change the majority of View::share to View::make()->with()
2014-11-10 10:37:49 +01:00
Sander Dorigo
5d5e308942 Updated read me. 2014-11-10 07:55:52 +01:00
Stewart Malik
6a18f81cec Merge branch 'develop' of https://github.com/sonikarc/firefly-iii into develop 2014-11-09 16:01:20 +00:00
Stewart Malik
1ff135d172 [Fixes #21] Change the majority of View::share to View::make()->with() 2014-11-10 02:27:19 +10:30
Sander Dorigo
e666e5e9e3 Clean up composer.json 2014-11-09 11:32:18 +01:00
Sander Dorigo
9874e77ddf Remove ignore instructions. 2014-11-09 11:30:00 +01:00
Sander Dorigo
27e3ec693a New screenshot. 2014-11-09 11:20:54 +01:00
Sander Dorigo
6bb1415ad7 Updated readme file. 2014-11-09 11:10:57 +01:00
Sander Dorigo
83594e6f1f Merge branch 'release/3.1.5' 2014-11-09 11:09:38 +01:00
Sander Dorigo
0f6008705c Added a screenshot 2014-11-09 11:08:53 +01:00
Sander Dorigo
c58b653bb7 Updated read me file. 2014-11-09 11:01:57 +01:00
Sander Dorigo
f69b6f9b4e New chart for budget-overview. 2014-11-09 08:42:09 +01:00
Sander Dorigo
7750b06476 Added a "spent"-bar in budgets. 2014-11-09 08:02:47 +01:00
Sander Dorigo
873384a34b Built the 'show'-view for budgets. 2014-11-08 19:11:51 +01:00
Sander Dorigo
ac299e7279 More rounding. 2014-11-08 11:38:50 +01:00
Sander Dorigo
7895d7f5d0 Format amount. 2014-11-08 11:37:55 +01:00
Sander Dorigo
fe05d218fc Allow piggy bank edit/update. 2014-11-08 11:36:20 +01:00
Sander Dorigo
8196313ac0 Optimized queries. 2014-11-08 10:16:12 +01:00
Sander Dorigo
6d8f84654f Also add stuff not in budgets. 2014-11-08 09:15:03 +01:00
Sander Dorigo
ab4f34a96b Extended reports 2014-11-07 22:06:30 +01:00
Sander Dorigo
139d985904 All kinds of fixes and things. I should really start organizing. 2014-11-07 11:18:06 +01:00
Sander Dorigo
44705f0e18 Some bugfixes and cleanup. 2014-11-06 20:33:37 +01:00
Sander Dorigo
ddea7d696a Delete and update routines. 2014-11-06 07:38:15 +01:00
Sander Dorigo
f814f45e36 Test fix for budgeting. 2014-11-05 21:37:24 +01:00
Sander Dorigo
f7117d47c2 Whoops, bugfix. 2014-11-05 21:23:23 +01:00
Sander Dorigo
01b0a1058d Form fix. 2014-11-05 21:22:31 +01:00
Sander Dorigo
21f362c7b9 Lots of stuff for budgets, accounts and others! 2014-11-05 19:57:56 +01:00
Sander Dorigo
aaab7f8e0e Some fixes for budgets 2014-11-04 20:37:00 +01:00
Sander Dorigo
09e1f68c69 Font fix. 2014-11-02 21:26:41 +01:00
Sander Dorigo
03729aa5ae Chart cleanup 2014-11-02 21:24:50 +01:00
Sander Dorigo
ef39f31ea1 First reports. 2014-11-02 18:46:01 +01:00
Sander Dorigo
0f1437dd6a Delete piggy banks. 2014-11-02 16:47:01 +01:00
Sander Dorigo
03aac2f744 Implemented method stub. 2014-11-02 14:59:09 +01:00
Sander Dorigo
2f8b10e82c All kinds of new code, especially for the piggy banks. 2014-11-02 14:58:12 +01:00
Sander Dorigo
3231effd20 Cleanup and fix everything related to piggy banks. 2014-10-31 07:32:43 +01:00
Sander Dorigo
f7722c1189 Clean up piggy bank controller. 2014-10-30 19:26:52 +01:00
Sander Dorigo
70c2450ac4 Clean up the routes. 2014-10-30 19:26:43 +01:00
Sander Dorigo
2d5b0d0f99 Moved some stuff around. 2014-10-30 19:26:28 +01:00
Sander Dorigo
f0c0002a6d Some cleanup 2014-10-30 18:24:10 +01:00
Sander Dorigo
dd9f08d4fa New code for charts. 2014-10-30 18:12:27 +01:00
Sander Dorigo
de2e384225 Merge branch 'feature/google-charts' into develop
Conflicts:
	app/views/accounts/show.blade.php
2014-10-30 18:09:03 +01:00
Sander Dorigo
ffcd1fde0f Even more charts and tables. 2014-10-30 18:06:29 +01:00
Sander Dorigo
d5e1da5948 Some more stats on the piggy banks. 2014-10-29 12:39:15 +01:00
Sander Dorigo
ad479a5c7f Added some placeholders. 2014-10-29 12:33:19 +01:00
Sander Dorigo
0707603b63 Add buttons and a placeholder. 2014-10-29 12:26:26 +01:00
Sander Dorigo
2f9c383004 All new stufs! 2014-10-29 10:30:52 +01:00
Sander Dorigo
8ad0d7af93 Update views and CSS 2014-10-28 16:29:31 +01:00
Sander Dorigo
9b4391c0bf Initial set of code required for GCharts. 2014-10-28 16:29:24 +01:00
Sander Dorigo
da7802a0a4 New controller, updated composer. 2014-10-28 16:15:16 +01:00
Sander Dorigo
9c69949e8c Added edit and new buttons. 2014-10-28 15:59:10 +01:00
Sander Dorigo
b1d7a9451a Cleaner piggybank view. 2014-10-28 11:25:22 +01:00
Sander Dorigo
004488d453 New todo items. 2014-10-28 11:10:40 +01:00
Sander Dorigo
fc91372dd0 Merge branch 'feature/account-cleanup' into develop 2014-10-28 09:33:54 +01:00
Sander Dorigo
5970a9dc91 Merge branch 'master' of https://github.com/JC5/firefly-iii into feature/account-cleanup 2014-10-28 09:32:22 +01:00
Sander Dorigo
264cac4f9b Merge branch 'develop' of https://github.com/JC5/firefly-iii into feature/account-cleanup 2014-10-28 09:32:16 +01:00
Sander Dorigo
633328a965 Removed references to sankey. 2014-10-28 09:29:47 +01:00
Sander Dorigo
4d4b62a766 Add todo-text 2014-10-28 09:28:14 +01:00
Sander Dorigo
aeb2c7deeb Remove function. 2014-10-28 09:27:46 +01:00
Sander Dorigo
c323942d92 Add placeholder. 2014-10-28 09:27:36 +01:00
Sander Dorigo
a0afa25145 Cleanup and prep-work for new charts (will be a new feature). 2014-10-28 09:25:29 +01:00
Sander Dorigo
4533b46436 Updated menu logic 2014-10-28 06:00:41 +01:00
Sander Dorigo
e5f8db78f9 New views and layouts for the account controller. 2014-10-28 05:59:14 +01:00
Sander Dorigo
899f61671f All new library set for the account controller (and others). 2014-10-28 05:58:48 +01:00
Sander Dorigo
d84d88cc10 Completely revamped the account controller. 2014-10-28 05:58:32 +01:00
Sander Dorigo
97e7ac4052 New routes for accounts. 2014-10-28 05:58:10 +01:00
Sander Dorigo
ba4ffa44d2 Fixed a spelling error. 2014-10-27 21:28:58 +01:00
Sander Dorigo
07caeccf68 Code formatting and a reference to a new form element. 2014-10-27 21:28:30 +01:00
Sander Dorigo
d54832f61f Code formatting. 2014-10-27 21:28:15 +01:00
Sander Dorigo
b212753633 A new form field. 2014-10-27 21:27:45 +01:00
James Cole
f38d80cbf5 Update composer.json 2014-10-23 16:42:11 +02:00
James Cole
8bea1acd8e Update composer.json 2014-10-23 16:42:01 +02:00
Sander Dorigo
42458ce11d Merge branch 'release/3.1.4' 2014-10-14 07:32:00 +02:00
Sander Dorigo
aceb683d07 Remove chart when nothing to show. 2014-10-14 07:27:06 +02:00
Sander Dorigo
b7517b49ed Expand match to include expense account. 2014-10-14 07:24:59 +02:00
Sander Dorigo
849b711b79 Recycle code instead of copy pasting. 2014-10-14 07:24:41 +02:00
Sander Dorigo
25585b28c7 Removed "date in the future" demand. 2014-10-14 07:24:27 +02:00
Sander Dorigo
073da8fb2a Small layout changes. 2014-10-13 20:47:36 +02:00
Sander Dorigo
a787ff3f3c Merge branch 'release/3.1.3' 2014-10-13 19:13:44 +02:00
Sander Dorigo
733b6d7eb7 Expand the chart. 2014-10-13 18:50:37 +02:00
Sander Dorigo
36d8dee853 Building a chart for the recurring transactions. 2014-10-13 17:54:20 +02:00
Sander Dorigo
65a2e07d24 Cleaned out most of the "reminders" code. 2014-10-12 09:45:57 +02:00
Sander Dorigo
7c97c558ab No reference to reminders. 2014-10-12 09:41:10 +02:00
Sander Dorigo
a6bb61050c Remove piggy bank reminders. 2014-10-12 09:41:00 +02:00
Sander Dorigo
b184aa2315 No trigger for recurring transactions. 2014-10-12 09:39:40 +02:00
Sander Dorigo
e4595333e7 Do not destroy reminders since there aren't any. 2014-10-12 09:39:29 +02:00
Sander Dorigo
41dd139bde Trigger no longer fires or creates reminders for piggy banks. 2014-10-12 09:37:31 +02:00
Sander Dorigo
c577dd302a Removed unused reminder methods. 2014-10-12 09:36:24 +02:00
Sander Dorigo
0ab87de78b Removed unused routes. 2014-10-12 09:34:47 +02:00
Sander Dorigo
8a22509b41 Removed a no longer used view. 2014-10-12 09:34:30 +02:00
Sander Dorigo
b024c18441 Cleaned out the reminder controller. 2014-10-12 09:34:10 +02:00
Sander Dorigo
d9ac681a68 Bug fixes in recurring transaction matching. 2014-10-12 09:31:25 +02:00
Sander Dorigo
637a5579ec Small cleanup. 2014-10-12 09:29:19 +02:00
Sander Dorigo
4794156e80 Merge branch 'master' into develop 2014-10-12 08:20:31 +02:00
Sander Dorigo
5f4db7874c New view and what-not for feature. 2014-10-12 08:19:18 +02:00
Sander Dorigo
b4ea1839a5 Fixed some bugs in the recurring transaction match. 2014-10-12 08:03:35 +02:00
Sander Dorigo
6a6d889983 Merge branch 'release/3.1.1' 2014-10-12 07:39:27 +02:00
Sander Dorigo
81662473a6 Merge branch 'release/3.1' 2014-10-11 12:11:17 +02:00
502 changed files with 27061 additions and 20269 deletions

View File

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

15
.gitignore vendored
View File

@@ -1,10 +1,8 @@
/bootstrap/compiled.php
/vendor
composer.phar
composer.lock
.env.*.php
.env.php
.DS_Store
Thumbs.db
.idea/
tests/_output/*
@@ -14,3 +12,16 @@ index.html*
app/storage/firefly-export*
.vagrant
firefly-iii-import-*.json
tests/_output/*
testing.sqlite
_ide_helper_models.php
clean.sqlite
tests/acceptance/AcceptanceTester.php
tests/functional/FunctionalTester.php
tests/unit/UnitTester.php
pi.php
tests/_data/db.sqlite
tests/_data/dump.sql
db.sqlite_snapshot
c3.php
db.sqlite-journal

View File

@@ -2,12 +2,15 @@ language: php
php:
- 5.5
- 5.4
- hhvm
- 5.6
install:
- composer install
script:
- ./tests/_data/db.sh
- php vendor/bin/codecept build
- php vendor/bin/codecept run --coverage --coverage-xml
after_script:
- php vendor/bin/coveralls

View File

@@ -1,49 +1,54 @@
firefly-iii
Firefly III
===========
[![Build Status](https://travis-ci.org/JC5/firefly-iii.svg?branch=master)](https://travis-ci.org/JC5/firefly-iii)
![Still maintained?](http://stillmaintained.com/JC5/firefly-iii.png)
[![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)
[![Latest Stable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/stable.svg)](https://packagist.org/packages/grumpydictator/firefly-iii)
[![Total Downloads](https://poser.pugx.org/grumpydictator/firefly-iii/downloads.svg)](https://packagist.org/packages/grumpydictator/firefly-iii)
[![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 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
laptop and [Firefly II](https://github.com/JC5/Firefly) is live.
## Current features
- [A double-entry bookkeeping system](http://en.wikipedia.org/wiki/Double-entry_bookkeeping_system).
- [A double-entry bookkeeping system](http://en.wikipedia.org/wiki/Double-entry_bookkeeping_system);
- You can store, edit and remove withdrawals, deposits and transfers. This allows you full financial management;
- It's possible to create, change and manage money using _budgets_;
- Organize transactions using categories;
- Save towards a goal using piggy banks;
- Predict and anticipate large expenses using "repeated expenses" (ie. yearly taxes);
- Predict and anticipate bills using "recurring transactions" (rent for example).
- Predict and anticipate bills using "recurring transactions" (rent for example);
- View basic income / expense reports.
- Lots of help text in case you don't get it;
Everything is organised:
- Clear views that should show you how you're doing;
- Easy navigation through your records;
- Browse back and forth to see previous months or even years;
- Lots of help text in case you don't get it;
- Lots of charts because we all love them.
- Financial reporting showing you how well you are doing;
## Changes
Firefly III will feature, but does not feature yet:
- Financial reporting showing you how well you are doing;
- More control over other resources outside of personal finance
- Accounts shared with a partner (household accounts)
- Debts
- Credit cards
- More test-coverage (aka: actual test coverage);
- More test-coverage;
- Firefly will be able to split transactions; a single purchase can be split in multiple entries, for more fine-grained control.
- Firefly will be able to join transactions.
- Transfers and transactions are combined into one internal datatype which is more consistent with what you're actually doing: moving money from A to B. The fact that A or B or both are yours should not matter.
- Any other features I might not have thought of.
Some stuff has been removed:
@@ -51,14 +56,20 @@ Some stuff has been removed:
- The nesting of budgets, categories and beneficiaries is removed because it was pretty pointless.
- Firefly will not encrypt the content of the (MySQL) tables. Old versions of Firefly had this capability but it sucks when searching, sorting and organizing entries.
## Screenshots
![Index](http://i.imgur.com/TkZNIer.png)
![Accounts](http://i.imgur.com/YE8WavP.png)
![Budgets](http://i.imgur.com/Go0M6Nd.png)
![Reports](http://i.imgur.com/EnEIyQI.png)
## Current state
I have the basics up and running. Test coverage is currently non-existent.
I have the basics up and running. Test coverage is currently coming, slowly.
Although I have not checked extensively, some forms and views have CSRF vulnerabilities. This is because not all
views escape all characters by default. Will be fixed.
The current layout / look & feel is a pretty basic Bootstrap3 template. I am currently working on a more consistent,
expanded layout which will feature shiny AJAX things and data tables and all the Web 3.0 goodies you've come to expect
from social media sites.
Questions, ideas or other things to contribute? [Let me know](https://github.com/JC5/firefly-iii/issues/new)!
Questions, ideas or other things to contribute? [Let me know](https://github.com/JC5/firefly-iii/issues/new)!

View File

@@ -0,0 +1,606 @@
# ************************************************************
# 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,7 +1,369 @@
<?php
use Carbon\Carbon;
use DaveJamesMiller\Breadcrumbs\Generator;
use FireflyIII\Exception\FireflyException;
/*
* Back home.
*/
Breadcrumbs::register('home', function($breadcrumbs) {
$breadcrumbs->push('Home', route('index'));
});
Breadcrumbs::register(
'home',
function (Generator $breadcrumbs) {
$breadcrumbs->push('Home', route('index'));
}
);
// accounts
Breadcrumbs::register(
'accounts.index', function (Generator $breadcrumbs, $what) {
$breadcrumbs->parent('home');
$breadcrumbs->push(ucfirst(e($what)) . ' accounts', route('accounts.index', $what));
}
);
Breadcrumbs::register(
'accounts.show', function (Generator $breadcrumbs, \Account $account) {
switch ($account->accountType->type) {
default:
throw new FireflyException('Cannot handle account type "' . e($account->accountType->type) . '"');
break;
case 'Default account':
case 'Asset account':
$what = 'asset';
break;
case 'Cash account':
$what = 'cash';
break;
case 'Expense account':
case 'Beneficiary account':
$what = 'expense';
break;
case 'Revenue account':
$what = 'revenue';
break;
}
$breadcrumbs->parent('accounts.index', $what);
$breadcrumbs->push(e($account->name), route('accounts.show', $account->id));
}
);
Breadcrumbs::register(
'accounts.delete', function (Generator $breadcrumbs, \Account $account) {
$breadcrumbs->parent('accounts.show', $account);
$breadcrumbs->push('Delete ' . e($account->name), route('accounts.delete', $account->id));
}
);
Breadcrumbs::register(
'accounts.edit', function (Generator $breadcrumbs, \Account $account) {
$breadcrumbs->parent('accounts.show', $account);
$breadcrumbs->push('Edit ' . e($account->name), route('accounts.edit', $account->id));
}
);
// budgets.
Breadcrumbs::register(
'budgets.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Budgets', route('budgets.index'));
}
);
Breadcrumbs::register(
'budgets.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('budgets.index');
$breadcrumbs->push('Create new budget', route('budgets.create'));
}
);
Breadcrumbs::register(
'budgets.edit', function (Generator $breadcrumbs, Budget $budget) {
$breadcrumbs->parent('budgets.show', $budget);
$breadcrumbs->push('Edit ' . e($budget->name), route('budgets.edit', $budget->id));
}
);
Breadcrumbs::register(
'budgets.delete', function (Generator $breadcrumbs, Budget $budget) {
$breadcrumbs->parent('budgets.show', $budget);
$breadcrumbs->push('Delete ' . e($budget->name), route('budgets.delete', $budget->id));
}
);
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)) {
$breadcrumbs->push(
DateKit::periodShow($repetition->startdate, $repetition->budgetlimit->repeat_freq), route('budgets.show', $budget->id, $repetition->id)
);
}
}
);
// categories
Breadcrumbs::register(
'categories.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Categories', route('categories.index'));
}
);
Breadcrumbs::register(
'categories.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('categories.index');
$breadcrumbs->push('Create new category', route('categories.create'));
}
);
Breadcrumbs::register(
'categories.edit', function (Generator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.show', $category);
$breadcrumbs->push('Edit ' . e($category->name), route('categories.edit', $category->id));
}
);
Breadcrumbs::register(
'categories.delete', function (Generator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.show', $category);
$breadcrumbs->push('Delete ' . e($category->name), route('categories.delete', $category->id));
}
);
Breadcrumbs::register(
'categories.show', function (Generator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.index');
$breadcrumbs->push(e($category->name), route('categories.show', $category->id));
}
);
// piggy banks
Breadcrumbs::register(
'piggyBanks.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Piggy banks', route('piggyBanks.index'));
}
);
Breadcrumbs::register(
'piggyBanks.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('piggyBanks.index');
$breadcrumbs->push('Create new piggy bank', route('piggyBanks.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));
}
);
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));
}
);
Breadcrumbs::register(
'piggyBanks.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('piggyBanks.index');
$breadcrumbs->push(e($piggyBank->name), route('piggyBanks.show', $piggyBank->id));
}
);
// preferences
Breadcrumbs::register(
'preferences', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Preferences', route('preferences'));
}
);
// profile
Breadcrumbs::register(
'profile', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Profile', route('profile'));
}
);
Breadcrumbs::register(
'change-password', function (Generator $breadcrumbs) {
$breadcrumbs->parent('profile');
$breadcrumbs->push('Change your password', route('change-password'));
}
);
// bills
Breadcrumbs::register(
'bills.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Bills', route('bills.index'));
}
);
Breadcrumbs::register(
'bills.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('bills.index');
$breadcrumbs->push('Create new bill', route('bills.create'));
}
);
Breadcrumbs::register(
'bills.edit', function (Generator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.show', $bill);
$breadcrumbs->push('Edit ' . e($bill->name), route('bills.edit', $bill->id));
}
);
Breadcrumbs::register(
'bills.delete', function (Generator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.show', $bill);
$breadcrumbs->push('Delete ' . e($bill->name), route('bills.delete', $bill->id));
}
);
Breadcrumbs::register(
'bills.show', function (Generator $breadcrumbs, Bill $bill) {
$breadcrumbs->parent('bills.index');
$breadcrumbs->push(e($bill->name), route('bills.show', $bill->id));
}
);
// reminders
Breadcrumbs::register(
'reminders.show', function (Generator $breadcrumbs, Reminder $reminder) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Reminder #' . $reminder->id, route('reminders.show', $reminder->id));
}
);
// repeated expenses
Breadcrumbs::register(
'repeated.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Repeated expenses', route('repeated.index'));
}
);
Breadcrumbs::register(
'repeated.create', function (Generator $breadcrumbs) {
$breadcrumbs->parent('repeated.index');
$breadcrumbs->push('Create new repeated expense', route('repeated.create'));
}
);
Breadcrumbs::register(
'repeated.edit', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('repeated.show', $piggyBank);
$breadcrumbs->push('Edit ' . e($piggyBank->name), route('repeated.edit', $piggyBank->id));
}
);
Breadcrumbs::register(
'repeated.delete', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('repeated.show', $piggyBank);
$breadcrumbs->push('Delete ' . e($piggyBank->name), route('repeated.delete', $piggyBank->id));
}
);
Breadcrumbs::register(
'repeated.show', function (Generator $breadcrumbs, PiggyBank $piggyBank) {
$breadcrumbs->parent('repeated.index');
$breadcrumbs->push(e($piggyBank->name), route('repeated.show', $piggyBank->id));
}
);
// reports
Breadcrumbs::register(
'reports.index', function (Generator $breadcrumbs) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Reports', route('reports.index'));
}
);
Breadcrumbs::register(
'reports.year', function (Generator $breadcrumbs, Carbon $date) {
$breadcrumbs->parent('reports.index');
$breadcrumbs->push($date->format('Y'), route('reports.year', $date->format('Y')));
}
);
Breadcrumbs::register(
'reports.month', function (Generator $breadcrumbs, Carbon $date) {
$breadcrumbs->parent('reports.index');
$breadcrumbs->push('Monthly report for ' . $date->format('F Y'), route('reports.month', $date));
}
);
Breadcrumbs::register(
'reports.budget', function (Generator $breadcrumbs, Carbon $date) {
$breadcrumbs->parent('reports.index');
$breadcrumbs->push('Budget report for ' . $date->format('F Y'), route('reports.budget', $date));
}
);
// search
Breadcrumbs::register(
'search', function (Generator $breadcrumbs, $query) {
$breadcrumbs->parent('home');
$breadcrumbs->push('Search for "' . e($query) . '"', route('search'));
}
);
// transactions
Breadcrumbs::register(
'transactions.index', function (Generator $breadcrumbs, $what) {
$breadcrumbs->parent('home');
switch ($what) {
case 'expenses':
case 'withdrawal':
$subTitle = 'Expenses';
break;
case 'revenue':
case 'deposit':
$subTitle = 'Revenue, income and deposits';
break;
case 'transfer':
case 'transfers':
$subTitle = 'Transfers';
break;
case 'opening balance':
$subTitle = 'Opening balances';
break;
default:
throw new FireflyException('Cannot handle $what "' . e($what) . '" in bread crumbs');
}
$breadcrumbs->push($subTitle, route('transactions.index', $what));
}
);
Breadcrumbs::register(
'transactions.create', function (Generator $breadcrumbs, $what) {
$breadcrumbs->parent('transactions.index', $what);
$breadcrumbs->push('Create new ' .e($what), route('transactions.create', $what));
}
);
Breadcrumbs::register(
'transactions.edit', function (Generator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.show', $journal);
$breadcrumbs->push('Edit ' . e($journal->description), route('transactions.edit', $journal->id));
}
);
Breadcrumbs::register(
'transactions.delete', function (Generator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.show', $journal);
$breadcrumbs->push('Delete ' . e($journal->description), route('transactions.delete', $journal->id));
}
);
Breadcrumbs::register(
'transactions.show', function (Generator $breadcrumbs, TransactionJournal $journal) {
$breadcrumbs->parent('transactions.index', strtolower($journal->transactionType->type));
$breadcrumbs->push(e($journal->description), route('transactions.show', $journal->id));
}
);

76
app/commands/Cleanup.php Normal file
View File

@@ -0,0 +1,76 @@
<?php
use Illuminate\Console\Command;
/**
* Class Cleanup
*/
class Cleanup extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Clean caches, regenerate some stuff.';
/**
* The console command name.
*
* @var string
*/
protected $name = 'firefly:cleanup';
/**
*
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function fire()
{
$this->info('Start!');
Artisan::call('clear-compiled');
$this->info('Cleared compiled...');
Artisan::call('ide-helper:generate');
$this->info('IDE helper, done...');
Artisan::call('ide-helper:models');
$this->info('IDE models, done...');
Artisan::call('optimize');
$this->info('Optimized...');
Artisan::call('dump-autoload');
$this->info('Done!');
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
// ['example', InputArgument::REQUIRED, 'An example argument.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
// ['example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null],
];
}
}

View File

@@ -1,3 +1,4 @@
local/
laptop/
vagrant/
vagrant/
production/

View File

@@ -37,13 +37,11 @@ return [
'Illuminate\Validation\ValidationServiceProvider',
'Illuminate\View\ViewServiceProvider',
'Illuminate\Workbench\WorkbenchServiceProvider',
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
'Barryvdh\Debugbar\ServiceProvider',
'Firefly\Storage\StorageServiceProvider',
'Firefly\Helper\HelperServiceProvider',
'Firefly\Validation\ValidationServiceProvider',
//'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
//'Barryvdh\Debugbar\ServiceProvider',
'FireflyIII\FF3ServiceProvider',
'DaveJamesMiller\Breadcrumbs\ServiceProvider',
'TwigBridge\ServiceProvider'
'Grumpydictator\Gchart\GchartServiceProvider',
],
'manifest' => storage_path() . '/meta',
'aliases' => [
@@ -86,8 +84,7 @@ return [
'URL' => 'Illuminate\Support\Facades\URL',
'Validator' => 'Illuminate\Support\Facades\Validator',
'View' => 'Illuminate\Support\Facades\View',
'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade',
'Twig' => 'TwigBridge\Facade\Twig',
'Breadcrumbs' => 'DaveJamesMiller\Breadcrumbs\Facade'
],

View File

@@ -1,3 +1,3 @@
<?php
return [];
return [];

View File

@@ -1,4 +1,4 @@
<?php
return [
'import' => ''
];
];

View File

@@ -1,11 +1,15 @@
<?php
use Carbon\Carbon;
return [
'index_periods' => ['1D', '1W', '1M', '3M', '6M','1Y', 'custom'],
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
'piggybank_periods' => ['day', 'week', 'month', 'year'],
'periods_to_text' => [
'index_periods' => ['1D', '1W', '1M', '3M', '6M', '1Y', 'custom'],
'budget_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
'piggy_bank_periods' => [
'week' => 'Week',
'month' => 'Month',
'quarter' => 'Quarter',
'year' => 'Year'
],
'periods_to_text' => [
'weekly' => 'A week',
'monthly' => 'A month',
'quarterly' => 'A quarter',
@@ -13,7 +17,12 @@ return [
'yearly' => 'A year',
],
'range_to_text' => [
'accountRoles' => [
'defaultExpense' => 'Default expense account',
'sharedExpense' => 'Shared expense account'
],
'range_to_text' => [
'1D' => 'day',
'1W' => 'week',
'1M' => 'month',
@@ -21,15 +30,15 @@ return [
'6M' => 'half year',
'custom' => '(custom)'
],
'range_to_name' => [
'1D' => 'one day',
'1W' => 'one week',
'1M' => 'one month',
'3M' => 'three months',
'6M' => 'six months',
'1Y' => 'one year',
'range_to_name' => [
'1D' => 'one day',
'1W' => 'one week',
'1M' => 'one month',
'3M' => 'three months',
'6M' => 'six months',
'1Y' => 'one year',
],
'range_to_repeat_freq' => [
'range_to_repeat_freq' => [
'1D' => 'weekly',
'1W' => 'weekly',
'1M' => 'monthly',
@@ -37,4 +46,4 @@ return [
'6M' => 'half-year',
'custom' => 'monthly'
],
];
];

View File

@@ -0,0 +1,15 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Application Debug Mode
|--------------------------------------------------------------------------
|
| When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown.
|
*/
'debug' => true,
'log_level' => 'debug',
];

View File

@@ -0,0 +1,12 @@
<?php
return [
'driver' => 'file',
'path' => storage_path() . '/cache',
'connection' => null,
'table' => 'cache',
'memcached' => [
['host' => '127.0.0.1', 'port' => 11211, 'weight' => 100],
],
'prefix' => 'laravel',
];

View File

@@ -0,0 +1,37 @@
<?php
return [
'default' => 'mysql',
'connections' => [
'mysql' => [
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'homestead',
'username' => 'homestead',
'password' => 'secret',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
],
'sqlite' => [
'driver' => 'sqlite',
'database' => realpath(__DIR__.'/../../../tests/_data/testing.sqlite'),
'prefix' => ''
],
'pgsql' => [
'driver' => 'pgsql',
'host' => 'localhost',
'database' => 'homestead',
'username' => 'homestead',
'password' => 'secret',
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
],
],
];

View File

@@ -0,0 +1,13 @@
<?php
return [
'driver' => 'smtp',
'host' => 'smtp.gmail.com',
'port' => 587,
'from' => ['address' => '@gmail.com', 'name' => 'Firefly III'],
'encryption' => 'tls',
'username' => '@gmail.com',
'password' => '',
'sendmail' => '/usr/sbin/sendmail -bs',
'pretend' => false,
];

View File

@@ -2,14 +2,14 @@
use Illuminate\Support\Facades\Config;
return array(
return [
'enabled' => Config::get('app.debug'),
'enabled' => Config::get('app.debug'),
'storage' => array(
'storage' => [
'enabled' => true,
'path' => storage_path() . '/debugbar',
),
'path' => storage_path() . '/debugbar',
],
/*
|--------------------------------------------------------------------------
@@ -37,8 +37,8 @@ return array(
|
*/
'capture_ajax' => true,
'capture_ajax' => true,
/*
|--------------------------------------------------------------------------
| Capture Console Commands
@@ -59,7 +59,7 @@ return array(
|
*/
'collectors' => array(
'collectors' => [
'phpinfo' => true, // Php version
'messages' => true, // Messages
'time' => true, // Time Datalogger
@@ -78,7 +78,7 @@ return array(
'files' => false, // Show the included files
'config' => false, // Display config settings
'auth' => false, // Display Laravel authentication status
),
],
/*
|--------------------------------------------------------------------------
@@ -89,27 +89,27 @@ return array(
|
*/
'options' => array(
'auth' => array(
'options' => [
'auth' => [
'show_name' => false, // Also show the users name/email in the debugbar
),
'db' => array(
'with_params' => true, // Render SQL with the parameters substituted
'timeline' => false, // Add the queries to the timeline
),
'mail' => array(
],
'db' => [
'with_params' => true, // Render SQL with the parameters substituted
'timeline' => false, // Add the queries to the timeline
],
'mail' => [
'full_log' => false
),
'views' => array(
],
'views' => [
'data' => false, //Note: Can slow down the application, because the data can be quite large..
),
'route' => array(
],
'route' => [
'label' => true // show complete route on bar
),
'logs' => array(
],
'logs' => [
'file' => null
),
),
],
],
/*
|--------------------------------------------------------------------------
@@ -122,6 +122,6 @@ return array(
|
*/
'inject' => true,
'inject' => true,
);
];

View File

@@ -1,6 +1,6 @@
<?php
return array(
return [
/*
|--------------------------------------------------------------------------
@@ -11,7 +11,7 @@ return array(
|
*/
'filename' => '_ide_helper.php',
'filename' => '_ide_helper.php',
/*
|--------------------------------------------------------------------------
@@ -25,9 +25,9 @@ return array(
'include_helpers' => false,
'helper_files' => array(
base_path().'/vendor/laravel/framework/src/Illuminate/Support/helpers.php',
),
'helper_files' => [
base_path() . '/vendor/laravel/framework/src/Illuminate/Support/helpers.php',
],
/*
|--------------------------------------------------------------------------
@@ -39,9 +39,9 @@ return array(
|
*/
'model_locations' => array(
'model_locations' => [
'app/models',
),
],
/*
@@ -53,14 +53,14 @@ return array(
|
*/
'extra' => array(
'Artisan' => array('Illuminate\Foundation\Artisan'),
'Eloquent' => array('Illuminate\Database\Eloquent\Builder', 'Illuminate\Database\Query\Builder'),
'Session' => array('Illuminate\Session\Store'),
),
'extra' => [
'Artisan' => ['Illuminate\Foundation\Artisan'],
'Eloquent' => ['Illuminate\Database\Eloquent\Builder', 'Illuminate\Database\Query\Builder'],
'Session' => ['Illuminate\Session\Store'],
],
'magic' => array(
'Log' => array(
'magic' => [
'Log' => [
'debug' => 'Monolog\Logger::addDebug',
'info' => 'Monolog\Logger::addInfo',
'notice' => 'Monolog\Logger::addNotice',
@@ -69,7 +69,8 @@ return array(
'critical' => 'Monolog\Logger::addCritical',
'alert' => 'Monolog\Logger::addAlert',
'emergency' => 'Monolog\Logger::addEmergency',
)
)
]
]
);
];

View File

@@ -1,5 +1,5 @@
<?php
return array(
return [
'view' => 'laravel-breadcrumbs::bootstrap3',
);
];

View File

@@ -1,134 +0,0 @@
<?php
/**
* This file is part of the TwigBridge package.
*
* @copyright Robert Crowe <hello@vivalacrowe.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Configuration options for the built-in extensions.
*/
return [
/*
|--------------------------------------------------------------------------
| Extensions
|--------------------------------------------------------------------------
|
| Enabled extensions.
|
| `Twig_Extension_Debug` is enabled automatically if twig.debug is TRUE.
|
*/
'enabled' => [
'TwigBridge\Extension\Loader\Facades',
'TwigBridge\Extension\Loader\Filters',
'TwigBridge\Extension\Loader\Functions',
'TwigBridge\Extension\Laravel\Auth',
'TwigBridge\Extension\Laravel\Config',
'TwigBridge\Extension\Laravel\Form',
'TwigBridge\Extension\Laravel\Html',
'TwigBridge\Extension\Laravel\Input',
'TwigBridge\Extension\Laravel\Session',
'TwigBridge\Extension\Laravel\String',
'TwigBridge\Extension\Laravel\Translator',
'TwigBridge\Extension\Laravel\Url',
// 'TwigBridge\Extension\Laravel\Legacy\Facades',
],
/*
|--------------------------------------------------------------------------
| Facades
|--------------------------------------------------------------------------
|
| Available facades. Access like `{{ Config.get('foo.bar') }}`.
|
| Each facade can take an optional array of options. To mark the whole facade
| as safe you can set the option `'is_safe' => true`. Setting the facade as
| safe means that any HTML returned will not be escaped.
|
| It is advisable to not set the whole facade as safe and instead mark the
| each appropriate method as safe for security reasons. You can do that with
| the following syntax:
|
| <code>
| 'Form' => [
| 'is_safe' => [
| 'open'
| ]
| ]
| </code>
|
| The values of the `is_safe` array must match the called method on the facade
| in order to be marked as safe.
|
*/
'facades' => [],
/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
|
| Available functions. Access like `{{ secure_url(...) }}`.
|
| Each function can take an optional array of options. These options are
| passed directly to `Twig_SimpleFunction`.
|
| So for example, to mark a function as safe you can do the following:
|
| <code>
| 'link_to' => [
| 'is_safe' => ['html']
| ]
| </code>
|
| The options array also takes a `callback` that allows you to name the
| function differently in your Twig templates than what it's actually called.
|
| <code>
| 'link' => [
| 'callback' => 'link_to'
| ]
| </code>
|
*/
'functions' => [],
/*
|--------------------------------------------------------------------------
| Filters
|--------------------------------------------------------------------------
|
| Available filters. Access like `{{ variable|filter }}`.
|
| Each filter can take an optional array of options. These options are
| passed directly to `Twig_SimpleFilter`.
|
| So for example, to mark a filter as safe you can do the following:
|
| <code>
| 'studly_case' => [
| 'is_safe' => ['html']
| ]
| </code>
|
| The options array also takes a `callback` that allows you to name the
| filter differently in your Twig templates than what is actually called.
|
| <code>
| 'snake' => [
| 'callback' => 'snake_case'
| ]
| </code>
|
*/
'filters' => [],
];

View File

@@ -1,88 +0,0 @@
<?php
/**
* This file is part of the TwigBridge package.
*
* @copyright Robert Crowe <hello@vivalacrowe.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Illuminate\Support\Facades\Config;
/**
* Configuration options for Twig.
*/
return [
/*
|--------------------------------------------------------------------------
| Extension
|--------------------------------------------------------------------------
|
| File extension for Twig view files.
|
*/
'extension' => 'twig',
/*
|--------------------------------------------------------------------------
| Accepts all Twig environment configuration options
|--------------------------------------------------------------------------
|
| http://twig.sensiolabs.org/doc/api.html#environment-options
|
*/
'environment' => [
// When set to true, the generated templates have a __toString() method
// that you can use to display the generated nodes.
// default: false
'debug' => Config::get('app.debug', false),
// The charset used by the templates.
// default: utf-8
'charset' => 'utf-8',
// The base template class to use for generated templates.
// default: TwigBridge\Twig\Template
'base_template_class' => 'TwigBridge\Twig\Template',
// An absolute path where to store the compiled templates, or false to disable caching. If null
// then the cache file path is used.
// default: cache file storage path
'cache' => null,
// When developing with Twig, it's useful to recompile the template
// whenever the source code changes. If you don't provide a value
// for the auto_reload option, it will be determined automatically based on the debug value.
'auto_reload' => true,
// If set to false, Twig will silently ignore invalid variables
// (variables and or attributes/methods that do not exist) and
// replace them with a null value. When set to true, Twig throws an exception instead.
// default: false
'strict_variables' => false,
// If set to true, auto-escaping will be enabled by default for all templates.
// default: true
'autoescape' => true,
// A flag that indicates which optimizations to apply
// (default to -1 -- all optimizations are enabled; set it to 0 to disable)
'optimizations' => -1,
],
/*
|--------------------------------------------------------------------------
| Global variables
|--------------------------------------------------------------------------
|
| These will always be passed in and can be accessed as Twig variables.
| NOTE: these will be overwritten if you pass data into the view with the same key.
|
*/
'globals' => [],
];

0
app/config/queue.php Executable file → Normal file
View File

View File

@@ -0,0 +1,2 @@
<?php
return ['log_level' => 'debug',];

View File

@@ -1,20 +1,3 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Default Cache Driver
|--------------------------------------------------------------------------
|
| This option controls the default cache "driver" that will be used when
| using the Caching library. Of course, you may use other drivers any
| time you wish. This is the default when another is not specified.
|
| Supported: "file", "database", "apc", "memcached", "redis", "array"
|
*/
'driver' => 'array',
);
return ['driver' => 'array',];

View File

@@ -4,8 +4,9 @@ return [
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => ':memory:',
'database' => realpath(__DIR__.'/../../../tests/_data/db.sqlite'),
'prefix' => ''
],
]
]
];
];

View File

@@ -0,0 +1,13 @@
<?php
return [
'driver' => 'smtp',
'host' => '',
'port' => 587,
'from' => ['address' => '', 'name' => 'Firefly III'],
'encryption' => 'tls',
'username' => '',
'password' => '',
'sendmail' => '/usr/sbin/sendmail -bs',
'pretend' => true,
];

View File

@@ -1,21 +1,3 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Default Session Driver
|--------------------------------------------------------------------------
|
| This option controls the default session "driver" that will be used on
| requests. By default, we will use the lightweight native driver but
| you may specify any of the other wonderful drivers provided here.
|
| Supported: "native", "cookie", "database", "apc",
| "memcached", "redis", "array"
|
*/
'driver' => 'array',
);
return ['driver' => 'array',];

View File

@@ -0,0 +1,2 @@
<?php
return ['log_level' => 'debug',];

View File

@@ -0,0 +1,8 @@
<?php
return [
'verify_mail' => false,
'verify_reset' => true,
'allow_register' => true
];

View File

@@ -0,0 +1,3 @@
<?php
return ['driver' => 'array',];

View File

@@ -0,0 +1,12 @@
<?php
return [
'default' => 'sqlite',
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => ''
]
]
];

View File

@@ -0,0 +1,13 @@
<?php
return [
'driver' => 'smtp',
'host' => '',
'port' => 587,
'from' => ['address' => '', 'name' => 'Firefly III'],
'encryption' => 'tls',
'username' => '',
'password' => '',
'sendmail' => '/usr/sbin/sendmail -bs',
'pretend' => true,
];

View File

@@ -0,0 +1,3 @@
<?php
return ['driver' => 'array',];

View File

@@ -1,6 +1,6 @@
<?php
return [
'paths' => array(__DIR__ . '/../views'),
'paths' => [__DIR__ . '/../views'],
'pagination' => 'pagination::slider-3',
];

View File

@@ -1,94 +1,78 @@
<?php
use Firefly\Helper\Controllers\AccountInterface as AI;
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Database\Account\Account as AccountRepository;
use FireflyIII\Exception\FireflyException;
/**
* Class AccountController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class AccountController extends \BaseController
class AccountController extends BaseController
{
/** @var array */
protected $_accountTypesByIdentifier
= [
'asset' => ['Default account', 'Asset account'],
'expense' => ['Expense account', 'Beneficiary account'],
'revenue' => ['Revenue account'],
];
/** @var AccountRepository */
protected $_repository;
protected $_accounts;
/** @var array */
protected $_shortNamesByFullName
= [
'Default account' => 'asset',
'Asset account' => 'asset',
'Expense account' => 'expense',
'Beneficiary account' => 'expense',
'Revenue account' => 'revenue',
'Cash account' => 'cash',
];
/** @var array */
protected $_subIconsByIdentifier
= [
'asset' => 'fa-money',
'Asset account' => 'fa-money',
'Default account' => 'fa-money',
'Cash account' => 'fa-money',
'expense' => 'fa-shopping-cart',
'Expense account' => 'fa-shopping-cart',
'Beneficiary account' => 'fa-shopping-cart',
'revenue' => 'fa-download',
'Revenue account' => 'fa-download',
];
/** @var array */
protected $_subTitlesByIdentifier
= [
'asset' => 'Asset accounts',
'expense' => 'Expense accounts',
'revenue' => 'Revenue accounts',
];
/**
* @param ARI $repository
* @param AI $accounts
* @param AccountRepository $repository
*/
public function __construct(ARI $repository, AI $accounts)
public function __construct(AccountRepository $repository)
{
$this->_accounts = $accounts;
$this->_repository = $repository;
View::share('mainTitleIcon', 'fa-credit-card');
View::share('title', 'Accounts');
}
/**
* @param $what
*
* @return \Illuminate\View\View
*/
public function create($what)
{
switch ($what) {
case 'asset':
View::share('subTitleIcon', 'fa-money');
break;
case 'expense':
View::share('subTitleIcon', 'fa-shopping-cart');
break;
case 'revenue':
View::share('subTitleIcon', 'fa-download');
break;
}
$subTitleIcon = $this->_subIconsByIdentifier[$what];
$subTitle = 'Create a new ' . e($what) . ' account';
return View::make('accounts.create')->with('subTitle', 'Create a new ' . $what . ' account')->with(
'what', $what
);
}
/**
* @return $this
*/
public function asset()
{
View::share('subTitleIcon', 'fa-money');
$accounts = $this->_repository->getOfTypes(['Asset account', 'Default account']);
return View::make('accounts.asset')->with('subTitle', 'Asset accounts')->with(
'accounts', $accounts
);
}
/**
* @return $this
*/
public function expense()
{
View::share('subTitleIcon', 'fa-shopping-cart');
$accounts = $this->_repository->getOfTypes(['Expense account', 'Beneficiary account']);
return View::make('accounts.expense')->with('subTitle', 'Expense accounts')->with(
'accounts', $accounts
);
}
/**
* @return $this
*/
public function revenue()
{
View::share('subTitleIcon', 'fa-download');
$accounts = $this->_repository->getOfTypes(['Revenue account']);
return View::make('accounts.revenue')->with('subTitle', 'Revenue accounts')->with(
'accounts', $accounts
);
return View::make('accounts.create', compact('subTitleIcon', 'what', 'subTitle'));
}
/**
@@ -98,10 +82,9 @@ class AccountController extends \BaseController
*/
public function delete(Account $account)
{
return View::make('accounts.delete')->with('account', $account)
->with(
'subTitle', 'Delete ' . strtolower($account->accountType->type) . ' "' . $account->name . '"'
);
$subTitle = 'Delete ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
return View::make('accounts.delete', compact('account', 'subTitle'));
}
/**
@@ -111,24 +94,16 @@ class AccountController extends \BaseController
*/
public function destroy(Account $account)
{
$type = $account->accountType->type;
$type = $account->accountType->type;
$typeName = $this->_shortNamesByFullName[$type];
$name = $account->name;
$this->_repository->destroy($account);
Session::flash('success', 'The account was deleted.');
switch ($type) {
case 'Asset account':
case 'Default account':
return Redirect::route('accounts.asset');
break;
case 'Expense account':
case 'Beneficiary account':
return Redirect::route('accounts.expense');
break;
case 'Revenue account':
return Redirect::route('accounts.revenue');
break;
}
Session::flash('success', 'The ' . e($typeName) . ' account "' . e($name) . '" was deleted.');
return Redirect::route('accounts.index', $typeName);
}
/**
@@ -139,138 +114,127 @@ class AccountController extends \BaseController
public function edit(Account $account)
{
switch ($account->accountType->type) {
case 'Asset account':
case 'Default account':
View::share('subTitleIcon', 'fa-money');
break;
case 'Expense account':
case 'Beneficiary account':
View::share('subTitleIcon', 'fa-shopping-cart');
break;
case 'Revenue account':
View::share('subTitleIcon', 'fa-download');
break;
}
$openingBalance = $this->_repository->openingBalanceTransaction($account);
$subTitleIcon = $this->_subIconsByIdentifier[$account->accountType->type];
$subTitle = 'Edit ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
$openingBalance = $this->_accounts->openingBalanceTransaction($account);
return View::make('accounts.edit')->with('account', $account)->with('openingBalance', $openingBalance)
// pre fill some useful values.
$preFilled = [
'account_role' => $account->getMeta('accountRole'),
'openingBalanceDate' => $openingBalance ? $openingBalance->date->format('Y-m-d') : null,
'openingBalance' => $openingBalance ? $openingBalance->getAmount($account) : null
];
Session::flash('preFilled', $preFilled);
->with('subTitle', 'Edit ' . strtolower($account->accountType->type) . ' "' . $account->name . '"');
return View::make('accounts.edit', compact('account', 'subTitle', 'openingBalance', 'subTitleIcon'));
}
/**
* @return $this
*
* @param string $what
*
* @return View
* @throws FireflyException
*/
public function index()
public function index($what = 'default')
{
return View::make('error')->with('message', 'This view has been disabled');
$subTitle = $this->_subTitlesByIdentifier[$what];
$subTitleIcon = $this->_subIconsByIdentifier[$what];
$accounts = $this->_repository->getAccountsByType($this->_accountTypesByIdentifier[$what]);
return View::make('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
}
/**
* @param Account $account
* @param string $range
*
* @return $this
*/
public function show(Account $account)
public function show(Account $account, $range = 'session')
{
switch ($account->accountType->type) {
case 'Asset account':
case 'Default account':
View::share('subTitleIcon', 'fa-money');
break;
case 'Expense account':
case 'Beneficiary account':
View::share('subTitleIcon', 'fa-shopping-cart');
break;
case 'Revenue account':
View::share('subTitleIcon', 'fa-download');
break;
}
$subTitleIcon = $this->_subIconsByIdentifier[$account->accountType->type];
$what = $this->_shortNamesByFullName[$account->accountType->type];
$journals = $this->_repository->getTransactionJournals($account, 50, $range);
$subTitle = 'Details for ' . strtolower(e($account->accountType->type)) . ' "' . e($account->name) . '"';
$data = $this->_accounts->show($account, 40);
return View::make('accounts.show')->with('account', $account)->with('show', $data)->with(
'subTitle',
'Details for ' . strtolower($account->accountType->type) . ' "' . $account->name . '"'
);
return View::make('accounts.show', compact('account', 'what', 'range', 'subTitleIcon', 'journals', 'subTitle'));
}
/**
* @return $this|\Illuminate\Http\RedirectResponse
* @throws FireflyException
*/
public function store()
{
$data = Input::all();
$data['what'] = isset($data['what']) && $data['what'] != '' ? $data['what'] : 'asset';
$data = Input::except('_token');
// always validate:
$messages = $this->_repository->validate($data);
switch ($data['what']) {
default:
case 'asset':
$data['account_type'] = 'Asset account';
break;
case 'expense':
$data['account_type'] = 'Expense account';
break;
case 'revenue':
$data['account_type'] = 'Revenue account';
break;
// 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 account: ' . $messages['errors']->first());
}
$account = $this->_repository->store($data);
if ($account->validate()) {
// saved! return to wherever.
Session::flash('success', 'Account "' . $account->name . '" created!');
if (intval(Input::get('create')) === 1) {
return Redirect::route('accounts.create', $data['what'])->withInput();
} else {
return Redirect::route('accounts.' . e($data['what']));
}
} else {
// did not save, return with error:
Session::flash('error', 'Could not save the new account: ' . $account->errors()->first());
return Redirect::route('accounts.create', $data['what'])->withErrors($account->errors())->withInput();
// return to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('accounts.create', e($data['what']))->withInput();
}
// store
$this->_repository->store($data);
Session::flash('success', 'Account "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('accounts.index', e($data['what']));
}
return Redirect::route('accounts.create', e($data['what']))->withInput();
}
/**
* @param Account $account
*
* @return $this|\Illuminate\Http\RedirectResponse
* @return $this
* @throws FireflyException
*/
public function update(Account $account)
{
/** @var \Account $account */
$account = $this->_repository->update($account, Input::all());
if ($account->validate()) {
Session::flash('success', 'Account "' . $account->name . '" updated.');
switch ($account->accountType->type) {
case 'Asset account':
case 'Default account':
return Redirect::route('accounts.asset');
break;
case 'Expense account':
case 'Beneficiary account':
return Redirect::route('accounts.expense');
break;
case 'Revenue account':
return Redirect::route('accounts.revenue');
break;
}
$data = Input::except('_token');
$data['what'] = $this->_shortNamesByFullName[$account->accountType->type];
} else {
Session::flash('error', 'Could not update account: ' . $account->errors()->first());
return Redirect::route('accounts.edit', $account->id)->withInput()->withErrors($account->errors());
// always validate:
$messages = $this->_repository->validate($data);
// 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 update account: ' . $messages['errors']->first());
}
// return to update screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('accounts.edit', $account->id)->withInput();
}
// update
$this->_repository->update($account, $data);
Session::flash('success', 'Account "' . e($data['name']) . '" updated.');
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('accounts.index', e($data['what']));
}
// go back to update screen.
return Redirect::route('accounts.edit', $account->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
}

View File

@@ -0,0 +1,212 @@
<?php
use FireflyIII\Database\Bill\Bill as Repository;
use FireflyIII\Exception\FireflyException;
/**
*
* @SuppressWarnings("CamelCase") // I'm fine with this.
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
* @SuppressWarnings("NPathComplexity")
* Class BillController
*
*/
class BillController extends BaseController
{
/** @var Repository */
protected $_repository;
/**
* @param Repository $repository
*/
public function __construct(Repository $repository)
{
$this->_repository = $repository;
View::share('title', 'Bills');
View::share('mainTitleIcon', 'fa-calendar-o');
}
/**
* @return $this
*/
public function create()
{
$periods = \Config::get('firefly.periods_to_text');
return View::make('bills.create')->with('periods', $periods)->with('subTitle', 'Create new');
}
/**
* @param Bill $bill
*
* @return $this
*/
public function delete(Bill $bill)
{
return View::make('bills.delete')->with('bill', $bill)->with(
'subTitle', 'Delete "' . e($bill->name) . '"'
);
}
/**
* @param Bill $bill
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Bill $bill)
{
$this->_repository->destroy($bill);
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::make('bills.edit')->with('periods', $periods)->with('bill', $bill)->with(
'subTitle', 'Edit "' . e($bill->name) . '"'
);
}
/**
* @return $this
*/
public function index()
{
$bills = $this->_repository->get();
$bills->each(
function (Bill $bill) {
$bill->nextExpectedMatch = $this->_repository->nextExpectedMatch($bill);
$bill->lastFoundMatch = $this->_repository->lastFoundMatch($bill);
}
);
return View::make('bills.index', compact('bills'));
}
/**
* @param Bill $bill
*
* @return mixed
*/
public function rescan(Bill $bill)
{
if (intval($bill->active) == 0) {
Session::flash('warning', 'Inactive bills cannot be scanned.');
return Redirect::intended('/');
}
$this->_repository->scanEverything($bill);
Session::flash('success', 'Rescanned everything.');
return Redirect::intended('/');
}
/**
* @param Bill $bill
*
* @return mixed
*/
public function show(Bill $bill)
{
$journals = $bill->transactionjournals()->withRelevantData()->orderBy('date', 'DESC')->get();
$bill->nextExpectedMatch = $this->_repository->nextExpectedMatch($bill);
$hideBill = true;
return View::make('bills.show', compact('journals', 'hideBill', 'bill'))->with(
'subTitle', e($bill->name)
);
}
/**
* @return $this
* @throws FireflyException
*/
public function store()
{
$data = Input::all();
$data['user_id'] = Auth::user()->id;
// always validate:
$messages = $this->_repository->validate($data);
// 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 bill: ' . $messages['errors']->first());
}
// return to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('bills.create')->withInput();
}
// store
$this->_repository->store($data);
Session::flash('success', 'Bill "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('bills.index');
}
return Redirect::route('bills.create')->withInput();
}
/**
* @param Bill $bill
*
* @return $this
* @throws FireflyException
*/
public function update(Bill $bill)
{
$data = Input::except('_token');
$data['active'] = isset($data['active']) ? 1 : 0;
$data['automatch'] = isset($data['automatch']) ? 1 : 0;
$data['user_id'] = Auth::user()->id;
// always validate:
$messages = $this->_repository->validate($data);
// 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 update bill: ' . $messages['errors']->first());
}
// return to update screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('bills.edit', $bill->id)->withInput();
}
// update
$this->_repository->update($bill, $data);
Session::flash('success', 'Bill "' . e($data['name']) . '" updated.');
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('bills.index');
}
// go back to update screen.
return Redirect::route('bills.edit', $bill->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
}

View File

@@ -1,75 +1,60 @@
<?php
use Carbon\Carbon;
use Firefly\Exception\FireflyException;
use Firefly\Helper\Controllers\BudgetInterface as BI;
use Firefly\Storage\Budget\BudgetRepositoryInterface as BRI;
use FireflyIII\Database\Budget\Budget as BudgetRepository;
use FireflyIII\Shared\Preferences\PreferencesInterface as Pref;
/**
* Class BudgetController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings("CamelCase") // I'm fine with this.
* @SuppressWarnings("TooManyMethods") // I'm also fine with this.
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
* @SuppressWarnings("CouplingBetweenObjects") // There's only so much I can remove.
*
*/
class BudgetController extends BaseController
{
protected $_budgets;
/** @var Pref */
protected $_preferences;
/** @var BudgetRepository */
protected $_repository;
/**
* @param BI $budgets
* @param BRI $repository
* @param BudgetRepository $repository
* @param Pref $preferences
*/
public function __construct(BI $budgets, BRI $repository)
public function __construct(BudgetRepository $repository, Pref $preferences)
{
$this->_budgets = $budgets;
$this->_repository = $repository;
$this->_repository = $repository;
$this->_preferences = $preferences;
View::share('title', 'Budgets');
View::share('mainTitleIcon', 'fa-tasks');
}
public function nobudget($view = 'session') {
switch($view) {
default:
throw new FireflyException('Cannot show transactions without a budget for view "'.$view.'".');
break;
case 'session':
$start = Session::get('start');
$end = Session::get('end');
break;
}
/**
* @param Budget $budget
*
* @return \Illuminate\Http\JsonResponse
* @throws Exception
*/
public function amount(Budget $budget)
{
$amount = intval(Input::get('amount'));
$date = Session::get('start', Carbon::now()->startOfMonth());
$limitRepetition = $this->_repository->updateLimitAmount($budget, $date, $amount);
// Add expenses that have no budget:
$set = \Auth::user()->transactionjournals()->whereNotIn(
'transaction_journals.id', function ($query) use ($start, $end) {
$query->select('transaction_journals.id')->from('transaction_journals')
->leftJoin(
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
'transaction_journals.id'
)
->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('components.class', 'Budget');
}
)->before($end)->after($start)->get();
return Response::json(['name' => $budget->name, 'repetition' => $limitRepetition->id]);
return View::make('budgets.nobudget')
->with('view', $view)
->with('transactions',$set)
->with('subTitle', 'Transactions without a budget');
}
/**
* @return $this|\Illuminate\View\View
* @return $this
*/
public function create()
{
$periods = \Config::get('firefly.periods_to_text');
return View::make('budgets.create')->with('periods', $periods)->with('subTitle', 'Create a new budget');
return View::make('budgets.create')->with('subTitle', 'Create a new budget');
}
/**
@@ -79,8 +64,9 @@ class BudgetController extends BaseController
*/
public function delete(Budget $budget)
{
return View::make('budgets.delete')->with('budget', $budget)
->with('subTitle', 'Delete budget "' . $budget->name . '"');
$subTitle = 'Delete budget "' . e($budget->name) . '"';
return View::make('budgets.delete', compact('budget', 'subTitle'));
}
/**
@@ -90,16 +76,11 @@ class BudgetController extends BaseController
*/
public function destroy(Budget $budget)
{
// remove budget
Event::fire('budgets.destroy', [$budget]); // just before deletion.
Session::flash('success', 'Budget "' . e($budget->name) . '" was deleted.');
$this->_repository->destroy($budget);
Session::flash('success', 'The budget was deleted.');
// redirect:
if (Input::get('from') == 'date') {
return Redirect::route('budgets.index');
}
return Redirect::route('budgets.index.budget');
return Redirect::route('budgets.index');
}
@@ -110,116 +91,115 @@ class BudgetController extends BaseController
*/
public function edit(Budget $budget)
{
return View::make('budgets.edit')->with('budget', $budget)
->with('subTitle', 'Edit budget "' . $budget->name . '"');
}
/**
* @return $this|\Illuminate\View\View
*/
public function indexByBudget()
{
View::share('subTitleIcon', 'fa-folder-open');
$budgets = $this->_repository->get();
return View::make('budgets.indexByBudget')->with('budgets', $budgets)->with('today', new Carbon)
->with('subTitle', 'Grouped by budget');
$subTitle = 'Edit budget "' . e($budget->name) . '"';
return View::make('budgets.edit', compact('budget', 'subTitle'));
}
/**
* The index of the budget controller contains all budgets and the current relevant limit repetition.
*
* @return $this
*/
public function indexByDate()
public function index()
{
View::share('subTitleIcon', 'fa-calendar');
$budgets = $this->_repository->get();
// get a list of dates by getting all repetitions:
$set = $this->_repository->get();
$budgets = $this->_budgets->organizeByDate($set);
return View::make('budgets.indexByDate')->with('budgets', $budgets)
->with('subTitle', 'Grouped by date');
// loop the budgets:
$budgets->each(
function (Budget $budget) {
$budget->spent = $this->_repository->spentInMonth($budget, \Session::get('start', Carbon::now()->startOfMonth()));
$budget->currentRep = $this->_repository->getRepetitionByDate($budget, \Session::get('start', Carbon::now()->startOfMonth()));
}
);
$spent = $budgets->sum('spent');
$amount = $this->_preferences->get('budgetIncomeTotal' . \Session::get('start', Carbon::now()->startOfMonth())->format('FY'), 1000)->data;
$overspent = $spent > $amount;
$spentPCT = $overspent ? ceil($amount / $spent * 100) : ceil($spent / $amount * 100);
$budgetMax = $this->_preferences->get('budgetMaximum', 1000);
$budgetMaximum = $budgetMax->data;
return View::make('budgets.index', compact('budgetMaximum', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount'));
}
/**
* Three use cases for this view:
*
* - Show everything.
* - Show a specific repetition.
* - Show everything shows NO repetition.
*
* @param Budget $budget
* @param LimitRepetition $repetition
*
* @return int
* @return \Illuminate\View\View
*/
public function show(Budget $budget, \LimitRepetition $repetition = null)
public function noBudget()
{
$useSessionDates = Input::get('useSession') == 'true' ? true : false;
$view = null;
$title = null;
\Log::debug('Is envelope true? ' . (Input::get('noenvelope') == 'true'));
switch (true) {
case (!is_null($repetition)):
$data = $this->_budgets->organizeRepetition($repetition);
$view = 1;
$title = $budget->name . ', ' . $repetition->periodShow() . ', ' . mf(
$repetition->limit->amount,
false
);
break;
case (Input::get('noenvelope') == 'true'):
$data = $this->_budgets->outsideRepetitions($budget);
$view = 2;
$title = $budget->name . ', transactions outside an envelope';
break;
default:
$data = $this->_budgets->organizeRepetitions($budget, $useSessionDates);
$view = $useSessionDates ? 3 : 4;
$title = $useSessionDates ? $budget->name . ' in session period' : $budget->name;
break;
}
$start = \Session::get('start', Carbon::now()->startOfMonth());
$end = \Session::get('end', Carbon::now()->startOfMonth());
$list = $this->_repository->journalsNoBudget($start, $end);
$subTitle = 'Transactions without a budget in ' . $start->format('F Y');
return View::make('budgets.show')
->with('budget', $budget)
->with('repetitions', $data)
->with('view', $view)
->with('highlight', Input::get('highlight'))
->with('useSessionDates', $useSessionDates)
->with('subTitle', 'Overview for ' . $title);
return View::make('budgets.noBudget', compact('list', 'subTitle'));
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function store()
public function postUpdateIncome()
{
$this->_preferences->set('budgetIncomeTotal' . Session::get('start', Carbon::now()->startOfMonth())->format('FY'), intval(Input::get('amount')));
$budget = $this->_repository->store(Input::all());
if ($budget->validate()) {
Event::fire('budgets.store', [$budget]);
Session::flash('success', 'Budget created!');
return Redirect::route('budgets.index');
}
if (Input::get('create') == '1') {
return Redirect::route('budgets.create', ['from' => Input::get('from')]);
}
if (Input::get('from') == 'date') {
return Redirect::route('budgets.index');
} else {
return Redirect::route('budgets.index.budget');
}
} else {
Session::flash('error', 'Could not save the new budget');
return Redirect::route('budgets.create')->withInput()->withErrors($budget->errors());
/**
* @param Budget $budget
* @param LimitRepetition $repetition
*
* @return \Illuminate\View\View
*/
public function show(Budget $budget, LimitRepetition $repetition = null)
{
if (!is_null($repetition) && $repetition->budgetLimit->budget->id != $budget->id) {
return View::make('error')->with('message', 'Invalid selection.');
}
$hideBudget = true; // used in transaction list.
$journals = $this->_repository->getJournals($budget, $repetition);
$limits = $repetition ? [$repetition->budgetLimit] : $budget->budgetLimits()->orderBy('startdate', 'DESC')->get();
$subTitle = $repetition ? e($budget->name) . ' in ' . $repetition->startdate->format('F Y') : e($budget->name);
return View::make('budgets.show', compact('limits', 'budget', 'repetition', 'journals', 'subTitle', 'hideBudget'));
}
/**
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function store()
{
$data = Input::except('_token');
$data['user_id'] = Auth::user()->id;
// always validate:
$messages = $this->_repository->validate($data);
// 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 validate budget: ' . $messages['errors']->first());
}
// return to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('budgets.create')->withInput();
}
// store
$this->_repository->store($data);
Session::flash('success', 'Budget "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('budgets.index');
}
// create another.
return Redirect::route('budgets.create')->withInput();
}
/**
@@ -229,23 +209,45 @@ class BudgetController extends BaseController
*/
public function update(Budget $budget)
{
$budget = $this->_repository->update($budget, Input::all());
if ($budget->validate()) {
Event::fire('budgets.update', [$budget]);
Session::flash('success', 'Budget "' . $budget->name . '" updated.');
if (Input::get('from') == 'date') {
return Redirect::route('budgets.index');
} else {
return Redirect::route('budgets.index.budget');
}
} else {
Session::flash('error', 'Could not update budget: ' . $budget->errors()->first());
$data = Input::except('_token');
$data['user_id'] = Auth::user()->id;
return Redirect::route('budgets.edit', $budget->id)->withInput()->withErrors($budget->errors());
// always validate:
$messages = $this->_repository->validate($data);
// 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 update budget: ' . $messages['errors']->first());
}
// return to update screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('budgets.edit', $budget->id)->withInput();
}
// update
$this->_repository->update($budget, $data);
Session::flash('success', 'Budget "' . e($data['name']) . '" updated.');
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('budgets.index');
}
return Redirect::route('budgets.edit', $budget->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
/**
* @return $this
*/
public function updateIncome()
{
$budgetAmount = $this->_preferences->get('budgetIncomeTotal' . Session::get('start', Carbon::now()->startOfMonth())->format('FY'), 1000);
}
return View::make('budgets.income')->with('amount', $budgetAmount);
}
}

View File

@@ -1,28 +1,30 @@
<?php
use Firefly\Helper\Controllers\CategoryInterface as CI;
use Firefly\Storage\Category\CategoryRepositoryInterface as CRI;
use Carbon\Carbon;
use FireflyIII\Database\Category\Category as CategoryRepository;
use FireflyIII\Exception\FireflyException;
/**
* Class CategoryController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
* @SuppressWarnings("CamelCase") // I'm fine with this.
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
*
* Class CategoryController
*/
class CategoryController extends BaseController
{
/** @var CategoryRepository */
protected $_repository;
protected $_category;
/**
* @param CRI $repository
* @param CI $category
* @param CategoryRepository $repository
*/
public function __construct(CRI $repository, CI $category)
public function __construct(CategoryRepository $repository)
{
$this->_repository = $repository;
$this->_category = $category;
View::share('title','Categories');
View::share('title', 'Categories');
View::share('mainTitleIcon', 'fa-bar-chart');
$this->_repository = $repository;
}
/**
@@ -33,6 +35,19 @@ class CategoryController extends BaseController
return View::make('categories.create')->with('subTitle', 'Create a new category');
}
/**
* @return \Illuminate\View\View
*/
public function noCategory()
{
$start = \Session::get('start', Carbon::now()->startOfMonth());
$end = \Session::get('end', Carbon::now()->startOfMonth());
$list = $this->_repository->journalsNoCategory($start, $end);
$subTitle = 'Transactions without a category in ' . $start->format('F Y');
return View::make('categories.noCategory', compact('list', 'subTitle'));
}
/**
* @param Category $category
*
@@ -40,8 +55,7 @@ class CategoryController extends BaseController
*/
public function delete(Category $category)
{
return View::make('categories.delete')->with('category', $category)
->with('subTitle', 'Delete category "' . $category->name . '"');
return View::make('categories.delete')->with('category', $category)->with('subTitle', 'Delete category "' . e($category->name) . '"');
}
/**
@@ -51,8 +65,10 @@ class CategoryController extends BaseController
*/
public function destroy(Category $category)
{
Session::flash('success', 'Category "' . e($category->name) . '" was deleted.');
$this->_repository->destroy($category);
Session::flash('success', 'The category was deleted.');
return Redirect::route('categories.index');
}
@@ -63,8 +79,7 @@ class CategoryController extends BaseController
*/
public function edit(Category $category)
{
return View::make('categories.edit')->with('category', $category)
->with('subTitle', 'Edit category "' . $category->name . '"');
return View::make('categories.edit')->with('category', $category)->with('subTitle', 'Edit category "' . e($category->name) . '"');
}
/**
@@ -74,8 +89,7 @@ class CategoryController extends BaseController
{
$categories = $this->_repository->get();
return View::make('categories.index')->with('categories', $categories)
->with('subTitle', 'All your categories');
return View::make('categories.index', compact('categories'));
}
/**
@@ -85,58 +99,88 @@ class CategoryController extends BaseController
*/
public function show(Category $category)
{
$start = \Session::get('start');
$end = \Session::get('end');
$hideCategory = true; // used in list.
$journals = $this->_repository->getTransactionJournals($category, 50);
$journals = $this->_category->journalsInRange($category, $start, $end);
return View::make('categories.show')->with('category', $category)->with('journals', $journals)->with(
'highlight', Input::get('highlight')
)->with('subTitle', 'Overview for category "' . $category->name . '"');
return View::make('categories.show', compact('category', 'journals', 'hideCategory'));
}
/**
* @return $this|\Illuminate\Http\RedirectResponse
* @return $this
* @throws FireflyException
*/
public function store()
{
$category = $this->_repository->store(Input::all());
if ($category->validate()) {
Session::flash('success', 'Category "' . $category->name . '" created!');
$data = Input::except('_token');
$data['user_id'] = Auth::user()->id;
if (Input::get('create') == '1') {
return Redirect::route('categories.create');
}
// always validate:
$messages = $this->_repository->validate($data);
return Redirect::route('categories.index');
} else {
Session::flash('error', 'Could not save the new category!');
// 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 category: ' . $messages['errors']->first());
}
// return to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('categories.create')->withInput();
}
// store
$this->_repository->store($data);
Session::flash('success', 'Category "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('categories.index');
}
return Redirect::route('categories.create')->withInput();
}
/**
* @param Category $category
*
* @return $this|\Illuminate\Http\RedirectResponse
* @return $this
* @throws FireflyException
*/
public function update(Category $category)
{
$category = $this->_repository->update($category, Input::all());
if ($category->validate()) {
Session::flash('success', 'Category "' . $category->name . '" updated.');
$data = Input::except('_token');
$data['user_id'] = Auth::user()->id;
return Redirect::route('categories.index');
} else {
Session::flash('success', 'Could not update category "' . $category->name . '".');
// always validate:
$messages = $this->_repository->validate($data);
return Redirect::route('categories.edit')->withErrors($category->errors())->withInput();
// 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 update category: ' . $messages['errors']->first());
}
// return to update screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('categories.edit', $category->id)->withInput();
}
// update
$this->_repository->update($category, $data);
Session::flash('success', 'Category "' . e($data['name']) . '" updated.');
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('categories.index');
}
// go back to update screen.
return Redirect::route('categories.edit', $category->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
}
}

View File

@@ -1,485 +0,0 @@
<?php
use Carbon\Carbon;
use Firefly\Helper\Controllers\ChartInterface;
use Firefly\Storage\Account\AccountRepositoryInterface;
/**
* Class ChartController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class ChartController extends BaseController
{
protected $_chart;
protected $_accounts;
/**
* @param ChartInterface $chart
* @param AccountRepositoryInterface $accounts
*/
public function __construct(ChartInterface $chart, AccountRepositoryInterface $accounts)
{
$this->_chart = $chart;
$this->_accounts = $accounts;
}
/**
* This method takes a budget, all limits and all their repetitions and displays three numbers per repetition:
* the amount of money in the repetition (represented as "an envelope"), the amount spent and the spent percentage.
*
* @param Budget $budget
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetDefault(\Budget $budget)
{
$expense = [];
$left = [];
$envelope = [];
// get all limit repetitions for this budget.
/** @var \Limit $limit */
foreach ($budget->limits as $limit) {
/** @var \LimitRepetition $rep */
foreach ($limit->limitrepetitions as $rep) {
// get the amount of money spent in this period on this budget.
$spentInRep = $rep->amount - $rep->leftInRepetition();
$pct = round((floatval($spentInRep) / floatval($limit->amount)) * 100, 2);
$name = $rep->periodShow();
$envelope[] = [$name, floatval($limit->amount)];
$expense[] = [$name, floatval($spentInRep)];
$left[] = [$name, $pct];
}
}
$return = [
'chart_title' => 'Overview for budget ' . $budget->name,
'subtitle' => 'All envelopes',
'series' => [
[
'type' => 'line',
'yAxis' => 1,
'name' => 'Amount in envelope',
'data' => $envelope
],
[
'type' => 'column',
'name' => 'Expenses in envelope',
'data' => $expense
],
[
'type' => 'line',
'yAxis' => 1,
'name' => 'Spent percentage for envelope',
'data' => $left
]
]
];
return Response::json($return);
}
/**
* This method takes a single limit repetition (so a single "envelope") and displays the amount of money spent
* per day and subsequently how much money is left.
*
* @param LimitRepetition $rep
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetLimit(\LimitRepetition $rep)
{
$budget = $rep->limit->budget;
$current = clone $rep->startdate;
$expense = [];
$leftInLimit = [];
$currentLeftInLimit = floatval($rep->limit->amount);
while ($current <= $rep->enddate) {
$spent = $this->_chart->spentOnDay($budget, $current);
$spent = floatval($spent) == 0 ? null : floatval($spent);
$entry = [$current->timestamp * 1000, $spent];
$expense[] = $entry;
$currentLeftInLimit = $currentLeftInLimit - $spent;
$leftInLimit[] = [$current->timestamp * 1000, $currentLeftInLimit];
$current->addDay();
}
$return = [
'chart_title' => 'Overview for budget ' . $budget->name,
'subtitle' =>
'Between ' . $rep->startdate->format('M jS, Y') . ' and ' . $rep->enddate->format('M jS, Y'),
'series' => [
[
'type' => 'column',
'name' => 'Expenses per day',
'yAxis' => 1,
'data' => $expense
],
[
'type' => 'line',
'name' => 'Left in envelope',
'data' => $leftInLimit
]
]
];
return Response::json($return);
}
/**
* This method takes a budget and gets all transactions in it which haven't got an envelope (limit).
*
* Usually this means that very old and unorganized or very NEW transactions get displayed; there was never an
* envelope or it hasn't been created (yet).
*
*
* @param Budget $budget
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetNoLimits(\Budget $budget)
{
/*
* Firefly can go about this two ways. Either it finds all transactions which definitely are IN an envelope
* and exclude them or it searches for transactions outside of the range of any of the envelopes there are.
*
* Since either is kinda shitty Firefly uses the first one because it's easier to build.
*/
$inRepetitions = $this->_chart->allJournalsInBudgetEnvelope($budget);
/*
* With this set of id's, Firefly can search for all journals NOT in that set.
* BUT they have to be in the budget (duh).
*/
$set = $this->_chart->journalsNotInSet($budget, $inRepetitions);
/*
* Next step: get all transactions for those journals.
*/
$transactions = $this->_chart->transactionsByJournals($set);
/*
* this set builds the chart:
*/
$expense = [];
foreach ($transactions as $t) {
$date = new Carbon($t->date);
$expense[] = [$date->timestamp * 1000, floatval($t->aggregate)];
}
$return = [
'chart_title' => 'Overview for ' . $budget->name,
'subtitle' => 'Not organized by an envelope',
'series' => [
[
'type' => 'column',
'name' => 'Expenses per day',
'data' => $expense
]
]
];
return Response::json($return);
}
/**
* This method gets all transactions within a budget within the period set by the current session
* start and end date. It also includes any envelopes which might exist within this period.
*
* @param Budget $budget
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetSession(\Budget $budget)
{
$series = [];
$end = clone Session::get('end');
$start = clone Session::get('start');
/*
* Expenses per day in the session's period. That's easy.
*/
$expense = [];
$current = clone Session::get('start');
while ($current <= $end) {
$spent = $this->_chart->spentOnDay($budget, $current);
$spent = floatval($spent) == 0 ? null : floatval($spent);
$expense[] = [$current->timestamp * 1000, $spent];
$current->addDay();
}
$series[] = [
'type' => 'column',
'name' => 'Expenses per day',
'data' => $expense
];
unset($expense, $spent, $current);
/*
* Find all limit repetitions (for this budget) between start and end. This is
* quite a complex query.
*/
$reps = $this->_chart->limitsInRange($budget, $start, $end);
/*
* For each limitrepetition Firefly creates a serie that contains the amount left in
* the limitrepetition for its entire date-range. Entries are only actually included when they
* fall into the charts date range.
*
* So example: the user has a session date from Jan 15 to Jan 30. The limitrepetition
* starts at 1 Jan until 1 Feb.
*
* Firefly loops from 1 Jan to 1 Feb but only includes Jan 15 / Jan 30.
* But it does keep count of the amount outside of these dates because otherwise the line might be wrong.
*/
/** @var \LimitRepetition $repetition */
foreach ($reps as $repetition) {
$limitAmount = $repetition->limit->amount;
// create a serie for the repetition.
$currentSerie = [
'type' => 'spline',
'id' => 'rep-' . $repetition->id,
'yAxis' => 1,
'name' => 'Envelope #' . $repetition->id . ' in ' . $repetition->periodShow(),
'data' => []
];
$current = clone $repetition->startdate;
while ($current <= $repetition->enddate) {
if ($current >= $start && $current <= $end) {
// spent on limit:
$spentSoFar = $this->_chart->spentOnLimitRepetitionBetweenDates(
$repetition, $repetition->startdate, $current
);
$leftInLimit = floatval($limitAmount) - floatval($spentSoFar);
$currentSerie['data'][] = [$current->timestamp * 1000, $leftInLimit];
}
$current->addDay();
}
// do something here.
$series[] = $currentSerie;
}
$return = [
'chart_title' => 'Overview for budget ' . $budget->name,
'subtitle' =>
'Between ' . Session::get('start')->format('M jS, Y') . ' and ' . Session::get('end')->format(
'M jS, Y'
),
'series' => $series
];
return Response::json($return);
}
/**
* @param Category $category
*
* @return \Illuminate\Http\JsonResponse
*/
public function categoryShowChart(Category $category)
{
$start = Session::get('start');
$end = Session::get('end');
$range = Session::get('range');
$serie = $this->_chart->categoryShowChart($category, $range, $start, $end);
$data = [
'chart_title' => $category->name,
'subtitle' => '<a href="' . route('categories.show', [$category->id]) . '">View more</a>',
'series' => $serie
];
return Response::json($data);
}
/**
* @param Account $account
*
* @return mixed
*/
public function homeAccount(Account $account = null)
{
// get preferences and accounts (if necessary):
$start = Session::get('start');
$end = Session::get('end');
if (is_null($account)) {
// get, depending on preferences:
/** @var \Firefly\Helper\Preferences\PreferencesHelperInterface $prefs */
$prefs = \App::make('Firefly\Helper\Preferences\PreferencesHelperInterface');
$pref = $prefs->get('frontpageAccounts', []);
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $acct */
$acct = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$accounts = $acct->getByIds($pref->data);
} else {
$accounts = [$account];
}
// loop and get array data.
$url = count($accounts) == 1 && is_array($accounts)
? '<a href="' . route('accounts.show', [$account->id]) . '">View more</a>'
:
'<a href="' . route('accounts.index') . '">View more</a>';
$data = [
'chart_title' => count($accounts) == 1 ? $accounts[0]->name : 'All accounts',
'subtitle' => $url,
'series' => []
];
foreach ($accounts as $account) {
$data['series'][] = $this->_chart->account($account, $start, $end);
}
return Response::json($data);
}
/**
* @param $name
* @param $day
* @param $month
* @param $year
*
* @return $this
*/
public function homeAccountInfo($name, $day, $month, $year)
{
$account = $this->_accounts->findByName($name);
$date = Carbon::createFromDate($year, $month, $day);
$result = $this->_chart->accountDailySummary($account, $date);
return View::make('charts.info')->with('rows', $result['rows'])->with('sum', $result['sum'])->with(
'account', $account
);
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function homeBudgets()
{
$start = Session::get('start');
$end = Session::get('end');
$data = [
'labels' => [],
'series' => [
[
'name' => 'Limit',
'data' => []
],
[
'name' => 'Spent',
'data' => []
],
]
];
// Get all budgets.
$budgets = \Auth::user()->budgets()->orderBy('name', 'ASC')->get();
$budgetIds = [];
/** @var \Budget $budget */
foreach ($budgets as $budget) {
$budgetIds[] = $budget->id;
// Does the budget have a limit starting on $start?
$rep = \LimitRepetition::
leftJoin('limits', 'limit_repetitions.limit_id', '=', 'limits.id')->leftJoin(
'components', 'limits.component_id', '=', 'components.id'
)->where('limit_repetitions.startdate', $start->format('Y-m-d'))->where(
'components.id', $budget->id
)->first(['limit_repetitions.*']);
if (is_null($rep)) {
$limit = 0.0;
$id = null;
$parameter = 'useSession=true';
} else {
$limit = floatval($rep->amount);
$id = $rep->id;
$parameter = '';
}
// Date range to check for expenses made?
if (is_null($rep)) {
// use the session start and end for our search query
$expenseStart = Session::get('start');
$expenseEnd = Session::get('end');
} else {
// use the limit's start and end for our search query
$expenseStart = $rep->startdate;
$expenseEnd = $rep->enddate;
}
// How much have we spent on this budget?
$expenses = floatval($budget->transactionjournals()->before($expenseEnd)->after($expenseStart)->lessThan(0)->sum('amount')) * -1;
// Append to chart:
if ($limit > 0 || $expenses > 0) {
$data['labels'][] = $budget->name;
$data['series'][0]['data'][] = [
'y' => $limit,
'url' => route('budgets.show', [$budget->id, $id]) . '?' . $parameter
];
$data['series'][1]['data'][] = [
'y' => $expenses,
'url' => route('budgets.show', [$budget->id, $id]) . '?' . $parameter
];
}
}
// Add expenses that have no budget:
$set = \Auth::user()->transactionjournals()->whereNotIn(
'transaction_journals.id', function ($query) use ($start, $end) {
$query->select('transaction_journals.id')->from('transaction_journals')
->leftJoin(
'component_transaction_journal', 'component_transaction_journal.transaction_journal_id', '=',
'transaction_journals.id'
)
->leftJoin('components', 'components.id', '=', 'component_transaction_journal.component_id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d'))
->where('components.class', 'Budget');
}
)->before($end)->after($start)->lessThan(0)->transactionTypes(['Withdrawal'])->sum('amount');
// This can be debugged by using get(['transaction_journals.*','transactions.amount']);
$data['labels'][] = 'No budget';
$data['series'][0]['data'][] = [
'y' => 0,
'url' => route('budgets.nobudget','session')
];
$data['series'][1]['data'][] = [
'y' => floatval($set) * -1,
'url' => route('budgets.nobudget','session')
];
return Response::json($data);
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function homeCategories()
{
$start = Session::get('start');
$end = Session::get('end');
return Response::json($this->_chart->categories($start, $end));
}
}

View File

@@ -0,0 +1,197 @@
<?php
use FireflyIII\Database\TransactionCurrency\TransactionCurrency as Repository;
/**
*
* @SuppressWarnings("CamelCase") // I'm fine with this.
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
*
* Class CurrencyController
*/
class CurrencyController extends BaseController
{
/** @var Repository */
protected $_repository;
/**
* @param Repository $repository
*/
public function __construct(Repository $repository)
{
$this->_repository = $repository;
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::make('currency.create', compact('subTitleIcon', 'subTitle'));
}
/**
* @param TransactionCurrency $currency
*
* @return \Illuminate\Http\RedirectResponse
*/
public function defaultCurrency(TransactionCurrency $currency)
{
/** @var \FireflyIII\Shared\Preferences\Preferences $preferences */
$preferences = App::make('FireflyIII\Shared\Preferences\Preferences');
$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::make('currency.delete', compact('currency'));
}
/**
* @param TransactionCurrency $currency
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(TransactionCurrency $currency)
{
Session::flash('success', 'Currency "' . e($currency->name) . '" deleted');
$this->_repository->destroy($currency);
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::make('currency.edit', compact('currency', 'subTitle', 'subTitleIcon'));
}
/**
* @return \Illuminate\View\View
*/
public function index()
{
$currencies = $this->_repository->get();
/** @var \FireflyIII\Shared\Preferences\Preferences $preferences */
$preferences = App::make('FireflyIII\Shared\Preferences\Preferences');
$currencyPreference = $preferences->get('currencyPreference', 'EUR');
$defaultCurrency = $this->_repository->findByCode($currencyPreference->data);
return View::make('currency.index', compact('currencies', 'defaultCurrency'));
}
/**
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function store()
{
$data = Input::except('_token');
// always validate:
$messages = $this->_repository->validate($data);
// 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 currency: ' . $messages['errors']->first());
}
// return to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('currency.create')->withInput();
}
// store
$this->_repository->store($data);
Session::flash('success', 'Currency "' . e($data['name']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('currency.index');
}
return Redirect::route('currency.create')->withInput();
}
/**
* @param TransactionCurrency $currency
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function update(TransactionCurrency $currency)
{
$data = Input::except('_token');
// always validate:
$messages = $this->_repository->validate($data);
// 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 update currency: ' . $messages['errors']->first());
}
// return to update screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('currency.edit', $currency->id)->withInput();
}
// update
$this->_repository->update($currency, $data);
Session::flash('success', 'Currency "' . e($data['name']) . '" updated.');
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('currency.index');
}
return Redirect::route('currency.edit', $currency->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
}

View File

@@ -0,0 +1,488 @@
<?php
use Carbon\Carbon;
use FireflyIII\Chart\ChartInterface;
use Grumpydictator\Gchart\GChart as GChart;
/**
* Class GoogleChartController
* @SuppressWarnings("CamelCase") // I'm fine with this.
* @SuppressWarnings("TooManyMethods") // I'm also fine with this.
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
* @SuppressWarnings("MethodLength") // There is one with 45 lines and im gonna move it.
* @SuppressWarnings("CouplingBetweenObjects") // There's only so much I can remove.
*/
class GoogleChartController extends BaseController
{
/** @var GChart */
protected $_chart;
/** @var Carbon */
protected $_end;
/** @var ChartInterface */
protected $_repository;
/** @var Carbon */
protected $_start;
/**
* @param GChart $chart
* @param ChartInterface $repository
*/
public function __construct(GChart $chart, ChartInterface $repository)
{
$this->_chart = $chart;
$this->_repository = $repository;
$this->_start = Session::get('start', Carbon::now()->startOfMonth());
$this->_end = Session::get('end', Carbon::now()->endOfMonth());
}
/**
* @param Account $account
* @param string $view
*
* @return \Illuminate\Http\JsonResponse
*/
public function accountBalanceChart(Account $account, $view = 'session')
{
$this->_chart->addColumn('Day of month', 'date');
$this->_chart->addColumn('Balance for ' . $account->name, 'number');
$start = $this->_start;
$end = $this->_end;
$count = $account->transactions()->count();
if ($view == 'all' && $count > 0) {
$first = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy(
'date', 'ASC'
)->first(['transaction_journals.date']);
$last = $account->transactions()->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')->orderBy(
'date', 'DESC'
)->first(['transaction_journals.date']);
$start = new Carbon($first->date);
$end = new Carbon($last->date);
}
$current = clone $start;
while ($end >= $current) {
$this->_chart->addRow(clone $current, Steam::balance($account, $current));
$current->addDay();
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
* This method renders the b
*/
public function allAccountsBalanceChart()
{
$this->_chart->addColumn('Day of the month', 'date');
/** @var \FireflyIII\Shared\Preferences\Preferences $preferences */
$preferences = App::make('FireflyIII\Shared\Preferences\Preferences');
$pref = $preferences->get('frontPageAccounts', []);
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
$accounts = count($pref->data) > 0 ? $acct->getByIds($pref->data) : $acct->getAssetAccounts();
/** @var Account $account */
foreach ($accounts as $account) {
$this->_chart->addColumn('Balance for ' . $account->name, 'number');
}
$current = clone $this->_start;
$current->subDay();
while ($this->_end >= $current) {
$row = [clone $current];
foreach ($accounts as $account) {
$row[] = Steam::balance($account, $current);
}
$this->_chart->addRowArray($row);
$current->addDay();
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function allBudgetsHomeChart()
{
$this->_chart->addColumn('Budget', 'string');
$this->_chart->addColumn('Budgeted', 'number');
$this->_chart->addColumn('Spent', 'number');
Log::debug('Now in allBudgetsHomeChart()');
/** @var \FireflyIII\Database\Budget\Budget $bdt */
$bdt = App::make('FireflyIII\Database\Budget\Budget');
$budgets = $bdt->get();
/** @var Budget $budget */
foreach ($budgets as $budget) {
Log::debug('Now working budget #' . $budget->id . ', ' . $budget->name);
/** @var \LimitRepetition $repetition */
$repetition = $bdt->repetitionOnStartingOnDate($budget, $this->_start);
if (is_null($repetition)) {
\Log::debug('Budget #' . $budget->id . ' has no repetition on ' . $this->_start->format('Y-m-d'));
// use the session start and end for our search query
$searchStart = $this->_start;
$searchEnd = $this->_end;
$limit = 0; // the limit is zero:
} else {
\Log::debug('Budget #' . $budget->id . ' has a repetition on ' . $this->_start->format('Y-m-d') . '!');
// use the limit's start and end for our search query
$searchStart = $repetition->startdate;
$searchEnd = $repetition->enddate;
$limit = floatval($repetition->amount); // the limit is the repetitions limit:
}
$expenses = floatval($budget->transactionjournals()->before($searchEnd)->after($searchStart)->lessThan(0)->sum('amount')) * -1;
\Log::debug('Expenses in budget ' . $budget->name . ' before ' . $searchEnd->format('Y-m-d') . ' and after ' . $searchStart . ' are: ' . $expenses);
if ($expenses > 0) {
$this->_chart->addRow($budget->name, $limit, $expenses);
}
}
$noBudgetSet = $bdt->expenseNoBudget($this->_start, $this->_end);
$sum = $noBudgetSet->sum('amount') * -1;
$this->_chart->addRow('No budget', 0, $sum);
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function allCategoriesHomeChart()
{
$this->_chart->addColumn('Category', 'string');
$this->_chart->addColumn('Spent', 'number');
// query!
$set = $this->_repository->getCategorySummary($this->_start, $this->_end);
foreach ($set as $entry) {
$entry->name = strlen($entry->name) == 0 ? '(no category)' : $entry->name;
$this->_chart->addRow($entry->name, floatval($entry->sum));
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
* @param Bill $bill
*
* @return \Illuminate\Http\JsonResponse
*/
public function billOverview(Bill $bill)
{
$this->_chart->addColumn('Date', 'date');
$this->_chart->addColumn('Max amount', 'number');
$this->_chart->addColumn('Min amount', 'number');
$this->_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) {
$amount = $result->getAmount();
} else {
$amount = 0;
}
unset($result);
$this->_chart->addRow(clone $start, $bill->amount_max, $bill->amount_min, $amount);
$start = DateKit::addPeriod($start, $bill->repeat_freq, 0);
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
*
* @return \Illuminate\Http\JsonResponse
* @throws \FireflyIII\Exception\FireflyException
*/
public function billsOverview()
{
$paid = ['items' => [], 'amount' => 0];
$unpaid = ['items' => [], 'amount' => 0];
$this->_chart->addColumn('Name', 'string');
$this->_chart->addColumn('Amount', 'number');
$set = $this->_repository->getBillsSummary($this->_start, $this->_end);
foreach ($set as $entry) {
if (intval($entry->journalId) == 0) {
$unpaid['items'][] = $entry->name;
$unpaid['amount'] += floatval($entry->averageAmount);
} else {
$paid['items'][] = $entry->description;
$paid['amount'] += floatval($entry->actualAmount);
}
}
$this->_chart->addRow('Unpaid: ' . join(', ', $unpaid['items']), $unpaid['amount']);
$this->_chart->addRow('Paid: ' . join(', ', $paid['items']), $paid['amount']);
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
*
* @param Budget $budget
* @param LimitRepetition $repetition
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetLimitSpending(\Budget $budget, \LimitRepetition $repetition)
{
$start = clone $repetition->startdate;
$end = $repetition->enddate;
$this->_chart->addColumn('Day', 'date');
$this->_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;
$this->_chart->addRow(clone $start, $amount);
$start->addDay();
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
*
* @param Budget $budget
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function budgetsAndSpending(Budget $budget, $year)
{
try {
new Carbon('01-01-' . $year);
} catch (Exception $e) {
return View::make('error')->with('message', 'Invalid year.');
}
/** @var \FireflyIII\Database\Budget\Budget $budgetRepository */
$budgetRepository = App::make('FireflyIII\Database\Budget\Budget');
$this->_chart->addColumn('Month', 'date');
$this->_chart->addColumn('Budgeted', 'number');
$this->_chart->addColumn('Spent', 'number');
$start = new Carbon('01-01-' . $year);
$end = clone $start;
$end->endOfYear();
while ($start <= $end) {
$spent = $budgetRepository->spentInMonth($budget, $start);
$repetition = $budgetRepository->repetitionOnStartingOnDate($budget, $start);
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;
}
$this->_chart->addRow(clone $start, $budgeted, $spent);
$start->addMonth();
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
*
* @param Category $component
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function categoriesAndSpending(Category $component, $year)
{
try {
new Carbon('01-01-' . $year);
} catch (Exception $e) {
return View::make('error')->with('message', 'Invalid year.');
}
/** @var \FireflyIII\Database\Category\Category $categoryRepository */
$categoryRepository = App::make('FireflyIII\Database\Category\Category');
$this->_chart->addColumn('Month', 'date');
$this->_chart->addColumn('Budgeted', 'number');
$this->_chart->addColumn('Spent', 'number');
$start = new Carbon('01-01-' . $year);
$end = clone $start;
$end->endOfYear();
while ($start <= $end) {
$spent = $categoryRepository->spentInMonth($component, $start);
$budgeted = null;
$this->_chart->addRow(clone $start, $budgeted, $spent);
$start->addMonth();
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
* @param PiggyBank $piggyBank
*
* @return \Illuminate\Http\JsonResponse
*/
public function piggyBankHistory(\PiggyBank $piggyBank)
{
$this->_chart->addColumn('Date', 'date');
$this->_chart->addColumn('Balance', 'number');
$set = \DB::table('piggy_bank_events')->where('piggy_bank_id', $piggyBank->id)->groupBy('date')->get(['date', DB::Raw('SUM(`amount`) AS `sum`')]);
foreach ($set as $entry) {
$this->_chart->addRow(new Carbon($entry->date), floatval($entry->sum));
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
*
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function yearInExp($year)
{
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
return View::make('error')->with('message', 'Invalid year.');
}
$this->_chart->addColumn('Month', 'date');
$this->_chart->addColumn('Income', 'number');
$this->_chart->addColumn('Expenses', 'number');
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */
$repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
$end = clone $start;
$end->endOfYear();
while ($start < $end) {
// total income:
$income = $repository->getSumOfIncomesByMonth($start);
$expense = $repository->getSumOfExpensesByMonth($start);
$this->_chart->addRow(clone $start, $income, $expense);
$start->addMonth();
}
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
/**
*
* @param $year
*
* @return \Illuminate\Http\JsonResponse
*/
public function yearInExpSum($year)
{
try {
$start = new Carbon('01-01-' . $year);
} catch (Exception $e) {
return View::make('error')->with('message', 'Invalid year.');
}
$this->_chart->addColumn('Summary', 'string');
$this->_chart->addColumn('Income', 'number');
$this->_chart->addColumn('Expenses', 'number');
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $repository */
$repository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
$end = clone $start;
$end->endOfYear();
$income = 0;
$expense = 0;
$count = 0;
while ($start < $end) {
// total income:
$income += $repository->getSumOfIncomesByMonth($start);
$expense += $repository->getSumOfExpensesByMonth($start);
$count++;
$start->addMonth();
}
$this->_chart->addRow('Sum', $income, $expense);
$count = $count > 0 ? $count : 1;
$this->_chart->addRow('Average', ($income / $count), ($expense / $count));
$this->_chart->generate();
return Response::json($this->_chart->getData());
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
*
* Class HelpController
*/
class HelpController extends BaseController
{
/**
* @param $route
*
* @return \Illuminate\Http\JsonResponse
*/
public function show($route)
{
$helpText = '<p>There is no help for this route!</p>';
$helpTitle = 'Help';
if (!Route::has($route)) {
\Log::error('No such route: ' . $route);
return Response::json(['title' => $helpTitle, 'text' => $helpText]);
}
if (Cache::has('help.' . $route . '.title') && Cache::has('help.' . $route . '.text')) {
$helpText = Cache::get('help.' . $route . '.text');
$helpTitle = Cache::get('help.' . $route . '.title');
return Response::json(['title' => $helpTitle, 'text' => $helpText]);
}
$uri = 'https://raw.githubusercontent.com/JC5/firefly-iii-help/master/' . e($route) . '.md';
\Log::debug('URL is: ' . $uri);
try {
$helpText = file_get_contents($uri);
} catch (ErrorException $e) {
\Log::error(trim($e->getMessage()));
}
\Log::debug('Found help for ' . $route);
\Log::debug('Help text length for route ' . $route . ' is ' . strlen($helpText));
\Log::debug('Help text IS: "' . $helpText . '".');
if (strlen(trim($helpText)) == 0) {
$helpText = '<p>There is no help for this route.</p>';
}
$helpText = \Michelf\Markdown::defaultTransform($helpText);
$helpTitle = $route;
Cache::put('help.' . $route . '.text', $helpText, 10080); // a week.
Cache::put('help.' . $route . '.title', $helpTitle, 10080);
return Response::json(['title' => $helpTitle, 'text' => $helpText]);
}
}

View File

@@ -1,79 +1,12 @@
<?php
use Firefly\Helper\Preferences\PreferencesHelperInterface as PHI;
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
use Firefly\Storage\Reminder\ReminderRepositoryInterface as RRI;
use Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface as TJRI;
use Carbon\Carbon;
/**
* Class HomeController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class HomeController extends BaseController
{
protected $_accounts;
protected $_preferences;
protected $_journal;
protected $_reminders;
/**
* @param ARI $accounts
* @param PHI $preferences
* @param TJRI $journal
* @param RRI $reminders
*/
public function __construct(ARI $accounts, PHI $preferences, TJRI $journal, RRI $reminders)
{
$this->_accounts = $accounts;
$this->_preferences = $preferences;
$this->_journal = $journal;
$this->_reminders = $reminders;
}
public function jobDev()
{
$fullName = storage_path() . DIRECTORY_SEPARATOR . 'firefly-export-2014-07-23.json';
\Log::notice('Pushed start job.');
Queue::push('Firefly\Queue\Import@start', ['file' => $fullName, 'user' => 1]);
}
/*
*
*/
public function sessionPrev()
{
/** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */
$toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface');
$toolkit->prev();
return Redirect::back();
//return Redirect::route('index');
}
/*
*
*/
public function sessionNext()
{
/** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */
$toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface');
$toolkit->next();
return Redirect::back();
//return Redirect::route('index');
}
public function rangeJump($range)
{
$viewRange = $this->_preferences->get('viewRange', '1M');
$valid = ['1D', '1W', '1M', '3M', '6M', '1Y',];
if(in_array($range,$valid)) {
$this->_preferences->set('viewRange', $range);
Session::forget('range');
}
return Redirect::back();
}
/**
* @return \Illuminate\Http\RedirectResponse
@@ -90,34 +23,81 @@ class HomeController extends BaseController
*/
public function index()
{
Event::fire('limits.check');
Event::fire('piggybanks.check');
Event::fire('recurring.check');
// count, maybe Firefly needs some introducing text to show:
$count = $this->_accounts->count();
$start = Session::get('start');
$end = Session::get('end');
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
/** @var \FireflyIII\Database\TransactionJournal\TransactionJournal $journalRepository */
$journalRepository = App::make('FireflyIII\Database\TransactionJournal\TransactionJournal');
/** @var \FireflyIII\Shared\Preferences\PreferencesInterface $preferences */
$preferences = App::make('FireflyIII\Shared\Preferences\PreferencesInterface');
$count = $acct->countAssetAccounts();
$start = Session::get('start', Carbon::now()->startOfMonth());
$end = Session::get('end', Carbon::now()->endOfMonth());
// get the preference for the home accounts to show:
$frontpage = $this->_preferences->get('frontpageAccounts', []);
if ($frontpage->data == []) {
$accounts = $this->_accounts->getActiveDefault();
$frontPage = $preferences->get('frontPageAccounts', []);
if ($frontPage->data == []) {
$accounts = $acct->getAssetAccounts();
} else {
$accounts = $this->_accounts->getByIds($frontpage->data);
$accounts = $acct->getByIds($frontPage->data);
}
$transactions = [];
foreach ($accounts as $account) {
$set = $this->_journal->getByAccountInDateRange($account, 10, $start, $end);
$set = $journalRepository->getInDateRangeAccount($account, $start, $end, 10);
if (count($set) > 0) {
$transactions[] = [$set, $account];
}
}
// build the home screen:
return View::make('index')->with('count', $count)->with('transactions', $transactions)->with('title', 'Firefly')
->with('subTitle', 'What\'s playing?')->with('mainTitleIcon', 'fa-fire');
return View::make('index')->with('count', $count)->with('transactions', $transactions)->with('title', 'Firefly')->with('subTitle', 'What\'s playing?')
->with('mainTitleIcon', 'fa-fire');
}
}
/**
* @param $range
*
* @return \Illuminate\Http\RedirectResponse
*/
public function rangeJump($range)
{
$valid = ['1D', '1W', '1M', '3M', '6M', '1Y',];
/** @var \FireflyIII\Shared\Preferences\PreferencesInterface $preferences */
$preferences = App::make('FireflyIII\Shared\Preferences\PreferencesInterface');
if (in_array($range, $valid)) {
$preferences->set('viewRange', $range);
Session::forget('range');
}
return Redirect::intended('/');
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function sessionNext()
{
Navigation::next();
return Redirect::intended('/');
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
public function sessionPrev()
{
Navigation::prev();
return Redirect::intended('/');
}
}

View File

@@ -1,25 +1,11 @@
<?php
use Firefly\Helper\Controllers\JsonInterface as JI;
use Illuminate\Support\Collection;
use LaravelBook\Ardent\Builder;
/**
* Class JsonController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class JsonController extends BaseController
{
/** @var \Firefly\Helper\Controllers\JsonInterface $helper */
protected $helper;
public function __construct(JI $helper)
{
$this->helper = $helper;
}
/**
* Returns a list of categories.
@@ -28,8 +14,8 @@ class JsonController extends BaseController
*/
public function categories()
{
/** @var \Firefly\Storage\Category\EloquentCategoryRepository $categories */
$categories = App::make('Firefly\Storage\Category\CategoryRepositoryInterface');
/** @var \FireflyIII\Database\Category\Category $categories */
$categories = App::make('FireflyIII\Database\Category\Category');
$list = $categories->get();
$return = [];
foreach ($list as $entry) {
@@ -48,9 +34,9 @@ class JsonController extends BaseController
*/
public function expenseAccounts()
{
/** @var \Firefly\Storage\Account\EloquentAccountRepository $accounts */
$accounts = App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$list = $accounts->getOfTypes(['Expense account', 'Beneficiary account']);
/** @var \FireflyIII\Database\Account\Account $accounts */
$accounts = App::make('FireflyIII\Database\Account\Account');
$list = $accounts->getExpenseAccounts();
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
@@ -61,99 +47,13 @@ class JsonController extends BaseController
}
/**
* Returns a list of transactions, expenses only, using the given parameters.
*
* @return \Illuminate\Http\JsonResponse
*/
public function expenses()
{
/*
* Gets most parameters from the Input::all() array:
*/
$parameters = $this->helper->dataTableParameters();
/*
* Add some more parameters to fine tune the query:
*/
$parameters['transactionTypes'] = ['Withdrawal'];
$parameters['amount'] = 'negative';
/*
* Get the query:
*/
$query = $this->helper->journalQuery($parameters);
/*
* Build result set:
*/
$resultSet = $this->helper->journalDataset($parameters, $query);
/*
* Build return data:
*/
return Response::json($resultSet);
}
/**
*
*/
public function recurringjournals(RecurringTransaction $recurringTransaction)
{
$parameters = $this->helper->dataTableParameters();
$parameters['transactionTypes'] = ['Withdrawal'];
$parameters['amount'] = 'negative';
$query = $this->helper->journalQuery($parameters);
$query->where('recurring_transaction_id', $recurringTransaction->id);
$resultSet = $this->helper->journalDataset($parameters, $query);
/*
* Build return data:
*/
return Response::json($resultSet);
}
public function recurring()
{
$parameters = $this->helper->dataTableParameters();
$query = $this->helper->recurringTransactionsQuery($parameters);
$resultSet = $this->helper->recurringTransactionsDataset($parameters, $query);
return Response::json($resultSet);
}
/**
* @return \Illuminate\Http\JsonResponse|string
*/
public function revenue()
{
$parameters = $this->helper->dataTableParameters();
$parameters['transactionTypes'] = ['Deposit'];
$parameters['amount'] = 'positive';
$query = $this->helper->journalQuery($parameters);
$resultSet = $this->helper->journalDataset($parameters, $query);
/*
* Build return data:
*/
return Response::json($resultSet);
}
/**
* Returns a JSON list of all revenue accounts.
*
* @return \Illuminate\Http\JsonResponse
*/
public function revenueAccounts()
{
/** @var \Firefly\Storage\Account\EloquentAccountRepository $accounts */
$accounts = App::make('Firefly\Storage\Account\AccountRepositoryInterface');
$list = $accounts->getOfTypes(['Revenue account']);
/** @var \FireflyIII\Database\Account\Account $accounts */
$accounts = App::make('FireflyIII\Database\Account\Account');
$list = $accounts->getRevenueAccounts();
$return = [];
foreach ($list as $entry) {
$return[] = $entry->name;
@@ -162,25 +62,4 @@ class JsonController extends BaseController
return Response::json($return);
}
/**
* Returns a list of all transfers.
*
* @return \Illuminate\Http\JsonResponse
*/
public function transfers()
{
$parameters = $this->helper->dataTableParameters();
$parameters['transactionTypes'] = ['Transfer'];
$parameters['amount'] = 'positive';
$query = $this->helper->journalQuery($parameters);
$resultSet = $this->helper->journalDataset($parameters, $query);
/*
* Build return data:
*/
return Response::json($resultSet);
}
}
}

View File

@@ -1,162 +0,0 @@
<?php
use Firefly\Storage\Budget\BudgetRepositoryInterface as BRI;
use Firefly\Storage\Limit\LimitRepositoryInterface as LRI;
/**
* Class LimitController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class LimitController extends BaseController
{
protected $_budgets;
protected $_limits;
/**
* @param BRI $budgets
* @param LRI $limits
*/
public function __construct(BRI $budgets, LRI $limits)
{
$this->_budgets = $budgets;
$this->_limits = $limits;
View::share('title','Envelopes');
View::share('mainTitleIcon', 'fa-tasks');
}
/**
* @param Budget $budget
*
* @return $this
*/
public function create(\Budget $budget = null)
{
$periods = \Config::get('firefly.periods_to_text');
$prefilled = [
'startdate' => \Input::get('startdate') ? : date('Y-m-d'),
'repeat_freq' => \Input::get('repeat_freq') ? : 'monthly',
'budget_id' => $budget ? $budget->id : null
];
/** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */
$toolkit = App::make('Firefly\Helper\Toolkit\Toolkit');
$budgets = $toolkit->makeSelectList($this->_budgets->get());
return View::make('limits.create')->with('budgets', $budgets)->with(
'periods', $periods
)->with('prefilled', $prefilled)->with('subTitle','New envelope');
}
/**
* @param Limit $limit
*
* @return $this
*/
public function delete(\Limit $limit)
{
return View::make('limits.delete')->with('limit', $limit)->with('subTitle','Delete envelope');
}
/**
* @param Limit $limit
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(\Limit $limit)
{
Event::fire('limits.destroy', [$limit]); // before
$success = $this->_limits->destroy($limit);
if ($success) {
Session::flash('success', 'The envelope was deleted.');
} else {
Session::flash('error', 'Could not delete the envelope. Check the logs to be sure.');
}
if (Input::get('from') == 'date') {
return Redirect::route('budgets.index');
} else {
return Redirect::route('budgets.index.budget');
}
}
/**
* @param Limit $limit
*
* @return $this
*/
public function edit(Limit $limit)
{
/** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */
$toolkit = App::make('Firefly\Helper\Toolkit\Toolkit');
$budgets = $toolkit->makeSelectList($this->_budgets->get());
$periods = \Config::get('firefly.periods_to_text');
return View::make('limits.edit')->with('limit', $limit)->with('budgets', $budgets)->with(
'periods', $periods
)->with('subTitle','Edit envelope');
}
/**
* @param Budget $budget
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function store(Budget $budget = null)
{
// find a limit with these properties, as Firefly might already have one:
$limit = $this->_limits->store(Input::all());
if ($limit->validate()) {
Session::flash('success', 'Envelope created!');
Event::fire('limits.store', [$limit]);
if (Input::get('from') == 'date') {
return Redirect::route('budgets.index');
} else {
return Redirect::route('budgets.index.budget');
}
} else {
Session::flash('error', 'Could not save new envelope.');
$budgetId = $budget ? $budget->id : null;
$parameters = [$budgetId, 'from' => Input::get('from')];
return Redirect::route('budgets.limits.create', $parameters)->withInput()
->withErrors($limit->errors());
}
}
/**
* @param Limit $limit
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function update(\Limit $limit)
{
$limit = $this->_limits->update($limit, Input::all());
if ($limit->validate()) {
Event::fire('limits.update', [$limit]);
Session::flash('success', 'Limit saved!');
if (Input::get('from') == 'date') {
return Redirect::route('budgets.index');
} else {
return Redirect::route('budgets.index.budget');
}
} else {
Session::flash('error', 'Could not save new limit: ' . $limit->errors()->first());
return Redirect::route('budgets.limits.edit', [$limit->id, 'from' => Input::get('from')])->withInput()
->withErrors($limit->errors());
}
}
}

View File

@@ -1,52 +0,0 @@
<?php
/**
* Class MigrateController
*/
class MigrateController extends BaseController
{
/**
* @return $this
*/
public function index()
{
return View::make('migrate.index')->with('index', 'Migration')->with('title','Migrate')->
with('subTitle','From Firefly II to Firefly III');
}
/**
*
*/
public function upload()
{
if (Input::hasFile('file') && Input::file('file')->isValid()) {
$path = storage_path();
$fileName = 'firefly-iii-import-' . date('Y-m-d-H-i') . '.json';
$fullName = $path . DIRECTORY_SEPARATOR . $fileName;
if (Input::file('file')->move($path, $fileName)) {
// so now Firefly pushes something in a queue and does something with it! Yay!
\Log::debug('Pushed a job to start the import.');
Queue::push('Firefly\Queue\Import@start', ['file' => $fullName, 'user' => \Auth::user()->id]);
if (Config::get('queue.default') == 'sync') {
Session::flash('success', 'Your data has been imported!');
} else {
Session::flash(
'success',
'The import job has been queued. Please be patient. Data will appear slowly. Please be patient.'
);
}
return Redirect::route('index');
}
Session::flash('error', 'Could not save file to storage.');
return Redirect::route('migrate.index');
} else {
Session::flash('error', 'Please upload a file.');
return Redirect::route('migrate.index');
}
}
}

View File

@@ -1,404 +1,358 @@
<?php
use Firefly\Exception\FireflyException;
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
use Firefly\Storage\Piggybank\PiggybankRepositoryInterface as PRI;
use Carbon\Carbon;
use FireflyIII\Database\PiggyBank\PiggyBank as Repository;
use FireflyIII\Exception\FireflyException;
use Illuminate\Support\Collection;
/**
* Class PiggybankController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.TooManyMethods)
* @SuppressWarnings("CamelCase") // I'm fine with this.
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
* @SuppressWarnings("TooManyMethods") // I'm also fine with this.
* @SuppressWarnings("CouplingBetweenObjects") // There's only so much I can remove.
*
*
* Class PiggyBankController
*
*/
class PiggybankController extends BaseController
class PiggyBankController extends BaseController
{
protected $_accounts;
/** @var Repository */
protected $_repository;
/**
* @param PRI $repository
* @param ARI $accounts
* @param Repository $repository
*/
public function __construct(PRI $repository, ARI $accounts)
public function __construct(Repository $repository)
{
$this->_repository = $repository;
$this->_accounts = $accounts;
}
/**
* @param Piggybank $piggyBank
*
* @return $this
*/
public function addMoney(Piggybank $piggyBank)
{
$what = 'add';
$maxAdd = $this->_repository->leftOnAccount($piggyBank->account);
$maxRemove = null;
return View::make('piggybanks.modifyAmount')->with('what', $what)->with('maxAdd', $maxAdd)->with(
'maxRemove', $maxRemove
)->with('piggybank', $piggyBank);
}
/**
* @return $this
*/
public function createPiggybank()
{
/** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */
$toolkit = App::make('Firefly\Helper\Toolkit\Toolkit');
$periods = Config::get('firefly.piggybank_periods');
$list = $this->_accounts->getActiveDefault();
$accounts = $toolkit->makeSelectList($list);
View::share('title', 'Piggy banks');
View::share('subTitle', 'Create new');
View::share('mainTitleIcon', 'fa-sort-amount-asc');
return View::make('piggybanks.create-piggybank')->with('accounts', $accounts)
->with('periods', $periods);
}
/**
* @return $this
*/
public function createRepeated()
{
/** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */
$toolkit = App::make('Firefly\Helper\Toolkit\Toolkit');
$periods = Config::get('firefly.piggybank_periods');
$list = $this->_accounts->getActiveDefault();
$accounts = $toolkit->makeSelectList($list);
View::share('title', 'Repeated expenses');
View::share('subTitle', 'Create new');
View::share('mainTitleIcon', 'fa-rotate-right');
return View::make('piggybanks.create-repeated')->with('accounts', $accounts)->with('periods', $periods);
}
/**
* @param Piggybank $piggyBank
* Add money to piggy bank
*
* @param PiggyBank $piggyBank
*
* @return $this
*/
public function delete(Piggybank $piggyBank)
{
View::share('subTitle', 'Delete "' . $piggyBank->name . '"');
if ($piggyBank->repeats == 1) {
View::share('title', 'Repeated expenses');
View::share('mainTitleIcon', 'fa-rotate-right');
} else {
View::share('title', 'Piggy banks');
View::share('mainTitleIcon', 'fa-sort-amount-asc');
}
return View::make('piggybanks.delete')->with('piggybank', $piggyBank);
}
/**
* @param Piggybank $piggyBank
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Piggybank $piggyBank)
{
Event::fire('piggybanks.destroy', [$piggyBank]);
if ($piggyBank->repeats == 1) {
$route = 'piggybanks.index.repeated';
$message = 'Repeated expense';
} else {
$route = 'piggybanks.index.piggybanks';
$message = 'Piggybank';
}
$this->_repository->destroy($piggyBank);
Session::flash('success', $message . ' deleted.');
return Redirect::route($route);
}
/**
* @param Piggybank $piggyBank
*
* @return $this
*/
public function edit(Piggybank $piggyBank)
{
/** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */
$toolkit = App::make('Firefly\Helper\Toolkit\Toolkit');
$list = $this->_accounts->getActiveDefault();
$accounts = $toolkit->makeSelectList($list);
$periods = Config::get('firefly.piggybank_periods');
View::share('subTitle', 'Edit "' . $piggyBank->name . '"');
if ($piggyBank->repeats == 1) {
View::share('title', 'Repeated expenses');
View::share('mainTitleIcon', 'fa-rotate-left');
return View::make('piggybanks.edit-repeated')->with('piggybank', $piggyBank)->with('accounts', $accounts)
->with('periods', $periods);
} else {
// piggy bank.
View::share('title', 'Piggy banks');
View::share('mainTitleIcon', 'fa-sort-amount-asc');
return View::make('piggybanks.edit-piggybank')->with('piggybank', $piggyBank)->with('accounts', $accounts)
->with('periods', $periods);
}
}
/**
* @param Piggybank $piggyBank
*
* @return \Illuminate\Http\RedirectResponse
* @throws Firefly\Exception\FireflyException
*/
public function modMoney(Piggybank $piggyBank)
{
$amount = floatval(Input::get('amount'));
switch (Input::get('what')) {
default:
throw new FireflyException('No such action');
break;
case 'add':
$maxAdd = $this->_repository->leftOnAccount($piggyBank->account);
if (round($amount, 2) <= round(min($maxAdd, $piggyBank->targetamount), 2)) {
Session::flash('success', 'Amount updated!');
$this->_repository->modifyAmount($piggyBank, $amount);
Event::fire('piggybanks.modifyAmountAdd', [$piggyBank, $amount]);
} else {
Session::flash('warning', 'Could not!');
}
break;
case 'remove':
$rep = $piggyBank->currentRelevantRep();
$maxRemove = $rep->currentamount;
if (round($amount, 2) <= round($maxRemove, 2)) {
Session::flash('success', 'Amount updated!');
$this->_repository->modifyAmount($piggyBank, ($amount * -1));
Event::fire('piggybanks.modifyAmountRemove', [$piggyBank, ($amount * -1)]);
} else {
Session::flash('warning', 'Could not!');
}
break;
}
if($piggyBank->repeats == 1) {
$route = 'piggybanks.index.repeated';
} else {
$route = 'piggybanks.index.piggybanks';
}
return Redirect::route($route);
}
/**
* @return $this
*/
public function piggybanks()
{
$countRepeating = $this->_repository->countRepeating();
$countNonRepeating = $this->_repository->countNonrepeating();
$piggybanks = $this->_repository->get();
// get the accounts with each piggy bank and check their balance; Fireflyy might needs to
// show the user a correction.
$accounts = [];
/** @var \Piggybank $piggybank */
foreach ($piggybanks as $piggybank) {
$account = $piggybank->account;
$id = $account->id;
if (!isset($accounts[$id])) {
$account->leftOnAccount = $this->_repository->leftOnAccount($account);
$accounts[$id] = ['account' => $account, 'left' => $this->_repository->leftOnAccount($account)];
}
}
View::share('title', 'Piggy banks');
View::share('subTitle', 'Save for big expenses');
View::share('mainTitleIcon', 'fa-sort-amount-asc');
return View::make('piggybanks.index')->with('piggybanks', $piggybanks)
->with('countRepeating', $countRepeating)
->with('countNonRepeating', $countNonRepeating)
->with('accounts', $accounts);
}
/**
* @param Piggybank $piggyBank
*
* @return $this
*/
public function removeMoney(Piggybank $piggyBank)
{
$what = 'remove';
$maxAdd = $this->_repository->leftOnAccount($piggyBank->account);
$maxRemove = $piggyBank->currentRelevantRep()->currentamount;
return View::make('piggybanks.modifyAmount')->with('what', $what)->with('maxAdd', $maxAdd)->with(
'maxRemove', $maxRemove
)->with('piggybank', $piggyBank);
}
/**
* @return $this
*/
public function repeated()
{
$countRepeating = $this->_repository->countRepeating();
$countNonRepeating = $this->_repository->countNonrepeating();
$piggybanks = $this->_repository->get();
// get the accounts with each piggy bank and check their balance; Fireflyy might needs to
// show the user a correction.
$accounts = [];
/** @var \Piggybank $piggybank */
foreach ($piggybanks as $piggybank) {
$account = $piggybank->account;
$id = $account->id;
if (!isset($accounts[$id])) {
$account->leftOnAccount = $this->_repository->leftOnAccount($account);
$accounts[$id] = ['account' => $account, 'left' => $this->_repository->leftOnAccount($account)];
}
}
View::share('title', 'Repeated expenses');
View::share('subTitle', 'Save for returning bills');
View::share('mainTitleIcon', 'fa-rotate-left');
return View::make('piggybanks.index')->with('piggybanks', $piggybanks)
->with('countRepeating', $countRepeating)
->with('countNonRepeating', $countNonRepeating)
->with('accounts', $accounts);
}
/**
*
*/
public function show(Piggybank $piggyBank)
public function add(PiggyBank $piggyBank)
{
$leftOnAccount = $this->_repository->leftOnAccount($piggyBank->account);
$balance = $piggyBank->account->balance();
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = $piggyBank->targetamount - $savedSoFar;
$maxAmount = min($leftOnAccount, $leftToSave);
View::share('subTitle', $piggyBank->name);
if ($piggyBank->repeats == 1) {
// repeated expense.
View::share('title', 'Repeated expenses');
View::share('mainTitleIcon', 'fa-rotate-left');
} else {
// piggy bank.
View::share('title', 'Piggy banks');
View::share('mainTitleIcon', 'fa-sort-amount-asc');
}
\Log::debug('Now going to view for piggy bank #' . $piggyBank->id . ' (' . $piggyBank->name . ')');
return View::make('piggybanks.show')->with('piggyBank', $piggyBank)->with('leftOnAccount', $leftOnAccount)
->with('balance', $balance);
return View::make('piggy_banks.add', compact('piggyBank', 'maxAmount'));
}
/**
* @return $this|\Illuminate\Http\RedirectResponse
* @return mixed
*/
public function storePiggybank()
{
$data = Input::all();
unset($data['_token']);
// extend the data array with the settings needed to create a piggy bank:
$data['repeats'] = 0;
$data['rep_times'] = 1;
$data['rep_every'] = 1;
$data['order'] = 0;
$piggyBank = $this->_repository->store($data);
if (!is_null($piggyBank->id)) {
Session::flash('success', 'New piggy bank "' . $piggyBank->name . '" created!');
Event::fire('piggybanks.store', [$piggyBank]);
return Redirect::route('piggybanks.index.piggybanks');
} else {
Session::flash('error', 'Could not save piggy bank: ' . $piggyBank->errors()->first());
return Redirect::route('piggybanks.create.piggybank')->withInput()->withErrors($piggyBank->errors());
}
}
/**
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function storeRepeated()
public function create()
{
$data = Input::all();
unset($data['_token']);
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
// extend the data array with the settings needed to create a repeated:
$data['repeats'] = 1;
$data['order'] = 0;
$piggyBank = $this->_repository->store($data);
if ($piggyBank->id) {
Session::flash('success', 'New piggy bank "' . $piggyBank->name . '" created!');
Event::fire('piggybanks.store', [$piggyBank]);
return Redirect::route('piggybanks.index.repeated');
} else {
Session::flash('error', 'Could not save piggy bank: ' . $piggyBank->errors()->first());
return Redirect::route('piggybanks.create.repeated')->withInput()->withErrors($piggyBank->errors());
}
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = FFForm::makeSelectList($acct->getAssetAccounts());
$subTitle = 'Create new piggy bank';
$subTitleIcon = 'fa-plus';
return View::make('piggy_banks.create', compact('accounts', 'periods', 'subTitle', 'subTitleIcon'));
}
/**
* @param Piggybank $piggyBank
* @param PiggyBank $piggyBank
*
* @return $this|\Illuminate\Http\RedirectResponse
* @return $this
*/
public function update(Piggybank $piggyBank)
public function delete(PiggyBank $piggyBank)
{
$piggyBank = $this->_repository->update($piggyBank, Input::all());
if ($piggyBank->validate()) {
if ($piggyBank->repeats == 1) {
$route = 'piggybanks.index.repeated';
$message = 'Repeated expense';
} else {
$route = 'piggybanks.index.piggybanks';
$message = 'Piggy bank';
}
$subTitle = 'Delete "' . e($piggyBank->name) . '"';
return View::make('piggy_banks.delete', compact('piggyBank', 'subTitle'));
}
Session::flash('success', $message . ' "' . $piggyBank->name . '" updated.');
Event::fire('piggybanks.update', [$piggyBank]);
/**
* @param PiggyBank $piggyBank
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(PiggyBank $piggyBank)
{
return Redirect::route($route);
Session::flash('success', 'Piggy bank "' . e($piggyBank->name) . '" deleted.');
$this->_repository->destroy($piggyBank);
return Redirect::route('piggy_banks.index');
}
/**
* @param PiggyBank $piggyBank
*
* @return $this
*/
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->getAssetAccounts());
$subTitle = 'Edit piggy bank "' . e($piggyBank->name) . '"';
$subTitleIcon = 'fa-pencil';
/*
* Flash some data to fill the form.
*/
if (is_null($piggyBank->targetdate) || $piggyBank->targetdate == '') {
$targetDate = null;
} else {
Session::flash('error', 'Could not update piggy bank: ' . $piggyBank->errors()->first());
$targetDate = new Carbon($piggyBank->targetdate);
$targetDate = $targetDate->format('Y-m-d');
}
$preFilled = ['name' => $piggyBank->name,
'account_id' => $piggyBank->account_id,
'targetamount' => $piggyBank->targetamount,
'targetdate' => $targetDate,
'reminder' => $piggyBank->reminder,
'remind_me' => intval($piggyBank->remind_me) == 1 || !is_null($piggyBank->reminder) ? true : false
];
Session::flash('preFilled', $preFilled);
return Redirect::route('piggybanks.edit', $piggyBank->id)->withErrors($piggyBank->errors())->withInput();
return View::make('piggy_banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'accounts', 'periods', 'preFilled'));
}
/**
* @return $this
*/
public function index()
{
/** @var Collection $piggyBanks */
$piggyBanks = $this->_repository->get();
$accounts = [];
/** @var PiggyBank $piggyBank */
foreach ($piggyBanks as $piggyBank) {
$piggyBank->savedSoFar = floatval($piggyBank->currentRelevantRep()->currentamount);
$piggyBank->percentage = intval($piggyBank->savedSoFar / $piggyBank->targetamount * 100);
$piggyBank->leftToSave = $piggyBank->targetamount - $piggyBank->savedSoFar;
/*
* Fill account information:
*/
$account = $piggyBank->account;
if (!isset($accounts[$account->id])) {
$accounts[$account->id] = [
'name' => $account->name,
'balance' => Steam::balance($account),
'leftForPiggyBanks' => $this->_repository->leftOnAccount($account),
'sumOfSaved' => $piggyBank->savedSoFar,
'sumOfTargets' => floatval($piggyBank->targetamount),
'leftToSave' => $piggyBank->leftToSave
];
} else {
$accounts[$account->id]['sumOfSaved'] += $piggyBank->savedSoFar;
$accounts[$account->id]['sumOfTargets'] += floatval($piggyBank->targetamount);
$accounts[$account->id]['leftToSave'] += $piggyBank->leftToSave;
}
}
return View::make('piggy_banks.index', compact('piggyBanks', 'accounts'));
}
/**
* POST add money to piggy bank
*
* @param PiggyBank $piggyBank
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postAdd(PiggyBank $piggyBank)
{
$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);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$leftToSave = $piggyBank->targetamount - $savedSoFar;
$maxAmount = round(min($leftOnAccount, $leftToSave), 2);
if ($amount <= $maxAmount) {
$repetition = $piggyBank->currentRelevantRep();
$repetition->currentamount += $amount;
$repetition->save();
/*
* Create event!
*/
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');
}
/**
* @param PiggyBank $piggyBank
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postRemove(PiggyBank $piggyBank)
{
$amount = floatval(Input::get('amount'));
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
if ($amount <= $savedSoFar) {
$repetition = $piggyBank->currentRelevantRep();
$repetition->currentamount -= $amount;
$repetition->save();
/*
* Create event!
*/
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');
}
/**
* @param PiggyBank $piggyBank
*
* @SuppressWarnings("Unused")
*
* @return \Illuminate\View\View
*/
public function remove(PiggyBank $piggyBank)
{
return View::make('piggy_banks.remove', compact('piggyBank'));
}
/**
* @param PiggyBank $piggyBank
*
* @return $this
*/
public function show(PiggyBank $piggyBank)
{
$events = $piggyBank->piggyBankEvents()->orderBy('date', 'DESC')->orderBy('id', 'DESC')->get();
/*
* Number of reminders:
*/
$subTitle = e($piggyBank->name);
return View::make('piggy_banks.show', compact('piggyBank', 'events', 'subTitle'));
}
/**
*
*/
public function store()
{
$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;
// always validate:
$messages = $this->_repository->validate($data);
// 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 to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
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();
}
}
/**
* @param PiggyBank $piggyBank
*
* @return $this
* @throws FireflyException
*/
public function update(PiggyBank $piggyBank)
{
$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);
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 to update screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('piggy_banks.edit', $piggyBank->id)->withInput();
}
// update
$this->_repository->update($piggyBank, $data);
Session::flash('success', 'Piggy bank "' . e($data['name']) . '" updated.');
// 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

@@ -1,29 +1,21 @@
<?php
use Firefly\Helper\Preferences\PreferencesHelperInterface as PHI;
use Firefly\Storage\Account\AccountRepositoryInterface as ARI;
/**
* Class PreferencesController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
*
*/
class PreferencesController extends BaseController
{
protected $_accounts;
protected $_preferences;
/**
* @param ARI $accounts
* @param PHI $preferences
*
*/
public function __construct(ARI $accounts, PHI $preferences)
public function __construct()
{
$this->_accounts = $accounts;
$this->_preferences = $preferences;
View::share('title','Preferences');
View::share('mainTitleIcon','fa-gear');
View::share('title', 'Preferences');
View::share('mainTitleIcon', 'fa-gear');
}
/**
@@ -31,16 +23,22 @@ class PreferencesController extends BaseController
*/
public function index()
{
$accounts = $this->_accounts->getDefault();
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
$viewRange = $this->_preferences->get('viewRange', '1M');
/** @var \FireflyIII\Shared\Preferences\Preferences $preferences */
$preferences = App::make('FireflyIII\Shared\Preferences\Preferences');
$accounts = $acct->getAssetAccounts();
$viewRange = $preferences->get('viewRange', '1M');
$viewRangeValue = $viewRange->data;
$frontPage = $preferences->get('frontPageAccounts', []);
$budgetMax = $preferences->get('budgetMaximum', 1000);
$budgetMaximum = $budgetMax->data;
// pref:
$frontpage = $this->_preferences->get('frontpageAccounts', []);
return View::make('preferences.index')->with('accounts', $accounts)->with('frontpageAccounts', $frontpage)
->with('viewRange', $viewRangeValue);
return View::make('preferences.index', compact('budgetMaximum'))->with('accounts', $accounts)->with('frontPageAccounts', $frontPage)->with(
'viewRange', $viewRangeValue
);
}
/**
@@ -48,24 +46,31 @@ class PreferencesController extends BaseController
*/
public function postIndex()
{
/** @var \FireflyIII\Shared\Preferences\Preferences $preferences */
$preferences = App::make('FireflyIII\Shared\Preferences\Preferences');
// frontpage accounts
$frontpageAccounts = [];
foreach (Input::get('frontpageAccounts') as $id) {
$frontpageAccounts[] = intval($id);
// front page accounts
$frontPageAccounts = [];
foreach (Input::get('frontPageAccounts') as $id) {
$frontPageAccounts[] = intval($id);
}
$this->_preferences->set('frontpageAccounts', $frontpageAccounts);
$preferences->set('frontPageAccounts', $frontPageAccounts);
// view range:
$this->_preferences->set('viewRange', Input::get('viewRange'));
$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,19 +1,21 @@
<?php
use Firefly\Storage\User\UserRepositoryInterface as URI;
/**
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
*
* Class ProfileController
*/
class ProfileController extends BaseController
{
/**
* @param URI $user
* @return \Illuminate\View\View
*/
public function __construct(URI $user)
public function changePassword()
{
$this->user = $user;
return View::make('profile.change-password')->with('title', Auth::user()->email)->with('subTitle', 'Change your password')->with(
'mainTitleIcon', 'fa-user'
);
}
/**
@@ -22,21 +24,7 @@ class ProfileController extends BaseController
*/
public function index()
{
View::share('title','Profile');
View::share('subTitle',Auth::user()->email);
View::share('mainTitleIcon','fa-user');
return View::make('profile.index');
}
/**
* @return \Illuminate\View\View
*/
public function changePassword()
{
View::share('title',Auth::user()->email);
View::share('subTitle','Change your password');
View::share('mainTitleIcon','fa-user');
return View::make('profile.change-password');
return View::make('profile.index')->with('title', 'Profile')->with('subTitle', Auth::user()->email)->with('mainTitleIcon', 'fa-user');
}
/**
@@ -46,7 +34,6 @@ class ProfileController extends BaseController
{
// old, new1, new2
/** @noinspection PhpUndefinedFieldInspection */
if (!Hash::check(Input::get('old'), Auth::user()->password)) {
Session::flash('error', 'Invalid current password!');
@@ -70,12 +57,13 @@ class ProfileController extends BaseController
}
// update the user with the new password.
/** @noinspection PhpParamsInspection */
$this->user->updatePassword(Auth::user(), Input::get('new1'));
/** @var \FireflyIII\Database\User\User $repository */
$repository = \App::make('FireflyIII\Database\User\User');
$repository->updatePassword(Auth::user(), Input::get('new1'));
Session::flash('success', 'Password changed!');
return Redirect::route('profile');
}
}
}

View File

@@ -1,213 +0,0 @@
<?php
use Firefly\Exception\FireflyException;
use Firefly\Storage\RecurringTransaction\RecurringTransactionRepositoryInterface as RTR;
use Firefly\Helper\Controllers\RecurringInterface as RI;
/**
* Class RecurringController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class RecurringController extends BaseController
{
protected $_repository;
protected $_helper;
/**
* @param RTR $repository
* @param RI $helper
*/
public function __construct(RTR $repository, RI $helper)
{
$this->_repository = $repository;
$this->_helper = $helper;
View::share('title', 'Recurring transactions');
View::share('mainTitleIcon', 'fa-rotate-right');
}
/**
* @return $this
*/
public function create()
{
View::share('subTitle', 'Create new');
$periods = \Config::get('firefly.periods_to_text');
return View::make('recurring.create')->with('periods', $periods);
}
/**
* @param RecurringTransaction $recurringTransaction
*
* @return $this
*/
public function delete(RecurringTransaction $recurringTransaction)
{
View::share('subTitle', 'Delete "' . $recurringTransaction->name . '"');
return View::make('recurring.delete')->with('recurringTransaction', $recurringTransaction);
}
/**
* @param RecurringTransaction $recurringTransaction
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(RecurringTransaction $recurringTransaction)
{
//Event::fire('recurring.destroy', [$recurringTransaction]);
$result = $this->_repository->destroy($recurringTransaction);
if ($result === true) {
Session::flash('success', 'The recurring transaction was deleted.');
} else {
Session::flash('error', 'Could not delete the recurring transaction. Check the logs to be sure.');
}
return Redirect::route('recurring.index');
}
/**
* @param RecurringTransaction $recurringTransaction
*
* @return $this
*/
public function edit(RecurringTransaction $recurringTransaction)
{
$periods = \Config::get('firefly.periods_to_text');
View::share('subTitle', 'Edit "' . $recurringTransaction->name . '"');
return View::make('recurring.edit')->with('periods', $periods)->with(
'recurringTransaction', $recurringTransaction
);
}
/**
* @return $this
*/
public function index()
{
return View::make('recurring.index');
}
/**
*
*/
public function show(RecurringTransaction $recurringTransaction)
{
View::share('subTitle', $recurringTransaction->name);
return View::make('recurring.show')->with('recurring', $recurringTransaction);
}
public function store()
{
$data = Input::except(['_token', 'post_submit_action']);
switch (Input::get('post_submit_action')) {
default:
throw new FireflyException('Method ' . Input::get('post_submit_action') . ' not implemented yet.');
break;
case 'store':
case 'create_another':
/*
* Try to store:
*/
$messageBag = $this->_repository->store($data);
/*
* Failure!
*/
if ($messageBag->count() > 0) {
Session::flash('error', 'Could not save recurring transaction: ' . $messageBag->first());
return Redirect::route('recurring.create')->withInput()->withErrors($messageBag);
}
/*
* Success!
*/
Session::flash('success', 'Recurring transaction "' . e(Input::get('name')) . '" saved!');
/*
* Redirect to original location or back to the form.
*/
if (Input::get('post_submit_action') == 'create_another') {
return Redirect::route('recurring.create')->withInput();
} else {
return Redirect::route('recurring.index');
}
break;
case 'validate_only':
$messageBags = $this->_helper->validate($data);
Session::flash('warnings', $messageBags['warnings']);
Session::flash('successes', $messageBags['successes']);
Session::flash('errors', $messageBags['errors']);
return Redirect::route('recurring.create')->withInput();
break;
}
}
public function update(RecurringTransaction $recurringTransaction)
{
$data = Input::except(['_token', 'post_submit_action']);
switch (Input::get('post_submit_action')) {
case 'update':
case 'return_to_edit':
$messageBag = $this->_repository->update($recurringTransaction, $data);
if ($messageBag->count() == 0) {
// has been saved, return to index:
Session::flash('success', 'Recurring transaction updated!');
if (Input::get('post_submit_action') == 'return_to_edit') {
return Redirect::route('recurring.edit', $recurringTransaction->id)->withInput();
} else {
return Redirect::route('recurring.index');
}
} else {
Session::flash('error', 'Could not update recurring transaction: ' . $messageBag->first());
return Redirect::route('transactions.edit', $recurringTransaction->id)->withInput()
->withErrors($messageBag);
}
break;
case 'validate_only':
$data = Input::all();
$data['id'] = $recurringTransaction->id;
$messageBags = $this->_helper->validate($data);
Session::flash('warnings', $messageBags['warnings']);
Session::flash('successes', $messageBags['successes']);
Session::flash('errors', $messageBags['errors']);
return Redirect::route('recurring.edit', $recurringTransaction->id)->withInput();
break;
// update
default:
throw new FireflyException('Method ' . Input::get('post_submit_action') . ' not implemented yet.');
break;
}
// /** @var \RecurringTransaction $recurringTransaction */
// $recurringTransaction = $this->_repository->update($recurringTransaction, Input::all());
// if ($recurringTransaction->errors()->count() == 0) {
// Session::flash('success', 'The recurring transaction has been updated.');
// //Event::fire('recurring.update', [$recurringTransaction]);
//
// return Redirect::route('recurring.index');
// } else {
// Session::flash(
// 'error', 'Could not update the recurring transaction: ' . $recurringTransaction->errors()->first()
// );
//
// return Redirect::route('recurring.edit', $recurringTransaction->id)->withInput()->withErrors(
// $recurringTransaction->errors()
// );
// }
}
}

View File

@@ -0,0 +1,139 @@
<?php
use FireflyIII\Helper\Related\RelatedInterface;
use Illuminate\Support\Collection;
/**
* Class RelatedController
*/
class RelatedController extends BaseController
{
protected $_repository;
public function __construct(RelatedInterface $repository)
{
$this->_repository = $repository;
}
/**
* @param TransactionJournal $journal
*
* @return \Illuminate\Http\JsonResponse
*/
public function alreadyRelated(TransactionJournal $journal)
{
$ids = [];
/** @var TransactionGroup $group */
foreach ($journal->transactiongroups()->get() as $group) {
/** @var TransactionJournal $loopJournal */
foreach ($group->transactionjournals()->get() as $loopJournal) {
if ($loopJournal->id != $journal->id) {
$ids[] = $loopJournal->id;
}
}
}
$unique = array_unique($ids);
if (count($unique) > 0) {
$set = $this->_repository->getJournalsByIds($unique);
$set->each(
function (TransactionJournal $journal) {
$journal->amount = Amount::format($journal->getAmount());
}
);
return Response::json($set->toArray());
} else {
return Response::json((new Collection)->toArray());
}
}
/**
* @param TransactionJournal $parentJournal
* @param TransactionJournal $childJournal
*
* @return \Illuminate\Http\JsonResponse
*/
public function relate(TransactionJournal $parentJournal, TransactionJournal $childJournal)
{
$group = new TransactionGroup;
$group->relation = 'balance';
$group->user_id = $this->_repository->getUser()->id;
$group->save();
$group->transactionjournals()->save($parentJournal);
$group->transactionjournals()->save($childJournal);
return Response::json(true);
}
/**
* @param TransactionJournal $journal
*
* @return \Illuminate\View\View
*/
public function related(TransactionJournal $journal)
{
$groups = $journal->transactiongroups()->get();
$members = new Collection;
/** @var TransactionGroup $group */
foreach ($groups as $group) {
/** @var TransactionJournal $loopJournal */
foreach ($group->transactionjournals()->get() as $loopJournal) {
if ($loopJournal->id != $journal->id) {
$members->push($loopJournal);
}
}
}
return View::make('related.relate', compact('journal', 'members'));
}
/**
* @param TransactionJournal $parentJournal
* @param TransactionJournal $childJournal
*
* @return \Illuminate\Http\JsonResponse
* @throws Exception
*/
public function removeRelation(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 Response::json(true);
}
/**
* @param TransactionJournal $journal
*
* @return \Illuminate\Http\JsonResponse
*/
public function search(TransactionJournal $journal)
{
$search = e(trim(Input::get('searchValue')));
$result = $this->_repository->search($search, $journal);
$result->each(
function (TransactionJournal $j) {
$j->amount = Amount::format($j->getAmount());
}
);
return Response::json($result->toArray());
}
}

View File

@@ -1,97 +1,93 @@
<?php
use Carbon\Carbon;
use Firefly\Storage\Reminder\ReminderRepositoryInterface as RRI;
use FireflyIII\Exception\FireflyException;
/**
* Class ReminderController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
*/
class ReminderController extends BaseController
{
protected $_repository;
/**
* @param RRI $repository
*
*/
public function __construct(RRI $repository)
public function __construct()
{
$this->_repository = $repository;
View::share('title', 'Reminders');
View::share('mainTitleIcon', 'fa-lightbulb-o');
}
/**
* @param Reminder $reminder
*
* @return \Illuminate\Http\JsonResponse
* @return \Illuminate\Http\RedirectResponse
* @throws FireflyException
*/
public function dismiss(\Reminder $reminder)
public function act(Reminder $reminder)
{
$reminder = $this->_repository->deactivate($reminder);
return Response::json($reminder->id);
}
$class = get_class($reminder->remindersable);
/**
* Returns the reminders currently active for the modal dialog.
*/
public function modalDialog()
{
$today = new Carbon;
$reminders = $this->_repository->getPiggybankReminders();
/** @var \Reminder $reminder */
foreach ($reminders as $index => $reminder) {
if (\Session::has('dismissal-' . $reminder->id)) {
$time = \Session::get('dismissal-' . $reminder->id);
if ($time >= $today) {
unset($reminders[$index]);
}
}
}
return View::make('reminders.popup')->with('reminders', $reminders);
}
/**
* @param Reminder $reminder
*
* @return \Illuminate\Http\JsonResponse
*/
public function postpone(\Reminder $reminder)
{
$now = new Carbon;
$now->addDay();
Session::put('dismissal-' . $reminder->id, $now);
return Response::json($reminder->id);
}
/**
* @param Reminder $reminder
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function redirect(\Reminder $reminder)
{
if ($reminder instanceof PiggybankReminder) {
// fields to prefill:
$parameters = [
'account_to_id' => $reminder->piggybank->account->id,
'amount' => round($reminder->amountToSave(), 2),
'description' => 'Money for ' . $reminder->piggybank->name,
'piggybank_id' => $reminder->piggybank->id,
'reminder_id' => $reminder->id
if ($class == 'PiggyBank') {
$amount = Reminders::amountForReminder($reminder);
$preFilled = [
'amount' => round($amount, 2),
'description' => 'Money for ' . $reminder->remindersable->name,
'piggy_bank_id' => $reminder->remindersable_id,
'account_to_id' => $reminder->remindersable->account_id
];
Session::flash('preFilled', $preFilled);
return Redirect::to(
route('transactions.create', ['what' => 'transfer']) . '?' . http_build_query($parameters)
);
return Redirect::route('transactions.create', 'transfer');
}
return View::make('error')->with('message', 'No such reminder.');
return View::make('error')->with('message', 'This reminder has an invalid class connected to it.');
}
}
/**
* @param Reminder $reminder
*
* @return \Illuminate\Http\RedirectResponse
*/
public function dismiss(Reminder $reminder)
{
$reminder->active = 0;
$reminder->save();
Session::flash('success', 'Reminder dismissed');
return Redirect::route('index');
}
/**
* @param Reminder $reminder
*
* @return \Illuminate\Http\RedirectResponse
*/
public function notNow(Reminder $reminder)
{
$reminder->active = 0;
$reminder->notnow = 1;
$reminder->save();
Session::flash('success', 'Reminder dismissed');
return Redirect::route('index');
}
/**
* @param Reminder $reminder
*
* @return \Illuminate\View\View
*/
public function show(Reminder $reminder)
{
$amount = null;
if (get_class($reminder->remindersable) == 'PiggyBank') {
$amount = Reminders::amountForReminder($reminder);
}
return View::make('reminders.show', compact('reminder', 'amount'));
}
}

View File

@@ -0,0 +1,227 @@
<?php
use Carbon\Carbon;
use FireflyIII\Database\PiggyBank\RepeatedExpense as Repository;
use FireflyIII\Exception\FireflyException;
/**
* @SuppressWarnings("CamelCase") // I'm fine with this.
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
* @SuppressWarnings("CouplingBetweenObjects") // There's only so much I can remove.
*
* Class RepeatedExpenseController
*/
class RepeatedExpenseController extends BaseController
{
/** @var Repository */
protected $_repository;
/**
* @param Repository $repository
*/
public function __construct(Repository $repository)
{
View::share('title', 'Repeated expenses');
View::share('mainTitleIcon', 'fa-rotate-left');
$this->_repository = $repository;
}
/**
* @return $this
*/
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->getAssetAccounts());
return View::make('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::make('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.');
$this->_repository->destroy($repeatedExpense);
return Redirect::route('repeated.index');
}
/**
* @param PiggyBank $repeatedExpense
*
* @return $this
*/
public function edit(PiggyBank $repeatedExpense)
{
/** @var \FireflyIII\Database\Account\Account $acct */
$acct = App::make('FireflyIII\Database\Account\Account');
$periods = Config::get('firefly.piggy_bank_periods');
$accounts = FFForm::makeSelectList($acct->getAssetAccounts());
$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,
'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::make('repeatedExpense.edit', compact('subTitle', 'subTitleIcon', 'repeatedExpense', 'accounts', 'periods', 'preFilled'));
}
/**
* @return \Illuminate\View\View
*/
public function index()
{
$subTitle = 'Overview';
$expenses = $this->_repository->get();
$expenses->each(
function (PiggyBank $piggyBank) {
$piggyBank->currentRelevantRep();
}
);
return View::make('repeatedExpense.index', compact('expenses', 'subTitle'));
}
/**
* @param PiggyBank $repeatedExpense
*
* @return \Illuminate\View\View
*/
public function show(PiggyBank $repeatedExpense)
{
$subTitle = $repeatedExpense->name;
$today = Carbon::now();
$repetitions = $repeatedExpense->piggyBankRepetitions()->get();
$repetitions->each(
function (PiggyBankRepetition $repetition) {
$repetition->bars = $this->_repository->calculateParts($repetition);
}
);
return View::make('repeatedExpense.show', compact('repetitions', 'repeatedExpense', 'today', 'subTitle'));
}
/**
*
*/
public function store()
{
$data = Input::all();
$data['repeats'] = 1;
$data['user_id'] = Auth::user()->id;
$targetDate = new Carbon($data['targetdate']);
$startDate = \DateKit::subtractPeriod($targetDate, $data['rep_length']);
$data['startdate'] = $startDate->format('Y-m-d');
$data['targetdate'] = $targetDate->format('Y-m-d');
$data['reminder_skip'] = 0;
$data['remind_me'] = isset($data['remind_me']) ? 1 : 0;
$data['order'] = 0;
// always validate:
$messages = $this->_repository->validate($data);
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 repeated expense: ' . $messages['errors']->first());
}
// return to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('repeated.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('repeated.index');
}
return Redirect::route('repeated.create')->withInput();
}
/**
* @param PiggyBank $repeatedExpense
*
* @return $this
* @throws FireflyException
*/
public function update(PiggyBank $repeatedExpense)
{
$data = Input::except('_token');
$data['rep_every'] = 0;
$data['reminder_skip'] = 0;
$data['order'] = 0;
$data['repeats'] = 1;
$data['remind_me'] = isset($data['remind_me']) ? 1 : 0;
$data['user_id'] = Auth::user()->id;
// always validate:
$messages = $this->_repository->validate($data);
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 repeated expense: ' . $messages['errors']->first());
}
// return to update screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput();
}
// update
$this->_repository->update($repeatedExpense, $data);
Session::flash('success', 'Repeated expense "' . e($data['name']) . '" updated.');
// go back to list
if ($data['post_submit_action'] == 'update') {
return Redirect::route('repeated.index');
}
// go back to update screen.
return Redirect::route('repeated.edit', $repeatedExpense->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
}

View File

@@ -1,18 +1,133 @@
<?php
use Carbon\Carbon;
use FireflyIII\Database\TransactionJournal\TransactionJournal as TransactionJournalRepository;
use FireflyIII\Report\ReportInterface as Report;
/**
*
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class ReportController
*/
class ReportController extends BaseController
{
/** @var \FireflyIII\Database\Budget\Budget */
protected $_budgets;
/** @var TransactionJournalRepository */
protected $_journals;
/** @var Report */
protected $_repository;
/**
* @param TransactionJournalRepository $journals
* @param Report $repository
*/
public function __construct(TransactionJournalRepository $journals, Report $repository)
{
$this->_journals = $journals;
$this->_repository = $repository;
/** @var \FireflyIII\Database\Budget\Budget _budgets */
$this->_budgets = App::make('FireflyIII\Database\Budget\Budget');
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')
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return View::make('error')->with('message', 'Invalid date');
}
$date = new Carbon($year . '-' . $month . '-01');
$dayEarly = clone $date;
$dayEarly = $dayEarly->subDay();
$accounts = $this->_repository->getAccountListBudgetOverview($date);
$budgets = $this->_repository->getBudgetsForMonth($date);
return View::make('reports.budget', compact('date', 'accounts', 'budgets', 'dayEarly'));
}
/**
*
*/
public function index()
{
return View::make('reports.index')->with('title','Reports')->with('mainTitleIcon','fa-line-chart');
$start = $this->_journals->firstDate();
$months = $this->_repository->listOfMonths(clone $start);
$years = $this->_repository->listOfYears(clone $start);
$title = 'Reports';
$mainTitleIcon = 'fa-line-chart';
return View::make('reports.index', compact('years', 'months', 'title', 'mainTitleIcon'));
}
}
/**
* @param string $year
* @param string $month
*
* @return \Illuminate\View\View
*/
public function month($year = '2014', $month = '1')
{
try {
new Carbon($year . '-' . $month . '-01');
} catch (Exception $e) {
return View::make('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.
$income = $this->_repository->getIncomeForMonth($date);
$expenses = $this->_repository->getExpenseGroupedForMonth($date, 10);
$budgets = $this->_repository->getBudgetsForMonth($date);
$categories = $this->_repository->getCategoriesForMonth($date, 10);
$accounts = $this->_repository->getAccountsForMonth($date);
return View::make(
'reports.month',
compact('date', 'accounts', 'categories', 'budgets', 'expenses', 'subTitle', 'displaySum', 'subTitleIcon', 'income')
);
}
/**
* @param $year
*
* @return $this
*/
public function year($year)
{
try {
new Carbon('01-01-' . $year);
} catch (Exception $e) {
return View::make('error')->with('message', 'Invalid date.');
}
$date = new Carbon('01-01-' . $year);
$end = clone $date;
$end->endOfYear();
$title = 'Reports';
$subTitle = $year;
$subTitleIcon = 'fa-bar-chart';
$mainTitleIcon = 'fa-line-chart';
$balances = $this->_repository->yearBalanceReport($date);
$groupedIncomes = $this->_repository->revenueGroupedByAccount($date, $end, 15);
$groupedExpenses = $this->_repository->expensesGroupedByAccount($date, $end, 15);
return View::make(
'reports.year', compact('date', 'groupedIncomes', 'groupedExpenses', 'year', 'balances', 'title', 'subTitle', 'subTitleIcon', 'mainTitleIcon')
);
}
}

View File

@@ -1,50 +1,38 @@
<?php
use Firefly\Helper\Controllers\SearchInterface as SI;
/**
* Class SearchController
*/
class SearchController extends BaseController
{
protected $_helper;
public function __construct(SI $helper)
{
$this->_helper = $helper;
}
/**
* Results always come in the form of an array [results, count, fullCount]
*/
public function index()
{
/** @var \FireflyIII\Search\Search $searcher */
$searcher = App::make('FireflyIII\Search\Search');
$subTitle = null;
$rawQuery = null;
$result = [];
if (!is_null(Input::get('q'))) {
$result = [];
if (!is_null(Input::get('q')) && strlen(Input::get('q')) > 0) {
$rawQuery = trim(Input::get('q'));
$words = explode(' ', $rawQuery);
$subTitle = 'Results for "' . e($rawQuery) . '"';
$transactions = $this->_helper->searchTransactions($words);
$accounts = $this->_helper->searchAccounts($words);
$categories = $this->_helper->searchCategories($words);
$budgets = $this->_helper->searchBudgets($words);
$tags = $this->_helper->searchTags($words);
$result = [
'transactions' => $transactions,
'accounts' => $accounts,
'categories' => $categories,
'budgets' => $budgets,
'tags' => $tags
];
$transactions = $searcher->searchTransactions($words);
$accounts = $searcher->searchAccounts($words);
$categories = $searcher->searchCategories($words);
$budgets = $searcher->searchBudgets($words);
$tags = $searcher->searchTags($words);
$result = ['transactions' => $transactions, 'accounts' => $accounts, 'categories' => $categories, 'budgets' => $budgets, 'tags' => $tags];
}
return View::make('search.index')->with('title', 'Search')->with('subTitle', $subTitle)->with(
'mainTitleIcon', 'fa-search'
)->with('query', $rawQuery)->with('result',$result);
)->with('query', $rawQuery)->with('result', $result);
}
}
}

View File

@@ -1,37 +1,46 @@
<?php
use Firefly\Exception\FireflyException;
use Firefly\Helper\Controllers\TransactionInterface as TI;
use Firefly\Storage\TransactionJournal\TransactionJournalRepositoryInterface as TJRI;
use Illuminate\Support\MessageBag;
use FireflyIII\Database\TransactionJournal\TransactionJournal as Repository;
use FireflyIII\Exception\FireflyException;
use FireflyIII\Helper\TransactionJournal\HelperInterface as Helper;
use Illuminate\Support\Collection;
/**
* Class TransactionController
*
* @SuppressWarnings(PHPMD.CamelCasePropertyName)
* @SuppressWarnings("CamelCase") // I'm fine with this.
* @SuppressWarnings("CyclomaticComplexity") // It's all 5. So ok.
* @SuppressWarnings("CouplingBetweenObjects") // There's only so much I can remove.
* @SuppressWarnings("TooManyMethods") // I'm also fine with this.
* @SuppressWarnings("ExcessiveClassComplexity")
*
* Class TransactionController
*
*/
class TransactionController extends BaseController
{
/** @var Helper */
protected $_helper;
/** @var Repository */
protected $_repository;
/**
* Construct a new transaction controller with two of the most often used helpers.
*
* @param TJRI $repository
* @param TI $helper
* @param Repository $repository
* @param Helper $helper
*/
public function __construct(TJRI $repository, TI $helper)
public function __construct(Repository $repository, Helper $helper)
{
$this->_repository = $repository;
$this->_helper = $helper;
$this->_helper = $helper;
View::share('title', 'Transactions');
View::share('mainTitleIcon', 'fa-repeat');
}
/**
* Shows the view helping the user to create a new transaction journal.
*
@@ -41,68 +50,48 @@ class TransactionController extends BaseController
*/
public function create($what = 'deposit')
{
/*
* The repositories we need:
*/
/** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */
$toolkit = App::make('Firefly\Helper\Toolkit\Toolkit');
$accounts = FFForm::makeSelectList($this->_helper->getAssetAccounts());
$budgets = FFForm::makeSelectList($this->_helper->getBudgets());
$budgets[0] = '(no budget)';
$piggyBanks = $this->_helper->getPiggyBanks();
$repeatedExpenses = $this->_helper->getRepeatedExpenses();
$list = $piggyBanks->merge($repeatedExpenses);
$piggies = FFForm::makeSelectList($list);
$piggies[0] = '(no piggy bank)';
$preFilled = Session::has('preFilled') ? Session::get('preFilled') : [];
$respondTo = ['account_id', 'account_from_id'];
$subTitle = 'Add a new ' . e($what);
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accountRepository */
$accountRepository = App::make('Firefly\Storage\Account\AccountRepositoryInterface');
/** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budgetRepository */
$budgetRepository = App::make('Firefly\Storage\Budget\BudgetRepositoryInterface');
/** @var \Firefly\Storage\Piggybank\PiggybankRepositoryInterface $piggyRepository */
$piggyRepository = App::make('Firefly\Storage\Piggybank\PiggybankRepositoryInterface');
// get asset accounts with names and id's.
$assetAccounts = $toolkit->makeSelectList($accountRepository->getActiveDefault());
// get budgets as a select list.
$budgets = $toolkit->makeSelectList($budgetRepository->get());
$budgets[0] = '(no budget)';
// get the piggy banks.
$piggies = $toolkit->makeSelectList($piggyRepository->get());
$piggies[0] = '(no piggy bank)';
/*
* respond to a possible given values in the URL.
*/
$prefilled = Session::has('prefilled') ? Session::get('prefilled') : [];
$respondTo = ['account_id', 'account_from_id'];
foreach ($respondTo as $r) {
if (!is_null(Input::get($r))) {
$prefilled[$r] = Input::get($r);
$preFilled[$r] = Input::get($r);
}
}
Session::put('prefilled', $prefilled);
Session::put('preFilled', $preFilled);
return View::make('transactions.create')->with('accounts', $assetAccounts)->with('budgets', $budgets)->with(
'what', $what
)->with('piggies', $piggies)->with('subTitle', 'Add a new ' . $what);
asort($piggies);
return View::make('transactions.create', compact('accounts', 'budgets', 'what', 'piggies', 'subTitle'));
}
/**
* Shows the form that allows a user to delete a transaction journal.
*
* @param TransactionJournal $transactionJournal
* @param TransactionJournal $journal
*
* @return $this
*/
public function delete(TransactionJournal $transactionJournal)
public function delete(TransactionJournal $journal)
{
$type = strtolower($transactionJournal->transactionType->type);
$type = strtolower($journal->transactionType->type);
$subTitle = 'Delete ' . e($type) . ' "' . e($journal->description) . '"';
return View::make('transactions.delete')->with('journal', $transactionJournal)->with(
'subTitle', 'Delete ' . $type . ' "' . $transactionJournal->description . '"'
);
return View::make('transactions.delete', compact('journal', 'subTitle'));
}
/**
* @param TransactionJournal $transactionJournal
*
@@ -110,20 +99,23 @@ class TransactionController extends BaseController
*/
public function destroy(TransactionJournal $transactionJournal)
{
$type = $transactionJournal->transactionType->type;
$transactionJournal->delete();
$type = $transactionJournal->transactionType->type;
$return = 'withdrawal';
Session::flash('success', 'Transaction "' . e($transactionJournal->description) . '" destroyed.');
$this->_repository->destroy($transactionJournal);
switch ($type) {
case 'Withdrawal':
return Redirect::route('transactions.expenses');
break;
case 'Deposit':
return Redirect::route('transactions.revenue');
$return = 'deposit';
break;
case 'Transfer':
return Redirect::route('transactions.transfers');
$return = 'transfers';
break;
}
return Redirect::route('transactions.index', $return);
}
/**
@@ -135,118 +127,77 @@ class TransactionController extends BaseController
*/
public function edit(TransactionJournal $journal)
{
/*
* All the repositories we need:
*/
/** @var \Firefly\Helper\Toolkit\Toolkit $toolkit */
$toolkit = App::make('Firefly\Helper\Toolkit\Toolkit');
/** @var \Firefly\Storage\Account\AccountRepositoryInterface $accountRepository */
$accountRepository = App::make('Firefly\Storage\Account\AccountRepositoryInterface');
/** @var \Firefly\Storage\Budget\BudgetRepositoryInterface $budgetRepository */
$budgetRepository = App::make('Firefly\Storage\Budget\BudgetRepositoryInterface');
/** @var \Firefly\Storage\Piggybank\PiggybankRepositoryInterface $piggyRepository */
$piggyRepository = App::make('Firefly\Storage\Piggybank\PiggybankRepositoryInterface');
// type is useful for display:
$what = strtolower($journal->transactiontype->type);
// get asset accounts with names and id's.
$accounts = $toolkit->makeSelectList($accountRepository->getActiveDefault());
// get budgets as a select list.
$budgets = $toolkit->makeSelectList($budgetRepository->get());
$budgets[0] = '(no budget)';
/*
* Get all piggy banks plus (if any) the relevant piggy bank. Since just one
* of the transactions in the journal has this field, it should all fill in nicely.
*/
// get the piggy banks.
$piggies = $toolkit->makeSelectList($piggyRepository->get());
$piggies[0] = '(no piggy bank)';
$piggyBankId = 0;
foreach ($journal->transactions as $t) {
if (!is_null($t->piggybank_id)) {
$piggyBankId = $t->piggybank_id;
}
}
/*
* Data to properly display the edit form.
*/
$prefilled = [
'date' => $journal->date->format('Y-m-d'),
'category' => '',
'budget_id' => 0,
'piggybank_id' => $piggyBankId
$what = strtolower($journal->transactiontype->type);
$subTitle = 'Edit ' . e($what) . ' "' . e($journal->description) . '"';
$budgets = FFForm::makeSelectList($this->_helper->getBudgets(), true);
$accounts = FFForm::makeSelectList($this->_helper->getAssetAccounts());
$piggies = FFForm::makeSelectList($this->_helper->getPiggyBanks(), true);
$transactions = $journal->transactions()->orderBy('amount', 'DESC')->get();
$preFilled = [
'date' => $journal->date->format('Y-m-d'),
'category' => '',
'budget_id' => 0,
'piggy_bank_id' => 0
];
/*
* Fill in the category.
*/
$category = $journal->categories()->first();
if (!is_null($category)) {
$prefilled['category'] = $category->name;
$preFilled['category'] = $category->name;
}
/*
* Switch on the type of transaction edited by the user and fill in other
* relevant fields:
*/
$budget = $journal->budgets()->first();
if (!is_null($budget)) {
$preFilled['budget_id'] = $budget->id;
}
if ($journal->piggyBankEvents()->count() > 0) {
$preFilled['piggy_bank_id'] = $journal->piggyBankEvents()->first()->piggy_bank_id;
}
$preFilled['amount'] = $journal->getAmount();
$preFilled['account_id'] = $this->_helper->getAssetAccount($what, $transactions);
$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':
$prefilled['account_id'] = $journal->transactions[0]->account->id;
$prefilled['expense_account'] = $journal->transactions[1]->account->name;
$prefilled['amount'] = floatval($journal->transactions[1]->amount);
$budget = $journal->budgets()->first();
if (!is_null($budget)) {
$prefilled['budget_id'] = $budget->id;
}
$subTitleIcon = 'fa-long-arrow-left';
$subTitle = 'Expenses';
$journals = $this->_repository->getWithdrawalsPaginated(50);
break;
case 'revenue':
case 'deposit':
$prefilled['account_id'] = $journal->transactions[1]->account->id;
$prefilled['revenue_account'] = $journal->transactions[0]->account->name;
$prefilled['amount'] = floatval($journal->transactions[1]->amount);
$subTitleIcon = 'fa-long-arrow-right';
$subTitle = 'Revenue, income and deposits';
$journals = $this->_repository->getDepositsPaginated(50);
break;
case 'transfer':
$prefilled['account_from_id'] = $journal->transactions[1]->account->id;
$prefilled['account_to_id'] = $journal->transactions[0]->account->id;
$prefilled['amount'] = floatval($journal->transactions[1]->amount);
case 'transfers':
$subTitleIcon = 'fa-arrows-h';
$subTitle = 'Transfers';
$journals = $this->_repository->getTransfersPaginated(50);
break;
}
/*
* Show the view.
*/
return View::make('transactions.edit')->with('journal', $journal)->with('accounts', $accounts)->with(
'what', $what
)->with('budgets', $budgets)->with('data', $prefilled)->with('piggies', $piggies)->with(
'subTitle', 'Edit ' . $what . ' "' . $journal->description . '"'
);
return View::make('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals'));
}
/**
* @return $this
*/
public function expenses()
{
return View::make('transactions.list')->with('subTitle', 'Expenses')->with(
'subTitleIcon', 'fa-long-arrow-left'
)->with('what', 'expenses');
}
/**
* @return $this
*/
public function revenue()
{
return View::make('transactions.list')->with('subTitle', 'Revenue')->with(
'subTitleIcon', 'fa-long-arrow-right'
)->with('what', 'revenue');
}
/**
* @param TransactionJournal $journal
@@ -255,8 +206,31 @@ class TransactionController extends BaseController
*/
public function show(TransactionJournal $journal)
{
return View::make('transactions.show')->with('journal', $journal)->with(
'subTitle', $journal->transactionType->type . ' "' . $journal->description . '"'
$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.created_at', '<=', $journal->created_at->format('Y-m-d H:i:s')
)->where('transaction_journals.id', '!=', $journal->id)->sum('transactions.amount')
);
$t->after = $t->before + $t->amount;
}
);
$members = new Collection;
/** @var TransactionGroup $group */
foreach ($journal->transactiongroups()->get() as $group) {
/** @var TransactionJournal $loopJournal */
foreach ($group->transactionjournals()->get() as $loopJournal) {
if ($loopJournal->id != $journal->id) {
$members->push($loopJournal);
}
}
}
return View::make('transactions.show', compact('journal', 'members'))->with(
'subTitle', e($journal->transactionType->type) . ' "' . e($journal->description) . '"'
);
}
@@ -268,112 +242,90 @@ class TransactionController extends BaseController
*/
public function store($what)
{
/*
* Collect data to process:
*/
$data = Input::except(['_token']);
$data['what'] = $what;
$data = Input::except('_token');
$transactionType = $this->_repository->getJournalType($what);
$transactionCurrency = $this->_repository->getJournalCurrency('EUR');
$data['transaction_type_id'] = $transactionType->id;
$data['transaction_currency_id'] = $transactionCurrency->id;
$data['completed'] = 0;
$data['what'] = $what;
$data['currency'] = 'EUR';
switch (Input::get('post_submit_action')) {
case 'store':
case 'create_another':
/*
* Try to store:
*/
$messageBag = $this->_helper->store($data);
// always validate:
$messages = $this->_repository->validate($data);
/*
* Failure!
*/
if ($messageBag->count() > 0) {
Session::flash('error', 'Could not save transaction: ' . $messageBag->first());
return Redirect::route('transactions.create', [$what])->withInput()->withErrors($messageBag);
}
/*
* Success!
*/
Session::flash('success', 'Transaction "' . e(Input::get('description')) . '" saved!');
/*
* Redirect to original location or back to the form.
*/
if (Input::get('post_submit_action') == 'create_another') {
return Redirect::route('transactions.create', $what)->withInput();
} else {
return Redirect::route('transactions.index.' . $what);
}
break;
case 'validate_only':
$messageBags = $this->_helper->validate($data);
Session::flash('warnings', $messageBags['warnings']);
Session::flash('successes', $messageBags['successes']);
Session::flash('errors', $messageBags['errors']);
return Redirect::route('transactions.create', [$what])->withInput();
break;
default:
throw new FireflyException('Method ' . Input::get('post_submit_action') . ' not implemented yet.');
break;
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 transaction: ' . $messages['errors']->first());
}
// return to create screen:
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('transactions.create', $data['what'])->withInput();
}
// store
$journal = $this->_repository->store($data);
Event::fire('transactionJournal.store', [$journal, Input::get('piggy_bank_id')]); // new and used.
/*
* Also trigger on both transactions.
*/
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
Event::fire('transaction.store', [$transaction]);
}
Session::flash('success', 'Transaction "' . e($data['description']) . '" stored.');
if ($data['post_submit_action'] == 'store') {
return Redirect::route('transactions.index', $data['what']);
}
return Redirect::route('transactions.create', $data['what'])->withInput();
}
public function transfers()
{
return View::make('transactions.list')->with('subTitle', 'Transfers')->with(
'subTitleIcon', 'fa-arrows-h'
)->with('what', 'transfers');
}
/**
* @param TransactionJournal $journal
*
* @return $this
* @throws FireflyException
*/
public function update(TransactionJournal $journal)
{
switch (Input::get('post_submit_action')) {
case 'update':
case 'return_to_edit':
$what = strtolower($journal->transactionType->type);
$messageBag = $this->_helper->update($journal, Input::all());
if ($messageBag->count() == 0) {
// has been saved, return to index:
Session::flash('success', 'Transaction updated!');
Event::fire('journals.update', [$journal]);
$data = Input::except('_token');
$data['currency'] = 'EUR';
$data['what'] = strtolower($journal->transactionType->type);
$data['transaction_type_id'] = $journal->transaction_type_id;
$data['transaction_currency_id'] = $journal->transaction_currency_id;
$data['completed'] = 1;
$messages = $this->_repository->validate($data);
if (Input::get('post_submit_action') == 'return_to_edit') {
return Redirect::route('transactions.edit', $journal->id)->withInput();
} else {
return Redirect::route('transactions.index.' . $what);
}
} else {
Session::flash('error', 'Could not update transaction: ' . $journal->errors()->first());
return Redirect::route('transactions.edit', $journal->id)->withInput()->withErrors(
$journal->errors()
);
}
break;
case 'validate_only':
$data = Input::all();
$data['what'] = strtolower($journal->transactionType->type);
$messageBags = $this->_helper->validate($data);
Session::flash('warnings', $messageBags['warnings']);
Session::flash('successes', $messageBags['successes']);
Session::flash('errors', $messageBags['errors']);
return Redirect::route('transactions.edit', $journal->id)->withInput();
break;
default:
throw new FireflyException('Method ' . Input::get('post_submit_action') . ' not implemented yet.');
break;
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 transaction: ' . $messages['errors']->first());
}
if ($data['post_submit_action'] == 'validate_only' || $messages['errors']->count() > 0) {
return Redirect::route('transactions.edit', $journal->id)->withInput();
}
$this->_repository->update($journal, $data);
Session::flash('success', 'Transaction "' . e($data['description']) . '" updated.');
Event::fire('transactionJournal.update', [$journal]); // new and used.
/** @var Transaction $transaction */
foreach ($journal->transactions()->get() as $transaction) {
Event::fire('transaction.update', [$transaction]);
}
if ($data['post_submit_action'] == 'update') {
return Redirect::route('transactions.index', $data['what']);
}
// go back to update screen.
return Redirect::route('transactions.edit', $journal->id)->withInput(['post_submit_action' => 'return_to_edit']);
}
}
}

View File

@@ -1,8 +1,5 @@
<?php
use Firefly\Helper\Email\EmailHelperInterface as EHI;
use Firefly\Storage\User\UserRepositoryInterface as URI;
/**
* Class UserController
*/
@@ -11,15 +8,9 @@ class UserController extends BaseController
/**
* Constructor.
*
* @param URI $user
* @param EHI $email
*/
public function __construct(URI $user, EHI $email)
public function __construct()
{
$this->user = $user;
$this->email = $email;
}
/**
@@ -32,6 +23,18 @@ class UserController extends BaseController
return View::make('user.login');
}
/**
* Logout user.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function logout()
{
Auth::logout();
Session::flush();
return Redirect::route('login');
}
/**
* Login.
@@ -41,10 +44,7 @@ class UserController extends BaseController
public function postLogin()
{
$rememberMe = Input::get('remember_me') == '1';
$data = [
'email' => Input::get('email'),
'password' => Input::get('password')
];
$data = ['email' => Input::get('email'), 'password' => Input::get('password')];
$result = Auth::attempt($data, $rememberMe);
if ($result) {
return Redirect::route('index');
@@ -55,20 +55,6 @@ class UserController extends BaseController
return View::make('user.login');
}
/**
* If allowed, show the register form.
*
* @return $this|\Illuminate\View\View
*/
public function register()
{
if (Config::get('auth.allow_register') !== true) {
return View::make('error')->with('message', 'Not possible');
}
return View::make('user.register');
}
/**
* If allowed, register the user.
*
@@ -81,70 +67,72 @@ class UserController extends BaseController
*/
public function postRegister()
{
if (Config::get('auth.allow_register') !== true) {
return View::make('error')->with('message', 'Not possible');
}
$user = $this->user->register(Input::all());
/** @var \FireflyIII\Database\User\User $repository */
$repository = App::make('FireflyIII\Database\User\User');
/** @var \FireflyIII\Shared\Mail\RegistrationInterface $email */
$email = App::make('FireflyIII\Shared\Mail\RegistrationInterface');
$user = $repository->register(Input::all());
if ($user) {
if (Config::get('auth.verify_mail') === true) {
$this->email->sendVerificationMail($user);
$email->sendVerificationMail($user);
return View::make('user.verification-pending');
}
$this->email->sendPasswordMail($user);
return View::make('user.registered');
return View::make('user.verification-pending');
}
return View::make('user.register');
}
/**
* Logout user.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function logout()
{
Auth::logout();
Session::flush();
return Redirect::route('index');
}
/**
* Show form to help user get a new password.
*
* @return \Illuminate\View\View
*/
public function remindme()
{
return View::make('user.remindme');
}
/**
* If need to verify, send new reset code.
* Otherwise, send new password.
*
* @return \Illuminate\View\View
*/
public function postRemindme()
public function postRemindMe()
{
$user = $this->user->findByEmail(Input::get('email'));
/** @var \FireflyIII\Database\User\User $repository */
$repository = App::make('FireflyIII\Database\User\User');
/** @var \FireflyIII\Shared\Mail\RegistrationInterface $email */
$email = App::make('FireflyIII\Shared\Mail\RegistrationInterface');
$user = $repository->findByEmail(Input::get('email'));
if (!$user) {
Session::flash('error', 'No good!');
return View::make('user.remindme');
return View::make('user.remindMe');
}
if (Config::get('auth.verify_reset') === true) {
$this->email->sendResetVerification($user);
$email->sendResetVerification($user);
return View::make('user.verification-pending');
}
$this->email->sendPasswordMail($user);
return View::make('user.verification-pending');
return View::make('user.registered');
}
/**
* If allowed, show the register form.
*
* @return $this|\Illuminate\View\View
*/
public function register()
{
return View::make('user.register');
}
/**
* Show form to help user get a new password.
*
* @return \Illuminate\View\View
*/
public function remindMe()
{
return View::make('user.remindMe');
}
/**
@@ -156,14 +144,21 @@ class UserController extends BaseController
*/
public function reset($reset)
{
$user = $this->user->findByReset($reset);
/** @var \FireflyIII\Database\User\User $repository */
$repository = App::make('FireflyIII\Database\User\User');
/** @var \FireflyIII\Shared\Mail\RegistrationInterface $email */
$email = App::make('FireflyIII\Shared\Mail\RegistrationInterface');
$user = $repository->findByReset($reset);
if ($user) {
$this->email->sendPasswordMail($user);
$email->sendPasswordMail($user);
return View::make('user.registered');
}
return View::make('error')->with('message', 'Yo no hablo reset code!');
return View::make('error')->with('message', 'No reset code found!');
}
}
}

View File

@@ -5,12 +5,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateUsersTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateUsersTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
/**
* Run the migrations.
*
@@ -26,21 +34,9 @@ class CreateUsersTable extends Migration
$table->string('password', 60);
$table->string('reset', 32)->nullable();
$table->string('remember_token', 255)->nullable();
$table->boolean('migrated');
$table->unique('email');
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
}

View File

@@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateAccountTypesTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateAccountTypesTable extends Migration
{
@@ -29,14 +28,14 @@ class CreateAccountTypesTable extends Migration
public function up()
{
Schema::create(
'account_types', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('type', 50);
$table->boolean('editable');
'account_types', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('type', 30);
$table->boolean('editable');
$table->unique('type');
}
$table->unique('type');
}
);
}

View File

@@ -6,11 +6,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateAccountsTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateAccountsTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('accounts');
}
/**
* Run the migrations.
*
@@ -22,34 +31,22 @@ class CreateAccountsTable extends Migration
'accounts', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->integer('user_id')->unsigned();
$table->integer('account_type_id')->unsigned();
$table->string('name', 100);
$table->boolean('active');
// connect accounts to users
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
// connect accounts to account_types
$table->foreign('account_type_id')
->references('id')->on('account_types')
->onDelete('cascade');
$table->foreign('account_type_id')->references('id')->on('account_types')->onDelete('cascade');
// for a user, the account name must be unique.
$table->unique(['user_id', 'account_type_id', 'name']);
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('accounts');
}
}

View File

@@ -6,11 +6,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateComponentsTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateComponentsTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('components');
}
/**
* Run the migrations.
*
@@ -22,29 +31,19 @@ class CreateComponentsTable extends Migration
'components', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->string('name', 50);
$table->integer('user_id')->unsigned();
$table->string('class', 20);
// connect components to users
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
// for a user, the component type & name must be unique.
$table->unique(['user_id', 'class', 'name']);
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('components');
}
}

View File

@@ -6,11 +6,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreatePiggybanksTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreatePiggybanksTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('piggybanks');
}
/**
* Run the migrations.
*
@@ -28,31 +37,22 @@ class CreatePiggybanksTable extends Migration
$table->date('startdate')->nullable();
$table->date('targetdate')->nullable();
$table->boolean('repeats');
$table->enum('rep_length', ['day', 'week', 'month', 'year'])->nullable();
$table->enum('rep_length', ['day', 'week', 'quarter', 'month', 'year'])->nullable();
$table->smallInteger('rep_every')->unsigned();
$table->smallInteger('rep_times')->unsigned()->nullable();
$table->enum('reminder', ['day', 'week', 'month', 'year'])->nullable();
$table->enum('reminder', ['day', 'week', 'quarter', 'month', 'year'])->nullable();
$table->smallInteger('reminder_skip')->unsigned();
$table->boolean('remind_me');
$table->integer('order')->unsigned();
// connect account to piggybank.
$table->foreign('account_id')
->references('id')->on('accounts')
->onDelete('cascade');
// connect account to piggy bank.
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
// for an account, the name must be unique.
$table->unique(['account_id', 'name']);
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('piggybanks');
}
}

View File

@@ -6,11 +6,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateTransactionCurrenciesTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateTransactionCurrenciesTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('transaction_currencies');
}
/**
* Run the migrations.
*
@@ -22,19 +31,13 @@ class CreateTransactionCurrenciesTable extends Migration
'transaction_currencies', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->string('code', 3);
// code must be unique.
$table->unique(['code']);
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('transaction_currencies');
}
}

View File

@@ -6,11 +6,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateTransactionTypesTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateTransactionTypesTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('transaction_types');
}
/**
* Run the migrations.
*
@@ -22,19 +31,13 @@ class CreateTransactionTypesTable extends Migration
'transaction_types', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->string('type', 50);
// type must be unique.
$table->unique(['type']);
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('transaction_types');
}
}

View File

@@ -6,11 +6,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateRecurringTransactionsTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateRecurringTransactionsTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('recurring_transactions');
}
/**
* Run the migrations.
*
@@ -34,6 +43,10 @@ class CreateRecurringTransactionsTable extends Migration
$table->enum('repeat_freq', ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly']);
$table->smallInteger('skip')->unsigned();
// connect user id to users
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
// for a user, the name must be unique
$table->unique(['user_id', 'name']);
@@ -41,14 +54,4 @@ class CreateRecurringTransactionsTable extends Migration
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('recurring_transactions');
}
}

View File

@@ -6,11 +6,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateTransactionJournalsTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateTransactionJournalsTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('transaction_journals');
}
/**
* Run the migrations.
*
@@ -22,6 +31,7 @@ class CreateTransactionJournalsTable extends Migration
'transaction_journals', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->integer('user_id')->unsigned();
$table->integer('transaction_type_id')->unsigned();
$table->integer('recurring_transaction_id')->unsigned()->nullable();
@@ -30,37 +40,21 @@ class CreateTransactionJournalsTable extends Migration
$table->boolean('completed');
$table->date('date');
// connect users
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
// connect transaction journals to transaction types
$table->foreign('transaction_type_id')
->references('id')->on('transaction_types')
->onDelete('cascade');
$table->foreign('transaction_type_id')->references('id')->on('transaction_types')->onDelete('cascade');
// connect transaction journals to recurring transactions
$table->foreign('recurring_transaction_id')
->references('id')->on('recurring_transactions')
->onDelete('set null');
$table->foreign('recurring_transaction_id')->references('id')->on('recurring_transactions')->onDelete('set null');
// connect transaction journals to transaction currencies
$table->foreign('transaction_currency_id')
->references('id')->on('transaction_currencies')
->onDelete('cascade');
$table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('cascade');
// connect users
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('transaction_journals');
}
}

View File

@@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateTransactionsTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateTransactionsTable extends Migration
{
@@ -32,26 +31,25 @@ class CreateTransactionsTable extends Migration
'transactions', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->integer('account_id')->unsigned();
$table->integer('piggybank_id')->nullable()->unsigned();
$table->integer('transaction_journal_id')->unsigned();
$table->string('description', 255)->nullable();
$table->decimal('amount', 10, 2);
// connect transactions to transaction journals
$table->foreign('transaction_journal_id')
->references('id')->on('transaction_journals')
->onDelete('cascade');
// connect account id:
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
// connect piggy banks
$table->foreign('piggybank_id')
->references('id')->on('piggybanks')
->onDelete('set null');
$table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('set null');
// connect transactions to transaction journals
$table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade');
// connect account id:
$table->foreign('account_id')
->references('id')->on('accounts')
->onDelete('cascade');
}
);

View File

@@ -6,11 +6,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateComponentTransactionTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateComponentTransactionTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('component_transaction');
}
/**
* Run the migrations.
*
@@ -25,26 +34,15 @@ class CreateComponentTransactionTable extends Migration
$table->integer('transaction_id')->unsigned();
// connect to components
$table->foreign('component_id')
->references('id')->on('components')
->onDelete('cascade');
$table->foreign('component_id')->references('id')->on('components')->onDelete('cascade');
// connect to transactions
$table->foreign('transaction_id')
->references('id')->on('transactions')
->onDelete('cascade');
$table->foreign('transaction_id')->references('id')->on('transactions')->onDelete('cascade');
// combo must be unique:
$table->unique(['component_id', 'transaction_id']);
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('component_transaction');
}
}

View File

@@ -6,37 +6,10 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateComponentTransactionJournalTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateComponentTransactionJournalTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'component_transaction_journal', function (Blueprint $table) {
$table->increments('id');
$table->integer('component_id')->unsigned();
$table->integer('transaction_journal_id')->unsigned();
// link components with component_id
$table->foreign('component_id')
->references('id')->on('components')
->onDelete('cascade');
// link transaction journals with transaction_journal_id
$table->foreign('transaction_journal_id')
->references('id')->on('transaction_journals')
->onDelete('cascade');
}
);
}
/**
* Reverse the migrations.
*
@@ -47,4 +20,29 @@ class CreateComponentTransactionJournalTable extends Migration
Schema::drop('component_transaction_journal');
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'component_transaction_journal', function (Blueprint $table) {
$table->increments('id');
$table->integer('component_id')->unsigned();
$table->integer('transaction_journal_id')->unsigned();
// link components with component_id
$table->foreign('component_id')->references('id')->on('components')->onDelete('cascade');
// link transaction journals with transaction_journal_id
$table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade');
// combo must be unique:
$table->unique(['component_id', 'transaction_journal_id'], 'cid_tjid_unique');
}
);
}
}

View File

@@ -6,11 +6,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreatePreferencesTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreatePreferencesTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('preferences');
}
/**
* Run the migrations.
*
@@ -27,21 +36,12 @@ class CreatePreferencesTable extends Migration
$table->text('data');
// connect preferences to users
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
// only one preference per name per user
$table->unique(['user_id', 'name']);
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('preferences');
}
}

View File

@@ -1,31 +1,15 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateSessionTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateSessionTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'sessions', function ($t) {
$t->string('id')->unique();
$t->text('payload');
$t->integer('last_activity');
}
);
}
/**
* Reverse the migrations.
*
@@ -36,4 +20,20 @@ class CreateSessionTable extends Migration
Schema::drop('sessions');
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'sessions', function (Blueprint $table) {
$table->string('id')->unique();
$table->text('payload');
$table->integer('last_activity');
}
);
}
}

View File

@@ -6,38 +6,10 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateLimitsTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateLimitsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'limits', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('component_id')->unsigned();
$table->date('startdate');
$table->decimal('amount', 10, 2);
$table->boolean('repeats');
$table->enum('repeat_freq', ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly']);
$table->unique(['component_id', 'startdate', 'repeat_freq']);
// connect component
$table->foreign('component_id')
->references('id')->on('components')
->onDelete('cascade');
}
);
}
/**
* Reverse the migrations.
*
@@ -48,4 +20,29 @@ class CreateLimitsTable extends Migration
Schema::drop('limits');
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'limits', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('component_id')->unsigned();
$table->date('startdate');
$table->decimal('amount', 10, 2);
$table->boolean('repeats');
$table->enum('repeat_freq', ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly']);
$table->unique(['component_id', 'startdate', 'repeat_freq'], 'unique_ci_combi');
// connect component
$table->foreign('component_id')->references('id')->on('components')->onDelete('cascade');
}
);
}
}

View File

@@ -6,11 +6,20 @@ use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateLimitRepeatTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateLimitRepeatTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('limit_repetitions');
}
/**
* Run the migrations.
*
@@ -30,21 +39,9 @@ class CreateLimitRepeatTable extends Migration
$table->unique(['limit_id', 'startdate', 'enddate']);
// connect limit
$table->foreign('limit_id')
->references('id')->on('limits')
->onDelete('cascade');
$table->foreign('limit_id')->references('id')->on('limits')->onDelete('cascade');
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('limit_repetitions');
}
}

View File

@@ -0,0 +1,50 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateComponentRecurringTransactionTable
*
*/
class CreateComponentRecurringTransactionTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('component_recurring_transaction');
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'component_recurring_transaction', function (Blueprint $table) {
$table->increments('id');
$table->integer('component_id')->unsigned();
$table->integer('recurring_transaction_id')->unsigned();
$table->boolean('optional');
// link components with component_id
$table->foreign('component_id')->references('id')->on('components')->onDelete('cascade');
// link transaction journals with transaction_journal_id
$table->foreign('recurring_transaction_id')->references('id')->on('recurring_transactions')->onDelete('cascade');
// component and recurring transaction must be unique.
$table->unique(['component_id', 'recurring_transaction_id'], 'cid_rtid_unique');
}
);
}
}

View File

@@ -1,51 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class RecurringTransactionsToComponents
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class RecurringTransactionsToComponents extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'component_recurring_transaction', function (Blueprint $table) {
$table->increments('id');
$table->integer('component_id')->unsigned();
$table->integer('recurring_transaction_id')->unsigned();
$table->boolean('optional');
// link components with component_id
$table->foreign('component_id')
->references('id')->on('components')
->onDelete('cascade');
// link transaction journals with transaction_journal_id
$table->foreign('recurring_transaction_id')
->references('id')->on('recurring_transactions')
->onDelete('cascade');
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('component_recurring_transaction');
}
}

View File

@@ -3,9 +3,23 @@
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePiggyInstance extends Migration
/**
* Class CreatePiggyInstance
*
*/
class CreatePiggybankRepetitionsTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('piggybank_repetitions');
}
/**
* Run the migrations.
*
@@ -25,21 +39,9 @@ class CreatePiggyInstance extends Migration
$table->unique(['piggybank_id', 'startdate', 'targetdate']);
// connect instance to piggybank.
$table->foreign('piggybank_id')
->references('id')->on('piggybanks')
->onDelete('cascade');
$table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('cascade');
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('piggybank_repetitions');
}
}

View File

@@ -3,9 +3,23 @@
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePiggyEvents extends Migration
/**
* Class CreatePiggybankEventsTable
*
*/
class CreatePiggybankEventsTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('piggybank_events');
}
/**
* Run the migrations.
*
@@ -18,25 +32,18 @@ class CreatePiggyEvents extends Migration
$table->increments('id');
$table->timestamps();
$table->integer('piggybank_id')->unsigned();
$table->integer('transaction_journal_id')->unsigned()->nullable();
$table->date('date');
$table->decimal('amount', 10, 2);
// connect instance to piggybank.
$table->foreign('piggybank_id')
->references('id')->on('piggybanks')
->onDelete('cascade');
$table->foreign('piggybank_id')->references('id')->on('piggybanks')->onDelete('cascade');
// connect to journal:
$table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('set null');
}
);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('piggybank_events');
}
}

View File

@@ -3,6 +3,10 @@
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateRemindersTable
*
*/
class CreateRemindersTable extends Migration
{
@@ -27,30 +31,16 @@ class CreateRemindersTable extends Migration
'reminders', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('class', 40);
$table->integer('piggybank_id')->unsigned()->nullable();
$table->integer('recurring_transaction_id')->unsigned()->nullable();
$table->integer('user_id')->unsigned();
$table->date('startdate');
$table->date('enddate')->nullable();
$table->boolean('active');
// connect reminders to piggy banks.
$table->foreign('piggybank_id')
->references('id')->on('piggybanks')
->onDelete('set null');
// connect reminders to recurring transactions.
$table->foreign('recurring_transaction_id')
->references('id')->on('recurring_transactions')
->onDelete('set null');
$table->boolean('notnow')->default(0);
$table->integer('remindersable_id')->unsigned()->nullable();
$table->string('remindersable_type')->nullable();
// connect reminders to users
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
}
);
}

View File

@@ -1,41 +0,0 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateImportmapsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('importmaps', function(Blueprint $table)
{
$table->increments('id');
$table->timestamps();
$table->integer('user_id')->unsigned();
$table->string('file',500);
$table->integer('totaljobs')->unsigned();
$table->integer('jobsdone')->unsigned();
// connect maps to users
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('importmaps');
}
}

View File

@@ -1,42 +0,0 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateImportentriesTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('importentries', function(Blueprint $table)
{
$table->increments('id');
$table->timestamps();
$table->string('class',200);
$table->integer('importmap_id')->unsigned();
$table->integer('old')->unsigned();
$table->integer('new')->unsigned();
// map import entries to import map.
// connect accounts to account_types
$table->foreign('importmap_id')
->references('id')->on('importmaps')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('importentries');
}
}

View File

@@ -1,35 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateFailedJobsTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('failed_jobs');
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('failed_jobs', function (Blueprint $table) {
$table->increments('id');
$table->text('connection');
$table->text('queue');
$table->text('payload');
$table->timestamp('failed_at');
});
}
}

View File

@@ -0,0 +1,47 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateAccountMetaTable
*
*/
class CreateAccountMetaTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schema::drop('account_meta');
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//
Schema::create(
'account_meta', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('account_id')->unsigned();
$table->string('name');
$table->text('data');
$table->unique(['account_id', 'name']);
}
);
}
}

View File

@@ -0,0 +1,46 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateTransactionGroupsTable
*
*/
class CreateTransactionGroupsTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('transaction_groups');
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'transaction_groups', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->integer('user_id')->unsigned();
$table->enum('relation', ['balance']);
// connect reminders to users
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
}
);
}
}

View File

@@ -0,0 +1,49 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateTransactionGroupTransactionJournalTable
*
* @SuppressWarnings(PHPMD.ShortMethodName)
*/
class CreateTransactionGroupTransactionJournalTable extends Migration
{
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schema::drop('transaction_group_transaction_journal');
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(
'transaction_group_transaction_journal', function (Blueprint $table) {
$table->increments('id');
$table->integer('transaction_group_id')->unsigned();
$table->integer('transaction_journal_id')->unsigned();
// link to foreign tables.
$table->foreign('transaction_group_id', 'tr_grp_id')->references('id')->on('transaction_groups')->onDelete('cascade');
$table->foreign('transaction_journal_id', 'tr_trj_id')->references('id')->on('transaction_journals')->onDelete('cascade');
// add unique.
$table->unique(['transaction_group_id', 'transaction_journal_id'], 'tt_joined');
}
);
}
}

View File

@@ -0,0 +1,494 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Down:
* 1. Create new Components based on Budgets.
* 2. Create new Components based on Categories
* 3. Recreate component_id in limits
* 4. Update all budget_limits entries (component_id).
* 5. Add the foreign key to component_id in budget_limits
* 6. Drop column 'budget_id' in budget_limits.
* 7. Create table journal_components.
* 8. create entries for budgets in journal_components.
* 9. create entries for categories in journal_components.
* 10. drop table budget_journals
* 11. drop table category_journals
* 12. drop table budgets
* 13. drop table categories.
* 14. rename budget_limits to limits.
* 15. Rename piggy_bank_events to piggybank_events
* 16. Rename field 'budget_limit_id' to 'limit_id' in 'limit_repetitions'
* 17. Do not recreate component_recurring_transaction
* 18. Do not recreate component_transaction
* 19. Do not recreate field 'piggybank_id' in 'transactions'
* 20. Drop fields from currency table.
*
*
*
* Up:
*
* 1. Create new budget table.
* 2. Create new category table.
* 3. Create journal_budget table.
* 4. Create journal_category table.
* 5. Move budgets to new budgets table AND move journal_components to budget_components.
* 6. Move categories to categories table AND move journal_components to category_components.
* 7. Rename limits to budget_limits.
* 8. Rename piggybank_events to piggy_bank_events
* 9. Rename field 'limit_id' to 'budget_limit_id' in 'limit_repetitions'
* 10. Create field budget_id in budget_limits.
* 11. Update budget_limits with budgets (instead of components).
* 12. drop table journal_components
* 13. Drop table component_recurring_transaction
* 14. Drop table component_transaction
* 15. Drop field 'piggybank_id' from 'transactions'
* 16. Drop field 'component_id' from 'budget_limits'
* 17. Expand currency table with new fields.
*
* Class ChangesForV321
*/
class ChangesForV321 extends Migration
{
public function down()
{
$this->moveBudgetsBack(); // 1.
$this->moveCategoriesBack(); // 2.
$this->createComponentId(); // 3.
$this->updateComponentInBudgetLimits(); // 4.
$this->createComponentIdForeignKey(); // 5.
$this->dropBudgetIdColumnInBudgetLimits(); // 6.
$createComponents = new CreateComponentTransactionJournalTable; // 7.
$createComponents->up();
$this->moveBackEntriesForBudgetsInJoinedTable(); // 8.
$this->moveBackEntriesForCategoriesInJoinedTable(); // 9.
$this->dropBudgetJournalTable(); // 10.
$this->dropCategoryJournalTable(); // 11.
$this->dropBudgetTable(); // 12.
$this->dropCategoryTable(); // 13.
$this->renameBudgetLimits(); // 14.
$this->renamePiggyBankEvents(); // 15.
$this->renameBudgetLimitToBudgetInRepetitions(); // 16.
// 17, 18, 19
$this->dropFieldsFromCurrencyTable(); // 20.
}
public function moveBudgetsBack()
{
Budget::get()->each(
function (Budget $budget) {
Component::firstOrCreate(
[
'name' => $budget->name,
'user_id' => $budget->user_id,
'class' => 'Budget'
]
);
}
);
}
public function moveCategoriesBack()
{
Category::get()->each(
function (Category $category) {
Component::firstOrCreate(
[
'name' => $category->name,
'user_id' => $category->user_id,
'class' => 'Category'
]
);
}
);
}
public function createComponentId()
{
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->integer('component_id')->unsigned();
}
);
}
public function updateComponentInBudgetLimits()
{
BudgetLimit::get()->each(
function (BudgetLimit $bl) {
$budgetId = $bl->budget_id;
$budget = Budget::find($budgetId);
if ($budget) {
$component = Component::where('class', 'Budget')->where('user_id', $budget->user_id)->where('name', $budget->name)->first();
if ($component) {
$bl->component_id = $component->id;
$bl->save();
}
}
}
);
}
public function createComponentIdForeignKey()
{
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->foreign('component_id', 'limits_component_id_foreign')->references('id')->on('components')->onDelete('cascade');
}
);
}
public function dropBudgetIdColumnInBudgetLimits()
{
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->dropForeign('bid_foreign');
$table->dropColumn('budget_id'); // also drop foreign key!
}
);
}
public function moveBackEntriesForBudgetsInJoinedTable()
{
$set = DB::table('budget_transaction_journal')->get();
foreach ($set as $entry) {
$budget = Budget::find($entry->budget_id);
if ($budget) {
$component = Component::where('class', 'Budget')->where('name', $budget->name)->where('user_id', $budget->user_id)->first();
if ($component) {
DB::table('component_transaction_journal')->insert(
[
'component_id' => $component->id,
'transaction_journal_id' => $entry->transaction_journal_id
]
);
}
}
}
}
public function moveBackEntriesForCategoriesInJoinedTable()
{
$set = DB::table('category_transaction_journal')->get();
foreach ($set as $entry) {
$category = Category::find($entry->category_id);
if ($category) {
$component = Component::where('class', 'Category')->where('name', $category->name)->where('user_id', $category->user_id)->first();
if ($component) {
DB::table('component_transaction_journal')->insert(
[
'component_id' => $component->id,
'transaction_journal_id' => $entry->transaction_journal_id
]
);
}
}
}
}
public function dropBudgetJournalTable()
{
Schema::dropIfExists('budget_transaction_journal');
}
public function dropCategoryJournalTable()
{
Schema::dropIfExists('category_transaction_journal');
}
public function dropBudgetTable()
{
Schema::dropIfExists('budgets');
}
public function dropCategoryTable()
{
Schema::dropIfExists('categories');
}
public function renameBudgetLimits()
{
Schema::rename('budget_limits', 'limits');
}
public function renamePiggyBankEvents()
{
Schema::rename('piggy_bank_events', 'piggybank_events');
}
public function renameBudgetLimitToBudgetInRepetitions()
{
Schema::table(
'limit_repetitions', function (Blueprint $table) {
$table->renameColumn('budget_limit_id', 'limit_id');
}
);
}
public function dropFieldsFromCurrencyTable()
{
Schema::table(
'transaction_currencies', function (Blueprint $table) {
$table->dropColumn('symbol');
$table->dropColumn('name');
}
);
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$this->createBudgetTable(); // 1.
$this->createCategoryTable(); // 2.
$this->createBudgetJournalTable(); // 3
$this->createCategoryJournalTable(); // 4.
$this->moveBudgets(); // 5.
$this->moveCategories(); // 6.
$this->correctNameForBudgetLimits(); // 7.
$this->correctNameForPiggyBankEvents(); // 8.
$this->renameBudgetToBudgetLimitInRepetitions(); // 9.
$this->addBudgetIdFieldToBudgetLimits(); // 10.
$this->moveComponentIdToBudgetId(); // 11.
$this->dropComponentJournalTable(); // 12.
$this->dropComponentRecurringTransactionTable(); // 13.
$this->dropComponentTransactionTable(); // 14.
$this->dropPiggyBankIdFromTransactions(); // 15.
$this->dropComponentIdFromBudgetLimits(); // 16.
$this->expandCurrencyTable(); // 17.
}
public function createBudgetTable()
{
Schema::create(
'budgets', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->string('name', 50);
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unique(['user_id', 'name']);
}
);
}
public function createCategoryTable()
{
Schema::create(
'categories', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->softDeletes();
$table->string('name', 50);
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unique(['user_id', 'name']);
}
);
}
public function createBudgetJournalTable()
{
Schema::create(
'budget_transaction_journal', function (Blueprint $table) {
$table->increments('id');
$table->integer('budget_id')->unsigned();
$table->integer('transaction_journal_id')->unsigned();
$table->foreign('budget_id')->references('id')->on('budgets')->onDelete('cascade');
$table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade');
$table->unique(['budget_id', 'transaction_journal_id'], 'budid_tjid_unique');
}
);
}
public function createCategoryJournalTable()
{
Schema::create(
'category_transaction_journal', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->integer('transaction_journal_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
$table->foreign('transaction_journal_id')->references('id')->on('transaction_journals')->onDelete('cascade');
$table->unique(['category_id', 'transaction_journal_id'], 'catid_tjid_unique');
}
);
}
public function moveBudgets()
{
Component::where('class', 'Budget')->get()->each(
function (Component $c) {
$entry = [
'user_id' => $c->user_id,
'name' => $c->name
];
$budget = Budget::firstOrCreate($entry);
Log::debug('Migrated budget #' . $budget->id . ': ' . $budget->name);
// create entry in budget_transaction_journal
$connections = DB::table('component_transaction_journal')->where('component_id', $c->id)->get();
foreach ($connections as $connection) {
DB::table('budget_transaction_journal')->insert(
[
'budget_id' => $budget->id,
'transaction_journal_id' => $connection->transaction_journal_id
]
);
}
}
);
}
public function moveCategories()
{
Component::where('class', 'Category')->get()->each(
function (Component $c) {
$entry = [
'user_id' => $c->user_id,
'name' => $c->name
];
$category = Category::firstOrCreate($entry);
Log::debug('Migrated category #' . $category->id . ': ' . $category->name);
// create entry in category_transaction_journal
$connections = DB::table('component_transaction_journal')->where('component_id', $c->id)->get();
foreach ($connections as $connection) {
DB::table('category_transaction_journal')->insert(
[
'category_id' => $category->id,
'transaction_journal_id' => $connection->transaction_journal_id
]
);
}
}
);
}
public function correctNameForBudgetLimits()
{
Schema::rename('limits', 'budget_limits');
}
public function correctNameForPiggyBankEvents()
{
Schema::rename('piggybank_events', 'piggy_bank_events');
}
public function renameBudgetToBudgetLimitInRepetitions()
{
Schema::table(
'limit_repetitions', function (Blueprint $table) {
$table->renameColumn('limit_id', 'budget_limit_id');
}
);
}
public function addBudgetIdFieldToBudgetLimits()
{
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->integer('budget_id', false, true)->nullable()->after('updated_at');
$table->foreign('budget_id', 'bid_foreign')->references('id')->on('budgets')->onDelete('cascade');
}
);
}
public function moveComponentIdToBudgetId()
{
\Log::debug('Now in moveComponentIdToBudgetId()');
BudgetLimit::get()->each(
function (BudgetLimit $bl) {
\Log::debug('Now at budgetLimit #' . $bl->id . ' with component_id: ' . $bl->component_id);
$component = Component::find($bl->component_id);
if ($component) {
\Log::debug('Found component with id #' . $component->id . ' and name ' . $component->name);
$budget = Budget::whereName($component->name)->whereUserId($component->user_id)->first();
if ($budget) {
\Log::debug('Found a budget with ID #' . $budget->id . ' and name ' . $budget->name);
$bl->budget_id = $budget->id;
$bl->save();
\Log::debug('Connected budgetLimit #' . $bl->id . ' to budget_id' . $budget->id);
} else {
\Log::debug('Could not find a matching budget with name ' . $component->name);
}
} else {
\Log::debug('Could not find a component with id ' . $bl->component_id);
}
}
);
\Log::debug('Done with moveComponentIdToBudgetId()');
}
public function dropComponentJournalTable()
{
Schema::dropIfExists('component_transaction_journal');
}
public function dropComponentRecurringTransactionTable()
{
Schema::dropIfExists('component_recurring_transaction');
}
public function dropComponentTransactionTable()
{
Schema::dropIfExists('component_transaction');
}
public function dropPiggyBankIdFromTransactions()
{
Schema::table(
'transactions', function (Blueprint $table) {
if (Schema::hasColumn('transactions', 'piggybank_id')) {
$table->dropForeign('transactions_piggybank_id_foreign');
$table->dropColumn('piggybank_id');
}
}
);
}
public function dropComponentIdFromBudgetLimits()
{
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->dropForeign('limits_component_id_foreign');
$table->dropColumn('component_id');
}
);
}
public function expandCurrencyTable()
{
Schema::table(
'transaction_currencies', function (Blueprint $table) {
$table->string('name', 48)->nullable();
$table->string('symbol', 8)->nullable();
}
);
\DB::update('UPDATE `transaction_currencies` SET `symbol` = "&#8364;", `name` = "Euro" WHERE `code` = "EUR";');
}
}

View File

@@ -0,0 +1,168 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class ChangesForV322
*/
class ChangesForV322 extends Migration
{
/**
*
*/
public function down()
{
// rename tables:
Schema::rename('piggy_bank_repetitions', 'piggybank_repetitions');
Schema::rename('piggy_banks', 'piggybanks');
// rename fields
Schema::table(
'piggy_bank_events', function (Blueprint $table) {
$table->renameColumn('piggy_bank_id', 'piggybank_id');
}
);
Schema::table(
'piggybank_repetitions', function (Blueprint $table) {
$table->renameColumn('piggy_bank_id', 'piggybank_id');
}
);
// remove soft delete to piggy banks
Schema::table(
'piggybanks', function (Blueprint $table) {
$table->dropSoftDeletes();
}
);
// drop keys from bills (foreign bills_uid_for and unique uid_name_unique)
Schema::table(
'bills', function (Blueprint $table) {
$table->dropForeign('bills_uid_for');
$table->dropUnique('uid_name_unique');
}
);
// drop foreign key from transaction_journals (bill_id_foreign)
Schema::table(
'transaction_journals', function (Blueprint $table) {
$table->dropForeign('bill_id_foreign');
}
);
// drop foreign key from budget_limits:
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->dropForeign('bid_foreign');
$table->dropUnique('unique_bl_combi');
}
);
// rename bills to recurring_transactions
Schema::rename('bills', 'recurring_transactions');
// recreate foreign key recurring_transactions_user_id_foreign in recurring_transactions
// recreate unique recurring_transactions_user_id_name_unique in recurring_transactions
Schema::table(
'recurring_transactions', function (Blueprint $table) {
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unique(['user_id', 'name']);
}
);
// rename bill_id to recurring_transaction_id
// recreate foreign transaction_journals_recurring_transaction_id_foreign in transaction_journals
Schema::table(
'transaction_journals', function (Blueprint $table) {
$table->renameColumn('bill_id', 'recurring_transaction_id');
$table->foreign('recurring_transaction_id')->references('id')->on('recurring_transactions')->onDelete('set null');
}
);
}
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// rename tables:
Schema::rename('piggybank_repetitions', 'piggy_bank_repetitions');
Schema::rename('piggybanks', 'piggy_banks');
// recreate it the correct way:
Schema::table(
'budget_limits', function (Blueprint $table) {
$table->unique(['budget_id', 'startdate', 'repeat_freq'], 'unique_bl_combi');
}
);
// rename fields
Schema::table(
'piggy_bank_events', function (Blueprint $table) {
$table->renameColumn('piggybank_id', 'piggy_bank_id');
}
);
Schema::table(
'piggy_bank_repetitions', function (Blueprint $table) {
$table->renameColumn('piggybank_id', 'piggy_bank_id');
}
);
// add soft delete to piggy banks
Schema::table(
'piggy_banks', function (Blueprint $table) {
$table->softDeletes();
}
);
// rename everything related to recurring transactions, aka bills:
Schema::table(
'transaction_journals', function (Blueprint $table) {
// drop relation
$table->dropForeign('transaction_journals_recurring_transaction_id_foreign');
// rename column
$table->renameColumn('recurring_transaction_id', 'bill_id');
}
);
Schema::table(
'recurring_transactions', function (Blueprint $table) {
$table->dropForeign('recurring_transactions_user_id_foreign');
$table->dropUnique('recurring_transactions_user_id_name_unique');
}
);
// rename table:
Schema::rename('recurring_transactions', 'bills');
// recreate foreign relation:
Schema::table(
'transaction_journals', function (Blueprint $table) {
$table->foreign('bill_id', 'bill_id_foreign')->references('id')->on('bills')->onDelete('set null');
}
);
// recreate more foreign relations.
Schema::table(
'bills', function (Blueprint $table) {
// connect user id to users
$table->foreign('user_id', 'bills_uid_for')->references('id')->on('users')->onDelete('cascade');
// for a user, the name must be unique
$table->unique(['user_id', 'name'], 'uid_name_unique');
}
);
}
}

View File

@@ -38,4 +38,4 @@ class AccountTypeSeeder extends Seeder
}
}
}

View File

@@ -19,6 +19,7 @@ class DatabaseSeeder extends Seeder
$this->call('TransactionCurrencySeeder');
$this->call('TransactionTypeSeeder');
$this->call('DefaultUserSeeder');
$this->call('TestContentSeeder');
}
}

View File

@@ -8,17 +8,15 @@ class DefaultUserSeeder extends Seeder
public function run()
{
DB::table('users')->delete();
if (App::environment() == 'testing' || App::environment() == 'homestead') {
User::create(
[
'email' => 's@nder.be',
'password' => 'sander',
'reset' => null,
'remember_token' => null,
'migrated' => 0
]
);
User::create(['email' => 'thegrumpydictator@gmail.com', 'password' => 'james', 'reset' => null, 'remember_token' => null]);
User::create(['email' => 'acceptance@example.com', 'password' => 'acceptance', 'reset' => null, 'remember_token' => null]);
User::create(['email' => 'functional@example.com', 'password' => 'functional', 'reset' => null, 'remember_token' => null]);
User::create(['email' => 'reset@example.com', 'password' => 'functional', 'reset' => 'okokokokokokokokokokokokokokokok', 'remember_token' => null]);
}
}
}
}

View File

@@ -0,0 +1,561 @@
<?php
use Carbon\Carbon;
/**
*
* @SuppressWarnings("CamelCase") // I'm fine with this.
*
* Class TestContentSeeder
*/
class TestContentSeeder extends Seeder
{
/** @var string */
public $eom;
/** @var string */
public $neom;
/** @var string */
public $nsom;
/** @var string */
public $som;
/** @var string */
public $today;
/** @var string */
public $yaeom;
/** @var string */
public $yasom;
/** @var Carbon */
protected $_endOfMonth;
/** @var Carbon */
protected $_nextEndOfMonth;
/** @var Carbon */
protected $_nextStartOfMonth;
/** @var Carbon */
protected $_startOfMonth;
/** @var Carbon */
protected $_today;
/** @var Carbon */
protected $_yearAgoEndOfMonth;
/** @var Carbon */
protected $_yearAgoStartOfMonth;
/**
*
*/
public function __construct()
{
$this->_startOfMonth = Carbon::now()->startOfMonth();
$this->som = $this->_startOfMonth->format('Y-m-d');
$this->_endOfMonth = Carbon::now()->endOfMonth();
$this->eom = $this->_endOfMonth->format('Y-m-d');
$this->_nextStartOfMonth = Carbon::now()->addMonth()->startOfMonth();
$this->nsom = $this->_nextStartOfMonth->format('Y-m-d');
$this->_nextEndOfMonth = Carbon::now()->addMonth()->endOfMonth();
$this->neom = $this->_nextEndOfMonth->format('Y-m-d');
$this->_yearAgoStartOfMonth = Carbon::now()->subYear()->startOfMonth();
$this->yasom = $this->_yearAgoStartOfMonth->format('Y-m-d');
$this->_yearAgoEndOfMonth = Carbon::now()->subYear()->startOfMonth();
$this->yaeom = $this->_yearAgoEndOfMonth->format('Y-m-d');
$this->_today = Carbon::now();
$this->today = $this->_today->format('Y-m-d');
}
/**
* Dates are always this month, the start of this month or earlier.
*/
public function run()
{
if (App::environment() == 'testing' || App::environment() == 'homestead') {
$user = User::whereEmail('thegrumpydictator@gmail.com')->first();
// create initial accounts and various other stuff:
$this->createAssetAccounts($user);
$this->createBudgets($user);
$this->createCategories($user);
$this->createPiggyBanks($user);
$this->createReminders($user);
$this->createRecurringTransactions($user);
$this->createBills($user);
$this->createExpenseAccounts($user);
$this->createRevenueAccounts($user);
// get some objects from the database:
$checking = Account::whereName('Checking account')->orderBy('id', 'DESC')->first();
$savings = Account::whereName('Savings account')->orderBy('id', 'DESC')->first();
$landLord = Account::whereName('Land lord')->orderBy('id', 'DESC')->first();
$utilities = Account::whereName('Utilities company')->orderBy('id', 'DESC')->first();
$television = Account::whereName('TV company')->orderBy('id', 'DESC')->first();
$phone = Account::whereName('Phone agency')->orderBy('id', 'DESC')->first();
$employer = Account::whereName('Employer')->orderBy('id', 'DESC')->first();
$bills = Budget::whereName('Bills')->orderBy('id', 'DESC')->first();
$groceries = Budget::whereName('Groceries')->orderBy('id', 'DESC')->first();
$house = Category::whereName('House')->orderBy('id', 'DESC')->first();
$withdrawal = TransactionType::whereType('Withdrawal')->first();
$deposit = TransactionType::whereType('Deposit')->first();
$transfer = TransactionType::whereType('Transfer')->first();
$euro = TransactionCurrency::whereCode('EUR')->first();
$rentBill = Bill::where('name', 'Rent')->first();
$current = clone $this->_yearAgoStartOfMonth;
while ($current <= $this->_startOfMonth) {
$cur = $current->format('Y-m-d');
$formatted = $current->format('F Y');
// create expenses for rent, utilities, TV, phone on the 1st of the month.
$this->createTransaction($checking, $landLord, 800, $withdrawal, 'Rent for ' . $formatted, $cur, $euro, $bills, $house, $rentBill);
$this->createTransaction($checking, $utilities, 150, $withdrawal, 'Utilities for ' . $formatted, $cur, $euro, $bills, $house);
$this->createTransaction($checking, $television, 50, $withdrawal, 'TV for ' . $formatted, $cur, $euro, $bills, $house);
$this->createTransaction($checking, $phone, 50, $withdrawal, 'Phone bill for ' . $formatted, $cur, $euro, $bills, $house);
// two transactions. One without a budget, one without a category.
$this->createTransaction($checking, $phone, 10, $withdrawal, 'Extra charges on phone bill for ' . $formatted, $cur, $euro, null, $house);
$this->createTransaction($checking, $television, 5, $withdrawal, 'Extra charges on TV bill for ' . $formatted, $cur, $euro, $bills, null);
// income from job:
$this->createTransaction($employer, $checking, rand(3500, 4000), $deposit, 'Salary for ' . $formatted, $cur, $euro);
$this->createTransaction($checking, $savings, 2000, $transfer, 'Salary to savings account in ' . $formatted, $cur, $euro);
$this->createGroceries($current);
$this->createBigExpense(clone $current);
echo 'Created test-content for ' . $current->format('F Y') . "\n";
$current->addMonth();
}
// piggy bank event
// add money to this piggy bank
// create a piggy bank event to match:
$piggyBank = PiggyBank::whereName('New camera')->orderBy('id', 'DESC')->first();
$intoPiggy = $this->createTransaction($checking, $savings, 100, $transfer, 'Money for piggy', $this->yaeom, $euro, $groceries, $house);
PiggyBankEvent::create(
[
'piggy_bank_id' => $piggyBank->id,
'transaction_journal_id' => $intoPiggy->id,
'date' => $this->yaeom,
'amount' => 100
]
);
}
}
/**
* @param User $user
*/
public function createAssetAccounts(User $user)
{
$assetType = AccountType::whereType('Asset account')->first();
$ibType = AccountType::whereType('Initial balance account')->first();
$obType = TransactionType::whereType('Opening balance')->first();
$euro = TransactionCurrency::whereCode('EUR')->first();
$acc_a = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Checking account', 'active' => 1]);
$acc_b = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Savings account', 'active' => 1]);
$acc_c = Account::create(['user_id' => $user->id, 'account_type_id' => $assetType->id, 'name' => 'Delete me', 'active' => 1]);
$acc_d = Account::create(['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Checking account initial balance', 'active' => 0]);
$acc_e = Account::create(['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Savings account initial balance', 'active' => 0]);
$acc_f = Account::create(['user_id' => $user->id, 'account_type_id' => $ibType->id, 'name' => 'Delete me initial balance', 'active' => 0]);
$this->createTransaction($acc_d, $acc_a, 4000, $obType, 'Initial Balance for Checking account', $this->yasom, $euro);
$this->createTransaction($acc_e, $acc_b, 10000, $obType, 'Initial Balance for Savings account', $this->yasom, $euro);
$this->createTransaction($acc_f, $acc_c, 100, $obType, 'Initial Balance for Delete me', $this->yasom, $euro);
}
/**
* @param Account $from
* @param Account $to
* @param $amount
* @param TransactionType $type
* @param $description
* @param $date
* @param TransactionCurrency $currency
*
* @param Budget $budget
* @param Category $category
* @param Bill $bill
*
* @return TransactionJournal
*/
public function createTransaction(
Account $from, Account $to, $amount, TransactionType $type, $description, $date, TransactionCurrency $currency, Budget $budget = null,
Category $category = null, Bill $bill = null
) {
$user = User::whereEmail('thegrumpydictator@gmail.com')->first();
$billID = is_null($bill) ? null : $bill->id;
/** @var TransactionJournal $journal */
$journal = TransactionJournal::create(
[
'user_id' => $user->id, 'transaction_type_id' => $type->id, 'transaction_currency_id' => $currency->id, 'bill_id' => $billID,
'description' => $description, 'completed' => 1, 'date' => $date
]
);
Transaction::create(['account_id' => $from->id, 'transaction_journal_id' => $journal->id, 'amount' => $amount * -1]);
Transaction::create(['account_id' => $to->id, 'transaction_journal_id' => $journal->id, 'amount' => $amount]);
if (!is_null($budget)) {
$journal->budgets()->save($budget);
}
if (!is_null($category)) {
$journal->categories()->save($category);
}
return $journal;
}
/**
* @param User $user
*/
public function createBudgets(User $user)
{
$groceries = Budget::create(['user_id' => $user->id, 'name' => 'Groceries']);
$bills = Budget::create(['user_id' => $user->id, 'name' => 'Bills']);
$deleteMe = Budget::create(['user_id' => $user->id, 'name' => 'Delete me']);
Budget::create(['user_id' => $user->id, 'name' => 'Budget without repetition']);
$groceriesLimit = BudgetLimit::create(
['startdate' => $this->som, 'amount' => 201, 'repeats' => 0, 'repeat_freq' => 'monthly', 'budget_id' => $groceries->id]
);
$billsLimit = BudgetLimit::create(
['startdate' => $this->som, 'amount' => 202, 'repeats' => 0, 'repeat_freq' => 'monthly', 'budget_id' => $bills->id]
);
$deleteMeLimit = BudgetLimit::create(
['startdate' => $this->som, 'amount' => 203, 'repeats' => 0, 'repeat_freq' => 'monthly', 'budget_id' => $deleteMe->id]
);
// and because we have no filters, some repetitions:
LimitRepetition::create(['budget_limit_id' => $groceriesLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 201]);
LimitRepetition::create(['budget_limit_id' => $billsLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 202]);
LimitRepetition::create(['budget_limit_id' => $deleteMeLimit->id, 'startdate' => $this->som, 'enddate' => $this->eom, 'amount' => 203]);
}
/**
* @param User $user
*/
public function createCategories(User $user)
{
Category::create(['user_id' => $user->id, 'name' => 'DailyGroceries']);
Category::create(['user_id' => $user->id, 'name' => 'Lunch']);
Category::create(['user_id' => $user->id, 'name' => 'House']);
Category::create(['user_id' => $user->id, 'name' => 'Delete me']);
}
/**
* @param User $user
*/
public function createPiggyBanks(User $user)
{
// account
$savings = Account::whereName('Savings account')->orderBy('id', 'DESC')->first();
// some dates
$endDate = clone $this->_startOfMonth;
$nextYear = clone $this->_startOfMonth;
$endDate->addMonths(4);
$nextYear->addYear()->subDay();
$next = $nextYear->format('Y-m-d');
$end = $endDate->format('Y-m-d');
// piggy bank
$newCamera = PiggyBank::create(
[
'account_id' => $savings->id,
'name' => 'New camera',
'targetamount' => 2000,
'startdate' => $this->som,
'targetdate' => null,
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => null,
'reminder_skip' => 0,
'remind_me' => 0,
'order' => 0,
]
);
// and some events!
PiggyBankEvent::create(['piggy_bank_id' => $newCamera->id, 'date' => $this->som, 'amount' => 100]);
PiggyBankRepetition::create(['piggy_bank_id' => $newCamera->id, 'startdate' => $this->som, 'targetdate' => null, 'currentamount' => 100]);
$newClothes = PiggyBank::create(
[
'account_id' => $savings->id,
'name' => 'New clothes',
'targetamount' => 2000,
'startdate' => $this->som,
'targetdate' => $end,
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => null,
'reminder_skip' => 0,
'remind_me' => 0,
'order' => 0,
]
);
PiggyBankEvent::create(['piggy_bank_id' => $newClothes->id, 'date' => $this->som, 'amount' => 100]);
PiggyBankRepetition::create(['piggy_bank_id' => $newClothes->id, 'startdate' => $this->som, 'targetdate' => $end, 'currentamount' => 100]);
// weekly reminder piggy bank
$weekly = PiggyBank::create(
[
'account_id' => $savings->id,
'name' => 'Weekly reminder for clothes',
'targetamount' => 2000,
'startdate' => $this->som,
'targetdate' => $next,
'repeats' => 0,
'rep_length' => null,
'rep_every' => 0,
'rep_times' => null,
'reminder' => 'week',
'reminder_skip' => 0,
'remind_me' => 1,
'order' => 0,
]
);
PiggyBankRepetition::create(['piggy_bank_id' => $weekly->id, 'startdate' => $this->som, 'targetdate' => $next, 'currentamount' => 0]);
}
/**
* @param User $user
*/
public function createReminders(User $user)
{
// for weekly piggy bank (clothes)
$nextWeek = clone $this->_startOfMonth;
$piggyBank = PiggyBank::whereName('New clothes')->orderBy('id', 'DESC')->first();
$nextWeek->addWeek();
$week = $nextWeek->format('Y-m-d');
Reminder::create(
['user_id' => $user->id, 'startdate' => $this->som, 'enddate' => $week, 'active' => 1, 'notnow' => 0,
'remindersable_id' => $piggyBank->id, 'remindersable_type' => 'PiggyBank']
);
// a fake reminder::
Reminder::create(
['user_id' => $user->id, 'startdate' => $this->som, 'enddate' => $week, 'active' => 0, 'notnow' => 0, 'remindersable_id' => 40,
'remindersable_type' => 'Transaction']
);
}
/**
* @param User $user
*/
public function createRecurringTransactions(User $user)
{
// account
$savings = Account::whereName('Savings account')->orderBy('id', 'DESC')->first();
$recurring = PiggyBank::create(
[
'account_id' => $savings->id,
'name' => 'Nieuwe spullen',
'targetamount' => 1000,
'startdate' => $this->som,
'targetdate' => $this->eom,
'repeats' => 1,
'rep_length' => 'month',
'rep_every' => 0,
'rep_times' => 0,
'reminder' => 'month',
'reminder_skip' => 0,
'remind_me' => 1,
'order' => 0,
]
);
PiggyBankRepetition::create(['piggy_bank_id' => $recurring->id, 'startdate' => $this->som, 'targetdate' => $this->eom, 'currentamount' => 0]);
PiggyBankRepetition::create(
['piggy_bank_id' => $recurring->id, 'startdate' => $this->nsom, 'targetdate' => $this->neom, 'currentamount' => 0]
);
Reminder::create(
['user_id' => $user->id, 'startdate' => $this->som, 'enddate' => $this->neom, 'active' => 1, 'notnow' => 0,
'remindersable_id' => $recurring->id, 'remindersable_type' => 'PiggyBank']
);
}
/**
* @param $user
*/
public function createBills($user)
{
// bill
Bill::create(
[
'user_id' => $user->id, 'name' => 'Rent', 'match' => 'rent,landlord',
'amount_min' => 700,
'amount_max' => 900,
'date' => $this->som,
'active' => 1,
'automatch' => 1,
'repeat_freq' => 'monthly',
'skip' => 0,
]
);
// bill
Bill::create(
[
'user_id' => $user->id,
'name' => 'Gas licht',
'match' => 'no,match',
'amount_min' => 500,
'amount_max' => 700,
'date' => $this->som,
'active' => 1,
'automatch' => 1,
'repeat_freq' => 'monthly',
'skip' => 0,
]
);
// bill
Bill::create(
[
'user_id' => $user->id,
'name' => 'Something something',
'match' => 'mumble,mumble',
'amount_min' => 500,
'amount_max' => 700,
'date' => $this->som,
'active' => 0,
'automatch' => 1,
'repeat_freq' => 'monthly',
'skip' => 0,
]
);
}
/**
* @param $user
*/
public function createExpenseAccounts($user)
{
//// create expenses for rent, utilities, water, TV, phone on the 1st of the month.
$expenseType = AccountType::whereType('Expense account')->first();
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Land lord', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Utilities company', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Water company', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'TV company', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Phone agency', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Super savers', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Groceries House', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Lunch House', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $expenseType->id, 'name' => 'Buy More', 'active' => 1]);
}
/**
* @param $user
*/
public function createRevenueAccounts($user)
{
$revenueType = AccountType::whereType('Revenue account')->first();
Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'Employer', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'IRS', 'active' => 1]);
Account::create(['user_id' => $user->id, 'account_type_id' => $revenueType->id, 'name' => 'Second job employer', 'active' => 1]);
}
/**
* @param Carbon $date
*/
public function createGroceries(Carbon $date)
{
// variables we need:
$checking = Account::whereName('Checking account')->orderBy('id', 'DESC')->first();
$shopOne = Account::whereName('Groceries House')->orderBy('id', 'DESC')->first();
$shopTwo = Account::whereName('Super savers')->orderBy('id', 'DESC')->first();
$lunchHouse = Account::whereName('Lunch House')->orderBy('id', 'DESC')->first();
$lunch = Category::whereName('Lunch')->orderBy('id', 'DESC')->first();
$daily = Category::whereName('DailyGroceries')->orderBy('id', 'DESC')->first();
$euro = TransactionCurrency::whereCode('EUR')->first();
$withdrawal = TransactionType::whereType('Withdrawal')->first();
$groceries = Budget::whereName('Groceries')->orderBy('id', 'DESC')->first();
$shops = [$shopOne, $shopTwo];
// create groceries and lunch (daily, between 5 and 10 euro).
$mStart = clone $date;
$mEnd = clone $date;
$mEnd->endOfMonth();
while ($mStart <= $mEnd) {
$mFormat = $mStart->format('Y-m-d');
$shop = $shops[rand(0, 1)];
$this->createTransaction($checking, $shop, (rand(500, 1000) / 100), $withdrawal, 'Groceries', $mFormat, $euro, $groceries, $daily);
$this->createTransaction($checking, $lunchHouse, (rand(200, 600) / 100), $withdrawal, 'Lunch', $mFormat, $euro, $groceries, $lunch);
$mStart->addDay();
}
}
/**
* @param $date
*/
public function createBigExpense($date)
{
$date->addDays(12);
$dollar = TransactionCurrency::whereCode('USD')->first();
$checking = Account::whereName('Checking account')->orderBy('id', 'DESC')->first();
$savings = Account::whereName('Savings account')->orderBy('id', 'DESC')->first();
$buyMore = Account::whereName('Buy More')->orderBy('id', 'DESC')->first();
$withdrawal = TransactionType::whereType('Withdrawal')->first();
$transfer = TransactionType::whereType('Transfer')->first();
$user = User::whereEmail('thegrumpydictator@gmail.com')->first();
// create some big expenses, move some money around.
$amount = rand(500, 2000);
$one = $this->createTransaction(
$savings, $checking, $amount, $transfer, 'Money for big expense in ' . $date->format('F Y'), $date->format('Y-m-d'), $dollar
);
$two = $this->createTransaction(
$checking, $buyMore, $amount, $withdrawal, 'Big expense in ' . $date->format('F Y'), $date->format('Y-m-d'), $dollar
);
$group = TransactionGroup::create(
[
'user_id' => $user->id,
'relation' => 'balance'
]
);
$group->transactionjournals()->save($one);
$group->transactionjournals()->save($two);
}
}

View File

@@ -10,9 +10,9 @@ class TransactionCurrencySeeder extends Seeder
{
DB::table('transaction_currencies')->delete();
TransactionCurrency::create(
['code' => 'EUR']
);
TransactionCurrency::create(['code' => 'EUR','name' => 'Euro','symbol' => '&#8364;']);
TransactionCurrency::create(['code' => 'USD','name' => 'US Dollar','symbol' => '$']);
TransactionCurrency::create(['code' => 'HUF','name' => 'Hungarian forint','symbol' => 'Ft']);
}
}
}

View File

@@ -17,4 +17,4 @@ class TransactionTypeSeeder extends Seeder
TransactionType::create(['type' => 'Opening balance']);
}
}
}

View File

@@ -5,12 +5,17 @@
App::before(
function ($request) {
// put IP in session if not already there.
$reminders = [];
if (Auth::check()) {
/** @var \Firefly\Helper\Toolkit\ToolkitInterface $toolkit */
$toolkit = App::make('Firefly\Helper\Toolkit\ToolkitInterface');
$toolkit->getDateRange();
$toolkit->checkImportJobs();
Filter::setSessionDateRange();
Reminders::updateReminders();
Steam::removeEmptyBudgetLimits();
$reminders = Reminders::getReminders();
}
View::share('reminders', $reminders);
}
);
@@ -67,6 +72,7 @@ Route::filter(
if (Auth::check()) {
return Redirect::to('/');
}
return null;
}
);
@@ -88,3 +94,11 @@ Route::filter(
}
}
);
Route::filter(
'allow-register', function () {
if (Config::get('auth.allow_register') !== true) {
return View::make('error')->with('message', 'Not possible');
}
}
);

View File

@@ -1,6 +1,6 @@
<?php
return array(
return [
/*
|--------------------------------------------------------------------------
@@ -17,4 +17,4 @@ return array(
'next' => 'Next &raquo;',
);
];

View File

@@ -1,24 +1,24 @@
<?php
return array(
return [
/*
|--------------------------------------------------------------------------
| Password Reminder Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
/*
|--------------------------------------------------------------------------
| Password Reminder Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
"password" => "Passwords must be at least six characters and match the confirmation.",
"password" => "Passwords must be at least six characters and match the confirmation.",
"user" => "We can't find a user with that e-mail address.",
"user" => "We can't find a user with that e-mail address.",
"token" => "This password reset token is invalid.",
"token" => "This password reset token is invalid.",
"sent" => "Password reminder sent!",
"sent" => "Password reminder sent!",
);
];

View File

@@ -21,12 +21,12 @@ return [
"alpha_num" => "The :attribute may only contain letters and numbers.",
"array" => "The :attribute must be an array.",
"before" => "The :attribute must be a date before :date.",
"between" => array(
"between" => [
"numeric" => "The :attribute must be between :min and :max.",
"file" => "The :attribute must be between :min and :max kilobytes.",
"string" => "The :attribute must be between :min and :max characters.",
"array" => "The :attribute must have between :min and :max items.",
),
],
"confirmed" => "The :attribute confirmation does not match.",
"date" => "The :attribute is not a valid date.",
"date_format" => "The :attribute does not match the format :format.",
@@ -39,19 +39,19 @@ return [
"in" => "The selected :attribute is invalid.",
"integer" => "The :attribute must be an integer.",
"ip" => "The :attribute must be a valid IP address.",
"max" => array(
"max" => [
"numeric" => "The :attribute may not be greater than :max.",
"file" => "The :attribute may not be greater than :max kilobytes.",
"string" => "The :attribute may not be greater than :max characters.",
"array" => "The :attribute may not have more than :max items.",
),
],
"mimes" => "The :attribute must be a file of type: :values.",
"min" => array(
"min" => [
"numeric" => "The :attribute must be at least :min.",
"file" => "The :attribute must be at least :min kilobytes.",
"string" => "The :attribute must be at least :min characters.",
"array" => "The :attribute must have at least :min items.",
),
],
"not_in" => "The selected :attribute is invalid.",
"numeric" => "The :attribute must be a number.",
"regex" => "The :attribute format is invalid.",
@@ -62,12 +62,12 @@ return [
"required_without" => "The :attribute field is required when :values is not present.",
"required_without_all" => "The :attribute field is required when none of :values are present.",
"same" => "The :attribute and :other must match.",
"size" => array(
"size" => [
"numeric" => "The :attribute must be :size.",
"file" => "The :attribute must be :size kilobytes.",
"string" => "The :attribute must be :size characters.",
"array" => "The :attribute must contain :size items.",
),
],
"unique" => "The :attribute has already been taken.",
"url" => "The :attribute format is invalid.",
@@ -82,11 +82,11 @@ return [
|
*/
'custom' => array(
'attribute-name' => array(
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
),
),
],
],
'alphabasic' => 'The :attribute field must consist of basic alphanumeric characters.',
/*
@@ -100,6 +100,6 @@ return [
|
*/
'attributes' => array(),
'attributes' => [],
];

View File

@@ -1,121 +0,0 @@
<?php
namespace Firefly\Database;
use LaravelBook\Ardent\Ardent;
/**
* Class SingleTableInheritanceEntity
*
* @package Firefly\Database
*/
abstract class SingleTableInheritanceEntity extends Ardent
{
/**
* The field that stores the subclass
*
* @var string
*/
protected $subclassField = null;
/**
* must be overridden and set to true in subclasses
*
* @var bool
*/
protected $isSubclass = false;
/**
* @param array $attributes
*
* @return \Illuminate\Database\Eloquent\Model|static
*/
public function newFromBuilder($attributes = [])
{
$instance = $this->mapData((array)$attributes)->newInstance([], true);
$instance->setRawAttributes((array)$attributes, true);
return $instance;
}
/**
* if no subclass is defined, function as normal
*
* @param array $attributes
*
* @return \Illuminate\Database\Eloquent\Model|static
*/
public function mapData(array $attributes)
{
if (!$this->subclassField) {
return $this->newInstance();
}
return new $attributes[$this->subclassField];
}
/**
*
* instead of using $this->newInstance(), call
* newInstance() on the object from mapData
*
* @param bool $excludeDeleted
*
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function newQuery($excludeDeleted = true)
{
// If using Laravel 4.0.x then use the following commented version of this command
// $builder = new Builder($this->newBaseQueryBuilder());
// newEloquentBuilder() was added in 4.1
$builder = $this->newEloquentBuilder($this->newBaseQueryBuilder());
// Once Firefly has the query builders, it will set the model instances so the
// builder can easily access any information it may need from the model
// while it is constructing and executing various queries against it.
$builder->setModel($this)->with($this->with);
if ($excludeDeleted && $this->softDelete) {
$builder->whereNull($this->getQualifiedDeletedAtColumn());
}
if ($this->subclassField && $this->isSubclass()) {
$builder->where($this->subclassField, '=', get_class($this));
}
return $builder;
}
/**
* @return bool
*/
public function isSubclass()
{
return $this->isSubclass;
}
/**
* ensure that the subclass field is assigned on save
*
* @param array $rules
* @param array $customMessages
* @param array $options
* @param callable $beforeSave
* @param callable $afterSave
*
* @return bool
*/
public function save(
array $rules = [],
array $customMessages = [],
array $options = [],
\Closure $beforeSave = null,
\Closure $afterSave = null
) {
if ($this->subclassField) {
$this->attributes[$this->subclassField] = get_class($this);
}
return parent::save($rules, $customMessages, $options, $beforeSave, $afterSave);
}
}

View File

@@ -1,11 +0,0 @@
<?php
namespace Firefly\Exception;
/**
* Class ValidationException
*
* @package Firefly\Exception
*/
class ValidationException extends \Exception {
}

View File

@@ -1,143 +0,0 @@
<?php
namespace Firefly\Helper\Controllers;
/**
* Class Account
*
* @package Firefly\Helper\Controllers
*/
class Account implements AccountInterface
{
/**
* @param \Account $account
* @return \TransactionJournal|null
*/
public function openingBalanceTransaction(\Account $account)
{
return \TransactionJournal::withRelevantData()
->accountIs($account)
->leftJoin('transaction_types', 'transaction_types.id', '=',
'transaction_journals.transaction_type_id')
->where('transaction_types.type', 'Opening balance')
->first(['transaction_journals.*']);
}
/**
* Since it is entirely possible the database is messed up somehow it might be that a transaction
* journal has only one transaction. This is mainly caused by wrong deletions and other artefacts from the past.
*
* If it is the case, Firefly removes $item and continues like nothing ever happened. This will however,
* mess up some statisics but it's decided everybody should learn to live with that.
*
* Firefly might be needing some cleanup routine in the future.
*
* For now, Firefly simply warns the user of this.
*
* @param \Account $account
* @param $perPage
*
* @return array|mixed
* @throws \Firefly\Exception\FireflyException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function show(\Account $account, $perPage)
{
$start = \Session::get('start');
$end = \Session::get('end');
$stats = [
'accounts' => []
];
$items = [];
// build a query:
$query = \TransactionJournal::withRelevantData()
->defaultSorting()
->accountIs($account)
->after($start)
->before($end);
// filter some:
switch (\Input::get('type')) {
case 'transactions':
$query->transactionTypes(['Deposit', 'Withdrawal']);
break;
case 'transfers':
$query->transactionTypes(['Transfer']);
break;
}
switch (\Input::get('show')) {
case 'expenses':
case 'out':
$query->lessThan(0);
break;
case 'income':
case 'in':
$query->moreThan(0);
break;
}
// build paginator:
$totalItems = $query->count();
$page = max(1, intval(\Input::get('page')));
$skip = ($page - 1) * $perPage;
$result = $query->skip($skip)->take($perPage)->get(['transaction_journals.*']);
// get the relevant budgets, categories and accounts from this list:
/** @var $item \TransactionJournal */
foreach ($result as $index => $item) {
foreach ($item->components as $component) {
$stats[$component->class][$component->id] = $component;
}
if (count($item->transactions) < 2) {
\Session::flash('warning', 'Some transactions are incomplete; they will not be shown.');
unset($result[$index]);
continue;
}
$items[] = $item;
$fromAccount = $item->transactions[0]->account;
$toAccount = $item->transactions[1]->account;
$stats['accounts'][$fromAccount->id] = $fromAccount;
$stats['accounts'][$toAccount->id] = $toAccount;
}
$paginator = \Paginator::make($items, $totalItems, $perPage);
unset($result, $page, $item, $fromAccount, $toAccount);
// statistics (transactions)
$trIn = floatval(\Transaction::before($end)->after($start)->accountIs($account)->moreThan(0)
->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount'));
$trOut = floatval(\Transaction::before($end)->after($start)->accountIs($account)->lessThan(0)
->transactionTypes(['Deposit', 'Withdrawal'])->sum('transactions.amount'));
$trDiff = $trIn + $trOut;
// statistics (transfers)
$trfIn = floatval(\Transaction::before($end)->after($start)->accountIs($account)->moreThan(0)
->transactionTypes(['Transfer'])->sum('transactions.amount'));
$trfOut = floatval(\Transaction::before($end)->after($start)->accountIs($account)->lessThan(0)
->transactionTypes(['Transfer'])->sum('transactions.amount'));
$trfDiff = $trfIn + $trfOut;
$stats['period'] = [
'in' => $trIn,
'out' => $trOut,
'diff' => $trDiff,
't_in' => $trfIn,
't_out' => $trfOut,
't_diff' => $trfDiff
];
$return = [
'journals' => $paginator,
'statistics' => $stats
];
return $return;
}
}

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