Compare commits

...

548 Commits

Author SHA1 Message Date
James Cole
2ddcf1120f Merge branch 'hotfix/4.6.3.1' 2017-07-23 20:02:45 +02:00
James Cole
d45c74915c This fixes #715 2017-07-23 20:02:32 +02:00
James Cole
57d6677131 Merge branch 'release/4.6.3' 2017-07-23 10:01:48 +02:00
James Cole
05e73344eb Various files for upgrade. 2017-07-23 09:54:07 +02:00
James Cole
fff8f96490 Merge pull request #706 from firefly-iii/l10n_develop
New Crowdin translations
2017-07-23 09:53:40 +02:00
James Cole
1ccfb34246 New translations firefly.php (Slovenian) 2017-07-23 09:50:53 +02:00
James Cole
b30bd00993 New translations firefly.php (Spanish) 2017-07-23 09:50:51 +02:00
James Cole
6b2d9fe816 New translations firefly.php (Portuguese, Brazilian) 2017-07-23 09:50:47 +02:00
James Cole
531114279d New translations firefly.php (Polish) 2017-07-23 09:50:45 +02:00
James Cole
944aaff0fa New translations firefly.php (Chinese Traditional) 2017-07-23 09:50:42 +02:00
James Cole
6bafa6819d New translations firefly.php (Dutch) 2017-07-23 09:50:40 +02:00
James Cole
8d7091285a New translations firefly.php (German) 2017-07-23 09:50:38 +02:00
James Cole
579e95219a New translations firefly.php (French) 2017-07-23 09:50:35 +02:00
James Cole
4a746881e3 New translations firefly.php (Russian) 2017-07-23 09:50:20 +02:00
James Cole
9122f1b642 New translations firefly.php (Dutch) 2017-07-23 09:40:08 +02:00
James Cole
8b033ed4a8 Update contributing and support guidelines [skip ci] 2017-07-23 09:37:51 +02:00
James Cole
8e53a63243 Broken translation. [skip ci] 2017-07-23 09:36:50 +02:00
James Cole
4de01e7387 New translations firefly.php (Dutch) 2017-07-23 09:30:10 +02:00
James Cole
f85ab74e2b Code cleanup and tests. 2017-07-23 08:32:51 +02:00
James Cole
8bb7d5de3f Various code clean up. 2017-07-23 08:16:11 +02:00
James Cole
68424e485c New translations firefly.php (Slovenian) 2017-07-23 07:41:00 +02:00
James Cole
ac34285eed New translations firefly.php (Spanish) 2017-07-23 07:40:58 +02:00
James Cole
e605a82573 New translations firefly.php (Portuguese, Brazilian) 2017-07-23 07:40:55 +02:00
James Cole
1061764426 New translations firefly.php (Polish) 2017-07-23 07:40:52 +02:00
James Cole
8d93e410f7 New translations firefly.php (Chinese Traditional) 2017-07-23 07:40:49 +02:00
James Cole
9336cdcc5d New translations firefly.php (Dutch) 2017-07-23 07:40:47 +02:00
James Cole
7639c03646 New translations firefly.php (German) 2017-07-23 07:40:45 +02:00
James Cole
2da55bff9c New translations firefly.php (French) 2017-07-23 07:40:43 +02:00
James Cole
6ea5d45dec New translations firefly.php (Russian) 2017-07-23 07:40:29 +02:00
James Cole
e9504a3899 New translations intro.php (Polish) 2017-07-23 07:40:25 +02:00
James Cole
7bff2fd1e5 New translations intro.php (Portuguese, Brazilian) 2017-07-23 07:40:23 +02:00
James Cole
694712e933 New translations intro.php (Russian) 2017-07-23 07:40:22 +02:00
James Cole
aa675559e6 New translations intro.php (Spanish) 2017-07-23 07:40:22 +02:00
James Cole
2af19d675a New translations intro.php (Slovenian) 2017-07-23 07:40:21 +02:00
James Cole
4588d16fc2 New translations intro.php (German) 2017-07-23 07:40:20 +02:00
James Cole
5dbd3031be New translations intro.php (French) 2017-07-23 07:40:19 +02:00
James Cole
59c16eba77 New translations intro.php (Dutch) 2017-07-23 07:40:17 +02:00
James Cole
8c21ec96d1 New translations intro.php (Chinese Traditional) 2017-07-23 07:40:16 +02:00
James Cole
2c00a8353d Fix small issue reenabling intro [skip ci] 2017-07-23 07:35:30 +02:00
James Cole
19e7a76f85 Forgot small statement [skip ci] 2017-07-23 07:32:06 +02:00
James Cole
f16a186faf Option to re-enable intro boxes. 2017-07-23 07:30:05 +02:00
James Cole
456dd39ec4 New intro texts. 2017-07-22 22:56:21 +02:00
James Cole
5b69a697e4 Improve pages to show intro texts. 2017-07-22 10:50:30 +02:00
James Cole
20d279fee4 New translations firefly.php (Slovenian) 2017-07-21 06:20:54 +02:00
James Cole
cd55d819af New translations firefly.php (Spanish) 2017-07-21 06:20:52 +02:00
James Cole
dce51da92f New translations firefly.php (Portuguese, Brazilian) 2017-07-21 06:20:48 +02:00
James Cole
6118cf6041 New translations firefly.php (Polish) 2017-07-21 06:20:45 +02:00
James Cole
4ae8bffd4d New translations firefly.php (Chinese Traditional) 2017-07-21 06:20:42 +02:00
James Cole
5ebe86d5b6 New translations firefly.php (Dutch) 2017-07-21 06:20:40 +02:00
James Cole
317d97a310 New translations firefly.php (German) 2017-07-21 06:20:38 +02:00
James Cole
082aa1d8e3 New translations firefly.php (French) 2017-07-21 06:20:36 +02:00
James Cole
2f2963676f New translations firefly.php (Russian) 2017-07-21 06:20:19 +02:00
James Cole
f2d388f742 Improve code for intro texts. 2017-07-21 06:00:10 +02:00
James Cole
d79008495a Remove some html comments. 2017-07-21 04:36:23 +02:00
James Cole
43f1867fb8 Language strings for #708 2017-07-21 04:36:09 +02:00
James Cole
043c28628c Fixes #708 2017-07-21 04:35:57 +02:00
James Cole
9540854c8a Language is not complete yet. [skip ci] 2017-07-21 04:26:13 +02:00
James Cole
b951a6ca66 Merge pull request #712 from simonsmiley/update-charts
Make charts easier to read
2017-07-19 16:11:58 +02:00
Simon Hanna
26561a395d Make charts easier to read
* Do not fill the area below the lines
* Provide border color
* Decrease transparency of border
2017-07-19 15:53:22 +02:00
James Cole
0a884c8718 New translations intro.php (Polish) 2017-07-16 18:40:23 +02:00
James Cole
b393e3c662 New translations intro.php (Portuguese, Brazilian) 2017-07-16 18:40:22 +02:00
James Cole
c36062210f New translations intro.php (Russian) 2017-07-16 18:40:21 +02:00
James Cole
861381fbb6 New translations intro.php (Spanish) 2017-07-16 18:40:20 +02:00
James Cole
b9019f9590 New translations intro.php (Slovenian) 2017-07-16 18:40:19 +02:00
James Cole
fcfa877e89 New translations intro.php (German) 2017-07-16 18:40:18 +02:00
James Cole
d61849eefe New translations intro.php (French) 2017-07-16 18:40:17 +02:00
James Cole
bc83bd6ec8 New translations intro.php (Dutch) 2017-07-16 18:40:15 +02:00
James Cole
c18c94e565 New translations intro.php (Chinese Traditional) 2017-07-16 18:40:15 +02:00
James Cole
77d077ec08 Fix help button. 2017-07-16 18:28:46 +02:00
James Cole
021d0e6359 More stuff for intro texts. 2017-07-16 18:14:29 +02:00
James Cole
7f4fd2c52f Fix tests. 2017-07-16 17:05:52 +02:00
James Cole
8ffe098e3b New translations firefly.php (Slovenian) 2017-07-16 13:20:56 +02:00
James Cole
a2ca86ca74 New translations firefly.php (Spanish) 2017-07-16 13:20:54 +02:00
James Cole
deef018806 New translations firefly.php (Portuguese, Brazilian) 2017-07-16 13:20:50 +02:00
James Cole
c3f8b2ea56 New translations firefly.php (Polish) 2017-07-16 13:20:47 +02:00
James Cole
e3696b6055 New translations firefly.php (Chinese Traditional) 2017-07-16 13:20:45 +02:00
James Cole
b82b340668 New translations firefly.php (Dutch) 2017-07-16 13:20:42 +02:00
James Cole
a8b01c439b New translations firefly.php (German) 2017-07-16 13:20:39 +02:00
James Cole
6ec686ca7e New translations firefly.php (French) 2017-07-16 13:20:37 +02:00
James Cole
fdb664fecb New translations firefly.php (Russian) 2017-07-16 13:20:21 +02:00
James Cole
09f838089b Allow rule to be applied to transactions (not just group). 2017-07-16 13:04:45 +02:00
James Cole
db0fe918b8 New translations firefly.php (Dutch) 2017-07-16 08:00:07 +02:00
James Cole
8ca696d547 New translations firefly.php (Dutch) 2017-07-16 07:50:41 +02:00
James Cole
b7ccb1ce5c New translations breadcrumbs.php (Dutch) 2017-07-16 07:50:33 +02:00
James Cole
5f0033e466 New translations intro.php (Polish) 2017-07-16 07:50:22 +02:00
James Cole
477adba3e1 New translations intro.php (Portuguese, Brazilian) 2017-07-16 07:50:21 +02:00
James Cole
eb15ca8ebd New translations intro.php (Russian) 2017-07-16 07:50:20 +02:00
James Cole
dbf5907c20 New translations intro.php (Spanish) 2017-07-16 07:50:19 +02:00
James Cole
e95deb9443 New translations intro.php (Slovenian) 2017-07-16 07:50:19 +02:00
James Cole
e19c36b5c4 New translations intro.php (German) 2017-07-16 07:50:18 +02:00
James Cole
fdd589db4f New translations intro.php (French) 2017-07-16 07:50:17 +02:00
James Cole
cd4e45d8f5 New translations intro.php (Dutch) 2017-07-16 07:50:16 +02:00
James Cole
e6e31b9cab New translations intro.php (Chinese Traditional) 2017-07-16 07:50:15 +02:00
James Cole
b676b1fef9 Simplify import storage routine. 2017-07-16 07:45:20 +02:00
James Cole
58bfb35fa6 Built a new routine for intro tours. 2017-07-16 07:35:08 +02:00
James Cole
09131e8c36 Add Russian language. 2017-07-15 22:42:14 +02:00
James Cole
1d6ca91c01 This fixes the tests. 2017-07-15 22:41:57 +02:00
James Cole
fa00ba2edd Expand tests and fix various small issues in strict comparison. 2017-07-15 22:17:24 +02:00
James Cole
65114c8483 New translations firefly.php (German) 2017-07-15 22:00:52 +02:00
James Cole
d033985141 New translations firefly.php (Polish) 2017-07-15 22:00:49 +02:00
James Cole
5badfbee93 New translations firefly.php (Portuguese, Brazilian) 2017-07-15 22:00:47 +02:00
James Cole
44a61842f0 New translations firefly.php (Slovenian) 2017-07-15 22:00:45 +02:00
James Cole
70b61af572 New translations firefly.php (French) 2017-07-15 22:00:42 +02:00
James Cole
53a53d393d New translations firefly.php (Chinese Traditional) 2017-07-15 22:00:38 +02:00
James Cole
6c95b5757b New translations firefly.php (Spanish) 2017-07-15 22:00:35 +02:00
James Cole
693b3e5a6f New translations firefly.php (Russian) 2017-07-15 22:00:18 +02:00
James Cole
aac1338bdd Merge pull request #705 from firefly-iii/l10n_develop
New Crowdin translations
2017-07-15 21:58:20 +02:00
James Cole
2979137102 New translations firefly.php (Dutch) 2017-07-15 21:50:12 +02:00
James Cole
0068675f3b Remove alert [skip ci] 2017-07-15 21:48:02 +02:00
James Cole
6c1a22ea7f Merge pull request #702 from firefly-iii/l10n_develop
New Crowdin translations
2017-07-15 21:42:33 +02:00
James Cole
2869b92e6b Merge branch 'develop' into l10n_develop 2017-07-15 21:42:27 +02:00
James Cole
8a38ce1964 Remove references to old tour but include code for new tour. 2017-07-15 21:40:42 +02:00
James Cole
3a7c5566ed New translations firefly.php (German) 2017-07-15 17:30:52 +02:00
James Cole
1bed8c2b08 New translations firefly.php (Polish) 2017-07-15 17:30:49 +02:00
James Cole
e24500b306 New translations firefly.php (Portuguese, Brazilian) 2017-07-15 17:30:47 +02:00
James Cole
6251914419 New translations firefly.php (Slovenian) 2017-07-15 17:30:45 +02:00
James Cole
8d9e943d57 New translations firefly.php (French) 2017-07-15 17:30:43 +02:00
James Cole
f71bc5d323 New translations firefly.php (Dutch) 2017-07-15 17:30:40 +02:00
James Cole
a8082b2b3f New translations firefly.php (Chinese Traditional) 2017-07-15 17:30:37 +02:00
James Cole
510b72303d New translations firefly.php (Spanish) 2017-07-15 17:30:35 +02:00
James Cole
4666d4bbaa New translations breadcrumbs.php (Chinese Traditional) 2017-07-15 17:30:28 +02:00
James Cole
025f1e9502 New translations breadcrumbs.php (Dutch) 2017-07-15 17:30:27 +02:00
James Cole
b4c05098a9 New translations breadcrumbs.php (French) 2017-07-15 17:30:27 +02:00
James Cole
3c8ee6f7f7 New translations breadcrumbs.php (German) 2017-07-15 17:30:26 +02:00
James Cole
8b34135b08 New translations breadcrumbs.php (Polish) 2017-07-15 17:30:24 +02:00
James Cole
d4b7c6689f New translations breadcrumbs.php (Portuguese, Brazilian) 2017-07-15 17:30:23 +02:00
James Cole
d72aadfb00 New translations breadcrumbs.php (Slovenian) 2017-07-15 17:30:21 +02:00
James Cole
00ff8ae166 New translations breadcrumbs.php (Spanish) 2017-07-15 17:30:20 +02:00
James Cole
cffcf49b26 New translations breadcrumbs.php (Russian) 2017-07-15 17:30:14 +02:00
James Cole
ad55aa8b85 New translations firefly.php (Russian) 2017-07-15 17:30:13 +02:00
James Cole
accbdea942 Improve search and display of results. 2017-07-15 17:19:12 +02:00
James Cole
22144b78ea Strict comparisons. 2017-07-15 16:41:07 +02:00
James Cole
c03ab269f0 Memory optimised, connect journal to tag. 2017-07-15 10:43:22 +02:00
James Cole
0c6c4d5959 Fix small issue in chart. 2017-07-15 10:26:27 +02:00
James Cole
e4e1873770 Improve import routine. 2017-07-15 10:26:16 +02:00
James Cole
3b3579025d Improve results when presented with invalid data. #701 2017-07-14 17:57:20 +02:00
James Cole
5cf8f2f4f4 Add sort flag for #698 2017-07-14 17:25:03 +02:00
James Cole
c4ff05b1ba Sort fix #698 [skip ci] 2017-07-14 17:21:30 +02:00
James Cole
2bf54d0b8e Remove extra X [skip ci] 2017-07-14 17:10:56 +02:00
James Cole
2a63888546 Table is sortable, #697 2017-07-14 17:10:06 +02:00
James Cole
cb8294cbd2 Disable button form on submit. 2017-07-14 17:05:32 +02:00
James Cole
c9a99be183 Fix #699 2017-07-14 17:04:18 +02:00
James Cole
5d2e026e5a New translations firefly.php (Polish) 2017-07-14 16:10:12 +02:00
James Cole
568fdad52a New translations form.php (Polish) 2017-07-14 16:10:08 +02:00
James Cole
174fb65fed New translations firefly.php (Polish) 2017-07-14 16:00:25 +02:00
James Cole
2e77c45ae8 New translations csv.php (Polish) 2017-07-14 15:50:27 +02:00
James Cole
1b674a0abf New translations firefly.php (Polish) 2017-07-14 15:50:25 +02:00
James Cole
4beb8b1f6b New translations csv.php (Polish) 2017-07-14 15:40:20 +02:00
James Cole
3c4abb7b60 Fixed some issues in import, should improve results for #701 2017-07-14 06:41:47 +02:00
James Cole
970c73c221 Fix path 2017-07-14 06:41:10 +02:00
James Cole
6797c1255f New translations firefly.php (Russian) 2017-07-13 14:40:45 +02:00
James Cole
0ed159b553 New translations firefly.php (Russian) 2017-07-13 14:30:23 +02:00
James Cole
faa8679804 New translations firefly.php (Russian) 2017-07-13 14:20:12 +02:00
James Cole
e3d2253958 New translations firefly.php (Russian) 2017-07-13 14:10:18 +02:00
James Cole
3f7b7996c0 New translations firefly.php (Russian) 2017-07-13 14:00:16 +02:00
James Cole
9229ff54df New translations csv.php (Russian) 2017-07-13 13:50:15 +02:00
James Cole
204ab8f427 New translations demo.php (Russian) 2017-07-13 13:50:13 +02:00
James Cole
8ee6c0789d New translations csv.php (Russian) 2017-07-13 13:40:21 +02:00
James Cole
be188e7266 New translations form.php (Russian) 2017-07-13 13:40:20 +02:00
James Cole
1a43b62750 New translations help.php (Russian) 2017-07-13 13:30:11 +02:00
James Cole
eaa8321aa8 New translations help.php (Russian) 2017-07-13 13:20:19 +02:00
James Cole
f01f0071dd New translations list.php (Russian) 2017-07-13 13:20:17 +02:00
James Cole
ec69cc3590 New translations list.php (Russian) 2017-07-13 13:10:16 +02:00
James Cole
102dac1eb8 New translations validation.php (Russian) 2017-07-13 13:10:14 +02:00
James Cole
d54c5f1f99 New translations passwords.php (Russian) 2017-07-13 12:10:27 +02:00
James Cole
c2e0e00c47 New translations pagination.php (Russian) 2017-07-13 12:10:26 +02:00
James Cole
f24e387363 New translations breadcrumbs.php (Russian) 2017-07-13 12:00:27 +02:00
James Cole
09715b83e4 New translations auth.php (Russian) 2017-07-13 11:50:19 +02:00
James Cole
e4f197bbc9 New translations breadcrumbs.php (Russian) 2017-07-13 11:50:18 +02:00
James Cole
de64cef48d New translations auth.php (Russian) 2017-07-13 11:01:08 +02:00
James Cole
b85329b371 New translations firefly.php (Russian) 2017-07-13 11:01:07 +02:00
James Cole
215f9a4245 New translations csv.php (Russian) 2017-07-13 11:00:58 +02:00
James Cole
80ce7a64ba New translations config.php (Russian) 2017-07-13 11:00:56 +02:00
James Cole
65f3dc0656 New translations breadcrumbs.php (Russian) 2017-07-13 11:00:55 +02:00
James Cole
f9b6b841b6 New translations form.php (Russian) 2017-07-13 11:00:53 +02:00
James Cole
d4f2d649e8 New translations help.php (Russian) 2017-07-13 11:00:50 +02:00
James Cole
15b057fe68 New translations demo.php (Russian) 2017-07-13 11:00:48 +02:00
James Cole
9cb549f4a1 New translations validation.php (Russian) 2017-07-13 11:00:47 +02:00
James Cole
4d67578458 New translations passwords.php (Russian) 2017-07-13 11:00:44 +02:00
James Cole
71faaf1c19 New translations list.php (Russian) 2017-07-13 11:00:43 +02:00
James Cole
0187f29b4b New translations pagination.php (Russian) 2017-07-13 11:00:40 +02:00
James Cole
9b6ccdd43a Fixes #694 2017-07-10 19:52:31 +02:00
James Cole
e82deddefb Merge branch 'release/4.6.2' 2017-07-08 09:55:44 +02:00
James Cole
780bec35bb Merge pull request #687 from firefly-iii/l10n_develop
New Crowdin translations
2017-07-08 09:47:01 +02:00
James Cole
27d80fd370 Updated libraries. 2017-07-08 06:53:15 +02:00
James Cole
952328d55c Routine to make sure imported entries have the correct opposing account and the correct amount. 2017-07-08 06:53:06 +02:00
James Cole
f747f3bd10 Updated changelog. 2017-07-08 06:30:41 +02:00
James Cole
11c3aca58d New version. 2017-07-08 06:28:52 +02:00
James Cole
5ef2067836 Some code cleanup. 2017-07-08 06:28:44 +02:00
James Cole
de9728895e Fixed #658 2017-07-08 06:09:17 +02:00
James Cole
19774f32c2 First code for #658 2017-07-07 17:51:14 +02:00
James Cole
e62b979708 Fix redirect error [skip ci] 2017-07-07 16:53:44 +02:00
James Cole
69eef30ad3 Various code clean up. 2017-07-07 13:50:15 +02:00
James Cole
71a41bc00d Add newlines [skip ci] 2017-07-07 08:09:42 +02:00
James Cole
dd508dbc49 This should fix #693. 2017-07-07 08:04:21 +02:00
James Cole
13ad40402a New translations firefly.php (German) 2017-07-06 11:30:11 +02:00
James Cole
98712f288c New translations firefly.php (German) 2017-07-04 20:40:08 +02:00
James Cole
a29a78e199 New translations csv.php (German) 2017-07-04 20:40:05 +02:00
James Cole
767267c89e New translations demo.php (German) 2017-07-04 20:20:16 +02:00
James Cole
b3801f65cf New translations demo.php (German) 2017-07-04 20:10:06 +02:00
James Cole
44a1d6b3d4 New translations csv.php (German) 2017-07-04 20:00:06 +02:00
James Cole
7a1528d1e4 New translations csv.php (German) 2017-07-04 19:50:10 +02:00
James Cole
c970a25d58 New translations firefly.php (German) 2017-07-04 19:50:09 +02:00
James Cole
0a78b0b130 New translations demo.php (German) 2017-07-04 19:50:06 +02:00
James Cole
69f6dc09d3 New translations demo.php (German) 2017-07-04 19:40:06 +02:00
James Cole
467e708617 New translations form.php (German) 2017-07-04 19:40:05 +02:00
James Cole
3a84591e61 Simplify edit transaction routine. 2017-07-04 16:31:16 +02:00
James Cole
a527066216 Add links to boxes for #688 2017-07-04 16:17:05 +02:00
James Cole
ef9823035f Add if-statement to catch unset POST data. 2017-07-04 16:03:00 +02:00
James Cole
513ee4c7d9 New translations firefly.php (Polish) 2017-07-03 18:00:20 +02:00
James Cole
fcc9b3a588 Merge branch 'release/4.6.1' 2017-07-02 09:36:20 +02:00
James Cole
71eed45b77 Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop
* 'develop' of https://github.com/firefly-iii/firefly-iii:
  New translations firefly.php (Dutch)
  New translations firefly.php (Chinese Traditional)
  New translations firefly.php (Dutch)
  New translations firefly.php (French)
  New translations firefly.php (German)
  New translations firefly.php (Polish)
  New translations firefly.php (Portuguese, Brazilian)
  New translations firefly.php (Slovenian)
  New translations firefly.php (Spanish)
2017-07-02 09:35:46 +02:00
James Cole
6940f00492 Merge pull request #686 from firefly-iii/l10n_develop
New Crowdin translations
2017-07-02 09:35:13 +02:00
James Cole
1c85c20fa9 New translations firefly.php (Dutch) 2017-07-02 09:35:03 +02:00
James Cole
ae30b02405 New version and changelog. 2017-07-02 09:32:19 +02:00
James Cole
89b7a9d3ac Updated composer file [skip ci] 2017-07-02 09:30:46 +02:00
James Cole
dc25fc99b3 New translations firefly.php (Chinese Traditional) 2017-07-02 09:30:42 +02:00
James Cole
6e6957a9ab New translations firefly.php (Dutch) 2017-07-02 09:30:40 +02:00
James Cole
0609e7db06 New translations firefly.php (French) 2017-07-02 09:30:38 +02:00
James Cole
f57097b79e New translations firefly.php (German) 2017-07-02 09:30:34 +02:00
James Cole
7e988d97d3 New translations firefly.php (Polish) 2017-07-02 09:30:32 +02:00
James Cole
2795042c2c Included some dev data by accident [skip ci] 2017-07-02 09:30:28 +02:00
James Cole
c3c86545fc New translations firefly.php (Portuguese, Brazilian) 2017-07-02 09:30:28 +02:00
James Cole
3fe14a3d56 New translations firefly.php (Slovenian) 2017-07-02 09:30:25 +02:00
James Cole
bad5740728 New translations firefly.php (Spanish) 2017-07-02 09:30:23 +02:00
James Cole
c164553ba1 Small cosmetic change. 2017-07-02 09:27:08 +02:00
James Cole
e6c72b2995 Fixed mobile display 2017-07-02 09:24:46 +02:00
James Cole
cbcefabbff Forgot a translation. 2017-07-02 09:24:30 +02:00
James Cole
97cfa3f3ae Remove old providers. 2017-07-02 09:24:20 +02:00
James Cole
803a008821 Improve bread crumbs 2017-07-02 09:24:11 +02:00
James Cole
658730928b Remove old JS 2017-07-02 09:24:00 +02:00
James Cole
310db374c8 Fix #678 2017-07-02 09:22:56 +02:00
James Cole
dc5bd648cf Fix for #685 2017-07-02 08:43:34 +02:00
James Cole
b6be9e6ade Fix for #682 2017-07-01 10:39:59 +02:00
James Cole
04f71496e3 Code for #678 2017-07-01 10:36:08 +02:00
James Cole
1eed142423 Small display bug related to #648 2017-07-01 10:29:07 +02:00
James Cole
f1e0ad0df0 CoC. [skip ci] 2017-06-30 07:22:12 +02:00
James Cole
f8fa5f1ba5 Improved mobile response, issue #678 2017-06-30 07:17:25 +02:00
James Cole
c187563267 Update report layout [skip ci] 2017-06-28 20:41:02 +02:00
James Cole
fcdbbd5dbc Update report layout [skip ci] 2017-06-28 20:39:12 +02:00
James Cole
6604d04c60 Slightly different report layout [skip ci] 2017-06-28 20:23:24 +02:00
James Cole
63be574a14 Merge branch 'release/4.6.0' 2017-06-28 18:13:00 +02:00
James Cole
2414f998ba Update git ignore file. 2017-06-28 18:09:32 +02:00
James Cole
90e2ecad4f Merge pull request #683 from firefly-iii/l10n_develop
New Crowdin translations
2017-06-28 18:08:27 +02:00
James Cole
87a3f5c715 New translations firefly.php (Dutch) 2017-06-28 18:07:52 +02:00
James Cole
a4ef81ebd8 Improve test coverage. 2017-06-28 18:05:38 +02:00
James Cole
67fc810fc2 Ignore test database. 2017-06-28 18:05:04 +02:00
James Cole
e13a61645d New change log 2017-06-28 18:04:42 +02:00
James Cole
aae4a78fd4 Possible fix for #649 [skip ci] 2017-06-28 15:52:13 +02:00
James Cole
3947da5e27 Possible fix for #682 2017-06-28 15:45:28 +02:00
James Cole
4e4ce2f77c Remove test database from Firefly III thing. [skip ci] 2017-06-28 15:31:11 +02:00
James Cole
d9a2e081bd Update travis script. 2017-06-28 15:27:31 +02:00
James Cole
e60dde7ce5 Merge pull request #681 from firefly-iii/l10n_develop
New Crowdin translations
2017-06-28 15:18:59 +02:00
James Cole
699b138999 Small link fixes [skip ci] 2017-06-28 15:18:11 +02:00
James Cole
8f191b497f Updated read me and contributing guidelines. 2017-06-28 15:17:19 +02:00
James Cole
fd013d617c New translations firefly.php (Chinese Traditional) 2017-06-28 15:11:10 +02:00
James Cole
a8bda38035 New translations firefly.php (Dutch) 2017-06-28 15:11:07 +02:00
James Cole
411de9aa23 New translations firefly.php (French) 2017-06-28 15:11:05 +02:00
James Cole
f0abe497ef New translations firefly.php (German) 2017-06-28 15:11:02 +02:00
James Cole
9c8be83f5d New translations firefly.php (Polish) 2017-06-28 15:10:58 +02:00
James Cole
45335af8cf New translations firefly.php (Portuguese, Brazilian) 2017-06-28 15:10:56 +02:00
James Cole
945e433bb7 New translations firefly.php (Slovenian) 2017-06-28 15:10:51 +02:00
James Cole
70729fdb0c New translations firefly.php (Spanish) 2017-06-28 15:10:48 +02:00
James Cole
4a435e5701 Updated composer file. 2017-06-28 15:01:06 +02:00
James Cole
427747c6b8 Merge pull request #666 from firefly-iii/l10n_develop
New Crowdin translations
2017-06-28 15:00:48 +02:00
James Cole
be9407cb57 New translations csv.php (Dutch) 2017-06-28 15:00:19 +02:00
James Cole
c380d3d2a0 New translations firefly.php (Dutch) 2017-06-28 15:00:13 +02:00
James Cole
489b0eb12d New translations firefly.php (Dutch) 2017-06-28 14:50:13 +02:00
James Cole
7c73629962 Merge pull request #680 from Xeli/l10n_develop
Fix en_US translation: no_accounts_imperative_revenue.
2017-06-28 12:41:26 +02:00
richard@xeli.eu
ff619eca1c Fix en_US translation: no_accounts_imperative_revenue. Change Expense to Revenue 2017-06-28 12:12:31 +02:00
James Cole
134a39fd71 New translations firefly.php (German) 2017-06-27 13:50:38 +02:00
James Cole
506509b1b2 Fix #677 2017-06-26 18:29:45 +02:00
James Cole
02a36316be Forgot to remove a variable. 2017-06-26 18:24:44 +02:00
James Cole
8549c7c81b This should fix #677 2017-06-26 18:24:29 +02:00
James Cole
5a0be7d2ad Push new version number. 2017-06-24 13:05:12 +02:00
James Cole
c6f44c6398 Composer update. 2017-06-24 13:04:50 +02:00
James Cole
04a8a0e6a1 Code clean up 2017-06-24 13:04:41 +02:00
James Cole
8a175d147b Remove JS console log. 2017-06-24 13:03:09 +02:00
James Cole
5fbc319b20 This fixes the tests (must still upload test database). 2017-06-24 12:38:24 +02:00
James Cole
8e3ba7caf2 Fix various import bugs. 2017-06-24 08:37:09 +02:00
James Cole
182aaa7d27 New translations csv.php (Spanish) 2017-06-24 07:30:48 +02:00
James Cole
ec17d466f7 New translations firefly.php (Chinese Traditional) 2017-06-24 07:30:46 +02:00
James Cole
79c2445117 New translations firefly.php (Dutch) 2017-06-24 07:30:44 +02:00
James Cole
aa59db1609 New translations firefly.php (French) 2017-06-24 07:30:42 +02:00
James Cole
814b106be2 New translations csv.php (Slovenian) 2017-06-24 07:30:40 +02:00
James Cole
3901ea0fbe New translations csv.php (Portuguese, Brazilian) 2017-06-24 07:30:39 +02:00
James Cole
65133107be New translations csv.php (Dutch) 2017-06-24 07:30:38 +02:00
James Cole
08d15cfc5e New translations csv.php (French) 2017-06-24 07:30:37 +02:00
James Cole
3c89f9a5f1 New translations csv.php (German) 2017-06-24 07:30:36 +02:00
James Cole
dbc6bc8206 New translations csv.php (Polish) 2017-06-24 07:30:35 +02:00
James Cole
dc38291ef5 New translations firefly.php (German) 2017-06-24 07:30:34 +02:00
James Cole
3bb634ed5b New translations firefly.php (Polish) 2017-06-24 07:30:32 +02:00
James Cole
4bdcfe4d30 New translations firefly.php (Portuguese, Brazilian) 2017-06-24 07:30:28 +02:00
James Cole
3b74784486 New translations firefly.php (Slovenian) 2017-06-24 07:30:25 +02:00
James Cole
5226664a3d New translations firefly.php (Spanish) 2017-06-24 07:30:23 +02:00
James Cole
6d23823b63 New translations csv.php (Chinese Traditional) 2017-06-24 07:30:20 +02:00
James Cole
da3a56c144 Further improve import storage. 2017-06-24 07:30:05 +02:00
James Cole
58aa54d8cf Improving import storage. 2017-06-24 07:21:10 +02:00
James Cole
e525e673a8 Import routine cleanup. 2017-06-24 06:57:24 +02:00
James Cole
445dbf8779 More and improved code for the import routine. 2017-06-24 05:49:33 +02:00
James Cole
6a27bea2a3 New translations firefly.php (Chinese Traditional) 2017-06-22 22:01:08 +02:00
James Cole
13163f9c5c New translations firefly.php (Dutch) 2017-06-22 22:01:05 +02:00
James Cole
fde08f922b New translations firefly.php (French) 2017-06-22 22:01:02 +02:00
James Cole
266ce00872 New translations firefly.php (German) 2017-06-22 22:00:56 +02:00
James Cole
623a70a0d1 New translations firefly.php (Polish) 2017-06-22 22:00:52 +02:00
James Cole
1d7b738040 New translations firefly.php (Portuguese, Brazilian) 2017-06-22 22:00:46 +02:00
James Cole
edc8dd2601 New translations firefly.php (Slovenian) 2017-06-22 22:00:43 +02:00
James Cole
31dc932ca4 New translations firefly.php (Spanish) 2017-06-22 22:00:40 +02:00
James Cole
edb355941c More code for import routine. 2017-06-22 21:50:10 +02:00
James Cole
cddaccb7f7 Further improve import routine 2017-06-21 20:04:35 +02:00
James Cole
a905cce2c9 Expand import routine. 2017-06-20 21:04:25 +02:00
James Cole
b9f110ac2b Refactor and rename some import things. 2017-06-17 22:49:44 +02:00
James Cole
7cc24417b3 Expanded import routine. 2017-06-14 20:13:19 +02:00
James Cole
b304284d70 Fix report bug. 2017-06-14 19:15:30 +02:00
James Cole
c382fb1577 Add debug info for #671 2017-06-12 19:58:32 +02:00
James Cole
77244f4e2c Lots of new code for new importer routine. 2017-06-12 19:12:07 +02:00
James Cole
8beab5f5bc Fix #672 2017-06-12 17:21:31 +02:00
James Cole
902ae3f0cf Fix for #671 2017-06-12 17:07:29 +02:00
James Cole
519ef4e486 New translations csv.php (French) 2017-06-10 15:21:17 +02:00
James Cole
699e04f371 New translations firefly.php (French) 2017-06-10 15:21:16 +02:00
James Cole
d73de0e60d New translations csv.php (German) 2017-06-10 15:21:12 +02:00
James Cole
8e0b7d2a73 New translations firefly.php (German) 2017-06-10 15:21:10 +02:00
James Cole
04283cf2d6 New translations csv.php (Polish) 2017-06-10 15:21:06 +02:00
James Cole
d60b4aa56f New translations csv.php (Chinese Traditional) 2017-06-10 15:20:57 +02:00
James Cole
9cfeda1b0c New translations firefly.php (Chinese Traditional) 2017-06-10 15:20:55 +02:00
James Cole
5e1bd8e1eb New translations csv.php (Dutch) 2017-06-10 15:20:48 +02:00
James Cole
9b495d212b New translations firefly.php (Polish) 2017-06-10 15:20:47 +02:00
James Cole
b6fdd0070b New translations firefly.php (Slovenian) 2017-06-10 15:20:40 +02:00
James Cole
eea387ad0c New translations csv.php (Spanish) 2017-06-10 15:20:33 +02:00
James Cole
9cdb0f173a New translations csv.php (Slovenian) 2017-06-10 15:20:31 +02:00
James Cole
51063230d0 New translations firefly.php (Dutch) 2017-06-10 15:20:30 +02:00
James Cole
1111478b7f New translations firefly.php (Portuguese, Brazilian) 2017-06-10 15:20:25 +02:00
James Cole
c99c9b441f New translations csv.php (Portuguese, Brazilian) 2017-06-10 15:20:17 +02:00
James Cole
b5065a0276 New translations firefly.php (Spanish) 2017-06-10 15:20:11 +02:00
James Cole
c79a577060 Remove unused files in import. 2017-06-10 15:10:46 +02:00
James Cole
091596e80e Lots of new code for new importer routine. 2017-06-10 15:09:41 +02:00
James Cole
0b4efe4ae1 Small typo in chart. [skip ci] 2017-06-09 12:53:31 +02:00
James Cole
1f9b7faa60 Code for #660 2017-06-09 11:52:20 +02:00
James Cole
762d7bcc34 Fix database for postgresql 2017-06-09 11:51:59 +02:00
James Cole
a2145f6b49 Possible fix for #667 2017-06-08 10:54:15 +02:00
James Cole
b48de98865 Fix a bug where the balance routine forgot to account for accounts without a currency preference. 2017-06-08 10:35:02 +02:00
James Cole
a23179dd83 Merge branch 'release/4.5.0' 2017-06-07 12:30:09 +02:00
James Cole
5c18794122 Update lock file, and update database. 2017-06-07 12:22:59 +02:00
James Cole
f04011f6a7 New translations firefly.php (Dutch) 2017-06-07 12:20:13 +02:00
James Cole
893498238e Merge pull request #647 from firefly-iii/l10n_develop
New Crowdin translations
2017-06-07 12:11:28 +02:00
James Cole
474fa9dea0 New translations firefly.php (Dutch) 2017-06-07 12:10:10 +02:00
James Cole
d8a8574dda Prep for new release. 2017-06-07 12:08:32 +02:00
James Cole
935fb015d3 Live update budget amounts. 2017-06-07 11:58:04 +02:00
James Cole
8bbd3063ec Move code around for simplicity and fix tests. 2017-06-07 11:13:04 +02:00
James Cole
92c5cabd70 Try to untangle complex repositories 2017-06-07 08:18:42 +02:00
James Cole
e5db5a7b5c Various code clean up. 2017-06-07 07:38:58 +02:00
James Cole
28cf123da3 New translations firefly.php (French) 2017-06-06 20:41:24 +02:00
James Cole
5069367873 New translations firefly.php (German) 2017-06-06 20:41:16 +02:00
James Cole
234e656ff6 New translations firefly.php (Chinese Traditional) 2017-06-06 20:40:59 +02:00
James Cole
aeadfbdd6a New translations firefly.php (Polish) 2017-06-06 20:40:50 +02:00
James Cole
39288cfb0b New translations firefly.php (Slovenian) 2017-06-06 20:40:41 +02:00
James Cole
5e430968c1 New translations firefly.php (Dutch) 2017-06-06 20:40:34 +02:00
James Cole
154b74ce6f New translations firefly.php (Portuguese, Brazilian) 2017-06-06 20:40:26 +02:00
James Cole
2e26303b66 New translations firefly.php (Spanish) 2017-06-06 20:40:11 +02:00
James Cole
51ddcd9ee1 Plus not minus [skip ci] 2017-06-06 20:37:24 +02:00
James Cole
9d5d1c0a41 Updated budget view. 2017-06-06 20:35:39 +02:00
James Cole
6058ccff0d Merge pull request #664 from kressh/master
Add pgsql dependencies to Dockerfile
2017-06-06 20:01:43 +02:00
James Cole
a8ec4fe2fd New interface for budget overview. 2017-06-06 19:30:31 +02:00
James Cole
65ccb2d443 Fix error display #662 2017-06-06 19:29:10 +02:00
James Cole
0e929602a8 Verify currency data routine. 2017-06-06 07:23:54 +02:00
James Cole
5329e026dc Fixed various currency displays. 2017-06-06 07:18:09 +02:00
James Cole
a7412e43b3 Beter message for #662 2017-06-06 06:56:32 +02:00
Sergey Besedin
eeae24e058 Add pgsql dependencies 2017-06-06 01:22:09 +03:00
James Cole
17b6cc43d5 Fix display of foreign currencies in charts. 2017-06-05 22:11:54 +02:00
James Cole
b69a2ef0cd Can handle multi-currency balances better. 2017-06-05 15:09:17 +02:00
James Cole
6d1296094e Fixes a lot of issues in scrutinizer. 2017-06-05 11:20:38 +02:00
James Cole
c4039b53e6 Various code cleanup. 2017-06-05 11:12:50 +02:00
James Cole
64831b4c86 Code cleanup and refactoring. 2017-06-05 08:31:22 +02:00
James Cole
1dec270907 These changes fix the tests. 2017-06-05 07:37:53 +02:00
James Cole
f72f8b03df Catch empty currency preference 2017-06-05 07:03:32 +02:00
James Cole
0b47e5d05d Removed unnecessary variable. 2017-06-05 07:03:20 +02:00
James Cole
a487c7b4b2 Make sure amounts are formatted, and fixed some issues. 2017-06-04 23:39:26 +02:00
James Cole
3838b21459 New translations firefly.php (French) 2017-06-04 13:41:19 +02:00
James Cole
7801274d33 New translations firefly.php (German) 2017-06-04 13:41:15 +02:00
James Cole
a505406ee7 New translations firefly.php (Chinese Traditional) 2017-06-04 13:41:03 +02:00
James Cole
9487a95c13 New translations firefly.php (Polish) 2017-06-04 13:40:54 +02:00
James Cole
3b2fe13902 New translations firefly.php (Slovenian) 2017-06-04 13:40:47 +02:00
James Cole
db2898dfe5 New translations auth.php (Spanish) 2017-06-04 13:40:44 +02:00
James Cole
e08fd399d2 New translations csv.php (Spanish) 2017-06-04 13:40:40 +02:00
James Cole
e45ffba010 New translations passwords.php (Spanish) 2017-06-04 13:40:39 +02:00
James Cole
f7fde93ed2 New translations firefly.php (Dutch) 2017-06-04 13:40:37 +02:00
James Cole
3cf53604a1 New translations firefly.php (Portuguese, Brazilian) 2017-06-04 13:40:31 +02:00
James Cole
e041a5e037 New translations help.php (Spanish) 2017-06-04 13:40:19 +02:00
James Cole
6c8e10255b New translations form.php (Spanish) 2017-06-04 13:40:17 +02:00
James Cole
3464ab1527 New translations firefly.php (Spanish) 2017-06-04 13:40:13 +02:00
James Cole
82e74a2afd Big update to properly support multi currencies. 2017-06-04 13:39:16 +02:00
James Cole
771ebde295 Update journal collector so currency information is taken from the transaction. 2017-06-04 08:49:37 +02:00
James Cole
4ce4c3138c Update export routine so currency information is taken from the transaction. 2017-06-04 08:49:22 +02:00
James Cole
d37b46effc Database upgrade routine. 2017-06-04 08:48:54 +02:00
James Cole
0868aac750 Small update for 4.5.0 SQL update. 2017-06-04 08:48:40 +02:00
James Cole
4ff5f33966 Prep for solid multi-currency configuration. 2017-06-02 13:01:43 +02:00
James Cole
e1aebbe12b Remove non-existing charts. 2017-06-02 13:01:24 +02:00
James Cole
8273f467b6 Refactor some JS functions. 2017-06-02 13:00:43 +02:00
James Cole
74664afa68 Was not able to remove opening balance. 2017-06-02 13:00:24 +02:00
James Cole
c05f344371 Code clean up [skip ci] 2017-06-02 13:00:09 +02:00
James Cole
ec1507d644 Add some documentation [skip ci] 2017-06-02 12:59:27 +02:00
James Cole
8cdc1f0014 Rename several twig files. 2017-06-02 12:59:14 +02:00
James Cole
2b1ab5c6ef Fixed edit of multi currency transaction, ##651 2017-06-02 07:05:42 +02:00
James Cole
01fedc0bf8 Fix for #593, as inspired by @nhaarman. 2017-06-02 06:45:38 +02:00
James Cole
1bd82d71a2 New translations list.php (Spanish) 2017-05-25 16:50:09 +02:00
James Cole
1e9dacb6e4 New translations pagination.php (Spanish) 2017-05-25 16:40:16 +02:00
James Cole
94939ea3d3 New translations firefly.php (Portuguese, Brazilian) 2017-05-25 16:40:13 +02:00
James Cole
c3ff69d147 New translations list.php (Spanish) 2017-05-25 16:40:09 +02:00
James Cole
0fad9d4ac7 New translations validation.php (Spanish) 2017-05-25 16:40:07 +02:00
James Cole
70cd8ffb72 New translations validation.php (Spanish) 2017-05-25 16:30:10 +02:00
James Cole
61535bf4b8 New translations firefly.php (Spanish) 2017-05-25 16:30:08 +02:00
James Cole
4adcbf9e48 New translations demo.php (Spanish) 2017-05-25 16:20:11 +02:00
James Cole
3eba3167fd New translations firefly.php (Spanish) 2017-05-25 16:20:07 +02:00
James Cole
0608fd7732 New translations demo.php (Spanish) 2017-05-25 16:10:06 +02:00
James Cole
1f41f27e89 New translations breadcrumbs.php (Spanish) 2017-05-25 16:00:11 +02:00
James Cole
ded0df9303 New translations config.php (Spanish) 2017-05-25 16:00:06 +02:00
James Cole
2a7ba1893a New translations form.php (Slovenian) 2017-05-16 15:10:18 +02:00
James Cole
6b3b19632a New translations help.php (Slovenian) 2017-05-16 15:10:15 +02:00
James Cole
98bb0731df New translations list.php (Slovenian) 2017-05-16 15:10:12 +02:00
James Cole
a102f7044e New translations list.php (Slovenian) 2017-05-15 09:20:09 +02:00
James Cole
f1028dbaed New translations list.php (Slovenian) 2017-05-15 09:10:14 +02:00
James Cole
438ce5c3db New translations list.php (Slovenian) 2017-05-15 09:00:35 +02:00
James Cole
b995a1d091 New translations list.php (Slovenian) 2017-05-15 08:50:08 +02:00
James Cole
e072f83507 New translations list.php (Slovenian) 2017-05-14 10:10:08 +02:00
James Cole
79154bba25 New translations pagination.php (Slovenian) 2017-05-14 10:10:06 +02:00
James Cole
613eb7522c New translations pagination.php (Slovenian) 2017-05-14 10:00:10 +02:00
James Cole
0eb5653713 New translations csv.php (Slovenian) 2017-05-14 10:00:08 +02:00
James Cole
0d624f021b New translations csv.php (Slovenian) 2017-05-14 09:30:23 +02:00
James Cole
b263047f4e New translations csv.php (Slovenian) 2017-05-14 09:20:21 +02:00
James Cole
4410e1bbd7 New translations csv.php (Slovenian) 2017-05-14 09:10:12 +02:00
James Cole
8c3871e8de New translations csv.php (Slovenian) 2017-05-14 09:00:09 +02:00
James Cole
2eafd3cc15 Should fix #644 2017-05-14 08:57:43 +02:00
James Cole
368df66947 New translations validation.php (Slovenian) 2017-05-14 08:40:06 +02:00
James Cole
9f9a3ea8fd New translations breadcrumbs.php (Slovenian) 2017-05-14 01:20:08 +02:00
James Cole
f66286105f New translations validation.php (Slovenian) 2017-05-14 01:20:07 +02:00
James Cole
0f0f912370 Partial JS focus [skip ci] 2017-05-12 06:21:26 +02:00
James Cole
9fa0e37a5d Merge pull request #641 from firefly-iii/l10n_develop
New Crowdin translations
2017-05-12 06:20:05 +02:00
James Cole
a0cb51ff70 Merge branch 'develop' into l10n_develop 2017-05-12 06:19:56 +02:00
James Cole
a6305ddea4 New translations auth.php (Spanish) 2017-05-10 20:40:44 +02:00
James Cole
fb8638fe6a New translations breadcrumbs.php (Spanish) 2017-05-10 20:40:42 +02:00
James Cole
0009f1f865 New translations csv.php (Spanish) 2017-05-10 20:40:41 +02:00
James Cole
d449c35025 New translations passwords.php (Spanish) 2017-05-10 20:40:39 +02:00
James Cole
1893d1a2c2 New translations demo.php (Spanish) 2017-05-10 20:40:37 +02:00
James Cole
0c4539e4fa New translations validation.php (Spanish) 2017-05-10 20:40:31 +02:00
James Cole
feacddd1d7 Merge pull request #645 from elamperti/unfinished-translations-es_ES
Unfinished translations for Spanish language
2017-05-10 20:36:55 +02:00
Enrico Lamperti
0c44fe6ce0 Add translations for Spanish language 2017-05-07 21:24:07 -03:00
James Cole
17fb6983d8 Fix issue #637 with cash accounts. 2017-05-07 19:45:40 +02:00
James Cole
5fb73bdb01 Fix bug #642 2017-05-07 19:24:53 +02:00
James Cole
7f082ea389 Remove focus thing 2017-05-06 10:20:27 +02:00
James Cole
9856a1831a New translations firefly.php (Slovenian) 2017-05-04 17:40:13 +02:00
James Cole
dd17a20b60 New translations firefly.php (Slovenian) 2017-05-04 17:30:12 +02:00
James Cole
665a52b106 Merge branch 'release/4.4.3' 2017-05-03 21:25:44 +02:00
James Cole
f68d33870b Composer lock file and version update. 2017-05-03 21:25:13 +02:00
James Cole
49d13b12a5 No code coverage. 2017-05-03 21:22:01 +02:00
James Cole
674ab7e41f Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop
* 'develop' of https://github.com/firefly-iii/firefly-iii: (45 commits)
  New translations validation.php (Slovenian)
  New translations csv.php (Slovenian)
  New translations csv.php (Slovenian)
  New translations csv.php (Slovenian)
  New translations csv.php (Slovenian)
  New translations passwords.php (Slovenian)
  New translations csv.php (Slovenian)
  New translations csv.php (Slovenian)
  New translations config.php (Slovenian)
  New translations breadcrumbs.php (Slovenian)
  New translations breadcrumbs.php (Slovenian)
  New translations auth.php (Slovenian)
  New translations firefly.php (Slovenian)
  New translations breadcrumbs.php (Slovenian)
  New translations demo.php (Slovenian)
  New translations firefly.php (Slovenian)
  New translations firefly.php (Slovenian)
  New translations firefly.php (Slovenian)
  New translations firefly.php (Slovenian)
  New translations form.php (Slovenian)
  ...
2017-05-03 21:21:03 +02:00
James Cole
5b3eb3ba82 Merge pull request #639 from firefly-iii/l10n_develop
New Crowdin translations
2017-05-03 21:20:36 +02:00
James Cole
e28d3f3b5a Remove unused languages. 2017-05-03 21:14:37 +02:00
James Cole
870d8b5008 No prefix key, issue #624 2017-05-03 21:12:49 +02:00
James Cole
6aa240e9a3 Update version and changelog. 2017-05-03 21:12:19 +02:00
James Cole
b55a4047d0 New translations validation.php (Slovenian) 2017-05-03 17:50:07 +02:00
James Cole
a07d87318c New translations csv.php (Slovenian) 2017-05-03 17:40:08 +02:00
James Cole
dd6555c903 New translations csv.php (Slovenian) 2017-05-03 17:30:12 +02:00
James Cole
e8c40b6044 New translations csv.php (Slovenian) 2017-05-03 17:21:14 +02:00
James Cole
91c17a0b2a New translations csv.php (Slovenian) 2017-05-03 09:40:10 +02:00
James Cole
2ed0ea0243 New translations passwords.php (Slovenian) 2017-05-03 09:00:11 +02:00
James Cole
df2f92433a New translations csv.php (Slovenian) 2017-05-03 01:10:06 +02:00
James Cole
68b3fc72bf New translations csv.php (Slovenian) 2017-05-03 01:00:11 +02:00
James Cole
df5bb14758 New translations config.php (Slovenian) 2017-05-03 01:00:08 +02:00
James Cole
e24199bbbe New translations breadcrumbs.php (Slovenian) 2017-05-03 00:40:06 +02:00
James Cole
2c6099556b New translations breadcrumbs.php (Slovenian) 2017-05-03 00:30:13 +02:00
James Cole
f98215a5da New translations auth.php (Slovenian) 2017-05-03 00:30:11 +02:00
James Cole
b6b6888493 New translations firefly.php (Slovenian) 2017-05-03 00:30:09 +02:00
James Cole
f8e5b9be43 New translations breadcrumbs.php (Slovenian) 2017-05-03 00:20:10 +02:00
James Cole
692210214f New translations demo.php (Slovenian) 2017-05-03 00:20:08 +02:00
James Cole
cff2546c0c New translations firefly.php (Slovenian) 2017-05-03 00:10:14 +02:00
James Cole
f0cc1200f3 New translations firefly.php (Slovenian) 2017-05-03 00:00:14 +02:00
James Cole
e83a9af455 New translations firefly.php (Slovenian) 2017-05-02 23:50:09 +02:00
James Cole
fb84f9d9cf New translations firefly.php (Slovenian) 2017-05-02 23:40:12 +02:00
James Cole
118a2515e1 New translations form.php (Slovenian) 2017-05-02 23:40:09 +02:00
James Cole
63e891b0f7 New translations firefly.php (Slovenian) 2017-05-02 23:30:11 +02:00
James Cole
9891080b57 New translations firefly.php (Slovenian) 2017-05-02 23:20:10 +02:00
James Cole
bc7a7e55af New translations firefly.php (Slovenian) 2017-05-02 23:00:13 +02:00
James Cole
9b8a029de1 New translations demo.php (Slovenian) 2017-05-02 22:40:10 +02:00
James Cole
11b5575422 New translations csv.php (Slovenian) 2017-05-02 22:40:09 +02:00
James Cole
06336aa580 New translations form.php (Slovenian) 2017-05-02 22:40:07 +02:00
James Cole
aa8c1d6e9c New translations demo.php (Slovenian) 2017-05-02 22:30:08 +02:00
James Cole
9a4d5d8abf New translations firefly.php (Slovenian) 2017-05-02 22:20:11 +02:00
James Cole
3c5631bca3 New translations firefly.php (Slovenian) 2017-05-02 22:10:17 +02:00
James Cole
84f85f87b2 New translations firefly.php (Slovenian) 2017-05-02 22:00:13 +02:00
James Cole
c35db5976f New translations form.php (Slovenian) 2017-05-02 22:00:10 +02:00
James Cole
8d1fcf988c New translations firefly.php (Slovenian) 2017-05-02 21:50:11 +02:00
James Cole
bbf8f2dd69 New translations form.php (Slovenian) 2017-05-02 21:50:07 +02:00
James Cole
2f6436e34f New translations list.php (Slovenian) 2017-05-02 21:10:34 +02:00
James Cole
9cbb03107d New translations help.php (Slovenian) 2017-05-02 21:10:33 +02:00
James Cole
ee44d7fb2e New translations pagination.php (Slovenian) 2017-05-02 21:10:31 +02:00
James Cole
6a0fcd9cf0 New translations passwords.php (Slovenian) 2017-05-02 21:10:30 +02:00
James Cole
43cfe3b858 New translations demo.php (Slovenian) 2017-05-02 21:10:29 +02:00
James Cole
dba83c1c03 New translations validation.php (Slovenian) 2017-05-02 21:10:28 +02:00
James Cole
053e139d00 New translations form.php (Slovenian) 2017-05-02 21:10:26 +02:00
James Cole
04f791a839 New translations firefly.php (Slovenian) 2017-05-02 21:10:24 +02:00
James Cole
a4029c9490 New translations auth.php (Slovenian) 2017-05-02 21:10:20 +02:00
James Cole
d471dfec43 New translations csv.php (Slovenian) 2017-05-02 21:10:19 +02:00
James Cole
494bbd46d0 New translations config.php (Slovenian) 2017-05-02 21:10:17 +02:00
James Cole
1525b9ad06 New translations breadcrumbs.php (Slovenian) 2017-05-02 21:10:16 +02:00
James Cole
19847ee80b Change log update and added Slovenian. 2017-05-02 21:08:29 +02:00
James Cole
fddf1f146c Pie chart tests. 2017-05-02 20:54:49 +02:00
James Cole
5f19cb1c0c Fix canvas things. 2017-04-29 08:56:08 +02:00
James Cole
aaeae992e1 Reinstate support class. 2017-04-29 08:55:50 +02:00
James Cole
a0e7be9d45 Fix binding. 2017-04-29 08:55:37 +02:00
James Cole
78faf7e14c Forgot call to sprintf. [skip ci] 2017-04-29 08:33:32 +02:00
James Cole
98f84c2c37 Introducing filters to the journal collector. 2017-04-29 08:22:56 +02:00
James Cole
278805043e Update gitignore file. 2017-04-28 20:18:07 +02:00
James Cole
dc5215e41e Update tests. 2017-04-28 20:17:10 +02:00
James Cole
7e11691ea4 Update code to work with filters. 2017-04-28 20:08:25 +02:00
James Cole
c83dfc44d6 Update internal filters. 2017-04-28 20:08:04 +02:00
James Cole
68a01b1735 More text about Heroku. 2017-04-28 20:07:26 +02:00
James Cole
0307b58d17 Small changes to make code more testable. 2017-04-28 18:04:57 +02:00
James Cole
9d1508049e Add comment [skip ci] 2017-04-28 18:03:27 +02:00
James Cole
42322055f9 New filters to clean up the journal collector. 2017-04-28 18:02:54 +02:00
James Cole
5de8fce156 Make event handlers easier to test (and then ignore them). 2017-04-28 10:34:11 +02:00
James Cole
29ff92f833 Clean up event related code. 2017-04-28 07:51:43 +02:00
James Cole
359007c5bf Clean up event related code. 2017-04-28 07:51:09 +02:00
James Cole
bbe40518e4 Can now also test event code. 2017-04-27 08:26:58 +02:00
James Cole
b26f3c0cc6 User registration is now a Mailable. See #636 2017-04-27 08:03:15 +02:00
James Cole
552b4b67a6 Merge branch 'release/4.4.2' 2017-04-27 07:45:50 +02:00
James Cole
7fbf359efd New version [skip ci] 2017-04-27 07:45:15 +02:00
James Cole
052b804855 Fixed a bug where the opening balance could not be stored. 2017-04-27 07:44:35 +02:00
James Cole
67cc611495 Merge branch 'release/4.4.1' 2017-04-27 03:32:16 +02:00
James Cole
7e2c24b82e New test config 2017-04-27 03:29:11 +02:00
James Cole
4a6bbd4dca Update example config 2017-04-27 03:26:54 +02:00
James Cole
166bfba5b9 New version. [skip ci] 2017-04-27 03:17:34 +02:00
James Cole
87b8ac5f4e Update read me with deploy button [skip ci] 2017-04-27 03:16:27 +02:00
James Cole
46b4100291 Default key for instant deployment [skip ci] 2017-04-27 03:11:50 +02:00
James Cole
83090ade94 Generate app key [skip ci] 2017-04-27 03:06:39 +02:00
James Cole
44b7a42d5a Experimental deploy button script [skip ci] 2017-04-27 03:03:31 +02:00
James Cole
1a5617d430 Fixes a bug in the new user handler [skip ci] 2017-04-27 02:56:57 +02:00
James Cole
fa818e0924 Configure nginx [skip ci] 2017-04-27 02:49:06 +02:00
James Cole
f87b531fe1 Configure nginx [skip ci] 2017-04-27 02:45:26 +02:00
James Cole
82fd0c4d37 Set default db driver to be pgsql. [skip ci] 2017-04-27 02:40:57 +02:00
James Cole
26ceb9e3be Include config for Heroku. [skip ci] 2017-04-27 02:39:48 +02:00
James Cole
743458b853 Include config for Heroku. [skip ci] 2017-04-27 02:38:29 +02:00
James Cole
920e5f6fbe Force seed. 2017-04-26 21:32:43 +02:00
James Cole
fc0dd22769 Deploy heroku database. [skip ci] 2017-04-26 21:31:46 +02:00
James Cole
c7c61ce280 Log to error log. 2017-04-26 21:26:44 +02:00
James Cole
5f5a603f71 Update example file and config file for Laravel thing. [skip ci] 2017-04-26 21:02:21 +02:00
James Cole
d611858883 Remove compile step [skip ci] 2017-04-26 20:59:34 +02:00
James Cole
dbc9ce76a0 Try herocu config [skip ci] 2017-04-26 20:57:50 +02:00
James Cole
62386e2e40 Procfile for Herocu deployment. [skip ci] 2017-04-26 20:51:06 +02:00
485 changed files with 14831 additions and 13027 deletions

View File

@@ -3,6 +3,7 @@ APP_DEBUG=true
APP_FORCE_SSL=false
APP_FORCE_ROOT=
APP_KEY=TestTestTestTestTestTestTestTest
APP_LOG=daily
APP_LOG_LEVEL=debug
APP_URL=http://localhost
@@ -25,7 +26,7 @@ REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_DRIVER=log
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_FROM=changeme@example.com

View File

@@ -4,20 +4,12 @@
## 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!
I am always interested in expanding Firefly III's many features. If you are requesting a new feature, please check out the list of [often requested features](https://firefly-iii.github.io/requested-features/).
## Pull requests
I can only accept pull requests against the `develop` branch, never the `master` branch.
When contributing to Firefly III, please first discuss the change you wish to make via issue, email, or any other method. 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.
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.

11
.github/SUPPORT.md vendored Normal file
View File

@@ -0,0 +1,11 @@
# Welcome to Firefly III on Github!
:+1::tada: Thank you for taking the time to contribute something to Firefly III!
## Bugs
First of all: thank you for reporting a bug instead of ditching the tool altogether. 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. Bugs have a lot of priority!
## Installation problems
Please 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! If not, open an issue and I will help where I can.

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ Homestead.json
Homestead.yaml
.env
public/google*.html
report.html

View File

@@ -16,14 +16,14 @@ install:
- php artisan optimize
- php artisan env
- cp .env.testing .env
- mv storage/database/databasecopy.sqlite storage/database/database.sqlite
- wget -q https://github.com/firefly-iii/test-data/raw/master/storage/database.sqlite -O storage/database/database.sqlite
- mkdir -p build/logs
script:
- phpunit -c phpunit.coverage.xml
- phpunit -c phpunit.xml
after_success:
- travis_retry php vendor/bin/coveralls -x storage/build/clover.xml
#after_success:
# - travis_retry php vendor/bin/coveralls -x storage/build/clover.xml
# safelist
branches:

View File

@@ -2,6 +2,105 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [4.6.3.1] - 2017-07-23
### Fixed
- Hotfix to close issue #715
## [4.6.3] - 2017-07-23
This will be the last release to support PHP 7.0.
### Added
- New guidelines and new introduction tour to aid new users.
- Rules can now be applied at will to transactions, not just rule groups.
### Changed
- Improved category overview.
- Improved budget overview.
- Improved budget report.
- Improved command line import responsiveness and speed.
- All code comparisons are now strict.
- Improve search page.
- Charts are easier to read thanks to @simonsmiley
- Fixed #708.
### Fixed
- Fixed bug where import would not respect default account. #694
- Fixed various broken paths
- Fixed several import inconsistencies.
- Various bug fixes.
### Security
- Initial release.
## [4.6.2] - 2017-07-08
### Added
- Links added to boxes, idea by @simonsmiley
### Fixed
- Various bugs in import routine
## [4.6.1] - 2017-07-02
### Fixed
- Fixed several small issues all around.
## [4.6.0] - 2017-06-28
### Changed
- Revamped import routine. Will be buggy.
### Fixed
- Issue #667, postgresql reported by @skibbipl.
- Issue #680 by @Xeli
- Fixed #660
- Fixes #672, reported by @dzaikos
- Translation error fixed by
- Fix a bug where the balance routine forgot to account for accounts without a currency preference.
- Various other bugfixes.
## [4.5.0] - 2017-06-07
### Added
- Better support for multi-currency transactions and display of transactions, accounts and everything. This requires a database overhaul (moving the currency information to specific transactions) so be careful when upgrading.
- Translations for Spanish and Slovenian.
- New interface for budget page, ~~stolen from~~ inspired by YNAB.
- Expanded Docker to work with postgresql as well, thanks to @kressh
### Fixed
- PostgreSQL support in database upgrade routine (#644, reported by @skibbipl)
- Frontpage budget chart was off, fix by @nhaarman
- Was not possible to remove opening balance.
## [4.4.3] - 2017-05-03
### Added
- Added support for Slovenian
- Removed support for Spanish. No translations whatsoever by the guy who requested it.
- Removed support for Russian. Same thing.
- Removed support for Croatian. Same thing.
- Removed support for Chinese Traditional, Hong Kong. Same thing.
### Changed
- The journal collector, an internal piece of code to collect transactions, now uses a slightly different method of collecting journals. This may cause problems.
### Fixed
- Issue #638 as reported by [worldworm](https://github.com/worldworm).
- Possible fix for #624
## [4.4.2] - 2017-04-27
### Fixed
- Fixed a bug where the opening balance could not be stored.
## [4.4.1] - 2017-04-27
### Added
- Support for deployment on Heroku
### Fixed
- Bug in new-user routine.
## [4.4.0] - 2017-04-23
### Added
- Firefly III can now handle foreign currencies better, including some code to get the exchange rate live from the web.

46
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at thegrumpydictator@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -11,13 +11,14 @@ RUN apt-get update -y && \
libtidy-dev \
libxml2-dev \
libsqlite3-dev \
libpq-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
RUN docker-php-ext-install -j$(nproc) curl gd intl json mcrypt readline tidy zip bcmath xml mbstring pdo_sqlite pdo_mysql bz2 pdo_pgsql
# 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

1
Procfile Normal file
View File

@@ -0,0 +1 @@
web: vendor/bin/heroku-php-nginx -C nginx_app.conf public/

View File

@@ -10,9 +10,11 @@
## Try it out!
Try out Firefly III on the [demo site](https://firefly-iii.nder.be/).
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/firefly-iii/firefly-iii/tree/master)
## Installation
Firefly III can be run on Heroku. Register for a free Heroku account and instantly run Firefly III on your very own cloud instance. There is also a [demo site](https://firefly-iii.nder.be) with an example financial administration already present.
## Getting started
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).
@@ -22,7 +24,7 @@ Personal financial management is pretty difficult, and everybody has their own a
Firefly works on the principle that if you know where you're money is going, you can stop it from going there.
#### Some advantages of using Firefly
### Some advantages of using Firefly
- 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!
@@ -31,6 +33,25 @@ Firefly works on the principle that if you know where you're money is going, you
Firefly is pretty awesome. [You can read more about Firefly III, and its features, on the Github Pages](https://firefly-iii.github.io/).
### Contributing
Please read [CONTRIBUTING.md](https://github.com/firefly-iii/firefly-iii/blob/master/.github/CONTRIBUTING.md) for details on contributing, and the process for submitting pull requests. Please check out the [code of conduct](https://github.com/firefly-iii/firefly-iii/blob/master/CODE_OF_CONDUCT.md) as well.
### Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions available, see [the tags](https://github.com/firefly-iii/firefly-iii/tags) on this repository.
### Authors
* James Cole
* Over time, [many people have contributed to Firefly III](https://github.com/firefly-iii/firefly-iii/graphs/contributors).
### License
This work [is licensed](https://github.com/firefly-iii/firefly-iii/blob/master/LICENSE) under a [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/).
### Other stuff
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).

59
app.json Normal file
View File

@@ -0,0 +1,59 @@
{
"name": "Firefly III",
"description": "A free and open source personal finances manager",
"repository": "https://github.com/firefly-iii/firefly-iii",
"logo": "https://raw.githubusercontent.com/firefly-iii/firefly-iii/master/public/mstile-150x150.png",
"keywords": [
"finance",
"finances",
"manager",
"management",
"euro",
"dollar",
"laravel",
"money",
"currency",
"financials",
"financial",
"budgets",
"administration",
"tool",
"tooling",
"help",
"helper",
"assistant",
"planning",
"organizing",
"bills",
"personal finance",
"budgets",
"budgeting",
"budgeting tool",
"budgeting application",
"transactions",
"self hosted",
"self-hosted",
"transfers",
"management"
],
"website": "https://firefly-iii.github.io/",
"addons": [
{
"plan": "heroku-postgresql"
}
],
"scripts": {
"postdeploy": "export APP_KEY=$(php artisan --no-ansi key:generate --show)"
},
"buildpacks": [
{
"url": "heroku/php"
}
],
"env": {
"APP_KEY": {
"description": "This key is used to encrypt your data.",
"value": "base64:If1gJN4pyycXTq+WS5TjneDympKuu+8SKvTl6RZnhJg="
}
}
}

View File

@@ -14,10 +14,14 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands;
use Artisan;
use FireflyIII\Import\Logging\CommandHandler;
use FireflyIII\Import\Routine\ImportRoutine;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Console\Command;
use Illuminate\Support\MessageBag;
use Log;
use Monolog\Formatter\LineFormatter;
/**
* Class CreateImport
@@ -51,6 +55,7 @@ class CreateImport extends Command
/**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength) // cannot be helped
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five exactly.
*/
public function handle()
{
@@ -73,30 +78,55 @@ class CreateImport extends Command
return;
}
$this->info(sprintf('Going to create a job to import file: %s', $file));
$this->info(sprintf('Using configuration file: %s', $configuration));
$this->info(sprintf('Import into user: #%d (%s)', $user->id, $user->email));
$this->info(sprintf('Type of import: %s', $type));
$this->line(sprintf('Going to create a job to import file: %s', $file));
$this->line(sprintf('Using configuration file: %s', $configuration));
$this->line(sprintf('Import into user: #%d (%s)', $user->id, $user->email));
$this->line(sprintf('Type of import: %s', $type));
/** @var ImportJobRepositoryInterface $jobRepository */
$jobRepository = app(ImportJobRepositoryInterface::class);
$jobRepository->setUser($user);
$job = $jobRepository->create($type);
$this->line(sprintf('Created job "%s"...', $job->key));
$this->line(sprintf('Created job "%s"', $job->key));
Artisan::call('firefly:encrypt-file', ['file' => $file, 'key' => $job->key]);
$this->line('Stored import data...');
$job->configuration = $configurationData;
$job->status = 'settings_complete';
$job->status = 'configured';
$job->save();
$this->line('Stored configuration...');
if ($this->option('start') === true) {
$this->line('The import will start in a moment. This process is not visible...');
Log::debug('Go for import!');
Artisan::call('firefly:start-import', ['key' => $job->key]);
$this->line('Done!');
// normally would refer to other firefly:start-import but that doesn't seem to work all to well...
$monolog = Log::getMonolog();
$handler = new CommandHandler($this);
$formatter = new LineFormatter(null, null, false, true);
$handler->setFormatter($formatter);
$monolog->pushHandler($handler);
// start the actual routine:
/** @var ImportRoutine $routine */
$routine = app(ImportRoutine::class);
$routine->setJob($job);
$routine->run();
// give feedback.
/** @var MessageBag $error */
foreach ($routine->errors as $index => $error) {
$this->error(sprintf('Error importing line #%d: %s', $index, $error));
}
$this->line(
sprintf('The import has finished. %d transactions have been imported out of %d records.', $routine->journals->count(), $routine->lines)
);
}
return;

View File

@@ -13,12 +13,11 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands;
use FireflyIII\Import\ImportProcedure;
use FireflyIII\Import\Logging\CommandHandler;
use FireflyIII\Import\Routine\ImportRoutine;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
use Log;
/**
@@ -75,15 +74,18 @@ class Import extends Command
$monolog = Log::getMonolog();
$handler = new CommandHandler($this);
$monolog->pushHandler($handler);
$importProcedure = new ImportProcedure;
$result = $importProcedure->runImport($job);
// display result to user:
$this->presentResults($result);
$this->line('The import has completed.');
/** @var ImportRoutine $routine */
$routine = app(ImportRoutine::class);
$routine->setJob($job);
$routine->run();
// get any errors from the importer:
$this->presentErrors($job);
/** @var MessageBag $error */
foreach ($routine->errors as $index => $error) {
$this->error(sprintf('Error importing line #%d: %s', $index, $error));
}
$this->line(sprintf('The import has finished. %d transactions have been imported out of %d records.', $routine->journals->count(), $routine->lines));
return;
}
@@ -96,12 +98,14 @@ class Import extends Command
private function isValid(ImportJob $job): bool
{
if (is_null($job)) {
Log::error('This job does not seem to exist.');
$this->error('This job does not seem to exist.');
return false;
}
if ($job->status != 'settings_complete') {
if ($job->status !== 'configured') {
Log::error(sprintf('This job is not ready to be imported (status is %s).', $job->status));
$this->error('This job is not ready to be imported.');
return false;
@@ -109,36 +113,4 @@ class Import extends Command
return true;
}
/**
* @param ImportJob $job
*/
private function presentErrors(ImportJob $job)
{
$extendedStatus = $job->extended_status;
if (isset($extendedStatus['errors']) && count($extendedStatus['errors']) > 0) {
$this->line(sprintf('The following %d error(s) occured during the import:', count($extendedStatus['errors'])));
foreach ($extendedStatus['errors'] as $error) {
$this->error($error);
}
}
}
/**
* @param Collection $result
*/
private function presentResults(Collection $result)
{
/**
* @var int $index
* @var TransactionJournal $journal
*/
foreach ($result as $index => $journal) {
if (!is_null($journal->id)) {
$this->line(sprintf('Line #%d has been imported as transaction #%d.', $index, $journal->id));
continue;
}
$this->error(sprintf('Could not store line #%d', $index));
}
}
}

View File

@@ -32,9 +32,11 @@ use Illuminate\Database\QueryException;
use Log;
use Preferences;
use Schema;
use Steam;
/**
* Class UpgradeDatabase
* @SuppressWarnings(PHPMD.CouplingBetweenObjects) // it just touches a lot of things.
*
* @package FireflyIII\Console\Commands
*/
@@ -72,11 +74,59 @@ class UpgradeDatabase extends Command
$this->repairPiggyBanks();
$this->updateAccountCurrencies();
$this->updateJournalCurrencies();
$this->currencyInfoToTransactions();
$this->verifyCurrencyInfo();
$this->info('Firefly III database is up to date.');
}
/**
* Moves the currency id info to the transaction instead of the journal.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // cannot be helped.
*/
private function currencyInfoToTransactions()
{
$count = 0;
$set = TransactionJournal::with('transactions')->get();
/** @var TransactionJournal $journal */
foreach ($set as $journal) {
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
if (is_null($transaction->transaction_currency_id)) {
$transaction->transaction_currency_id = $journal->transaction_currency_id;
$transaction->save();
$count++;
}
}
// read and use the foreign amounts when present.
if ($journal->hasMeta('foreign_amount')) {
$amount = Steam::positive($journal->getMeta('foreign_amount'));
// update both transactions:
foreach ($journal->transactions as $transaction) {
$transaction->foreign_amount = $amount;
if (bccomp($transaction->amount, '0') === -1) {
// update with negative amount:
$transaction->foreign_amount = bcmul($amount, '-1');
}
// set foreign currency id:
$transaction->foreign_currency_id = intval($journal->getMeta('foreign_currency_id'));
$transaction->save();
}
$journal->deleteMeta('foreign_amount');
$journal->deleteMeta('foreign_currency_id');
}
}
$this->line(sprintf('Updated currency information for %d transactions', $count));
}
/**
* Migrate budget repetitions to new format.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's 5.
*/
private function migrateRepetitions()
{
@@ -104,6 +154,8 @@ class UpgradeDatabase extends Command
/**
* Make sure there are only transfers linked to piggy bank events.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // cannot be helped.
*/
private function repairPiggyBanks()
{
@@ -111,6 +163,7 @@ class UpgradeDatabase extends Command
if (!Schema::hasTable('piggy_bank_events')) {
return;
}
$set = PiggyBankEvent::with(['PiggyBank', 'TransactionJournal', 'TransactionJournal.TransactionType'])->get();
/** @var PiggyBankEvent $event */
foreach ($set as $event) {
@@ -162,7 +215,7 @@ class UpgradeDatabase extends Command
}
/**
*
* Make sure all accounts have proper currency info.
*/
private function updateAccountCurrencies()
{
@@ -172,42 +225,38 @@ class UpgradeDatabase extends Command
/** @var Account $account */
foreach ($accounts as $account) {
// get users preference, fall back to system pref.
$defaultCurrencyCode = Preferences::getForUser($account->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
$accountCurrency = intval($account->getMeta('currency_id'));
$openingBalance = $account->getOpeningBalance();
$openingBalanceCurrency = intval($openingBalance->transaction_currency_id);
$defaultCurrencyCode = Preferences::getForUser($account->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
$accountCurrency = intval($account->getMeta('currency_id'));
$openingBalance = $account->getOpeningBalance();
$obCurrency = intval($openingBalance->transaction_currency_id);
// both 0? set to default currency:
if ($accountCurrency === 0 && $openingBalanceCurrency === 0) {
if ($accountCurrency === 0 && $obCurrency === 0) {
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $defaultCurrency->id]);
$this->line(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $defaultCurrencyCode));
continue;
}
// opening balance 0, account not zero? just continue:
if ($accountCurrency > 0 && $openingBalanceCurrency === 0) {
continue;
}
// account is set to 0, opening balance is not?
if ($accountCurrency === 0 && $openingBalanceCurrency > 0) {
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $openingBalanceCurrency]);
if ($accountCurrency === 0 && $obCurrency > 0) {
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $obCurrency]);
$this->line(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $defaultCurrencyCode));
continue;
}
// both are equal, just continue:
if ($accountCurrency === $openingBalanceCurrency) {
continue;
}
// do not match:
if ($accountCurrency !== $openingBalanceCurrency) {
if ($accountCurrency !== $obCurrency) {
// update opening balance:
$openingBalance->transaction_currency_id = $accountCurrency;
$openingBalance->save();
$this->line(sprintf('Account #%d ("%s") now has a correct currency for opening balance.', $account->id, $account->name));
continue;
}
// opening balance 0, account not zero? just continue:
// both are equal, just continue:
}
}
@@ -269,9 +318,11 @@ class UpgradeDatabase extends Command
$repository = app(CurrencyRepositoryInterface::class);
$notification = '%s #%d uses %s but should use %s. It has been updated. Please verify this in Firefly III.';
$transfer = 'Transfer #%d has been updated to use the correct currencies. Please verify this in Firefly III.';
$driver = DB::connection()->getDriverName();
$pgsql = ['pgsql', 'postgresql'];
foreach ($types as $type => $operator) {
$set = TransactionJournal
$query = TransactionJournal
::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')->leftJoin(
'transactions', function (JoinClause $join) use ($operator) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', $operator, '0');
@@ -280,9 +331,15 @@ class UpgradeDatabase extends Command
->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id')
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
->where('transaction_types.type', $type)
->where('account_meta.name', 'currency_id')
->where('transaction_journals.transaction_currency_id', '!=', DB::raw('account_meta.data'))
->get(['transaction_journals.*', 'account_meta.data as expected_currency_id', 'transactions.amount as transaction_amount']);
->where('account_meta.name', 'currency_id');
if (in_array($driver, $pgsql)) {
$query->where('transaction_journals.transaction_currency_id', '!=', DB::raw('cast(account_meta.data as int)'));
}
if (!in_array($driver, $pgsql)) {
$query->where('transaction_journals.transaction_currency_id', '!=', DB::raw('account_meta.data'));
}
$set = $query->get(['transaction_journals.*', 'account_meta.data as expected_currency_id', 'transactions.amount as transaction_amount']);
/** @var TransactionJournal $journal */
foreach ($set as $journal) {
$expectedCurrency = $repository->find(intval($journal->expected_currency_id));
@@ -334,4 +391,25 @@ class UpgradeDatabase extends Command
}
}
}
/**
*
*/
private function verifyCurrencyInfo()
{
$count = 0;
$transactions = Transaction::get();
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$currencyId = intval($transaction->transaction_currency_id);
$foreignId = intval($transaction->foreign_currency_id);
if ($currencyId === $foreignId) {
$transaction->foreign_currency_id = null;
$transaction->foreign_amount = null;
$transaction->save();
$count++;
}
}
$this->line(sprintf('Updated currency information for %d transactions', $count));
}
}

View File

@@ -50,10 +50,10 @@ class UpgradeFireflyInstructions extends Command
public function handle()
{
if ($this->argument('task') == 'update') {
if ($this->argument('task') === 'update') {
$this->updateInstructions();
}
if ($this->argument('task') == 'install') {
if ($this->argument('task') === 'install') {
$this->installInstructions();
}
}

View File

@@ -259,7 +259,7 @@ class VerifyDatabase extends Command
{
$plural = str_plural($name);
$class = sprintf('FireflyIII\Models\%s', ucfirst($name));
$field = $name == 'tag' ? 'tag' : 'name';
$field = $name === 'tag' ? 'tag' : 'name';
$set = $class::leftJoin($name . '_transaction_journal', $plural . '.id', '=', $name . '_transaction_journal.' . $name . '_id')
->leftJoin('users', $plural . '.user_id', '=', 'users.id')
->distinct()

View File

@@ -26,7 +26,9 @@ class StoredTransactionJournal extends Event
use SerializesModels;
/** @var TransactionJournal */
public $journal;
/** @var int */
public $piggyBankId;
/**

View File

@@ -26,6 +26,7 @@ class UpdatedTransactionJournal extends Event
use SerializesModels;
/** @var TransactionJournal */
public $journal;
/**

View File

@@ -303,7 +303,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')
->leftJoin('accounts AS opposing_accounts', 'opposing.account_id', '=', 'opposing_accounts.id')
->leftJoin('transaction_types', 'transaction_journals.transaction_type_id', 'transaction_types.id')
->leftJoin('transaction_currencies', 'transaction_journals.transaction_currency_id', '=', 'transaction_currencies.id')
->leftJoin('transaction_currencies', 'transactions.transaction_currency_id', '=', 'transaction_currencies.id')
->whereIn('transactions.account_id', $accountIds)
->where('transaction_journals.user_id', $this->job->user_id)
->where('transaction_journals.date', '>=', $this->start->format('Y-m-d'))
@@ -338,7 +338,7 @@ class JournalExportCollector extends BasicCollector implements CollectorInterfac
'transaction_journals.encrypted as journal_encrypted',
'transaction_journals.transaction_type_id',
'transaction_types.type as transaction_type',
'transaction_journals.transaction_currency_id',
'transactions.transaction_currency_id',
'transaction_currencies.code AS transaction_currency_code',
]

View File

@@ -88,7 +88,7 @@ final class Entry
$entry->budget_name = $object->budget_name ?? '';
// update description when transaction description is different:
if (!is_null($object->description) && $object->description != $entry->description) {
if (!is_null($object->description) && $object->description !== $entry->description) {
$entry->description = $entry->description . ' (' . $object->description . ')';
}

View File

@@ -110,9 +110,16 @@ class ChartJsGenerator implements GeneratorInterface
];
// sort by value, keep keys.
// different sort when values are positive and when they're negative.
asort($data);
$next = next($data);
if (!is_bool($next) && bccomp($next, '0') === 1) {
// next is positive, sort other way around.
arsort($data);
}
unset($next);
$index = 0;
$index = 0;
foreach ($data as $key => $value) {
// make larger than 0

View File

@@ -22,10 +22,15 @@ interface GeneratorInterface
{
/**
* Will generate a (ChartJS) compatible array from the given input. Expects this format:
* Will generate a Chart JS compatible array from the given input. Expects this format
*
* Will take labels for all from first set.
*
* 0: [
* 'label' => 'label of set',
* 'type' => bar or line, optional
* 'yAxisID' => ID of yAxis, optional, will not be included when unused.
* 'fill' => if to fill a line? optional, will not be included when unused.
* 'entries' =>
* [
* 'label-of-entry' => 'value'
@@ -33,12 +38,16 @@ interface GeneratorInterface
* ]
* 1: [
* 'label' => 'label of another set',
* 'type' => bar or line, optional
* 'yAxisID' => ID of yAxis, optional, will not be included when unused.
* 'fill' => if to fill a line? optional, will not be included when unused.
* 'entries' =>
* [
* 'label-of-entry' => 'value'
* ]
* ]
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five.
*
* @param array $data
*

View File

@@ -19,6 +19,7 @@ use FireflyIII\Generator\Report\ReportGeneratorInterface;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use Illuminate\Support\Collection;
use Steam;
@@ -147,6 +148,8 @@ class MonthReportGenerator implements ReportGeneratorInterface
*/
private function getAuditReport(Account $account, Carbon $date): array
{
/** @var CurrencyRepositoryInterface $currencyRepos */
$currencyRepos = app(CurrencyRepositoryInterface::class);
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
@@ -155,15 +158,21 @@ class MonthReportGenerator implements ReportGeneratorInterface
$journals = $journals->reverse();
$dayBeforeBalance = Steam::balance($account, $date);
$startBalance = $dayBeforeBalance;
$currency = $currencyRepos->find(intval($account->getMeta('currency_id')));
/** @var Transaction $journal */
foreach ($journals as $transaction) {
$transaction->before = $startBalance;
$transactionAmount = $transaction->transaction_amount;
$newBalance = bcadd($startBalance, $transactionAmount);
$transaction->after = $newBalance;
$startBalance = $newBalance;
if ($currency->id === $transaction->foreign_currency_id) {
$transactionAmount = $transaction->transaction_foreign_amount;
}
$newBalance = bcadd($startBalance, $transactionAmount);
$transaction->after = $newBalance;
$startBalance = $newBalance;
$transaction->currency = $currency;
}
/*

View File

@@ -18,6 +18,9 @@ use Carbon\Carbon;
use FireflyIII\Generator\Report\ReportGeneratorInterface;
use FireflyIII\Generator\Report\Support;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use Illuminate\Support\Collection;
@@ -156,11 +159,13 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
->setTypes([TransactionType::WITHDRAWAL])
->setBudgets($this->budgets)->withOpposingAccount()->disableFilter();
->setBudgets($this->budgets)->withOpposingAccount();
$collector->removeFilter(TransferFilter::class);
$collector->addFilter(OpposingAccountFilter::class);
$collector->addFilter(PositiveAmountFilter::class);
$accountIds = $this->accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$transactions = self::filterExpenses($transactions, $accountIds);
$this->expenses = $transactions;
return $transactions;

View File

@@ -18,6 +18,10 @@ use Carbon\Carbon;
use FireflyIII\Generator\Report\ReportGeneratorInterface;
use FireflyIII\Generator\Report\Support;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use Illuminate\Support\Collection;
@@ -166,11 +170,13 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setCategories($this->categories)->withOpposingAccount()->disableFilter();
->setCategories($this->categories)->withOpposingAccount();
$collector->removeFilter(TransferFilter::class);
$collector->addFilter(OpposingAccountFilter::class);
$collector->addFilter(PositiveAmountFilter::class);
$accountIds = $this->accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$transactions = self::filterExpenses($transactions, $accountIds);
$this->expenses = $transactions;
return $transactions;
@@ -190,9 +196,11 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->setCategories($this->categories)->withOpposingAccount();
$accountIds = $this->accounts->pluck('id')->toArray();
$collector->addFilter(OpposingAccountFilter::class);
$collector->addFilter(NegativeAmountFilter::class);
$transactions = $collector->getJournals();
$transactions = self::filterIncome($transactions, $accountIds);
$this->income = $transactions;
return $transactions;

View File

@@ -15,7 +15,6 @@ namespace FireflyIII\Generator\Report;
use FireflyIII\Models\Transaction;
use Illuminate\Support\Collection;
use Log;
/**
@@ -25,61 +24,6 @@ use Log;
*/
class Support
{
/**
* @param Collection $collection
* @param array $accounts
*
* @return Collection
*/
public static function filterExpenses(Collection $collection, array $accounts): Collection
{
return self::filterTransactions($collection, $accounts, 1);
}
/**
* @param Collection $collection
* @param array $accounts
*
* @return Collection
*/
public static function filterIncome(Collection $collection, array $accounts): Collection
{
return self::filterTransactions($collection, $accounts, -1);
}
/**
* @param Collection $collection
* @param array $accounts
* @param int $modifier
*
* @return Collection
*/
public static function filterTransactions(Collection $collection, array $accounts, int $modifier): Collection
{
$result = $collection->filter(
function (Transaction $transaction) use ($accounts, $modifier) {
$opposing = $transaction->opposing_account_id;
// remove internal transfer
if (in_array($opposing, $accounts)) {
Log::debug(sprintf('Filtered #%d because its opposite is in accounts.', $transaction->id));
return null;
}
// remove positive amount
if (bccomp($transaction->transaction_amount, '0') === $modifier) {
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
return null;
}
return $transaction;
}
);
return $result;
}
/**
* @return Collection
*/

View File

@@ -16,6 +16,10 @@ use Carbon\Carbon;
use FireflyIII\Generator\Report\ReportGeneratorInterface;
use FireflyIII\Generator\Report\Support;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
@@ -162,11 +166,14 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setTags($this->tags)->withOpposingAccount()->disableFilter();
->setTags($this->tags)->withOpposingAccount();
$collector->removeFilter(TransferFilter::class);
$collector->addFilter(OpposingAccountFilter::class);
$collector->addFilter(PositiveAmountFilter::class);
$transactions = $collector->getJournals();
$accountIds = $this->accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$transactions = self::filterExpenses($transactions, $accountIds);
$this->expenses = $transactions;
return $transactions;
@@ -186,9 +193,11 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->setTags($this->tags)->withOpposingAccount();
$accountIds = $this->accounts->pluck('id')->toArray();
$collector->addFilter(OpposingAccountFilter::class);
$collector->addFilter(NegativeAmountFilter::class);
$transactions = $collector->getJournals();
$transactions = self::filterIncome($transactions, $accountIds);
$this->income = $transactions;
return $transactions;

View File

@@ -14,76 +14,95 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\StoredTransactionJournal;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface as JRI;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface as PRI;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface as RGRI;
use FireflyIII\Rules\Processor;
use FireflyIII\Support\Events\BillScanner;
use Log;
/**
* @codeCoverageIgnore
*
* Class StoredJournalEventHandler
*
* @package FireflyIII\Handlers\Events
*/
class StoredJournalEventHandler
{
/** @var JRI */
public $journalRepository;
/** @var PRI */
public $repository;
/** @var RGRI */
public $ruleGroupRepository;
/**
* StoredJournalEventHandler constructor.
*
* @param PRI $repository
* @param JRI $journalRepository
* @param RGRI $ruleGroupRepository
*/
public function __construct(PRI $repository, JRI $journalRepository, RGRI $ruleGroupRepository)
{
$this->repository = $repository;
$this->journalRepository = $journalRepository;
$this->ruleGroupRepository = $ruleGroupRepository;
}
/**
* This method connects a new transfer to a piggy bank.
*
*
*
* @param StoredTransactionJournal $event
*
* @return bool
*/
public function connectToPiggyBank(StoredTransactionJournal $event): bool
{
/** @var TransactionJournal $journal */
$journal = $event->journal;
$piggyBankId = $event->piggyBankId;
Log::debug(sprintf('Trying to connect journal %d to piggy bank %d.', $journal->id, $piggyBankId));
$piggyBank = $this->repository->find($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) {
// is a transfer?
if (!$this->journalRepository->isTransfer($journal)) {
Log::info(sprintf('Will not connect %s #%d to a piggy bank.', $journal->transactionType->type, $journal->id));
return true;
}
/*
* Verify existence of piggy bank:
*/
if (!$this->verifyExistence($event)) {
Log::error(sprintf('No such piggy bank or no repetition on %s', $journal->date->format('Y-m-d')));
// piggy exists?
if (is_null($piggyBank->id)) {
Log::error(sprintf('There is no piggy bank with ID #%d', $piggyBankId));
return true;
}
/*
* 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);
// repetition exists?
$repetition = $this->repository->getRepetition($piggyBank, $journal->date);
if (is_null($repetition->id)) {
Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d')));
return true;
}
// get the amount
$amount = $this->repository->getExactAmount($piggyBank, $repetition, $journal);
if (bccomp($amount, '0') === 0) {
Log::debug('Amount is zero, will not create event.');
return true;
}
$repetition->currentamount = bcadd($repetition->currentamount, $amount);
$repetition->save();
// update amount
$this->repository->addAmountToRepetition($repetition, $amount);
$event = $this->repository->createEventWithJournal($piggyBank, $amount, $journal);
/** @var PiggyBankEvent $event */
$event = PiggyBankEvent::create(
['piggy_bank_id' => $piggyBank->id, 'transaction_journal_id' => $journal->id, 'date' => $journal->date, 'amount' => $amount]
);
Log::debug(sprintf('Created piggy bank event #%d', $event->id));
return true;
@@ -100,16 +119,11 @@ class StoredJournalEventHandler
{
// get all the user's rule groups, with the rules, order by 'order'.
$journal = $storedJournalEvent->journal;
$groups = $journal->user->ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get();
//
$groups = $this->ruleGroupRepository->getActiveGroups($journal->user);
/** @var RuleGroup $group */
foreach ($groups as $group) {
$rules = $group->rules()
->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id')
->where('rule_triggers.trigger_type', 'user_action')
->where('rule_triggers.trigger_value', 'store-journal')
->where('rules.active', 1)
->get(['rules.*']);
$rules = $this->ruleGroupRepository->getActiveStoreRules($group);
/** @var Rule $rule */
foreach ($rules as $rule) {
@@ -117,9 +131,8 @@ class StoredJournalEventHandler
$processor->handleTransactionJournal($journal);
if ($rule->stop_processing) {
return true;
break;
}
}
}
@@ -140,81 +153,4 @@ class StoredJournalEventHandler
return true;
}
/**
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's 6 but I can live with it.
* @param TransactionJournal $journal
* @param PiggyBank $piggyBank
* @param PiggyBankRepetition $repetition
*
* @return string
*/
private function getExactAmount(TransactionJournal $journal, PiggyBank $piggyBank, PiggyBankRepetition $repetition): string
{
$amount = $journal->amountPositive();
$sources = $journal->sourceAccountList()->pluck('id')->toArray();
$room = bcsub(strval($piggyBank->targetamount), strval($repetition->currentamount));
$compare = bcmul($repetition->currentamount, '-1');
Log::debug(sprintf('Will add/remove %f to piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name));
// if piggy account matches source account, the amount is positive
if (in_array($piggyBank->account_id, $sources)) {
$amount = bcmul($amount, '-1');
Log::debug(sprintf('Account #%d is the source, so will remove amount from piggy bank.', $piggyBank->account_id));
}
// if the amount is positive, make sure it fits in piggy bank:
if (bccomp($amount, '0') === 1 && bccomp($room, $amount) === -1) {
// amount is positive and $room is smaller than $amount
Log::debug(sprintf('Room in piggy bank for extra money is %f', $room));
Log::debug(sprintf('There is NO room to add %f to piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name));
Log::debug(sprintf('New amount is %f', $room));
return $room;
}
// amount is negative and $currentamount is smaller than $amount
if (bccomp($amount, '0') === -1 && bccomp($compare, $amount) === 1) {
Log::debug(sprintf('Max amount to remove is %f', $repetition->currentamount));
Log::debug(sprintf('Cannot remove %f from piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name));
Log::debug(sprintf('New amount is %f', $compare));
return $compare;
}
return $amount;
}
/**
* @param StoredTransactionJournal $event
*
* @return bool
*/
private function verifyExistence(StoredTransactionJournal $event): bool
{
/** @var TransactionJournal $journal */
$journal = $event->journal;
$piggyBankId = $event->piggyBankId;
/** @var PiggyBank $piggyBank */
$piggyBank = $journal->user->piggyBanks()->where('piggy_banks.id', $piggyBankId)->first(['piggy_banks.*']);
if (is_null($piggyBank)) {
Log::error('No such piggy bank!');
return false;
}
Log::debug(sprintf('Found piggy bank #%d: "%s"', $piggyBank->id, $piggyBank->name));
// update piggy bank rep for date of transaction journal.
$repetition = $piggyBank->piggyBankRepetitions()->relevantOnDate($journal->date)->first();
if (is_null($repetition)) {
Log::error(sprintf('No piggy bank repetition on %s!', $journal->date->format('Y-m-d')));
return false;
}
return true;
}
}

View File

@@ -17,16 +17,31 @@ namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\UpdatedTransactionJournal;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Rules\Processor;
use FireflyIII\Support\Events\BillScanner;
/**
* @codeCoverageIgnore
*
* Class UpdatedJournalEventHandler
*
* @package FireflyIII\Handlers\Events
*/
class UpdatedJournalEventHandler
{
/** @var RuleGroupRepositoryInterface */
public $repository;
/**
* StoredJournalEventHandler constructor.
*
* @param RuleGroupRepositoryInterface $ruleGroupRepository
*/
public function __construct(RuleGroupRepositoryInterface $ruleGroupRepository)
{
$this->repository = $ruleGroupRepository;
}
/**
* This method will check all the rules when a journal is updated.
@@ -39,16 +54,11 @@ class UpdatedJournalEventHandler
{
// get all the user's rule groups, with the rules, order by 'order'.
$journal = $updatedJournalEvent->journal;
$groups = $journal->user->ruleGroups()->where('rule_groups.active', 1)->orderBy('order', 'ASC')->get();
//
$groups = $this->repository->getActiveGroups($journal->user);
/** @var RuleGroup $group */
foreach ($groups as $group) {
$rules = $group->rules()
->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id')
->where('rule_triggers.trigger_type', 'user_action')
->where('rule_triggers.trigger_value', 'update-journal')
->where('rules.active', 1)
->get(['rules.*']);
$rules = $this->repository->getActiveUpdateRules($group);
/** @var Rule $rule */
foreach ($rules as $rule) {
$processor = Processor::make($rule);

View File

@@ -15,8 +15,9 @@ namespace FireflyIII\Handlers\Events;
use FireflyIII\Events\RegisteredUser;
use FireflyIII\Events\RequestedNewPassword;
use FireflyIII\Mail\RegisteredUser as RegisteredUserMail;
use FireflyIII\Mail\RequestedNewPassword as RequestedNewPasswordMail;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Mail\Message;
use Log;
use Mail;
use Swift_TransportException;
@@ -68,15 +69,14 @@ class UserEventHandler
// send email.
try {
Mail::send(
['emails.password-html', 'emails.password-text'], ['url' => $url, 'ip' => $ipAddress], function (Message $message) use ($email) {
$message->to($email, $email)->subject('Your password reset request');
}
);
Mail::to($email)->send(new RequestedNewPasswordMail($url, $ipAddress));
// @codeCoverageIgnoreStart
} catch (Swift_TransportException $e) {
Log::error($e->getMessage());
}
// @codeCoverageIgnoreEnd
return true;
}
@@ -93,23 +93,23 @@ class UserEventHandler
$sendMail = env('SEND_REGISTRATION_MAIL', true);
if (!$sendMail) {
return true;
return true; // @codeCoverageIgnore
}
// get the email address
$email = $event->user->email;
$address = route('index');
$uri = route('index');
$ipAddress = $event->ipAddress;
// send email.
try {
Mail::send(
['emails.registered-html', 'emails.registered-text'], ['address' => $address, 'ip' => $ipAddress], function (Message $message) use ($email) {
$message->to($email, $email)->subject('Welcome to Firefly III!');
}
);
Mail::to($email)->send(new RegisteredUserMail($uri, $ipAddress));
// @codeCoverageIgnoreStart
} catch (Swift_TransportException $e) {
Log::error($e->getMessage());
}
// @codeCoverageIgnoreEnd
return true;
}
}

View File

@@ -16,7 +16,9 @@ namespace FireflyIII\Helpers\Attachments;
use Crypt;
use FireflyIII\Models\Attachment;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
use Log;
use Storage;
use Symfony\Component\HttpFoundation\File\UploadedFile;
@@ -28,6 +30,8 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
class AttachmentHelper implements AttachmentHelperInterface
{
/** @var Collection */
public $attachments;
/** @var MessageBag */
public $errors;
/** @var MessageBag */
@@ -49,6 +53,7 @@ class AttachmentHelper implements AttachmentHelperInterface
$this->allowedMimes = (array)config('firefly.allowedMimes');
$this->errors = new MessageBag;
$this->messages = new MessageBag;
$this->attachments = new Collection;
$this->uploadDisk = Storage::disk('upload');
}
@@ -64,6 +69,14 @@ class AttachmentHelper implements AttachmentHelperInterface
return $path;
}
/**
* @return Collection
*/
public function getAttachments(): Collection
{
return $this->attachments;
}
/**
* @return MessageBag
*/
@@ -110,7 +123,7 @@ class AttachmentHelper implements AttachmentHelperInterface
$md5 = md5_file($file->getRealPath());
$name = $file->getClientOriginalName();
$class = get_class($model);
$count = auth()->user()->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
$count = $model->user->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
if ($count > 0) {
$msg = (string)trans('validation.file_already_attached', ['name' => $name]);
@@ -137,7 +150,7 @@ class AttachmentHelper implements AttachmentHelperInterface
}
$attachment = new Attachment; // create Attachment object.
$attachment->user()->associate(auth()->user());
$attachment->user()->associate($model->user);
$attachment->attachable()->associate($model);
$attachment->md5 = md5_file($file->getRealPath());
$attachment->filename = $file->getClientOriginalName();
@@ -145,17 +158,21 @@ class AttachmentHelper implements AttachmentHelperInterface
$attachment->size = $file->getSize();
$attachment->uploaded = 0;
$attachment->save();
Log::debug('Created attachment:', $attachment->toArray());
$fileObject = $file->openFile('r');
$fileObject->rewind();
$content = $fileObject->fread($file->getSize());
$encrypted = Crypt::encrypt($content);
Log::debug(sprintf('Full file length is %d and upload size is %d.', strlen($content), $file->getSize()));
Log::debug(sprintf('Encrypted content is %d', strlen($encrypted)));
// store it:
$this->uploadDisk->put($attachment->fileName(), $encrypted);
$attachment->uploaded = 1; // update attachment
$attachment->save();
$this->attachments->push($attachment);
$name = e($file->getClientOriginalName()); // add message:
$msg = (string)trans('validation.file_attached', ['name' => $name]);
@@ -188,6 +205,8 @@ class AttachmentHelper implements AttachmentHelperInterface
}
/**
* @codeCoverageIgnore
*
* @param UploadedFile $file
*
* @return bool
@@ -218,7 +237,7 @@ class AttachmentHelper implements AttachmentHelperInterface
return false;
}
if (!$this->validSize($file)) {
return false;
return false; // @codeCoverageIgnore
}
if ($this->hasFile($file, $model)) {
return false;

View File

@@ -15,6 +15,7 @@ namespace FireflyIII\Helpers\Attachments;
use FireflyIII\Models\Attachment;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
/**
@@ -32,6 +33,11 @@ interface AttachmentHelperInterface
*/
public function getAttachmentLocation(Attachment $attachment): string;
/**
* @return Collection
*/
public function getAttachments(): Collection;
/**
* @return MessageBag
*/

View File

@@ -12,8 +12,11 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Chart;
use Carbon\Carbon;
use FireflyIII\Generator\Report\Support;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
@@ -91,6 +94,7 @@ class MetaPieChart implements MetaPieChartInterface
if ($this->collectOtherObjects && $direction === 'expense') {
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setUser($this->user);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)->setTypes([TransactionType::WITHDRAWAL]);
$journals = $collector->getJournals();
$sum = strval($journals->sum('transaction_amount'));
@@ -102,6 +106,7 @@ class MetaPieChart implements MetaPieChartInterface
if ($this->collectOtherObjects && $direction === 'income') {
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setUser($this->user);
$collector->setAccounts($this->accounts)->setRange($this->start, $this->end)->setTypes([TransactionType::DEPOSIT]);
$journals = $collector->getJournals();
$sum = strval($journals->sum('transaction_amount'));
@@ -114,6 +119,8 @@ class MetaPieChart implements MetaPieChartInterface
}
/**
* @codeCoverageIgnore
*
* @param Collection $accounts
*
* @return MetaPieChartInterface
@@ -126,6 +133,8 @@ class MetaPieChart implements MetaPieChartInterface
}
/**
* @codeCoverageIgnore
*
* @param Collection $budgets
*
* @return MetaPieChartInterface
@@ -138,6 +147,8 @@ class MetaPieChart implements MetaPieChartInterface
}
/**
* @codeCoverageIgnore
*
* @param Collection $categories
*
* @return MetaPieChartInterface
@@ -150,6 +161,8 @@ class MetaPieChart implements MetaPieChartInterface
}
/**
* @codeCoverageIgnore
*
* @param bool $collectOtherObjects
*
* @return MetaPieChartInterface
@@ -162,6 +175,8 @@ class MetaPieChart implements MetaPieChartInterface
}
/**
* @codeCoverageIgnore
*
* @param Carbon $end
*
* @return MetaPieChartInterface
@@ -174,6 +189,8 @@ class MetaPieChart implements MetaPieChartInterface
}
/**
* @codeCoverageIgnore
*
* @param Carbon $start
*
* @return MetaPieChartInterface
@@ -186,6 +203,8 @@ class MetaPieChart implements MetaPieChartInterface
}
/**
* @codeCoverageIgnore
*
* @param Collection $tags
*
* @return MetaPieChartInterface
@@ -198,6 +217,8 @@ class MetaPieChart implements MetaPieChartInterface
}
/**
* @codeCoverageIgnore
*
* @param User $user
*
* @return MetaPieChartInterface
@@ -209,23 +230,32 @@ class MetaPieChart implements MetaPieChartInterface
return $this;
}
protected function getTransactions(string $direction)
/**
* @param string $direction
*
* @return Collection
*/
protected function getTransactions(string $direction): Collection
{
$types = [TransactionType::DEPOSIT, TransactionType::TRANSFER];
$modifier = -1;
if ($direction === 'expense') {
$types = [TransactionType::WITHDRAWAL, TransactionType::TRANSFER];
$modifier = 1;
}
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$types = [TransactionType::DEPOSIT, TransactionType::TRANSFER];
$collector->addFilter(NegativeAmountFilter::class);
if ($direction === 'expense') {
$types = [TransactionType::WITHDRAWAL, TransactionType::TRANSFER];
$collector->addFilter(PositiveAmountFilter::class);
$collector->removeFilter(NegativeAmountFilter::class);
}
$collector->setUser($this->user);
$collector->setAccounts($this->accounts);
$collector->setRange($this->start, $this->end);
$collector->setTypes($types);
$collector->withOpposingAccount();
$collector->addFilter(OpposingAccountFilter::class);
if ($direction === 'income') {
$collector->disableFilter();
$collector->removeFilter(TransferFilter::class);
}
if ($this->budgets->count() > 0) {
@@ -240,11 +270,7 @@ class MetaPieChart implements MetaPieChartInterface
$collector->withBudgetInformation();
}
$accountIds = $this->accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$set = Support::filterTransactions($transactions, $accountIds, $modifier);
return $set;
return $collector->getJournals();
}
/**
@@ -286,6 +312,7 @@ class MetaPieChart implements MetaPieChartInterface
$chartData = [];
$names = [];
$repository = app($this->repositories[$type]);
$repository->setUser($this->user);
foreach ($array as $objectId => $amount) {
if (!isset($names[$objectId])) {
$object = $repository->find(intval($objectId));
@@ -300,6 +327,11 @@ class MetaPieChart implements MetaPieChartInterface
}
/**
* @param Collection $set
*
* @return array
*/
private function groupByTag(Collection $set): array
{
$grouped = [];

View File

@@ -147,13 +147,13 @@ class BalanceLine
if ($this->getBudget() instanceof BudgetModel && !is_null($this->getBudget()->id)) {
return $this->getBudget()->name;
}
if ($this->getRole() == self::ROLE_DEFAULTROLE) {
if ($this->getRole() === self::ROLE_DEFAULTROLE) {
return strval(trans('firefly.no_budget'));
}
if ($this->getRole() == self::ROLE_TAGROLE) {
if ($this->getRole() === self::ROLE_TAGROLE) {
return strval(trans('firefly.coveredWithTags'));
}
if ($this->getRole() == self::ROLE_DIFFROLE) {
if ($this->getRole() === self::ROLE_DIFFROLE) {
return strval(trans('firefly.leftUnbalanced'));
}

View File

@@ -96,7 +96,7 @@ class Bill
{
$set = $this->bills->sortBy(
function (BillLine $bill) {
$active = intval($bill->getBill()->active) == 0 ? 1 : 0;
$active = intval($bill->getBill()->active) === 0 ? 1 : 0;
$name = $bill->getBill()->name;
return $active . $name;

View File

@@ -18,12 +18,17 @@ use Carbon\Carbon;
use Crypt;
use DB;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Filter\FilterInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\Encryption\DecryptException;
@@ -55,25 +60,39 @@ class JournalCollector implements JournalCollectorInterface
'transaction_journals.description',
'transaction_journals.date',
'transaction_journals.encrypted',
'transaction_currencies.code as transaction_currency_code',
'transaction_types.type as transaction_type_type',
'transaction_journals.bill_id',
'bills.name as bill_name',
'bills.name_encrypted as bill_name_encrypted',
'transactions.id as id',
'transactions.amount as transaction_amount',
'transactions.description as transaction_description',
'transactions.account_id',
'transactions.identifier',
'transactions.transaction_journal_id',
'transactions.amount as transaction_amount',
'transactions.transaction_currency_id as transaction_currency_id',
'transaction_currencies.code as transaction_currency_code',
'transaction_currencies.symbol as transaction_currency_symbol',
'transaction_currencies.decimal_places as transaction_currency_dp',
'transactions.foreign_amount as transaction_foreign_amount',
'transactions.foreign_currency_id as foreign_currency_id',
'foreign_currencies.code as foreign_currency_code',
'foreign_currencies.symbol as foreign_currency_symbol',
'foreign_currencies.decimal_places as foreign_currency_dp',
'accounts.name as account_name',
'accounts.encrypted as account_encrypted',
'account_types.type as account_type',
];
/** @var bool */
private $filterInternalTransfers;
/** @var bool */
private $filterTransfers = false;
/** @var array */
private $filters = [InternalTransferFilter::class];
/** @var bool */
private $joinedBudget = false;
/** @var bool */
@@ -95,6 +114,22 @@ class JournalCollector implements JournalCollectorInterface
/** @var User */
private $user;
/**
* @param string $filter
*
* @return JournalCollectorInterface
*/
public function addFilter(string $filter): JournalCollectorInterface
{
$interfaces = class_implements($filter);
if (in_array(FilterInterface::class, $interfaces)) {
Log::debug(sprintf('Enabled filter %s', $filter));
$this->filters[] = $filter;
}
return $this;
}
/**
* @return int
* @throws FireflyException
@@ -119,36 +154,6 @@ class JournalCollector implements JournalCollectorInterface
return $this->count;
}
/**
* @return JournalCollectorInterface
*/
public function disableFilter(): JournalCollectorInterface
{
$this->filterTransfers = false;
return $this;
}
/**
* @return JournalCollectorInterface
*/
public function disableInternalFilter(): JournalCollectorInterface
{
$this->filterInternalTransfers = false;
return $this;
}
/**
* @return JournalCollectorInterface
*/
public function enableInternalFilter(): JournalCollectorInterface
{
$this->filterInternalTransfers = true;
return $this;
}
/**
* @return Collection
*/
@@ -157,14 +162,9 @@ class JournalCollector implements JournalCollectorInterface
$this->run = true;
/** @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()));
// possibly filter "internal" transfers:
$set = $this->filterInternalTransfers($set);
Log::debug(sprintf('Count of set after filterInternalTransfers() is %d', $set->count()));
// run all filters:
$set = $this->filter($set);
// loop for decryption.
$set->each(
@@ -204,6 +204,22 @@ class JournalCollector implements JournalCollectorInterface
return $journals;
}
/**
* @param string $filter
*
* @return JournalCollectorInterface
*/
public function removeFilter(string $filter): JournalCollectorInterface
{
$key = array_search($filter, $this->filters, true);
if (!($key === false)) {
Log::debug(sprintf('Removed filter %s', $filter));
unset($this->filters[$key]);
}
return $this;
}
/**
* @param Collection $accounts
*
@@ -219,6 +235,7 @@ class JournalCollector implements JournalCollectorInterface
}
if ($accounts->count() > 1) {
$this->addFilter(TransferFilter::class);
$this->filterTransfers = true;
}
@@ -242,6 +259,7 @@ class JournalCollector implements JournalCollectorInterface
}
if ($accounts->count() > 1) {
$this->addFilter(TransferFilter::class);
$this->filterTransfers = true;
}
@@ -464,7 +482,9 @@ class JournalCollector implements JournalCollectorInterface
*/
public function setUser(User $user)
{
Log::debug(sprintf('Journal collector now collecting for user #%d', $user->id));
$this->user = $user;
$this->startQuery();
}
/**
@@ -472,19 +492,22 @@ class JournalCollector implements JournalCollectorInterface
*/
public function startQuery()
{
Log::debug('journalCollector::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')
->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transactions.transaction_currency_id')
->leftJoin('transaction_currencies as foreign_currencies', 'foreign_currencies.id', 'transactions.foreign_currency_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');
->orderBy('transaction_journals.id', 'DESC')
->orderBy('transaction_journals.description', 'DESC');
$this->query = $query;
@@ -560,79 +583,23 @@ class JournalCollector implements JournalCollectorInterface
*
* @return Collection
*/
private function filterInternalTransfers(Collection $set): Collection
private function filter(Collection $set): Collection
{
if ($this->filterInternalTransfers === false) {
Log::debug('Did NO filtering for internal transfers on given set.');
return $set;
}
if ($this->joinedOpposing === false) {
Log::info('Cannot filter internal transfers because no opposing information is present.');
return $set;
}
$accountIds = $this->accountIds;
$set = $set->filter(
function (Transaction $transaction) use ($accountIds) {
// both id's in $accountids?
if (in_array($transaction->account_id, $accountIds) && in_array($transaction->opposing_account_id, $accountIds)) {
Log::debug(
sprintf(
'Transaction #%d has #%d and #%d in set, so removed',
$transaction->id, $transaction->account_id, $transaction->opposing_account_id
), $accountIds
);
return false;
}
return $transaction;
// create all possible filters:
$filters = [
InternalTransferFilter::class => new InternalTransferFilter($this->accountIds),
OpposingAccountFilter::class => new OpposingAccountFilter($this->accountIds),
TransferFilter::class => new TransferFilter,
PositiveAmountFilter::class => new PositiveAmountFilter,
NegativeAmountFilter::class => new NegativeAmountFilter,
];
Log::debug(sprintf('Will run %d filters on the set.', count($this->filters)));
foreach ($this->filters as $enabled) {
if (isset($filters[$enabled])) {
Log::debug(sprintf('Before filter %s: %d', $enabled, $set->count()));
$set = $filters[$enabled]->filter($set);
Log::debug(sprintf('After filter %s: %d', $enabled, $set->count()));
}
);
return $set;
}
/**
* If the set of accounts used by the collector includes more than one asset
* 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 by removing transfers that have been selected twice.
*
* @param Collection $set
*
* @return Collection
*/
private function filterTransfers(Collection $set): Collection
{
if ($this->filterTransfers) {
$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;

View File

@@ -28,26 +28,18 @@ use Illuminate\Support\Collection;
*/
interface JournalCollectorInterface
{
/**
* @param string $filter
*
* @return JournalCollectorInterface
*/
public function addFilter(string $filter): JournalCollectorInterface;
/**
* @return int
*/
public function count(): int;
/**
* @return JournalCollectorInterface
*/
public function disableFilter(): JournalCollectorInterface;
/**
* @return JournalCollectorInterface
*/
public function disableInternalFilter(): JournalCollectorInterface;
/**
* @return JournalCollectorInterface
*/
public function enableInternalFilter(): JournalCollectorInterface;
/**
* @return Collection
*/
@@ -58,6 +50,13 @@ interface JournalCollectorInterface
*/
public function getPaginatedJournals(): LengthAwarePaginator;
/**
* @param string $filter
*
* @return JournalCollectorInterface
*/
public function removeFilter(string $filter): JournalCollectorInterface;
/**
* @param Collection $accounts
*

View File

@@ -0,0 +1,56 @@
<?php
/**
* AmountFilter.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\Filter;
use FireflyIII\Models\Transaction;
use Illuminate\Support\Collection;
use Log;
/**
* Class AmountFilter
*
* This filter removes transactions with either a positive amount ($parameters = 1) or a negative amount
* ($parameter = -1). This is helpful when a Collection has you with both transactions in a journal.
*
* @package FireflyIII\Helpers\Filter
*/
class AmountFilter implements FilterInterface
{
/** @var int */
private $modifier = 0;
public function __construct(int $modifier)
{
$this->modifier = $modifier;
}
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
return $set->filter(
function (Transaction $transaction) {
// remove by amount
if (bccomp($transaction->transaction_amount, '0') === $this->modifier) {
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
return null;
}
return $transaction;
}
);
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* EmptyFilter.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\Filter;
use Illuminate\Support\Collection;
/**
* Class EmptyFilter
*
* @package FireflyIII\Helpers\Filter
*/
class EmptyFilter implements FilterInterface
{
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
return $set;
}
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* FilterInterface.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\Filter;
use Illuminate\Support\Collection;
interface FilterInterface
{
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection;
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* InternalTransferFilter.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\Filter;
use FireflyIII\Models\Transaction;
use Illuminate\Support\Collection;
use Log;
/**
* Class InternalTransferFilter
*
* This filter removes any filters that are from A to B or from B to A given a set of
* account id's (in $parameters) where A and B are mentioned. So transfers between the mentioned
* accounts will be removed.
*
* @package FireflyIII\Helpers\Filter
*/
class InternalTransferFilter implements FilterInterface
{
/** @var array */
private $accounts = [];
/**
* InternalTransferFilter constructor.
*
* @param array $accounts
*/
public function __construct(array $accounts)
{
$this->accounts = $accounts;
}
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
return $set->filter(
function (Transaction $transaction) {
if (is_null($transaction->opposing_account_id)) {
return $transaction;
}
// both id's in $parameters?
if (in_array($transaction->account_id, $this->accounts) && in_array($transaction->opposing_account_id, $this->accounts)) {
Log::debug(
sprintf(
'Transaction #%d has #%d and #%d in set, so removed',
$transaction->id, $transaction->account_id, $transaction->opposing_account_id
), $this->accounts
);
return false;
}
return $transaction;
}
);
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* NegativeAmountFilter.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\Filter;
use FireflyIII\Models\Transaction;
use Illuminate\Support\Collection;
use Log;
/**
* Class NegativeAmountFilter
*
* This filter removes entries with a negative amount (the original modifier is -1).
*
* @package FireflyIII\Helpers\Filter
*/
class NegativeAmountFilter implements FilterInterface
{
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
return $set->filter(
function (Transaction $transaction) {
// remove by amount
if (bccomp($transaction->transaction_amount, '0') === -1) {
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
return null;
}
return $transaction;
}
);
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* OpposingAccountFilter.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\Filter;
use FireflyIII\Models\Transaction;
use Illuminate\Support\Collection;
use Log;
/**
* Class OpposingAccountFilter
*
* This filter is similar to the internal transfer filter but only removes transactions when the opposing account is
* amongst $parameters (list of account ID's).
*
* @package FireflyIII\Helpers\Filter
*/
class OpposingAccountFilter implements FilterInterface
{
/** @var array */
private $accounts = [];
/**
* InternalTransferFilter constructor.
*
* @param array $accounts
*/
public function __construct(array $accounts)
{
$this->accounts = $accounts;
}
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
return $set->filter(
function (Transaction $transaction) {
$opposing = $transaction->opposing_account_id;
// remove internal transfer
if (in_array($opposing, $this->accounts)) {
Log::debug(sprintf('Filtered #%d because its opposite is in accounts.', $transaction->id), $this->accounts);
return null;
}
return $transaction;
}
);
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* PositiveAmountFilter.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\Filter;
use FireflyIII\Models\Transaction;
use Illuminate\Support\Collection;
use Log;
/**
* Class PositiveAmountFilter
*
* This filter removes entries with a negative amount (the original modifier is -1).
*
* This filter removes transactions with either a positive amount ($parameters = 1) or a negative amount
* ($parameter = -1). This is helpful when a Collection has you with both transactions in a journal.
*
* @package FireflyIII\Helpers\Filter
*/
class PositiveAmountFilter implements FilterInterface
{
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
return $set->filter(
function (Transaction $transaction) {
// remove by amount
if (bccomp($transaction->transaction_amount, '0') === 1) {
Log::debug(sprintf('Filtered #%d because amount is %f.', $transaction->id, $transaction->transaction_amount));
return null;
}
return $transaction;
}
);
}
}

View File

@@ -0,0 +1,58 @@
<?php
/**
* TransferFilter.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\Filter;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use Illuminate\Support\Collection;
use Steam;
/**
* Class TransferFilter
*
* This filter removes any transfers that are in the collection twice (from A to B and from B to A).
*
* @package FireflyIII\Helpers\Filter
*/
class TransferFilter implements FilterInterface
{
/**
* @param Collection $set
*
* @return Collection
*/
public function filter(Collection $set): Collection
{
$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;
if (!isset($count[$key])) {
// not yet counted? add to new set and count it:
$new->push($transaction);
$count[$key] = 1;
}
}
return $new;
}
}

View File

@@ -27,6 +27,7 @@ use Route;
*/
class Help implements HelpInterface
{
const CACHEKEY = 'help_%s_%s';
/** @var string */
protected $userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36';
@@ -38,7 +39,7 @@ class Help implements HelpInterface
*/
public function getFromCache(string $route, string $language): string
{
$line = sprintf('help.%s.%s', $route, $language);
$line = sprintf(self::CACHEKEY, $route, $language);
return Cache::get($line);
}
@@ -64,12 +65,12 @@ class Help implements HelpInterface
return '';
}
Log::debug(sprintf('Status code is %d', $result->status_code));
if ($result->status_code === 200) {
$content = trim($result->body);
}
if (strlen($content) > 0) {
Log::debug('Content is longer than zero. Expect something.');
$converter = new CommonMarkConverter();
@@ -98,7 +99,7 @@ class Help implements HelpInterface
*/
public function inCache(string $route, string $language): bool
{
$line = sprintf('help.%s.%s', $route, $language);
$line = sprintf(self::CACHEKEY, $route, $language);
$result = Cache::has($line);
if ($result) {
Log::debug(sprintf('Cache has this entry: %s', 'help.' . $route . '.' . $language));
@@ -120,7 +121,7 @@ class Help implements HelpInterface
*/
public function putInCache(string $route, string $language, string $content)
{
$key = sprintf('help.%s.%s', $route, $language);
$key = sprintf(self::CACHEKEY, $route, $language);
if (strlen($content) > 0) {
Log::debug(sprintf('Will store entry in cache: %s', $key));
Cache::put($key, $content, 10080); // a week.

View File

@@ -244,7 +244,7 @@ class BalanceReportHelper implements BalanceReportHelperInterface
foreach ($accounts as $account) {
$leftEntry = $tagsLeft->filter(
function (Tag $tag) use ($account) {
return $tag->account_id == $account->id;
return $tag->account_id === $account->id;
}
);
$left = '0';

View File

@@ -56,7 +56,7 @@ class BudgetReportHelper implements BudgetReportHelperInterface
/** @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
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 (bccomp($spent, '0') === -1) {

View File

@@ -187,7 +187,7 @@ class PopupReport implements PopupReportInterface
$journals = $journals->filter(
function (Transaction $transaction) use ($report) {
// get the destinations:
$destinations = $transaction->destinationAccountList($transaction->transactionJournal)->pluck('id')->toArray();
$destinations = $transaction->transactionJournal->destinationAccountList()->pluck('id')->toArray();
// do these intersect with the current list?
return !empty(array_intersect($report, $destinations));
@@ -196,4 +196,4 @@ class PopupReport implements PopupReportInterface
return $journals;
}
}
}

View File

@@ -80,4 +80,4 @@ interface PopupReportInterface
* @return Collection
*/
public function byIncome(Account $account, array $attributes): Collection;
}
}

View File

@@ -194,7 +194,7 @@ class AccountController extends Controller
return view(
'accounts.edit', compact(
'allCurrencies', 'currencySelectList', 'account', 'currency', 'subTitle', 'subTitleIcon', 'openingBalance', 'what', 'roles'
'allCurrencies', 'currencySelectList', 'account', 'currency', 'subTitle', 'subTitleIcon', 'what', 'roles'
)
);
}
@@ -219,8 +219,8 @@ class AccountController extends Controller
$start->subDay();
$ids = $accounts->pluck('id')->toArray();
$startBalances = Steam::balancesById($ids, $start);
$endBalances = Steam::balancesById($ids, $end);
$startBalances = Steam::balancesByAccounts($accounts, $start);
$endBalances = Steam::balancesByAccounts($accounts, $end);
$activities = Steam::getLastActivities($ids);
$accounts->each(
@@ -293,8 +293,8 @@ class AccountController extends Controller
$periods = $this->getPeriodOverview($account);
}
$count = 0;
$loop = 0;
$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) {
@@ -308,7 +308,7 @@ class AccountController extends Controller
$journals = $collector->getPaginatedJournals();
$journals->setPath('accounts/show/' . $account->id . '/' . $moment);
$count = $journals->getCollection()->count();
if ($count === 0) {
if ($count === 0 && $loop < 3) {
$start->subDay();
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfPeriod($start, $range);
@@ -316,7 +316,7 @@ class AccountController extends Controller
}
}
if ($moment != 'all' && $loop > 1) {
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)]

View File

@@ -98,10 +98,13 @@ class AttachmentController extends Controller
*/
public function download(AttachmentRepositoryInterface $repository, Attachment $attachment)
{
if ($repository->exists($attachment)) {
$content = $repository->getContent($attachment);
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
/** @var LaravelResponse $response */
$response = response($content, 200);
$response
@@ -149,7 +152,8 @@ class AttachmentController extends Controller
{
$image = 'images/page_green.png';
if ($attachment->mime == 'application/pdf') {
if ($attachment->mime === 'application/pdf') {
$image = 'images/page_white_acrobat.png';
}
$file = public_path($image);

View File

@@ -175,7 +175,7 @@ class BillController extends Controller
*/
public function rescan(Request $request, BillRepositoryInterface $repository, Bill $bill)
{
if (intval($bill->active) == 0) {
if (intval($bill->active) === 0) {
$request->session()->flash('warning', strval(trans('firefly.cannot_scan_inactive_bill')));
return redirect(URL::previous());
@@ -206,7 +206,7 @@ class BillController extends Controller
/** @var Carbon $date */
$date = session('start');
$year = $date->year;
$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);
$yearAverage = $repository->getYearAverage($bill, $date);
$overallAverage = $repository->getOverallAverage($bill);

View File

@@ -15,6 +15,7 @@ namespace FireflyIII\Http\Controllers;
use Amount;
use Carbon\Carbon;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Http\Requests\BudgetFormRequest;
@@ -80,7 +81,7 @@ class BudgetController extends Controller
/** @var Carbon $end */
$end = session('end', Carbon::now()->endOfMonth());
$budgetLimit = $this->repository->updateLimitAmount($budget, $start, $end, $amount);
if ($amount == 0) {
if ($amount === 0) {
$budgetLimit = null;
}
Preferences::mark();
@@ -166,16 +167,38 @@ class BudgetController extends Controller
}
/**
* @param string|null $moment
*
* @return View
*/
public function index()
public function index(string $moment = null)
{
$range = Preferences::get('viewRange', '1M')->data;
$start = session('start', new Carbon);
$end = session('end', new Carbon);
// make date if present:
if (!is_null($moment) || strlen(strval($moment)) !== 0) {
try {
$start = new Carbon($moment);
$end = Navigation::endOfPeriod($start, $range);
} catch (Exception $e) {
// start and end are already defined.
}
}
$next = clone $end;
$next->addDay();
$prev = clone $start;
$prev->subDay();
$prev = Navigation::startOfPeriod($prev, $range);
$this->repository->cleanupBudgets();
$budgets = $this->repository->getActiveBudgets();
$inactive = $this->repository->getInactiveBudgets();
$start = session('start', new Carbon);
$end = session('end', new Carbon);
$periodStart = $start->formatLocalized($this->monthAndDayFormat);
$periodEnd = $end->formatLocalized($this->monthAndDayFormat);
$budgetInformation = $this->collectBudgetInformation($budgets, $start, $end);
@@ -184,9 +207,44 @@ class BudgetController extends Controller
$spent = array_sum(array_column($budgetInformation, 'spent'));
$budgeted = array_sum(array_column($budgetInformation, 'budgeted'));
// select thing for last 12 periods:
$previousLoop = [];
$previousDate = clone $start;
$count = 0;
while ($count < 12) {
$previousDate->subDay();
$previousDate = Navigation::startOfPeriod($previousDate, $range);
$format = $previousDate->format('Y-m-d');
$previousLoop[$format] = Navigation::periodShow($previousDate, $range);
$count++;
}
// select thing for next 12 periods:
$nextLoop = [];
$nextDate = clone $end;
$nextDate->addDay();
$count = 0;
while ($count < 12) {
$format = $nextDate->format('Y-m-d');
$nextLoop[$format] = Navigation::periodShow($nextDate, $range);
$nextDate = Navigation::endOfPeriod($nextDate, $range);
$count++;
$nextDate->addDay();
}
// display info
$currentMonth = Navigation::periodShow($start, $range);
$nextText = Navigation::periodShow($next, $range);
$prevText = Navigation::periodShow($prev, $range);
return view(
'budgets.index',
compact('available', 'periodStart', 'periodEnd', 'budgetInformation', 'inactive', 'budgets', 'spent', 'budgeted')
compact(
'available', 'currentMonth', 'next', 'nextText', 'prev', 'prevText',
'periodStart', 'periodEnd', 'budgetInformation', 'inactive', 'budgets',
'spent', 'budgeted', 'previousLoop', 'nextLoop', 'start'
)
);
}
@@ -235,7 +293,7 @@ class BudgetController extends Controller
);
}
$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);
$count = 0;
@@ -244,7 +302,7 @@ class BudgetController extends Controller
Log::info('Now at no-budget loop start.');
while ($count === 0 && $loop < 3) {
$loop++;
Log::info('Count is zero, search for journals.');
Log::info(sprintf('Count is zero, search for journals between %s and %s.', $start->format('Y-m-d'), $end->format('Y-m-d')));
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setLimit($pageSize)->setPage($page)
@@ -252,7 +310,7 @@ class BudgetController extends Controller
$journals = $collector->getPaginatedJournals();
$journals->setPath('/budgets/list/no-budget');
$count = $journals->getCollection()->count();
if ($count === 0) {
if ($count === 0 && $loop < 3) {
$start->subDay();
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfPeriod($start, $range);
@@ -260,7 +318,7 @@ class BudgetController extends Controller
}
}
if ($moment != 'all' && $loop > 1) {
if ($moment !== 'all' && $loop > 1) {
$subTitle = trans(
'firefly.without_budget_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
@@ -299,7 +357,7 @@ class BudgetController extends Controller
/** @var Carbon $start */
$start = session('first', Carbon::create()->startOfYear());
$end = new Carbon;
$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);
$limits = $this->getLimits($budget, $start, $end);
$repetition = null;
@@ -326,11 +384,11 @@ class BudgetController extends Controller
*/
public function showByBudgetLimit(Request $request, Budget $budget, BudgetLimit $budgetLimit)
{
if ($budgetLimit->budget->id != $budget->id) {
if ($budgetLimit->budget->id !== $budget->id) {
throw new FireflyException('This budget limit is not part of this budget.');
}
$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);
$subTitle = trans(
'firefly.budget_in_period', [

View File

@@ -15,6 +15,7 @@ namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Http\Requests\CategoryFormRequest;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Category;
@@ -198,7 +199,7 @@ class CategoryController extends Controller
);
}
$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);
$count = 0;
@@ -211,11 +212,11 @@ class CategoryController extends Controller
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withoutCategory()->withOpposingAccount();
$collector->disableInternalFilter();
$collector->removeFilter(InternalTransferFilter::class);
$journals = $collector->getPaginatedJournals();
$journals->setPath('/categories/list/no-category');
$count = $journals->getCollection()->count();
if ($count === 0) {
if ($count === 0 && $loop < 3) {
$start->subDay();
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfPeriod($start, $range);
@@ -223,7 +224,7 @@ class CategoryController extends Controller
}
}
if ($moment != 'all' && $loop > 1) {
if ($moment !== 'all' && $loop > 1) {
$subTitle = trans(
'firefly.without_category_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
@@ -246,7 +247,7 @@ class CategoryController extends Controller
// default values:
$subTitle = $category->name;
$subTitleIcon = 'fa-bar-chart';
$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);
$count = 0;
$loop = 0;
@@ -294,11 +295,12 @@ class CategoryController extends Controller
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
->setCategory($category)->withBudgetInformation()->withCategoryInformation()->disableInternalFilter();
->setCategory($category)->withBudgetInformation()->withCategoryInformation();
$collector->removeFilter(InternalTransferFilter::class);
$journals = $collector->getPaginatedJournals();
$journals->setPath('categories/show/' . $category->id);
$count = $journals->getCollection()->count();
if ($count === 0) {
if ($count === 0 && $loop < 3) {
$start->subDay();
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfPeriod($start, $range);
@@ -306,7 +308,7 @@ class CategoryController extends Controller
}
}
if ($moment != 'all' && $loop > 1) {
if ($moment !== 'all' && $loop > 1) {
$subTitle = trans(
'firefly.journals_in_period_for_category',
['name' => $category->name, 'start' => $start->formatLocalized($this->monthAndDayFormat),
@@ -402,14 +404,17 @@ class CategoryController extends Controller
// count journals without budget in this period:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()->withOpposingAccount()->disableInternalFilter();
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()
->withOpposingAccount();
$collector->removeFilter(InternalTransferFilter::class);
$count = $collector->getJournals()->count();
// amount transferred
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withoutCategory()
->withOpposingAccount()->setTypes([TransactionType::TRANSFER])->disableInternalFilter();
->withOpposingAccount()->setTypes([TransactionType::TRANSFER]);
$collector->removeFilter(InternalTransferFilter::class);
$transferred = Steam::positive($collector->getJournals()->sum('transaction_amount'));
// amount spent
@@ -458,7 +463,7 @@ class CategoryController extends Controller
$accountRepository = app(AccountRepositoryInterface::class);
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
$first = $repository->firstUseDate($category);
if ($first->year == 1900) {
if ($first->year === 1900) {
$first = new Carbon;
}
$range = Preferences::get('viewRange', '1M')->data;
@@ -488,7 +493,8 @@ class CategoryController extends Controller
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->setCategory($category)
->withOpposingAccount()->setTypes([TransactionType::TRANSFER])->disableInternalFilter();
->withOpposingAccount()->setTypes([TransactionType::TRANSFER]);
$collector->removeFilter(InternalTransferFilter::class);
$transferred = Steam::positive($collector->getJournals()->sum('transaction_amount'));
$entries->push(

View File

@@ -14,7 +14,6 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
@@ -115,9 +114,8 @@ class AccountController extends Controller
$start->subDay();
$accounts = $repository->getAccountsByType([AccountType::EXPENSE, AccountType::BENEFICIARY]);
$ids = $accounts->pluck('id')->toArray();
$startBalances = Steam::balancesById($ids, $start);
$endBalances = Steam::balancesById($ids, $end);
$startBalances = Steam::balancesByAccounts($accounts, $start);
$endBalances = Steam::balancesByAccounts($accounts, $end);
$chartData = [];
foreach ($accounts as $account) {
@@ -129,6 +127,7 @@ class AccountController extends Controller
$chartData[$account->name] = $diff;
}
}
arsort($chartData);
$data = $this->generator->singleSet(strval(trans('firefly.spent')), $chartData);
$cache->store($data);
@@ -336,7 +335,7 @@ class AccountController extends Controller
/**
* @param Account $account
* @param Carbon $start
* @param Carbon $start
*
* @return \Illuminate\Http\JsonResponse
* @throws FireflyException
@@ -411,9 +410,8 @@ class AccountController extends Controller
$accounts = $repository->getAccountsByType([AccountType::REVENUE]);
$start->subDay();
$ids = $accounts->pluck('id')->toArray();
$startBalances = Steam::balancesById($ids, $start);
$endBalances = Steam::balancesById($ids, $end);
$startBalances = Steam::balancesByAccounts($accounts, $start);
$endBalances = Steam::balancesByAccounts($accounts, $end);
foreach ($accounts as $account) {
$id = $account->id;
@@ -427,7 +425,7 @@ class AccountController extends Controller
}
arsort($chartData);
$data = $this->generator->singleSet(strval(trans('firefly.spent')), $chartData);
$data = $this->generator->singleSet(strval(trans('firefly.earned')), $chartData);
$cache->store($data);
return Response::json($data);

View File

@@ -31,6 +31,7 @@ use Illuminate\Support\Collection;
use Navigation;
use Preferences;
use Response;
use Steam;
/**
* Class BudgetController
@@ -123,7 +124,7 @@ class BudgetController extends Controller
*/
public function budgetLimit(Budget $budget, BudgetLimit $budgetLimit)
{
if ($budgetLimit->budget->id != $budget->id) {
if ($budgetLimit->budget->id !== $budget->id) {
throw new FireflyException('This budget limit is not part of this budget.');
}
@@ -320,12 +321,12 @@ class BudgetController extends Controller
['label' => strval(trans('firefly.overspent')), 'entries' => [], 'type' => 'bar',],
];
/** @var Budget $budget */
foreach ($budgets as $budget) {
// get relevant repetitions:
$limits = $this->repository->getBudgetLimits($budget, $start, $end);
$expenses = $this->getExpensesForBudget($limits, $budget, $start, $end);
foreach ($expenses as $name => $row) {
$chartData[0]['entries'][$name] = $row['spent'];
$chartData[1]['entries'][$name] = $row['left'];
@@ -529,9 +530,7 @@ class BudgetController extends Controller
$rows = $this->spentInPeriodMulti($budget, $limits);
foreach ($rows as $name => $row) {
if (bccomp($row['spent'], '0') !== 0 || bccomp($row['left'], '0') !== 0) {
$return[$name]['spent'] = bcmul($row['spent'], '-1');
$return[$name]['left'] = $row['left'];
$return[$name]['overspent'] = bcmul($row['overspent'], '-1');
$return[$name] = $row;
}
}
unset($rows, $row);
@@ -563,6 +562,7 @@ class BudgetController extends Controller
/** @var BudgetLimit $budgetLimit */
foreach ($limits as $budgetLimit) {
$expenses = $this->repository->spentInPeriod(new Collection([$budget]), new Collection, $budgetLimit->start_date, $budgetLimit->end_date);
$expenses = Steam::positive($expenses);
if ($limits->count() > 1) {
$name = $budget->name . ' ' . trans(
@@ -578,10 +578,14 @@ class BudgetController extends Controller
* left: amount of budget limit min spent, or 0 when < 0.
* spent: spent, or amount of budget limit when > amount
*/
$amount = $budgetLimit->amount;
$left = bccomp(bcadd($amount, $expenses), '0') < 1 ? '0' : bcadd($amount, $expenses);
$spent = bccomp($expenses, $amount) === 1 ? $expenses : bcmul($amount, '-1');
$overspent = bccomp(bcadd($amount, $expenses), '0') < 1 ? bcadd($amount, $expenses) : '0';
$amount = $budgetLimit->amount;
$leftInLimit = bcsub($amount, $expenses);
$hasOverspent = bccomp($leftInLimit, '0') === -1;
$left = $hasOverspent ? '0' : bcsub($amount, $expenses);
$spent = $hasOverspent ? $amount : $expenses;
$overspent = $hasOverspent ? Steam::positive($leftInLimit) : '0';
$return[$name] = [
'left' => $left,
'overspent' => $overspent,

View File

@@ -16,9 +16,11 @@ namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
use FireflyIII\Generator\Report\Support;
use FireflyIII\Helpers\Chart\MetaPieChartInterface;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
@@ -234,12 +236,15 @@ class BudgetReportController extends Controller
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setBudgets($budgets)->withOpposingAccount()->disableFilter();
$accountIds = $accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$set = Support::filterExpenses($transactions, $accountIds);
->setBudgets($budgets)->withOpposingAccount();
$collector->removeFilter(TransferFilter::class);
return $set;
$collector->addFilter(OpposingAccountFilter::class);
$collector->addFilter(PositiveAmountFilter::class);
$transactions = $collector->getJournals();
return $transactions;
}
/**

View File

@@ -67,7 +67,7 @@ class CategoryController extends Controller
$start = $repository->firstUseDate($category);
if ($start->year == 1900) {
if ($start->year === 1900) {
$start = new Carbon;
}
@@ -277,10 +277,10 @@ class CategoryController extends Controller
*/
public function specificPeriod(CategoryRepositoryInterface $repository, Category $category, Carbon $date)
{
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($date, $range);
$end = Navigation::endOfPeriod($date, $range);
$data = $this->makePeriodChart($repository, $category, $start, $end);
$range = Preferences::get('viewRange', '1M')->data;
$start = Navigation::startOfPeriod($date, $range);
$end = Navigation::endOfPeriod($date, $range);
$data = $this->makePeriodChart($repository, $category, $start, $end);
return Response::json($data);
}
@@ -336,9 +336,9 @@ class CategoryController extends Controller
$sum = bcadd($spent, $earned);
$label = trim(Navigation::periodShow($start, '1D'));
$chartData[0]['entries'][$label] = round(bcmul($spent, '-1'),12);
$chartData[1]['entries'][$label] = round($earned,12);
$chartData[2]['entries'][$label] = round($sum,12);
$chartData[0]['entries'][$label] = round(bcmul($spent, '-1'), 12);
$chartData[1]['entries'][$label] = round($earned, 12);
$chartData[2]['entries'][$label] = round($sum, 12);
$start->addDay();

View File

@@ -16,9 +16,12 @@ namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
use FireflyIII\Generator\Report\Category\MonthReportGenerator;
use FireflyIII\Helpers\Chart\MetaPieChartInterface;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
@@ -244,7 +247,7 @@ class CategoryReportController extends Controller
// remove all empty entries to prevent cluttering:
$newSet = [];
foreach ($chartData as $key => $entry) {
if (!array_sum($entry['entries']) == 0) {
if (!array_sum($entry['entries']) === 0) {
$newSet[$key] = $chartData[$key];
}
}
@@ -271,12 +274,15 @@ class CategoryReportController extends Controller
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setCategories($categories)->withOpposingAccount()->disableFilter();
$accountIds = $accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$set = MonthReportGenerator::filterExpenses($transactions, $accountIds);
->setCategories($categories)->withOpposingAccount();
$collector->removeFilter(TransferFilter::class);
return $set;
$collector->addFilter(OpposingAccountFilter::class);
$collector->addFilter(PositiveAmountFilter::class);
$transactions = $collector->getJournals();
return $transactions;
}
/**
@@ -293,11 +299,13 @@ class CategoryReportController extends Controller
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->setCategories($categories)->withOpposingAccount();
$accountIds = $accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$set = MonthReportGenerator::filterIncome($transactions, $accountIds);
return $set;
$collector->addFilter(OpposingAccountFilter::class);
$collector->addFilter(NegativeAmountFilter::class);
$transactions = $collector->getJournals();
return $transactions;
}
/**

View File

@@ -67,11 +67,10 @@ class ReportController extends Controller
if ($cache->has()) {
return Response::json($cache->get()); // @codeCoverageIgnore
}
$ids = $accounts->pluck('id')->toArray();
$current = clone $start;
$chartData = [];
while ($current < $end) {
$balances = Steam::balancesById($ids, $current);
$balances = Steam::balancesByAccounts($accounts, $current);
$sum = $this->arraySum($balances);
$label = $current->formatLocalized(strval(trans('config.month_and_day')));
$chartData[$label] = $sum;
@@ -104,7 +103,7 @@ class ReportController extends Controller
$cache->addProperty($accounts);
$cache->addProperty($end);
if ($cache->has()) {
//return Response::json($cache->get()); // @codeCoverageIgnore
return Response::json($cache->get()); // @codeCoverageIgnore
}
Log::debug('Going to do operations for accounts ', $accounts->pluck('id')->toArray());
$format = Navigation::preferredCarbonLocalizedFormat($start, $end);
@@ -250,7 +249,7 @@ class ReportController extends Controller
$cache->addProperty($accounts);
$cache->addProperty($end);
if ($cache->has()) {
// return $cache->get(); // @codeCoverageIgnore
return $cache->get(); // @codeCoverageIgnore
}
$currentStart = clone $start;

View File

@@ -14,9 +14,12 @@ namespace FireflyIII\Http\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
use FireflyIII\Generator\Report\Tag\MonthReportGenerator;
use FireflyIII\Helpers\Chart\MetaPieChartInterface;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
use FireflyIII\Helpers\Filter\TransferFilter;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Tag;
use FireflyIII\Models\Transaction;
@@ -228,7 +231,7 @@ class TagReportController extends Controller
// remove all empty entries to prevent cluttering:
$newSet = [];
foreach ($chartData as $key => $entry) {
if (!array_sum($entry['entries']) == 0) {
if (!array_sum($entry['entries']) === 0) {
$newSet[$key] = $chartData[$key];
}
}
@@ -303,12 +306,15 @@ class TagReportController extends Controller
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->setTags($tags)->withOpposingAccount()->disableFilter();
$accountIds = $accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$set = MonthReportGenerator::filterExpenses($transactions, $accountIds);
->setTags($tags)->withOpposingAccount();
$collector->removeFilter(TransferFilter::class);
return $set;
$collector->addFilter(OpposingAccountFilter::class);
$collector->addFilter(PositiveAmountFilter::class);
$transactions = $collector->getJournals();
return $transactions;
}
/**
@@ -325,11 +331,13 @@ class TagReportController extends Controller
$collector = app(JournalCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->setTags($tags)->withOpposingAccount();
$accountIds = $accounts->pluck('id')->toArray();
$transactions = $collector->getJournals();
$set = MonthReportGenerator::filterIncome($transactions, $accountIds);
return $set;
$collector->addFilter(OpposingAccountFilter::class);
$collector->addFilter(NegativeAmountFilter::class);
$transactions = $collector->getJournals();
return $transactions;
}
/**
@@ -356,4 +364,4 @@ class TagReportController extends Controller
return $grouped;
}
}
}

View File

@@ -18,10 +18,13 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use Log;
use Route;
use Session;
use URL;
use View;
@@ -47,22 +50,50 @@ class Controller extends BaseController
*/
public function __construct()
{
// for transaction lists:
View::share('hideBudgets', false);
View::share('hideCategories', false);
View::share('hideBills', false);
View::share('hideTags', false);
// is site a demo site?
$isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data;
View::share('IS_DEMO_SITE', $isDemoSite);
View::share('DEMO_USERNAME', env('DEMO_USERNAME', ''));
View::share('DEMO_PASSWORD', env('DEMO_PASSWORD', ''));
// translations:
$this->middleware(
function ($request, $next) {
// translations for specific strings:
$this->monthFormat = (string)trans('config.month');
$this->monthAndDayFormat = (string)trans('config.month_and_day');
$this->dateTimeFormat = (string)trans('config.date_time');
// get shown-intro-preference:
if (auth()->check()) {
// some routes have a "what" parameter, which indicates a special page:
$specificPage = is_null(Route::current()->parameter('what')) ? '' : '_' . Route::current()->parameter('what');
$page = str_replace('.', '_', Route::currentRouteName());
// indicator if user has seen the help for this page ( + special page):
$key = 'shown_demo_' . $page . $specificPage;
// is there an intro for this route?
$intro = config('intro.' . $page);
$specialIntro = config('intro.' . $page . $specificPage);
$shownDemo = true;
// either must be array and either must be > 0
if ((is_array($intro) || is_array($specialIntro)) && (count($intro) > 0 || count($specialIntro) > 0)) {
$shownDemo = Preferences::get($key, false)->data;
Log::debug(sprintf('Check if user has already seen intro with key "%s". Result is %d', $key, $shownDemo));
}
View::share('shownDemo', $shownDemo);
View::share('current_route_name', $page);
View::share('original_route_name', Route::currentRouteName());
}
return $next($request);
}
);

View File

@@ -25,62 +25,95 @@ use Response;
*/
class HelpController extends Controller
{
/** @var HelpInterface */
private $help;
/**
* HelpController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->help = app(HelpInterface::class);
return $next($request);
}
);
}
/**
* @param HelpInterface $help
* @param $route
*
* @return \Illuminate\Http\JsonResponse
*/
public function show(HelpInterface $help, string $route)
public function show(string $route)
{
$language = Preferences::get('language', config('firefly.default_language', 'en_US'))->data;
$content = '<p>' . strval(trans('firefly.route_has_no_help')) . '</p>';
$html = $this->getHelpText($route, $language);
if (!$help->hasRoute($route)) {
return Response::json(['html' => $html]);
}
/**
* @param string $route
* @param string $language
*
* @return string
*/
private function getHelpText(string $route, string $language): string
{
// get language and default variables.
$content = '<p>' . strval(trans('firefly.route_has_no_help')) . '</p>';
// if no such route, log error and return default text.
if (!$this->help->hasRoute($route)) {
Log::error('No such route: ' . $route);
return Response::json($content);
return $content;
}
if ($help->inCache($route, $language)) {
$content = $help->getFromCache($route, $language);
// help content may be cached:
if ($this->help->inCache($route, $language)) {
$content = $this->help->getFromCache($route, $language);
Log::debug(sprintf('Help text %s was in cache.', $language));
return Response::json($content);
return $content;
}
$content = $help->getFromGithub($route, $language);
$notYourLanguage = '<p><em>' . strval(trans('firefly.help_may_not_be_your_language')) . '</em></p>';
// get help content from Github:
$content = $this->help->getFromGithub($route, $language);
// get backup language content (try English):
// content will have 0 length when Github failed. Try en_US when it does:
if (strlen($content) === 0) {
$language = 'en_US';
if ($help->inCache($route, $language)) {
// also check cache first:
if ($this->help->inCache($route, $language)) {
Log::debug(sprintf('Help text %s was in cache.', $language));
$content = $notYourLanguage . $help->getFromCache($route, $language);
}
if (!$help->inCache($route, $language)) {
$content = trim($notYourLanguage . $help->getFromGithub($route, $language));
$content = $this->help->getFromCache($route, $language);
return $content;
}
$content = $this->help->getFromGithub($route, $language);
}
if ($content === $notYourLanguage) {
$content = '<p>' . strval(trans('firefly.route_has_no_help')) . '</p>';
// help still empty?
if (strlen($content) !== 0) {
$this->help->putInCache($route, $language, $content);
return $content;
}
$help->putInCache($route, $language, $content);
return Response::json($content);
return '<p>' . strval(trans('firefly.route_has_no_help')) . '</p>';
}

View File

@@ -21,9 +21,11 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Illuminate\Support\Collection;
use Log;
use Preferences;
use Route as RouteFacade;
use Session;
use View;
@@ -107,7 +109,7 @@ class HomeController extends Controller
$types = config('firefly.accountTypesByIdentifier.asset');
$count = $repository->count($types);
if ($count == 0) {
if ($count === 0) {
return redirect(route('new-user.index'));
}
@@ -120,7 +122,6 @@ class HomeController extends Controller
$start = session('start', Carbon::now()->startOfMonth());
/** @var Carbon $end */
$end = session('end', Carbon::now()->endOfMonth());
$showTour = Preferences::get('tour', true)->data;
$accounts = $repository->getAccountsById($frontPage->data);
$showDepositsFrontpage = Preferences::get('showDepositsFrontpage', false)->data;
@@ -137,10 +138,34 @@ class HomeController extends Controller
}
return view(
'index', compact('count', 'showTour', 'title', 'subTitle', 'mainTitleIcon', 'transactions', 'showDepositsFrontpage', 'billCount')
'index', compact('count', 'title', 'subTitle', 'mainTitleIcon', 'transactions', 'showDepositsFrontpage', 'billCount')
);
}
public function routes()
{
$set = RouteFacade::getRoutes();
$ignore = ['chart.', 'javascript.', 'json.', 'report-data.', 'popup.', 'debugbar.'];
/** @var Route $route */
foreach ($set as $route) {
$name = $route->getName();
if (!is_null($name) && in_array('GET', $route->methods()) && strlen($name) > 0) {
$found = false;
foreach ($ignore as $string) {
if (strpos($name, $string) !== false) {
$found = true;
}
}
if (!$found) {
echo 'touch ' . $route->getName() . '.md;';
}
}
}
return '&nbsp;';
}
/**
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/

View File

@@ -12,32 +12,29 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use Crypt;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Requests\ImportUploadRequest;
use FireflyIII\Import\ImportProcedureInterface;
use FireflyIII\Import\Setup\SetupInterface;
use FireflyIII\Import\Configurator\ConfiguratorInterface;
use FireflyIII\Import\Routine\ImportRoutine;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Http\Response as LaravelResponse;
use Log;
use Response;
use Session;
use SplFileObject;
use Storage;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use View;
/**
* Class ImportController
* Class ImportController.
*
* @package FireflyIII\Http\Controllers
*/
class ImportController extends Controller
{
/** @var ImportJobRepositoryInterface */
public $repository;
/**
*
*/
@@ -48,7 +45,8 @@ class ImportController extends Controller
$this->middleware(
function ($request, $next) {
View::share('mainTitleIcon', 'fa-archive');
View::share('title', trans('firefly.import_data_full'));
View::share('title', trans('firefly.import_index_title'));
$this->repository = app(ImportJobRepositoryInterface::class);
return $next($request);
}
@@ -56,28 +54,7 @@ class ImportController extends Controller
}
/**
* This is the last step before the import starts.
*
* @param ImportJob $job
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*/
public function complete(ImportJob $job)
{
Log::debug('Now in complete()', ['job' => $job->key]);
if (!$this->jobInCorrectStep($job, 'complete')) {
return $this->redirectToCorrectStep($job);
}
$subTitle = trans('firefly.import_complete');
$subTitleIcon = 'fa-star';
return view('import.complete', compact('job', 'subTitle', 'subTitleIcon'));
}
/**
* This is step 3.
* This is the first step in configuring the job. It can only be executed
* when the job is set to "import_status_never_started".
* This is step 3. This repeats until the job is configured.
*
* @param ImportJob $job
*
@@ -86,37 +63,43 @@ class ImportController extends Controller
*/
public function configure(ImportJob $job)
{
Log::debug('Now at start of configure()');
if (!$this->jobInCorrectStep($job, 'configure')) {
return $this->redirectToCorrectStep($job);
}
// create configuration class:
$configurator = $this->makeConfigurator($job);
// actual code
$importer = $this->makeImporter($job);
$importer->configure();
$data = $importer->getConfigurationData();
$subTitle = trans('firefly.configure_import');
// is the job already configured?
if ($configurator->isJobConfigured()) {
$this->repository->updateStatus($job, 'configured');
return redirect(route('import.status', [$job->key]));
}
$view = $configurator->getNextView();
$data = $configurator->getNextData();
$subTitle = trans('firefly.import_config_bread_crumb');
$subTitleIcon = 'fa-wrench';
return view('import.' . $job->file_type . '.configure', compact('data', 'job', 'subTitle', 'subTitleIcon'));
return view($view, compact('data', 'job', 'subTitle', 'subTitleIcon'));
}
/**
* Generate a JSON file of the job's config and send it to the user.
* Generate a JSON file of the job's configuration and send it to the user.
*
* @param ImportJob $job
*
* @return mixed
* @return LaravelResponse
*/
public function download(ImportJob $job)
{
Log::debug('Now in download()', ['job' => $job->key]);
$config = $job->configuration;
$config = $job->configuration;
// This is CSV import specific:
$config['column-roles-complete'] = false;
$config['column-mapping-complete'] = false;
$config['initial-config-complete'] = false;
$config['delimiter'] = $config['delimiter'] === "\t" ? 'tab' : $config['delimiter'];
$result = json_encode($config, JSON_PRETTY_PRINT);
$name = sprintf('"%s"', addcslashes('import-configuration-' . date('Y-m-d') . '.json', '"\\'));
$result = json_encode($config, JSON_PRETTY_PRINT);
$name = sprintf('"%s"', addcslashes('import-configuration-' . date('Y-m-d') . '.json', '"\\'));
/** @var LaravelResponse $response */
$response = response($result, 200);
@@ -134,26 +117,6 @@ class ImportController extends Controller
}
/**
* @param ImportJob $job
*
* @return View
*/
public function finished(ImportJob $job)
{
if (!$this->jobInCorrectStep($job, 'finished')) {
return $this->redirectToCorrectStep($job);
}
// if there is a tag (there might not be), we can link to it:
$tagId = $job->extended_status['importTag'] ?? 0;
$subTitle = trans('firefly.import_finished');
$subTitleIcon = 'fa-star';
return view('import.finished', compact('job', 'subTitle', 'subTitleIcon', 'tagId'));
}
/**
* This is step 1. Upload a file.
*
@@ -161,8 +124,7 @@ class ImportController extends Controller
*/
public function index()
{
Log::debug('Now at index');
$subTitle = trans('firefly.import_data_index');
$subTitle = trans('firefly.import_index_sub_title');
$subTitleIcon = 'fa-home';
$importFileTypes = [];
$defaultImportType = config('firefly.default_import_format');
@@ -175,42 +137,75 @@ class ImportController extends Controller
}
/**
* This is step 2. It creates an Import Job. Stores the import.
*
* @param ImportUploadRequest $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function initialize(ImportUploadRequest $request)
{
Log::debug('Now in initialize()');
// create import job:
$type = $request->get('import_file_type');
$job = $this->repository->create($type);
Log::debug('Created new job', ['key' => $job->key, 'id' => $job->id]);
// process file:
$this->repository->processFile($job, $request->files->get('import_file'));
// process config, if present:
if ($request->files->has('configuration_file')) {
$this->repository->processConfiguration($job, $request->files->get('configuration_file'));
}
$this->repository->updateStatus($job, 'initialized');
return redirect(route('import.configure', [$job->key]));
}
/**
*
* Show status of import job in JSON.
*
* @param ImportJob $job
*
* @return \Illuminate\Http\JsonResponse
*/
public function json(ImportJob $job)
{
$result = [
'showPercentage' => false,
'started' => false,
'finished' => false,
'running' => false,
'errors' => $job->extended_status['errors'],
'percentage' => 0,
'steps' => $job->extended_status['total_steps'],
'stepsDone' => $job->extended_status['steps_done'],
'statusText' => trans('firefly.import_status_' . $job->status),
'finishedText' => '',
$result = [
'started' => false,
'finished' => false,
'running' => false,
'errors' => array_values($job->extended_status['errors']),
'percentage' => 0,
'show_percentage' => false,
'steps' => $job->extended_status['steps'],
'done' => $job->extended_status['done'],
'statusText' => trans('firefly.import_status_job_' . $job->status),
'status' => $job->status,
'finishedText' => '',
];
$percentage = 0;
if ($job->extended_status['total_steps'] !== 0) {
$percentage = round(($job->extended_status['steps_done'] / $job->extended_status['total_steps']) * 100, 0);
if ($job->extended_status['steps'] !== 0) {
$result['percentage'] = round(($job->extended_status['done'] / $job->extended_status['steps']) * 100, 0);
$result['show_percentage'] = true;
}
if ($job->status === 'import_complete') {
$tagId = $job->extended_status['importTag'];
if ($job->status === 'finished') {
$tagId = $job->extended_status['tag'];
/** @var TagRepositoryInterface $repository */
$repository = app(TagRepositoryInterface::class);
$tag = $repository->find($tagId);
$result['finished'] = true;
$result['finishedText'] = trans('firefly.import_finished_link', ['link' => route('tags.show', [$tag->id]), 'tag' => $tag->tag]);
$result['finishedText'] = trans('firefly.import_status_finished_job', ['link' => route('tags.show', [$tag->id, 'all']), 'tag' => $tag->tag]);
}
if ($job->status === 'import_running') {
$result['started'] = true;
$result['running'] = true;
$result['showPercentage'] = true;
$result['percentage'] = $percentage;
if ($job->status === 'running') {
$result['started'] = true;
$result['running'] = true;
}
return Response::json($result);
@@ -219,286 +214,82 @@ class ImportController extends Controller
/**
* Step 4. Save the configuration.
*
* @param Request $request
* @param ImportJobRepositoryInterface $repository
* @param ImportJob $job
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function postConfigure(Request $request, ImportJobRepositoryInterface $repository, ImportJob $job)
{
Log::debug('Now in postConfigure()', ['job' => $job->key]);
if (!$this->jobInCorrectStep($job, 'process')) {
return $this->redirectToCorrectStep($job);
}
Log::debug('Continue postConfigure()', ['job' => $job->key]);
// actual code
$importer = $this->makeImporter($job);
$data = $request->all();
$files = $request->files;
$importer->saveImportConfiguration($data, $files);
// update job:
$repository->updateStatus($job, 'import_configuration_saved');
// return redirect to settings.
// this could loop until the user is done.
return redirect(route('import.settings', [$job->key]));
}
/**
* This step 6. Depending on the importer, this will process the
* settings given and store them.
*
* @param Request $request
* @param ImportJob $job
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws FireflyException
*/
public function postSettings(Request $request, ImportJob $job)
public function postConfigure(Request $request, ImportJob $job)
{
Log::debug('Now in postSettings()', ['job' => $job->key]);
if (!$this->jobInCorrectStep($job, 'store-settings')) {
return $this->redirectToCorrectStep($job);
}
$importer = $this->makeImporter($job);
$importer->storeSettings($request);
// return redirect to settings (for more settings perhaps)
return redirect(route('import.settings', [$job->key]));
}
/**
* Step 5. Depending on the importer, this will show the user settings to
* fill in.
*
* @param ImportJobRepositoryInterface $repository
* @param ImportJob $job
*
* @return View
*/
public function settings(ImportJobRepositoryInterface $repository, ImportJob $job)
{
Log::debug('Now in settings()', ['job' => $job->key]);
if (!$this->jobInCorrectStep($job, 'settings')) {
return $this->redirectToCorrectStep($job);
}
Log::debug('Continue in settings()');
$importer = $this->makeImporter($job);
$subTitle = trans('firefly.settings_for_import');
$subTitleIcon = 'fa-wrench';
// now show settings screen to user.
if ($importer->requireUserSettings()) {
Log::debug('Job requires user config.');
$data = $importer->getDataForSettings();
$view = $importer->getViewForSettings();
return view($view, compact('data', 'job', 'subTitle', 'subTitleIcon'));
}
Log::debug('Job does NOT require user config.');
$repository->updateStatus($job, 'settings_complete');
// if no more settings, save job and continue to process thing.
return redirect(route('import.complete', [$job->key]));
// ask the importer for the requested action.
// for example pick columns or map data.
// depends of course on the data in the job.
}
/**
* @param ImportProcedureInterface $importProcedure
* @param ImportJob $job
*/
public function start(ImportProcedureInterface $importProcedure, ImportJob $job)
{
set_time_limit(0);
if ($job->status == 'settings_complete') {
$importProcedure->runImport($job);
}
}
/**
* This is the last step before the import starts.
*
* @param ImportJob $job
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*/
public function status(ImportJob $job)
{ //
Log::debug('Now in status()', ['job' => $job->key]);
if (!$this->jobInCorrectStep($job, 'status')) {
return $this->redirectToCorrectStep($job);
}
$subTitle = trans('firefly.import_status');
$subTitleIcon = 'fa-star';
return view('import.status', compact('job', 'subTitle', 'subTitleIcon'));
}
/**
* This is step 2. It creates an Import Job. Stores the import.
*
* @param ImportUploadRequest $request
* @param ImportJobRepositoryInterface $repository
* @param UserRepositoryInterface $userRepository
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function upload(ImportUploadRequest $request, ImportJobRepositoryInterface $repository, UserRepositoryInterface $userRepository)
{
Log::debug('Now in upload()');
// create import job:
$type = $request->get('import_file_type');
$job = $repository->create($type);
Log::debug('Created new job', ['key' => $job->key, 'id' => $job->id]);
/** @var UploadedFile $upload */
$upload = $request->files->get('import_file');
$newName = $job->key . '.upload';
$uploaded = new SplFileObject($upload->getRealPath());
$content = $uploaded->fread($uploaded->getSize());
$contentEncrypted = Crypt::encrypt($content);
$disk = Storage::disk('upload');
// user is demo user, replace upload with prepared file.
if ($userRepository->hasRole(auth()->user(), 'demo')) {
$stubsDisk = Storage::disk('stubs');
$content = $stubsDisk->get('demo-import.csv');
$contentEncrypted = Crypt::encrypt($content);
$disk->put($newName, $contentEncrypted);
Log::debug('Replaced upload with demo file.');
// also set up prepared configuration.
$configuration = json_decode($stubsDisk->get('demo-configuration.json'), true);
$repository->setConfiguration($job, $configuration);
Log::debug('Set configuration for demo user', $configuration);
// also flash info
Session::flash('info', trans('demo.import-configure-security'));
}
if (!$userRepository->hasRole(auth()->user(), 'demo')) {
// user is not demo, process original upload:
$disk->put($newName, $contentEncrypted);
Log::debug('Uploaded file', ['name' => $upload->getClientOriginalName(), 'size' => $upload->getSize(), 'mime' => $upload->getClientMimeType()]);
}
// store configuration file's content into the job's configuration thing. Otherwise, leave it empty.
// demo user's configuration upload is ignored completely.
if ($request->files->has('configuration_file') && !auth()->user()->hasRole('demo')) {
/** @var UploadedFile $configFile */
$configFile = $request->files->get('configuration_file');
Log::debug(
'Uploaded configuration file',
['name' => $configFile->getClientOriginalName(), 'size' => $configFile->getSize(), 'mime' => $configFile->getClientMimeType()]
);
$configFileObject = new SplFileObject($configFile->getRealPath());
$configRaw = $configFileObject->fread($configFileObject->getSize());
$configuration = json_decode($configRaw, true);
// @codeCoverageIgnoreStart
if (!is_null($configuration) && is_array($configuration)) {
Log::debug('Found configuration', $configuration);
$repository->setConfiguration($job, $configuration);
}
// @codeCoverageIgnoreEnd
Log::debug('Now in postConfigure()', ['job' => $job->key]);
$configurator = $this->makeConfigurator($job);
// is the job already configured?
if ($configurator->isJobConfigured()) {
return redirect(route('import.status', [$job->key]));
}
$data = $request->all();
$configurator->configureJob($data);
// return to configure
return redirect(route('import.configure', [$job->key]));
}
/**
* @param ImportJob $job
* @param string $method
*
* @return bool
* @return \Illuminate\Http\JsonResponse
* @throws FireflyException
*/
private function jobInCorrectStep(ImportJob $job, string $method): bool
public function start(ImportJob $job)
{
Log::debug('Now in jobInCorrectStep()', ['job' => $job->key, 'method' => $method]);
switch ($method) {
case 'configure':
case 'process':
return $job->status === 'import_status_never_started';
case 'settings':
case 'store-settings':
Log::debug(sprintf('Job %d with key %s has status %s', $job->id, $job->key, $job->status));
return $job->status === 'import_configuration_saved';
case 'finished':
return $job->status === 'import_complete';
case 'complete':
return $job->status === 'settings_complete';
case 'status':
return ($job->status === 'settings_complete') || ($job->status === 'import_running');
/** @var ImportRoutine $routine */
$routine = app(ImportRoutine::class);
$routine->setJob($job);
$result = $routine->run();
if ($result) {
return Response::json(['run' => 'ok']);
}
return false; // @codeCoverageIgnore
throw new FireflyException('Job did not complete succesfully.');
}
/**
* @param ImportJob $job
*
* @return SetupInterface
* @throws FireflyException
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*/
private function makeImporter(ImportJob $job): SetupInterface
public function status(ImportJob $job)
{
// create proper importer (depends on job)
$type = strtolower($job->file_type);
// validate type:
$validTypes = array_keys(config('firefly.import_formats'));
if (in_array($type, $validTypes)) {
/** @var SetupInterface $importer */
$importer = app('FireflyIII\Import\Setup\\' . ucfirst($type) . 'Setup');
$importer->setJob($job);
return $importer;
$statuses = ['configured', 'running', 'finished'];
if (!in_array($job->status, $statuses)) {
return redirect(route('import.configure', [$job->key]));
}
throw new FireflyException(sprintf('"%s" is not a valid file type', $type)); // @codeCoverageIgnore
$subTitle = trans('firefly.import_status_sub_title');
$subTitleIcon = 'fa-star';
return view('import.status', compact('job', 'subTitle', 'subTitleIcon'));
}
/**
* @param ImportJob $job
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @return ConfiguratorInterface
* @throws FireflyException
*/
private function redirectToCorrectStep(ImportJob $job)
private function makeConfigurator(ImportJob $job): ConfiguratorInterface
{
Log::debug('Now in redirectToCorrectStep()', ['job' => $job->key]);
switch ($job->status) {
case 'import_status_never_started':
Log::debug('Will redirect to configure()');
return redirect(route('import.configure', [$job->key]));
case 'import_configuration_saved':
Log::debug('Will redirect to settings()');
return redirect(route('import.settings', [$job->key]));
case 'settings_complete':
Log::debug('Will redirect to complete()');
return redirect(route('import.complete', [$job->key]));
case 'import_complete':
Log::debug('Will redirect to finished()');
return redirect(route('import.finished', [$job->key]));
$type = $job->file_type;
$key = sprintf('firefly.import_configurators.%s', $type);
$className = config($key);
if (is_null($className)) {
throw new FireflyException('Cannot find configurator class for this job.'); // @codeCoverageIgnore
}
/** @var ConfiguratorInterface $configurator */
$configurator = app($className);
$configurator->setJob($job);
throw new FireflyException('Cannot redirect for job state ' . $job->status); // @codeCoverageIgnore
return $configurator;
}
}

View File

@@ -34,7 +34,7 @@ class JavascriptController extends Controller
* @param AccountRepositoryInterface $repository
* @param CurrencyRepositoryInterface $currencyRepository
*
* @return $this
* @return \Illuminate\Http\Response
*/
public function accounts(AccountRepositoryInterface $repository, CurrencyRepositoryInterface $currencyRepository)
{
@@ -63,7 +63,7 @@ class JavascriptController extends Controller
/**
* @param CurrencyRepositoryInterface $repository
*
* @return $this
* @return \Illuminate\Http\Response
*/
public function currencies(CurrencyRepositoryInterface $repository)
{
@@ -71,8 +71,8 @@ class JavascriptController extends Controller
$data = ['currencies' => [],];
/** @var TransactionCurrency $currency */
foreach ($currencies as $currency) {
$currencyId = $currency->id;
$entry = ['name' => $currency->name, 'code' => $currency->code, 'symbol' => $currency->symbol];
$currencyId = $currency->id;
$entry = ['name' => $currency->name, 'code' => $currency->code, 'symbol' => $currency->symbol];
$data['currencies'][$currencyId] = $entry;
}

View File

@@ -41,7 +41,6 @@ class ExchangeController extends Controller
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$rate = $repository->getExchangeRate($fromCurrency, $toCurrency, $date);
$amount = null;
if (is_null($rate->id)) {
Log::debug(sprintf('No cached exchange rate in database for %s to %s on %s', $fromCurrency->code, $toCurrency->code, $date->format('Y-m-d')));
$preferred = env('EXCHANGE_RATE_SERVICE', config('firefly.preferred_exchange_service'));
@@ -63,4 +62,4 @@ class ExchangeController extends Controller
return Response::json($return);
}
}
}

View File

@@ -0,0 +1,166 @@
<?php
/**
* IntroController.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\Http\Controllers\Json;
use FireflyIII\Support\Facades\Preferences;
use Log;
use Response;
/**
* Class IntroController
*
* @package FireflyIII\Http\Controllers\Json
*/
class IntroController
{
/**
* @param string $route
* @param string $specificPage
*
* @return \Illuminate\Http\JsonResponse
*/
public function getIntroSteps(string $route, string $specificPage = '')
{
$steps = $this->getBasicSteps($route);
$specificSteps = $this->getSpecificSteps($route, $specificPage);
if (count($specificSteps) === 0) {
return Response::json($steps);
}
if ($this->hasOutroStep($route)) {
// save last step:
$lastStep = $steps[count($steps) - 1];
// remove last step:
array_pop($steps);
// merge arrays and add last step again
$steps = array_merge($steps, $specificSteps);
$steps[] = $lastStep;
}
if (!$this->hasOutroStep($route)) {
$steps = array_merge($steps, $specificSteps);
}
return Response::json($steps);
}
/**
* @param string $route
*
* @return bool
*/
public function hasOutroStep(string $route): bool
{
$routeKey = str_replace('.', '_', $route);
$elements = config(sprintf('intro.%s', $routeKey));
if (!is_array($elements)) {
return false;
}
$keys = array_keys($elements);
return in_array('outro', $keys);
}
/**
* @param string $route
* @param string $specialPage
*
* @return \Illuminate\Http\JsonResponse
*/
public function postEnable(string $route, string $specialPage = '')
{
$route = str_replace('.', '_', $route);
$key = 'shown_demo_' . $route;
if ($specialPage !== '') {
$key .= '_' . $specialPage;
}
Log::debug(sprintf('Going to mark the following route as NOT done: %s with special "%s" (%s)', $route, $specialPage, $key));
Preferences::set($key, false);
return Response::json(['message' => trans('firefly.intro_boxes_after_refresh')]);
}
/**
* @param string $route
* @param string $specialPage
*
* @return \Illuminate\Http\JsonResponse
*/
public function postFinished(string $route, string $specialPage = '')
{
$key = 'shown_demo_' . $route;
if ($specialPage !== '') {
$key .= '_' . $specialPage;
}
Log::debug(sprintf('Going to mark the following route as done: %s with special "%s" (%s)', $route, $specialPage, $key));
Preferences::set($key, true);
return Response::json(['result' => sprintf('Reported demo watched for route "%s".', $route)]);
}
/**
* @param string $route
*
* @return array
*/
private function getBasicSteps(string $route): array
{
$routeKey = str_replace('.', '_', $route);
$elements = config(sprintf('intro.%s', $routeKey));
$steps = [];
if (is_array($elements) && count($elements) > 0) {
foreach ($elements as $key => $options) {
$currentStep = $options;
// get the text:
$currentStep['intro'] = trans('intro.' . $route . '_' . $key);
// save in array:
$steps[] = $currentStep;
}
}
return $steps;
}
/**
* @param string $route
* @param string $specificPage
*
* @return array
*/
private function getSpecificSteps(string $route, string $specificPage): array
{
$steps = [];
// user is on page with specific instructions:
if (strlen($specificPage) > 0) {
$routeKey = str_replace('.', '_', $route);
$elements = config(sprintf('intro.%s', $routeKey . '_' . $specificPage));
if (is_array($elements) && count($elements) > 0) {
foreach ($elements as $key => $options) {
$currentStep = $options;
// get the text:
$currentStep['intro'] = trans('intro.' . $route . '_' . $specificPage . '_' . $key);
// save in array:
$steps[] = $currentStep;
}
}
}
return $steps;
}
}

View File

@@ -15,12 +15,10 @@ namespace FireflyIII\Http\Controllers;
use Amount;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
@@ -28,7 +26,6 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Http\Request;
use Preferences;
use Response;
/**
@@ -116,10 +113,11 @@ class JsonController extends Controller
* Since both this method and the chart use the exact same data, we can suffice
* with calling the one method in the bill repository that will get this amount.
*/
$amount = $repository->getBillsPaidInRange($start, $end); // will be a negative amount.
$amount = bcmul($amount, '-1');
$amount = $repository->getBillsPaidInRange($start, $end); // will be a negative amount.
$amount = bcmul($amount, '-1');
$currency = Amount::getDefaultCurrency();
$data = ['box' => 'bills-paid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$data = ['box' => 'bills-paid', 'amount' => Amount::formatAnything($currency, $amount, false), 'amount_raw' => $amount];
return Response::json($data);
}
@@ -131,19 +129,19 @@ class JsonController extends Controller
*/
public function boxBillsUnpaid(BillRepositoryInterface $repository)
{
$start = session('start', Carbon::now()->startOfMonth());
$end = session('end', Carbon::now()->endOfMonth());
$amount = $repository->getBillsUnpaidInRange($start, $end); // will be a positive amount.
$data = ['box' => 'bills-unpaid', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$start = session('start', Carbon::now()->startOfMonth());
$end = session('end', Carbon::now()->endOfMonth());
$amount = $repository->getBillsUnpaidInRange($start, $end); // will be a positive amount.
$currency = Amount::getDefaultCurrency();
$data = ['box' => 'bills-unpaid', 'amount' => Amount::formatAnything($currency, $amount, false), 'amount_raw' => $amount];
return Response::json($data);
}
/**
* @param AccountTaskerInterface $accountTasker
* @param AccountRepositoryInterface $repository
*
* @return \Illuminate\Http\JsonResponse
* @internal param AccountTaskerInterface $accountTasker
* @internal param AccountRepositoryInterface $repository
*
*/
public function boxIn()
@@ -167,18 +165,19 @@ class JsonController extends Controller
->setTypes([TransactionType::DEPOSIT])
->withOpposingAccount();
$amount = strval($collector->getJournals()->sum('transaction_amount'));
$data = ['box' => 'in', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$amount = strval($collector->getJournals()->sum('transaction_amount'));
$currency = Amount::getDefaultCurrency();
$data = ['box' => 'in', 'amount' => Amount::formatAnything($currency, $amount, false), 'amount_raw' => $amount];
$cache->store($data);
return Response::json($data);
}
/**
* @param AccountTaskerInterface $accountTasker
* @param AccountRepositoryInterface $repository
*
* @return \Symfony\Component\HttpFoundation\Response
* @internal param AccountTaskerInterface $accountTasker
* @internal param AccountRepositoryInterface $repository
*
*/
public function boxOut()
{
@@ -200,9 +199,9 @@ class JsonController extends Controller
$collector->setAllAssetAccounts()->setRange($start, $end)
->setTypes([TransactionType::WITHDRAWAL])
->withOpposingAccount();
$amount = strval($collector->getJournals()->sum('transaction_amount'));
$data = ['box' => 'out', 'amount' => Amount::format($amount, false), 'amount_raw' => $amount];
$amount = strval($collector->getJournals()->sum('transaction_amount'));
$currency = Amount::getDefaultCurrency();
$data = ['box' => 'out', 'amount' => Amount::formatAnything($currency, $amount, false), 'amount_raw' => $amount];
$cache->store($data);
return Response::json($data);
@@ -236,16 +235,6 @@ class JsonController extends Controller
return Response::json($return);
}
/**
* @return \Illuminate\Http\JsonResponse
*/
public function endTour()
{
Preferences::set('tour', false);
return Response::json('true');
}
/**
* Returns a JSON list of all beneficiaries.
*
@@ -292,34 +281,6 @@ class JsonController extends Controller
}
/**
*
*/
public function tour()
{
$pref = Preferences::get('tour', true);
if (!$pref) {
throw new FireflyException('Cannot find preference for tour. Exit.'); // @codeCoverageIgnore
}
$headers = ['main-content', 'sidebar-toggle', 'account-menu', 'budget-menu', 'report-menu', 'transaction-menu', 'option-menu', 'main-content-end'];
$steps = [];
foreach ($headers as $header) {
$steps[] = [
'element' => '#' . $header,
'title' => trans('help.' . $header . '-title'),
'content' => trans('help.' . $header . '-text'),
];
}
$steps[0]['orphan'] = true;// orphan and backdrop for first element.
$steps[0]['backdrop'] = true;
$steps[1]['placement'] = 'left';// sidebar position left:
$steps[7]['orphan'] = true; // final in the center again.
$steps[7]['backdrop'] = true;
$template = view('json.tour')->render();
return Response::json(['steps' => $steps, 'template' => $template]);
}
/**
* @param JournalCollectorInterface $collector
* @param string $what
@@ -364,7 +325,7 @@ class JsonController extends Controller
$keys = array_keys(config('firefly.rule-triggers'));
$triggers = [];
foreach ($keys as $key) {
if ($key != 'user_action') {
if ($key !== 'user_action') {
$triggers[$key] = trans('firefly.rule_trigger_' . $key . '_choice');
}
}

View File

@@ -54,7 +54,6 @@ class NewUserController extends Controller
View::share('title', trans('firefly.welcome'));
View::share('mainTitleIcon', 'fa-fire');
$types = config('firefly.accountTypesByIdentifier.asset');
$count = $repository->count($types);
@@ -74,30 +73,13 @@ class NewUserController extends Controller
*/
public function submit(NewUserFormRequest $request, AccountRepositoryInterface $repository)
{
$count = 1;
// create normal asset account:
$this->createAssetAccount($request, $repository);
// create savings account
$savingBalance = strval($request->get('savings_balance')) === '' ? '0' : strval($request->get('savings_balance'));
if (bccomp($savingBalance, '0') !== 0) {
$this->createSavingsAccount($request, $repository);
$count++;
}
$this->createSavingsAccount($request, $repository);
// create credit card.
$limit = strval($request->get('credit_card_limit')) === '' ? '0' : strval($request->get('credit_card_limit'));
if (bccomp($limit, '0') !== 0) {
$this->storeCreditCard($request, $repository);
$count++;
}
$message = strval(trans('firefly.stored_new_accounts_new_user'));
if ($count == 1) {
$message = strval(trans('firefly.stored_new_account_new_user'));
}
Session::flash('success', $message);
Session::flash('success', strval(trans('firefly.stored_new_accounts_new_user')));
Preferences::mark();
return redirect(route('index'));
@@ -112,15 +94,15 @@ class NewUserController extends Controller
private function createAssetAccount(NewUserFormRequest $request, AccountRepositoryInterface $repository): bool
{
$assetAccount = [
'name' => $request->get('bank_name'),
'iban' => null,
'accountType' => 'asset',
'virtualBalance' => 0,
'active' => true,
'accountRole' => 'defaultAsset',
'openingBalance' => round($request->input('bank_balance'), 12),
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => intval($request->input('amount_currency_id_bank_balance')),
'name' => $request->get('bank_name'),
'iban' => null,
'accountType' => 'asset',
'virtualBalance' => 0,
'active' => true,
'accountRole' => 'defaultAsset',
'openingBalance' => round($request->input('bank_balance'), 12),
'openingBalanceDate' => new Carbon,
'currency_id' => intval($request->input('amount_currency_id_bank_balance')),
];
$repository->store($assetAccount);
@@ -137,44 +119,19 @@ class NewUserController extends Controller
private function createSavingsAccount(NewUserFormRequest $request, AccountRepositoryInterface $repository): bool
{
$savingsAccount = [
'name' => $request->get('bank_name') . ' savings account',
'iban' => null,
'accountType' => 'asset',
'virtualBalance' => 0,
'active' => true,
'accountRole' => 'savingAsset',
'openingBalance' => round($request->input('savings_balance'), 12),
'openingBalanceDate' => new Carbon,
'openingBalanceCurrency' => intval($request->input('amount_currency_id_savings_balance')),
'name' => $request->get('bank_name') . ' savings account',
'iban' => null,
'accountType' => 'asset',
'virtualBalance' => 0,
'active' => true,
'accountRole' => 'savingAsset',
'openingBalance' => round($request->input('savings_balance'), 12),
'openingBalanceDate' => new Carbon,
'currency_id' => intval($request->input('amount_currency_id_savings_balance')),
];
$repository->store($savingsAccount);
return true;
}
/**
* @param NewUserFormRequest $request
* @param AccountRepositoryInterface $repository
*
* @return bool
*/
private function storeCreditCard(NewUserFormRequest $request, AccountRepositoryInterface $repository): bool
{
$creditAccount = [
'name' => 'Credit card',
'iban' => null,
'accountType' => 'asset',
'virtualBalance' => round($request->get('credit_card_limit'), 12),
'active' => true,
'accountRole' => 'ccAsset',
'openingBalance' => null,
'openingBalanceDate' => null,
'openingBalanceCurrency' => intval($request->input('amount_currency_id_credit_card_limit')),
'ccType' => 'monthlyFull',
'ccMonthlyPaymentDate' => Carbon::now()->year . '-01-01',
];
$repository->store($creditAccount);
return true;
}
}

View File

@@ -89,7 +89,7 @@ class PiggyBankController extends Controller
/** @var Carbon $date */
$date = session('end', Carbon::now()->endOfMonth());
$leftOnAccount = $piggyBank->leftOnAccount($date);
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount?? '0';
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount ?? '0';
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
$maxAmount = min($leftOnAccount, $leftToSave);
@@ -276,18 +276,29 @@ class PiggyBankController extends Controller
*/
public function postAdd(Request $request, PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
{
$amount = $request->get('amount');
$amount = $request->get('amount');
$currency = Amount::getDefaultCurrency();
if ($repository->canAddAmount($piggyBank, $amount)) {
$repository->addAmount($piggyBank, $amount);
Session::flash('success', strval(trans('firefly.added_amount_to_piggy', ['amount' => Amount::format($amount, false), 'name' => $piggyBank->name])));
Session::flash(
'success', strval(
trans(
'firefly.added_amount_to_piggy',
['amount' => Amount::formatAnything($currency, $amount, false), 'name' => $piggyBank->name]
)
)
);
Preferences::mark();
return redirect(route('piggy-banks.index'));
}
Log::error('Cannot add ' . $amount . ' because canAddAmount returned false.');
Session::flash('error', strval(trans('firefly.cannot_add_amount_piggy', ['amount' => Amount::format($amount, false), 'name' => e($piggyBank->name)])));
Session::flash(
'error', strval(
trans('firefly.cannot_add_amount_piggy', ['amount' => Amount::formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)])
)
);
return redirect(route('piggy-banks.index'));
}
@@ -301,11 +312,13 @@ class PiggyBankController extends Controller
*/
public function postRemove(Request $request, PiggyBankRepositoryInterface $repository, PiggyBank $piggyBank)
{
$amount = $request->get('amount');
$amount = $request->get('amount');
$currency = Amount::getDefaultCurrency();
if ($repository->canRemoveAmount($piggyBank, $amount)) {
$repository->removeAmount($piggyBank, $amount);
Session::flash(
'success', strval(trans('firefly.removed_amount_from_piggy', ['amount' => Amount::format($amount, false), 'name' => $piggyBank->name]))
'success',
strval(trans('firefly.removed_amount_from_piggy', ['amount' => Amount::formatAnything($currency, $amount, false), 'name' => $piggyBank->name]))
);
Preferences::mark();
@@ -314,7 +327,11 @@ class PiggyBankController extends Controller
$amount = strval(round($request->get('amount'), 12));
Session::flash('error', strval(trans('firefly.cannot_remove_from_piggy', ['amount' => Amount::format($amount, false), 'name' => e($piggyBank->name)])));
Session::flash(
'error', strval(
trans('firefly.cannot_remove_from_piggy', ['amount' => Amount::formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)])
)
);
return redirect(route('piggy-banks.index'));
}
@@ -380,7 +397,7 @@ class PiggyBankController extends Controller
// @codeCoverageIgnoreEnd
}
return redirect($this->getPreviousUri('piggy-banks.edit.uri'));
return redirect($this->getPreviousUri('piggy-banks.create.uri'));
}
/**

View File

@@ -56,12 +56,8 @@ class PreferencesController extends Controller
*/
public function code(Google2FA $google2fa)
{
$domain = $this->getDomain();
$secretKey = 'FIREFLYIII';
$secretKey = str_pad($secretKey, intval(pow(2, ceil(log(strlen($secretKey), 2)))), 'X');
/** @noinspection PhpMethodParametersCountMismatchInspection */
$secret = $google2fa->generateSecretKey(16, $secretKey);
$domain = $this->getDomain();
$secret = $google2fa->generateSecretKey(16);
Session::flash('two-factor-secret', $secret);
$image = $google2fa->getQRCodeInline('Firefly III at ' . $domain, auth()->user()->email, $secret, 150);

View File

@@ -120,7 +120,7 @@ class CategoryController extends Controller
foreach ($categories as $category) {
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $end);
if (bccomp($spent, '0') !== 0) {
$report[$category->id] = ['name' => $category->name, 'spent' => $spent];
$report[$category->id] = ['name' => $category->name, 'spent' => $spent, 'id' => $category->id];
}
}

View File

@@ -15,10 +15,7 @@ namespace FireflyIII\Http\Controllers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Support\Collection;

View File

@@ -13,12 +13,18 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use ExpandedForm;
use FireflyIII\Http\Requests\RuleFormRequest;
use FireflyIII\Http\Requests\SelectTransactionsRequest;
use FireflyIII\Http\Requests\TestRuleFormRequest;
use FireflyIII\Jobs\ExecuteRuleOnExistingTransactions;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Rules\TransactionMatcher;
@@ -188,6 +194,41 @@ class RuleController extends Controller
return view('rules.rule.edit', compact('rule', 'subTitle', 'primaryTrigger', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount'));
}
/**
* Execute the given rule on a set of existing transactions
*
* @param SelectTransactionsRequest $request
* @param AccountRepositoryInterface $repository
* @param Rule $rule
*
* @return \Illuminate\Http\RedirectResponse
* @internal param RuleGroup $ruleGroup
*/
public function execute(SelectTransactionsRequest $request, AccountRepositoryInterface $repository, Rule $rule)
{
// Get parameters specified by the user
$accounts = $repository->getAccountsById($request->get('accounts'));
$startDate = new Carbon($request->get('start_date'));
$endDate = new Carbon($request->get('end_date'));
// Create a job to do the work asynchronously
$job = new ExecuteRuleOnExistingTransactions($rule);
// Apply parameters to the job
$job->setUser(auth()->user());
$job->setAccounts($accounts);
$job->setStartDate($startDate);
$job->setEndDate($endDate);
// Dispatch a new job to execute it in a queue
$this->dispatch($job);
// Tell the user that the job is queued
Session::flash('success', strval(trans('firefly.applied_rule_selection', ['title' => $rule->title])));
return redirect()->route('rules.index');
}
/**
* @param RuleGroupRepositoryInterface $repository
*
@@ -238,6 +279,25 @@ class RuleController extends Controller
}
/**
* @param AccountRepositoryInterface $repository
* @param Rule $rule
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function selectTransactions(AccountRepositoryInterface $repository, Rule $rule)
{
// does the user have shared accounts?
$accounts = $repository->getAccountsByType([AccountType::ASSET]);
$accountList = ExpandedForm::makeSelectList($accounts);
$checkedAccounts = array_keys($accountList);
$first = session('first')->format('Y-m-d');
$today = Carbon::create()->format('Y-m-d');
$subTitle = (string)trans('firefly.apply_rule_selection', ['title' => $rule->title]);
return view('rules.rule.select-transactions', compact('checkedAccounts', 'accountList', 'first', 'today', 'rule', 'subTitle'));
}
/**
* @param RuleFormRequest $request
* @param RuleRepositoryInterface $repository
@@ -282,7 +342,7 @@ class RuleController extends Controller
// build trigger array from response
$triggers = $this->getValidTriggerList($request);
if (count($triggers) == 0) {
if (count($triggers) === 0) {
return Response::json(['html' => '', 'warning' => trans('firefly.warning_no_valid_triggers')]);
}
@@ -294,19 +354,66 @@ class RuleController extends Controller
$matcher->setLimit($limit);
$matcher->setRange($range);
$matcher->setTriggers($triggers);
$matchingTransactions = $matcher->findMatchingTransactions();
$matchingTransactions = $matcher->findTransactionsByTriggers();
// Warn the user if only a subset of transactions is returned
$warning = '';
if (count($matchingTransactions) == $limit) {
if (count($matchingTransactions) === $limit) {
$warning = trans('firefly.warning_transaction_subset', ['max_num_transactions' => $limit]);
}
if (count($matchingTransactions) == 0) {
if (count($matchingTransactions) === 0) {
$warning = trans('firefly.warning_no_matching_transactions', ['num_transactions' => $range]);
}
// Return json response
$view = view('list.journals-tiny-tasker', ['transactions' => $matchingTransactions])->render();
$view = view('list.journals-tiny', ['transactions' => $matchingTransactions])->render();
return Response::json(['html' => $view, 'warning' => $warning]);
}
/**
* This method allows the user to test a certain set of rule triggers. The rule triggers are grabbed from
* the rule itself.
*
* This method will parse and validate those rules and create a "TransactionMatcher" which will attempt
* to find transaction journals matching the users input. A maximum range of transactions to try (range) and
* a maximum number of transactions to return (limit) are set as well.
*
*
* @param Rule $rule
*
* @return \Illuminate\Http\JsonResponse
*/
public function testTriggersByRule(Rule $rule)
{
$triggers = $rule->ruleTriggers;
if (count($triggers) === 0) {
return Response::json(['html' => '', 'warning' => trans('firefly.warning_no_valid_triggers')]);
}
$limit = config('firefly.test-triggers.limit');
$range = config('firefly.test-triggers.range');
/** @var TransactionMatcher $matcher */
$matcher = app(TransactionMatcher::class);
$matcher->setLimit($limit);
$matcher->setRange($range);
$matcher->setRule($rule);
$matchingTransactions = $matcher->findTransactionsByRule();
// Warn the user if only a subset of transactions is returned
$warning = '';
if (count($matchingTransactions) === $limit) {
$warning = trans('firefly.warning_transaction_subset', ['max_num_transactions' => $limit]);
}
if (count($matchingTransactions) === 0) {
$warning = trans('firefly.warning_no_matching_transactions', ['num_transactions' => $range]);
}
// Return json response
$view = view('list.journals-tiny', ['transactions' => $matchingTransactions])->render();
return Response::json(['html' => $view, 'warning' => $warning]);
}
@@ -440,7 +547,7 @@ class RuleController extends Controller
/** @var RuleTrigger $entry */
foreach ($rule->ruleTriggers as $entry) {
if ($entry->trigger_type != 'user_action') {
if ($entry->trigger_type !== 'user_action') {
$count = ($index + 1);
$triggers[] = view(
'rules.partials.trigger',

View File

@@ -178,7 +178,7 @@ class RuleGroupController extends Controller
$this->dispatch($job);
// Tell the user that the job is queued
Session::flash('success', strval(trans('firefly.executed_group_on_existing_transactions', ['title' => $ruleGroup->title])));
Session::flash('success', strval(trans('firefly.applied_rule_group_selection', ['title' => $ruleGroup->title])));
return redirect()->route('rules.index');
}
@@ -197,7 +197,7 @@ class RuleGroupController extends Controller
$checkedAccounts = array_keys($accountList);
$first = session('first')->format('Y-m-d');
$today = Carbon::create()->format('Y-m-d');
$subTitle = (string)trans('firefly.execute_on_existing_transactions');
$subTitle = (string)trans('firefly.apply_rule_group_selection', ['title' => $ruleGroup->title]);
return view('rules.rule-group.select-transactions', compact('checkedAccounts', 'accountList', 'first', 'today', 'ruleGroup', 'subTitle'));
}
@@ -246,14 +246,14 @@ class RuleGroupController extends Controller
* @param RuleGroupRepositoryInterface $repository
* @param RuleGroup $ruleGroup
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function update(RuleGroupFormRequest $request, RuleGroupRepositoryInterface $repository, RuleGroup $ruleGroup)
{
$data = [
'title' => $request->input('title'),
'description' => $request->input('description'),
'active' => intval($request->input('active')) == 1,
'active' => intval($request->input('active')) === 1,
];
$repository->update($ruleGroup, $data);

View File

@@ -15,7 +15,7 @@ namespace FireflyIII\Http\Controllers;
use FireflyIII\Support\Search\SearchInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Response;
use View;
/**
@@ -51,47 +51,29 @@ class SearchController extends Controller
*/
public function index(Request $request, SearchInterface $searcher)
{
// yes, hard coded values:
$minSearchLen = 1;
$limit = 20;
$fullQuery = $request->get('q');
// ui stuff:
$subTitle = '';
// parse search terms:
$searcher->parseQuery($fullQuery);
$query = $searcher->getWordsAsString();
$subTitle = trans('breadcrumbs.search_result', ['query' => $query]);
// query stuff
$query = null;
$result = [];
$rawQuery = $request->get('q');
$hasModifiers = true;
$modifiers = [];
return view('search.index', compact('query', 'fullQuery', 'subTitle'));
}
if (!is_null($request->get('q')) && strlen($request->get('q')) >= $minSearchLen) {
// parse query, find modifiers:
// set limit for search
$searcher->setLimit($limit);
$searcher->parseQuery($request->get('q'));
public function search(Request $request, SearchInterface $searcher)
{
$fullQuery = $request->get('query');
$transactions = $searcher->searchTransactions();
$accounts = new Collection;
$categories = new Collection;
$tags = new Collection;
$budgets = new Collection;
// parse search terms:
$searcher->parseQuery($fullQuery);
$searcher->setLimit(20);
$transactions = $searcher->searchTransactions();
$html = view('search.search', compact('transactions'))->render();
// no special search thing?
if (!$searcher->hasModifiers()) {
$hasModifiers = false;
$accounts = $searcher->searchAccounts();
$categories = $searcher->searchCategories();
$budgets = $searcher->searchBudgets();
$tags = $searcher->searchTags();
}
$query = $searcher->getWordsAsString();
$subTitle = trans('firefly.search_results_for', ['query' => $query]);
$result = ['transactions' => $transactions, 'accounts' => $accounts, 'categories' => $categories, 'budgets' => $budgets, 'tags' => $tags];
return Response::json(['count' => $transactions->count(), 'html' => $html]);
}
return view('search.index', compact('rawQuery', 'hasModifiers', 'modifiers', 'subTitle', 'limit', 'query', 'result'));
}
}

View File

@@ -15,6 +15,7 @@ namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Http\Requests\TagFormRequest;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
@@ -235,7 +236,7 @@ class TagController extends Controller
// default values:
$subTitle = $tag->tag;
$subTitleIcon = 'fa-tag';
$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);
$count = 0;
$loop = 0;
@@ -245,6 +246,7 @@ class TagController extends Controller
$periods = new Collection;
$apiKey = env('GOOGLE_MAPS_API_KEY', '');
$sum = '0';
$path = 'tags/show/' . $tag->id;
// prep for "all" view.
@@ -253,6 +255,7 @@ class TagController extends Controller
$start = $repository->firstUseDate($tag);
$end = new Carbon;
$sum = $repository->sumOfTag($tag);
$path = 'tags/show/' . $tag->id . '/all';
}
// prep for "specific date" view.
@@ -282,15 +285,15 @@ class TagController extends Controller
Log::info('Now at tag loop start.');
while ($count === 0 && $loop < 3) {
$loop++;
Log::info('Count is zero, search for journals.');
Log::info(sprintf('Count is zero, search for journals between %s and %s (pagesize %d, page %d).', $start, $end, $pageSize, $page));
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
->setTag($tag)->withBudgetInformation()->withCategoryInformation();
->setTag($tag)->withBudgetInformation()->withCategoryInformation()->removeFilter(InternalTransferFilter::class);
$journals = $collector->getPaginatedJournals();
$journals->setPath('tags/show/' . $tag->id);
$journals->setPath($path);
$count = $journals->getCollection()->count();
if ($count === 0) {
if ($count === 0 && $loop < 3) {
$start->subDay();
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfPeriod($start, $range);
@@ -298,7 +301,7 @@ class TagController extends Controller
}
}
if ($moment != 'all' && $loop > 1) {
if ($moment !== 'all' && $loop > 1) {
$subTitle = trans(
'firefly.journals_in_period_for_tag',
['tag' => $tag->tag, 'start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]

View File

@@ -174,14 +174,23 @@ class ConvertController extends Controller
switch ($joined) {
default:
throw new FireflyException('Cannot handle ' . $joined); // @codeCoverageIgnore
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT: // one
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT:
// one
$destination = $sourceAccount;
break;
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER: // two
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER:
// two
$destination = $accountRepository->find(intval($data['destination_account_asset']));
break;
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL: // three
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL: // five
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL:
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL:
// three and five
if ($data['destination_account_expense'] === '') {
// destination is a cash account.
$destination = $accountRepository->getCashAccount();
return $destination;
}
$data = [
'name' => $data['destination_account_expense'],
'accountType' => 'expense',
@@ -191,8 +200,9 @@ class ConvertController extends Controller
];
$destination = $accountRepository->store($data);
break;
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER: // four
case TransactionType::TRANSFER . '-' . TransactionType::DEPOSIT: // six
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER:
case TransactionType::TRANSFER . '-' . TransactionType::DEPOSIT:
// four and six
$destination = $destinationAccount;
break;
}
@@ -219,8 +229,16 @@ class ConvertController extends Controller
switch ($joined) {
default:
throw new FireflyException('Cannot handle ' . $joined); // @codeCoverageIgnore
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT: // one
case TransactionType::TRANSFER . '-' . TransactionType::DEPOSIT: // six
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT:
case TransactionType::TRANSFER . '-' . TransactionType::DEPOSIT:
if ($data['source_account_revenue'] === '') {
// destination is a cash account.
$destination = $accountRepository->getCashAccount();
return $destination;
}
$data = [
'name' => $data['source_account_revenue'],
'accountType' => 'revenue',
@@ -230,14 +248,14 @@ class ConvertController extends Controller
];
$source = $accountRepository->store($data);
break;
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER: // two
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL: // five
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER:
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL:
$source = $sourceAccount;
break;
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL: // three
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL:
$source = $destinationAccount;
break;
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER: // four
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER:
$source = $accountRepository->find(intval($data['source_account_asset']));
break;
}

View File

@@ -19,6 +19,7 @@ use FireflyIII\Http\Requests\MassDeleteJournalRequest;
use FireflyIII\Http\Requests\MassEditJournalRequest;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
@@ -85,7 +86,7 @@ class MassController extends Controller
foreach ($ids as $journalId) {
/** @var TransactionJournal $journal */
$journal = $repository->find(intval($journalId));
if (!is_null($journal->id) && $journalId == $journal->id) {
if (!is_null($journal->id) && $journalId === $journal->id) {
$set->push($journal);
}
}
@@ -126,8 +127,7 @@ class MassController extends Controller
$budgetRepository = app(BudgetRepositoryInterface::class);
$budgets = $budgetRepository->getBudgets();
// skip transactions that have multiple destinations
// or multiple sources:
// skip transactions that have multiple destinations, multiple sources or are an opening balance.
$filtered = new Collection;
$messages = [];
/**
@@ -135,8 +135,8 @@ class MassController extends Controller
* @var TransactionJournal $journal
*/
foreach ($journals as $index => $journal) {
$sources = $journal->sourceAccountList($journal);
$destinations = $journal->destinationAccountList($journal);
$sources = $journal->sourceAccountList();
$destinations = $journal->destinationAccountList();
if ($sources->count() > 1) {
$messages[] = trans('firefly.cannot_edit_multiple_source', ['description' => $journal->description, 'id' => $journal->id]);
continue;
@@ -146,6 +146,10 @@ class MassController extends Controller
$messages[] = trans('firefly.cannot_edit_multiple_dest', ['description' => $journal->description, 'id' => $journal->id]);
continue;
}
if ($journal->transactionType->type === TransactionType::OPENING_BALANCE) {
$messages[] = trans('firefly.cannot_edit_opening_balance');
continue;
}
$filtered->push($journal);
}
@@ -158,13 +162,21 @@ class MassController extends Controller
Session::flash('gaEventCategory', 'transactions');
Session::flash('gaEventAction', 'mass-edit');
// set some values to be used in the edit routine:
// collect some useful meta data for the mass edit:
$filtered->each(
function (TransactionJournal $journal) {
$journal->amount = $journal->amountPositive();
$sources = $journal->sourceAccountList();
$destinations = $journal->destinationAccountList();
$journal->transaction_count = $journal->transactions()->count();
$transaction = $journal->positiveTransaction();
$currency = $transaction->transactionCurrency;
$journal->amount = floatval($transaction->amount);
$sources = $journal->sourceAccountList();
$destinations = $journal->destinationAccountList();
$journal->transaction_count = $journal->transactions()->count();
$journal->currency_symbol = $currency->symbol;
$journal->transaction_type_type = $journal->transactionType->type;
$journal->foreign_amount = floatval($transaction->foreign_amount);
$journal->foreign_currency = $transaction->foreignCurrency;
if (!is_null($sources->first())) {
$journal->source_account_id = $sources->first()->id;
$journal->source_account_name = $sources->first()->editname;
@@ -201,13 +213,17 @@ class MassController extends Controller
if ($journal) {
// get optional fields:
$what = strtolower($journal->transactionTypeStr());
$sourceAccountId = $request->get('source_account_id')[$journal->id] ?? 0;
$sourceAccountId = $request->get('source_account_id')[$journal->id] ?? 0;
$sourceAccountName = $request->get('source_account_name')[$journal->id] ?? '';
$destAccountId = $request->get('destination_account_id')[$journal->id] ?? 0;
$destAccountId = $request->get('destination_account_id')[$journal->id] ?? 0;
$destAccountName = $request->get('destination_account_name')[$journal->id] ?? '';
$budgetId = $request->get('budget_id')[$journal->id] ?? 0;
$budgetId = $request->get('budget_id')[$journal->id] ?? 0;
$category = $request->get('category')[$journal->id];
$tags = $journal->tags->pluck('tag')->toArray();
$amount = round($request->get('amount')[$journal->id], 12);
$foreignAmount = isset($request->get('foreign_amount')[$journal->id]) ? round($request->get('foreign_amount')[$journal->id], 12) : null;
$foreignCurrencyId = isset($request->get('foreign_currency_id')[$journal->id]) ?
intval($request->get('foreign_currency_id')[$journal->id]) : null;
// build data array
$data = [
@@ -218,16 +234,19 @@ class MassController extends Controller
'source_account_name' => $sourceAccountName,
'destination_account_id' => intval($destAccountId),
'destination_account_name' => $destAccountName,
'amount' => round($request->get('amount')[$journal->id], 12),
'currency_id' => $journal->transaction_currency_id,
'amount' => $foreignAmount,
'native_amount' => $amount,
'source_amount' => $amount,
'date' => new Carbon($request->get('date')[$journal->id]),
'interest_date' => $journal->interest_date,
'book_date' => $journal->book_date,
'process_date' => $journal->process_date,
'budget_id' => intval($budgetId),
'currency_id' => $foreignCurrencyId,
'foreign_amount' => $foreignAmount,
'destination_amount' => $foreignAmount,
'category' => $category,
'tags' => $tags,
];
// call repository update function.
$repository->update($journal, $data);
@@ -235,6 +254,7 @@ class MassController extends Controller
$count++;
}
}
}
Preferences::mark();
Session::flash('success', trans('firefly.mass_edited_transactions_success', ['amount' => $count]));

View File

@@ -21,6 +21,7 @@ use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\JournalFormRequest;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -54,6 +55,9 @@ class SingleController extends Controller
/** @var PiggyBankRepositoryInterface */
private $piggyBanks;
/** @var JournalRepositoryInterface */
private $repository;
/**
*
*/
@@ -74,6 +78,7 @@ class SingleController extends Controller
$this->piggyBanks = app(PiggyBankRepositoryInterface::class);
$this->attachments = app(AttachmentHelperInterface::class);
$this->currency = app(CurrencyRepositoryInterface::class);
$this->repository = app(JournalRepositoryInterface::class);
View::share('title', trans('firefly.transactions'));
View::share('mainTitleIcon', 'fa-repeat');
@@ -93,27 +98,35 @@ class SingleController extends Controller
$category = $journal->categories()->first();
$categoryName = is_null($category) ? '' : $category->name;
$tags = join(',', $journal->tags()->get()->pluck('tag')->toArray());
/** @var Transaction $transaction */
$transaction = $journal->transactions()->first();
$amount = Steam::positive($transaction->amount);
$foreignAmount = is_null($transaction->foreign_amount) ? null : Steam::positive($transaction->foreign_amount);
$preFilled = [
'description' => $journal->description,
'source_account_id' => $source->id,
'source_account_name' => $source->name,
'destination_account_id' => $destination->id,
'destination_account_name' => $destination->name,
'amount' => $journal->amountPositive(),
'date' => $journal->date->format('Y-m-d'),
'budget_id' => $budgetId,
'category' => $categoryName,
'tags' => $tags,
'interest_date' => $journal->getMeta('interest_date'),
'book_date' => $journal->getMeta('book_date'),
'process_date' => $journal->getMeta('process_date'),
'due_date' => $journal->getMeta('due_date'),
'payment_date' => $journal->getMeta('payment_date'),
'invoice_date' => $journal->getMeta('invoice_date'),
'internal_reference' => $journal->getMeta('internal_reference'),
'notes' => $journal->getMeta('notes'),
'description' => $journal->description,
'source_account_id' => $source->id,
'source_account_name' => $source->name,
'destination_account_id' => $destination->id,
'destination_account_name' => $destination->name,
'amount' => $amount,
'source_amount' => $amount,
'destination_amount' => $foreignAmount,
'foreign_amount' => $foreignAmount,
'native_amount' => $foreignAmount,
'amount_currency_id_amount' => $transaction->foreign_currency_id ?? 0,
'date' => $journal->date->format('Y-m-d'),
'budget_id' => $budgetId,
'category' => $categoryName,
'tags' => $tags,
'interest_date' => $journal->getMeta('interest_date'),
'book_date' => $journal->getMeta('book_date'),
'process_date' => $journal->getMeta('process_date'),
'due_date' => $journal->getMeta('due_date'),
'payment_date' => $journal->getMeta('payment_date'),
'invoice_date' => $journal->getMeta('invoice_date'),
'internal_reference' => $journal->getMeta('internal_reference'),
'notes' => $journal->getMeta('notes'),
];
Session::flash('preFilled', $preFilled);
@@ -161,7 +174,7 @@ class SingleController extends Controller
*
* @param TransactionJournal $journal
*
* @return View
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*/
public function delete(TransactionJournal $journal)
{
@@ -191,7 +204,7 @@ class SingleController extends Controller
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(JournalRepositoryInterface $repository, TransactionJournal $transactionJournal)
public function destroy(TransactionJournal $transactionJournal)
{
// @codeCoverageIgnoreStart
if ($this->isOpeningBalance($transactionJournal)) {
@@ -201,7 +214,7 @@ class SingleController extends Controller
$type = $transactionJournal->transactionTypeStr();
Session::flash('success', strval(trans('firefly.deleted_' . strtolower($type), ['description' => e($transactionJournal->description)])));
$repository->delete($transactionJournal);
$this->repository->delete($transactionJournal);
Preferences::mark();
@@ -220,10 +233,7 @@ class SingleController extends Controller
return $this->redirectToAccount($journal);
}
// @codeCoverageIgnoreEnd
$count = $journal->transactions()->count();
if ($count > 2) {
if ($this->isSplitJournal($journal)) {
return redirect(route('transactions.split.edit', [$journal->id]));
}
@@ -238,6 +248,8 @@ class SingleController extends Controller
$sourceAccounts = $journal->sourceAccountList();
$destinationAccounts = $journal->destinationAccountList();
$optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data;
$pTransaction = $journal->positiveTransaction();
$foreignCurrency = !is_null($pTransaction->foreignCurrency) ? $pTransaction->foreignCurrency : $pTransaction->transactionCurrency;
$preFilled = [
'date' => $journal->dateAsString(),
'interest_date' => $journal->dateAsString('interest_date'),
@@ -250,8 +262,6 @@ class SingleController extends Controller
'source_account_name' => $sourceAccounts->first()->edit_name,
'destination_account_id' => $destinationAccounts->first()->id,
'destination_account_name' => $destinationAccounts->first()->edit_name,
'amount' => $journal->amountPositive(),
'currency' => $journal->transactionCurrency,
// new custom fields:
'due_date' => $journal->dateAsString('due_date'),
@@ -260,30 +270,25 @@ class SingleController extends Controller
'interal_reference' => $journal->getMeta('internal_reference'),
'notes' => $journal->getMeta('notes'),
// exchange rate fields
'native_amount' => $journal->amountPositive(),
'native_currency' => $journal->transactionCurrency,
// amount fields
'amount' => $pTransaction->amount,
'source_amount' => $pTransaction->amount,
'native_amount' => $pTransaction->amount,
'destination_amount' => $pTransaction->foreign_amount,
'currency' => $pTransaction->transactionCurrency,
'source_currency' => $pTransaction->transactionCurrency,
'native_currency' => $pTransaction->transactionCurrency,
'foreign_currency' => $foreignCurrency,
'destination_currency' => $foreignCurrency,
];
// if user has entered a foreign currency, update some fields
$foreignCurrencyId = intval($journal->getMeta('foreign_currency_id'));
if ($foreignCurrencyId > 0) {
// update some fields in pre-filled.
// @codeCoverageIgnoreStart
$preFilled['amount'] = $journal->getMeta('foreign_amount');
$preFilled['currency'] = $this->currency->find(intval($journal->getMeta('foreign_currency_id')));
// @codeCoverageIgnoreEnd
// amounts for withdrawals and deposits:
// amount, native_amount, source_amount, destination_amount
if (($journal->isWithdrawal() || $journal->isDeposit()) && !is_null($pTransaction->foreign_amount)) {
$preFilled['amount'] = $pTransaction->foreign_amount;
$preFilled['currency'] = $pTransaction->foreignCurrency;
}
if ($journal->isWithdrawal() && $destinationAccounts->first()->accountType->type == AccountType::CASH) {
$preFilled['destination_account_name'] = '';
}
if ($journal->isDeposit() && $sourceAccounts->first()->accountType->type == AccountType::CASH) {
$preFilled['source_account_name'] = '';
}
Session::flash('preFilled', $preFilled);
Session::flash('gaEventCategory', 'transactions');
Session::flash('gaEventAction', 'edit-' . $what);
@@ -319,6 +324,7 @@ class SingleController extends Controller
return redirect(route('transactions.create', [$request->input('what')]))->withInput();
}
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
$this->attachments->saveAttachmentsForModel($journal, $files);
@@ -401,4 +407,20 @@ class SingleController extends Controller
// redirect to previous URL.
return redirect($this->getPreviousUri('transactions.edit.uri'));
}
/**
* @param TransactionJournal $journal
*
* @return bool
*/
private function isSplitJournal(TransactionJournal $journal): bool
{
$count = $this->repository->countTransactions($journal);
if ($count > 2) {
return true;
}
return false;
}
}

View File

@@ -93,7 +93,7 @@ class SplitController extends Controller
}
$uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size')));
$currencies = ExpandedForm::makeSelectList($this->currencies->get());
$currencies = $this->currencies->get();
$assetAccounts = ExpandedForm::makeSelectList($this->accounts->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]));
$optionalFields = Preferences::get('transaction_journal_optional_fields', [])->data;
$budgets = ExpandedForm::makeSelectListWithEmpty($this->budgets->getActiveBudgets());
@@ -130,7 +130,6 @@ class SplitController extends Controller
*/
public function update(Request $request, JournalRepositoryInterface $repository, TransactionJournal $journal)
{
if ($this->isOpeningBalance($journal)) {
return $this->redirectToAccount($journal);
}
@@ -179,7 +178,6 @@ class SplitController extends Controller
'journal_source_account_id' => $request->get('journal_source_account_id'),
'journal_source_account_name' => $request->get('journal_source_account_name'),
'journal_destination_account_id' => $request->get('journal_destination_account_id'),
'currency_id' => $request->get('currency_id'),
'what' => $request->get('what'),
'date' => $request->get('date'),
// all custom fields:
@@ -218,10 +216,9 @@ class SplitController extends Controller
'journal_source_account_id' => $request->old('journal_source_account_id', $sourceAccounts->first()->id),
'journal_source_account_name' => $request->old('journal_source_account_name', $sourceAccounts->first()->name),
'journal_destination_account_id' => $request->old('journal_destination_account_id', $destinationAccounts->first()->id),
'currency_id' => $request->old('currency_id', $journal->transaction_currency_id),
'destinationAccounts' => $destinationAccounts,
'what' => strtolower($journal->transactionTypeStr()),
'date' => $request->old('date', $journal->date),
'date' => $request->old('date', $journal->date->format('Y-m-d')),
'tags' => join(',', $journal->tags->pluck('tag')->toArray()),
// all custom fields:
@@ -253,14 +250,22 @@ class SplitController extends Controller
/** @var array $transaction */
foreach ($transactions as $index => $transaction) {
$set = [
'description' => $transaction['description'],
'source_account_id' => $transaction['source_account_id'],
'source_account_name' => $transaction['source_account_name'],
'destination_account_id' => $transaction['destination_account_id'],
'destination_account_name' => $transaction['destination_account_name'],
'amount' => round($transaction['destination_amount'], 12),
'budget_id' => isset($transaction['budget_id']) ? intval($transaction['budget_id']) : 0,
'category' => $transaction['category'],
'description' => $transaction['description'],
'source_account_id' => $transaction['source_account_id'],
'source_account_name' => $transaction['source_account_name'],
'destination_account_id' => $transaction['destination_account_id'],
'destination_account_name' => $transaction['destination_account_name'],
'amount' => round($transaction['destination_amount'], 12),
'budget_id' => isset($transaction['budget_id']) ? intval($transaction['budget_id']) : 0,
'category' => $transaction['category'],
'transaction_currency_id' => $transaction['transaction_currency_id'],
'transaction_currency_code' => $transaction['transaction_currency_code'],
'transaction_currency_symbol' => $transaction['transaction_currency_symbol'],
'foreign_amount' => round($transaction['foreign_destination_amount'], 12),
'foreign_currency_id' => $transaction['foreign_currency_id'],
'foreign_currency_code' => $transaction['foreign_currency_code'],
'foreign_currency_symbol' => $transaction['foreign_currency_symbol'],
];
// set initial category and/or budget:
@@ -294,8 +299,12 @@ class SplitController extends Controller
'destination_account_id' => $transaction['destination_account_id'] ?? 0,
'destination_account_name' => $transaction['destination_account_name'] ?? '',
'amount' => round($transaction['amount'] ?? 0, 12),
'foreign_amount' => !isset($transaction['foreign_amount']) ? null : round($transaction['foreign_amount'] ?? 0, 12),
'budget_id' => isset($transaction['budget_id']) ? intval($transaction['budget_id']) : 0,
'category' => $transaction['category'] ?? '',
'transaction_currency_id' => intval($transaction['transaction_currency_id']),
'foreign_currency_id' => $transaction['foreign_currency_id'] ?? null,
];
}
Log::debug(sprintf('Found %d splits in request data.', count($return)));

View File

@@ -16,8 +16,8 @@ namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Helpers\Filter\InternalTransferFilter;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalTaskerInterface;
use FireflyIII\Support\CacheProperties;
@@ -70,7 +70,7 @@ class TransactionController extends Controller
// default values:
$subTitleIcon = config('firefly.transactionIconsByWhat.' . $what);
$types = config('firefly.transactionTypesByWhat.' . $what);
$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);
$count = 0;
$loop = 0;
@@ -78,6 +78,7 @@ class TransactionController extends Controller
$start = null;
$end = null;
$periods = new Collection;
$path = '/transactions/' . $what;
// prep for "all" view.
if ($moment === 'all') {
@@ -85,12 +86,14 @@ class TransactionController extends Controller
$first = $repository->first();
$start = $first->date ?? new Carbon;
$end = new Carbon;
$path = '/transactions/' . $what . '/all/';
}
// prep for "specific date" view.
if (strlen($moment) > 0 && $moment !== 'all') {
$start = new Carbon($moment);
$end = Navigation::endOfPeriod($start, $range);
$path = '/transactions/' . $what . '/' . $moment;
$subTitle = trans(
'firefly.title_' . $what . '_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
@@ -115,12 +118,12 @@ class TransactionController extends Controller
Log::info('Count is zero, search for journals.');
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes($types)->setLimit($pageSize)->setPage($page)->withOpposingAccount()
->disableInternalFilter();
$collector->setAllAssetAccounts()->setRange($start, $end)->setTypes($types)->setLimit($pageSize)->setPage($page)->withOpposingAccount();
$collector->removeFilter(InternalTransferFilter::class);
$journals = $collector->getPaginatedJournals();
$journals->setPath('/budgets/list/no-budget');
$journals->setPath($path);
$count = $journals->getCollection()->count();
if ($count === 0) {
if ($count === 0 && $loop < 3) {
$start->subDay();
$start = Navigation::startOfPeriod($start, $range);
$end = Navigation::endOfPeriod($start, $range);
@@ -128,7 +131,7 @@ class TransactionController extends Controller
}
}
if ($moment != 'all' && $loop > 1) {
if ($moment !== 'all' && $loop > 1) {
$subTitle = trans(
'firefly.title_' . $what . '_between',
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
@@ -170,7 +173,7 @@ class TransactionController extends Controller
* @param TransactionJournal $journal
* @param JournalTaskerInterface $tasker
*
* @return View
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*/
public function show(TransactionJournal $journal, JournalTaskerInterface $tasker)
{
@@ -178,21 +181,12 @@ class TransactionController extends Controller
return $this->redirectToAccount($journal);
}
$events = $tasker->getPiggyBankEvents($journal);
$transactions = $tasker->getTransactionsOverview($journal);
$what = strtolower($journal->transaction_type_type ?? $journal->transactionType->type);
$subTitle = trans('firefly.' . $what) . ' "' . e($journal->description) . '"';
$foreignCurrency = null;
$events = $tasker->getPiggyBankEvents($journal);
$transactions = $tasker->getTransactionsOverview($journal);
$what = strtolower($journal->transaction_type_type ?? $journal->transactionType->type);
$subTitle = trans('firefly.' . $what) . ' "' . e($journal->description) . '"';
if ($journal->hasMeta('foreign_currency_id')) {
// @codeCoverageIgnoreStart
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$foreignCurrency = $repository->find(intval($journal->getMeta('foreign_currency_id')));
// @codeCoverageIgnoreEnd
}
return view('transactions.show', compact('journal', 'events', 'subTitle', 'what', 'transactions', 'foreignCurrency'));
return view('transactions.show', compact('journal', 'events', 'subTitle', 'what', 'transactions'));
}
@@ -234,7 +228,8 @@ class TransactionController extends Controller
// count journals without budget in this period:
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withOpposingAccount()->setTypes($types)->disableInternalFilter();
$collector->setAllAssetAccounts()->setRange($end, $currentEnd)->withOpposingAccount()->setTypes($types);
$collector->removeFilter(InternalTransferFilter::class);
$set = $collector->getJournals();
$sum = $set->sum('transaction_amount');
$journals = $set->count();

View File

@@ -38,19 +38,19 @@ class AccountFormRequest extends Request
public function getAccountData(): array
{
return [
'name' => $this->string('name'),
'active' => $this->boolean('active'),
'accountType' => $this->string('what'),
'currency_id' => $this->integer('currency_id'),
'virtualBalance' => $this->float('virtualBalance'),
'iban' => $this->string('iban'),
'BIC' => $this->string('BIC'),
'accountNumber' => $this->string('accountNumber'),
'accountRole' => $this->string('accountRole'),
'openingBalance' => $this->float('openingBalance'),
'openingBalanceDate' => $this->date('openingBalanceDate'),
'ccType' => $this->string('ccType'),
'ccMonthlyPaymentDate' => $this->string('ccMonthlyPaymentDate'),
'name' => $this->string('name'),
'active' => $this->boolean('active'),
'accountType' => $this->string('what'),
'currency_id' => $this->integer('currency_id'),
'virtualBalance' => $this->float('virtualBalance'),
'iban' => $this->string('iban'),
'BIC' => $this->string('BIC'),
'accountNumber' => $this->string('accountNumber'),
'accountRole' => $this->string('accountRole'),
'openingBalance' => $this->float('openingBalance'),
'openingBalanceDate' => $this->date('openingBalanceDate'),
'ccType' => $this->string('ccType'),
'ccMonthlyPaymentDate' => $this->string('ccMonthlyPaymentDate'),
];
}

View File

@@ -38,8 +38,9 @@ class ImportUploadRequest extends Request
$types = array_keys(config('firefly.import_formats'));
return [
'import_file' => 'required|file',
'import_file_type' => 'required|in:' . join(',', $types),
'import_file' => 'required|file',
'import_file_type' => 'required|in:' . join(',', $types),
'configuration_file' => 'file',
];
}

View File

@@ -37,7 +37,7 @@ class TagFormRequest extends Request
*/
public function collectTagData(): array
{
if ($this->get('setTag') == 'true') {
if ($this->get('setTag') === 'true') {
$latitude = $this->string('latitude');
$longitude = $this->string('longitude');
$zoomLevel = $this->integer('zoomLevel');

View File

@@ -10,6 +10,7 @@
*/
declare(strict_types=1);
use Carbon\Carbon;
use DaveJamesMiller\Breadcrumbs\Generator as BreadCrumbGenerator;
use FireflyIII\Exceptions\FireflyException;
@@ -78,10 +79,10 @@ Breadcrumbs::register(
$breadcrumbs->push(trans('firefly.everything'), route('accounts.show', [$account->id, 'all']));
}
// when is specific period or when empty:
if ($moment !== 'all') {
if ($moment !== 'all' && $moment !== '(nothing)') {
$title = trans(
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
);
$breadcrumbs->push($title, route('accounts.show', [$account->id, $moment, $start, $end]));
}
@@ -91,7 +92,7 @@ Breadcrumbs::register(
Breadcrumbs::register(
'accounts.delete', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
$breadcrumbs->parent('accounts.show', $account, '', new Carbon, new Carbon);
$breadcrumbs->parent('accounts.show', $account, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->push(trans('firefly.delete_account', ['name' => e($account->name)]), route('accounts.delete', [$account->id]));
}
);
@@ -99,7 +100,7 @@ Breadcrumbs::register(
Breadcrumbs::register(
'accounts.edit', function (BreadCrumbGenerator $breadcrumbs, Account $account) {
$breadcrumbs->parent('accounts.show', $account, '', new Carbon, new Carbon);
$breadcrumbs->parent('accounts.show', $account, '(nothing)', new Carbon, new Carbon);
$what = config('firefly.shortNamesByFullName.' . $account->accountType->type);
$breadcrumbs->push(trans('firefly.edit_' . $what . '_account', ['name' => e($account->name)]), route('accounts.edit', [$account->id]));
@@ -257,8 +258,8 @@ Breadcrumbs::register(
if ($moment === 'all') {
$breadcrumbs->push(trans('firefly.everything'), route('budgets.no-budget', ['all']));
}
// when is specific period:
if ($moment !== 'all') {
// when is specific period or when empty:
if ($moment !== 'all' && $moment !== '(nothing)') {
$title = trans(
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
@@ -312,13 +313,13 @@ Breadcrumbs::register(
Breadcrumbs::register(
'categories.edit', function (BreadCrumbGenerator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.show', $category, '', new Carbon, new Carbon);
$breadcrumbs->parent('categories.show', $category, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->push(trans('firefly.edit_category', ['name' => e($category->name)]), route('categories.edit', [$category->id]));
}
);
Breadcrumbs::register(
'categories.delete', function (BreadCrumbGenerator $breadcrumbs, Category $category) {
$breadcrumbs->parent('categories.show', $category, '', new Carbon, new Carbon);
$breadcrumbs->parent('categories.show', $category, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->push(trans('firefly.delete_category', ['name' => e($category->name)]), route('categories.delete', [$category->id]));
}
);
@@ -333,8 +334,8 @@ Breadcrumbs::register(
if ($moment === 'all') {
$breadcrumbs->push(trans('firefly.everything'), route('categories.show', [$category->id, 'all']));
}
// when is specific period:
if ($moment !== 'all') {
// when is specific period or when empty:
if ($moment !== 'all' && $moment !== '(nothing)') {
$title = trans(
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
@@ -354,8 +355,8 @@ Breadcrumbs::register(
if ($moment === 'all') {
$breadcrumbs->push(trans('firefly.everything'), route('categories.no-category', ['all']));
}
// when is specific period:
if ($moment !== 'all') {
// when is specific period or when empty:
if ($moment !== 'all' && $moment !== '(nothing)') {
$title = trans(
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
@@ -469,26 +470,20 @@ Breadcrumbs::register(
$breadcrumbs->push(trans('firefly.import'), route('import.index'));
}
);
Breadcrumbs::register(
'import.complete', function (BreadCrumbGenerator $breadcrumbs, ImportJob $job) {
$breadcrumbs->parent('import.index');
$breadcrumbs->push(trans('firefly.bread_crumb_import_complete', ['key' => $job->key]), route('import.complete', [$job->key]));
}
);
Breadcrumbs::register(
'import.configure', function (BreadCrumbGenerator $breadcrumbs, ImportJob $job) {
$breadcrumbs->parent('import.index');
$breadcrumbs->push(trans('firefly.bread_crumb_configure_import', ['key' => $job->key]), route('import.configure', [$job->key]));
$breadcrumbs->push(trans('firefly.import_config_sub_title', ['key' => $job->key]), route('import.configure', [$job->key]));
}
);
Breadcrumbs::register(
'import.finished', function (BreadCrumbGenerator $breadcrumbs, ImportJob $job) {
'import.status', function (BreadCrumbGenerator $breadcrumbs, ImportJob $job) {
$breadcrumbs->parent('import.index');
$breadcrumbs->push(trans('firefly.bread_crumb_import_finished', ['key' => $job->key]), route('import.finished', [$job->key]));
$breadcrumbs->push(trans('firefly.import_status_bread_crumb', ['key' => $job->key]), route('import.status', [$job->key]));
}
);
/**
* PREFERENCES
*/
@@ -686,7 +681,7 @@ Breadcrumbs::register(
Breadcrumbs::register(
'search.index', function (BreadCrumbGenerator $breadcrumbs, $query) {
$breadcrumbs->parent('home');
$breadcrumbs->push(trans('breadcrumbs.searchResult', ['query' => e($query)]), route('search.index'));
$breadcrumbs->push(trans('breadcrumbs.search_result', ['query' => e($query)]), route('search.index'));
}
);
@@ -710,14 +705,14 @@ Breadcrumbs::register(
Breadcrumbs::register(
'tags.edit', function (BreadCrumbGenerator $breadcrumbs, Tag $tag) {
$breadcrumbs->parent('tags.show', $tag, '', new Carbon, new Carbon);
$breadcrumbs->parent('tags.show', $tag, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->push(trans('breadcrumbs.edit_tag', ['tag' => e($tag->tag)]), route('tags.edit', [$tag->id]));
}
);
Breadcrumbs::register(
'tags.delete', function (BreadCrumbGenerator $breadcrumbs, Tag $tag) {
$breadcrumbs->parent('tags.show', $tag, '', new Carbon, new Carbon);
$breadcrumbs->parent('tags.show', $tag, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->push(trans('breadcrumbs.delete_tag', ['tag' => e($tag->tag)]), route('tags.delete', [$tag->id]));
}
);
@@ -726,16 +721,17 @@ Breadcrumbs::register(
Breadcrumbs::register(
'tags.show', function (BreadCrumbGenerator $breadcrumbs, Tag $tag, string $moment, Carbon $start, Carbon $end) {
$breadcrumbs->parent('tags.index');
$breadcrumbs->push(e($tag->tag), route('tags.show', [$tag->id], $moment));
$breadcrumbs->push(e($tag->tag), route('tags.show', [$tag->id, $moment]));
if ($moment === 'all') {
$breadcrumbs->push(trans('firefly.everything'), route('tags.show', [$tag->id], $moment));
$breadcrumbs->push(trans('firefly.everything'), route('tags.show', [$tag->id, $moment]));
}
if ($moment !== 'all') {
// when is specific period or when empty:
if ($moment !== 'all' && $moment !== '(nothing)') {
$title = trans(
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
);
$breadcrumbs->push($title, route('tags.show', [$tag->id], $moment));
$breadcrumbs->push($title, route('tags.show', [$tag->id, $moment]));
}
}
);
@@ -753,8 +749,8 @@ Breadcrumbs::register(
$breadcrumbs->push(trans('firefly.everything'), route('transactions.index', [$what, 'all']));
}
// when is specific period:
if ($moment !== 'all') {
// when is specific period or when empty:
if ($moment !== 'all' && $moment !== '(nothing)') {
$title = trans(
'firefly.between_dates_breadcrumb', ['start' => $start->formatLocalized(strval(trans('config.month_and_day'))),
'end' => $end->formatLocalized(strval(trans('config.month_and_day')))]
@@ -767,7 +763,7 @@ Breadcrumbs::register(
Breadcrumbs::register(
'transactions.create', function (BreadCrumbGenerator $breadcrumbs, string $what) {
$breadcrumbs->parent('transactions.index', $what, '', new Carbon, new Carbon);
$breadcrumbs->parent('transactions.index', $what, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->push(trans('breadcrumbs.create_' . e($what)), route('transactions.create', [$what]));
}
);
@@ -789,7 +785,7 @@ Breadcrumbs::register(
'transactions.show', function (BreadCrumbGenerator $breadcrumbs, TransactionJournal $journal) {
$what = strtolower($journal->transactionType->type);
$breadcrumbs->parent('transactions.index', $what, '', new Carbon, new Carbon);
$breadcrumbs->parent('transactions.index', $what, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->push($journal->description, route('transactions.show', [$journal->id]));
}
);
@@ -814,7 +810,7 @@ Breadcrumbs::register(
if ($journals->count() > 0) {
$journalIds = $journals->pluck('id')->toArray();
$what = strtolower($journals->first()->transactionType->type);
$breadcrumbs->parent('transactions.index', $what, '', new Carbon, new Carbon);
$breadcrumbs->parent('transactions.index', $what, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.edit', $journalIds));
return;
@@ -829,7 +825,7 @@ Breadcrumbs::register(
$journalIds = $journals->pluck('id')->toArray();
$what = strtolower($journals->first()->transactionType->type);
$breadcrumbs->parent('transactions.index', $what, '', new Carbon, new Carbon);
$breadcrumbs->parent('transactions.index', $what, '(nothing)', new Carbon, new Carbon);
$breadcrumbs->push(trans('firefly.mass_edit_journals'), route('transactions.mass.delete', $journalIds));
}
);

View File

@@ -0,0 +1,65 @@
<?php
/**
* ConfiguratorInterface.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\Import\Configurator;
use FireflyIII\Models\ImportJob;
/**
* Interface ConfiguratorInterface
*
* @package FireflyIII\Import\Configurator
*/
interface ConfiguratorInterface
{
/**
* ConfiguratorInterface constructor.
*/
public function __construct();
/**
* Store any data from the $data array into the job.
*
* @param array $data
*
* @return bool
*/
public function configureJob(array $data): bool;
/**
* Return the data required for the next step in the job configuration.
*
* @return array
*/
public function getNextData(): array;
/**
* Returns the view of the next step in the job configuration.
*
* @return string
*/
public function getNextView(): string;
/**
* Returns true when the initial configuration for this job is complete.
*
* @return bool
*/
public function isJobConfigured(): bool;
/**
* @param ImportJob $job
*
* @return void
*/
public function setJob(ImportJob $job);
}

View File

@@ -0,0 +1,159 @@
<?php
/**
* CsvConfigurator.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\Import\Configurator;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Support\Import\Configuration\ConfigurationInterface;
use FireflyIII\Support\Import\Configuration\Csv\Initial;
use FireflyIII\Support\Import\Configuration\Csv\Map;
use FireflyIII\Support\Import\Configuration\Csv\Roles;
use Log;
/**
* Class CsvConfigurator
*
* @package FireflyIII\Import\Configurator
*/
class CsvConfigurator implements ConfiguratorInterface
{
private $job;
/**
* ConfiguratorInterface constructor.
*/
public function __construct()
{
}
/**
* Store any data from the $data array into the job.
*
* @param array $data
*
* @return bool
* @throws FireflyException
*/
public function configureJob(array $data): bool
{
$class = $this->getConfigurationClass();
$job = $this->job;
/** @var ConfigurationInterface $object */
$object = new $class($this->job);
$object->setJob($job);
return $object->storeConfiguration($data);
}
/**
* Return the data required for the next step in the job configuration.
*
* @return array
* @throws FireflyException
*/
public function getNextData(): array
{
$class = $this->getConfigurationClass();
$job = $this->job;
/** @var ConfigurationInterface $object */
$object = app($class);
$object->setJob($job);
return $object->getData();
}
/**
* @return string
* @throws FireflyException
*/
public function getNextView(): string
{
if (!$this->job->configuration['initial-config-complete']) {
return 'import.csv.initial';
}
if (!$this->job->configuration['column-roles-complete']) {
return 'import.csv.roles';
}
if (!$this->job->configuration['column-mapping-complete']) {
return 'import.csv.map';
}
throw new FireflyException('No view for state');
}
/**
* @return bool
*/
public function isJobConfigured(): bool
{
$config = $this->job->configuration;
$config['initial-config-complete'] = $config['initial-config-complete'] ?? false;
$config['column-roles-complete'] = $config['column-roles-complete'] ?? false;
$config['column-mapping-complete'] = $config['column-mapping-complete'] ?? false;
$this->job->configuration = $config;
$this->job->save();
if ($this->job->configuration['initial-config-complete']
&& $this->job->configuration['column-roles-complete']
&& $this->job->configuration['column-mapping-complete']
) {
return true;
}
return false;
}
/**
* @param ImportJob $job
*/
public function setJob(ImportJob $job)
{
$this->job = $job;
if (is_null($this->job->configuration) || count($this->job->configuration) === 0) {
Log::debug(sprintf('Gave import job %s initial configuration.', $this->job->key));
$this->job->configuration = config('csv.default_config');
$this->job->save();
}
}
/**
* @return string
* @throws FireflyException
*/
private function getConfigurationClass(): string
{
$class = false;
switch (true) {
case (!$this->job->configuration['initial-config-complete']):
$class = Initial::class;
break;
case (!$this->job->configuration['column-roles-complete']):
$class = Roles::class;
break;
case (!$this->job->configuration['column-mapping-complete']):
$class = Map::class;
break;
default:
break;
}
if ($class === false || strlen($class) === 0) {
throw new FireflyException('Cannot handle current job state in getConfigurationClass().');
}
if (!class_exists($class)) {
throw new FireflyException(sprintf('Class %s does not exist in getConfigurationClass().', $class));
}
return $class;
}
}

View File

@@ -1,69 +0,0 @@
<?php
/**
* AccountId.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\Import\Converter;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Log;
/**
* Class AccountId
*
* @package FireflyIII\Import\Converter
*/
class AccountId extends BasicConverter implements ConverterInterface
{
/**
* @param $value
*
* @return Account
*/
public function convert($value)
{
$value = intval(trim($value));
Log::debug('Going to convert using AssetAccountId', ['value' => $value]);
if ($value === 0) {
$this->setCertainty(0);
return new Account;
}
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user);
if (isset($this->mapping[$value])) {
Log::debug('Found account in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]);
$account = $repository->find(intval($this->mapping[$value]));
if (!is_null($account->id)) {
Log::debug('Found account by ID', ['id' => $account->id]);
$this->setCertainty(100);
return $account;
}
}
$account = $repository->find($value);// not mapped? Still try to find it first:
if (!is_null($account->id)) {
$this->setCertainty(90);
Log::debug('Found account by ID ', ['id' => $account->id]);
return $account;
}
$this->setCertainty(0); // should not really happen. If the ID does not match FF, what is FF supposed to do?
return new Account;
}
}

View File

@@ -18,7 +18,7 @@ namespace FireflyIII\Import\Converter;
*
* @package FireflyIII\Import\Converter
*/
class Amount extends BasicConverter implements ConverterInterface
class Amount implements ConverterInterface
{
/**
@@ -28,18 +28,18 @@ class Amount extends BasicConverter implements ConverterInterface
*
* @param $value
*
* @return float
* @return string
*/
public function convert($value): float
public function convert($value): string
{
$len = strlen($value);
$decimalPosition = $len - 3;
$decimal = null;
if (($len > 2 && $value{$decimalPosition} == '.') || ($len > 2 && strpos($value, '.') > $decimalPosition)) {
if (($len > 2 && $value{$decimalPosition} === '.') || ($len > 2 && strpos($value, '.') > $decimalPosition)) {
$decimal = '.';
}
if ($len > 2 && $value{$decimalPosition} == ',') {
if ($len > 2 && $value{$decimalPosition} === ',') {
$decimal = ',';
}
@@ -59,10 +59,7 @@ class Amount extends BasicConverter implements ConverterInterface
$value = str_replace($search, '', $value);
}
$this->setCertainty(90);
return round(floatval($value), 12);
return strval(round(floatval($value), 12));
}
}

View File

@@ -1,87 +0,0 @@
<?php
/**
* AssetAccountIban.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\Import\Converter;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Log;
/**
* Class AssetAccountIban
*
* @package FireflyIII\Import\Converter
*/
class AssetAccountIban extends BasicConverter implements ConverterInterface
{
/**
* @param $value
*
* @return Account
*/
public function convert($value): Account
{
$value = trim($value);
Log::debug('Going to convert ', ['value' => $value]);
if (strlen($value) === 0) {
$this->setCertainty(0);
return new Account;
}
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user);
if (isset($this->mapping[$value])) {
Log::debug('Found account in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]);
$account = $repository->find(intval($this->mapping[$value]));
if (!is_null($account->id)) {
$this->setCertainty(100);
Log::debug('Found account by ID', ['id' => $account->id]);
return $account;
}
}
// not mapped? Still try to find it first:
$account = $repository->findByIban($value, [AccountType::ASSET]);
if (!is_null($account->id)) {
Log::debug('Found account by IBAN', ['id' => $account->id]);
$this->setCertainty(50);
return $account;
}
$account = $repository->store(
['name' => 'Asset account with IBAN ' . $value, 'iban' => $value, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0,
'active' => true, 'openingBalance' => 0]
);
if (is_null($account->id)) {
$this->setCertainty(0);
Log::info('Could not store new asset account by IBAN', $account->getErrors()->toArray());
return new Account;
}
$this->setCertainty(100);
return $account;
}
}

View File

@@ -1,90 +0,0 @@
<?php
/**
* AssetAccountName.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\Import\Converter;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Log;
/**
* Class AssetAccountName
*
* @package FireflyIII\Import\Converter
*/
class AssetAccountName extends BasicConverter implements ConverterInterface
{
/**
* @param $value
*
* @return Account
*/
public function convert($value)
{
$value = trim($value);
Log::debug('Going to convert using AssetAccountName', ['value' => $value]);
if (strlen($value) === 0) {
$this->setCertainty(0);
return new Account;
}
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user);
if (isset($this->mapping[$value])) {
Log::debug('Found account in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]);
$account = $repository->find(intval($this->mapping[$value]));
if (!is_null($account->id)) {
Log::debug('Found account by ID', ['id' => $account->id]);
$this->setCertainty(100);
return $account;
}
}
// not mapped? Still try to find it first:
$account = $repository->findByName($value, [AccountType::ASSET]);
if (!is_null($account->id)) {
Log::debug('Found asset account by name', ['value' => $value, 'id' => $account->id]);
return $account;
}
$account = $repository->store(
['name' => $value, 'iban' => null, 'openingBalance' => 0, 'user' => $this->user->id, 'accountType' => 'asset', 'virtualBalance' => 0,
'active' => true]
);
if (is_null($account->id)) {
$this->setCertainty(0);
Log::info('Could not store new asset account by name', $account->getErrors()->toArray());
return new Account;
}
$this->setCertainty(100);
Log::debug('Created new asset account ', ['name' => $account->name, 'id' => $account->id]);
return $account;
}
}

View File

@@ -1,96 +0,0 @@
<?php
/**
* AssetAccountNumber.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\Import\Converter;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Log;
/**
* Class AssetAccountNumber
*
* @package FireflyIII\Import\Converter
*/
class AssetAccountNumber extends BasicConverter implements ConverterInterface
{
/**
* @param $value
*
* @return Account
*/
public function convert($value)
{
$value = trim($value);
Log::debug('Going to convert using AssetAccountNumber', ['value' => $value]);
if (strlen($value) === 0) {
return new Account;
}
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($this->user);
if (isset($this->mapping[$value])) {
Log::debug('Found account in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]);
$account = $repository->find(intval($this->mapping[$value]));
if (!is_null($account->id)) {
Log::debug('Found account by ID', ['id' => $account->id]);
return $account;
}
}
// not mapped? Still try to find it first:
$account = $repository->findByAccountNumber($value, [AccountType::ASSET]);
if (!is_null($account->id)) {
Log::debug('Found account by name', ['id' => $account->id]);
$this->setCertainty(50);
return $account;
}
// try to find by the name we would give it:
$accountName = 'Asset account with number ' . e($value);
$account = $repository->findByName($accountName, [AccountType::ASSET]);
if (!is_null($account->id)) {
Log::debug('Found account by name', ['id' => $account->id]);
$this->setCertainty(50);
return $account;
}
$account = $repository->store(
['name' => $accountName, 'openingBalance' => 0, 'iban' => null, 'user' => $this->user->id,
'accountType' => 'asset',
'virtualBalance' => 0, 'accountNumber' => $value, 'active' => true]
);
if (is_null($account->id)) {
$this->setCertainty(0);
Log::info('Could not store new asset account by account number', $account->getErrors()->toArray());
return new Account;
}
$this->setCertainty(100);
return $account;
}
}

View File

@@ -1,85 +0,0 @@
<?php
/**
* BasicConverter.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\Import\Converter;
use FireflyIII\User;
/**
* Class BasicConverter
*
* @package FireflyIII\Import\Converter
*/
class BasicConverter
{
/** @var int */
public $certainty = 50;
/** @var array */
public $config;
/** @var bool */
public $doMap;
/** @var array */
public $mapping = [];
/** @var User */
public $user;
/**
* @return int
*/
public function getCertainty(): int
{
return $this->certainty;
}
/**
* @param int $certainty
*/
protected function setCertainty(int $certainty)
{
$this->certainty = $certainty;
}
/**
* @param array $config
*/
public function setConfig(array $config)
{
$this->config = $config;
}
/**
* @param mixed $doMap
*/
public function setDoMap(bool $doMap)
{
$this->doMap = $doMap;
}
/**
* @param array $mapping
*
*/
public function setMapping(array $mapping)
{
$this->mapping = $mapping;
}
/**
* @param User $user
*/
public function setUser(User $user)
{
$this->user = $user;
}
}

View File

@@ -1,76 +0,0 @@
<?php
/**
* BillId.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\Import\Converter;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Log;
/**
* Class BillId
*
* @package FireflyIII\Import\Converter
*/
class BillId extends BasicConverter implements ConverterInterface
{
/**
* @param $value
*
* @return Bill
*/
public function convert($value)
{
$value = intval(trim($value));
Log::debug('Going to convert using BillId', ['value' => $value]);
if ($value === 0) {
$this->setCertainty(0);
return new Bill;
}
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$repository->setUser($this->user);
if (isset($this->mapping[$value])) {
Log::debug('Found bill in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]);
$bill = $repository->find(intval($this->mapping[$value]));
if (!is_null($bill->id)) {
Log::debug('Found bill by ID', ['id' => $bill->id]);
$this->setCertainty(100);
return $bill;
}
}
// not mapped? Still try to find it first:
$bill = $repository->find($value);
if (!is_null($bill->id)) {
Log::debug('Found bill by ID ', ['id' => $bill->id]);
$this->setCertainty(100);
return $bill;
}
// should not really happen. If the ID does not match FF, what is FF supposed to do?
Log::info(sprintf('Could not find bill with ID %d. Will return NULL', $value));
$this->setCertainty(0);
return new Bill;
}
}

View File

@@ -1,99 +0,0 @@
<?php
/**
* BillName.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\Import\Converter;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Log;
/**
* Class BillName
*
* @package FireflyIII\Import\Converter
*/
class BillName extends BasicConverter implements ConverterInterface
{
/**
* @param $value
*
* @return Bill
* @throws FireflyException
*/
public function convert($value)
{
$value = trim($value);
Log::debug('Going to convert using BillName', ['value' => $value]);
if (strlen($value) === 0) {
$this->setCertainty(0);
return new Bill;
}
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$repository->setUser($this->user);
if (isset($this->mapping[$value])) {
Log::debug('Found bill in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]);
$bill = $repository->find(intval($this->mapping[$value]));
if (!is_null($bill->id)) {
Log::debug('Found bill by ID', ['id' => $bill->id]);
$this->setCertainty(100);
return $bill;
}
}
// not mapped? Still try to find it first:
$bill = $repository->findByName($value);
if (!is_null($bill->id)) {
Log::debug('Found bill by name ', ['id' => $bill->id]);
$this->setCertainty(100);
return $bill;
}
// create new bill. Use a lot of made up values.
$bill = $repository->store(
[
'name' => $value,
'match' => $value,
'amount_min' => 1,
'user' => $this->user->id,
'amount_max' => 10,
'date' => date('Ymd'),
'repeat_freq' => 'monthly',
'skip' => 0,
'automatch' => 0,
'active' => 1,
]
);
if (is_null($bill->id)) {
$this->setCertainty(0);
Log::info('Could not store new bill by name', $bill->getErrors()->toArray());
return new Bill;
}
$this->setCertainty(100);
return $bill;
}
}

View File

@@ -1,76 +0,0 @@
<?php
/**
* BudgetId.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\Import\Converter;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Log;
/**
* Class BudgetId
*
* @package FireflyIII\Import\Converter
*/
class BudgetId extends BasicConverter implements ConverterInterface
{
/**
* @param $value
*
* @return Budget
*/
public function convert($value)
{
$value = intval(trim($value));
Log::debug('Going to convert using BudgetId', ['value' => $value]);
if ($value === 0) {
$this->setCertainty(0);
return new Budget;
}
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$repository->setUser($this->user);
if (isset($this->mapping[$value])) {
Log::debug('Found budget in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]);
$budget = $repository->find(intval($this->mapping[$value]));
if (!is_null($budget->id)) {
Log::debug('Found budget by ID', ['id' => $budget->id]);
$this->setCertainty(100);
return $budget;
}
}
// not mapped? Still try to find it first:
$budget = $repository->find($value);
if (!is_null($budget->id)) {
Log::debug('Found budget by ID ', ['id' => $budget->id]);
$this->setCertainty(100);
return $budget;
}
// should not really happen. If the ID does not match FF, what is FF supposed to do?
$this->setCertainty(0);
Log::info(sprintf('Could not find budget with ID %d. Will return NULL', $value));
return new Budget;
}
}

View File

@@ -1,80 +0,0 @@
<?php
/**
* BudgetName.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\Import\Converter;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Log;
/**
* Class BudgetName
*
* @package FireflyIII\Import\Converter
*/
class BudgetName extends BasicConverter implements ConverterInterface
{
/**
* @param $value
*
* @return Budget
*/
public function convert($value)
{
$value = trim($value);
Log::debug('Going to convert using BudgetName', ['value' => $value]);
if (strlen($value) === 0) {
$this->setCertainty(0);
return new Budget;
}
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$repository->setUser($this->user);
if (isset($this->mapping[$value])) {
Log::debug('Found budget in mapping. Should exist.', ['value' => $value, 'map' => $this->mapping[$value]]);
$budget = $repository->find(intval($this->mapping[$value]));
if (!is_null($budget->id)) {
Log::debug('Found budget by ID', ['id' => $budget->id]);
$this->setCertainty(100);
return $budget;
}
}
// not mapped? Still try to find it first:
$budget = $repository->findByName($value);
if (!is_null($budget->id)) {
Log::debug('Found budget by name ', ['id' => $budget->id]);
$this->setCertainty(100);
return $budget;
}
// create new budget. Use a lot of made up values.
$budget = $repository->store(
[
'name' => $value,
'user' => $this->user->id,
]
);
$this->setCertainty(100);
return $budget;
}
}

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