mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-08-17 11:16:39 +00:00
Compare commits
486 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3e28e9a016 | ||
|
423f9fefa9 | ||
|
5707dc7579 | ||
|
3be1cdb249 | ||
|
426d3d948c | ||
|
9a3aed8038 | ||
|
fb58bf1bf5 | ||
|
a6dbd912c6 | ||
|
65ce277a20 | ||
|
0b2d423c87 | ||
|
da056092fb | ||
|
45aa85d690 | ||
|
5c35fee0c2 | ||
|
24bdc319dd | ||
|
f1dcc41e42 | ||
|
550f301ba2 | ||
|
d9bf4d1c0d | ||
|
c3c1a6eb22 | ||
|
2c4454418e | ||
|
e44de572f5 | ||
|
f27919f91b | ||
|
ba9968bde0 | ||
|
05ea8216ff | ||
|
fa1695672a | ||
|
ac6f98fc47 | ||
|
1a1f89f555 | ||
|
6c3262e176 | ||
|
b4bdb48f1e | ||
|
823afe877b | ||
|
cb8e082414 | ||
|
98c1fcc68f | ||
|
8c439a2852 | ||
|
50c6109be7 | ||
|
6e362663b5 | ||
|
74c9feb53f | ||
|
402e8588cf | ||
|
778a42bcc0 | ||
|
584f7ced84 | ||
|
8e892e7ea5 | ||
|
3386c8b455 | ||
|
6fa73ee28d | ||
|
8ec8042045 | ||
|
cddc123539 | ||
|
4c2938c5cd | ||
|
6d03ddadcc | ||
|
64311da4b4 | ||
|
0cbb50ae9d | ||
|
7e96054dc2 | ||
|
578298580e | ||
|
ee5afaa6bc | ||
|
15b023d116 | ||
|
1ef96c0b4d | ||
|
8c3ae40de1 | ||
|
94fcfacec4 | ||
|
ba7c01c6bc | ||
|
9f92e1b7bd | ||
|
1f0e692ee2 | ||
|
0acd75a24f | ||
|
eedf27f8a5 | ||
|
b451e207e2 | ||
|
c0c37eec7b | ||
|
89363ecfa3 | ||
|
593e799ca1 | ||
|
8fc055cad9 | ||
|
75f86462e2 | ||
|
40892ccfa7 | ||
|
87fbf9c1a5 | ||
|
4944b233b6 | ||
|
9f23462c42 | ||
|
84a24f0333 | ||
|
7a885bfc3c | ||
|
3ba0cf1454 | ||
|
2d67a3159d | ||
|
290f25f1a0 | ||
|
1659904f81 | ||
|
230bd6e40a | ||
|
ce27e97b92 | ||
|
18c1223c7b | ||
|
8ef659f5de | ||
|
037452e525 | ||
|
e3482011d5 | ||
|
62748fa255 | ||
|
7a9df05f6b | ||
|
335279e728 | ||
|
0332104738 | ||
|
9f04854902 | ||
|
73008a35fe | ||
|
eae96cd2af | ||
|
cb670bb27d | ||
|
fe1fb23e5b | ||
|
c2dd61e96b | ||
|
80f5e61b6b | ||
|
dbcae16b75 | ||
|
886dcae822 | ||
|
ed495ec600 | ||
|
ddb60ccdc5 | ||
|
335e2083af | ||
|
7b1d9d4962 | ||
|
da6ff9f90a | ||
|
48f26c7bf1 | ||
|
3ce317b170 | ||
|
b741565f57 | ||
|
d8fea44968 | ||
|
778300b67e | ||
|
cb2b44fef3 | ||
|
cdb5875d6b | ||
|
01c5e15bcd | ||
|
f0babb4be7 | ||
|
10b00da874 | ||
|
e9f391b2eb | ||
|
50be39b054 | ||
|
a94e0bb3da | ||
|
3f65d5d760 | ||
|
48cb528ae4 | ||
|
e62e0345df | ||
|
441f011fba | ||
|
af1349160a | ||
|
2072607889 | ||
|
073fd5aa0d | ||
|
7b4703e4ff | ||
|
1484621300 | ||
|
40709c8367 | ||
|
b6ab5770a2 | ||
|
83b7cb4ff9 | ||
|
256dba66b2 | ||
|
6ac12f8ffa | ||
|
82e438d29b | ||
|
e86547645c | ||
|
8b901084fe | ||
|
1a0cbbdb31 | ||
|
30ac62ffb7 | ||
|
8ab294e90b | ||
|
f5edb15f43 | ||
|
eed6107ce7 | ||
|
d49dc599a2 | ||
|
3c5179f145 | ||
|
067d17c09c | ||
|
4c88c9af86 | ||
|
1c84afe186 | ||
|
9d4c4be468 | ||
|
de7db8db78 | ||
|
407ba4dd6d | ||
|
5135be3000 | ||
|
b8ab7d1a14 | ||
|
6211fd8496 | ||
|
a4f273b48b | ||
|
68d820a97c | ||
|
ebadfd6358 | ||
|
cf93a88adc | ||
|
bd2c4252bb | ||
|
84e7af04b9 | ||
|
37c63bc6b5 | ||
|
e7d3716549 | ||
|
73bc5372c0 | ||
|
b999a8f0fb | ||
|
16678aa5e1 | ||
|
f9ab49911d | ||
|
3fabe2e9fb | ||
|
9a8a3e94d6 | ||
|
32ef2ef801 | ||
|
76cd3d35e2 | ||
|
900dea2c66 | ||
|
8e6ca0dd05 | ||
|
4b4ad7f1a8 | ||
|
21a0a5d573 | ||
|
3cfa3f3b27 | ||
|
c77b43458e | ||
|
9ab0a83f7c | ||
|
d3cda8811d | ||
|
55740c0d97 | ||
|
c0a524c8a3 | ||
|
e51c2d10f0 | ||
|
7af55b7268 | ||
|
7350b1da1b | ||
|
136adbe723 | ||
|
cb2863eaf3 | ||
|
d054f9b92f | ||
|
9c83c18137 | ||
|
999a7481e4 | ||
|
a3b684b4ed | ||
|
cb312ca025 | ||
|
1335a52db3 | ||
|
727221e2cb | ||
|
360f286ed3 | ||
|
6aecd77b77 | ||
|
ca85cab6fb | ||
|
742479bb01 | ||
|
68e54a9297 | ||
|
056d83eda4 | ||
|
42ec55d0db | ||
|
c89bd89d9a | ||
|
31a0be5bb4 | ||
|
07610ae8fb | ||
|
dbc95dd878 | ||
|
792e8a9947 | ||
|
d774cde109 | ||
|
cc111d14b0 | ||
|
bb3ba42ce2 | ||
|
f4ecf2d1aa | ||
|
1997666196 | ||
|
3aa9057c5f | ||
|
834f8382e9 | ||
|
357638a26c | ||
|
919a0c01e4 | ||
|
6ff618e388 | ||
|
ac765b7e4c | ||
|
2134e87c31 | ||
|
0d37288129 | ||
|
7cbd41137d | ||
|
ba43d7063f | ||
|
c9b2e29ba0 | ||
|
4720519aef | ||
|
d7b0106e7d | ||
|
0a2cbaa047 | ||
|
3e5f615ffc | ||
|
00dc73e6d9 | ||
|
aa5b9a1727 | ||
|
f63a287a6c | ||
|
b9d4c8dcd6 | ||
|
94433f1714 | ||
|
a4dd4358b4 | ||
|
4e79b43395 | ||
|
6bb54bfa85 | ||
|
0df6c3a8dc | ||
|
dc25086eab | ||
|
3299188edf | ||
|
f6afb46f6f | ||
|
98993cfa9b | ||
|
5a920d5efd | ||
|
935276af88 | ||
|
5a505c8469 | ||
|
2c2abe8b8e | ||
|
638099d989 | ||
|
0f32f6be4c | ||
|
1f7c98bdcf | ||
|
72068a4b78 | ||
|
c8038e0774 | ||
|
6b39beecb4 | ||
|
b1ba64db12 | ||
|
ad53832766 | ||
|
d5bffc8ed7 | ||
|
69b36ddd1d | ||
|
9f926394a6 | ||
|
1e7ecbdf9d | ||
|
beb8a461cf | ||
|
e235a57e2f | ||
|
114b27079e | ||
|
6e19bc01f5 | ||
|
f9dfdeafb3 | ||
|
f05d626e38 | ||
|
918041258e | ||
|
a5b13aa67f | ||
|
1383cbd4d5 | ||
|
e9b7e82aea | ||
|
fd6e7fc1ab | ||
|
743deb4227 | ||
|
b051278d2e | ||
|
bfda4bc199 | ||
|
4456ef2326 | ||
|
7336367eff | ||
|
9cb6c7697e | ||
|
cd44f51072 | ||
|
d8976379b1 | ||
|
8aa847c718 | ||
|
6691b238f7 | ||
|
cca2758138 | ||
|
4a74e68e31 | ||
|
3d3842b9d6 | ||
|
9d889d05e4 | ||
|
9f920bcfe3 | ||
|
1bb49fa496 | ||
|
6b1d8d3aaa | ||
|
c6b6ed7fa8 | ||
|
34454261d2 | ||
|
ddf9f52737 | ||
|
10b969a074 | ||
|
5df0634380 | ||
|
f0f965421c | ||
|
6381408fba | ||
|
43e738cb44 | ||
|
6d4303aa3f | ||
|
13c2db5378 | ||
|
36f6bda525 | ||
|
78886e7b1f | ||
|
3dce194930 | ||
|
ec776bb6eb | ||
|
243d942a6e | ||
|
ea6aba62c4 | ||
|
73743721b1 | ||
|
61eb5b341d | ||
|
d758f72393 | ||
|
1b1367f4c2 | ||
|
07388dd58a | ||
|
359c71ef2f | ||
|
93d4d3df1d | ||
|
d3a7596be2 | ||
|
114d3812cc | ||
|
b2d4dcfbf1 | ||
|
0baf8f6d18 | ||
|
2f8e3a0707 | ||
|
d7a4bf22c6 | ||
|
0c2f9d22b9 | ||
|
e75c5aac49 | ||
|
77e5024f54 | ||
|
7329c0b200 | ||
|
0afe3c48a1 | ||
|
1ab5e923bc | ||
|
90b3bd77e7 | ||
|
9c60443f97 | ||
|
058e5602a3 | ||
|
eebac2a66d | ||
|
7e8f5c9548 | ||
|
d34b49bd48 | ||
|
ccffae287d | ||
|
ad69011ac5 | ||
|
f8ea0f971d | ||
|
9918410954 | ||
|
4f4e6fac16 | ||
|
15e99bd672 | ||
|
696e9a6fde | ||
|
36cbb3d71f | ||
|
f69598c6aa | ||
|
5fc31f3c1e | ||
|
6581ee0ee0 | ||
|
69e7501d47 | ||
|
314abbea8b | ||
|
82c9a75578 | ||
|
651101912c | ||
|
fb0d463040 | ||
|
8c254554eb | ||
|
2d9c89375a | ||
|
61aba29df7 | ||
|
8c949e6190 | ||
|
6eb9188690 | ||
|
6832f2ebd0 | ||
|
3e02b50ea1 | ||
|
7b7743c03e | ||
|
de20563275 | ||
|
9e720c3a38 | ||
|
54685c1f5f | ||
|
eb8f8fa935 | ||
|
9adbbd872c | ||
|
4bd38f97a2 | ||
|
78ab1e200a | ||
|
11280e473d | ||
|
f9750a64f8 | ||
|
ac2ab65471 | ||
|
0530c0402c | ||
|
a58a560bbb | ||
|
96ab112b22 | ||
|
b388dcc7d4 | ||
|
f511a25c94 | ||
|
58d8b6f95b | ||
|
953d68c3a2 | ||
|
9e2f7af59b | ||
|
840dfa6696 | ||
|
4a20c008ff | ||
|
981ffe4194 | ||
|
2597633b0e | ||
|
71d174d765 | ||
|
4aa9a04516 | ||
|
258d6a1688 | ||
|
2e2c12d6a4 | ||
|
44d189d7d3 | ||
|
ab508a3d9e | ||
|
4e166c7d2e | ||
|
7f175a4870 | ||
|
0a627f6f9e | ||
|
d34cc65984 | ||
|
78d034d366 | ||
|
638fa9005f | ||
|
5cb9907bf8 | ||
|
f08fcc36fb | ||
|
d231cd9f61 | ||
|
86a586f866 | ||
|
9d4cba1620 | ||
|
e9afd55e9d | ||
|
9fa326f630 | ||
|
af9473c126 | ||
|
cb08df0770 | ||
|
d49ca2eb11 | ||
|
a3f8841ec3 | ||
|
fd678c286d | ||
|
2a3f9b621b | ||
|
359e1b3943 | ||
|
754336b3cf | ||
|
4918f1c4cb | ||
|
5d5e308942 | ||
|
6a18f81cec | ||
|
1ff135d172 | ||
|
e666e5e9e3 | ||
|
9874e77ddf | ||
|
27e3ec693a | ||
|
6bb1415ad7 | ||
|
83594e6f1f | ||
|
0f6008705c | ||
|
c58b653bb7 | ||
|
f69b6f9b4e | ||
|
7750b06476 | ||
|
873384a34b | ||
|
ac299e7279 | ||
|
7895d7f5d0 | ||
|
fe05d218fc | ||
|
8196313ac0 | ||
|
6d8f84654f | ||
|
ab4f34a96b | ||
|
139d985904 | ||
|
44705f0e18 | ||
|
ddea7d696a | ||
|
f814f45e36 | ||
|
f7117d47c2 | ||
|
01b0a1058d | ||
|
21f362c7b9 | ||
|
aaab7f8e0e | ||
|
09e1f68c69 | ||
|
03729aa5ae | ||
|
ef39f31ea1 | ||
|
0f1437dd6a | ||
|
03aac2f744 | ||
|
2f8b10e82c | ||
|
3231effd20 | ||
|
f7722c1189 | ||
|
70c2450ac4 | ||
|
2d5b0d0f99 | ||
|
f0c0002a6d | ||
|
dd9f08d4fa | ||
|
de2e384225 | ||
|
ffcd1fde0f | ||
|
d5e1da5948 | ||
|
ad479a5c7f | ||
|
0707603b63 | ||
|
2f9c383004 | ||
|
8ad0d7af93 | ||
|
9b4391c0bf | ||
|
da7802a0a4 | ||
|
9c69949e8c | ||
|
b1d7a9451a | ||
|
004488d453 | ||
|
fc91372dd0 | ||
|
5970a9dc91 | ||
|
264cac4f9b | ||
|
633328a965 | ||
|
4d4b62a766 | ||
|
aeb2c7deeb | ||
|
c323942d92 | ||
|
a0afa25145 | ||
|
4533b46436 | ||
|
e5f8db78f9 | ||
|
899f61671f | ||
|
d84d88cc10 | ||
|
97e7ac4052 | ||
|
ba4ffa44d2 | ||
|
07caeccf68 | ||
|
d54832f61f | ||
|
b212753633 | ||
|
f38d80cbf5 | ||
|
8bea1acd8e | ||
|
42458ce11d | ||
|
aceb683d07 | ||
|
b7517b49ed | ||
|
849b711b79 | ||
|
25585b28c7 | ||
|
073da8fb2a | ||
|
a787ff3f3c | ||
|
733b6d7eb7 | ||
|
36d8dee853 | ||
|
65a2e07d24 | ||
|
7c97c558ab | ||
|
a6bb61050c | ||
|
b184aa2315 | ||
|
e4595333e7 | ||
|
41dd139bde | ||
|
c577dd302a | ||
|
0ab87de78b | ||
|
8a22509b41 | ||
|
b024c18441 | ||
|
d9ac681a68 | ||
|
637a5579ec | ||
|
4794156e80 | ||
|
5f4db7874c | ||
|
b4ea1839a5 | ||
|
6a6d889983 | ||
|
287c2e7af8 | ||
|
0fe6acc8cf | ||
|
7d2dab7ca0 | ||
|
f68c1aff26 |
@@ -1 +1,3 @@
|
||||
src_dir: .
|
||||
coverage_clover: tests/_output/coverage.xml
|
||||
json_path: tests/_output/coveralls-upload.json
|
||||
|
15
.gitignore
vendored
15
.gitignore
vendored
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
38
README.md
38
README.md
@@ -1,34 +1,39 @@
|
||||
firefly-iii
|
||||
Firefly III
|
||||
===========
|
||||
|
||||
[](https://travis-ci.org/JC5/firefly-iii)
|
||||

|
||||
[](https://travis-ci.org/JC5/firefly-iii)
|
||||
[](http://stillmaintained.com/JC5/firefly-iii)
|
||||
[](https://coveralls.io/r/JC5/firefly-iii?branch=master)
|
||||
[](https://insight.sensiolabs.com/projects/d44c7012-5f50-41ad-add8-8445330e4102)
|
||||
|
||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
||||
[](https://packagist.org/packages/grumpydictator/firefly-iii)
|
||||
[](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.
|
||||
|
||||
## Changes
|
||||
@@ -40,10 +45,9 @@ Firefly III will feature, but does not feature yet:
|
||||
- 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 +55,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
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 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)!
|
||||
|
@@ -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
76
app/commands/Cleanup.php
Normal 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],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
3
app/config/.gitignore
vendored
3
app/config/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
local/
|
||||
laptop/
|
||||
vagrant/
|
||||
vagrant/
|
||||
production/
|
||||
|
@@ -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'
|
||||
|
||||
],
|
||||
|
||||
|
@@ -1,3 +1,3 @@
|
||||
<?php
|
||||
|
||||
return [];
|
||||
return [];
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
return [
|
||||
'import' => ''
|
||||
];
|
||||
];
|
||||
|
@@ -1,11 +1,15 @@
|
||||
<?php
|
||||
use Carbon\Carbon;
|
||||
|
||||
return [
|
||||
'index_periods' => ['1D', '1W', '1M', '3M', '6M', '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,7 +30,15 @@ return [
|
||||
'6M' => 'half year',
|
||||
'custom' => '(custom)'
|
||||
],
|
||||
'range_to_repeat_freq' => [
|
||||
'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' => [
|
||||
'1D' => 'weekly',
|
||||
'1W' => 'weekly',
|
||||
'1M' => 'monthly',
|
||||
@@ -29,4 +46,4 @@ return [
|
||||
'6M' => 'half-year',
|
||||
'custom' => 'monthly'
|
||||
],
|
||||
];
|
||||
];
|
||||
|
15
app/config/homestead/app.php
Normal file
15
app/config/homestead/app.php
Normal 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',
|
||||
];
|
12
app/config/homestead/cache.php
Normal file
12
app/config/homestead/cache.php
Normal 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',
|
||||
];
|
37
app/config/homestead/database.php
Normal file
37
app/config/homestead/database.php
Normal 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',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
13
app/config/homestead/mail.php
Normal file
13
app/config/homestead/mail.php
Normal 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,
|
||||
];
|
@@ -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,
|
||||
|
||||
);
|
||||
];
|
||||
|
@@ -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',
|
||||
)
|
||||
)
|
||||
]
|
||||
]
|
||||
|
||||
);
|
||||
|
||||
];
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
return [
|
||||
'view' => 'laravel-breadcrumbs::bootstrap3',
|
||||
);
|
||||
];
|
||||
|
@@ -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' => [],
|
||||
|
||||
];
|
@@ -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
0
app/config/queue.php
Executable file → Normal file
2
app/config/testing/app.php
Normal file
2
app/config/testing/app.php
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
return ['log_level' => 'debug',];
|
@@ -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',];
|
||||
|
@@ -4,8 +4,9 @@ return [
|
||||
'connections' => [
|
||||
'sqlite' => [
|
||||
'driver' => 'sqlite',
|
||||
'database' => ':memory:',
|
||||
'database' => realpath(__DIR__.'/../../../tests/_data/db.sqlite'),
|
||||
'prefix' => ''
|
||||
],
|
||||
]
|
||||
|
||||
]
|
||||
];
|
||||
];
|
||||
|
13
app/config/testing/mail.php
Normal file
13
app/config/testing/mail.php
Normal 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,
|
||||
];
|
@@ -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',];
|
||||
|
2
app/config/testingInMemory/app.php
Normal file
2
app/config/testingInMemory/app.php
Normal file
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
return ['log_level' => 'debug',];
|
8
app/config/testingInMemory/auth.php
Normal file
8
app/config/testingInMemory/auth.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'verify_mail' => false,
|
||||
'verify_reset' => true,
|
||||
'allow_register' => true
|
||||
|
||||
];
|
3
app/config/testingInMemory/cache.php
Normal file
3
app/config/testingInMemory/cache.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
return ['driver' => 'array',];
|
12
app/config/testingInMemory/database.php
Normal file
12
app/config/testingInMemory/database.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
return [
|
||||
'default' => 'sqlite',
|
||||
'connections' => [
|
||||
'sqlite' => [
|
||||
'driver' => 'sqlite',
|
||||
'database' => ':memory:',
|
||||
'prefix' => ''
|
||||
]
|
||||
|
||||
]
|
||||
];
|
13
app/config/testingInMemory/mail.php
Normal file
13
app/config/testingInMemory/mail.php
Normal 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,
|
||||
];
|
3
app/config/testingInMemory/session.php
Normal file
3
app/config/testingInMemory/session.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
return ['driver' => 'array',];
|
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'paths' => array(__DIR__ . '/../views'),
|
||||
'paths' => [__DIR__ . '/../views'],
|
||||
'pagination' => 'pagination::slider-3',
|
||||
];
|
||||
|
@@ -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']);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
212
app/controllers/BillController.php
Normal file
212
app/controllers/BillController.php
Normal 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']);
|
||||
|
||||
}
|
||||
}
|
@@ -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,118 +91,105 @@ 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);
|
||||
// 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()));
|
||||
}
|
||||
);
|
||||
|
||||
return View::make('budgets.indexByDate')->with('budgets', $budgets)
|
||||
->with('subTitle', 'Grouped by date');
|
||||
$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;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public function show(Budget $budget, \LimitRepetition $repetition = null)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
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.index', compact('budgetMaximum', 'budgets', 'spent', 'spentPCT', 'overspent', 'amount'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
@@ -229,23 +197,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);
|
||||
}
|
||||
}
|
||||
|
@@ -1,28 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Firefly\Helper\Controllers\CategoryInterface as CI;
|
||||
use Firefly\Storage\Category\CategoryRepositoryInterface as CRI;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,8 +41,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 +51,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 +65,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 +75,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 +85,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']);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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));
|
||||
|
||||
|
||||
}
|
||||
}
|
197
app/controllers/CurrencyController.php
Normal file
197
app/controllers/CurrencyController.php
Normal 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']);
|
||||
|
||||
}
|
||||
|
||||
}
|
488
app/controllers/GoogleChartController.php
Normal file
488
app/controllers/GoogleChartController.php
Normal 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->transactionsWithoutBudgetInDateRange($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());
|
||||
|
||||
}
|
||||
}
|
54
app/controllers/HelpController.php
Normal file
54
app/controllers/HelpController.php
Normal 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]);
|
||||
|
||||
}
|
||||
}
|
@@ -1,64 +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');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
@@ -74,34 +22,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('/');
|
||||
}
|
||||
}
|
||||
|
@@ -1,26 +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.
|
||||
@@ -29,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) {
|
||||
@@ -49,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;
|
||||
@@ -62,78 +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 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;
|
||||
@@ -142,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,404 +1,354 @@
|
||||
<?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;
|
||||
|
||||
|
||||
// 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']);
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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()
|
||||
// );
|
||||
// }
|
||||
}
|
||||
}
|
139
app/controllers/RelatedController.php
Normal file
139
app/controllers/RelatedController.php
Normal 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());
|
||||
}
|
||||
|
||||
}
|
@@ -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'));
|
||||
}
|
||||
|
||||
}
|
||||
|
227
app/controllers/RepeatedExpenseController.php
Normal file
227
app/controllers/RepeatedExpenseController.php
Normal 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']);
|
||||
|
||||
}
|
||||
}
|
@@ -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')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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']);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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!');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
|
||||
}
|
||||
);
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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');
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
@@ -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');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
@@ -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');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@@ -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']);
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -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');
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
494
app/database/migrations/2014_12_13_190730_changes_for_v321.php
Normal file
494
app/database/migrations/2014_12_13_190730_changes_for_v321.php
Normal 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` = "€", `name` = "Euro" WHERE `code` = "EUR";');
|
||||
}
|
||||
|
||||
|
||||
}
|
168
app/database/migrations/2014_12_24_191544_changes_for_v322.php
Normal file
168
app/database/migrations/2014_12_24_191544_changes_for_v322.php
Normal 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');
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -38,4 +38,4 @@ class AccountTypeSeeder extends Seeder
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ class DatabaseSeeder extends Seeder
|
||||
$this->call('TransactionCurrencySeeder');
|
||||
$this->call('TransactionTypeSeeder');
|
||||
$this->call('DefaultUserSeeder');
|
||||
$this->call('TestContentSeeder');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
561
app/database/seeds/TestContentSeeder.php
Normal file
561
app/database/seeds/TestContentSeeder.php
Normal 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);
|
||||
}
|
||||
}
|
@@ -10,9 +10,9 @@ class TransactionCurrencySeeder extends Seeder
|
||||
{
|
||||
DB::table('transaction_currencies')->delete();
|
||||
|
||||
TransactionCurrency::create(
|
||||
['code' => 'EUR']
|
||||
);
|
||||
TransactionCurrency::create(['code' => 'EUR','name' => 'Euro','symbol' => '€']);
|
||||
TransactionCurrency::create(['code' => 'USD','name' => 'US Dollar','symbol' => '$']);
|
||||
TransactionCurrency::create(['code' => 'HUF','name' => 'Hungarian forint','symbol' => 'Ft']);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -17,4 +17,4 @@ class TransactionTypeSeeder extends Seeder
|
||||
TransactionType::create(['type' => 'Opening balance']);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -17,4 +17,4 @@ return array(
|
||||
|
||||
'next' => 'Next »',
|
||||
|
||||
);
|
||||
];
|
||||
|
@@ -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!",
|
||||
|
||||
);
|
||||
];
|
||||
|
@@ -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' => [],
|
||||
|
||||
];
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
namespace Firefly\Exception;
|
||||
|
||||
/**
|
||||
* Class ValidationException
|
||||
*
|
||||
* @package Firefly\Exception
|
||||
*/
|
||||
class ValidationException extends \Exception {
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Firefly\Helper\Controllers;
|
||||
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
/**
|
||||
* Interface AccountInterface
|
||||
*
|
||||
* @package Firefly\Helper\Controllers
|
||||
*/
|
||||
interface AccountInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function openingBalanceTransaction(\Account $account);
|
||||
|
||||
/**
|
||||
* @param \Account $account
|
||||
* @param $perPage
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function show(\Account $account, $perPage);
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user