Compare commits

..

755 Commits
4.3.2 ... 4.3.8

Author SHA1 Message Date
James Cole
970ce917b0 Merge branch 'release/4.3.8' 2017-04-08 17:54:10 +02:00
James Cole
db46d450bf New files for new release. 2017-04-08 17:51:34 +02:00
James Cole
db806b92dd Merge pull request #618 from firefly-iii/l10n_develop
New Crowdin translations
2017-04-08 10:20:55 +02:00
James Cole
6765f08b07 Fixed some tests. [skip ci] 2017-04-08 10:20:34 +02:00
James Cole
99d75ba14b New translations firefly.php (Dutch) 2017-04-08 10:10:23 +02:00
James Cole
0e8ce5680c New translations firefly.php (Dutch) 2017-04-08 10:00:17 +02:00
James Cole
fd01b54a14 Code for charts #628 [skip ci] 2017-04-08 09:18:04 +02:00
James Cole
ce6253bbd7 New translations firefly.php (Dutch) 2017-04-08 09:10:16 +02:00
James Cole
4fd33f19c6 Experimental code for #628 2017-04-08 09:00:37 +02:00
James Cole
01ae278f09 Float > intval. [skip ci] 2017-04-08 08:53:53 +02:00
James Cole
7907c71e47 Code to verify issue #620 2017-04-08 07:00:51 +02:00
James Cole
4e44733dcc Updated code for #624 2017-04-08 06:51:16 +02:00
James Cole
dd1d7bb02a Should fix issue #624 2017-04-01 08:56:39 +02:00
James Cole
6f933b3bd1 Small updates. 2017-04-01 08:13:43 +02:00
James Cole
243530b750 Forgot a return value. 2017-03-30 18:43:12 +02:00
James Cole
ea984281b0 Should fix tests. 2017-03-30 18:42:02 +02:00
James Cole
92cd3d60b9 Forgot two files. 2017-03-29 21:21:10 +02:00
James Cole
5920ccee04 Various code cleanup. 2017-03-29 21:20:54 +02:00
James Cole
569fec4610 Double check on NULL. [skip ci] 2017-03-25 22:07:07 +01:00
James Cole
5770edcde2 Expanded test coverage. 2017-03-25 13:41:17 +01:00
James Cole
1fb0a64f31 Various code cleanup [skip ci] 2017-03-24 15:15:12 +01:00
James Cole
fe66d089ad Expanded test coverage. 2017-03-24 15:01:53 +01:00
James Cole
cef10b4d4e New translations firefly.php (French) 2017-03-24 11:12:14 +01:00
James Cole
b45aa6446d New translations firefly.php (Chinese Traditional) 2017-03-24 11:11:56 +01:00
James Cole
61749312b2 New translations firefly.php (Croatian) 2017-03-24 11:11:48 +01:00
James Cole
842bb2c5a6 New translations firefly.php (Chinese Traditional, Hong Kong) 2017-03-24 11:11:40 +01:00
James Cole
4358fe99b1 New translations firefly.php (Russian) 2017-03-24 11:11:25 +01:00
James Cole
3fda8b3714 New translations firefly.php (Dutch) 2017-03-24 11:11:13 +01:00
James Cole
09f3274adc New translations firefly.php (Spanish) 2017-03-24 11:11:04 +01:00
James Cole
029224f708 New translations firefly.php (Polish) 2017-03-24 11:10:52 +01:00
James Cole
e87cce12f8 New translations firefly.php (German) 2017-03-24 11:10:43 +01:00
James Cole
7660667153 New translations firefly.php (Portuguese, Brazilian) 2017-03-24 11:10:33 +01:00
James Cole
222b3008d5 Expanded test coverage. 2017-03-24 11:07:38 +01:00
James Cole
398cf0b312 Small improvements in the search [skip ci] 2017-03-24 07:17:38 +01:00
James Cole
5ad8be2483 This fixes the tests 2017-03-22 17:37:34 +01:00
James Cole
6fe319702d Expand test coverage. Remove else-statement. 2017-03-22 17:02:15 +01:00
James Cole
32c89f9a98 Expand category view. 2017-03-22 17:00:01 +01:00
James Cole
64f983786e New translations firefly.php (French) 2017-03-22 01:20:18 +01:00
James Cole
16438b416d New translations list.php (French) 2017-03-22 01:10:26 +01:00
James Cole
52cd292a69 New translations form.php (French) 2017-03-22 01:10:24 +01:00
James Cole
53b501df19 New translations firefly.php (French) 2017-03-22 01:10:23 +01:00
James Cole
477acafc4c Improve test coverage. 2017-03-21 20:46:14 +01:00
James Cole
ab9146b7c6 Update README.md
New badge
2017-03-21 14:24:10 +01:00
James Cole
4d15913e18 New translations csv.php (French) 2017-03-21 13:50:24 +01:00
James Cole
63a91811e2 New translations firefly.php (French) 2017-03-21 13:50:23 +01:00
James Cole
9df4da6173 New translations validation.php (French) 2017-03-21 13:50:14 +01:00
James Cole
643927799b New translations demo.php (French) 2017-03-21 11:50:25 +01:00
James Cole
2652e23089 New translations firefly.php (French) 2017-03-21 11:50:23 +01:00
James Cole
b70c5ae41e New translations demo.php (French) 2017-03-21 10:11:17 +01:00
James Cole
c53d9b2855 New translations demo.php (French) 2017-03-21 10:00:35 +01:00
James Cole
2f6712be87 New translations config.php (French) 2017-03-21 09:50:13 +01:00
James Cole
37f78985ae Update AccountController.php 2017-03-21 08:17:27 +01:00
James Cole
34ac9bc71a Update AccountController.php 2017-03-21 08:15:21 +01:00
James Cole
19ff2484fd Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop
* 'develop' of https://github.com/firefly-iii/firefly-iii:
  Changed to get relative path and not absolute path
2017-03-21 06:29:38 +01:00
James Cole
b7ef2211d9 Include Firefly version in error mail [skip ci] 2017-03-21 06:28:06 +01:00
James Cole
c5206a4559 Merge pull request #623 from welbert/develop
Changed to get relative path and not absolute path
2017-03-20 20:29:01 +01:00
Welbert Serra
894296f63d Changed to get relative path and not absolute path
If you access with absolute path, favicon don't appear on site and the [progressive webApp](https://developers.google.com/web/progressive-web-apps/) is not correctly generate. Get 404 error
2017-03-19 17:51:32 -03:00
James Cole
61526df245 Make dir where json log will end up. 2017-03-19 20:39:27 +01:00
James Cole
92549c4485 No more script removal. 2017-03-19 18:01:09 +01:00
James Cole
6014892d4d New database and new test script. 2017-03-19 17:58:07 +01:00
James Cole
9515ce6807 Expand tests. 2017-03-19 17:54:21 +01:00
James Cole
1adb0f2f0e Improve test coverage. 2017-03-18 20:53:44 +01:00
James Cole
00b1b54347 New test database. 2017-03-18 11:02:21 +01:00
James Cole
282ce041e1 Code cleanup for #595 2017-03-18 11:02:02 +01:00
James Cole
3215c4ee4b Expand code and some refactoring for #595 2017-03-18 08:09:14 +01:00
James Cole
fce00c95c9 New translations firefly.php (French) 2017-03-18 07:51:13 +01:00
James Cole
0a69ab1dc2 New translations firefly.php (Chinese Traditional) 2017-03-18 07:51:05 +01:00
James Cole
94771d250a New translations firefly.php (Croatian) 2017-03-18 07:50:59 +01:00
James Cole
b8395a1dbb New translations firefly.php (Chinese Traditional, Hong Kong) 2017-03-18 07:50:54 +01:00
James Cole
0436cd1584 New translations firefly.php (Russian) 2017-03-18 07:50:44 +01:00
James Cole
2c774bb94c New translations firefly.php (Dutch) 2017-03-18 07:50:39 +01:00
James Cole
b879d90b0d New translations firefly.php (Spanish) 2017-03-18 07:50:35 +01:00
James Cole
ba52b5c328 New translations firefly.php (German) 2017-03-18 07:50:27 +01:00
James Cole
bf61de13f4 New translations firefly.php (Polish) 2017-03-18 07:50:22 +01:00
James Cole
b26e67ae07 New translations firefly.php (Portuguese, Brazilian) 2017-03-18 07:50:19 +01:00
James Cole
edafd16c75 Bread crumbs for #595 2017-03-18 07:46:57 +01:00
James Cole
c62e3dcb78 Code for #595 2017-03-18 07:46:42 +01:00
James Cole
68be58c9f2 Line chart 2017-03-18 07:46:14 +01:00
James Cole
a25a499ed4 Code cleanup 2017-03-18 07:45:52 +01:00
James Cole
97f67912f4 Remove logging 2017-03-18 07:45:40 +01:00
James Cole
e2f3788ff5 Expand tests. 2017-03-17 16:34:57 +01:00
James Cole
fd1f06c2cb Small fix. 2017-03-16 21:00:34 +01:00
James Cole
2db8d25038 This should fix tests 2017-03-16 20:46:18 +01:00
James Cole
d618ddc8c5 Lot of debug info for #619 2017-03-16 17:52:13 +01:00
James Cole
79aa0afc97 Possible fix for #619 2017-03-15 20:09:36 +01:00
James Cole
e53d294c1c Expand tests. 2017-03-12 21:24:34 +01:00
James Cole
aedc3fdff9 Fix #620 2017-03-12 20:43:37 +01:00
James Cole
b67dfeced2 Expand tests. 2017-03-12 09:22:33 +01:00
James Cole
65dbfcba5c Expand tests. 2017-03-12 08:38:13 +01:00
James Cole
8f14c78ba1 Expand some tests. 2017-03-11 22:28:51 +01:00
James Cole
be1b64bb78 New translations demo.php (French) 2017-03-11 12:10:17 +01:00
James Cole
a34c285820 New translations demo.php (French) 2017-03-11 12:00:19 +01:00
James Cole
298f0c194d New translations firefly.php (French) 2017-03-11 08:01:29 +01:00
James Cole
f5ad569aba New translations firefly.php (Chinese Traditional) 2017-03-11 08:01:20 +01:00
James Cole
c70df01532 New translations firefly.php (Croatian) 2017-03-11 08:01:13 +01:00
James Cole
03e115e066 New translations firefly.php (Chinese Traditional, Hong Kong) 2017-03-11 08:01:08 +01:00
James Cole
b88fce35ad New translations firefly.php (Russian) 2017-03-11 08:00:56 +01:00
James Cole
d214e9ff49 New translations firefly.php (Dutch) 2017-03-11 08:00:50 +01:00
James Cole
bd8382c005 New translations firefly.php (Spanish) 2017-03-11 08:00:45 +01:00
James Cole
18cb815e45 New translations firefly.php (German) 2017-03-11 08:00:34 +01:00
James Cole
800e8aca6e New translations firefly.php (Polish) 2017-03-11 08:00:27 +01:00
James Cole
63a6e0754b New translations firefly.php (Portuguese, Brazilian) 2017-03-11 08:00:23 +01:00
James Cole
4abc271805 Implemented #595 for transactions. 2017-03-11 07:41:26 +01:00
James Cole
22cca3858c New translations firefly.php (French) 2017-03-10 19:41:27 +01:00
James Cole
b816fbdf82 New translations firefly.php (Chinese Traditional) 2017-03-10 19:41:17 +01:00
James Cole
d400060b8b New translations firefly.php (Croatian) 2017-03-10 19:41:10 +01:00
James Cole
c88cfa2d9d New translations firefly.php (Chinese Traditional, Hong Kong) 2017-03-10 19:41:03 +01:00
James Cole
b060027304 New translations firefly.php (Russian) 2017-03-10 19:40:51 +01:00
James Cole
d4787aca9c New translations firefly.php (Dutch) 2017-03-10 19:40:45 +01:00
James Cole
69ae2e93f8 New translations firefly.php (Spanish) 2017-03-10 19:40:40 +01:00
James Cole
82a37c62c1 New translations firefly.php (German) 2017-03-10 19:40:30 +01:00
James Cole
ca69970242 New translations firefly.php (Polish) 2017-03-10 19:40:25 +01:00
James Cole
fac3853d95 New translations firefly.php (Portuguese, Brazilian) 2017-03-10 19:40:21 +01:00
James Cole
9dd2f447cc Fix in date range [skip ci] 2017-03-10 19:36:22 +01:00
James Cole
ecbd7ca95b Also implement #595 for the no-cat view. 2017-03-10 19:34:46 +01:00
James Cole
0c52d54d7d Optimized some views and fixed tests for #595 2017-03-10 18:54:50 +01:00
James Cole
78276ac66b New translations firefly.php (French) 2017-03-10 16:12:09 +01:00
James Cole
ca0a22d755 New translations firefly.php (Chinese Traditional) 2017-03-10 16:11:56 +01:00
James Cole
47361fd77a New translations firefly.php (Croatian) 2017-03-10 16:11:49 +01:00
James Cole
1af6fd5d74 New translations firefly.php (Chinese Traditional, Hong Kong) 2017-03-10 16:11:42 +01:00
James Cole
51df78ad2d New translations firefly.php (Russian) 2017-03-10 16:11:27 +01:00
James Cole
84a3e68eb5 New translations firefly.php (Dutch) 2017-03-10 16:11:18 +01:00
James Cole
b2904e09d8 New translations firefly.php (Spanish) 2017-03-10 16:11:11 +01:00
James Cole
fc42a621e4 New translations firefly.php (German) 2017-03-10 16:10:55 +01:00
James Cole
a1c4fb73cd New translations firefly.php (Polish) 2017-03-10 16:10:46 +01:00
James Cole
c18f19db97 New translations firefly.php (Portuguese, Brazilian) 2017-03-10 16:10:40 +01:00
James Cole
ebc712f6b5 Consistency for #595 2017-03-10 16:08:58 +01:00
James Cole
ef0057d88d Add opposing account info [skip ci] #595 2017-03-10 15:28:04 +01:00
James Cole
a8fdfdd5e0 Add opposing account info [skip ci] #595 2017-03-10 15:27:19 +01:00
James Cole
89f7e1ba2a New translations firefly.php (French) 2017-03-09 21:11:36 +01:00
James Cole
6508b4058f New translations firefly.php (Chinese Traditional) 2017-03-09 21:11:25 +01:00
James Cole
bec5d93af6 New translations firefly.php (Croatian) 2017-03-09 21:11:18 +01:00
James Cole
1125fcd6c5 New translations firefly.php (Chinese Traditional, Hong Kong) 2017-03-09 21:11:11 +01:00
James Cole
ff43a547a6 New translations firefly.php (Russian) 2017-03-09 21:10:57 +01:00
James Cole
ca8684146c New translations firefly.php (Dutch) 2017-03-09 21:10:51 +01:00
James Cole
44bea62383 New translations firefly.php (Spanish) 2017-03-09 21:10:45 +01:00
James Cole
8dc2faa5e5 New translations firefly.php (German) 2017-03-09 21:10:34 +01:00
James Cole
f4867d1d09 New translations firefly.php (Polish) 2017-03-09 21:10:29 +01:00
James Cole
8d172801b5 New translations firefly.php (Portuguese, Brazilian) 2017-03-09 21:10:24 +01:00
James Cole
db6e6dfe4a Fix tests for #595 2017-03-09 21:05:37 +01:00
James Cole
61007a95a6 Initial code for #595, transactions with no budget 2017-03-09 20:54:18 +01:00
James Cole
bf138670e8 New translations firefly.php (Dutch) 2017-03-09 08:20:49 +01:00
James Cole
0e59f7433c Code and tests for #615 2017-03-09 08:19:05 +01:00
James Cole
9a033ac62a New translations firefly.php (French) 2017-03-08 20:41:39 +01:00
James Cole
789412ee6a New translations firefly.php (Chinese Traditional) 2017-03-08 20:41:28 +01:00
James Cole
91125d20ef New translations firefly.php (Croatian) 2017-03-08 20:41:19 +01:00
James Cole
292b3672e2 New translations firefly.php (Chinese Traditional, Hong Kong) 2017-03-08 20:41:14 +01:00
James Cole
14ef6b753c New translations firefly.php (Russian) 2017-03-08 20:40:56 +01:00
James Cole
55fcb97a10 New translations firefly.php (Dutch) 2017-03-08 20:40:50 +01:00
James Cole
6b8ec544c1 New translations firefly.php (Spanish) 2017-03-08 20:40:44 +01:00
James Cole
c0aad385cd New translations firefly.php (German) 2017-03-08 20:40:33 +01:00
James Cole
ecfb5e4711 New translations firefly.php (Polish) 2017-03-08 20:40:26 +01:00
James Cole
46c9967a68 New translations firefly.php (Portuguese, Brazilian) 2017-03-08 20:40:23 +01:00
James Cole
176c44e2b9 Remove newline [skip ci] 2017-03-08 20:38:08 +01:00
James Cole
5957cf5ff8 Remove space. [skip ci] 2017-03-08 20:37:40 +01:00
James Cole
436a270524 Merge branch 'release/4.3.7' 2017-03-06 21:07:40 +01:00
James Cole
7a1c14b766 Update for new release. 2017-03-06 21:04:14 +01:00
James Cole
721c4aa888 Merge pull request #609 from firefly-iii/l10n_develop
New Crowdin translations
2017-03-06 20:54:52 +01:00
James Cole
638aab4eea Update TagRepository.php 2017-03-06 10:16:52 +01:00
James Cole
9aa44f7458 New translations 2017-03-05 19:00:15 +01:00
James Cole
1e887a2a8d Start replacing html comments with twig comments 2017-03-05 18:46:12 +01:00
James Cole
78571ad121 Update change log 2017-03-05 18:45:55 +01:00
James Cole
8e5ec79097 Wrote new tests. 2017-03-05 18:15:38 +01:00
James Cole
fc351f36b1 New translations 2017-03-05 13:31:21 +01:00
James Cole
80204147f7 New translations 2017-03-05 13:31:12 +01:00
James Cole
d599b8e5ea New translations 2017-03-05 13:31:06 +01:00
James Cole
208ef9d664 New translations 2017-03-05 13:31:00 +01:00
James Cole
c14da542d1 New translations 2017-03-05 13:30:48 +01:00
James Cole
451832cb2b New translations 2017-03-05 13:30:42 +01:00
James Cole
1409aeb8ed New translations 2017-03-05 13:30:38 +01:00
James Cole
342f24cfe4 New translations 2017-03-05 13:30:27 +01:00
James Cole
8aedfd5153 New translations 2017-03-05 13:30:22 +01:00
James Cole
33b099456f New translations 2017-03-05 13:30:18 +01:00
James Cole
42cb40102f Updated test database. 2017-03-05 13:26:31 +01:00
James Cole
2fbeaaccd3 Expand tests. 2017-03-05 13:21:36 +01:00
James Cole
57fb75bef4 Fix for #611 [skip ci] 2017-03-05 12:19:12 +01:00
James Cole
5c0e22cd31 Fix for #612 [skip ci] 2017-03-05 12:17:55 +01:00
James Cole
879f74e521 Code cleanup. 2017-03-05 11:19:06 +01:00
James Cole
e5a2e1a8c7 Updated tests 2017-03-05 11:18:34 +01:00
James Cole
884d6c59a2 Expand some tests. 2017-03-04 19:14:36 +01:00
James Cole
c206a95d55 Improved various tests. 2017-03-04 15:29:20 +01:00
James Cole
8b4ef4e2da Fix for #610 2017-03-04 13:08:16 +01:00
James Cole
bac5238589 New test database. 2017-03-04 11:21:42 +01:00
James Cole
ae05d4d51d Expand tests 2017-03-04 11:20:57 +01:00
James Cole
9d22bbee1c Add code coverage ignore instructions. 2017-03-04 11:19:44 +01:00
James Cole
1d6007b848 New translations 2017-03-04 07:31:20 +01:00
James Cole
3157339e44 New translations 2017-03-04 07:31:10 +01:00
James Cole
b31d5eefd1 New translations 2017-03-04 07:31:04 +01:00
James Cole
e47398dc71 New translations 2017-03-04 07:30:58 +01:00
James Cole
757d472704 New translations 2017-03-04 07:30:47 +01:00
James Cole
9d0ae99602 New translations 2017-03-04 07:30:41 +01:00
James Cole
0d9ceb6fde New translations 2017-03-04 07:30:37 +01:00
James Cole
cb665d4016 New translations 2017-03-04 07:30:27 +01:00
James Cole
9673dc96d9 New translations 2017-03-04 07:30:22 +01:00
James Cole
2295091427 New translations 2017-03-04 07:30:18 +01:00
James Cole
45f4395f26 Large commit to get rid of a lot of static methods. 2017-03-04 07:26:03 +01:00
James Cole
d9aa074330 Large commit to get rid of a lot of static methods. 2017-03-04 07:18:35 +01:00
James Cole
33c20c8dc4 Renamed a parameter 2017-03-04 06:54:05 +01:00
James Cole
8101f910f0 Update tests. 2017-03-04 06:53:46 +01:00
James Cole
8fb6c1a0c8 Various small changes. 2017-03-03 18:19:25 +01:00
James Cole
978e3e615c This prevented FF from displaying cash account properly. 2017-03-03 12:55:28 +01:00
James Cole
b3b8981b4b Catch null pointer exception. 2017-03-02 19:57:46 +01:00
James Cole
015064e5af Update composer.lock 2017-03-02 19:45:04 +01:00
James Cole
7ef8ff60a5 Update config files. 2017-03-02 19:41:17 +01:00
James Cole
4c3f54699e Merge pull request #590 from firefly-iii/l10n_develop
New Crowdin translations
2017-03-02 19:26:13 +01:00
James Cole
3bf5040324 Fixed null pointer in debug message [skip ci] 2017-03-02 16:42:33 +01:00
James Cole
ed9e5b31fa Merge pull request #606 from Zsub/fix-piggy-bank-interaction
Set default piggy for new transaction
2017-03-02 07:28:17 +01:00
Joris de Vries
506e97e12d Set default piggy for new transaction
Fixes #605. By explicitly setting the selected piggybank to the 0-piggy, new transactions will not inadvertently get coupled to a piggybank if the piggy’s name starts with characters that get sorted before `(` (such as `!` or `’`).
2017-03-01 22:45:37 +01:00
James Cole
9365f9ab60 This fixes #604 2017-03-01 21:13:45 +01:00
James Cole
dd1e9ecb32 This fixes #599 2017-03-01 21:02:47 +01:00
James Cole
d3a2bf174d This fixes #605 2017-03-01 20:57:52 +01:00
James Cole
311020ff2e This fixes #602 2017-03-01 20:49:16 +01:00
James Cole
a6df3ac1fb New translations 2017-02-26 14:40:10 +01:00
James Cole
d313b50e39 Updated composer.lock 2017-02-26 11:52:40 +01:00
James Cole
b23eb07018 Fix error when not-existing import job is submitted. 2017-02-26 11:48:38 +01:00
James Cole
2116486fe0 Various code cleanup 2017-02-25 17:39:50 +01:00
James Cole
eed8fe22c6 Make sure the loop is broken. #595 2017-02-25 13:34:44 +01:00
James Cole
1cec91e4bf New translations 2017-02-25 13:31:13 +01:00
James Cole
8decf8ab9f Make PHP modules mandatory in composer file. 2017-02-25 13:26:01 +01:00
James Cole
79b0c20adb Forgot about the date for account lists, #595 [skip ci] 2017-02-25 13:22:06 +01:00
James Cole
65647ca822 New translations 2017-02-25 13:21:20 +01:00
James Cole
18fafcd45f New translations 2017-02-25 13:21:10 +01:00
James Cole
b7723f4487 New translations 2017-02-25 13:21:04 +01:00
James Cole
6418df87bb New translations 2017-02-25 13:20:58 +01:00
James Cole
daa88c5be1 New translations 2017-02-25 13:20:47 +01:00
James Cole
707b70b136 New translations 2017-02-25 13:20:42 +01:00
James Cole
f9b3b6f7d3 New translations 2017-02-25 13:20:37 +01:00
James Cole
b295eef970 New translations 2017-02-25 13:20:28 +01:00
James Cole
f13dace7ad New translations 2017-02-25 13:20:22 +01:00
James Cole
8dfc40ed3e New translations 2017-02-25 13:20:18 +01:00
James Cole
2e637031ac Fix charts for #595, account overview. 2017-02-25 13:19:42 +01:00
James Cole
de9ef20014 First code for #595. Charts are still broken. 2017-02-25 13:13:51 +01:00
James Cole
4f50689d0e - Will now return 0 when nothing to save or when target date is in the past.
- Will calculate correctly when date difference with target date is more than a year.
- Will always return a string
- Will do calculations using bcmath module.
2017-02-25 13:05:33 +01:00
James Cole
082392f9e0 New translations 2017-02-25 13:01:34 +01:00
James Cole
aca2ef08f1 New translations 2017-02-25 13:01:24 +01:00
James Cole
90fcec4ca8 New translations 2017-02-25 13:01:17 +01:00
James Cole
c90db28b9e New translations 2017-02-25 13:01:11 +01:00
James Cole
56b617bd57 New translations 2017-02-25 13:00:56 +01:00
James Cole
06d58c16d8 New translations 2017-02-25 13:00:50 +01:00
James Cole
b1a807139a New translations 2017-02-25 13:00:45 +01:00
James Cole
ac07736040 New translations 2017-02-25 13:00:34 +01:00
James Cole
c68ba8d510 New translations 2017-02-25 13:00:28 +01:00
James Cole
470802c93b New translations 2017-02-25 13:00:24 +01:00
James Cole
c58745b6ce Merge pull request #597 from Zsub/make-text-translatable
Make suggested savings text translatable
2017-02-25 12:56:31 +01:00
James Cole
9eea4749f0 Remove IDE and environment specific files from gitignore, as inspired by #598. 2017-02-25 12:55:56 +01:00
Joris de Vries
251206fb75 Make suggested savings text translatable
PR #594 introduced suggested savings, this commit makes the text translatable.
2017-02-25 12:26:46 +01:00
James Cole
b53a6c5703 Update .travis.yml in this branch so it stops building this branch. 2017-02-25 06:13:08 +01:00
James Cole
8c6972d12d Various code cleanup. 2017-02-25 05:57:01 +01:00
James Cole
fe0d88b7b3 New translations 2017-02-25 05:31:24 +01:00
James Cole
658b6de9c7 New translations 2017-02-25 05:31:14 +01:00
James Cole
4ea89c3811 New translations 2017-02-25 05:31:07 +01:00
James Cole
2d3d71f46a New translations 2017-02-25 05:31:02 +01:00
James Cole
80a6f431b6 New translations 2017-02-25 05:30:49 +01:00
James Cole
0644729148 New translations 2017-02-25 05:30:43 +01:00
James Cole
07da48e5ea New translations 2017-02-25 05:30:38 +01:00
James Cole
b3f565819b New translations 2017-02-25 05:30:28 +01:00
James Cole
af4abfbed9 New translations 2017-02-25 05:30:22 +01:00
James Cole
eb0011cb46 New translations 2017-02-25 05:30:18 +01:00
James Cole
444439fdab Merge pull request #594 from Zsub/show-suggested-monthly-savings
Show suggested monthly savings for a piggybank
2017-02-25 05:24:05 +01:00
Joris de Vries
a0e66b913b Show suggested monthly savings for a piggybank
If a piggybank has both a target date and a target amount, show how much money needs to be added to the piggybank each month to achieve both targets.

Strings are currently hard-coded because I want to gauge the reaction to this :)
2017-02-24 22:00:49 +01:00
James Cole
96c780c804 New text for translation [skip ci] 2017-02-24 21:11:51 +01:00
James Cole
4f1f46aa93 New translations 2017-02-24 21:11:48 +01:00
James Cole
1d9f76ee5a New translations 2017-02-24 21:11:36 +01:00
James Cole
a7ceda7eea New translations 2017-02-24 21:11:28 +01:00
James Cole
baec4c4d70 New translations 2017-02-24 21:11:21 +01:00
James Cole
4fa850048c New translations 2017-02-24 21:11:04 +01:00
James Cole
8163655a24 New translations 2017-02-24 21:10:56 +01:00
James Cole
4cabf8d2e3 New translations 2017-02-24 21:10:49 +01:00
James Cole
db2f08fa96 New translations 2017-02-24 21:10:36 +01:00
James Cole
a68be2fed7 New translations 2017-02-24 21:10:29 +01:00
James Cole
c3e9aea3a7 New translations 2017-02-24 21:10:24 +01:00
James Cole
40c38af766 Final code for tag report. 2017-02-24 21:09:20 +01:00
James Cole
fc2cee7a54 Fixes tests. 2017-02-24 21:01:33 +01:00
James Cole
3d4feff7de More code for the tag report. 2017-02-24 20:27:26 +01:00
James Cole
f63c6875cd Initial code base for tag report. 2017-02-24 20:01:35 +01:00
James Cole
115b72149c New translations 2017-02-24 16:21:01 +01:00
James Cole
a7e8118c83 New translations 2017-02-24 16:11:55 +01:00
James Cole
8569cc5ac6 New translations 2017-02-24 16:11:43 +01:00
James Cole
7a0ffce36f New translations 2017-02-24 16:11:33 +01:00
James Cole
c573d95ec5 New translations 2017-02-24 16:11:27 +01:00
James Cole
d3e1fba4e0 New translations 2017-02-24 16:11:10 +01:00
James Cole
e7dd087b52 New translations 2017-02-24 16:10:59 +01:00
James Cole
c7cb79906c New translations 2017-02-24 16:10:53 +01:00
James Cole
3c3f80c5a0 New translations 2017-02-24 16:10:39 +01:00
James Cole
e20fb3c3ac New translations 2017-02-24 16:10:32 +01:00
James Cole
e3986a4dd4 New translations 2017-02-24 16:10:26 +01:00
James Cole
a3926e3996 New translations 2017-02-24 16:00:31 +01:00
James Cole
e737683efb Fine-tune some translations [skip ci] 2017-02-24 16:00:24 +01:00
James Cole
0157c4ed65 New translations 2017-02-24 15:50:41 +01:00
James Cole
058ade266d New translations 2017-02-24 09:21:23 +01:00
James Cole
e0adb4c397 New translations 2017-02-24 09:10:35 +01:00
James Cole
35aa61bb23 Different icon [skip ci] 2017-02-23 17:47:46 +01:00
James Cole
27236d19cf Clone, not copy [skip ci] 2017-02-23 17:47:36 +01:00
James Cole
063ca3121a Fixes #593 2017-02-23 17:43:29 +01:00
James Cole
b8521c6875 New translations 2017-02-23 07:41:38 +01:00
James Cole
e3798d6462 New translations 2017-02-23 07:41:28 +01:00
James Cole
387a3e541f New translations 2017-02-23 07:41:20 +01:00
James Cole
42a3b411e4 New translations 2017-02-23 07:41:15 +01:00
James Cole
25c7ec4175 New translations 2017-02-23 07:40:59 +01:00
James Cole
7ec11765da New translations 2017-02-23 07:40:52 +01:00
James Cole
d57ae126b7 New translations 2017-02-23 07:40:45 +01:00
James Cole
87f133555c New translations 2017-02-23 07:40:34 +01:00
James Cole
db9883d851 New translations 2017-02-23 07:40:27 +01:00
James Cole
8dad5ff7db New translations 2017-02-23 07:40:23 +01:00
James Cole
fc36f9cd8c Added empty box for bills as well. 2017-02-23 07:30:08 +01:00
James Cole
563c668e3f Code to catch empty lists and nudge user in the right direction. 2017-02-23 07:24:05 +01:00
James Cole
b3df1f3d26 Move template around 2017-02-23 07:02:28 +01:00
James Cole
1ac3f7af3b Included a message about translations after a PR was submitted that I had to close :( [skip ci] 2017-02-23 06:53:58 +01:00
James Cole
6cbb86aed7 New translations 2017-02-22 21:51:55 +01:00
James Cole
e459a8c88b New translations 2017-02-22 21:51:41 +01:00
James Cole
ca003b7d4d New translations 2017-02-22 21:51:33 +01:00
James Cole
03f873a6d3 New translations 2017-02-22 21:51:27 +01:00
James Cole
5dbec53847 New translations 2017-02-22 21:51:11 +01:00
James Cole
49dfad9b0c Approved. Step name: Proofread 2017-02-22 21:51:02 +01:00
James Cole
4ee0462d1b New translations 2017-02-22 21:50:55 +01:00
James Cole
3f78be4471 New translations 2017-02-22 21:50:41 +01:00
James Cole
d93fad39ac New translations 2017-02-22 21:50:33 +01:00
James Cole
aa3429bb0e New translations 2017-02-22 21:50:28 +01:00
James Cole
d88246f2f6 First code for #588 2017-02-22 21:40:27 +01:00
James Cole
201db34936 Update various sandstorm files. [skip ci] 2017-02-22 21:27:39 +01:00
James Cole
47709dfc7c Test catches some exceptions. 2017-02-22 20:35:31 +01:00
James Cole
2aaafc54ee Merge pull request #587 from Zsub/fix-tag-date
Fix saving a tag’s date
2017-02-22 20:21:25 +01:00
Joris de Vries
e211881691 Remove superfluous declaration of $date
The null check is already part of the `$this->date()` function and `$date` is never used.
2017-02-22 20:20:00 +01:00
Joris de Vries
0d32f16041 Fix saving a tag’s date
The `date` function takes the fieldname where a date is stored, not the literal date.
2017-02-22 20:07:30 +01:00
James Cole
2082e8d462 Small updates to read me [skip ci] 2017-02-22 17:58:57 +01:00
James Cole
bfc95cfc57 Update composer file. 2017-02-22 17:17:22 +01:00
James Cole
35aeb7e04a Update tag view 2017-02-22 17:15:54 +01:00
James Cole
adcddb09cd Updated link to installation guide. [skip ci] 2017-02-20 19:41:33 +01:00
James Cole
56199f899f Merge branch 'release/4.3.6' 2017-02-20 05:43:34 +01:00
James Cole
ca5c845064 Update to 4.3.6 2017-02-20 05:43:05 +01:00
James Cole
a8ac69f008 Fix #578 [skip ci] 2017-02-20 05:41:43 +01:00
James Cole
b9309bc7b1 Stop Travis from building weird branches. 2017-02-19 17:01:29 +01:00
James Cole
41596feb56 Merge branch 'release/4.3.5' 2017-02-19 16:49:45 +01:00
James Cole
cf1813b413 Updated composer.lock 2017-02-19 16:48:49 +01:00
James Cole
5b267c0e95 Update to version 4.3.5 2017-02-19 16:36:03 +01:00
James Cole
3741f70c29 Merge pull request #576 from firefly-iii/l10n_develop
New Crowdin translations
2017-02-19 16:33:54 +01:00
James Cole
1f37ea3d3c Translated 2017-02-19 12:30:11 +01:00
James Cole
283ee076c7 Expand view [skip ci] 2017-02-19 12:19:30 +01:00
James Cole
b13a878927 Slightly expanded modifiers [skip ci] 2017-02-19 12:17:07 +01:00
James Cole
364eb2838e Translated 2017-02-19 12:12:59 +01:00
James Cole
94631ca8d7 Approved. Step name: Proofread 2017-02-19 12:12:58 +01:00
James Cole
2ed095d58f Approved. Step name: Proofread 2017-02-19 12:12:56 +01:00
James Cole
9c10e3970d Approved. Step name: Proofread 2017-02-19 12:12:55 +01:00
James Cole
0cf4f44e95 Approved. Step name: Proofread 2017-02-19 12:12:54 +01:00
James Cole
89638a0094 Approved. Step name: Proofread 2017-02-19 12:12:52 +01:00
James Cole
d7531cf4ff Approved. Step name: Proofread 2017-02-19 12:12:51 +01:00
James Cole
2c5acb8ecd Approved. Step name: Proofread 2017-02-19 12:12:50 +01:00
James Cole
824c317f74 Translated 2017-02-19 12:12:49 +01:00
James Cole
d208fd1772 New translations 2017-02-19 12:12:48 +01:00
James Cole
f145aaded9 New translations 2017-02-19 12:12:46 +01:00
James Cole
c7043478f6 New translations 2017-02-19 12:12:45 +01:00
James Cole
d16bb7f394 Approved. Step name: Proofread 2017-02-19 12:12:44 +01:00
James Cole
3ed314dbc6 New translations 2017-02-19 12:12:43 +01:00
James Cole
e8c5942e33 Approved. Step name: Proofread 2017-02-19 12:12:42 +01:00
James Cole
96c704760c Approved. Step name: Proofread 2017-02-19 12:12:40 +01:00
James Cole
70c99f18e1 New translations 2017-02-19 12:12:39 +01:00
James Cole
5e2bdb6356 Translated 2017-02-19 12:12:38 +01:00
James Cole
dd13285f04 Translated 2017-02-19 12:12:37 +01:00
James Cole
561a5bf699 New translations 2017-02-19 12:12:35 +01:00
James Cole
f2d794e372 New translations 2017-02-19 12:12:34 +01:00
James Cole
f0931b8438 New translations 2017-02-19 12:12:33 +01:00
James Cole
aadb9addd5 New translations 2017-02-19 12:12:31 +01:00
James Cole
66abb50d23 Translated 2017-02-19 12:12:30 +01:00
James Cole
4eca99b745 New translations 2017-02-19 12:12:29 +01:00
James Cole
a95a265d47 Translated 2017-02-19 12:12:27 +01:00
James Cole
b0e70c25d0 New translations 2017-02-19 12:12:26 +01:00
James Cole
8914bd6b9a New translations 2017-02-19 12:12:25 +01:00
James Cole
26751e10ee Expand modifiers 2017-02-19 12:12:24 +01:00
James Cole
579ee9f199 New translations 2017-02-19 12:12:22 +01:00
James Cole
48fcb76ba4 New translations 2017-02-19 12:12:21 +01:00
James Cole
b872bbbb42 New translations 2017-02-19 12:12:19 +01:00
James Cole
73c88aa11f Translated 2017-02-19 12:12:18 +01:00
James Cole
aa1700b7b4 New translations 2017-02-19 12:12:16 +01:00
James Cole
1aa8e43bdf New translations 2017-02-19 12:12:15 +01:00
James Cole
fa8200d3e2 New translations 2017-02-19 12:12:14 +01:00
James Cole
bd9fcc6e8d New translations 2017-02-19 12:12:12 +01:00
James Cole
6167667f9a Translated 2017-02-19 12:12:11 +01:00
James Cole
1081379689 New translations 2017-02-19 12:12:10 +01:00
James Cole
712526f1c3 New translations 2017-02-19 12:12:08 +01:00
James Cole
7c0cfc5596 Translated 2017-02-19 12:12:07 +01:00
James Cole
edd0dcbcef New translations 2017-02-19 12:12:06 +01:00
James Cole
b322d67ffc New translations 2017-02-19 12:12:05 +01:00
James Cole
38dbac199d Translated 2017-02-19 12:12:02 +01:00
James Cole
6eb695c5eb New translations 2017-02-19 12:12:00 +01:00
James Cole
b0fd5889aa New translations 2017-02-19 12:11:58 +01:00
James Cole
b181f2edf0 New translations 2017-02-19 12:11:57 +01:00
James Cole
376940e089 New translations 2017-02-19 12:11:56 +01:00
James Cole
1c0762a3df New translations 2017-02-19 12:11:55 +01:00
James Cole
df39f5ab98 New translations 2017-02-19 12:11:54 +01:00
James Cole
9cd1ae1220 New translations 2017-02-19 12:11:52 +01:00
James Cole
3ddef6fe78 New translations 2017-02-19 12:11:50 +01:00
James Cole
b8c78217e8 New translations 2017-02-19 12:11:49 +01:00
James Cole
3a1b514982 New translations 2017-02-19 12:11:47 +01:00
James Cole
5d34dab2ef New translations 2017-02-19 12:11:46 +01:00
James Cole
541ed1e764 New translations 2017-02-19 12:11:45 +01:00
James Cole
5e764a345e New translations 2017-02-19 12:11:42 +01:00
James Cole
33de51c4aa New translations 2017-02-19 12:11:41 +01:00
James Cole
5aa038e195 New translations 2017-02-19 12:11:40 +01:00
James Cole
0fe437c66b New translations 2017-02-19 12:11:38 +01:00
James Cole
790d156503 Translated 2017-02-19 12:11:37 +01:00
James Cole
9f515bea20 Translated 2017-02-19 12:11:36 +01:00
James Cole
1422adac3f New translations 2017-02-19 12:11:35 +01:00
James Cole
5f17e41190 New translations 2017-02-19 12:11:33 +01:00
James Cole
0d9daaffe8 New translations 2017-02-19 12:11:32 +01:00
James Cole
e1f3bf8d45 New translations 2017-02-19 12:11:31 +01:00
James Cole
20a7723e63 New translations 2017-02-19 12:11:30 +01:00
James Cole
5ffa6d9500 New translations 2017-02-19 12:11:29 +01:00
James Cole
86956969ce New translations 2017-02-19 12:11:28 +01:00
James Cole
13beb888c1 Translated 2017-02-19 12:11:26 +01:00
James Cole
c1d4caf1a9 New translations 2017-02-19 12:11:25 +01:00
James Cole
5e9a605ae4 New translations 2017-02-19 12:11:23 +01:00
James Cole
c79d0ed276 Translated 2017-02-19 12:11:22 +01:00
James Cole
6204e575a2 New translations 2017-02-19 12:11:21 +01:00
James Cole
19f181723a New translations 2017-02-19 12:11:18 +01:00
James Cole
4a49bf8799 New translations 2017-02-19 12:11:17 +01:00
James Cole
8128c6aed6 New translations 2017-02-19 12:11:16 +01:00
James Cole
45dfc74ab3 New translations 2017-02-19 12:11:14 +01:00
James Cole
72c4ecced7 New translations 2017-02-19 12:11:13 +01:00
James Cole
d21187df6a Approved. Step name: Proofread 2017-02-19 12:11:12 +01:00
James Cole
bf33025569 Translated 2017-02-19 12:11:09 +01:00
James Cole
065620aec9 Translated 2017-02-19 12:11:08 +01:00
James Cole
e8e0fbc988 New translations 2017-02-19 12:11:07 +01:00
James Cole
21e61d08dd New translations 2017-02-19 12:11:06 +01:00
James Cole
ca9cc50423 New translations 2017-02-19 12:11:05 +01:00
James Cole
0fde74883f New translations 2017-02-19 12:11:03 +01:00
James Cole
c1d12e5129 New translations 2017-02-19 12:11:02 +01:00
James Cole
8ee6cd6c41 New translations 2017-02-19 12:10:59 +01:00
James Cole
bb09ea5fa2 New translations 2017-02-19 12:10:57 +01:00
James Cole
6b92ef9d71 New translations 2017-02-19 12:10:56 +01:00
James Cole
a49f8a27e2 Translated 2017-02-19 12:10:55 +01:00
James Cole
d0b3b4b186 Translated 2017-02-19 12:10:54 +01:00
James Cole
0bd688962b New translations 2017-02-19 12:10:52 +01:00
James Cole
c737ceb63f New translations 2017-02-19 12:10:51 +01:00
James Cole
d24e5b9eca Translated 2017-02-19 12:10:50 +01:00
James Cole
d68c2b5b8f New translations 2017-02-19 12:10:49 +01:00
James Cole
6803707b1f Translated 2017-02-19 12:10:47 +01:00
James Cole
13574d812f Translated 2017-02-19 12:10:46 +01:00
James Cole
f4e95bdbca Translated 2017-02-19 12:10:45 +01:00
James Cole
eb83023864 Translated 2017-02-19 12:10:44 +01:00
James Cole
10c81fdfba Translated 2017-02-19 12:10:42 +01:00
James Cole
7c47723992 New translations 2017-02-19 12:10:41 +01:00
James Cole
0154183800 New translations 2017-02-19 12:10:38 +01:00
James Cole
a2b0ea9c5b Translated 2017-02-19 12:10:37 +01:00
James Cole
c49caf663c Translated 2017-02-19 12:10:35 +01:00
James Cole
17e6698133 New translations 2017-02-19 12:10:34 +01:00
James Cole
a7b99b1bb5 New translations 2017-02-19 12:10:33 +01:00
James Cole
8d6a217f22 Translated 2017-02-19 12:10:30 +01:00
James Cole
d5b1722c0c Translated 2017-02-19 12:10:28 +01:00
James Cole
0d9a81f0e4 New translations 2017-02-19 12:10:27 +01:00
James Cole
821a443e44 New translations 2017-02-19 12:10:24 +01:00
James Cole
9d8d54e5c8 New translations 2017-02-19 12:10:23 +01:00
James Cole
411739277d Translated 2017-02-19 12:10:21 +01:00
James Cole
fa71feb9fb Translated 2017-02-19 12:10:20 +01:00
James Cole
00f9194bfa New translations 2017-02-19 12:10:19 +01:00
James Cole
a3e955400f Translated 2017-02-19 12:10:17 +01:00
James Cole
05060cee5b New translations 2017-02-19 12:10:16 +01:00
James Cole
c10148753a New translations 2017-02-19 12:10:14 +01:00
James Cole
53bb64641b Translated 2017-02-19 12:10:13 +01:00
James Cole
9a124bb3b2 New translations 2017-02-19 12:10:12 +01:00
James Cole
91568cf919 Translated 2017-02-19 12:10:10 +01:00
James Cole
b149a816dd Make search work. [skip ci] 2017-02-19 09:36:51 +01:00
James Cole
bf35ecc07a Fixed tests 2017-02-19 09:17:02 +01:00
James Cole
711a1a1d4f Final modifiers. 2017-02-19 09:07:14 +01:00
James Cole
a27b686446 Add budget keyword. 2017-02-19 07:41:12 +01:00
James Cole
1f6180ce5d Updated search modifiers. 2017-02-19 07:38:51 +01:00
James Cole
b5032a7597 Added a new helper function. 2017-02-19 07:34:39 +01:00
James Cole
5073fd937c Expand search with a bunch of keywords for #510 2017-02-18 20:10:03 +01:00
James Cole
f0cb63fd48 Some small optimisations. 2017-02-18 09:32:10 +01:00
James Cole
f7642beb7c Better 2fa handling 2017-02-17 20:15:17 +01:00
James Cole
48c26c5837 Update test coverage 2017-02-17 20:14:38 +01:00
James Cole
65a899bf25 Clean up session code 2017-02-17 20:14:22 +01:00
James Cole
5d0cdc4ffa Various code cleanup. 2017-02-17 06:42:36 +01:00
James Cole
1d979778e8 Merge pull request #573 from firefly-iii/l10n_develop
New Crowdin translations
2017-02-16 22:42:35 +01:00
James Cole
917b8b40cf Merge branch 'develop' into l10n_develop 2017-02-16 22:42:24 +01:00
James Cole
466ec92492 Remove some commented code. 2017-02-16 22:34:37 +01:00
James Cole
4ff5f526ba Add new lines to files. 2017-02-16 22:33:32 +01:00
James Cole
8460ee2dc4 Small fix in read me [skip ci] 2017-02-16 22:30:57 +01:00
James Cole
fa39330ceb New change log [skip ci] 2017-02-16 22:30:46 +01:00
James Cole
1857bb17d9 Approved. Step name: Proofread 2017-02-16 22:30:14 +01:00
James Cole
fe54b2fa3a Names are now links [skip ci] 2017-02-16 22:13:04 +01:00
James Cole
4fbf0291e6 Updated composer things. 2017-02-16 21:06:31 +01:00
James Cole
8bfcc3315a This fixes #572 2017-02-16 21:01:22 +01:00
James Cole
c8f6b42ce6 Fix tests 2017-02-15 22:02:02 +01:00
James Cole
8f5289b7dc Fixed some transaction list filter issues. 2017-02-15 21:55:50 +01:00
James Cole
281e3f706b New translations 2017-02-15 20:12:02 +01:00
James Cole
6dfa027ae2 New translations 2017-02-15 20:11:48 +01:00
James Cole
623cd51b1c New translations 2017-02-15 20:11:39 +01:00
James Cole
3d9e723a0e New translations 2017-02-15 20:11:33 +01:00
James Cole
4a2b7cfc4e New translations 2017-02-15 20:11:15 +01:00
James Cole
c15bee4511 New translations 2017-02-15 20:11:05 +01:00
James Cole
f4afcd29e0 New translations 2017-02-15 20:10:56 +01:00
James Cole
770e77a862 New translations 2017-02-15 20:10:41 +01:00
James Cole
684d1dc432 New translations 2017-02-15 20:10:33 +01:00
James Cole
ec9ddb2bfb New translations 2017-02-15 20:10:27 +01:00
James Cole
a5f8aa914f Build code for tag report. 2017-02-15 20:07:10 +01:00
James Cole
ae06f1b8f0 Yeah never mind. [skip ci] 2017-02-15 18:16:07 +01:00
James Cole
e8f76d896b Expand code climate config [skip ci] 2017-02-15 17:25:36 +01:00
James Cole
07ecb3f0e8 Expand code climate config [skip ci] 2017-02-15 17:23:56 +01:00
James Cole
893f2d2c55 Include code climate config [skip ci] 2017-02-15 17:17:15 +01:00
James Cole
395a7bb33c This should fix the tests 2017-02-15 17:07:56 +01:00
James Cole
636b371b86 Fixes #553 2017-02-15 16:20:16 +01:00
James Cole
f0783df123 This should fix #566 2017-02-15 15:24:01 +01:00
James Cole
fa54763425 This fixes #570 2017-02-15 15:22:04 +01:00
James Cole
cf2cd9680b This fixes #569 2017-02-15 15:18:52 +01:00
James Cole
47aa996b6b This fixes #567 2017-02-15 15:12:46 +01:00
James Cole
6442887c1a Merge pull request #562 from patrickkostjens/develop
Use Docker volumes created by docker-compose to persist data
2017-02-13 20:54:22 +01:00
James Cole
7a34536c80 Fixes #565 2017-02-13 20:39:23 +01:00
Patrick Kostjens
e9a67b1c82 Bugfix: Mount app in app container instead of db container 2017-02-12 21:38:58 +01:00
Patrick Kostjens
bc4cf1a367 Incorporate comments: Use Docker storage instead of local folder for app storage 2017-02-12 21:04:15 +01:00
Patrick Kostjens
a1d40a5748 Mount local code base in development docker-compose 2017-02-12 20:52:26 +01:00
Patrick Kostjens
e42f858166 Incorporate review comment: Remove unneeded container name setting in docker-compose 2017-02-12 20:41:29 +01:00
Patrick Kostjens
75e0d19b4e Refactored docker-compose files to use base with dev/prod overrides 2017-02-12 19:37:37 +01:00
James Cole
5801eba22a Updated composer.lock file. 2017-02-12 18:47:17 +01:00
James Cole
fd3f756640 Restored most pre-5.4 tests. 2017-02-12 18:40:39 +01:00
Patrick Kostjens
bd1672fd7b Use Docker volume for mysql data storage 2017-02-12 18:07:48 +01:00
James Cole
2c36820622 New tests 2017-02-12 17:58:16 +01:00
Patrick Kostjens
ff1d1e5b8f Revert docker-compose to development version and create separate production file 2017-02-12 17:55:56 +01:00
James Cole
de0371dd1c New translations 2017-02-12 17:51:53 +01:00
James Cole
d6f4bbf4bc New translations 2017-02-12 17:51:44 +01:00
James Cole
5fc1e6ad64 New translations 2017-02-12 17:51:37 +01:00
James Cole
c37d772759 New translations 2017-02-12 17:51:32 +01:00
James Cole
fe2efd88cf New translations 2017-02-12 17:51:21 +01:00
James Cole
5a2f48f529 Approved. Step name: Proofread 2017-02-12 17:51:16 +01:00
James Cole
4459d09a90 New translations 2017-02-12 17:51:10 +01:00
James Cole
79fcd874f7 New translations 2017-02-12 17:51:00 +01:00
James Cole
643655a612 New translations 2017-02-12 17:50:54 +01:00
James Cole
adb0717ade New translations 2017-02-12 17:50:50 +01:00
Patrick Kostjens
1feae802c2 Use local folders in containers created by docker-compose to persist data 2017-02-12 17:30:24 +01:00
James Cole
ec146d4cbe Make sure the /javascript/ url’s are ignored. 2017-02-12 16:50:35 +01:00
James Cole
3399b133ae New user controller tests. 2017-02-12 13:23:08 +01:00
James Cole
1637190c27 Fix various tests. 2017-02-12 13:15:23 +01:00
James Cole
79f94771c3 Make tests compatible with laravel 5.4 2017-02-12 12:32:13 +01:00
James Cole
018af62826 First set of new tests. 2017-02-12 12:21:44 +01:00
James Cole
69bd292ed8 Initial set of empty controller tests 2017-02-12 12:00:11 +01:00
James Cole
ac63a082aa Update attachment controller test. 2017-02-12 11:53:04 +01:00
James Cole
e15bb05823 New test for attachments. 2017-02-12 11:47:22 +01:00
James Cole
5528663727 Re-implemented basic account controller tests. 2017-02-12 11:25:17 +01:00
James Cole
1a204d31e7 Small fix for opening balance issues in reports. 2017-02-12 10:58:37 +01:00
James Cole
0fe4273d4d Merge pull request #560 from elamperti/fix-smooth-curves
Fix smooth curves around data points in graphs
2017-02-12 08:42:51 +01:00
Enrico Lamperti
abf0fdcf35 Fix smooth curves in graphs 2017-02-11 17:38:04 -03:00
James Cole
78074a5a54 Code for #553 2017-02-11 18:38:38 +01:00
James Cole
dcc2b9c1cb This fixes #559 2017-02-11 18:35:16 +01:00
James Cole
b5a005dcc5 Better 404 page [skip ci] 2017-02-11 16:32:03 +01:00
James Cole
4c2d9e0eee Small code cleanup. 2017-02-11 15:52:55 +01:00
James Cole
fb73baca6a Merge pull request #558 from crash7/improve-docker
Improve docker support
2017-02-11 10:13:51 +01:00
James Cole
0be3dd4fe4 Add EOF 2017-02-11 10:12:11 +01:00
James Cole
8e89899070 Add EOF 2017-02-11 10:11:57 +01:00
James Cole
5e47492318 Clean up budget report partial 2017-02-11 10:05:58 +01:00
James Cole
aa2d78f36a Expand filter 2017-02-11 09:34:04 +01:00
Christian Musa
0cbed2d5d2 Improve docker support
- Add docker-compose file
- Add environment variable to initialize the database
- Add custom entrypoint that generates the .env file based on the environment variables
- Update Dockerfile (gettext-base package)
2017-02-11 00:36:38 -03:00
James Cole
3914796e4e Experimental new transfer filter. 2017-02-10 17:21:44 +01:00
James Cole
b9dac5ff55 Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop
* 'develop' of https://github.com/firefly-iii/firefly-iii:
  Update config.php, see #521
2017-02-08 22:24:20 +01:00
James Cole
1285a88660 Different value for title field [skip ci] 2017-02-08 22:07:47 +01:00
James Cole
96e0d4e29f Translated 2017-02-06 13:20:57 +01:00
James Cole
9bb8a9ccd1 New translations 2017-02-06 13:20:54 +01:00
James Cole
d9611bd84f New translations 2017-02-06 13:20:51 +01:00
James Cole
915afa4534 Translated 2017-02-06 13:20:47 +01:00
James Cole
5105c94233 New translations 2017-02-06 13:12:31 +01:00
James Cole
899d4fe611 New translations 2017-02-06 13:12:04 +01:00
James Cole
d45a12e544 New translations 2017-02-06 13:11:44 +01:00
James Cole
302fc876d9 Translated 2017-02-06 13:11:28 +01:00
James Cole
f6a25db17c New translations 2017-02-06 13:11:26 +01:00
James Cole
da11303539 New translations 2017-02-06 13:11:25 +01:00
James Cole
07ebe71839 New translations 2017-02-06 13:11:23 +01:00
James Cole
eba9c4e039 New translations 2017-02-06 13:11:12 +01:00
James Cole
7d80120611 Approved. Step name: Proofread 2017-02-06 08:32:09 +01:00
James Cole
f2ea5fb253 New translations 2017-02-06 08:31:57 +01:00
James Cole
451ab6c531 New translations 2017-02-06 08:31:48 +01:00
James Cole
796b63fcc5 New translations 2017-02-06 08:31:42 +01:00
James Cole
7d8b3e6513 New translations 2017-02-06 08:31:40 +01:00
James Cole
b2026106ec Update config.php, see #521 2017-02-06 08:29:18 +01:00
James Cole
dba92d73c4 Include new line at the end of the file. 2017-02-05 19:51:58 +01:00
James Cole
b09a250a03 Better link for issues. [skip ci] 2017-02-05 18:50:19 +01:00
James Cole
c6f69f63fc Friendly error message. [skip ci] 2017-02-05 18:49:13 +01:00
James Cole
3a7faa7368 Small fixes for laravel 5.4 2017-02-05 18:44:37 +01:00
James Cole
f863c01a1d Merge laravel 5.4 into develop. 2017-02-05 16:20:02 +01:00
James Cole
8a98204a69 Update app() calls 2017-02-05 16:16:15 +01:00
James Cole
77e52f42a6 Update export routine. 2017-02-05 16:14:23 +01:00
James Cole
704c0922e8 Update collector classes 2017-02-05 15:58:55 +01:00
James Cole
371ce37be4 Update export classes 2017-02-05 15:58:42 +01:00
James Cole
152fb3f885 Update the last providers. 2017-02-05 15:58:27 +01:00
James Cole
3ff83cd431 Remove speed trap. 2017-02-05 15:43:56 +01:00
James Cole
a9d5b6ef92 Update to laravel 5.4 style tests 2017-02-05 15:42:00 +01:00
James Cole
229f718754 Update Composer files. 2017-02-05 15:41:41 +01:00
James Cole
646b65918d Remove tests since they’ve been changed in Laravel 5.4. 2017-02-05 15:41:23 +01:00
James Cole
5e596a9cb7 Remove speedtrap from oh-unit file. 2017-02-05 08:47:37 +01:00
James Cole
353db6c4a5 Updated composer.lock file. 2017-02-05 08:35:17 +01:00
James Cole
959a1a08f0 Tell view whether we’re in Sandstorm.IO mode. 2017-02-05 08:27:23 +01:00
James Cole
3e510bd3f6 This fixes #549 2017-02-05 08:26:54 +01:00
James Cole
b68d5c4374 Include CSRF token for Sandstorm. 2017-02-04 09:02:07 +01:00
James Cole
dc348a72c8 Various new scripts to improve sandstorm.io experience. 2017-02-04 08:42:06 +01:00
James Cole
5e5d4eca4b Update some sandstorm.io files. 2017-02-04 03:22:19 +01:00
James Cole
96b5d174d1 Initial code base for Sandstorm.IO support. Very beta. 2017-02-04 03:04:55 +01:00
James Cole
df1da32745 Update composer [skip ci] 2017-02-04 02:26:16 +01:00
James Cole
a7c198048e Add app log method. [skip ci] 2017-02-04 02:20:17 +01:00
James Cole
e3599c002b Updated contribution instructions [skip ci] 2017-02-04 02:19:47 +01:00
James Cole
094f6a7476 Merge branch 'release/4.3.4' 2017-02-02 20:55:46 +01:00
James Cole
c3b4849fa0 Various updates for upcoming release 4.3.4 2017-02-02 20:55:01 +01:00
James Cole
dfd6c5379c Merge pull request #546 from firefly-iii/l10n_develop
New Crowdin translations
2017-02-02 20:41:47 +01:00
James Cole
9aa53c11e0 This fixes #550 2017-02-02 20:37:39 +01:00
James Cole
b0d93621a8 This fixes #551 2017-02-02 20:36:32 +01:00
James Cole
a337d9a599 New route for JS file, may fix #550 2017-02-02 07:36:57 +01:00
James Cole
615d90c8f4 Update various service providers. 2017-02-02 07:35:53 +01:00
James Cole
7ffd77dc76 Translated 2017-01-31 01:17:32 +01:00
James Cole
96fdf4fd93 Translated 2017-01-31 01:17:29 +01:00
James Cole
27b8ce0f7f Translated 2017-01-31 01:17:27 +01:00
James Cole
e057c4d79c Removed reference to crud service provider. 2017-01-30 17:29:18 +01:00
James Cole
8263fa41dd Rewrote currency and export/import job service provider 2017-01-30 17:29:05 +01:00
James Cole
eeae4d215d Removed old service provider. 2017-01-30 17:20:00 +01:00
James Cole
646ed0d4dd Rewrote attachment, budget and category service providers. 2017-01-30 17:19:51 +01:00
James Cole
ac54032f55 Need to call everything from collector to work. 2017-01-30 17:10:23 +01:00
James Cole
3aaf356054 Rewrote bill service provider 2017-01-30 17:10:08 +01:00
James Cole
2c786e6a38 Small fixes to collector because constructor is gone. 2017-01-30 17:09:44 +01:00
James Cole
355baa7fef Rewrote account service provider. 2017-01-30 16:59:55 +01:00
James Cole
01468c2663 Rewrote journal service provider 2017-01-30 16:58:10 +01:00
James Cole
c7341c9194 Also extend collector. 2017-01-30 16:57:00 +01:00
James Cole
1e947870a6 Remove all constructors. 2017-01-30 16:46:30 +01:00
James Cole
311c1a3c84 Implement all setUser methods. 2017-01-30 16:42:58 +01:00
James Cole
84e380e4d0 Give all repositories a new setUser function. 2017-01-30 16:40:49 +01:00
James Cole
4cad2eb0c4 Upgraded validator 2017-01-30 16:35:41 +01:00
James Cole
4bc3af7176 Updated composer.lock file for change to bread crumbs. 2017-01-30 16:35:31 +01:00
James Cole
e80298f815 Include laravel bread crumbs and custom repository. 2017-01-30 16:31:41 +01:00
James Cole
14971cf249 Overrule logging. 2017-01-30 16:30:35 +01:00
James Cole
b79dcd7f23 Disable ConfigureLogging class. 2017-01-30 16:27:33 +01:00
James Cole
395aaad9c6 New class name. 2017-01-30 16:21:01 +01:00
James Cole
29f763d4e4 Update composer files. 2017-01-30 16:20:23 +01:00
James Cole
2f943c91d2 New contributing guidelines [skip ci] 2017-01-30 14:13:52 +01:00
James Cole
91c96311de Expand contributing guidelines. [skip ci] 2017-01-30 11:41:39 +01:00
James Cole
0f929faa16 Merge branch 'release/4.3.3' 2017-01-30 11:18:29 +01:00
James Cole
7a40c34cf0 New change log. 2017-01-30 11:18:02 +01:00
James Cole
462d987de9 Merge pull request #532 from firefly-iii/l10n_develop
New Crowdin translations
2017-01-30 11:11:36 +01:00
James Cole
f64e8d8973 Composer update. [skip ci] 2017-01-30 11:10:34 +01:00
James Cole
21222eb697 Mention new version. 2017-01-30 10:33:44 +01:00
James Cole
e47d6fb3ac Move default option to bottom. 2017-01-30 10:33:18 +01:00
James Cole
c7fc10ac89 Remove debug statements. 2017-01-30 08:32:16 +01:00
James Cole
e8b528f520 New translations 2017-01-29 22:05:43 +01:00
James Cole
b22de7bf70 New translations 2017-01-29 22:05:38 +01:00
James Cole
ec119c8f6e Translated 2017-01-29 21:55:32 +01:00
James Cole
a20b38598e New translations 2017-01-29 21:45:32 +01:00
James Cole
aa0eb47205 New translations 2017-01-29 21:35:31 +01:00
James Cole
723db9d71e New translations 2017-01-29 13:36:21 +01:00
James Cole
1d8dc3d65d Approved. Step name: Proofread 2017-01-24 16:17:57 +01:00
James Cole
fe2716876a New translations 2017-01-24 15:44:55 +01:00
James Cole
fac0e97e5d New translations 2017-01-24 15:44:27 +01:00
James Cole
449d009c28 New translations 2017-01-24 15:43:49 +01:00
James Cole
55b2e6fe25 New translations 2017-01-24 15:43:36 +01:00
James Cole
9989b3b9da New translations 2017-01-24 15:43:27 +01:00
James Cole
7ab1cbfc1f New translations 2017-01-24 15:43:13 +01:00
James Cole
62d19c3902 New translations 2017-01-24 15:42:34 +01:00
James Cole
19700e7ee3 New translations 2017-01-24 15:42:08 +01:00
James Cole
de3e8edd6d New translations 2017-01-24 15:41:44 +01:00
James Cole
deda48af4a New translations 2017-01-24 15:41:32 +01:00
James Cole
7688d7c619 Include trigger that responds to tags 2017-01-24 15:38:41 +01:00
James Cole
76328b5c45 New translations 2017-01-24 15:11:51 +01:00
James Cole
1de17bf06f New translations 2017-01-24 15:11:31 +01:00
James Cole
6724daf995 New translations 2017-01-24 15:11:11 +01:00
James Cole
7caca053a1 New translations 2017-01-24 15:10:54 +01:00
James Cole
ae1bf8c017 New translations 2017-01-24 15:10:33 +01:00
James Cole
d20b0da438 Approved. Step name: Proofread 2017-01-24 15:10:11 +01:00
James Cole
a0218d7df1 New translations 2017-01-24 15:09:55 +01:00
James Cole
5ae5d67b91 New translations 2017-01-24 15:09:39 +01:00
James Cole
8493ed7603 New translations 2017-01-24 15:09:28 +01:00
James Cole
804b681d40 New translations 2017-01-24 15:09:18 +01:00
James Cole
e8303bd059 Expand the multi-select to various other fields. 2017-01-24 15:07:01 +01:00
James Cole
ac6c5d4e32 New translations 2017-01-24 13:57:08 +01:00
James Cole
90b0d0d52c New translations 2017-01-24 13:37:12 +01:00
James Cole
4093bdbd3e New translations 2017-01-24 13:37:08 +01:00
James Cole
a2097cf981 New translations 2017-01-24 13:27:14 +01:00
James Cole
6a33d0c9dc New translations 2017-01-24 13:27:07 +01:00
James Cole
525d5fb427 New translations 2017-01-24 13:17:40 +01:00
James Cole
e4946b8cd5 New translations 2017-01-24 13:17:35 +01:00
James Cole
76b32df622 Remove nightly. 2017-01-24 12:33:16 +01:00
James Cole
bc1079364d This should fix the nightly. No more hhvm. 2017-01-24 12:24:02 +01:00
James Cole
8602febe9d If/then thing for HHVM 2017-01-24 12:15:52 +01:00
James Cole
d55dfe27dc Updated test script 2017-01-24 12:08:06 +01:00
James Cole
90c16e2a07 Update travis.yml. 2017-01-24 11:49:05 +01:00
James Cole
149c1cd9b1 Approved. Step name: Proofread 2017-01-24 08:17:31 +01:00
James Cole
20f1a43369 Approved. Step name: Proofread 2017-01-24 08:17:20 +01:00
James Cole
e8fb8f993d Approved. Step name: Proofread 2017-01-24 08:07:14 +01:00
James Cole
f0c782dc01 New translations 2017-01-24 08:03:02 +01:00
James Cole
50c13e6d20 New translations 2017-01-24 08:02:44 +01:00
James Cole
69bedd035f New translations 2017-01-24 08:02:30 +01:00
James Cole
85337f0a31 New translations 2017-01-24 08:02:22 +01:00
James Cole
f8a7e2f98e New translations 2017-01-24 08:02:15 +01:00
James Cole
ec90a49d43 New translations 2017-01-24 08:02:07 +01:00
James Cole
5812b150c6 New translations 2017-01-24 08:01:45 +01:00
James Cole
c7ebc7273f Translated 2017-01-24 08:01:36 +01:00
James Cole
5226c87304 Translated 2017-01-24 08:01:35 +01:00
James Cole
25dd1c5d35 New translations 2017-01-24 08:01:31 +01:00
James Cole
c5a9e5e56d New translations 2017-01-24 08:01:26 +01:00
James Cole
47ed70d671 New translations 2017-01-24 08:01:20 +01:00
James Cole
cb5526f469 New translations 2017-01-24 08:01:14 +01:00
James Cole
a4f128077f New translations 2017-01-24 08:01:10 +01:00
James Cole
7140ba76d5 Small language things [skip ci] 2017-01-24 07:53:46 +01:00
James Cole
872e8f2de6 Hip new multi select. 2017-01-24 07:37:29 +01:00
James Cole
6c14e9d083 No sleep for the wicked [skip ci] 2017-01-24 07:26:06 +01:00
James Cole
e4b1812b46 Fix small layout thing [skip ci] 2017-01-23 18:03:17 +01:00
James Cole
1c2c6bb1d0 Various small changes. 2017-01-22 11:23:56 +01:00
James Cole
baefd4f93b Two new rule triggers 2017-01-22 11:23:40 +01:00
James Cole
4270fe07ab Rules now have auto-complete. 2017-01-22 09:15:53 +01:00
James Cole
e4ae925d2b Include typeahead [skip ci] 2017-01-21 13:34:41 +01:00
James Cole
dc599361a4 Removed unused method. 2017-01-21 09:15:33 +01:00
James Cole
738a311f49 Various code cleanup. 2017-01-21 09:07:10 +01:00
James Cole
71f6ba3418 Make request code more uniform. 2017-01-21 08:32:23 +01:00
James Cole
d1d573c408 Fix some tests. 2017-01-20 19:50:32 +01:00
James Cole
50e39a4a75 Update rule controller to have some auto complete functionality. 2017-01-20 19:50:22 +01:00
James Cole
8635fe7ebb Update requests to use uniform methods. 2017-01-20 19:49:35 +01:00
James Cole
6b57d4397a Try with “true” instead of “1”. 2017-01-20 16:27:30 +01:00
James Cole
8f2b898b2b Update some tests. 2017-01-20 16:22:19 +01:00
James Cole
0d1d360d18 Can now clone transaction #538. Wasn’t that difficult. 2017-01-20 12:23:52 +01:00
James Cole
def3b3a155 Fix for #539 2017-01-20 12:23:09 +01:00
James Cole
d344512743 Update update and installation instructions. 2017-01-20 10:08:38 +01:00
James Cole
19eef71133 Make sure all date fields have a fallback. 2017-01-20 08:18:52 +01:00
James Cole
61d58a354e Various code cleanup. 2017-01-20 08:03:26 +01:00
James Cole
be868d37f2 Fixed some issues with the monthly report and missing amounts. 2017-01-19 21:54:27 +01:00
James Cole
20bb151cf3 Add updated_at value. 2017-01-18 07:28:49 +01:00
James Cole
77f889aba6 Include a batch of naughty strings to see what happens to Firefly. 2017-01-16 20:10:47 +01:00
James Cole
1e69a54972 Small JS issue. [skip ci] 2017-01-15 20:18:32 +01:00
James Cole
6b7a47ca28 Clean up JS. 2017-01-15 20:10:34 +01:00
James Cole
c3fdd3b5f7 Allow date picker for browsers that do not support it natively. See issue #535 2017-01-15 20:05:40 +01:00
James Cole
e9f2121667 Fix menu in Firefox. 2017-01-15 19:45:57 +01:00
James Cole
161e9e1e11 Final JS cleanup. 2017-01-15 19:28:54 +01:00
James Cole
e336a45f79 Edit JS file for split transaction 2017-01-15 19:16:46 +01:00
James Cole
9c09f93908 Update views and JS for delete (single) transaction. 2017-01-15 19:08:16 +01:00
James Cole
582398e7f6 Update views and JS for create (single) transaction. 2017-01-15 19:07:31 +01:00
James Cole
b118635abd Update views and JS for edit single transaction. 2017-01-15 19:00:06 +01:00
James Cole
ac0d4a75b5 Removed forgotten twig comment [skip ci] 2017-01-15 15:46:58 +01:00
James Cole
c212d5c5ea Order by date does not matter in this context. 2017-01-14 21:00:43 +01:00
James Cole
08ac27cccf Fix some scrutiniser issues. 2017-01-14 19:43:33 +01:00
James Cole
0b5cab99cf Fix some scrutiniser issues. 2017-01-14 18:52:52 +01:00
James Cole
cc0057cc56 Rename command [skip ci] 2017-01-14 17:24:30 +01:00
James Cole
1ce49b814b Fix rounding. [skip ci] 2017-01-14 17:23:47 +01:00
James Cole
5bbaaece38 Encryption is optional (but on by default) and a command to switch from one to the other 2017-01-14 17:13:57 +01:00
James Cole
30bc4ccfa7 More date fixes [skip ci] 2017-01-13 21:16:54 +01:00
James Cole
4f64f1d754 Force order by. [skip ci] 2017-01-13 21:14:46 +01:00
James Cole
c0e578dd47 Fix bug found by persistent user who kept mailing me about broken charts. Which turned out to be broken indeed! 2017-01-13 21:12:59 +01:00
James Cole
2b82fca2cf Small various bugs. 2017-01-13 20:48:51 +01:00
James Cole
f0028b33e9 Double check that deleted transaction journals are not included. 2017-01-13 16:12:09 +01:00
James Cole
7ddea23375 Merge branch 'master' into develop
* master:
  add firefly locales to Dockerfile fixes #521 for docker environment
  Code for 4.1.6
2017-01-12 20:58:06 +01:00
James Cole
83edccacc6 Delete CONTRIBUTING 2017-01-12 09:40:12 +01:00
James Cole
75e95d6452 With markdown 2017-01-12 09:39:53 +01:00
James Cole
423bb4bbcd Better layout 2017-01-12 09:37:12 +01:00
James Cole
43585c563c Merge pull request #534 from elohmeier/master
add firefly locales to Dockerfile
2017-01-12 08:48:58 +01:00
Enno Lohmeier
2564a41d05 add firefly locales to Dockerfile
fixes #521 for docker environment
2017-01-12 00:30:33 +01:00
James Cole
a0bb1e3625 CSS fix for #533 2017-01-10 19:55:52 +01:00
James Cole
9b4fd57f51 Optimize new JS code. 2017-01-10 18:35:00 +01:00
James Cole
e67709e339 Make index significantly simpler. 2017-01-10 18:25:03 +01:00
James Cole
0c4e913f30 New translations 2017-01-10 13:06:37 +01:00
James Cole
c6de0e51c7 New translations 2017-01-10 13:06:29 +01:00
James Cole
69e85adadf New translations 2017-01-10 12:54:39 +01:00
James Cole
b34068207f New translations 2017-01-10 12:54:32 +01:00
James Cole
68b7b4b3a4 New translations 2017-01-10 12:45:24 +01:00
James Cole
5e3ee30e66 New translations 2017-01-10 12:45:15 +01:00
James Cole
aaf7d12b46 New translations 2017-01-10 12:45:12 +01:00
James Cole
729a348657 New translations 2017-01-10 12:36:17 +01:00
585 changed files with 27194 additions and 13214 deletions

55
.env.docker Normal file
View File

@@ -0,0 +1,55 @@
APP_ENV=${FF_APP_ENV}
APP_DEBUG=false
APP_FORCE_SSL=false
APP_FORCE_ROOT=
APP_KEY=${FF_APP_KEY}
APP_LOG=daily
APP_LOG_LEVEL=warning
APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=${FF_DB_HOST}
DB_PORT=3306
DB_DATABASE=${FF_DB_NAME}
DB_USERNAME=${FF_DB_USER}
DB_PASSWORD=${FF_DB_PASSWORD}
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
COOKIE_PATH="/"
COOKIE_DOMAIN=
COOKIE_SECURE=false
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_FROM=changeme@example.com
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=true
SHOW_INCOMPLETE_TRANSLATIONS=false
CACHE_PREFIX=firefly
GOOGLE_MAPS_API_KEY=
ANALYTICS_ID=
SITE_OWNER=mail@example.com
USE_ENCRYPTION=true
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_APP_ID=
DEMO_USERNAME=
DEMO_PASSWORD=

View File

@@ -3,6 +3,7 @@ APP_DEBUG=false
APP_FORCE_SSL=false
APP_FORCE_ROOT=
APP_KEY=SomeRandomStringOf32CharsExactly
APP_LOG=daily
APP_LOG_LEVEL=warning
APP_URL=http://localhost
@@ -43,6 +44,7 @@ CACHE_PREFIX=firefly
GOOGLE_MAPS_API_KEY=
ANALYTICS_ID=
SITE_OWNER=mail@example.com
USE_ENCRYPTION=true
PUSHER_KEY=
PUSHER_SECRET=

55
.env.sandstorm Executable file
View File

@@ -0,0 +1,55 @@
APP_ENV=production
APP_DEBUG=true
APP_FORCE_SSL=false
APP_FORCE_ROOT=
APP_KEY=SomeRandomStringOf32CharsExactly
APP_LOG=syslog
APP_LOG_LEVEL=debug
APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=firefly
DB_USERNAME=firefly
DB_PASSWORD=firefly
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
COOKIE_PATH="/"
COOKIE_DOMAIN=
COOKIE_SECURE=false
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_FROM=changeme@example.com
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=true
SHOW_INCOMPLETE_TRANSLATIONS=false
CACHE_PREFIX=firefly
GOOGLE_MAPS_API_KEY=
ANALYTICS_ID=
SITE_OWNER=mail@example.com
USE_ENCRYPTION=true
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_APP_ID=
DEMO_USERNAME=
DEMO_PASSWORD=

View File

@@ -1 +0,0 @@
If you are requesting a new feature, please check out the list of [often requested features](https://firefly-iii.github.io/requested-features/) first. Thanks!

23
.github/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,23 @@
# Welcome to Firefly III on Github!
:+1::tada: Thank you for taking the time to contribute something to Firefly III!
## Feature requests
If you are requesting a new feature, please check out the list of [often requested features](https://firefly-iii.github.io/requested-features/).
## Bugs
If you find a bug, please take the time and see if the [demo site](https://firefly-iii.nder.be/) is also suffering from this bug. Include as many log files and details as you think are necessary.
## Installation problems
Take the time to read the [installation guide FAQ](https://firefly-iii.github.io/installation-guide-faq/) and make sure you search through closed issues for the problems other people have had. Your problem may be among them!
## Pull requests
I can only accept pull requests against the `develop` branch, never the `master` branch.
## Translations :us: :fr: :de:
If you see a spelling error, grammatical error or a weird translation in your language, please join [our CrowdIn](https://crowdin.com/project/firefly-iii) project. There, you can submit your translations and fixes. The GitHub repository will download these automatically and they will be included in the next release.

7
.gitignore vendored
View File

@@ -1,14 +1,7 @@
/node_modules
/public/storage
/vendor
/.idea
Homestead.json
Homestead.yaml
.env
_development
.env.local
result.html
test-import.sh
test-import-report.txt
public/google*.html
.env.backup

5
.sandstorm/.gitattributes vendored Normal file
View File

@@ -0,0 +1,5 @@
# vagrant-spk creates shell scripts, which must end in \n, even on a \r\n system.
*.sh text eol=lf

5
.sandstorm/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
# This file stores a list of sub-paths of .sandstorm/ that should be ignored by git.
.vagrant

103
.sandstorm/Vagrantfile vendored Normal file
View File

@@ -0,0 +1,103 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Guess at a reasonable name for the VM based on the folder vagrant-spk is
# run from. The timestamp is there to avoid conflicts if you have multiple
# folders with the same name.
VM_NAME = File.basename(File.dirname(File.dirname(__FILE__))) + "_sandstorm_#{Time.now.utc.to_i}"
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# Base on the Sandstorm snapshots of the official Debian 8 (jessie) box.
config.vm.box = "sandstorm/debian-jessie64"
if Vagrant.has_plugin?("vagrant-vbguest") then
# vagrant-vbguest is a Vagrant plugin that upgrades
# the version of VirtualBox Guest Additions within each
# guest. If you have the vagrant-vbguest plugin, then it
# needs to know how to compile kernel modules, etc., and so
# we give it this hint about operating system type.
config.vm.guest = "debian"
end
# We forward port 6080, the Sandstorm web port, so that developers can
# visit their sandstorm app from their browser as local.sandstorm.io:6080
# (aka 127.0.0.1:6080).
config.vm.network :forwarded_port, guest: 6080, host: 6080
# Use a shell script to "provision" the box. This installs Sandstorm using
# the bundled installer.
config.vm.provision "shell", inline: "sudo bash /opt/app/.sandstorm/global-setup.sh", keep_color: true
# Then, do stack-specific and app-specific setup.
config.vm.provision "shell", inline: "sudo bash /opt/app/.sandstorm/setup.sh", keep_color: true
# Shared folders are configured per-provider since vboxsf can't handle >4096 open files,
# NFS requires privilege escalation every time you bring a VM up,
# and 9p is only available on libvirt.
# Calculate the number of CPUs and the amount of RAM the system has,
# in a platform-dependent way; further logic below.
cpus = nil
total_kB_ram = nil
host = RbConfig::CONFIG['host_os']
if host =~ /darwin/
cpus = `sysctl -n hw.ncpu`.to_i
total_kB_ram = `sysctl -n hw.memsize`.to_i / 1024
elsif host =~ /linux/
cpus = `nproc`.to_i
total_kB_ram = `grep MemTotal /proc/meminfo | awk '{print $2}'`.to_i
elsif host =~ /mingw/
# powershell may not be available on Windows XP and Vista, so wrap this in a rescue block
begin
cpus = `powershell -Command "(Get-WmiObject Win32_Processor -Property NumberOfLogicalProcessors | Select-Object -Property NumberOfLogicalProcessors | Measure-Object NumberOfLogicalProcessors -Sum).Sum"`.to_i
total_kB_ram = `powershell -Command "Get-CimInstance -class cim_physicalmemory | % $_.Capacity}"`.to_i / 1024
rescue
end
end
# Use the same number of CPUs within Vagrant as the system, with 1
# as a default.
#
# Use at least 512MB of RAM, and if the system has more than 2GB of
# RAM, use 1/4 of the system RAM. This seems a reasonable compromise
# between having the Vagrant guest operating system not run out of
# RAM entirely (which it basically would if we went much lower than
# 512MB) and also allowing it to use up a healthily large amount of
# RAM so it can run faster on systems that can afford it.
if cpus.nil? or cpus.zero?
cpus = 1
end
if total_kB_ram.nil? or total_kB_ram < 2048000
assign_ram_mb = 512
else
assign_ram_mb = (total_kB_ram / 1024 / 4)
end
# Actually apply these CPU/memory values to the providers.
config.vm.provider :virtualbox do |vb, override|
vb.cpus = cpus
vb.memory = assign_ram_mb
vb.name = VM_NAME
vb.customize ["modifyvm", :id, "--nictype1", "Am79C973"]
# /opt/app and /host-dot-sandstorm are used by vagrant-spk
override.vm.synced_folder "..", "/opt/app"
override.vm.synced_folder ENV["HOME"] + "/.sandstorm", "/host-dot-sandstorm"
# /vagrant is not used by vagrant-spk; we need this line so it gets disabled; if we removed the
# line, vagrant would automatically insert a synced folder in /vagrant, which is not what we want.
override.vm.synced_folder "..", "/vagrant", disabled: true
end
config.vm.provider :libvirt do |libvirt, override|
libvirt.cpus = cpus
libvirt.memory = assign_ram_mb
libvirt.default_prefix = VM_NAME
# /opt/app and /host-dot-sandstorm are used by vagrant-spk
override.vm.synced_folder "..", "/opt/app", type: "9p", accessmode: "passthrough"
override.vm.synced_folder ENV["HOME"] + "/.sandstorm", "/host-dot-sandstorm", type: "9p", accessmode: "passthrough"
# /vagrant is not used by vagrant-spk; we need this line so it gets disabled; if we removed the
# line, vagrant would automatically insert a synced folder in /vagrant, which is not what we want.
override.vm.synced_folder "..", "/vagrant", type: "9p", accessmode: "passthrough", disabled: true
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

21
.sandstorm/build.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
# Checks if there's a composer.json, and if so, installs/runs composer.
# This script only runs once, when the app connects to sandstorm.
set -euo pipefail
cd /opt/app
cp .env.sandstorm .env
if [ -f /opt/app/composer.json ] ; then
if [ ! -f composer.phar ] ; then
curl -sS https://getcomposer.org/installer | php
fi
php composer.phar install --no-dev --no-suggest
fi
# link storage folder
rm -rf /opt/app/storage
ln -s /var/storage /opt/app

3
.sandstorm/changelog.md Normal file
View File

@@ -0,0 +1,3 @@
# 3.4.3
* Initial release on Sandstorm.io

View File

@@ -0,0 +1,3 @@
"Firefly III" is a financial manager. It can help you keep track of expenses, income, budgets and everything in between. It even supports credit cards, shared household accounts and savings accounts! Its pretty fancy. You should use it to save and organise money.
Firefly works on the principle that if you know where youre money is going, you can stop it from going there.

44
.sandstorm/global-setup.sh Executable file
View File

@@ -0,0 +1,44 @@
#!/bin/bash
set -euo pipefail
# Set options for curl. Since we only want to show errors from these curl commands, we also use
# 'cat' to buffer the output; for more information:
# https://github.com/sandstorm-io/vagrant-spk/issues/158
CURL_OPTS="--silent --show-error"
echo localhost > /etc/hostname
hostname localhost
# The following line copies stderr through stderr to cat without accidentally leaving it in the
# output file. Be careful when changing. See: https://github.com/sandstorm-io/vagrant-spk/pull/159
curl $CURL_OPTS https://install.sandstorm.io/ 2>&1 > /host-dot-sandstorm/caches/install.sh | cat
SANDSTORM_CURRENT_VERSION=$(curl $CURL_OPTS -f "https://install.sandstorm.io/dev?from=0&type=install")
SANDSTORM_PACKAGE="sandstorm-$SANDSTORM_CURRENT_VERSION.tar.xz"
if [[ ! -f /host-dot-sandstorm/caches/$SANDSTORM_PACKAGE ]] ; then
echo -n "Downloading Sandstorm version ${SANDSTORM_CURRENT_VERSION}..."
curl $CURL_OPTS --output "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE.partial" "https://dl.sandstorm.io/$SANDSTORM_PACKAGE" 2>&1 | cat
mv "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE.partial" "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE"
echo "...done."
fi
if [ ! -e /opt/sandstorm/latest/sandstorm ] ; then
echo -n "Installing Sandstorm version ${SANDSTORM_CURRENT_VERSION}..."
bash /host-dot-sandstorm/caches/install.sh -d -e "/host-dot-sandstorm/caches/$SANDSTORM_PACKAGE" >/dev/null
echo "...done."
fi
modprobe ip_tables
# Make the vagrant user part of the sandstorm group so that commands like
# `spk dev` work.
usermod -a -G 'sandstorm' 'vagrant'
# Bind to all addresses, so the vagrant port-forward works.
sudo sed --in-place='' \
--expression='s/^BIND_IP=.*/BIND_IP=0.0.0.0/' \
/opt/sandstorm/sandstorm.conf
sudo service sandstorm restart
# Enable apt-cacher-ng proxy to make things faster if one appears to be running on the gateway IP
GATEWAY_IP=$(ip route | grep ^default | cut -d ' ' -f 3)
if nc -z "$GATEWAY_IP" 3142 ; then
echo "Acquire::http::Proxy \"http://$GATEWAY_IP:3142\";" > /etc/apt/apt.conf.d/80httpproxy
fi
# Configure apt to retry fetching things that fail to download.
echo "APT::Acquire::Retries \"10\";" > /etc/apt/apt.conf.d/80sandstorm-retry

62
.sandstorm/launcher.sh Executable file
View File

@@ -0,0 +1,62 @@
#!/bin/bash
# Runs every time we create a new grain!
# Create a bunch of folders under the clean /var that php, nginx, and mysql expect to exist
mkdir -p /var/lib/mysql
mkdir -p /var/lib/nginx
mkdir -p /var/lib/php/sessions/
mkdir -p /var/log
mkdir -p /var/log/mysql
mkdir -p /var/log/nginx
# Wipe /var/run, since pidfiles and socket files from previous launches should go away
# TODO someday: I'd prefer a tmpfs for these.
rm -rf /var/run
mkdir -p /var/run
rm -rf /var/tmp
mkdir -p /var/tmp
mkdir -p /var/run/mysqld
# make storage directories
rm -rf /var/storage
mkdir -p /var/storage/app/public
mkdir -p /var/storage/build
mkdir -p /var/storage/database
mkdir -p /var/storage/debugbar
mkdir -p /var/storage/export
mkdir -p /var/storage/framework/cache
mkdir -p /var/storage/framework/sessions
mkdir -p /var/storage/framework/views
mkdir -p /var/storage/logs
mkdir -p /var/storage/upload
# Ensure mysql tables created
HOME=/etc/mysql /usr/bin/mysql_install_db --force
# Spawn mysqld, php
HOME=/etc/mysql /usr/sbin/mysqld &
/usr/sbin/php-fpm7.0 --nodaemonize --fpm-config /etc/php/7.0/fpm/php-fpm.conf &
# Wait until mysql and php have bound their sockets, indicating readiness
while [ ! -e /var/run/mysqld/mysqld.sock ] ; do
echo "waiting for mysql to be available at /var/run/mysqld/mysqld.sock"
sleep .5
done
while [ ! -e /var/run/php7.0-fpm.sock ] ; do
echo "waiting for php7.0-fpm to be available at /var/run/php7.0-fpm.sock"
sleep .5
done
echo "Installing database.."
# Install database for Firefly III
echo "CREATE DATABASE IF NOT EXISTS firefly; GRANT ALL on firefly.* TO 'firefly'@'localhost' IDENTIFIED BY 'firefly';" | mysql -uroot
echo "Done!"
echo "Migrating..."
php /opt/app/artisan migrate --seed --force
echo "Done!"
# Start nginx.
/usr/sbin/nginx -c /opt/app/.sandstorm/service-config/nginx.conf -g "daemon off;"

BIN
.sandstorm/pgp-keyring Normal file

Binary file not shown.

BIN
.sandstorm/pgp-signature Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,188 @@
@0x9411e6c8b3c8a4b6;
using Spk = import "/sandstorm/package.capnp";
# This imports:
# $SANDSTORM_HOME/latest/usr/include/sandstorm/package.capnp
# Check out that file to see the full, documented package definition format.
const pkgdef :Spk.PackageDefinition = (
# The package definition. Note that the spk tool looks specifically for the
# "pkgdef" constant.
id = "uws252ya9mep4t77tevn85333xzsgrpgth8q4y1rhknn1hammw70",
# Your app ID is actually its public key. The private key was placed in
# your keyring. All updates must be signed with the same key.
manifest = (
appTitle = (defaultText = "Firefly III"),
appVersion = 1,
appMarketingVersion = (defaultText = "3.4.6"),
actions = [
# Define your "new document" handlers here.
( nounPhrase = (defaultText = "administration"),
command = .myCommand
# The command to run when starting for the first time. (".myCommand"
# is just a constant defined at the bottom of the file.)
)
],
continueCommand = .myCommand,
# This is the command called to start your app back up after it has been
# shut down for inactivity. Here we're using the same command as for
# starting a new instance, but you could use different commands for each
# case.
metadata = (
icons = (
appGrid = (png = (dpi1x = embed "app-graphics/firefly-iii-128.png")),
grain = (png = (dpi1x = embed "app-graphics/firefly-iii-24.png",
dpi2x = embed "app-graphics/firefly-iii-48.png")),
market = (png = (dpi1x = embed "app-graphics/firefly-iii-150.png"))
),
website = "https://firefly-iii.github.io/",
codeUrl = "https://github.com/firefly-iii/firefly-iii",
#license = (openSource = mit),
license = (proprietary = (defaultText = embed "../LICENSE")),
# The license this package is distributed under. See
# https://docs.sandstorm.io/en/latest/developing/publishing-apps/#license
categories = [productivity],
# A list of categories/genres to which this app belongs, sorted with best fit first.
# See the list of categories at
# https://docs.sandstorm.io/en/latest/developing/publishing-apps/#categories
author = (
contactEmail = "thegrumpydictator@gmail.com",
upstreamAuthor = "James Cole",
pgpSignature = embed "pgp-signature",
),
pgpKeyring = embed "pgp-keyring",
description = (defaultText = embed "description.md"),
shortDescription = (defaultText = "Financial management"),
screenshots = [
# Screenshots to use for marketing purposes. Examples below.
# Sizes are given in device-independent pixels, so if you took these
# screenshots on a Retina-style high DPI screen, divide each dimension by two.
(width = 1200, height = 1000, png = embed "screenshots/screenshot-1.png"),
(width = 1200, height = 1000, png = embed "screenshots/screenshot-2.png"),
(width = 1200, height = 1518, png = embed "screenshots/screenshot-3.png"),
],
changeLog = (defaultText = embed "changelog.md"),
),
),
sourceMap = (
# Here we defined where to look for files to copy into your package. The
# `spk dev` command actually figures out what files your app needs
# automatically by running it on a FUSE filesystem. So, the mappings
# here are only to tell it where to find files that the app wants.
searchPath = [
( sourcePath = "." ), # Search this directory first.
( sourcePath = "/", # Then search the system root directory.
hidePaths = [ "home", "proc", "sys",
"etc/passwd", "etc/hosts", "etc/host.conf",
"etc/nsswitch.conf", "etc/resolv.conf" ]
# You probably don't want the app pulling files from these places,
# so we hide them. Note that /dev, /var, and /tmp are implicitly
# hidden because Sandstorm itself provides them.
)
]
),
fileList = "sandstorm-files.list",
# `spk dev` will write a list of all the files your app uses to this file.
# You should review it later, before shipping your app.
alwaysInclude = ["app","bootstrap","config","database","public","resources","routes"],
# Fill this list with more names of files or directories that should be
# included in your package, even if not listed in sandstorm-files.list.
# Use this to force-include stuff that you know you need but which may
# not have been detected as a dependency during `spk dev`. If you list
# a directory here, its entire contents will be included recursively.
#bridgeConfig = (
# # Used for integrating permissions and roles into the Sandstorm shell
# # and for sandstorm-http-bridge to pass to your app.
# # Uncomment this block and adjust the permissions and roles to make
# # sense for your app.
# # For more information, see high-level documentation at
# # https://docs.sandstorm.io/en/latest/developing/auth/
# # and advanced details in the "BridgeConfig" section of
# # https://github.com/sandstorm-io/sandstorm/blob/master/src/sandstorm/package.capnp
# viewInfo = (
# # For details on the viewInfo field, consult "ViewInfo" in
# # https://github.com/sandstorm-io/sandstorm/blob/master/src/sandstorm/grain.capnp
#
# permissions = [
# # Permissions which a user may or may not possess. A user's current
# # permissions are passed to the app as a comma-separated list of `name`
# # fields in the X-Sandstorm-Permissions header with each request.
# #
# # IMPORTANT: only ever append to this list! Reordering or removing fields
# # will change behavior and permissions for existing grains! To deprecate a
# # permission, or for more information, see "PermissionDef" in
# # https://github.com/sandstorm-io/sandstorm/blob/master/src/sandstorm/grain.capnp
# (
# name = "editor",
# # Name of the permission, used as an identifier for the permission in cases where string
# # names are preferred. Used in sandstorm-http-bridge's X-Sandstorm-Permissions HTTP header.
#
# title = (defaultText = "editor"),
# # Display name of the permission, e.g. to display in a checklist of permissions
# # that may be assigned when sharing.
#
# description = (defaultText = "grants ability to modify data"),
# # Prose describing what this role means, suitable for a tool tip or similar help text.
# ),
# ],
# roles = [
# # Roles are logical collections of permissions. For instance, your app may have
# # a "viewer" role and an "editor" role
# (
# title = (defaultText = "editor"),
# # Name of the role. Shown in the Sandstorm UI to indicate which users have which roles.
#
# permissions = [true],
# # An array indicating which permissions this role carries.
# # It should be the same length as the permissions array in
# # viewInfo, and the order of the lists must match.
#
# verbPhrase = (defaultText = "can make changes to the document"),
# # Brief explanatory text to show in the sharing UI indicating
# # what a user assigned this role will be able to do with the grain.
#
# description = (defaultText = "editors may view all site data and change settings."),
# # Prose describing what this role means, suitable for a tool tip or similar help text.
# ),
# (
# title = (defaultText = "viewer"),
# permissions = [false],
# verbPhrase = (defaultText = "can view the document"),
# description = (defaultText = "viewers may view what other users have written."),
# ),
# ],
# ),
# #apiPath = "/api",
# # Apps can export an API to the world. The API is to be used primarily by Javascript
# # code and native apps, so it can't serve out regular HTML to browsers. If a request
# # comes in to your app's API, sandstorm-http-bridge will prefix the request's path with
# # this string, if specified.
#),
);
const myCommand :Spk.Manifest.Command = (
# Here we define the command used to start up your server.
argv = ["/sandstorm-http-bridge", "8000", "--", "/opt/app/.sandstorm/launcher.sh"],
environ = [
# Note that this defines the *entire* environment seen by your app.
(key = "PATH", value = "/usr/local/bin:/usr/bin:/bin"),
(key = "SANDSTORM", value = "1"),
# Export SANDSTORM=1 into the environment, so that apps running within Sandstorm
# can detect if $SANDSTORM="1" at runtime, switching UI and/or backend to use
# the app's Sandstorm-specific integration code.
]
);

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

View File

@@ -0,0 +1,89 @@
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
image/svg+xml svg svgz;
image/webp webp;
application/font-woff woff;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.wap.wmlc wmlc;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}

View File

@@ -0,0 +1,87 @@
worker_processes 4;
pid /var/run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_names_hash_bucket_size 64;
server_tokens off;
server_name_in_redirect off;
include mime.types;
default_type application/octet-stream;
# Logging
access_log off;
error_log stderr;
# Prevent nginx from adding compression; this interacts badly with Sandstorm
# WebSession due to https://github.com/sandstorm-io/sandstorm/issues/289
gzip off;
# Trust the sandstorm-http-bridge's X-Forwarded-Proto.
map $http_x_forwarded_proto $fe_https {
default "";
https on;
}
server {
listen 8000 default_server;
listen [::]:8000 default_server ipv6only=on;
# Allow arbitrarily large bodies - Sandstorm can handle them, and requests
# are authenticated already, so there's no reason for apps to add additional
# limits by default.
client_max_body_size 0;
server_name localhost;
root /opt/app/public;
location / {
index index.php;
try_files $uri $uri/ /index.php?$query_string;
autoindex on;
sendfile off;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param HTTPS $fe_https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
#fastcgi_param REDIRECT_STATUS 200;
}
}
}

61
.sandstorm/setup.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
# When you change this file, you must take manual action. Read this doc:
# - https://docs.sandstorm.io/en/latest/vagrant-spk/customizing/#setupsh
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
# install packages so we can install apt-add-repository.
apt-get update
apt-get install -y python-software-properties software-properties-common
# actually add repository
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E9C74FEEA2098A6E
add-apt-repository "deb http://packages.dotdeb.org jessie all"
# install packages.
apt-get update
apt-get install -y nginx php7.0-fpm php7.0-mysql php7.0-cli php7.0-curl git php7.0-dev php7.0-intl php7.0-dom php7.0-mbstring php7.0-bcmath mysql-server
service nginx stop
service php7.0-fpm stop
service mysql stop
systemctl disable nginx
systemctl disable php7.0-fpm
systemctl disable mysql
# patch /etc/php/7.0/fpm/pool.d/www.conf to not change uid/gid to www-data
sed --in-place='' \
--expression='s/^listen.owner = www-data/;listen.owner = www-data/' \
--expression='s/^listen.group = www-data/;listen.group = www-data/' \
/etc/php/7.0/fpm/pool.d/www.conf
# patch /etc/php/7.0/fpm/php-fpm.conf to not have a pidfile
sed --in-place='' \
--expression='s/^pid =/;pid =/' \
/etc/php/7.0/fpm/php-fpm.conf
# move sock file to better dir:
sed --in-place='' \
--expression='s/^listen = \/run\/php\/php7.0-fpm.sock/listen = \/var\/run\/php7.0-fpm.sock/' \
/etc/php/7.0/fpm/pool.d/www.conf
# patch /etc/php/7.0/fpm/pool.d/www.conf to no clear environment variables
# so we can pass in SANDSTORM=1 to apps
sed --in-place='' \
--expression='s/^;clear_env = no/clear_env=no/' \
/etc/php/7.0/fpm/pool.d/www.conf
# patch mysql conf to not change uid, and to use /var/tmp over /tmp
# for secure-file-priv see https://github.com/sandstorm-io/vagrant-spk/issues/195
sed --in-place='' \
--expression='s/^user\t\t= mysql/#user\t\t= mysql/' \
--expression='s,^tmpdir\t\t= /tmp,tmpdir\t\t= /var/tmp,' \
--expression='/\[mysqld]/ a\ secure-file-priv = ""\' \
/etc/mysql/my.cnf
# patch mysql conf to use smaller transaction logs to save disk space
cat <<EOF > /etc/mysql/conf.d/sandstorm.cnf
[mysqld]
# Set the transaction log file to the minimum allowed size to save disk space.
# innodb_log_file_size = 1048576
# Set the main data file to grow by 1MB at a time, rather than 8MB at a time.
innodb_autoextend_increment = 1
EOF

1
.sandstorm/stack Normal file
View File

@@ -0,0 +1 @@
lemp

View File

@@ -1,17 +1,32 @@
language: php
sudo: false
php:
- '7.0'
- 7.0
- 7.1
cache:
directories:
- vendor
- $HOME/.composer/cache
install:
- phpenv config-rm xdebug.ini
- rm composer.lock
- composer update --no-scripts
- cp .env.testing .env
- php artisan clear-compiled
- php artisan optimize
- php artisan env
- cp .env.testing .env
- mv storage/database/databasecopy.sqlite storage/database/database.sqlite
- mkdir -p build/logs
script:
- phpunit
- phpunit -c phpunit.coverage.xml
after_success:
- travis_retry php vendor/bin/coveralls -x storage/build/clover.xml
# safelist
branches:
only:
- develop
- master

View File

@@ -3,6 +3,107 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [4.3.8] - 2017-04-08
### Added
- Better overview / show pages.
- #628, as reported by [xzaz](https://github.com/xzaz).
- Greatly expanded test coverage
### Fixed
- #619, as reported by [dfiel](https://github.com/dfiel).
- #620, as reported by [forcaeluz](https://github.com/forcaeluz).
- Attempt to fix #624, as reported by [TheSerenin](https://github.com/TheSerenin).
- Favicon link is relative now, fixed by [welbert](https://github.com/welbert).
- Some search bugs
## [4.3.7] - 2017-03-06
### Added
- Nice user friendly views for empty lists.
- Extended contribution guidelines.
- First version of financial report filtered on tags.
- Suggested monthly savings for piggy banks, by [Zsub](https://github.com/Zsub)
- Better test coverage.
### Changed
- Slightly changed tag overview.
- Consistent icon for bill in list.
- Slightly changed account overview.
### Removed
- Removed IDE specific views from .gitignore, issue #598
### Fixed
- Force key generation during installation.
- The `date` function takes the fieldname where a date is stored, not the literal date by [Zsub](https://github.com/Zsub)
- Improved budget frontpage chart, as suggested by [skibbipl](https://github.com/skibbipl)
- Issue #602 and #607, as reported by [skibbipl](https://github.com/skibbipl) and [dzaikos](https://github.com/dzaikos).
- Issue #605, as reported by [Zsub](https://github.com/Zsub).
- Issue #599, as reported by [leander091](https://github.com/leander091).
- Issue #610, as reported by [skibbipl](https://github.com/skibbipl).
- Issue #611, as reported by [ragnarkarlsson](https://github.com/ragnarkarlsson).
- Issue #612, as reported by [ragnarkarlsson](https://github.com/ragnarkarlsson).
- Issue #614, as reported by [worldworm](https://github.com/worldworm).
- Various other bug fixes.
## [4.3.6] - 2017-02-20
### Fixed
- #578, reported by [xpfgsyb](https://github.com/xpfgsyb).
## [4.3.5] - 2017-02-19
### Added
- Beta support for Sandstorm.IO
- Docker support by [@schoentoon](https://github.com/schoentoon), [@elohmeier](https://github.com/elohmeier), [@patrickkostjens](https://github.com/patrickkostjens) and [@crash7](https://github.com/crash7)!
- Can now use special keywords in the search to search for specic dates, categories, etc.
### Changed
- Updated to laravel 5.4!
- User friendly error message
- Updated locales to support more operating systems, first reported in #536 by [dabenzel](https://github.com/dabenzel)
- Updated budget report
- Improved 404 page
- Smooth curves, improved by [elamperti](https://github.com/elamperti).
### Fixed
- #549
- #553
- Fixed #559 reported by [elamperti](https://github.com/elamperti).
- #565, as reported by a user over the mail
- #566, as reported by [dspeckmann](https://github.com/dspeckmann)
- #567, as reported by [winsomniak](https://github.com/winsomniak)
- #569, as reported by [winsomniak](https://github.com/winsomniak)
- #572, as reported by [zjean](https://github.com/zjean)
- Many issues with the transaction filters which will fix reports (they tended to display the wrong amount).
## [4.3.4] - 2017-02-02
### Fixed
- Fixed bug #550, reported by [worldworm](https://github.com/worldworm)!
- Fixed bug #551, reported by [t-me](https://github.com/t-me)!
## [4.3.3] - 2017-01-30
_The 100th release of Firefly!_
### Added
- Add locales to Docker (#534) by [elohmeier](https://github.com/elohmeier).
- Optional database encryption. On by default.
- Datepicker for Firefox and other browsers.
- New instruction block for updating and installing.
- Ability to clone transactions.
- Use multi-select Bootstrap thing instead of massive lists of checkboxes.
### Removed
- Lots of old Javascript
### Fixed
- Missing sort broke various charts
- Bug in reports that made amounts behave weird
- Various bug fixes
### Security
- Tested FF against the naughty string list.
## [4.3.2] - 2017-01-09
An intermediate release because something in the Twig and Twigbridge libraries is broken and I have to make sure it doesn't affect you guys. But some cool features were on their way so there's that oo.
@@ -16,35 +117,35 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Fixed
- The password reset routine was broken.
- Issue #522, thanks to @xpfgsyb
- Issue #524, thanks to @worldworm
- Issue #526, thanks to @worldworm
- Issue #528, thanks to @skibbipl
- Issue #522, thanks to [xpfgsyb](https://github.com/xpfgsyb)
- Issue #524, thanks to [worldworm](https://github.com/worldworm)
- Issue #526, thanks to [worldworm](https://github.com/worldworm)
- Issue #528, thanks to [skibbipl](https://github.com/skibbipl)
- Various other fixes.
## [4.3.1] - 2017-01-04
### Added
- Support for Russian and Polish.
- Support for a proper demo website.
- Support for custom decimal places in currencies (#506, suggested by @xpfgsyb).
- Most amounts are now right-aligned (#511, suggested by @xpfgsyb).
- Support for custom decimal places in currencies (#506, suggested by [xpfgsyb](https://github.com/xpfgsyb)).
- Most amounts are now right-aligned (#511, suggested by [xpfgsyb](https://github.com/xpfgsyb)).
- German is now a "complete" language, more than 75% translated!
### Changed
- **[New Github repository!](github.com/firefly-iii/firefly-iii)**
- Better category overview.
- #502, thanks to @zjean
- #502, thanks to [zjean](https://github.com/zjean)
### Removed
- Removed a lot of administration functions.
- Removed ability to activate users.
### Fixed
- #501, thanks to @zjean
- #513, thanks to @skibbipl
- #501, thanks to [zjean](https://github.com/zjean)
- #513, thanks to [skibbipl](https://github.com/skibbipl)
### Security
- #519, thanks to @xpfgsyb
- #519, thanks to [xpfgsyb](https://github.com/xpfgsyb)
## [4.3.0] - 2015-12-26
### Added
@@ -77,7 +178,7 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Fixed
- Various bugs
- Issue #472 thanks to @zjean
- Issue #472 thanks to [zjean](https://github.com/zjean)
## [4.2.1] - 2016-12-09
### Added
@@ -112,10 +213,10 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Fixed
- Issue #408
- Various issues with split journals
- Issue #414, thx @zjean
- Issue #419, thx @schwalberich
- Issue #422, thx @xzaz
- Various import bugs, such as #416 (@zjean)
- Issue #414, thx [zjean](https://github.com/zjean)
- Issue #419, thx [schwalberich](https://github.com/schwalberich)
- Issue #422, thx [xzaz](https://github.com/xzaz)
- Various import bugs, such as #416 ([zjean](https://github.com/zjean))
### Security
@@ -137,9 +238,9 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Fixed
- Made all pages more mobile friendly.
- Fixed #395 found by @marcoveeneman.
- Fixed #398 found by @marcoveeneman.
- Fixed #401 found by @marcoveeneman.
- Fixed #395 found by [marcoveeneman](https://github.com/marcoveeneman).
- Fixed #398 found by [marcoveeneman](https://github.com/marcoveeneman).
- Fixed #401 found by [marcoveeneman](https://github.com/marcoveeneman).
- Many optimizations.
- Updated many libraries.
- Various bugs found by myself.
@@ -151,13 +252,13 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Changed
- Greatly expanded help pages and their function.
- Built a new transaction collector, which I think was the idea of @roberthorlings originally.
- Built a new transaction collector, which I think was the idea of [roberthorlings](https://github.com/roberthorlings) originally.
- Rebuilt seach engine.
### Fixed
- #375, thanks to @schoentoon which made it impossible to resurrect currencies.
- #370 thanks to @ksmolder
- #378, thanks to @HomelessAvatar
- #375, thanks to [schoentoon](https://github.com/schoentoon) which made it impossible to resurrect currencies.
- #370 thanks to [ksmolder](https://github.com/ksmolder)
- #378, thanks to [HomelessAvatar](https://github.com/HomelessAvatar)
## [4.1.5] - 2016-11-01
### Changed
@@ -170,7 +271,7 @@ An intermediate release because something in the Twig and Twigbridge libraries i
## [4.1.4] - 2016-10-30
### Added
- New Dockerfile thanks to @schoentoon
- New Dockerfile thanks to [schoentoon](https://github.com/schoentoon)
- Added changing the destination account as rule action.
- Added changing the source account as rule action.
- Can convert transactions into different types.
@@ -183,10 +284,10 @@ An intermediate release because something in the Twig and Twigbridge libraries i
- Change error message to refer to solution.
### Fixed
- #367 thanks to @HungryFeline
- #366 thanks to @3mz3t
- #362 and #341 thanks to @bnw
- #355 thanks to @roberthorlings
- #367 thanks to [HungryFeline](https://github.com/HungryFeline)
- #366 thanks to [3mz3t](https://github.com/3mz3t)
- #362 and #341 thanks to [bnw](https://github.com/bnw)
- #355 thanks to [roberthorlings](https://github.com/roberthorlings)
## [4.1.3] - 2016-10-22
### Fixed
@@ -218,29 +319,29 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Fixed
- #357, where non utf-8 files would break Firefly.
- Tab delimiter is not properly loaded from import configuration (@roberthorlings)
- Tab delimiter is not properly loaded from import configuration ([roberthorlings](https://github.com/roberthorlings))
- System response to yearly bills
## [4.0.2] - 2016-10-14
### Added
- Added ``intl`` dependency to composer file to ease installation (thanks @telyn)
- Added ``intl`` dependency to composer file to ease installation (thanks [telyn](https://github.com/telyn))
- Added support for Croatian.
### Changed
- Updated all copyright notices to refer to the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/)
- Fixed #344
- Fixed #346, thanks to @SanderKleykens
- Fixed #346, thanks to [SanderKleykens](https://github.com/SanderKleykens)
- #351
- Did some internal remodelling.
### Fixed
- PostgreSQL compatibility thanks to @SanderKleykens
- @RobertHorlings fixed a bug in the ABN Amro import specific.
- PostgreSQL compatibility thanks to [SanderKleykens](https://github.com/SanderKleykens)
- [roberthorlings](https://github.com/roberthorlings) fixed a bug in the ABN Amro import specific.
## [4.0.1] - 2016-10-04
### Added
- New ING import specific by @tomwerf
- New ING import specific by [tomwerf](https://github.com/tomwerf)
- New Presidents Choice specific to fix #307
- Added some trimming (#335)
@@ -255,10 +356,10 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Fixed
- Fixed a bug where incoming transactions would not be properly filtered in several reports.
- #334 by @cyberkov
- #334 by [cyberkov](https://github.com/cyberkov)
- #337
- #336
- #338 found by @roberthorlings
- #338 found by [roberthorlings](https://github.com/roberthorlings)
### Security
- Initial release.
@@ -269,29 +370,29 @@ An intermediate release because something in the Twig and Twigbridge libraries i
## [4.0.0] - 2015-09-26
### Added
- Upgraded to Laravel 5.3, most other libraries upgraded as well.
- Added GBP as currency, thanks to @Mortalife
- Added GBP as currency, thanks to [Mortalife](https://github.com/Mortalife)
### Changed
- Jump to version 4.0.0.
- Firefly III is now subject to a [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/) license. Previous versions of this software are still MIT licensed.
### Fixed
- Support for specific decimal places, thanks to @Mortalife
- Support for specific decimal places, thanks to [Mortalife](https://github.com/Mortalife)
- Various CSS fixes
- Various bugs, thanks to @fuf, @sandermulders and @vissert
- Various bugs, thanks to [fuf](https://github.com/fuf), [sandermulders](https://github.com/sandermulders) and [vissert](https://github.com/vissert)
- Various queries optimized for MySQL 5.7
## [3.10.4] - 2015-09-14
### Fixed
- Migration fix by @sandermulders
- Tricky import bug fix thanks to @vissert
- Currency preference will be correctly pulled from user settings, thanks to @fuf
- Migration fix by [sandermulders](https://github.com/sandermulders)
- Tricky import bug fix thanks to [vissert](https://github.com/vissert)
- Currency preference will be correctly pulled from user settings, thanks to [fuf](https://github.com/fuf)
- Simplified code for upgrade instructions.
## [3.10.3] - 2016-08-29
### Added
- More fields for mass-edit, thanks to @Vissert (#282)
- More fields for mass-edit, thanks to [vissert](https://github.com/vissert) (#282)
- First start of German translation
### Changed
@@ -302,7 +403,7 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Fixed
- A bug in the translation routine broke the import.
- It was possible to destroy your Firefly installation by removing all currencies. Thanks @mondjef
- It was possible to destroy your Firefly installation by removing all currencies. Thanks [mondjef](https://github.com/mondjef)
- Translation bugs.
- Import bug.
@@ -322,8 +423,8 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Fixed
- Bug in the mass edit routines.
- Firefly III over a proxy will now work (see [issue #290](https://github.com/firefly-iii/firefly-iii/issues/290)), thanks @dfiel for reporting.
- Sneaky bug in the import routine, fixed by @Bonno
- Firefly III over a proxy will now work (see [issue #290](https://github.com/firefly-iii/firefly-iii/issues/290)), thanks [dfiel](https://github.com/dfiel) for reporting.
- Sneaky bug in the import routine, fixed by [Bonno](https://github.com/Bonno)
## [3.10.1] - 2016-08-25
### Added
@@ -361,15 +462,15 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Fixed
- Issue #264
- Issue #265
- Fixed amount calculation problems, #266, thanks @xzaz
- Fixed amount calculation problems, #266, thanks [xzaz](https://github.com/xzaz)
- Issue #271
- Issue #278, #273, thanks @StevenReitsma and @rubella
- Issue #278, #273, thanks [StevenReitsma](https://github.com/StevenReitsma) and [rubella](https://github.com/rubella)
- Bug in attachment download routine would report the wrong size to the user's browser.
- Various NULL errors fixed.
- Various strict typing errors fixed.
- Fixed pagination problems, #276, thanks @xzaz
- Fixed pagination problems, #276, thanks [xzaz](https://github.com/xzaz)
- Fixed a bug where an expense would be assigned to a piggy bank if you created a transfer first.
- Bulk update problems, #280, thanks @stickgrinder
- Bulk update problems, #280, thanks [stickgrinder](https://github.com/stickgrinder)
- Fixed various problems with amount reporting of split transactions.
## [3.9.1]
@@ -378,8 +479,8 @@ An intermediate release because something in the Twig and Twigbridge libraries i
## [3.9.0]
### Added
- @zjean has added code that allows you to force "https://"-URL's.
- @tonicospinelli has added Portuguese (Brazil) translations.
- [zjean](https://github.com/zjean) has added code that allows you to force "https://"-URL's.
- [tonicospinelli](https://github.com/tonicospinelli) has added Portuguese (Brazil) translations.
- Firefly III supports the *splitting* of transactions:
- A withdrawal (expense) can be split into multiple sub-transactions (with multiple destinations)
- Likewise for deposits (incomes). You can set multiple sources.
@@ -410,7 +511,7 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Fixed
- Several CSV related bugs.
- Several other bugs.
- Bugs fixed by @Bonno.
- Bugs fixed by [Bonno](https://github.com/Bonno).
## [3.8.3] - 2016-04-17
### Added
@@ -457,7 +558,7 @@ An intermediate release because something in the Twig and Twigbridge libraries i
### Added
- Two factor authentication, thanks to the excellent work of [zjean](https://github.com/zjean).
- A new chart showing your net worth in year and multi-year reports.
- You can now see if your current or future rules actually match any transactions, thanks to the excellent work of @roberthorlings.
- You can now see if your current or future rules actually match any transactions, thanks to the excellent work of [roberthorlings](https://github.com/roberthorlings).
- New date fields for transactions. They are not used yet in reports or anything, but they can be filled in.
- New routine to export your data.
- Firefly III will mail the site owner when blocked users try to login, or when blocked domains are used in registrations.

View File

@@ -11,12 +11,17 @@ RUN apt-get update -y && \
libtidy-dev \
libxml2-dev \
libsqlite3-dev \
libbz2-dev && \
libbz2-dev \
gettext-base \
locales && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN docker-php-ext-install -j$(nproc) curl gd intl json mcrypt readline tidy zip bcmath xml mbstring pdo_sqlite pdo_mysql bz2
# Generate locales supported by firefly
RUN echo "en_US.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8" > /etc/locale.gen && locale-gen
# Enable apache mod rewrite..
RUN a2enmod rewrite
@@ -40,3 +45,5 @@ WORKDIR /var/www/firefly-iii
RUN composer install --no-scripts --no-dev
USER root
ENTRYPOINT ["/var/www/firefly-iii/docker/entrypoint.sh"]

View File

@@ -1,6 +1,6 @@
# Firefly III: A personal finances manager
[![Requires PHP7](https://img.shields.io/badge/php-7.0-red.svg)](https://secure.php.net/downloads.php#v7.0.4) [![Latest Stable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/stable)](https://packagist.org/packages/grumpydictator/firefly-iii) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/firefly-iii/firefly-iii/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/firefly-iii/firefly-iii/?branch=master) [![Build Status](https://travis-ci.org/firefly-iii/firefly-iii.svg?branch=master)](https://travis-ci.org/firefly-iii/firefly-iii) [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA)
[![Requires PHP7](https://img.shields.io/badge/php-7.0-red.svg)](https://secure.php.net/downloads.php) [![Latest Stable Version](https://poser.pugx.org/grumpydictator/firefly-iii/v/stable)](https://packagist.org/packages/grumpydictator/firefly-iii) [![License](https://img.shields.io/badge/license-CC%20BY--SA%204.0-lightgrey.svg)](https://creativecommons.org/licenses/by-sa/4.0/) [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA)
[![The index of Firefly III](https://i.nder.be/hurdhgyg/400)](https://i.nder.be/h2b37243) [![The account overview of Firefly III](https://i.nder.be/hnkfkdpr/400)](https://i.nder.be/hv70pbwc)
@@ -14,7 +14,7 @@ Try out Firefly III on the [demo site](https://firefly-iii.nder.be/).
## Installation
To install Firefly III, you'll need a web server (preferrably on Linux) and access to the command line. Then, please read the [installation guide](https://firefly-iii.github.io/installation-guide/).
To install Firefly III, you'll need a web server (preferrably on Linux) and access to the command line. Then, please read the [installation guide](https://firefly-iii.github.io/using-installing.html).
## More about Firefly III
@@ -26,7 +26,7 @@ Firefly works on the principle that if you know where you're money is going, you
- Firefly can import any CSV file, so migrating from other systems is easy.
- Firefly runs on your own server, so you are fully in control of your data. Remember, there is no such thing as "the cloud", its just somebody elses computer!
- Firefly has lots of features without becoming fancy or bloated.
- Firefly has lots of features without being fancy or bloated.
- If you feel you're missing something you can just ask me and I'll add it!
Firefly is pretty awesome. [You can read more about Firefly III, and its features, on the Github Pages](https://firefly-iii.github.io/).
@@ -34,3 +34,5 @@ Firefly is pretty awesome. [You can read more about Firefly III, and its feature
If you like Firefly and if it helps you save lots of money, why not send me [a dime for every dollar saved](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA) (this is a joke, although the Paypal form works just fine, try it!)
If you want to contact me, please open an issue or [email me](mailto:thegrumpydictator@gmail.com).
[![Build Status](https://travis-ci.org/firefly-iii/firefly-iii.svg?branch=master)](https://travis-ci.org/firefly-iii/firefly-iii) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/firefly-iii/firefly-iii/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/firefly-iii/firefly-iii/?branch=master) [![Coverage Status](https://coveralls.io/repos/github/firefly-iii/firefly-iii/badge.svg?branch=master)](https://coveralls.io/github/firefly-iii/firefly-iii?branch=master)

View File

@@ -79,11 +79,12 @@ class CreateImport extends Command
$this->info(sprintf('Type of import: %s', $type));
/** @var ImportJobRepositoryInterface $jobRepository */
$jobRepository = app(ImportJobRepositoryInterface::class, [$user]);
$job = $jobRepository->create($type);
$jobRepository = app(ImportJobRepositoryInterface::class);
$jobRepository->setUser($user);
$job = $jobRepository->create($type);
$this->line(sprintf('Created job "%s"...', $job->key));
Artisan::call('firefly:encrypt', ['file' => $file, 'key' => $job->key]);
Artisan::call('firefly:encrypt-file', ['file' => $file, 'key' => $job->key]);
$this->line('Stored import data...');
$job->configuration = $configurationData;

View File

@@ -35,7 +35,7 @@ class EncryptFile extends Command
*
* @var string
*/
protected $signature = 'firefly:encrypt {file} {key}';
protected $signature = 'firefly:encrypt-file {file} {key}';
/**
* Create a new command instance.

View File

@@ -58,7 +58,12 @@ class Import extends Command
{
Log::debug('Start start-import command');
$jobKey = $this->argument('key');
$job = ImportJob::whereKey($jobKey)->first();
$job = ImportJob::where('key', $jobKey)->first();
if (is_null($job)) {
$this->error(sprintf('No job found with key "%s"', $jobKey));
return;
}
if (!$this->isValid($job)) {
Log::error('Job is not valid for some reason. Exit.');

View File

@@ -9,7 +9,7 @@
* See the LICENSE file for details.
*/
declare(strict_types = 1);
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
@@ -17,8 +17,10 @@ namespace FireflyIII\Console\Commands;
use DB;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\LimitRepetition;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Illuminate\Console\Command;
use Illuminate\Database\QueryException;
use Log;
@@ -60,6 +62,7 @@ class UpgradeDatabase extends Command
{
$this->setTransactionIdentifier();
$this->migrateRepetitions();
$this->repairPiggyBanks();
}
private function migrateRepetitions()
@@ -69,7 +72,9 @@ class UpgradeDatabase extends Command
}
// get all budget limits with end_date NULL
$set = BudgetLimit::whereNull('end_date')->get();
$this->line(sprintf('Found %d budget limit(s) to update', $set->count()));
if ($set->count() > 0) {
$this->line(sprintf('Found %d budget limit(s) to update', $set->count()));
}
/** @var BudgetLimit $budgetLimit */
foreach ($set as $budgetLimit) {
// get limit repetition (should be just one):
@@ -84,6 +89,35 @@ class UpgradeDatabase extends Command
}
}
/**
* Make sure there are only transfers linked to piggy bank events.
*/
private function repairPiggyBanks()
{
// if table does not exist, return false
if (!Schema::hasTable('piggy_bank_events')) {
return;
}
$set = PiggyBankEvent::with(['PiggyBank', 'TransactionJournal', 'TransactionJournal.TransactionType'])->get();
/** @var PiggyBankEvent $event */
foreach ($set as $event) {
if (!is_null($event->transaction_journal_id)) {
$type = $event->transactionJournal->transactionType->type;
if ($type !== TransactionType::TRANSFER) {
$event->transaction_journal_id = null;
$event->save();
$this->line(
sprintf('Piggy bank #%d ("%s") was referenced by an invalid event. This has been fixed.', $event->piggy_bank_id,
$event->piggyBank->name
));
}
}
}
}
/**
* This is strangely complex, because the HAVING modifier is a no-no. And subqueries in Laravel are weird.
*/
@@ -151,7 +185,6 @@ class UpgradeDatabase extends Command
$opposing->save();
$processed[] = $transaction->id;
$processed[] = $opposing->id;
$this->line(sprintf('Database upgrade for journal #%d, transactions #%d and #%d', $journalId, $transaction->id, $opposing->id));
}
$identifier++;
}

View File

@@ -33,7 +33,7 @@ class UpgradeFireflyInstructions extends Command
*
* @var string
*/
protected $signature = 'firefly:upgrade-instructions';
protected $signature = 'firefly:instructions {task}';
/**
* Create a new command instance.
@@ -49,11 +49,47 @@ class UpgradeFireflyInstructions extends Command
*/
public function handle()
{
//
if ($this->argument('task') == 'update') {
$this->updateInstructions();
}
if ($this->argument('task') == 'install') {
$this->installInstructions();
}
}
/**
* Show a nice box
*
* @param string $text
*/
private function boxed(string $text)
{
$parts = explode("\n", wordwrap($text));
foreach ($parts as $string) {
$this->line('| ' . sprintf('%-77s', $string) . '|');
}
}
/**
* Show a nice info box
*
* @param string $text
*/
private function boxedInfo(string $text)
{
$parts = explode("\n", wordwrap($text));
foreach ($parts as $string) {
$this->info('| ' . sprintf('%-77s', $string) . '|');
}
}
private function installInstructions()
{
/** @var string $version */
$version = config('firefly.version');
$config = config('upgrade.text');
$text = null;
$config = config('upgrade.text.install');
$text = '';
foreach (array_keys($config) as $compare) {
// if string starts with:
$len = strlen($compare);
@@ -62,22 +98,69 @@ class UpgradeFireflyInstructions extends Command
}
}
$this->showLine();
$this->boxed('');
if (is_null($text)) {
$this->line(sprintf('Thank you for installing Firefly III, v%s', $version));
$this->info('There are no extra upgrade instructions.');
$this->line('Firefly III should be ready for use.');
$this->boxed(sprintf('Thank you for installin Firefly III, v%s!', $version));
$this->boxedInfo('There are no extra installation instructions.');
$this->boxed('Firefly III should be ready for use.');
$this->boxed('');
$this->showLine();
return;
}
$this->line('+------------------------------------------------------------------------------+');
$this->line('');
$this->line(sprintf('Thank you for installing Firefly III, v%s', $version));
$this->info(wordwrap($text));
$this->line('');
$this->line('+------------------------------------------------------------------------------+');
$this->boxed(sprintf('Thank you for installing Firefly III, v%s!', $version));
$this->boxedInfo($text);
$this->boxed('');
$this->showLine();
}
/**
* Show a line
*/
private function showLine()
{
$line = '+';
for ($i = 0; $i < 78; $i++) {
$line .= '-';
}
$line .= '+';
$this->line($line);
}
private function updateInstructions()
{
/** @var string $version */
$version = config('firefly.version');
$config = config('upgrade.text.upgrade');
$text = '';
foreach (array_keys($config) as $compare) {
// if string starts with:
$len = strlen($compare);
if (substr($version, 0, $len) === $compare) {
$text = $config[$compare];
}
}
$this->showLine();
$this->boxed('');
if (is_null($text)) {
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s', $version));
$this->boxedInfo('There are no extra upgrade instructions.');
$this->boxed('Firefly III should be ready for use.');
$this->boxed('');
$this->showLine();
return;
}
$this->boxed(sprintf('Thank you for updating to Firefly III, v%s!', $version));
$this->boxedInfo($text);
$this->boxed('');
$this->showLine();
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace FireflyIII\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
class UseEncryption extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command will make sure that entries in the database will be encrypted (or not) according to the settings in .env';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly:use-encryption';
/**
* Create a new command instance.
*
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle()
{
//
$this->handleObjects('Account', 'name', 'encrypted');
$this->handleObjects('Bill', 'name', 'name_encrypted');
$this->handleObjects('Bill', 'match', 'match_encrypted');
$this->handleObjects('Budget', 'name', 'encrypted');
$this->handleObjects('Category', 'name', 'encrypted');
$this->handleObjects('PiggyBank', 'name', 'encrypted');
$this->handleObjects('TransactionJournal', 'description', 'encrypted');
}
/**
* @param string $class
* @param string $field
* @param string $indicator
*/
public function handleObjects(string $class, string $field, string $indicator)
{
$fqn = sprintf('FireflyIII\Models\%s', $class);
$encrypt = config('firefly.encryption') ? 0 : 1;
$set = $fqn::where($indicator, $encrypt)->get();
foreach ($set as $entry) {
$newName = $entry->$field;
$entry->$field = $newName;
$entry->save();
}
$this->line(sprintf('Updated %d %s.', $set->count(), strtolower(Str::plural($class))));
}
}

View File

@@ -93,6 +93,7 @@ class VerifyDatabase extends Command
// report on journals with the wrong types of accounts.
$this->reportIncorrectJournals();
}
/**
@@ -131,7 +132,7 @@ class VerifyDatabase extends Command
/** @var Budget $entry */
foreach ($set as $entry) {
$line = sprintf(
'Notice: User #%d (%s) has budget #%d ("%s") which has no budget limits.',
'User #%d (%s) has budget #%d ("%s") which has no budget limits.',
$entry->user_id, $entry->email, $entry->id, $entry->name
);
$this->line($line);
@@ -277,7 +278,7 @@ class VerifyDatabase extends Command
}
$line = sprintf(
'Notice: User #%d (%s) has %s #%d ("%s") which has no transactions.',
'User #%d (%s) has %s #%d ("%s") which has no transactions.',
$entry->user_id, $entry->email, $name, $entry->id, $objName
);
$this->line($line);

View File

@@ -16,10 +16,10 @@ namespace FireflyIII\Console;
use FireflyIII\Console\Commands\CreateImport;
use FireflyIII\Console\Commands\EncryptFile;
use FireflyIII\Console\Commands\Import;
use FireflyIII\Console\Commands\MoveRepository;
use FireflyIII\Console\Commands\ScanAttachments;
use FireflyIII\Console\Commands\UpgradeDatabase;
use FireflyIII\Console\Commands\UpgradeFireflyInstructions;
use FireflyIII\Console\Commands\UseEncryption;
use FireflyIII\Console\Commands\VerifyDatabase;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -39,9 +39,9 @@ class Kernel extends ConsoleKernel
*/
protected $bootstrappers
= [
'Illuminate\Foundation\Bootstrap\DetectEnvironment',
'Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables',
'Illuminate\Foundation\Bootstrap\LoadConfiguration',
'FireflyIII\Bootstrap\ConfigureLogging',
//'FireflyIII\Bootstrap\ConfigureLogging',
'Illuminate\Foundation\Bootstrap\HandleExceptions',
'Illuminate\Foundation\Bootstrap\RegisterFacades',
'Illuminate\Foundation\Bootstrap\SetRequestForConsole',
@@ -63,6 +63,7 @@ class Kernel extends ConsoleKernel
EncryptFile::class,
ScanAttachments::class,
UpgradeDatabase::class,
UseEncryption::class,
];
/**

View File

@@ -97,6 +97,7 @@ class Handler extends ExceptionHandler
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'code' => $exception->getCode(),
'version' => config('firefly.version'),
];
// create job that will mail.
@@ -111,9 +112,9 @@ class Handler extends ExceptionHandler
/**
* Convert an authentication exception into an unauthenticated response.
*
* @param \Illuminate\Http\Request $request
* @param $request
*
* @return \Illuminate\Http\Response
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
protected function unauthenticated($request)
{

View File

@@ -16,7 +16,6 @@ namespace FireflyIII\Export\Collector;
use Carbon\Carbon;
use Crypt;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\ExportJob;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Collection;
@@ -43,10 +42,8 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
/**
* AttachmentCollector constructor.
*
* @param ExportJob $job
*/
public function __construct(ExportJob $job)
public function __construct()
{
/** @var AttachmentRepositoryInterface repository */
$this->repository = app(AttachmentRepositoryInterface::class);
@@ -54,7 +51,7 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
$this->uploadDisk = Storage::disk('upload');
$this->exportDisk = Storage::disk('export');
parent::__construct($job);
parent::__construct();
}
/**

View File

@@ -31,13 +31,10 @@ class BasicCollector
/**
* BasicCollector constructor.
*
* @param ExportJob $job
*/
public function __construct(ExportJob $job)
public function __construct()
{
$this->entries = new Collection;
$this->job = $job;
}
/**
@@ -56,5 +53,13 @@ class BasicCollector
$this->entries = $entries;
}
/**
* @param ExportJob $job
*/
public function setJob(ExportJob $job)
{
$this->job = $job;
}
}

View File

@@ -13,6 +13,7 @@ declare(strict_types = 1);
namespace FireflyIII\Export\Collector;
use FireflyIII\Models\ExportJob;
use Illuminate\Support\Collection;
/**
@@ -40,4 +41,11 @@ interface CollectorInterface
*/
public function setEntries(Collection $entries);
/**
* @param ExportJob $job
*
* @return mixed
*/
public function setJob(ExportJob $job);
}

View File

@@ -14,11 +14,11 @@ declare(strict_types = 1);
namespace FireflyIII\Export\Collector;
use Carbon\Carbon;
use Crypt;
use DB;
use FireflyIII\Models\Transaction;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Steam;
/**
* Class JournalExportCollector
@@ -118,7 +118,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
);
$set->each(
function ($obj) {
$obj->name = $obj->encrypted === 1 ? Crypt::decrypt($obj->name) : $obj->name;
$obj->name = Steam::decrypt(intval($obj->encrypted), $obj->name);
}
);
$array = [];
@@ -159,7 +159,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
);
$set->each(
function ($obj) {
$obj->name = $obj->encrypted === 1 ? Crypt::decrypt($obj->name) : $obj->name;
$obj->name = Steam::decrypt(intval($obj->encrypted), $obj->name);
}
);
$array = [];
@@ -202,7 +202,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
);
$set->each(
function ($obj) {
$obj->name = $obj->encrypted === 1 ? Crypt::decrypt($obj->name) : $obj->name;
$obj->name = Steam::decrypt(intval($obj->encrypted), $obj->name);
}
);
$array = [];
@@ -243,7 +243,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
);
$set->each(
function ($obj) {
$obj->name = $obj->encrypted === 1 ? Crypt::decrypt($obj->name) : $obj->name;
$obj->name = Steam::decrypt(intval($obj->encrypted), $obj->name);
}
);
$array = [];

View File

@@ -14,7 +14,6 @@ declare(strict_types = 1);
namespace FireflyIII\Export\Collector;
use Crypt;
use FireflyIII\Models\ExportJob;
use Illuminate\Contracts\Encryption\DecryptException;
use Log;
use Storage;
@@ -35,22 +34,12 @@ class UploadCollector extends BasicCollector implements CollectorInterface
/**
* AttachmentCollector constructor.
*
* @param ExportJob $job
*/
public function __construct(ExportJob $job)
public function __construct()
{
parent::__construct($job);
Log::debug('Going to collect attachments', ['key' => $job->key]);
// make storage:
parent::__construct();
$this->uploadDisk = Storage::disk('upload');
$this->exportDisk = Storage::disk('export');
// file names associated with the old import routine.
$this->vintageFormat = sprintf('csv-upload-%d-', auth()->user()->id);
}
/**
@@ -60,6 +49,11 @@ class UploadCollector extends BasicCollector implements CollectorInterface
*/
public function run(): bool
{
Log::debug('Going to collect attachments', ['key' => $this->job->key]);
// file names associated with the old import routine.
$this->vintageFormat = sprintf('csv-upload-%d-', $this->job->user->id);
// collect old upload files (names beginning with "csv-upload".
$this->collectVintageUploads();

View File

@@ -13,7 +13,7 @@ declare(strict_types = 1);
namespace FireflyIII\Export\Entry;
use Crypt;
use Steam;
/**
* To extend the exported object, in case of new features in Firefly III for example,
@@ -51,7 +51,6 @@ final class Entry
public $destination_account_id;
public $destination_account_name;
public $budget_id;
public $budget_name;
public $category_id;
@@ -74,15 +73,15 @@ final class Entry
{
$entry = new self;
$entry->journal_id = $object->transaction_journal_id;
$entry->description = self::decrypt($object->journal_encrypted, $object->journal_description);
$entry->description = Steam::decrypt(intval($object->journal_encrypted), $object->journal_description);
$entry->amount = $object->amount;
$entry->date = $object->date;
$entry->transaction_type = $object->transaction_type;
$entry->currency_code = $object->transaction_currency_code;
$entry->source_account_id = $object->account_id;
$entry->source_account_name = self::decrypt($object->account_name_encrypted, $object->account_name);
$entry->source_account_name = Steam::decrypt(intval($object->account_name_encrypted), $object->account_name);
$entry->destination_account_id = $object->opposing_account_id;
$entry->destination_account_name = self::decrypt($object->opposing_account_encrypted, $object->opposing_account_name);
$entry->destination_account_name = Steam::decrypt(intval($object->opposing_account_encrypted), $object->opposing_account_name);
$entry->category_id = $object->category_id ?? '';
$entry->category_name = $object->category_name ?? '';
$entry->budget_id = $object->budget_id ?? '';
@@ -96,19 +95,5 @@ final class Entry
return $entry;
}
/**
* @param int $isEncrypted
* @param $value
*
* @return string
*/
protected static function decrypt(int $isEncrypted, $value)
{
if ($isEncrypted === 1) {
return Crypt::decrypt($value);
}
return $value;
}
}

View File

@@ -26,17 +26,15 @@ class BasicExporter
{
/** @var ExportJob */
protected $job;
private $entries;
/** @var Collection */
private $entries;
/**
* BasicExporter constructor.
*
* @param ExportJob $job
*/
public function __construct(ExportJob $job)
public function __construct()
{
$this->entries = new Collection;
$this->job = $job;
}
/**
@@ -55,5 +53,13 @@ class BasicExporter
$this->entries = $entries;
}
/**
* @param ExportJob $job
*/
public function setJob(ExportJob $job)
{
$this->job = $job;
}
}

View File

@@ -14,7 +14,6 @@ declare(strict_types = 1);
namespace FireflyIII\Export\Exporter;
use FireflyIII\Export\Entry\Entry;
use FireflyIII\Models\ExportJob;
use League\Csv\Writer;
use SplFileObject;
@@ -30,13 +29,10 @@ class CsvExporter extends BasicExporter implements ExporterInterface
/**
* CsvExporter constructor.
*
* @param ExportJob $job
*/
public function __construct(ExportJob $job)
public function __construct()
{
parent::__construct($job);
parent::__construct();
}
/**

View File

@@ -13,6 +13,7 @@ declare(strict_types = 1);
namespace FireflyIII\Export\Exporter;
use FireflyIII\Models\ExportJob;
use Illuminate\Support\Collection;
/**
@@ -45,4 +46,9 @@ interface ExporterInterface
*/
public function setEntries(Collection $entries);
/**
* @param ExportJob $job
*/
public function setJob(ExportJob $job);
}

View File

@@ -19,7 +19,6 @@ use FireflyIII\Export\Collector\JournalExportCollector;
use FireflyIII\Export\Collector\UploadCollector;
use FireflyIII\Export\Entry\Entry;
use FireflyIII\Models\ExportJob;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Support\Collection;
use Log;
use Storage;
@@ -54,21 +53,12 @@ class Processor implements ProcessorInterface
/**
* Processor constructor.
*
* @param array $settings
*/
public function __construct(array $settings)
public function __construct()
{
// save settings
$this->settings = $settings;
$this->accounts = $settings['accounts'];
$this->exportFormat = $settings['exportFormat'];
$this->includeAttachments = $settings['includeAttachments'];
$this->includeOldUploads = $settings['includeOldUploads'];
$this->job = $settings['job'];
$this->journals = new Collection;
$this->exportEntries = new Collection;
$this->files = new Collection;
$this->journals = new Collection;
$this->exportEntries = new Collection;
$this->files = new Collection;
}
@@ -78,7 +68,8 @@ class Processor implements ProcessorInterface
public function collectAttachments(): bool
{
/** @var AttachmentCollector $attachmentCollector */
$attachmentCollector = app(AttachmentCollector::class, [$this->job]);
$attachmentCollector = app(AttachmentCollector::class);
$attachmentCollector->setJob($this->job);
$attachmentCollector->setDates($this->settings['startDate'], $this->settings['endDate']);
$attachmentCollector->run();
$this->files = $this->files->merge($attachmentCollector->getEntries());
@@ -92,7 +83,8 @@ class Processor implements ProcessorInterface
public function collectJournals(): bool
{
/** @var JournalExportCollector $collector */
$collector = app(JournalExportCollector::class, [$this->job]);
$collector = app(JournalExportCollector::class);
$collector->setJob($this->job);
$collector->setDates($this->settings['startDate'], $this->settings['endDate']);
$collector->setAccounts($this->settings['accounts']);
$collector->run();
@@ -108,7 +100,8 @@ class Processor implements ProcessorInterface
public function collectOldUploads(): bool
{
/** @var UploadCollector $uploadCollector */
$uploadCollector = app(UploadCollector::class, [$this->job]);
$uploadCollector = app(UploadCollector::class);
$uploadCollector->setJob($this->job);
$uploadCollector->run();
$this->files = $this->files->merge($uploadCollector->getEntries());
@@ -166,7 +159,8 @@ class Processor implements ProcessorInterface
public function exportJournals(): bool
{
$exporterClass = config('firefly.export_formats.' . $this->exportFormat);
$exporter = app($exporterClass, [$this->job]);
$exporter = app($exporterClass);
$exporter->setJob($this->job);
$exporter->setEntries($this->exportEntries);
$exporter->run();
$this->files->push($exporter->getFileName());
@@ -182,6 +176,20 @@ class Processor implements ProcessorInterface
return $this->files;
}
/**
* @param array $settings
*/
public function setSettings(array $settings)
{
// save settings
$this->settings = $settings;
$this->accounts = $settings['accounts'];
$this->exportFormat = $settings['exportFormat'];
$this->includeAttachments = $settings['includeAttachments'];
$this->includeOldUploads = $settings['includeOldUploads'];
$this->job = $settings['job'];
}
/**
*
*/

View File

@@ -25,11 +25,8 @@ interface ProcessorInterface
/**
* Processor constructor.
*
* @param array $settings
*
*/
public function __construct(array $settings);
public function __construct();
/**
* @return bool
@@ -65,4 +62,9 @@ interface ProcessorInterface
* @return Collection
*/
public function getFiles(): Collection;
/**
* @param array $settings
*/
public function setSettings(array $settings);
}

View File

@@ -14,6 +14,7 @@ declare(strict_types = 1);
namespace FireflyIII\Generator\Chart\Basic;
use FireflyIII\Support\ChartColour;
use Steam;
/**
* Class ChartJsGenerator
@@ -108,11 +109,7 @@ class ChartJsGenerator implements GeneratorInterface
foreach ($data as $key => $value) {
// make larger than 0
if (bccomp($value, '0') === -1) {
$value = bcmul($value, '-1');
}
$chartData['datasets'][0]['data'][] = $value;
$chartData['datasets'][0]['data'][] = floatval(Steam::positive($value));
$chartData['datasets'][0]['backgroundColor'][] = ChartColour::getColour($index);
$chartData['labels'][] = $key;
$index++;

View File

@@ -129,6 +129,16 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $this;
}
/**
* @param Collection $tags
*
* @return ReportGeneratorInterface
*/
public function setTags(Collection $tags): ReportGeneratorInterface
{
return $this;
}
/**
* @param Account $account
* @param Carbon $date
@@ -139,7 +149,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
{
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($this->start, $this->end);
$journals = $collector->getJournals();
$journals = $journals->reverse();

View File

@@ -132,51 +132,19 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
}
/**
* @param Collection $collection
* @param int $sortFlag
* @param Collection $tags
*
* @return array
* @return ReportGeneratorInterface
*/
private function getAverages(Collection $collection, int $sortFlag): array
public function setTags(Collection $tags): ReportGeneratorInterface
{
$result = [];
/** @var Transaction $transaction */
foreach ($collection as $transaction) {
// opposing name and ID:
$opposingId = $transaction->opposing_account_id;
// is not set?
if (!isset($result[$opposingId])) {
$name = $transaction->opposing_account_name;
$result[$opposingId] = [
'name' => $name,
'count' => 1,
'id' => $opposingId,
'average' => $transaction->transaction_amount,
'sum' => $transaction->transaction_amount,
];
continue;
}
$result[$opposingId]['count']++;
$result[$opposingId]['sum'] = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
$result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
}
// sort result by average:
$average = [];
foreach ($result as $key => $row) {
$average[$key] = floatval($row['average']);
}
array_multisort($average, $sortFlag, $result);
return $result;
return $this;
}
/**
* @return Collection
*/
private function getExpenses(): Collection
protected function getExpenses(): Collection
{
if ($this->expenses->count() > 0) {
Log::debug('Return previous set of expenses.');
@@ -185,7 +153,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
}
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
->setTypes([TransactionType::WITHDRAWAL])
->setBudgets($this->budgets)->withOpposingAccount()->disableFilter();
@@ -198,34 +166,6 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
return $transactions;
}
/**
* @return Collection
*/
private function getTopExpenses(): Collection
{
$transactions = $this->getExpenses()->sortBy('transaction_amount');
return $transactions;
}
/**
* @param Collection $collection
*
* @return array
*/
private function summarizeByAccount(Collection $collection): array
{
$result = [];
/** @var Transaction $transaction */
foreach ($collection as $transaction) {
$accountId = $transaction->account_id;
$result[$accountId] = $result[$accountId] ?? '0';
$result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
}
return $result;
}
/**
* @param Collection $collection
*

View File

@@ -142,51 +142,19 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
}
/**
* @param Collection $collection
* @param int $sortFlag
* @param Collection $tags
*
* @return array
* @return ReportGeneratorInterface
*/
private function getAverages(Collection $collection, int $sortFlag): array
public function setTags(Collection $tags): ReportGeneratorInterface
{
$result = [];
/** @var Transaction $transaction */
foreach ($collection as $transaction) {
// opposing name and ID:
$opposingId = $transaction->opposing_account_id;
// is not set?
if (!isset($result[$opposingId])) {
$name = $transaction->opposing_account_name;
$result[$opposingId] = [
'name' => $name,
'count' => 1,
'id' => $opposingId,
'average' => $transaction->transaction_amount,
'sum' => $transaction->transaction_amount,
];
continue;
}
$result[$opposingId]['count']++;
$result[$opposingId]['sum'] = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
$result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
}
// sort result by average:
$average = [];
foreach ($result as $key => $row) {
$average[$key] = floatval($row['average']);
}
array_multisort($average, $sortFlag, $result);
return $result;
return $this;
}
/**
* @return Collection
*/
private function getExpenses(): Collection
protected function getExpenses(): Collection
{
if ($this->expenses->count() > 0) {
Log::debug('Return previous set of expenses.');
@@ -195,7 +163,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
}
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setCategories($this->categories)->withOpposingAccount()->disableFilter();
@@ -211,14 +179,14 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
/**
* @return Collection
*/
private function getIncome(): Collection
protected function getIncome(): Collection
{
if ($this->income->count() > 0) {
return $this->income;
}
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->setCategories($this->categories)->withOpposingAccount();
@@ -230,85 +198,6 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
return $transactions;
}
/**
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly five.
* @param array $spent
* @param array $earned
*
* @return array
*/
private function getObjectSummary(array $spent, array $earned): array
{
$return = [];
/**
* @var int $accountId
* @var string $entry
*/
foreach ($spent as $objectId => $entry) {
if (!isset($return[$objectId])) {
$return[$objectId] = ['spent' => 0, 'earned' => 0];
}
$return[$objectId]['spent'] = $entry;
}
unset($entry);
/**
* @var int $accountId
* @var string $entry
*/
foreach ($earned as $objectId => $entry) {
if (!isset($return[$objectId])) {
$return[$objectId] = ['spent' => 0, 'earned' => 0];
}
$return[$objectId]['earned'] = $entry;
}
return $return;
}
/**
* @return Collection
*/
private function getTopExpenses(): Collection
{
$transactions = $this->getExpenses()->sortBy('transaction_amount');
return $transactions;
}
/**
* @return Collection
*/
private function getTopIncome(): Collection
{
$transactions = $this->getIncome()->sortByDesc('transaction_amount');
return $transactions;
}
/**
* @param Collection $collection
*
* @return array
*/
private function summarizeByAccount(Collection $collection): array
{
$result = [];
/** @var Transaction $transaction */
foreach ($collection as $transaction) {
$accountId = $transaction->account_id;
$result[$accountId] = $result[$accountId] ?? '0';
$result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
}
return $result;
}
/**
* @param Collection $collection
*

View File

@@ -17,7 +17,7 @@ namespace FireflyIII\Generator\Report\Category;
/**
* Class MultiYearReportGenerator
*
* @package FireflyIII\Generator\Report\Audit
* @package FireflyIII\Generator\Report\Category
*/
class MultiYearReportGenerator extends MonthReportGenerator
{

View File

@@ -17,7 +17,7 @@ namespace FireflyIII\Generator\Report\Category;
/**
* Class YearReportGenerator
*
* @package FireflyIII\Generator\Report\Audit
* @package FireflyIII\Generator\Report\Category
*/
class YearReportGenerator extends MonthReportGenerator
{

View File

@@ -49,7 +49,7 @@ class ReportGeneratorFactory
$class = sprintf('FireflyIII\Generator\Report\%s\%sReportGenerator', $type, $period);
if (class_exists($class)) {
/** @var ReportGeneratorInterface $obj */
$obj = new $class;
$obj = app($class);
$obj->setStartDate($start);
$obj->setEndDate($end);

View File

@@ -64,4 +64,11 @@ interface ReportGeneratorInterface
*/
public function setStartDate(Carbon $date): ReportGeneratorInterface;
/**
* @param Collection $tags
*
* @return ReportGeneratorInterface
*/
public function setTags(Collection $tags): ReportGeneratorInterface;
}

View File

@@ -106,4 +106,14 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $this;
}
/**
* @param Collection $tags
*
* @return ReportGeneratorInterface
*/
public function setTags(Collection $tags): ReportGeneratorInterface
{
return $this;
}
}

View File

@@ -103,4 +103,14 @@ class MultiYearReportGenerator implements ReportGeneratorInterface
return $this;
}
/**
* @param Collection $tags
*
* @return ReportGeneratorInterface
*/
public function setTags(Collection $tags): ReportGeneratorInterface
{
return $this;
}
}

View File

@@ -103,4 +103,14 @@ class YearReportGenerator implements ReportGeneratorInterface
return $this;
}
/**
* @param Collection $tags
*
* @return ReportGeneratorInterface
*/
public function setTags(Collection $tags): ReportGeneratorInterface
{
return $this;
}
}

View File

@@ -80,4 +80,124 @@ class Support
return $result;
}
/**
* @return Collection
*/
public function getTopExpenses(): Collection
{
$transactions = $this->getExpenses()->sortBy('transaction_amount');
return $transactions;
}
/**
* @return Collection
*/
public function getTopIncome(): Collection
{
$transactions = $this->getIncome()->sortByDesc('transaction_amount');
return $transactions;
}
/**
* @param Collection $collection
* @param int $sortFlag
*
* @return array
*/
protected function getAverages(Collection $collection, int $sortFlag): array
{
$result = [];
/** @var Transaction $transaction */
foreach ($collection as $transaction) {
// opposing name and ID:
$opposingId = $transaction->opposing_account_id;
// is not set?
if (!isset($result[$opposingId])) {
$name = $transaction->opposing_account_name;
$result[$opposingId] = [
'name' => $name,
'count' => 1,
'id' => $opposingId,
'average' => $transaction->transaction_amount,
'sum' => $transaction->transaction_amount,
];
continue;
}
$result[$opposingId]['count']++;
$result[$opposingId]['sum'] = bcadd($result[$opposingId]['sum'], $transaction->transaction_amount);
$result[$opposingId]['average'] = bcdiv($result[$opposingId]['sum'], strval($result[$opposingId]['count']));
}
// sort result by average:
$average = [];
foreach ($result as $key => $row) {
$average[$key] = floatval($row['average']);
}
array_multisort($average, $sortFlag, $result);
return $result;
}
/**
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly five.
* @param array $spent
* @param array $earned
*
* @return array
*/
protected function getObjectSummary(array $spent, array $earned): array
{
$return = [];
/**
* @var int $accountId
* @var string $entry
*/
foreach ($spent as $objectId => $entry) {
if (!isset($return[$objectId])) {
$return[$objectId] = ['spent' => 0, 'earned' => 0];
}
$return[$objectId]['spent'] = $entry;
}
unset($entry);
/**
* @var int $accountId
* @var string $entry
*/
foreach ($earned as $objectId => $entry) {
if (!isset($return[$objectId])) {
$return[$objectId] = ['spent' => 0, 'earned' => 0];
}
$return[$objectId]['earned'] = $entry;
}
return $return;
}
/**
* @param Collection $collection
*
* @return array
*/
protected function summarizeByAccount(Collection $collection): array
{
$result = [];
/** @var Transaction $transaction */
foreach ($collection as $transaction) {
$accountId = $transaction->account_id;
$result[$accountId] = $result[$accountId] ?? '0';
$result[$accountId] = bcadd($transaction->transaction_amount, $result[$accountId]);
}
return $result;
}
}

View File

@@ -0,0 +1,219 @@
<?php
/**
* MonthReportGenerator.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Generator\Report\Tag;
use Carbon\Carbon;
use FireflyIII\Generator\Report\ReportGeneratorInterface;
use FireflyIII\Generator\Report\Support;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use Illuminate\Support\Collection;
use Log;
/**
* Class MonthReportGenerator
*
* @package FireflyIII\Generator\Report\Tag
*/
class MonthReportGenerator extends Support implements ReportGeneratorInterface
{
/** @var Collection */
private $accounts;
/** @var Carbon */
private $end;
/** @var Collection */
private $expenses;
/** @var Collection */
private $income;
/** @var Carbon */
private $start;
/** @var Collection */
private $tags;
/**
* MonthReportGenerator constructor.
*/
public function __construct()
{
$this->expenses = new Collection;
$this->income = new Collection;
}
/**
* @return string
*/
public function generate(): string
{
$accountIds = join(',', $this->accounts->pluck('id')->toArray());
$tagTags = join(',', $this->tags->pluck('tag')->toArray());
$reportType = 'tag';
$expenses = $this->getExpenses();
$income = $this->getIncome();
$accountSummary = $this->getObjectSummary($this->summarizeByAccount($expenses), $this->summarizeByAccount($income));
$tagSummary = $this->getObjectSummary($this->summarizeByTag($expenses), $this->summarizeByTag($income));
$averageExpenses = $this->getAverages($expenses, SORT_ASC);
$averageIncome = $this->getAverages($income, SORT_DESC);
$topExpenses = $this->getTopExpenses();
$topIncome = $this->getTopIncome();
// render!
return view(
'reports.tag.month', compact(
'accountIds', 'tagTags', 'reportType', 'accountSummary', 'tagSummary', 'averageExpenses', 'averageIncome', 'topIncome',
'topExpenses'
)
)->with('start', $this->start)->with('end', $this->end)->with('tags', $this->tags)->with('accounts', $this->accounts)->render();
}
/**
* @param Collection $accounts
*
* @return ReportGeneratorInterface
*/
public function setAccounts(Collection $accounts): ReportGeneratorInterface
{
$this->accounts = $accounts;
return $this;
}
/**
* @param Collection $budgets
*
* @return ReportGeneratorInterface
*/
public function setBudgets(Collection $budgets): ReportGeneratorInterface
{
return $this;
}
/**
* @param Collection $categories
*
* @return ReportGeneratorInterface
*/
public function setCategories(Collection $categories): ReportGeneratorInterface
{
return $this;
}
/**
* @param Carbon $date
*
* @return ReportGeneratorInterface
*/
public function setEndDate(Carbon $date): ReportGeneratorInterface
{
$this->end = $date;
return $this;
}
/**
* @param Carbon $date
*
* @return ReportGeneratorInterface
*/
public function setStartDate(Carbon $date): ReportGeneratorInterface
{
$this->start = $date;
return $this;
}
/**
* @param Collection $tags
*
* @return ReportGeneratorInterface
*/
public function setTags(Collection $tags): ReportGeneratorInterface
{
$this->tags = $tags;
return $this;
}
/**
* @return Collection
*/
protected function getExpenses(): Collection
{
if ($this->expenses->count() > 0) {
Log::debug('Return previous set of expenses.');
return $this->expenses;
}
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setTags($this->tags)->withOpposingAccount()->disableFilter();
$accountIds = $this->accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$transactions = self::filterExpenses($transactions, $accountIds);
$this->expenses = $transactions;
return $transactions;
}
/**
* @return Collection
*/
protected function getIncome(): Collection
{
if ($this->income->count() > 0) {
return $this->income;
}
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->setTags($this->tags)->withOpposingAccount();
$accountIds = $this->accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$transactions = self::filterIncome($transactions, $accountIds);
$this->income = $transactions;
return $transactions;
}
/**
* @param Collection $collection
*
* @return array
*/
protected function summarizeByTag(Collection $collection): array
{
$result = [];
/** @var Transaction $transaction */
foreach ($collection as $transaction) {
$journal = $transaction->transactionJournal;
$journalTags = $journal->tags;
/** @var Tag $journalTag */
foreach ($journalTags as $journalTag) {
$journalTagId = $journalTag->id;
$result[$journalTagId] = $result[$journalTagId] ?? '0';
$result[$journalTagId] = bcadd($transaction->transaction_amount, $result[$journalTagId]);
}
}
return $result;
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* MultiYearReportGenerator.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Generator\Report\Tag;
/**
* Class MultiYearReportGenerator
*
* @package FireflyIII\Generator\Report\Tag
*/
class MultiYearReportGenerator extends MonthReportGenerator
{
/**
* Doesn't do anything different.
*/
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* YearReportGenerator.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Generator\Report\Tag;
/**
* Class YearReportGenerator
*
* @package FireflyIII\Generator\Report\Tag
*/
class YearReportGenerator extends MonthReportGenerator
{
/**
* Doesn't do anything different.
*/
}

View File

@@ -20,6 +20,7 @@ use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Rules\Processor;
use FireflyIII\Support\Events\BillScanner;
use Log;
@@ -45,6 +46,16 @@ class StoredJournalEventHandler
$piggyBankId = $event->piggyBankId;
Log::debug(sprintf('Trying to connect journal %d to piggy bank %d.', $journal->id, $piggyBankId));
/*
* Will only continue when journal is a transfer.
*/
Log::debug(sprintf('Journal transaction type is %s', $journal->transactionType->type));
if ($journal->transactionType->type !== TransactionType::TRANSFER) {
Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id));
return true;
}
/*
* Verify existence of piggy bank:
*/
@@ -57,9 +68,15 @@ class StoredJournalEventHandler
/*
* Get relevant data:
*/
$piggyBank = $journal->user->piggyBanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
$amount = $this->getExactAmount($journal, $piggyBank, $repetition);
$piggyBank = $journal->user->piggyBanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
$amount = $this->getExactAmount($journal, $piggyBank, $repetition);
if (bccomp($amount, '0') === 0) {
Log::debug('Amount is zero, will not create event.');
return true;
}
$repetition->currentamount = bcadd($repetition->currentamount, $amount);
$repetition->save();
@@ -134,8 +151,8 @@ class StoredJournalEventHandler
*/
private function getExactAmount(TransactionJournal $journal, PiggyBank $piggyBank, PiggyBankRepetition $repetition): string
{
$amount = TransactionJournal::amountPositive($journal);
$sources = TransactionJournal::sourceAccountList($journal)->pluck('id')->toArray();
$amount = $journal->amountPositive();
$sources = $journal->sourceAccountList()->pluck('id')->toArray();
$room = bcsub(strval($piggyBank->targetamount), strval($repetition->currentamount));
$compare = bcmul($repetition->currentamount, '-1');

View File

@@ -19,7 +19,6 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Mail\Message;
use Log;
use Mail;
use Session;
use Swift_TransportException;
/**
@@ -54,20 +53,6 @@ class UserEventHandler
return true;
}
/**
* Handle user logout events.
*
* @return bool
*/
public function logoutUser(): bool
{
// dump stuff from the session:
Session::forget('twofactor-authenticated');
Session::forget('twofactor-authenticated-date');
return true;
}
/**
* @param RequestedNewPassword $event
*

View File

@@ -32,9 +32,9 @@ class AttachmentHelper implements AttachmentHelperInterface
/** @var MessageBag */
public $messages;
/** @var array */
protected $allowedMimes;
protected $allowedMimes = [];
/** @var int */
protected $maxUploadSize;
protected $maxUploadSize = 0;
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
protected $uploadDisk;
@@ -44,8 +44,8 @@ class AttachmentHelper implements AttachmentHelperInterface
*/
public function __construct()
{
$this->maxUploadSize = config('firefly.maxUploadSize');
$this->allowedMimes = config('firefly.allowedMimes');
$this->maxUploadSize = intval(config('firefly.maxUploadSize'));
$this->allowedMimes = (array)config('firefly.allowedMimes');
$this->errors = new MessageBag;
$this->messages = new MessageBag;
$this->uploadDisk = Storage::disk('upload');

View File

@@ -9,7 +9,8 @@
* See the LICENSE file for details.
*/
declare(strict_types = 1);
declare(strict_types=1);
namespace FireflyIII\Helpers\Attachments;
use FireflyIII\Models\Attachment;
@@ -42,7 +43,9 @@ interface AttachmentHelperInterface
public function getMessages(): MessageBag;
/**
* @param Model $model
* @param Model $model
*
* @param null|array $files
*
* @return bool
*/

View File

@@ -14,13 +14,16 @@ namespace FireflyIII\Helpers\Chart;
use Carbon\Carbon;
use FireflyIII\Generator\Report\Support;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Steam;
/**
* Class MetaPieChart
@@ -45,19 +48,20 @@ class MetaPieChart implements MetaPieChartInterface
'account' => ['opposing_account_id'],
'budget' => ['transaction_journal_budget_id', 'transaction_budget_id'],
'category' => ['transaction_journal_category_id', 'transaction_category_id'],
'tag' => [],
];
/** @var array */
protected $repositories
= [
'account' => AccountRepositoryInterface::class,
'budget' => BudgetRepositoryInterface::class,
'category' => CategoryRepositoryInterface::class,
'tag' => TagRepositoryInterface::class,
];
/** @var Carbon */
protected $start;
/** @var Collection */
protected $tags;
/** @var string */
protected $total = '0';
/** @var User */
@@ -68,6 +72,7 @@ class MetaPieChart implements MetaPieChartInterface
$this->accounts = new Collection;
$this->budgets = new Collection;
$this->categories = new Collection;
$this->tags = new Collection;
}
/**
@@ -85,7 +90,7 @@ class MetaPieChart implements MetaPieChartInterface
// also collect all other transactions
if ($this->collectOtherObjects && $direction === 'expense') {
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [$this->user]);
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)->setTypes([TransactionType::WITHDRAWAL]);
$journals = $collector->getJournals();
$sum = strval($journals->sum('transaction_amount'));
@@ -96,7 +101,7 @@ class MetaPieChart implements MetaPieChartInterface
if ($this->collectOtherObjects && $direction === 'income') {
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)->setTypes([TransactionType::DEPOSIT]);
$journals = $collector->getJournals();
$sum = strval($journals->sum('transaction_amount'));
@@ -180,6 +185,18 @@ class MetaPieChart implements MetaPieChartInterface
return $this;
}
/**
* @param Collection $tags
*
* @return MetaPieChartInterface
*/
public function setTags(Collection $tags): MetaPieChartInterface
{
$this->tags = $tags;
return $this;
}
/**
* @param User $user
*
@@ -201,7 +218,7 @@ class MetaPieChart implements MetaPieChartInterface
$modifier = 1;
}
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts);
$collector->setRange($this->start, $this->end);
$collector->setTypes($types);
@@ -217,6 +234,11 @@ class MetaPieChart implements MetaPieChartInterface
if ($this->categories->count() > 0) {
$collector->setCategories($this->categories);
}
if ($this->tags->count() > 0) {
$collector->setTags($this->tags);
$collector->withCategoryInformation();
$collector->withBudgetInformation();
}
$accountIds = $this->accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
@@ -231,8 +253,13 @@ class MetaPieChart implements MetaPieChartInterface
*
* @return array
*/
protected function groupByFields(Collection $set, array $fields)
protected function groupByFields(Collection $set, array $fields): array
{
if (count($fields) === 0 && $this->tags->count() > 0) {
// do a special group on tags:
return $this->groupByTag($set);
}
$grouped = [];
/** @var Transaction $transaction */
foreach ($set as $transaction) {
@@ -258,16 +285,13 @@ class MetaPieChart implements MetaPieChartInterface
{
$chartData = [];
$names = [];
$repository = app($this->repositories[$type], [$this->user]);
$repository = app($this->repositories[$type]);
foreach ($array as $objectId => $amount) {
if (!isset($names[$objectId])) {
$object = $repository->find(intval($objectId));
$names[$objectId] = $object->name;
$names[$objectId] = $object->name ?? $object->tag;
}
if (bccomp($amount, '0') === -1) {
$amount = bcmul($amount, '-1');
}
$amount = Steam::positive($amount);
$this->total = bcadd($this->total, $amount);
$chartData[$names[$objectId]] = $amount;
}
@@ -275,4 +299,22 @@ class MetaPieChart implements MetaPieChartInterface
return $chartData;
}
}
private function groupByTag(Collection $set): array
{
$grouped = [];
/** @var Transaction $transaction */
foreach ($set as $transaction) {
$journal = $transaction->transactionJournal;
$tags = $journal->tags;
/** @var Tag $tag */
foreach ($tags as $tag) {
$tagId = $tag->id;
$grouped[$tagId] = $grouped[$tagId] ?? '0';
$grouped[$tagId] = bcadd($transaction->transaction_amount, $grouped[$tagId]);
}
}
return $grouped;
}
}

View File

@@ -72,6 +72,13 @@ interface MetaPieChartInterface
*/
public function setStart(Carbon $start): MetaPieChartInterface;
/**
* @param Collection $tags
*
* @return MetaPieChartInterface
*/
public function setTags(Collection $tags): MetaPieChartInterface;
/**
* @param User $user
*
@@ -79,4 +86,4 @@ interface MetaPieChartInterface
*/
public function setUser(User $user): MetaPieChartInterface;
}
}

View File

@@ -1,107 +0,0 @@
<?php
/**
* Account.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Collection;
use Illuminate\Support\Collection;
/**
* Class Account
*
* @package FireflyIII\Helpers\Collection
*/
class Account
{
/** @var Collection */
protected $accounts;
/** @var string */
protected $difference = '';
/** @var string */
protected $end = '';
/** @var string */
protected $start = '';
/**
* Account constructor.
*/
public function __construct()
{
$this->accounts = new Collection;
}
/**
* @return Collection
*/
public function getAccounts(): Collection
{
return $this->accounts;
}
/**
* @param Collection $accounts
*/
public function setAccounts(Collection $accounts)
{
$this->accounts = $accounts;
}
/**
* @return string
*/
public function getDifference(): string
{
return $this->difference;
}
/**
* @param string $difference
*/
public function setDifference(string $difference)
{
$this->difference = $difference;
}
/**
* @return string
*/
public function getEnd(): string
{
return $this->end;
}
/**
* @param string $end
*/
public function setEnd(string $end)
{
$this->end = $end;
}
/**
* @return string
*/
public function getStart(): string
{
return $this->start;
}
/**
* @param string $start
*/
public function setStart(string $start)
{
$this->start = $start;
}
}

View File

@@ -1,193 +0,0 @@
<?php
/**
* Budget.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Collection;
use Illuminate\Support\Collection;
/**
*
* Class Budget
*
* @package FireflyIII\Helpers\Collection
*/
class Budget
{
/** @var Collection */
protected $budgetLines;
/** @var string */
protected $budgeted = '0';
/** @var string */
protected $left = '0';
/** @var string */
protected $overspent = '0';
/** @var string */
protected $spent = '0';
/**
*
*/
public function __construct()
{
$this->budgetLines = new Collection;
}
/**
* @param BudgetLine $budgetLine
*
* @return Budget
*/
public function addBudgetLine(BudgetLine $budgetLine): Budget
{
$this->budgetLines->push($budgetLine);
return $this;
}
/**
* @param string $add
*
* @return Budget
*/
public function addBudgeted(string $add): Budget
{
$this->budgeted = bcadd($this->budgeted, $add);
return $this;
}
/**
* @param string $add
*
* @return Budget
*/
public function addLeft(string $add): Budget
{
$this->left = bcadd($this->left, $add);
return $this;
}
/**
* @param string $add
*
* @return Budget
*/
public function addOverspent(string $add): Budget
{
$this->overspent = bcadd($this->overspent, $add);
return $this;
}
/**
* @param string $add
*
* @return Budget
*/
public function addSpent(string $add): Budget
{
$this->spent = bcadd($this->spent, $add);
return $this;
}
/**
* @return \Illuminate\Support\Collection
*/
public function getBudgetLines(): Collection
{
return $this->budgetLines;
}
/**
* @return string
*/
public function getBudgeted(): string
{
return $this->budgeted;
}
/**
* @param string $budgeted
*
* @return Budget
*/
public function setBudgeted(string $budgeted): Budget
{
$this->budgeted = $budgeted;
return $this;
}
/**
* @return string
*/
public function getLeft(): string
{
return $this->left;
}
/**
* @param string $left
*
* @return Budget
*/
public function setLeft(string $left): Budget
{
$this->left = $left;
return $this;
}
/**
* @return string
*/
public function getOverspent(): string
{
return $this->overspent;
}
/**
* @param string $overspent
*
* @return Budget
*/
public function setOverspent(string $overspent): Budget
{
$this->overspent = $overspent;
return $this;
}
/**
* @return string
*/
public function getSpent(): string
{
return $this->spent;
}
/**
* @param string $spent
*
* @return Budget
*/
public function setSpent(string $spent): Budget
{
$this->spent = $spent;
return $this;
}
}

View File

@@ -1,161 +0,0 @@
<?php
/**
* BudgetLine.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Budget as BudgetModel;
use FireflyIII\Models\BudgetLimit;
/**
*
* Class BudgetLine
*
* @package FireflyIII\Helpers\Collection
*/
class BudgetLine
{
/** @var BudgetModel */
protected $budget;
/** @var BudgetLimit */
protected $budgetLimit;
/** @var string */
protected $budgeted = '0';
/** @var string */
protected $left = '0';
/** @var string */
protected $overspent = '0';
/** @var string */
protected $spent = '0';
/**
* @return BudgetModel
*/
public function getBudget(): BudgetModel
{
return $this->budget ?? new BudgetModel;
}
/**
* @param BudgetModel $budget
*
* @return BudgetLine
*/
public function setBudget(BudgetModel $budget): BudgetLine
{
$this->budget = $budget;
return $this;
}
/**
* @return BudgetLimit
*/
public function getBudgetLimit(): BudgetLimit
{
return $this->budgetLimit ?? new BudgetLimit;
}
/**
* @param BudgetLimit $budgetLimit
*
* @return BudgetLimit
*/
public function setBudgetLimit(BudgetLimit $budgetLimit): BudgetLine
{
$this->budgetLimit = $budgetLimit;
return $this;
}
/**
* @return string
*/
public function getBudgeted(): string
{
return $this->budgeted;
}
/**
* @param string $budgeted
*
* @return BudgetLine
*/
public function setBudgeted(string $budgeted): BudgetLine
{
$this->budgeted = $budgeted;
return $this;
}
/**
* @return string
*/
public function getLeft(): string
{
return $this->left;
}
/**
* @param string $left
*
* @return BudgetLine
*/
public function setLeft(string $left): BudgetLine
{
$this->left = $left;
return $this;
}
/**
* @return string
*/
public function getOverspent(): string
{
return $this->overspent;
}
/**
* @param string $overspent
*
* @return BudgetLine
*/
public function setOverspent(string $overspent): BudgetLine
{
$this->overspent = $overspent;
return $this;
}
/**
* @return string
*/
public function getSpent(): string
{
return $this->spent;
}
/**
* @param string $spent
*
* @return BudgetLine
*/
public function setSpent(string $spent): BudgetLine
{
$this->spent = $spent;
return $this;
}
}

View File

@@ -32,6 +32,7 @@ use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Log;
use Steam;
/**
* Maybe this is a good idea after all...
@@ -54,9 +55,7 @@ class JournalCollector implements JournalCollectorInterface
'transaction_journals.description',
'transaction_journals.date',
'transaction_journals.encrypted',
//'transaction_journals.transaction_currency_id',
'transaction_currencies.code as transaction_currency_code',
//'transaction_currencies.symbol as transaction_currency_symbol',
'transaction_types.type as transaction_type_type',
'transaction_journals.bill_id',
'bills.name as bill_name',
@@ -96,17 +95,6 @@ class JournalCollector implements JournalCollectorInterface
/** @var User */
private $user;
/**
* JournalCollector constructor.
*
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
$this->query = $this->startQuery();
}
/**
* @return int
* @throws FireflyException
@@ -167,7 +155,8 @@ class JournalCollector implements JournalCollectorInterface
public function getJournals(): Collection
{
$this->run = true;
$set = $this->query->get(array_values($this->fields));
/** @var Collection $set */
$set = $this->query->get(array_values($this->fields));
Log::debug(sprintf('Count of set is %d', $set->count()));
$set = $this->filterTransfers($set);
Log::debug(sprintf('Count of set after filterTransfers() is %d', $set->count()));
@@ -181,10 +170,10 @@ class JournalCollector implements JournalCollectorInterface
$set->each(
function (Transaction $transaction) {
$transaction->date = new Carbon($transaction->date);
$transaction->description = $transaction->encrypted ? Crypt::decrypt($transaction->description) : $transaction->description;
$transaction->description = Steam::decrypt(intval($transaction->encrypted), $transaction->description);
if (!is_null($transaction->bill_name)) {
$transaction->bill_name = $transaction->bill_name_encrypted ? Crypt::decrypt($transaction->bill_name) : $transaction->bill_name;
$transaction->bill_name = Steam::decrypt(intval($transaction->bill_name_encrypted), $transaction->bill_name);
}
try {
@@ -243,8 +232,9 @@ class JournalCollector implements JournalCollectorInterface
public function setAllAssetAccounts(): JournalCollectorInterface
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class, [$this->user]);
$accounts = $repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]);
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user);
$accounts = $repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]);
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$this->query->whereIn('transactions.account_id', $accountIds);
@@ -440,6 +430,20 @@ class JournalCollector implements JournalCollectorInterface
return $this;
}
/**
* @param Collection $tags
*
* @return JournalCollectorInterface
*/
public function setTags(Collection $tags): JournalCollectorInterface
{
$this->joinTagTables();
$tagIds = $tags->pluck('id')->toArray();
$this->query->whereIn('tag_transaction_journal.tag_id', $tagIds);
return $this;
}
/**
* @param array $types
*
@@ -455,6 +459,37 @@ class JournalCollector implements JournalCollectorInterface
return $this;
}
/**
* @param User $user
*/
public function setUser(User $user)
{
$this->user = $user;
}
/**
*
*/
public function startQuery()
{
/** @var EloquentBuilder $query */
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transaction_journals.user_id', $this->user->id)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC');
$this->query = $query;
}
/**
* @return JournalCollectorInterface
*/
@@ -483,36 +518,6 @@ class JournalCollector implements JournalCollectorInterface
{
$this->joinOpposingTables();
$accountIds = $this->accountIds;
$this->query->where(
function (EloquentBuilder $q1) use ($accountIds) {
// set 1:
// where source is in the set of $accounts
// but destination is not.
$q1->where(
function (EloquentBuilder $q2) use ($accountIds) {
// transactions.account_id in set
$q2->whereIn('transactions.account_id', $accountIds);
// opposing.account_id not in set
$q2->whereNotIn('opposing.account_id', $accountIds);
}
);
// set 1:
// where source is not in the set of $accounts
// but destination is.
$q1->orWhere(
function (EloquentBuilder $q3) use ($accountIds) {
// transactions.account_id not in set
$q3->whereNotIn('transactions.account_id', $accountIds);
// B in set
// opposing.account_id not in set
$q3->whereIn('opposing.account_id', $accountIds);
}
);
}
);
return $this;
}
@@ -596,7 +601,7 @@ class JournalCollector implements JournalCollectorInterface
* account, chances are the set include double entries: transfers get selected
* on both the source, and then again on the destination account.
*
* This method filters them out.
* This method filters them out by removing transfers that have been selected twice.
*
* @param Collection $set
*
@@ -605,36 +610,29 @@ class JournalCollector implements JournalCollectorInterface
private function filterTransfers(Collection $set): Collection
{
if ($this->filterTransfers) {
$set = $set->filter(
function (Transaction $transaction) {
if (!($transaction->transaction_type_type === TransactionType::TRANSFER && bccomp($transaction->transaction_amount, '0') === -1)) {
Log::debug(
sprintf(
'Included journal #%d (transaction #%d) because its a %s with amount %f',
$transaction->transaction_journal_id,
$transaction->id,
$transaction->transaction_type_type,
$transaction->transaction_amount
)
);
return $transaction;
}
Log::debug(
sprintf(
'Removed journal #%d (transaction #%d) because its a %s with amount %f',
$transaction->transaction_journal_id,
$transaction->id,
$transaction->transaction_type_type,
$transaction->transaction_amount
)
);
return false;
$count = [];
$new = new Collection;
/** @var Transaction $transaction */
foreach ($set as $transaction) {
if ($transaction->transaction_type_type !== TransactionType::TRANSFER) {
$new->push($transaction);
continue;
}
);
// make property string:
$journalId = $transaction->transaction_journal_id;
$amount = Steam::positive($transaction->transaction_amount);
$accountIds = [intval($transaction->account_id), intval($transaction->opposing_account_id)];
sort($accountIds);
$key = $journalId . '-' . join(',', $accountIds) . '-' . $amount;
Log::debug(sprintf('Key is %s', $key));
if (!isset($count[$key])) {
// not yet counted? add to new set and count it:
$new->push($transaction);
$count[$key] = 1;
}
}
return $new;
}
return $set;
@@ -728,27 +726,4 @@ class JournalCollector implements JournalCollectorInterface
$this->query->leftJoin('tag_transaction_journal', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
}
}
/**
* @return EloquentBuilder
*/
private function startQuery(): EloquentBuilder
{
/** @var EloquentBuilder $query */
$query = Transaction::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id')
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id')
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id')
->whereNull('transactions.deleted_at')
->whereNull('transaction_journals.deleted_at')
->where('transaction_journals.user_id', $this->user->id)
->orderBy('transaction_journals.date', 'DESC')
->orderBy('transaction_journals.order', 'ASC')
->orderBy('transaction_journals.id', 'DESC');
return $query;
}
}

View File

@@ -17,6 +17,7 @@ use Carbon\Carbon;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use FireflyIII\User;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
@@ -27,7 +28,6 @@ use Illuminate\Support\Collection;
*/
interface JournalCollectorInterface
{
/**
* @return int
*/
@@ -84,7 +84,6 @@ interface JournalCollectorInterface
*/
public function setBudget(Budget $budget): JournalCollectorInterface;
/**
* @param Collection $budgets
*
@@ -142,6 +141,13 @@ interface JournalCollectorInterface
*/
public function setTag(Tag $tag): JournalCollectorInterface;
/**
* @param Collection $tags
*
* @return JournalCollectorInterface
*/
public function setTags(Collection $tags): JournalCollectorInterface;
/**
* @param array $types
*
@@ -149,6 +155,13 @@ interface JournalCollectorInterface
*/
public function setTypes(array $types): JournalCollectorInterface;
public function setUser(User $user);
/**
*
*/
public function startQuery();
/**
* @return JournalCollectorInterface
*/

View File

@@ -9,7 +9,8 @@
* See the LICENSE file for details.
*/
declare(strict_types = 1);
declare(strict_types=1);
namespace FireflyIII\Helpers\Help;
use Cache;
@@ -43,12 +44,12 @@ class Help implements HelpInterface
}
/**
* @param string $language
* @param string $route
* @param string $language
*
* @return string
*/
public function getFromGithub(string $language, string $route): string
public function getFromGithub(string $route, string $language): string
{
$uri = sprintf('https://raw.githubusercontent.com/firefly-iii/help/master/%s/%s.md', $language, $route);
@@ -123,6 +124,7 @@ class Help implements HelpInterface
if (strlen($content) > 0) {
Log::debug(sprintf('Will store entry in cache: %s', $key));
Cache::put($key, $content, 10080); // a week.
return;
}
Log::info(sprintf('Will not cache %s because content is empty.', $key));

View File

@@ -29,12 +29,12 @@ interface HelpInterface
public function getFromCache(string $route, string $language): string;
/**
* @param string $language
* @param string $route
* @param string $language
*
* @return string
*/
public function getFromGithub(string $language, string $route): string;
public function getFromGithub(string $route, string $language): string;
/**
* @param string $route

View File

@@ -158,7 +158,9 @@ class BalanceReportHelper implements BalanceReportHelperInterface
foreach ($accounts as $account) {
$balanceEntry = new BalanceEntry;
$balanceEntry->setAccount($account);
$spent = $this->budgetRepository->spentInPeriod(new Collection([$budgetLimit->budget]), new Collection([$account]), $budgetLimit->start_date, $budgetLimit->end_date);
$spent = $this->budgetRepository->spentInPeriod(
new Collection([$budgetLimit->budget]), new Collection([$account]), $budgetLimit->start_date, $budgetLimit->end_date
);
$balanceEntry->setSpent($spent);
$line->addBalanceEntry($balanceEntry);
}

View File

@@ -15,8 +15,6 @@ namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
use FireflyIII\Helpers\Collection\BudgetLine;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
@@ -48,44 +46,63 @@ class BudgetReportHelper implements BudgetReportHelperInterface
* @param Carbon $end
* @param Collection $accounts
*
* @return BudgetCollection
* @return array
*/
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts): BudgetCollection
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts): array
{
$object = new BudgetCollection;
$set = $this->repository->getBudgets();
$set = $this->repository->getBudgets();
$array = [];
/** @var Budget $budget */
foreach ($set as $budget) {
$budgetLimits = $this->repository->getBudgetLimits($budget, $start, $end);
if ($budgetLimits->count() == 0) { // no budget limit(s) for this budget
$spent = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end);// spent for budget in time range
if ($spent > 0) {
$budgetLine = new BudgetLine;
$budgetLine->setBudget($budget)->setOverspent($spent);
$object->addOverspent($spent)->addBudgetLine($budgetLine);
if (bccomp($spent, '0') === -1) {
$line = [
'type' => 'budget',
'id' => $budget->id,
'name' => $budget->name,
'budgeted' => '0',
'spent' => $spent,
'left' => '0',
'overspent' => '0',
];
$array[] = $line;
}
continue;
}
/** @var BudgetLimit $budgetLimit */
foreach ($budgetLimits as $budgetLimit) { // one or more repetitions for budget
$data = $this->calculateExpenses($budget, $budgetLimit, $accounts);
$budgetLine = new BudgetLine;
$budgetLine->setBudget($budget)->setBudgetLimit($budgetLimit)
->setLeft($data['left'])->setSpent($data['expenses'])->setOverspent($data['overspent'])
->setBudgeted(strval($budgetLimit->amount));
$object->addBudgeted(strval($budgetLimit->amount))->addSpent($data['spent'])
->addLeft($data['left'])->addOverspent($data['overspent'])->addBudgetLine($budgetLine);
$data = $this->calculateExpenses($budget, $budgetLimit, $accounts);
$line = [
'type' => 'budget-line',
'start' => $budgetLimit->start_date,
'end' => $budgetLimit->end_date,
'limit' => $budgetLimit->id,
'id' => $budget->id,
'name' => $budget->name,
'budgeted' => strval($budgetLimit->amount),
'spent' => $data['expenses'],
'left' => $data['left'],
'overspent' => $data['overspent'],
];
$array[] = $line;
}
}
$noBudget = $this->repository->spentInPeriodWoBudget($accounts, $start, $end); // stuff outside of budgets
$budgetLine = new BudgetLine;
$budgetLine->setOverspent($noBudget)->setSpent($noBudget);
$object->addOverspent($noBudget)->addBudgetLine($budgetLine);
$noBudget = $this->repository->spentInPeriodWoBudget($accounts, $start, $end); // stuff outside of budgets
$line = [
'type' => 'no-budget',
'budgeted' => '0',
'spent' => $noBudget,
'left' => '0',
'overspent' => '0',
];
$array[] = $line;
return $object;
return $array;
}
/**

View File

@@ -15,7 +15,6 @@ namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Collection\Budget as BudgetCollection;
use Illuminate\Support\Collection;
/**
@@ -31,9 +30,9 @@ interface BudgetReportHelperInterface
* @param Carbon $end
* @param Collection $accounts
*
* @return BudgetCollection
* @return array
*/
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts): BudgetCollection;
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts): array;
/**
* @param Carbon $start

View File

@@ -0,0 +1,199 @@
<?php
/**
* PopupReport.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Report;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use Illuminate\Support\Collection;
/**
* Class PopupReport
*
* @package FireflyIII\Helpers\Report
*/
class PopupReport implements PopupReportInterface
{
/**
* @param Budget $budget
* @param Account $account
* @param array $attributes
*
* @return Collection
*/
public function balanceForBudget(Budget $budget, Account $account, array $attributes): Collection
{
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])->setBudget($budget);
$journals = $collector->getJournals();
return $journals;
}
/**
* @param Account $account
* @param array $attributes
*
* @return Collection
*/
public function balanceForNoBudget(Account $account, array $attributes): Collection
{
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector
->setAccounts(new Collection([$account]))
->setTypes([TransactionType::WITHDRAWAL])
->setRange($attributes['startDate'], $attributes['endDate'])
->withoutBudget();
return $collector->getJournals();
}
/**
* @param Budget $budget
* @param array $attributes
*
* @return Collection
*/
public function byBudget(Budget $budget, array $attributes): Collection
{
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($attributes['accounts'])->setRange($attributes['startDate'], $attributes['endDate']);
if (is_null($budget->id)) {
$collector->setTypes([TransactionType::WITHDRAWAL])->withoutBudget();
}
if (!is_null($budget->id)) {
$collector->setBudget($budget);
}
$journals = $collector->getJournals();
return $journals;
}
/**
* @param Category $category
* @param array $attributes
*
* @return Collection
*/
public function byCategory(Category $category, array $attributes): Collection
{
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($attributes['accounts'])->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setRange($attributes['startDate'], $attributes['endDate'])
->setCategory($category);
$journals = $collector->getJournals();
return $journals;
}
/**
* @param Account $account
* @param array $attributes
*
* @return Collection
*/
public function byExpenses(Account $account, array $attributes): Collection
{
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER]);
$journals = $collector->getJournals();
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
// filter for transfers and withdrawals TO the given $account
$journals = $journals->filter(
function (Transaction $transaction) use ($report) {
// get the destinations:
$sources = $transaction->transactionJournal->sourceAccountList()->pluck('id')->toArray();
// do these intersect with the current list?
return !empty(array_intersect($report, $sources));
}
);
return $journals;
}
/**
* @param Account $account
* @param array $attributes
*
* @return Collection
*/
public function byIncome(Account $account, array $attributes): Collection
{
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER]);
$journals = $collector->getJournals();
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
// filter the set so the destinations outside of $attributes['accounts'] are not included.
$journals = $journals->filter(
function (Transaction $transaction) use ($report) {
// get the destinations:
$destinations = $transaction->destinationAccountList($transaction->transactionJournal)->pluck('id')->toArray();
// do these intersect with the current list?
return !empty(array_intersect($report, $destinations));
}
);
return $journals;
}
/**
* @param $account
* @param $attributes
*
* @return Collection
*/
public function balanceDifference($account, $attributes): Collection
{
// row that displays difference
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector
->setAccounts(new Collection([$account]))
->setTypes([TransactionType::WITHDRAWAL])
->setRange($attributes['startDate'], $attributes['endDate'])
->withoutBudget();
$journals = $collector->getJournals();
return $journals->filter(
function (Transaction $transaction) {
$tags = $transaction->transactionJournal->tags()->where('tagMode', 'balancingAct')->count();
if ($tags === 0) {
return true;
}
return false;
}
);
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* PopupReportInterface.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
* This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License.
*
* See the LICENSE file for details.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Report;
use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use Illuminate\Support\Collection;
/**
* Interface PopupReportInterface
*
* @package FireflyIII\Helpers\Report
*/
interface PopupReportInterface
{
/**
* @param $account
* @param $attributes
*
* @return Collection
*/
public function balanceDifference($account, $attributes): Collection;
/**
* @param Budget $budget
* @param Account $account
* @param array $attributes
*
* @return Collection
*/
public function balanceForBudget(Budget $budget, Account $account, array $attributes): Collection;
/**
* @param Account $account
* @param array $attributes
*
* @return Collection
*/
public function balanceForNoBudget(Account $account, array $attributes): Collection;
/**
* @param Budget $budget
* @param array $attributes
*
* @return Collection
*/
public function byBudget(Budget $budget, array $attributes): Collection;
/**
* @param Category $category
* @param array $attributes
*
* @return Collection
*/
public function byCategory(Category $category, array $attributes): Collection;
/**
* @param Account $account
* @param array $attributes
*
* @return Collection
*/
public function byExpenses(Account $account, array $attributes): Collection;
/**
* @param Account $account
* @param array $attributes
*
* @return Collection
*/
public function byIncome(Account $account, array $attributes): Collection;
}

View File

@@ -16,15 +16,12 @@ namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Collection\Bill as BillCollection;
use FireflyIII\Helpers\Collection\BillLine;
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\FiscalHelperInterface;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use Illuminate\Support\Collection;
/**
@@ -68,7 +65,7 @@ class ReportHelper implements ReportHelperInterface
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$bills = $repository->getBillsForAccounts($accounts);
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setBills($bills);
$journals = $collector->getJournals();
$collection = new BillCollection;

View File

@@ -15,7 +15,6 @@ namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Collection\Bill as BillCollection;
use FireflyIII\Helpers\Collection\Category as CategoryCollection;
use FireflyIII\Helpers\Collection\Expense;
use FireflyIII\Helpers\Collection\Income;
use Illuminate\Support\Collection;

View File

@@ -23,18 +23,16 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Log;
use Navigation;
use Preferences;
use Session;
use Steam;
use URL;
use View;
/**
@@ -63,11 +61,12 @@ class AccountController extends Controller
}
/**
* @param string $what
* @param Request $request
* @param string $what
*
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory|View
* @return View
*/
public function create(string $what = 'asset')
public function create(Request $request, string $what = 'asset')
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
@@ -75,29 +74,35 @@ class AccountController extends Controller
$defaultCurrency = Amount::getDefaultCurrency();
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
$subTitle = trans('firefly.make_new_' . $what . '_account');
$roles = [];
foreach (config('firefly.accountRoles') as $role) {
$roles[$role] = strval(trans('firefly.account_role_' . $role));
}
// pre fill some data
Session::flash('preFilled', ['currency_id' => $defaultCurrency->id,]);
$request->session()->flash('preFilled', ['currency_id' => $defaultCurrency->id,]);
// put previous url in session if not redirect from store (not "create another").
if (session('accounts.create.fromStore') !== true) {
Session::put('accounts.create.url', URL::previous());
$this->rememberPreviousUri('accounts.create.uri');
}
Session::forget('accounts.create.fromStore');
Session::flash('gaEventCategory', 'accounts');
Session::flash('gaEventAction', 'create-' . $what);
$request->session()->forget('accounts.create.fromStore');
$request->session()->flash('gaEventCategory', 'accounts');
$request->session()->flash('gaEventAction', 'create-' . $what);
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'currencies'));
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'currencies', 'roles'));
}
/**
* @param ARI $repository
* @param Account $account
* @param Request $request
* @param AccountRepositoryInterface $repository
* @param Account $account
*
* @return View
*/
public function delete(ARI $repository, Account $account)
public function delete(Request $request, AccountRepositoryInterface $repository, Account $account)
{
$typeName = config('firefly.shortNamesByFullName.' . $account->accountType->type);
$subTitle = trans('firefly.delete_' . $typeName . '_account', ['name' => $account->name]);
@@ -105,48 +110,42 @@ class AccountController extends Controller
unset($accountList[$account->id]);
// put previous url in session
Session::put('accounts.delete.url', URL::previous());
Session::flash('gaEventCategory', 'accounts');
Session::flash('gaEventAction', 'delete-' . $typeName);
$this->rememberPreviousUri('accounts.delete.uri');
$request->session()->flash('gaEventCategory', 'accounts');
$request->session()->flash('gaEventAction', 'delete-' . $typeName);
return view('accounts.delete', compact('account', 'subTitle', 'accountList'));
}
/**
* @param Request $request
* @param ARI $repository
* @param Account $account
* @param Request $request
* @param AccountRepositoryInterface $repository
* @param Account $account
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function destroy(Request $request, ARI $repository, Account $account)
public function destroy(Request $request, AccountRepositoryInterface $repository, Account $account)
{
$type = $account->accountType->type;
$typeName = config('firefly.shortNamesByFullName.' . $type);
$name = $account->name;
$accountId = $account->id;
$moveTo = $repository->find(intval($request->get('move_account_before_delete')));
$type = $account->accountType->type;
$typeName = config('firefly.shortNamesByFullName.' . $type);
$name = $account->name;
$moveTo = $repository->find(intval($request->get('move_account_before_delete')));
$repository->destroy($account, $moveTo);
Session::flash('success', strval(trans('firefly.' . $typeName . '_deleted', ['name' => $name])));
$request->session()->flash('success', strval(trans('firefly.' . $typeName . '_deleted', ['name' => $name])));
Preferences::mark();
$uri = session('accounts.delete.url');
if (!(strpos($uri, sprintf('accounts/show/%s', $accountId)) === false)) {
// uri would point back to account
$uri = route('accounts.index', [$typeName]);
}
return redirect($uri);
return redirect($this->getPreviousUri('accounts.delete.uri'));
}
/**
* @param Request $request
* @param Account $account
*
* @return View
*/
public function edit(Account $account)
public function edit(Request $request, Account $account)
{
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
@@ -155,12 +154,17 @@ class AccountController extends Controller
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$currencies = ExpandedForm::makeSelectList($repository->get());
$roles = [];
foreach (config('firefly.accountRoles') as $role) {
$roles[$role] = strval(trans('firefly.account_role_' . $role));
}
// put previous url in session if not redirect from store (not "return_to_edit").
if (session('accounts.edit.fromUpdate') !== true) {
Session::put('accounts.edit.url', URL::previous());
$this->rememberPreviousUri('accounts.edit.uri');
}
Session::forget('accounts.edit.fromUpdate');
$request->session()->forget('accounts.edit.fromUpdate');
// pre fill some useful values.
@@ -181,20 +185,20 @@ class AccountController extends Controller
'virtualBalance' => $account->virtual_balance,
'currency_id' => $account->getMeta('currency_id'),
];
Session::flash('preFilled', $preFilled);
Session::flash('gaEventCategory', 'accounts');
Session::flash('gaEventAction', 'edit-' . $what);
$request->session()->flash('preFilled', $preFilled);
$request->session()->flash('gaEventCategory', 'accounts');
$request->session()->flash('gaEventAction', 'edit-' . $what);
return view('accounts.edit', compact('currencies', 'account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what'));
return view('accounts.edit', compact('currencies', 'account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what', 'roles'));
}
/**
* @param ARI $repository
* @param string $what
* @param AccountRepositoryInterface $repository
* @param string $what
*
* @return View
*/
public function index(ARI $repository, string $what)
public function index(AccountRepositoryInterface $repository, string $what)
{
$what = $what ?? 'asset';
$subTitle = trans('firefly.' . $what . '_accounts');
@@ -224,115 +228,111 @@ class AccountController extends Controller
return view('accounts.index', compact('what', 'subTitleIcon', 'subTitle', 'accounts'));
}
/**
* @param Request $request
* @param JournalCollectorInterface $collector
* @param Account $account
* @param Request $request
* @param JournalRepositoryInterface $repository
* @param Account $account
* @param string $moment
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*/
public function show(Request $request, JournalCollectorInterface $collector, Account $account)
public function show(Request $request, JournalRepositoryInterface $repository, Account $account, string $moment = '')
{
if ($account->accountType->type === AccountType::INITIAL_BALANCE) {
return $this->redirectToOriginalAccount($account);
}
// show journals from current period only:
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
$subTitle = $account->name;
$range = Preferences::get('viewRange', '1M')->data;
$start = session('start', Navigation::startOfPeriod(new Carbon, $range));
$end = session('end', Navigation::endOfPeriod(new Carbon, $range));
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$chartUri = route('chart.account.single', [$account->id]);
$accountType = $account->accountType->type;
$start = null;
$end = null;
$periods = new Collection;
// grab those journals:
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->setLimit($pageSize)->setPage($page);
$journals = $collector->getPaginatedJournals();
$journals->setPath('accounts/show/' . $account->id);
// prep for "all" view.
if ($moment === 'all') {
$subTitle = trans('firefly.all_journals_for_account', ['name' => $account->name]);
$chartUri = route('chart.account.all', [$account->id]);
$first = $repository->first();
$start = $first->date ?? new Carbon;
$end = new Carbon;
}
// generate entries for each period (and cache those)
$entries = $this->periodEntries($account);
// prep for "specific date" view.
if (strlen($moment) > 0 && $moment !== 'all') {
$start = new Carbon($moment);
$end = Navigation::endOfPeriod($start, $range);
$subTitle = trans(
'firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
$chartUri = route('chart.account.period', [$account->id, $start->format('Y-m-d')]);
$periods = $this->getPeriodOverview($account);
}
return view('accounts.show', compact('account', 'accountType', 'entries', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri'));
}
// prep for current period
if (strlen($moment) === 0) {
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
$subTitle = trans(
'firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
$periods = $this->getPeriodOverview($account);
}
/**
* @param Request $request
* @param ARI $repository
* @param Account $account
*
* @return View
*/
public function showAll(Request $request, AccountRepositoryInterface $repository, Account $account)
{
$subTitle = sprintf('%s (%s)', $account->name, strtolower(trans('firefly.everything')));
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$chartUri = route('chart.account.all', [$account->id]);
// replace with journal collector:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
$journals = $collector->getPaginatedJournals();
$journals->setPath('accounts/show/' . $account->id . '/all');
// get oldest and newest journal for account:
$start = $repository->oldestJournalDate($account);
$end = $repository->newestJournalDate($account);
// same call, except "entries".
return view('accounts.show', compact('account', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri'));
}
/**
* @param Request $request
* @param Account $account
* @param string $date
*
* @return View
*/
public function showByDate(Request $request, Account $account, string $date)
{
$carbon = new Carbon($date);
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($carbon, $range);
$end = Navigation::endOfPeriod($carbon, $range);
$subTitle = $account->name . ' (' . Navigation::periodShow($start, $range) . ')';
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$chartUri = route('chart.account.period', [$account->id, $carbon->format('Y-m-d')]);
$accountType = $account->accountType->type;
$count = 0;
$loop = 0;
// grab journals, but be prepared to jump a period back to get the right ones:
Log::info('Now at loop start.');
while ($count === 0 && $loop < 3) {
$loop++;
$collector = app(JournalCollectorInterface::class);
Log::info('Count is zero, search for journals.');
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page);
if (!is_null($start)) {
$collector->setRange($start, $end);
}
$journals = $collector->getPaginatedJournals();
$journals->setPath('accounts/show/' . $account->id . '/' . $moment);
$count = $journals->getCollection()->count();
if ($count === 0) {
$start->subDay();
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfPeriod($start, $range);
Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d')));
}
}
// replace with journal collector:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->setLimit($pageSize)->setPage($page);
$journals = $collector->getPaginatedJournals();
$journals->setPath('accounts/show/' . $account->id . '/' . $date);
if ($moment != 'all' && $loop > 1) {
$subTitle = trans(
'firefly.journals_in_period_for_account', ['name' => $account->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
}
// generate entries for each period (and cache those)
$entries = $this->periodEntries($account);
// same call, except "entries".
return view('accounts.show', compact('account', 'accountType', 'entries', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri'));
return view(
'accounts.show', compact('account', 'moment', 'accountType', 'periods', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri')
);
}
/**
* @param AccountFormRequest $request
* @param ARI $repository
* @param AccountFormRequest $request
* @param AccountRepositoryInterface $repository
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*
*/
public function store(AccountFormRequest $request, ARI $repository)
public function store(AccountFormRequest $request, AccountRepositoryInterface $repository)
{
$data = $request->getAccountData();
$account = $repository->store($data);
Session::flash('success', strval(trans('firefly.stored_new_account', ['name' => $account->name])));
$request->session()->flash('success', strval(trans('firefly.stored_new_account', ['name' => $account->name])));
Preferences::mark();
// update preferences if necessary:
@@ -344,39 +344,39 @@ class AccountController extends Controller
if (intval($request->get('create_another')) === 1) {
// set value so create routine will not overwrite URL:
Session::put('accounts.create.fromStore', true);
$request->session()->put('accounts.create.fromStore', true);
return redirect(route('accounts.create', [$request->input('what')]))->withInput();
}
// redirect to previous URL.
return redirect(session('accounts.create.url'));
return redirect($this->getPreviousUri('accounts.create.uri'));
}
/**
* @param AccountFormRequest $request
* @param ARI $repository
* @param Account $account
* @param AccountFormRequest $request
* @param AccountRepositoryInterface $repository
* @param Account $account
*
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function update(AccountFormRequest $request, ARI $repository, Account $account)
public function update(AccountFormRequest $request, AccountRepositoryInterface $repository, Account $account)
{
$data = $request->getAccountData();
$repository->update($account, $data);
Session::flash('success', strval(trans('firefly.updated_account', ['name' => $account->name])));
$request->session()->flash('success', strval(trans('firefly.updated_account', ['name' => $account->name])));
Preferences::mark();
if (intval($request->get('return_to_edit')) === 1) {
// set value so edit routine will not overwrite URL:
Session::put('accounts.edit.fromUpdate', true);
$request->session()->put('accounts.edit.fromUpdate', true);
return redirect(route('accounts.edit', [$account->id]))->withInput(['return_to_edit' => 1]);
}
// redirect to previous URL.
return redirect(session('accounts.edit.url'));
return redirect($this->getPreviousUri('accounts.edit.uri'));
}
@@ -405,10 +405,10 @@ class AccountController extends Controller
*
* @return Collection
*/
private function periodEntries(Account $account): Collection
private function getPeriodOverview(Account $account): Collection
{
/** @var ARI $repository */
$repository = app(ARI::class);
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
/** @var AccountTaskerInterface $tasker */
$tasker = app(AccountTaskerInterface::class);
@@ -426,9 +426,7 @@ class AccountController extends Controller
$cache->addProperty($account->id);
if ($cache->has()) {
Log::debug('Entries are cached, return cache.');
return $cache->get();
return $cache->get(); // @codeCoverageIgnore
}
// only include asset accounts when this account is an asset:
@@ -444,7 +442,14 @@ class AccountController extends Controller
$earned = $tasker->amountInInPeriod(new Collection([$account]), $assets, $end, $currentEnd);
$dateStr = $end->format('Y-m-d');
$dateName = Navigation::periodShow($end, $range);
$entries->push([$dateStr, $dateName, $spent, $earned, clone $end]);
$entries->push(
[
'string' => $dateStr,
'name' => $dateName,
'spent' => $spent,
'earned' => $earned,
'date' => clone $end]
);
$end = Navigation::subtractPeriod($end, $range, 1);
}
@@ -472,7 +477,7 @@ class AccountController extends Controller
$opposingTransaction = $journal->transactions()->where('transactions.id', '!=', $transaction->id)->first();
if (is_null($opposingTransaction)) {
throw new FireflyException('Expected an opposing transaction. This account has none. BEEP, error.');
throw new FireflyException('Expected an opposing transaction. This account has none. BEEP, error.'); // @codeCoverageIgnore
}
return redirect(route('accounts.show', [$opposingTransaction->account_id]));

View File

@@ -9,7 +9,7 @@
* See the LICENSE file for details.
*/
declare(strict_types = 1);
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Admin;
@@ -18,9 +18,9 @@ use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\UserFormRequest;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Log;
use Preferences;
use Session;
use URL;
use View;
/**
@@ -57,7 +57,7 @@ class UserController extends Controller
{
// put previous url in session if not redirect from store (not "return_to_edit").
if (session('users.edit.fromUpdate') !== true) {
Session::put('users.edit.url', URL::previous());
$this->rememberPreviousUri('users.edit.uri');
}
Session::forget('users.edit.fromUpdate');
@@ -130,33 +130,31 @@ class UserController extends Controller
*
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function update(UserFormRequest $request, User $user)
public function update(UserFormRequest $request, User $user, UserRepositoryInterface $repository)
{
Log::debug('Actually here');
$data = $request->getUserData();
// update password
if (strlen($data['password']) > 0) {
$user->password = bcrypt($data['password']);
$user->save();
$repository->changePassword($user, $data['password']);
}
// change blocked status and code:
$user->blocked = $data['blocked'];
$user->blocked_code = $data['blocked_code'];
$user->save();
$repository->changeStatus($user, $data['blocked'], $data['blocked_code']);
Session::flash('success', strval(trans('firefly.updated_user', ['email' => $user->email])));
Preferences::mark();
if (intval($request->get('return_to_edit')) === 1) {
// set value so edit routine will not overwrite URL:
// @codeCoverageIgnoreStart
Session::put('users.edit.fromUpdate', true);
return redirect(route('admin.users.edit', [$user->id]))->withInput(['return_to_edit' => 1]);
// @codeCoverageIgnoreEnd
}
// redirect to previous URL.
return redirect(session('users.edit.url'));
return redirect($this->getPreviousUri('users.edit.uri'));
}

View File

@@ -18,10 +18,10 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Requests\AttachmentFormRequest;
use FireflyIII\Models\Attachment;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Http\Response as LaravelResponse;
use Preferences;
use Response;
use Session;
use URL;
use View;
/**
@@ -53,38 +53,40 @@ class AttachmentController extends Controller
}
/**
* @param Request $request
* @param Attachment $attachment
*
* @return View
*/
public function delete(Attachment $attachment)
public function delete(Request $request, Attachment $attachment)
{
$subTitle = trans('firefly.delete_attachment', ['name' => $attachment->filename]);
// put previous url in session
Session::put('attachments.delete.url', URL::previous());
Session::flash('gaEventCategory', 'attachments');
Session::flash('gaEventAction', 'delete-attachment');
$this->rememberPreviousUri('attachments.delete.uri');
$request->session()->flash('gaEventCategory', 'attachments');
$request->session()->flash('gaEventAction', 'delete-attachment');
return view('attachments.delete', compact('attachment', 'subTitle'));
}
/**
* @param Request $request
* @param AttachmentRepositoryInterface $repository
* @param Attachment $attachment
*
* @return \Illuminate\Http\RedirectResponse
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function destroy(AttachmentRepositoryInterface $repository, Attachment $attachment)
public function destroy(Request $request, AttachmentRepositoryInterface $repository, Attachment $attachment)
{
$name = $attachment->filename;
$repository->destroy($attachment);
Session::flash('success', strval(trans('firefly.attachment_deleted', ['name' => $name])));
$request->session()->flash('success', strval(trans('firefly.attachment_deleted', ['name' => $name])));
Preferences::mark();
return redirect(session('attachments.delete.url'));
return redirect($this->getPreviousUri('attachments.delete.uri'));
}
/**
@@ -100,7 +102,9 @@ class AttachmentController extends Controller
$content = $repository->getContent($attachment);
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
return response($content, 200)
/** @var LaravelResponse $response */
$response = response($content, 200);
$response
->header('Content-Description', 'File Transfer')
->header('Content-Type', 'application/octet-stream')
->header('Content-Disposition', 'attachment; filename=' . $quoted)
@@ -110,25 +114,28 @@ class AttachmentController extends Controller
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', strlen($content));
return $response;
}
throw new FireflyException('Could not find the indicated attachment. The file is no longer there.');
}
/**
* @param Request $request
* @param Attachment $attachment
*
* @return View
*/
public function edit(Attachment $attachment)
public function edit(Request $request, Attachment $attachment)
{
$subTitleIcon = 'fa-pencil';
$subTitle = trans('firefly.edit_attachment', ['name' => $attachment->filename]);
// put previous url in session if not redirect from store (not "return_to_edit").
if (session('attachments.edit.fromUpdate') !== true) {
Session::put('attachments.edit.url', URL::previous());
$this->rememberPreviousUri('attachments.edit.uri');
}
Session::forget('attachments.edit.fromUpdate');
$request->session()->forget('attachments.edit.fromUpdate');
return view('attachments.edit', compact('attachment', 'subTitleIcon', 'subTitle'));
}
@@ -165,18 +172,19 @@ class AttachmentController extends Controller
$data = $request->getAttachmentData();
$repository->update($attachment, $data);
Session::flash('success', strval(trans('firefly.attachment_updated', ['name' => $attachment->filename])));
$request->session()->flash('success', strval(trans('firefly.attachment_updated', ['name' => $attachment->filename])));
Preferences::mark();
if (intval($request->get('return_to_edit')) === 1) {
// set value so edit routine will not overwrite URL:
Session::put('attachments.edit.fromUpdate', true);
// @codeCoverageIgnoreStart
$request->session()->put('attachments.edit.fromUpdate', true);
return redirect(route('attachments.edit', [$attachment->id]))->withInput(['return_to_edit' => 1]);
// @codeCoverageIgnoreEnd
}
// redirect to previous URL.
return redirect(session('attachments.edit.url'));
return redirect($this->getPreviousUri('attachments.edit.uri'));
}

View File

@@ -13,6 +13,7 @@ declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Auth;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
@@ -44,21 +45,18 @@ class ForgotPasswordController extends Controller
*
* @return \Illuminate\Http\RedirectResponse
*/
public function sendResetLinkEmail(Request $request)
public function sendResetLinkEmail(Request $request, UserRepositoryInterface $repository)
{
$this->validate($request, ['email' => 'required|email']);
// verify if the user is not a demo user. If so, we give him back an error.
$user = User::where('email', $request->get('email'))->first();
if (!is_null($user) && $user->hasRole('demo')) {
return back()->withErrors(
['email' => trans('firefly.cannot_reset_demo_user')]
);
if (!is_null($user) && $repository->hasRole($user, 'demo')) {
return back()->withErrors(['email' => trans('firefly.cannot_reset_demo_user')]);
}
$response = $this->broker()->sendResetLink(
$request->only('email')
);
$response = $this->broker()->sendResetLink($request->only('email'));
if ($response === Password::RESET_LINK_SENT) {
return back()->with('status', trans($response));
@@ -67,8 +65,6 @@ class ForgotPasswordController extends Controller
// If an error was returned by the password broker, we will get this message
// translated so we can notify a user of the problem. We'll redirect back
// to where the users came from so they can attempt this process again.
return back()->withErrors(
['email' => trans($response)]
);
return back()->withErrors(['email' => trans($response)]); // @codeCoverageIgnore
}
}

View File

@@ -16,11 +16,14 @@ use Config;
use FireflyConfig;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\User;
use Illuminate\Cookie\CookieJar;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Lang;
/**
* @codeCoverageIgnore
*
* Class LoginController
*
* @package FireflyIII\Http\Controllers\Auth
@@ -30,13 +33,6 @@ class LoginController extends Controller
use AuthenticatesUsers;
/**
* Where to redirect users after login / registration.
*
* @var string
*/
protected $redirectTo = '/';
/**
* Create a new controller instance.
*
@@ -80,6 +76,37 @@ class LoginController extends Controller
return $this->sendFailedLoginResponse($request, $errorMessage);
}
/**
* @param Request $request
* @param CookieJar $cookieJar
*
* @return $this
*/
public function logout(Request $request, CookieJar $cookieJar)
{
if (intval(getenv('SANDSTORM')) === 1) {
return view('error')->with('message', strval(trans('firefly.sandstorm_not_available')));
}
$cookie = $cookieJar->forever('twoFactorAuthenticated', 'false');
$this->guard()->logout();
$request->session()->flush();
$request->session()->regenerate();
return redirect('/')->withCookie($cookie);
}
/**
* @return string
*/
public function redirectTo(): string
{
return route('index');
}
/**
* Show the application login form.
*
@@ -87,8 +114,10 @@ class LoginController extends Controller
*
* @return \Illuminate\Http\Response
*/
public function showLoginForm(Request $request)
public function showLoginForm(Request $request, CookieJar $cookieJar)
{
// forget 2fa cookie:
$cookie = $cookieJar->forever('twoFactorAuthenticated', 'false');
// is allowed to?
$singleUserMode = FireflyConfig::get('single_user_mode', Config::get('firefly.configuration.single_user_mode'))->data;
$userCount = User::count();
@@ -100,7 +129,7 @@ class LoginController extends Controller
$email = $request->old('email');
$remember = $request->old('remember');
return view('auth.login', compact('allowRegistration', 'email', 'remember'));
return view('auth.login', compact('allowRegistration', 'email', 'remember'))->withCookie($cookie);
}
/**

View File

@@ -22,6 +22,8 @@ use Illuminate\Support\Facades\Password;
/**
* @codeCoverageIgnore
*
* Class PasswordController
*
* @package FireflyIII\Http\Controllers\Auth

View File

@@ -24,6 +24,8 @@ use Session;
use Validator;
/**
* @codeCoverageIgnore
*
* Class RegisterController
*
* @package FireflyIII\Http\Controllers\Auth
@@ -122,12 +124,15 @@ class RegisterController extends Controller
*/
protected function create(array $data)
{
return User::create(
/** @var User $user */
$user = User::create(
[
'email' => $data['email'],
'password' => bcrypt($data['password']),
]
);
return $user;
}
/**

View File

@@ -16,6 +16,8 @@ use FireflyIII\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
/**
* @codeCoverageIgnore
*
* Class ResetPasswordController
*
* @package FireflyIII\Http\Controllers\Auth

View File

@@ -13,13 +13,13 @@ declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Auth;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\TokenFormRequest;
use Illuminate\Cookie\CookieJar;
use Illuminate\Http\Request;
use Log;
use Preferences;
use Session;
/**
* Class TwoFactorController
@@ -30,19 +30,23 @@ class TwoFactorController extends Controller
{
/**
* @return mixed
* @param Request $request
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
* @throws FireflyException
*/
public function index()
public function index(Request $request)
{
$user = auth()->user();
// to make sure the validator in the next step gets the secret, we push it in session
$secret = Preferences::get('twoFactorAuthSecret', null)->data;
$secretPreference = Preferences::get('twoFactorAuthSecret', null);
$secret = is_null($secretPreference) ? null : $secretPreference->data;
$title = strval(trans('firefly.two_factor_title'));
// make sure the user has two factor configured:
$has2FA = Preferences::get('twoFactorAuthEnabled', null)->data;
$has2FA = Preferences::get('twoFactorAuthEnabled', false)->data;
if (is_null($has2FA) || $has2FA === false) {
return redirect(route('index'));
}
@@ -50,7 +54,7 @@ class TwoFactorController extends Controller
if (strlen(strval($secret)) === 0) {
throw new FireflyException('Your two factor authentication secret is empty, which it cannot be at this point. Please check the log files.');
}
Session::flash('two-factor-secret', $secret);
$request->session()->flash('two-factor-secret', $secret);
return view('auth.two-factor', compact('user', 'title'));
}
@@ -76,16 +80,18 @@ class TwoFactorController extends Controller
/**
* @param TokenFormRequest $request
* @SuppressWarnings(PHPMD.UnusedFormalParameter) // it's unused but the class does some validation.
* @param CookieJar $cookieJar
*
* @return mixed
* @SuppressWarnings(PHPMD.UnusedFormalParameter) // it's unused but the class does some validation.
*
*/
public function postIndex(TokenFormRequest $request)
public function postIndex(TokenFormRequest $request, CookieJar $cookieJar)
{
Session::put('twofactor-authenticated', true);
Session::put('twofactor-authenticated-date', new Carbon);
// set cookie!
$cookie = $cookieJar->forever('twoFactorAuthenticated', 'true');
return redirect(route('home'));
return redirect(route('home'))->withCookie($cookie);
}
}

View File

@@ -22,7 +22,6 @@ use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Preferences;
use Session;
use URL;
use View;
@@ -53,9 +52,11 @@ class BillController extends Controller
}
/**
* @param Request $request
*
* @return View
*/
public function create()
public function create(Request $request)
{
$periods = [];
foreach (config('firefly.bill_periods') as $current) {
@@ -66,61 +67,57 @@ class BillController extends Controller
// put previous url in session if not redirect from store (not "create another").
if (session('bills.create.fromStore') !== true) {
Session::put('bills.create.url', URL::previous());
$this->rememberPreviousUri('bills.create.uri');
}
Session::forget('bills.create.fromStore');
Session::flash('gaEventCategory', 'bills');
Session::flash('gaEventAction', 'create');
$request->session()->forget('bills.create.fromStore');
$request->session()->flash('gaEventCategory', 'bills');
$request->session()->flash('gaEventAction', 'create');
return view('bills.create', compact('periods', 'subTitle'));
}
/**
* @param Bill $bill
* @param Request $request
* @param Bill $bill
*
* @return View
*/
public function delete(Bill $bill)
public function delete(Request $request, Bill $bill)
{
// put previous url in session
Session::put('bills.delete.url', URL::previous());
Session::flash('gaEventCategory', 'bills');
Session::flash('gaEventAction', 'delete');
$this->rememberPreviousUri('bills.delete.uri');
$request->session()->flash('gaEventCategory', 'bills');
$request->session()->flash('gaEventAction', 'delete');
$subTitle = trans('firefly.delete_bill', ['name' => $bill->name]);
return view('bills.delete', compact('bill', 'subTitle'));
}
/**
* @param Request $request
* @param BillRepositoryInterface $repository
* @param Bill $bill
*
* @return \Illuminate\Http\RedirectResponse
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function destroy(BillRepositoryInterface $repository, Bill $bill)
public function destroy(Request $request, BillRepositoryInterface $repository, Bill $bill)
{
$name = $bill->name;
$billId = $bill->id;
$name = $bill->name;
$repository->destroy($bill);
Session::flash('success', strval(trans('firefly.deleted_bill', ['name' => $name])));
$request->session()->flash('success', strval(trans('firefly.deleted_bill', ['name' => $name])));
Preferences::mark();
$uri = session('bills.delete.url');
if (!(strpos($uri, sprintf('bills/show/%s', $billId)) === false)) {
// uri would point back to bill
$uri = route('bills.index');
}
return redirect($uri);
return redirect($this->getPreviousUri('bills.delete.uri'));
}
/**
* @param Bill $bill
* @param Request $request
* @param Bill $bill
*
* @return View
*/
public function edit(Bill $bill)
public function edit(Request $request, Bill $bill)
{
$periods = [];
foreach (config('firefly.bill_periods') as $current) {
@@ -130,11 +127,11 @@ class BillController extends Controller
// put previous url in session if not redirect from store (not "return_to_edit").
if (session('bills.edit.fromUpdate') !== true) {
Session::put('bills.edit.url', URL::previous());
$this->rememberPreviousUri('bills.edit.uri');
}
Session::forget('bills.edit.fromUpdate');
Session::flash('gaEventCategory', 'bills');
Session::flash('gaEventAction', 'edit');
$request->session()->forget('bills.edit.fromUpdate');
$request->session()->flash('gaEventCategory', 'bills');
$request->session()->flash('gaEventAction', 'edit');
return view('bills.edit', compact('subTitle', 'periods', 'bill'));
}
@@ -170,15 +167,16 @@ class BillController extends Controller
}
/**
* @param Request $request
* @param BillRepositoryInterface $repository
* @param Bill $bill
*
* @return \Illuminate\Http\RedirectResponse
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function rescan(BillRepositoryInterface $repository, Bill $bill)
public function rescan(Request $request, BillRepositoryInterface $repository, Bill $bill)
{
if (intval($bill->active) == 0) {
Session::flash('warning', strval(trans('firefly.cannot_scan_inactive_bill')));
$request->session()->flash('warning', strval(trans('firefly.cannot_scan_inactive_bill')));
return redirect(URL::previous());
}
@@ -190,7 +188,7 @@ class BillController extends Controller
}
Session::flash('success', strval(trans('firefly.rescanned_bill')));
$request->session()->flash('success', strval(trans('firefly.rescanned_bill')));
Preferences::mark();
return redirect(URL::previous());
@@ -215,7 +213,7 @@ class BillController extends Controller
// use collector:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setBills(new Collection([$bill]))->setLimit($pageSize)->setPage($page)->withBudgetInformation()
->withCategoryInformation();
$journals = $collector->getPaginatedJournals();
@@ -238,18 +236,19 @@ class BillController extends Controller
{
$billData = $request->getBillData();
$bill = $repository->store($billData);
Session::flash('success', strval(trans('firefly.stored_new_bill', ['name' => e($bill->name)])));
$request->session()->flash('success', strval(trans('firefly.stored_new_bill', ['name' => e($bill->name)])));
Preferences::mark();
if (intval($request->get('create_another')) === 1) {
// set value so create routine will not overwrite URL:
Session::put('bills.create.fromStore', true);
// @codeCoverageIgnoreStart
$request->session()->put('bills.create.fromStore', true);
return redirect(route('bills.create'))->withInput();
// @codeCoverageIgnoreEnd
}
// redirect to previous URL.
return redirect(session('bills.create.url'));
return redirect($this->getPreviousUri('bills.create.uri'));
}
@@ -265,18 +264,18 @@ class BillController extends Controller
$billData = $request->getBillData();
$bill = $repository->update($bill, $billData);
Session::flash('success', strval(trans('firefly.updated_bill', ['name' => e($bill->name)])));
$request->session()->flash('success', strval(trans('firefly.updated_bill', ['name' => e($bill->name)])));
Preferences::mark();
if (intval($request->get('return_to_edit')) === 1) {
// set value so edit routine will not overwrite URL:
Session::put('bills.edit.fromUpdate', true);
// @codeCoverageIgnoreStart
$request->session()->put('bills.edit.fromUpdate', true);
return redirect(route('bills.edit', [$bill->id]))->withInput(['return_to_edit' => 1]);
// @codeCoverageIgnoreEnd
}
// redirect to previous URL.
return redirect(session('bills.edit.url'));
return redirect($this->getPreviousUri('bills.edit.uri'));
}

View File

@@ -22,15 +22,17 @@ use FireflyIII\Http\Requests\BudgetIncomeRequest;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Log;
use Navigation;
use Preferences;
use Response;
use Session;
use URL;
use View;
/**
@@ -88,80 +90,76 @@ class BudgetController extends Controller
}
/**
* @param Request $request
*
* @return View
*/
public function create()
public function create(Request $request)
{
// put previous url in session if not redirect from store (not "create another").
if (session('budgets.create.fromStore') !== true) {
Session::put('budgets.create.url', URL::previous());
$this->rememberPreviousUri('budgets.create.uri');
}
Session::forget('budgets.create.fromStore');
Session::flash('gaEventCategory', 'budgets');
Session::flash('gaEventAction', 'create');
$request->session()->forget('budgets.create.fromStore');
$request->session()->flash('gaEventCategory', 'budgets');
$request->session()->flash('gaEventAction', 'create');
$subTitle = (string)trans('firefly.create_new_budget');
return view('budgets.create', compact('subTitle'));
}
/**
* @param Budget $budget
* @param Request $request
* @param Budget $budget
*
* @return View
*/
public function delete(Budget $budget)
public function delete(Request $request, Budget $budget)
{
$subTitle = trans('firefly.delete_budget', ['name' => $budget->name]);
// put previous url in session
Session::put('budgets.delete.url', URL::previous());
Session::flash('gaEventCategory', 'budgets');
Session::flash('gaEventAction', 'delete');
$this->rememberPreviousUri('budgets.delete.uri');
$request->session()->flash('gaEventCategory', 'budgets');
$request->session()->flash('gaEventAction', 'delete');
return view('budgets.delete', compact('budget', 'subTitle'));
}
/**
* @param Budget $budget
* @param Request $request
* @param Budget $budget
*
* @return \Illuminate\Http\RedirectResponse
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function destroy(Budget $budget)
public function destroy(Request $request, Budget $budget)
{
$name = $budget->name;
$budgetId = $budget->id;
$name = $budget->name;
$this->repository->destroy($budget);
Session::flash('success', strval(trans('firefly.deleted_budget', ['name' => e($name)])));
$request->session()->flash('success', strval(trans('firefly.deleted_budget', ['name' => e($name)])));
Preferences::mark();
$uri = session('budgets.delete.url');
if (!(strpos($uri, sprintf('budgets/show/%s', $budgetId)) === false)) {
// uri would point back to budget
$uri = route('budgets.index');
}
return redirect($uri);
return redirect($this->getPreviousUri('budgets.delete.uri'));
}
/**
* @param Budget $budget
* @param Request $request
* @param Budget $budget
*
* @return View
*/
public function edit(Budget $budget)
public function edit(Request $request, Budget $budget)
{
$subTitle = trans('firefly.edit_budget', ['name' => $budget->name]);
// put previous url in session if not redirect from store (not "return_to_edit").
if (session('budgets.edit.fromUpdate') !== true) {
Session::put('budgets.edit.url', URL::previous());
$this->rememberPreviousUri('budgets.edit.uri');
}
Session::forget('budgets.edit.fromUpdate');
Session::flash('gaEventCategory', 'budgets');
Session::flash('gaEventAction', 'edit');
$request->session()->forget('budgets.edit.fromUpdate');
$request->session()->flash('gaEventCategory', 'budgets');
$request->session()->flash('gaEventAction', 'edit');
return view('budgets.edit', compact('budget', 'subTitle'));
@@ -194,33 +192,86 @@ class BudgetController extends Controller
/**
* @param Request $request
* @param string $moment
*
* @return View
*/
public function noBudget(Request $request)
public function noBudget(Request $request, JournalRepositoryInterface $repository, string $moment = '')
{
/** @var Carbon $start */
$start = session('start', Carbon::now()->startOfMonth());
/** @var Carbon $end */
$end = session('end', Carbon::now()->endOfMonth());
// default values:
$range = Preferences::get('viewRange', '1M')->data;
$start = null;
$end = null;
$periods = new Collection;
// prep for "all" view.
if ($moment === 'all') {
$subTitle = trans('firefly.all_journals_without_budget');
$first = $repository->first();
$start = $first->date ?? new Carbon;
$end = new Carbon;
}
// prep for "specific date" view.
if (strlen($moment) > 0 && $moment !== 'all') {
$start = new Carbon($moment);
$end = Navigation::endOfPeriod($start, $range);
$subTitle = trans(
'firefly.without_budget_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
$periods = $this->getPeriodOverview();
}
// prep for current period
if (strlen($moment) === 0) {
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
$periods = $this->getPeriodOverview();
$subTitle = trans(
'firefly.without_budget_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
}
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$subTitle = trans(
'firefly.without_budget_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
// collector
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withoutBudget();
$journals = $collector->getPaginatedJournals();
$journals->setPath('/budgets/list/noBudget');
$count = 0;
$loop = 0;
// grab journals, but be prepared to jump a period back to get the right ones:
Log::info('Now at no-budget loop start.');
while ($count === 0 && $loop < 3) {
$loop++;
Log::info('Count is zero, search for journals.');
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setLimit($pageSize)->setPage($page)
->withoutBudget()->withOpposingAccount();
$journals = $collector->getPaginatedJournals();
$journals->setPath('/budgets/list/no-budget');
$count = $journals->getCollection()->count();
if ($count === 0) {
$start->subDay();
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfPeriod($start, $range);
Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d')));
}
}
return view('budgets.no-budget', compact('journals', 'subTitle'));
if ($moment != 'all' && $loop > 1) {
$subTitle = trans(
'firefly.without_budget_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
}
return view('budgets.no-budget', compact('journals', 'subTitle', 'moment', 'periods', 'start', 'end'));
}
/**
* @param BudgetIncomeRequest $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postUpdateIncome(BudgetIncomeRequest $request)
@@ -253,7 +304,7 @@ class BudgetController extends Controller
$repetition = null;
// collector:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setBudget($budget)->setLimit($pageSize)->setPage($page)->withCategoryInformation();
$journals = $collector->getPaginatedJournals();
$journals->setPath('/budgets/show/' . $budget->id);
@@ -278,22 +329,19 @@ class BudgetController extends Controller
throw new FireflyException('This budget limit is not part of this budget.');
}
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$subTitle = trans(
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$subTitle = trans(
'firefly.budget_in_period', [
'name' => $budget->name,
'start' => $budgetLimit->start_date->formatLocalized($this->monthAndDayFormat),
'end' => $budgetLimit->end_date->formatLocalized($this->monthAndDayFormat),
]
);
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH]);
// collector:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($budgetLimit->start_date, $budgetLimit->end_date)
->setBudget($budget)->setLimit($pageSize)->setPage($page)->withCategoryInformation();
$journals = $collector->getPaginatedJournals();
@@ -318,19 +366,18 @@ class BudgetController extends Controller
$data = $request->getBudgetData();
$budget = $this->repository->store($data);
Session::flash('success', strval(trans('firefly.stored_new_budget', ['name' => e($budget->name)])));
$request->session()->flash('success', strval(trans('firefly.stored_new_budget', ['name' => e($budget->name)])));
Preferences::mark();
if (intval($request->get('create_another')) === 1) {
// set value so create routine will not overwrite URL:
Session::put('budgets.create.fromStore', true);
// @codeCoverageIgnoreStart
$request->session()->put('budgets.create.fromStore', true);
return redirect(route('budgets.create'))->withInput();
// @codeCoverageIgnoreEnd
}
// redirect to previous URL.
return redirect(session('budgets.create.url'));
return redirect($this->getPreviousUri('budgets.create.uri'));
}
/**
@@ -344,19 +391,18 @@ class BudgetController extends Controller
$data = $request->getBudgetData();
$this->repository->update($budget, $data);
Session::flash('success', strval(trans('firefly.updated_budget', ['name' => e($budget->name)])));
$request->session()->flash('success', strval(trans('firefly.updated_budget', ['name' => e($budget->name)])));
Preferences::mark();
if (intval($request->get('return_to_edit')) === 1) {
// set value so edit routine will not overwrite URL:
Session::put('budgets.edit.fromUpdate', true);
// @codeCoverageIgnoreStart
$request->session()->put('budgets.edit.fromUpdate', true);
return redirect(route('budgets.edit', [$budget->id]))->withInput(['return_to_edit' => 1]);
// @codeCoverageIgnoreEnd
}
// redirect to previous URL.
return redirect(session('budgets.edit.url'));
return redirect($this->getPreviousUri('budgets.edit.uri'));
}
/**
@@ -416,7 +462,6 @@ class BudgetController extends Controller
return $return;
}
/**
* @param Budget $budget
* @param Carbon $start
@@ -434,7 +479,7 @@ class BudgetController extends Controller
$cache->addProperty('get-limits');
if ($cache->has()) {
return $cache->get();
return $cache->get(); // @codeCoverageIgnore
}
/** @var AccountRepositoryInterface $accountRepository */
@@ -453,4 +498,57 @@ class BudgetController extends Controller
return $set;
}
/**
* @return Collection
*/
private function getPeriodOverview(): Collection
{
$repository = app(JournalRepositoryInterface::class);
$first = $repository->first();
$start = $first->date ?? new Carbon;
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfX(new Carbon, $range);
$entries = new Collection;
// properties for cache
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('no-budget-period-entries');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
Log::debug('Going to get period expenses and incomes.');
while ($end >= $start) {
$end = Navigation::startOfPeriod($end, $range);
$currentEnd = Navigation::endOfPeriod($end, $range);
// count journals without budget in this period:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutBudget()->withOpposingAccount()->setTypes([TransactionType::WITHDRAWAL]);
$set = $collector->getJournals();
$sum = $set->sum('transaction_amount');
$journals = $set->count();
$dateStr = $end->format('Y-m-d');
$dateName = Navigation::periodShow($end, $range);
$entries->push(
[
'string' => $dateStr,
'name' => $dateName,
'count' => $journals,
'sum' => $sum,
'date' => clone $end,
]
);
$end = Navigation::subtractPeriod($end, $range, 1);
}
$cache->store($entries);
return $entries;
}
}

View File

@@ -9,7 +9,7 @@
* See the LICENSE file for details.
*/
declare(strict_types = 1);
declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
@@ -18,15 +18,17 @@ use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Http\Requests\CategoryFormRequest;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Log;
use Navigation;
use Preferences;
use Session;
use URL;
use Steam;
use View;
/**
@@ -56,80 +58,78 @@ class CategoryController extends Controller
}
/**
* @param Request $request
*
* @return View
*/
public function create()
public function create(Request $request)
{
if (session('categories.create.fromStore') !== true) {
Session::put('categories.create.url', URL::previous());
$this->rememberPreviousUri('categories.create.uri');
}
Session::forget('categories.create.fromStore');
Session::flash('gaEventCategory', 'categories');
Session::flash('gaEventAction', 'create');
$request->session()->forget('categories.create.fromStore');
$request->session()->flash('gaEventCategory', 'categories');
$request->session()->flash('gaEventAction', 'create');
$subTitle = trans('firefly.create_new_category');
return view('categories.create', compact('subTitle'));
}
/**
* @param Request $request
* @param Category $category
*
* @return View
*/
public function delete(Category $category)
public function delete(Request $request, Category $category)
{
$subTitle = trans('firefly.delete_category', ['name' => $category->name]);
// put previous url in session
Session::put('categories.delete.url', URL::previous());
Session::flash('gaEventCategory', 'categories');
Session::flash('gaEventAction', 'delete');
$this->rememberPreviousUri('categories.delete.uri');
$request->session()->flash('gaEventCategory', 'categories');
$request->session()->flash('gaEventAction', 'delete');
return view('categories.delete', compact('category', 'subTitle'));
}
/**
* @param Request $request
* @param CategoryRepositoryInterface $repository
* @param Category $category
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function destroy(CategoryRepositoryInterface $repository, Category $category)
public function destroy(Request $request, CategoryRepositoryInterface $repository, Category $category)
{
$name = $category->name;
$categoryId = $category->id;
$name = $category->name;
$repository->destroy($category);
Session::flash('success', strval(trans('firefly.deleted_category', ['name' => e($name)])));
$request->session()->flash('success', strval(trans('firefly.deleted_category', ['name' => e($name)])));
Preferences::mark();
$uri = session('categories.delete.url');
if (!(strpos($uri, sprintf('categories/show/%s', $categoryId)) === false)) {
// uri would point back to category
$uri = route('categories.index');
}
return redirect($uri);
return redirect($this->getPreviousUri('categories.delete.uri'));
}
/**
* @param Request $request
* @param Category $category
*
* @return View
*/
public function edit(Category $category)
public function edit(Request $request, Category $category)
{
$subTitle = trans('firefly.edit_category', ['name' => $category->name]);
// put previous url in session if not redirect from store (not "return_to_edit").
if (session('categories.edit.fromUpdate') !== true) {
Session::put('categories.edit.url', URL::previous());
$this->rememberPreviousUri('categories.edit.uri');
}
Session::forget('categories.edit.fromUpdate');
Session::flash('gaEventCategory', 'categories');
Session::flash('gaEventAction', 'edit');
$request->session()->forget('categories.edit.fromUpdate');
$request->session()->flash('gaEventCategory', 'categories');
$request->session()->flash('gaEventAction', 'edit');
return view('categories.edit', compact('category', 'subTitle'));
@@ -156,116 +156,164 @@ class CategoryController extends Controller
/**
* @return View
*/
public function noCategory()
public function noCategory(Request $request, JournalRepositoryInterface $repository, string $moment = '')
{
/** @var Carbon $start */
$start = session('start', Carbon::now()->startOfMonth());
/** @var Carbon $end */
$end = session('end', Carbon::now()->startOfMonth());
// default values:
$range = Preferences::get('viewRange', '1M')->data;
$start = null;
$end = null;
$periods = new Collection;
// new collector:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class, [auth()->user()]);
$collector->setAllAssetAccounts()->setRange($start, $end)->withoutCategory();//->groupJournals();
$journals = $collector->getJournals();
$subTitle = trans(
'firefly.without_category_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
// prep for "all" view.
if ($moment === 'all') {
$subTitle = trans('firefly.all_journals_without_category');
$first = $repository->first();
$start = $first->date ?? new Carbon;
$end = new Carbon;
}
return view('categories.no-category', compact('journals', 'subTitle'));
}
// prep for "specific date" view.
if (strlen($moment) > 0 && $moment !== 'all') {
$start = new Carbon($moment);
$end = Navigation::endOfPeriod($start, $range);
$subTitle = trans(
'firefly.without_category_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
$periods = $this->getNoCategoryPeriodOverview();
}
/**
* @param Request $request
* @param JournalCollectorInterface $collector
* @param Category $category
*
* @return View
*/
public function show(Request $request, JournalCollectorInterface $collector, Category $category)
{
$range = Preferences::get('viewRange', '1M')->data;
$start = session('start', Navigation::startOfPeriod(new Carbon, $range));
$end = session('end', Navigation::endOfPeriod(new Carbon, $range));
$hideCategory = true; // used in list.
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$subTitle = $category->name;
$subTitleIcon = 'fa-bar-chart';
$entries = $this->getGroupedEntries($category);
$method = 'default';
// prep for current period
if (strlen($moment) === 0) {
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
$periods = $this->getNoCategoryPeriodOverview();
$subTitle = trans(
'firefly.without_category_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
}
// get journals
$collector->setLimit($pageSize)->setPage($page)->setAllAssetAccounts()->setRange($start, $end)->setCategory($category)->withBudgetInformation();
$journals = $collector->getPaginatedJournals();
$journals->setPath('categories/show/' . $category->id);
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$count = 0;
$loop = 0;
// grab journals, but be prepared to jump a period back to get the right ones:
Log::info('Now at no-cat loop start.');
while ($count === 0 && $loop < 3) {
$loop++;
Log::info('Count is zero, search for journals.');
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withoutCategory()->withOpposingAccount();
$collector->disableInternalFilter();
$journals = $collector->getPaginatedJournals();
$journals->setPath('/categories/list/no-category');
$count = $journals->getCollection()->count();
if ($count === 0) {
$start->subDay();
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfPeriod($start, $range);
Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d')));
}
}
return view('categories.show', compact('category', 'method', 'journals', 'entries', 'hideCategory', 'subTitle', 'subTitleIcon', 'start', 'end'));
if ($moment != 'all' && $loop > 1) {
$subTitle = trans(
'firefly.without_category_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
}
return view('categories.no-category', compact('journals', 'subTitle', 'moment', 'periods', 'start', 'end'));
}
/**
* @param Request $request
* @param CategoryRepositoryInterface $repository
* @param Category $category
* @param string $moment
*
* @return View
*/
public function showAll(Request $request, CategoryRepositoryInterface $repository, Category $category)
public function show(Request $request, CategoryRepositoryInterface $repository, Category $category, string $moment = '')
{
$range = Preferences::get('viewRange', '1M')->data;
$start = $repository->firstUseDate($category);
if ($start->year == 1900) {
$start = new Carbon;
}
$end = Navigation::endOfPeriod(new Carbon, $range);
// default values:
$subTitle = $category->name;
$subTitleIcon = 'fa-bar-chart';
$hideCategory = true; // used in list.
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
$page = intval($request->get('page')) == 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$method = 'all';
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setLimit($pageSize)->setPage($page)->setAllAssetAccounts()->setCategory($category)->withBudgetInformation();
$journals = $collector->getPaginatedJournals();
$journals->setPath('categories/show/' . $category->id . '/all');
return view('categories.show', compact('category', 'method', 'journals', 'hideCategory', 'subTitle', 'subTitleIcon', 'start', 'end'));
}
/**
* @param Request $request
* @param Category $category
* @param string $date
*
* @return View
*/
public function showByDate(Request $request, Category $category, string $date)
{
$carbon = new Carbon($date);
$count = 0;
$loop = 0;
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($carbon, $range);
$end = Navigation::endOfPeriod($carbon, $range);
$subTitle = $category->name;
$subTitleIcon = 'fa-bar-chart';
$hideCategory = true; // used in list.
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
$entries = $this->getGroupedEntries($category);
$method = 'date';
$start = null;
$end = null;
$periods = new Collection;
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setLimit($pageSize)->setPage($page)->setAllAssetAccounts()->setRange($start, $end)->setCategory($category)->withBudgetInformation();
$journals = $collector->getPaginatedJournals();
$journals->setPath('categories/show/' . $category->id . '/' . $date);
return view('categories.show', compact('category', 'method', 'entries', 'journals', 'hideCategory', 'subTitle', 'subTitleIcon', 'start', 'end'));
// prep for "all" view.
if ($moment === 'all') {
$subTitle = trans('firefly.all_journals_for_category', ['name' => $category->name]);
$start = $repository->firstUseDate($category);
$end = new Carbon;
}
// prep for "specific date" view.
if (strlen($moment) > 0 && $moment !== 'all') {
$start = new Carbon($moment);
$end = Navigation::endOfPeriod($start, $range);
$subTitle = trans(
'firefly.journals_in_period_for_category',
['name' => $category->name,
'start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
$periods = $this->getPeriodOverview($category);
}
// prep for current period
if (strlen($moment) === 0) {
$start = clone session('start', Navigation::startOfPeriod(new Carbon, $range));
$end = clone session('end', Navigation::endOfPeriod(new Carbon, $range));
$periods = $this->getPeriodOverview($category);
$subTitle = trans(
'firefly.journals_in_period_for_category',
['name' => $category->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
}
// grab journals, but be prepared to jump a period back to get the right ones:
Log::info('Now at category loop start.');
while ($count === 0 && $loop < 3) {
$loop++;
Log::info('Count is zero, search for journals.');
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
->setCategory($category)->withBudgetInformation()->withCategoryInformation()->disableInternalFilter();
$journals = $collector->getPaginatedJournals();
$journals->setPath('categories/show/' . $category->id);
$count = $journals->getCollection()->count();
if ($count === 0) {
$start->subDay();
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfPeriod($start, $range);
Log::info(sprintf('Count is still zero, go back in time to "%s" and "%s"!', $start->format('Y-m-d'), $end->format('Y-m-d')));
}
}
if ($moment != 'all' && $loop > 1) {
$subTitle = trans(
'firefly.journals_in_period_for_category',
['name' => $category->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
'end' => $end->formatLocalized($this->monthAndDayFormat)]
);
}
return view('categories.show', compact('category', 'moment', 'journals', 'periods', 'subTitle', 'subTitleIcon', 'start', 'end'));
}
/**
* @param CategoryFormRequest $request
* @param CategoryRepositoryInterface $repository
@@ -277,13 +325,15 @@ class CategoryController extends Controller
$data = $request->getCategoryData();
$category = $repository->store($data);
Session::flash('success', strval(trans('firefly.stored_category', ['name' => e($category->name)])));
$request->session()->flash('success', strval(trans('firefly.stored_category', ['name' => e($category->name)])));
Preferences::mark();
if (intval($request->get('create_another')) === 1) {
Session::put('categories.create.fromStore', true);
// @codeCoverageIgnoreStart
$request->session()->put('categories.create.fromStore', true);
return redirect(route('categories.create'))->withInput();
// @codeCoverageIgnoreEnd
}
return redirect(route('categories.index'));
@@ -302,18 +352,93 @@ class CategoryController extends Controller
$data = $request->getCategoryData();
$repository->update($category, $data);
Session::flash('success', strval(trans('firefly.updated_category', ['name' => e($category->name)])));
$request->session()->flash('success', strval(trans('firefly.updated_category', ['name' => e($category->name)])));
Preferences::mark();
if (intval($request->get('return_to_edit')) === 1) {
Session::put('categories.edit.fromUpdate', true);
// @codeCoverageIgnoreStart
$request->session()->put('categories.edit.fromUpdate', true);
return redirect(route('categories.edit', [$category->id]));
// @codeCoverageIgnoreEnd
}
// redirect to previous URL.
return redirect(session('categories.edit.url'));
return redirect($this->getPreviousUri('categories.edit.uri'));
}
/**
* @return Collection
*/
private function getNoCategoryPeriodOverview(): Collection
{
$repository = app(JournalRepositoryInterface::class);
$first = $repository->first();
$start = $first->date ?? new Carbon;
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfX(new Carbon, $range);
$entries = new Collection;
// properties for cache
$cache = new CacheProperties;
$cache->addProperty($start);
$cache->addProperty($end);
$cache->addProperty('no-budget-period-entries');
if ($cache->has()) {
return $cache->get(); // @codeCoverageIgnore
}
Log::debug(sprintf('Going to get period expenses and incomes between %s and %s.', $start->format('Y-m-d'), $end->format('Y-m-d')));
while ($end >= $start) {
Log::debug('Loop!');
$end = Navigation::startOfPeriod($end, $range);
$currentEnd = Navigation::endOfPeriod($end, $range);
// count journals without budget in this period:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()->withOpposingAccount();
$count = $collector->getJournals()->count();
// amount transferred
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()
->withOpposingAccount()->setTypes([TransactionType::TRANSFER])->disableInternalFilter();
$transferred = Steam::positive($collector->getJournals()->sum('transaction_amount'));
// amount spent
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()->withOpposingAccount()->setTypes([TransactionType::WITHDRAWAL]);
$spent = $collector->getJournals()->sum('transaction_amount');
// amount earned
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()->withOpposingAccount()->setTypes([TransactionType::DEPOSIT]);
$earned = $collector->getJournals()->sum('transaction_amount');
$dateStr = $end->format('Y-m-d');
$dateName = Navigation::periodShow($end, $range);
$entries->push(
[
'string' => $dateStr,
'name' => $dateName,
'count' => $count,
'spent' => $spent,
'earned' => $earned,
'transferred' => $transferred,
'date' => clone $end,
]
);
$end = Navigation::subtractPeriod($end, $range, 1);
}
Log::debug('End of loops');
$cache->store($entries);
return $entries;
}
/**
@@ -321,7 +446,7 @@ class CategoryController extends Controller
*
* @return Collection
*/
private function getGroupedEntries(Category $category): Collection
private function getPeriodOverview(Category $category): Collection
{
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
@@ -345,7 +470,7 @@ class CategoryController extends Controller
$cache->addProperty($category->id);
if ($cache->has()) {
return $cache->get();
return $cache->get(); // @codeCoverageIgnore
}
while ($end >= $first) {
$end = Navigation::startOfPeriod($end, $range);
@@ -354,7 +479,25 @@ class CategoryController extends Controller
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $end, $currentEnd);
$dateStr = $end->format('Y-m-d');
$dateName = Navigation::periodShow($end, $range);
$entries->push([$dateStr, $dateName, $spent, $earned, clone $end]);
// amount transferred
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->setCategory($category)
->withOpposingAccount()->setTypes([TransactionType::TRANSFER])->disableInternalFilter();
$transferred = Steam::positive($collector->getJournals()->sum('transaction_amount'));
$entries->push(
[
'string' => $dateStr,
'name' => $dateName,
'spent' => $spent,
'earned' => $earned,
'sum' => bcadd($earned, $spent),
'transferred' => $transferred,
'date' => clone $end,
]
);
$end = Navigation::subtractPeriod($end, $range, 1);
}
$cache->store($entries);

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