mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-08-17 11:16:39 +00:00
Compare commits
479 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
63be574a14 | ||
|
2414f998ba | ||
|
90e2ecad4f | ||
|
87a3f5c715 | ||
|
a4ef81ebd8 | ||
|
67fc810fc2 | ||
|
e13a61645d | ||
|
aae4a78fd4 | ||
|
3947da5e27 | ||
|
4e4ce2f77c | ||
|
d9a2e081bd | ||
|
e60dde7ce5 | ||
|
699b138999 | ||
|
8f191b497f | ||
|
fd013d617c | ||
|
a8bda38035 | ||
|
411de9aa23 | ||
|
f0abe497ef | ||
|
9c8be83f5d | ||
|
45335af8cf | ||
|
945e433bb7 | ||
|
70729fdb0c | ||
|
4a435e5701 | ||
|
427747c6b8 | ||
|
be9407cb57 | ||
|
c380d3d2a0 | ||
|
489b0eb12d | ||
|
7c73629962 | ||
|
ff619eca1c | ||
|
134a39fd71 | ||
|
506509b1b2 | ||
|
02a36316be | ||
|
8549c7c81b | ||
|
5a0be7d2ad | ||
|
c6f44c6398 | ||
|
04a8a0e6a1 | ||
|
8a175d147b | ||
|
5fbc319b20 | ||
|
8e3ba7caf2 | ||
|
182aaa7d27 | ||
|
ec17d466f7 | ||
|
79c2445117 | ||
|
aa59db1609 | ||
|
814b106be2 | ||
|
3901ea0fbe | ||
|
65133107be | ||
|
08d15cfc5e | ||
|
3c89f9a5f1 | ||
|
dbc6bc8206 | ||
|
dc38291ef5 | ||
|
3bb634ed5b | ||
|
4bdcfe4d30 | ||
|
3b74784486 | ||
|
5226664a3d | ||
|
6d23823b63 | ||
|
da3a56c144 | ||
|
58aa54d8cf | ||
|
e525e673a8 | ||
|
445dbf8779 | ||
|
6a27bea2a3 | ||
|
13163f9c5c | ||
|
fde08f922b | ||
|
266ce00872 | ||
|
623a70a0d1 | ||
|
1d7b738040 | ||
|
edc8dd2601 | ||
|
31dc932ca4 | ||
|
edb355941c | ||
|
cddaccb7f7 | ||
|
a905cce2c9 | ||
|
b9f110ac2b | ||
|
7cc24417b3 | ||
|
b304284d70 | ||
|
c382fb1577 | ||
|
77244f4e2c | ||
|
8beab5f5bc | ||
|
902ae3f0cf | ||
|
519ef4e486 | ||
|
699e04f371 | ||
|
d73de0e60d | ||
|
8e0b7d2a73 | ||
|
04283cf2d6 | ||
|
d60b4aa56f | ||
|
9cfeda1b0c | ||
|
5e1bd8e1eb | ||
|
9b495d212b | ||
|
b6fdd0070b | ||
|
eea387ad0c | ||
|
9cdb0f173a | ||
|
51063230d0 | ||
|
1111478b7f | ||
|
c99c9b441f | ||
|
b5065a0276 | ||
|
c79a577060 | ||
|
091596e80e | ||
|
0b4efe4ae1 | ||
|
1f9b7faa60 | ||
|
762d7bcc34 | ||
|
a2145f6b49 | ||
|
b48de98865 | ||
|
a23179dd83 | ||
|
5c18794122 | ||
|
f04011f6a7 | ||
|
893498238e | ||
|
474fa9dea0 | ||
|
d8a8574dda | ||
|
935fb015d3 | ||
|
8bbd3063ec | ||
|
92c5cabd70 | ||
|
e5db5a7b5c | ||
|
28cf123da3 | ||
|
5069367873 | ||
|
234e656ff6 | ||
|
aeadfbdd6a | ||
|
39288cfb0b | ||
|
5e430968c1 | ||
|
154b74ce6f | ||
|
2e26303b66 | ||
|
51ddcd9ee1 | ||
|
9d5d1c0a41 | ||
|
6058ccff0d | ||
|
a8ec4fe2fd | ||
|
65ccb2d443 | ||
|
0e929602a8 | ||
|
5329e026dc | ||
|
a7412e43b3 | ||
|
eeae24e058 | ||
|
17b6cc43d5 | ||
|
b69a2ef0cd | ||
|
6d1296094e | ||
|
c4039b53e6 | ||
|
64831b4c86 | ||
|
1dec270907 | ||
|
f72f8b03df | ||
|
0b47e5d05d | ||
|
a487c7b4b2 | ||
|
3838b21459 | ||
|
7801274d33 | ||
|
a505406ee7 | ||
|
9487a95c13 | ||
|
3b2fe13902 | ||
|
db2898dfe5 | ||
|
e08fd399d2 | ||
|
e45ffba010 | ||
|
f7fde93ed2 | ||
|
3cf53604a1 | ||
|
e041a5e037 | ||
|
6c8e10255b | ||
|
3464ab1527 | ||
|
82e74a2afd | ||
|
771ebde295 | ||
|
4ce4c3138c | ||
|
d37b46effc | ||
|
0868aac750 | ||
|
4ff5f33966 | ||
|
e1aebbe12b | ||
|
8273f467b6 | ||
|
74664afa68 | ||
|
c05f344371 | ||
|
ec1507d644 | ||
|
8cdc1f0014 | ||
|
2b1ab5c6ef | ||
|
01fedc0bf8 | ||
|
1bd82d71a2 | ||
|
1e9dacb6e4 | ||
|
94939ea3d3 | ||
|
c3ff69d147 | ||
|
0fad9d4ac7 | ||
|
70cd8ffb72 | ||
|
61535bf4b8 | ||
|
4adcbf9e48 | ||
|
3eba3167fd | ||
|
0608fd7732 | ||
|
1f41f27e89 | ||
|
ded0df9303 | ||
|
2a7ba1893a | ||
|
6b3b19632a | ||
|
98bb0731df | ||
|
a102f7044e | ||
|
f1028dbaed | ||
|
438ce5c3db | ||
|
b995a1d091 | ||
|
e072f83507 | ||
|
79154bba25 | ||
|
613eb7522c | ||
|
0eb5653713 | ||
|
0d624f021b | ||
|
b263047f4e | ||
|
4410e1bbd7 | ||
|
8c3871e8de | ||
|
2eafd3cc15 | ||
|
368df66947 | ||
|
9f9a3ea8fd | ||
|
f66286105f | ||
|
0f0f912370 | ||
|
9fa0e37a5d | ||
|
a0cb51ff70 | ||
|
a6305ddea4 | ||
|
fb8638fe6a | ||
|
0009f1f865 | ||
|
d449c35025 | ||
|
1893d1a2c2 | ||
|
0c4539e4fa | ||
|
feacddd1d7 | ||
|
0c44fe6ce0 | ||
|
17fb6983d8 | ||
|
5fb73bdb01 | ||
|
7f082ea389 | ||
|
9856a1831a | ||
|
dd17a20b60 | ||
|
665a52b106 | ||
|
f68d33870b | ||
|
49d13b12a5 | ||
|
674ab7e41f | ||
|
5b3eb3ba82 | ||
|
e28d3f3b5a | ||
|
870d8b5008 | ||
|
6aa240e9a3 | ||
|
b55a4047d0 | ||
|
a07d87318c | ||
|
dd6555c903 | ||
|
e8c40b6044 | ||
|
91c17a0b2a | ||
|
2ed0ea0243 | ||
|
df2f92433a | ||
|
68b3fc72bf | ||
|
df5bb14758 | ||
|
e24199bbbe | ||
|
2c6099556b | ||
|
f98215a5da | ||
|
b6b6888493 | ||
|
f8e5b9be43 | ||
|
692210214f | ||
|
cff2546c0c | ||
|
f0cc1200f3 | ||
|
e83a9af455 | ||
|
fb84f9d9cf | ||
|
118a2515e1 | ||
|
63e891b0f7 | ||
|
9891080b57 | ||
|
bc7a7e55af | ||
|
9b8a029de1 | ||
|
11b5575422 | ||
|
06336aa580 | ||
|
aa8c1d6e9c | ||
|
9a4d5d8abf | ||
|
3c5631bca3 | ||
|
84f85f87b2 | ||
|
c35db5976f | ||
|
8d1fcf988c | ||
|
bbf8f2dd69 | ||
|
2f6436e34f | ||
|
9cbb03107d | ||
|
ee44d7fb2e | ||
|
6a0fcd9cf0 | ||
|
43cfe3b858 | ||
|
dba83c1c03 | ||
|
053e139d00 | ||
|
04f791a839 | ||
|
a4029c9490 | ||
|
d471dfec43 | ||
|
494bbd46d0 | ||
|
1525b9ad06 | ||
|
19847ee80b | ||
|
fddf1f146c | ||
|
5f19cb1c0c | ||
|
aaeae992e1 | ||
|
a0e7be9d45 | ||
|
78faf7e14c | ||
|
98f84c2c37 | ||
|
278805043e | ||
|
dc5215e41e | ||
|
7e11691ea4 | ||
|
c83dfc44d6 | ||
|
68a01b1735 | ||
|
0307b58d17 | ||
|
9d1508049e | ||
|
42322055f9 | ||
|
5de8fce156 | ||
|
29ff92f833 | ||
|
359007c5bf | ||
|
bbe40518e4 | ||
|
b26f3c0cc6 | ||
|
552b4b67a6 | ||
|
7fbf359efd | ||
|
052b804855 | ||
|
67cc611495 | ||
|
7e2c24b82e | ||
|
4a6bbd4dca | ||
|
166bfba5b9 | ||
|
87b8ac5f4e | ||
|
46b4100291 | ||
|
83090ade94 | ||
|
44b7a42d5a | ||
|
1a5617d430 | ||
|
fa818e0924 | ||
|
f87b531fe1 | ||
|
82fd0c4d37 | ||
|
26ceb9e3be | ||
|
743458b853 | ||
|
920e5f6fbe | ||
|
fc0dd22769 | ||
|
c7c61ce280 | ||
|
5f5a603f71 | ||
|
d611858883 | ||
|
dbc9ce76a0 | ||
|
62386e2e40 | ||
|
5aa7ab5e37 | ||
|
be1b57eab7 | ||
|
ad5c8b41e2 | ||
|
09752b25ad | ||
|
3f317f961b | ||
|
d6d6a62fda | ||
|
528833b831 | ||
|
95e2bca4a6 | ||
|
dfd3327108 | ||
|
653befbcd4 | ||
|
33202efcdc | ||
|
77a37411ba | ||
|
491f221741 | ||
|
e8e125a598 | ||
|
cb01ae0ac5 | ||
|
a09469c01f | ||
|
662f398b08 | ||
|
d7aef627b8 | ||
|
87bcf293aa | ||
|
0171831ebb | ||
|
50cc455f0f | ||
|
47a7729358 | ||
|
6d508e61a0 | ||
|
8ef9223d84 | ||
|
e58ea4d0c7 | ||
|
9629ba916e | ||
|
aad4df1596 | ||
|
30ed25f80a | ||
|
8b7000681c | ||
|
221adbf3db | ||
|
39129d8cd0 | ||
|
2c2d444906 | ||
|
04a1d785bf | ||
|
c0a0aa4652 | ||
|
21c24fd7f0 | ||
|
beb358f8ee | ||
|
e3cd11ec2e | ||
|
ee08fc2421 | ||
|
ae30f7920b | ||
|
f4786c3ec8 | ||
|
8b9e4d2539 | ||
|
d7ca7ed632 | ||
|
1346b25fc7 | ||
|
15d9314503 | ||
|
93f4006c9e | ||
|
16182fec6c | ||
|
99606ba936 | ||
|
be1ed56d42 | ||
|
d7fb6f83b8 | ||
|
665f1f470a | ||
|
7867f26120 | ||
|
8e195bf811 | ||
|
e3403dc87f | ||
|
5844e95488 | ||
|
cb3a1f2ff6 | ||
|
f95edb06a9 | ||
|
86d13060bc | ||
|
0b8c2f6f8d | ||
|
589cafc64f | ||
|
448dc7b5c3 | ||
|
10cfde6cab | ||
|
e48eb2ce2f | ||
|
20a30a2d1d | ||
|
2e5b8418ae | ||
|
054fd229d2 | ||
|
9bdf2c8877 | ||
|
04f858a355 | ||
|
a9bf405a65 | ||
|
463c866cfa | ||
|
03fe0c8fff | ||
|
102d9f3510 | ||
|
3cf9a40c42 | ||
|
ff33267296 | ||
|
f0dab5bdb9 | ||
|
209a907c61 | ||
|
c7984d4363 | ||
|
a388313e1c | ||
|
a3933cb307 | ||
|
89c82d9be9 | ||
|
6e6311a1a1 | ||
|
69b334ed8a | ||
|
a84b6f377f | ||
|
ee5db4e4cc | ||
|
20f3322e5a | ||
|
1e84bc3743 | ||
|
7f198cbd50 | ||
|
1c7d5ccefc | ||
|
41dc4d994e | ||
|
490733bdd1 | ||
|
ed8cf8c431 | ||
|
a7e1f85c4d | ||
|
4b8919420d | ||
|
9afc5d67a4 | ||
|
72afaddd7c | ||
|
8ae3182e1c | ||
|
9d7e16b390 | ||
|
3a2ed202ad | ||
|
9e4b9b98ab | ||
|
e65fb7d995 | ||
|
7197830edc | ||
|
687603ae84 | ||
|
23fc25f926 | ||
|
e0c1f07f92 | ||
|
9424aa3378 | ||
|
57e6e0945f | ||
|
d87a033f29 | ||
|
10481895e6 | ||
|
813432f386 | ||
|
aba78c9776 | ||
|
8dc56bcee0 | ||
|
32b6e030ef | ||
|
a27f5d2474 | ||
|
e2fe8cfb75 | ||
|
9f1c346365 | ||
|
3e56803e95 | ||
|
fc5feb054d | ||
|
8fc233e436 | ||
|
22303eb2ff | ||
|
d6477ff9ff | ||
|
a0f6f13650 | ||
|
1dd213d587 | ||
|
569e51afbe | ||
|
ff06a4ed0d | ||
|
ea3fdb0668 | ||
|
bd917f6484 | ||
|
ee96311222 | ||
|
135153ff9c | ||
|
fdb98133c8 | ||
|
ad4e2c0a85 | ||
|
e38cb263aa | ||
|
0922136389 | ||
|
2a05517a30 | ||
|
a0ee924aeb | ||
|
1595afce68 | ||
|
4919d730c8 | ||
|
1407d6cc66 | ||
|
55b092e7a0 | ||
|
93afb754f3 | ||
|
81c0ea8f5c | ||
|
6faacd3781 | ||
|
ea1e9e407f | ||
|
d4f5aa1578 | ||
|
1cbbf3fa5d | ||
|
dad3dc71ca | ||
|
afb1e9f230 | ||
|
c33dd1ecee | ||
|
7e31a29b12 | ||
|
9a69ce309e | ||
|
b99bfcd02e | ||
|
adb16e4560 | ||
|
953c38563b | ||
|
89ee9c058a | ||
|
bac7a73555 | ||
|
5fb6ff230b | ||
|
605a718418 | ||
|
994542c75d | ||
|
d5fdce02fa | ||
|
d3637de0c3 | ||
|
63acbb222d | ||
|
5e1fe157b6 | ||
|
8e811da967 | ||
|
fb23108f4e | ||
|
a0220eb5f8 | ||
|
c16cbd5bc8 | ||
|
2d0673e1bc | ||
|
a90e00d577 | ||
|
8db96025a3 | ||
|
595596d73f | ||
|
240797e92a | ||
|
6cafb91680 | ||
|
852ce3e32f | ||
|
6b9c9458fa |
@@ -41,6 +41,8 @@ SHOW_INCOMPLETE_TRANSLATIONS=false
|
||||
|
||||
CACHE_PREFIX=firefly
|
||||
|
||||
EXCHANGE_RATE_SERVICE=fixerio
|
||||
|
||||
GOOGLE_MAPS_API_KEY=
|
||||
ANALYTICS_ID=
|
||||
SITE_OWNER=mail@example.com
|
||||
|
@@ -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
|
||||
|
54
.github/CONTRIBUTING.md
vendored
54
.github/CONTRIBUTING.md
vendored
@@ -4,20 +4,64 @@
|
||||
|
||||
## 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/).
|
||||
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/).
|
||||
|
||||
## 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.
|
||||
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
|
||||
|
||||
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!
|
||||
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.
|
||||
|
||||
## 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.
|
||||
|
||||
# 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. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and 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](http://contributor-covenant.org/), version 1.4, available at [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4).
|
||||
|
@@ -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:
|
||||
|
92
CHANGELOG.md
92
CHANGELOG.md
@@ -2,7 +2,72 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [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.
|
||||
|
||||
### Security
|
||||
- Initial release.
|
||||
|
||||
## [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.
|
||||
- Can now make rules for attachments, see #608, as suggested by dzaikos.
|
||||
|
||||
### Fixed
|
||||
- Fixed #629, reported by forcaeluz
|
||||
- Fixed #630, reported by welbert
|
||||
- And more various bug fixes.
|
||||
|
||||
## [4.3.8] - 2017-04-08
|
||||
|
||||
@@ -203,13 +268,6 @@ An intermediate release because something in the Twig and Twigbridge libraries i
|
||||
- Updated all email messages.
|
||||
- Made some fonts local
|
||||
|
||||
|
||||
### Deprecated
|
||||
- Initial release.
|
||||
|
||||
### Removed
|
||||
- Initial release.
|
||||
|
||||
### Fixed
|
||||
- Issue #408
|
||||
- Various issues with split journals
|
||||
@@ -218,11 +276,6 @@ An intermediate release because something in the Twig and Twigbridge libraries i
|
||||
- Issue #422, thx [xzaz](https://github.com/xzaz)
|
||||
- Various import bugs, such as #416 ([zjean](https://github.com/zjean))
|
||||
|
||||
|
||||
### Security
|
||||
- Initial release.
|
||||
|
||||
|
||||
## [4.1.7] - 2016-11-19
|
||||
### Added
|
||||
- Check for database table presence in console commands.
|
||||
@@ -345,15 +398,6 @@ An intermediate release because something in the Twig and Twigbridge libraries i
|
||||
- New Presidents Choice specific to fix #307
|
||||
- Added some trimming (#335)
|
||||
|
||||
### Changed
|
||||
- Initial release.
|
||||
|
||||
### Deprecated
|
||||
- Initial release.
|
||||
|
||||
### Removed
|
||||
- Initial release.
|
||||
|
||||
### Fixed
|
||||
- Fixed a bug where incoming transactions would not be properly filtered in several reports.
|
||||
- #334 by [cyberkov](https://github.com/cyberkov)
|
||||
@@ -361,12 +405,6 @@ An intermediate release because something in the Twig and Twigbridge libraries i
|
||||
- #336
|
||||
- #338 found by [roberthorlings](https://github.com/roberthorlings)
|
||||
|
||||
### Security
|
||||
- Initial release.
|
||||
|
||||
|
||||
|
||||
|
||||
## [4.0.0] - 2015-09-26
|
||||
### Added
|
||||
- Upgraded to Laravel 5.3, most other libraries upgraded as well.
|
||||
|
@@ -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
1
Procfile
Normal file
@@ -0,0 +1 @@
|
||||
web: vendor/bin/heroku-php-nginx -C nginx_app.conf public/
|
27
README.md
27
README.md
@@ -10,9 +10,11 @@
|
||||
|
||||
## Try it out!
|
||||
|
||||
Try out Firefly III on the [demo site](https://firefly-iii.nder.be/).
|
||||
[](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", it’s just somebody else’s 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 the code of conduct, and the process for submitting pull requests.
|
||||
|
||||
### 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
59
app.json
Normal 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="
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* ConfigureLogging.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\Bootstrap;
|
||||
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Foundation\Bootstrap\ConfigureLogging as IlluminateConfigureLogging;
|
||||
use Illuminate\Log\Writer;
|
||||
|
||||
/**
|
||||
* Class ConfigureLogging
|
||||
*
|
||||
* @package FireflyIII\Bootstrap
|
||||
*/
|
||||
class ConfigureLogging extends IlluminateConfigureLogging
|
||||
{
|
||||
|
||||
/**
|
||||
* Configure the Monolog handlers for the application.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @param \Illuminate\Log\Writer $log
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configureDailyHandler(Application $app, Writer $log)
|
||||
{
|
||||
$config = $app->make('config');
|
||||
|
||||
$maxFiles = $config->get('app.log_max_files');
|
||||
|
||||
$log->useDailyFiles(
|
||||
$app->storagePath() . '/logs/firefly-iii.log', is_null($maxFiles) ? 5 : $maxFiles,
|
||||
$config->get('app.log_level', 'debug')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the Monolog handlers for the application.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @param \Illuminate\Log\Writer $log
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configureSingleHandler(Application $app, Writer $log)
|
||||
{
|
||||
$log->useFiles(
|
||||
$app->storagePath() . '/logs/firefly-iii.log',
|
||||
$app->make('config')->get('app.log_level', 'debug')
|
||||
);
|
||||
}
|
||||
}
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
@@ -88,7 +88,7 @@ class CreateImport extends Command
|
||||
$this->line('Stored import data...');
|
||||
|
||||
$job->configuration = $configurationData;
|
||||
$job->status = 'settings_complete';
|
||||
$job->status = 'configured';
|
||||
$job->save();
|
||||
$this->line('Stored configuration...');
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
|
@@ -9,16 +9,17 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
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 +76,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 +100,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 +115,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
|
@@ -15,16 +15,24 @@ namespace FireflyIII\Console\Commands;
|
||||
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\LimitRepetition;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Schema;
|
||||
use Steam;
|
||||
|
||||
/**
|
||||
* Class UpgradeDatabase
|
||||
@@ -63,8 +71,59 @@ class UpgradeDatabase extends Command
|
||||
$this->setTransactionIdentifier();
|
||||
$this->migrateRepetitions();
|
||||
$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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
private function migrateRepetitions()
|
||||
{
|
||||
if (!Schema::hasTable('budget_limits')) {
|
||||
@@ -102,18 +161,20 @@ class UpgradeDatabase extends Command
|
||||
/** @var PiggyBankEvent $event */
|
||||
foreach ($set as $event) {
|
||||
|
||||
if (!is_null($event->transaction_journal_id)) {
|
||||
$type = $event->transactionJournal->transactionType->type;
|
||||
if ($type !== TransactionType::TRANSFER) {
|
||||
$event->transaction_journal_id = null;
|
||||
$event->save();
|
||||
$this->line(
|
||||
sprintf('Piggy bank #%d ("%s") was referenced by an invalid event. This has been fixed.', $event->piggy_bank_id,
|
||||
$event->piggyBank->name
|
||||
));
|
||||
}
|
||||
|
||||
if (is_null($event->transaction_journal_id)) {
|
||||
continue;
|
||||
}
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $event->transactionJournal()->first();
|
||||
if (is_null($journal)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = $journal->transactionType->type;
|
||||
if ($type !== TransactionType::TRANSFER) {
|
||||
$event->transaction_journal_id = null;
|
||||
$event->save();
|
||||
$this->line(sprintf('Piggy bank #%d was referenced by an invalid event. This has been fixed.', $event->piggy_bank_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,6 +207,57 @@ class UpgradeDatabase extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function updateAccountCurrencies()
|
||||
{
|
||||
$accounts = Account::leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
||||
->whereIn('account_types.type', [AccountType::DEFAULT, AccountType::ASSET])->get(['accounts.*']);
|
||||
|
||||
/** @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);
|
||||
|
||||
// both 0? set to default currency:
|
||||
if ($accountCurrency === 0 && $openingBalanceCurrency === 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]);
|
||||
$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) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* grab all positive transactiosn from this journal that are not deleted. for each one, grab the negative opposing one
|
||||
* which has 0 as an identifier and give it the same identifier.
|
||||
@@ -189,4 +301,112 @@ class UpgradeDatabase extends Command
|
||||
$identifier++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that withdrawals, deposits and transfers have
|
||||
* a currency setting matching their respective accounts
|
||||
*/
|
||||
private function updateJournalCurrencies()
|
||||
{
|
||||
$types = [
|
||||
TransactionType::WITHDRAWAL => '<',
|
||||
TransactionType::DEPOSIT => '>',
|
||||
];
|
||||
$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) {
|
||||
$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');
|
||||
}
|
||||
)
|
||||
->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');
|
||||
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));
|
||||
$line = sprintf($notification, $type, $journal->id, $journal->transactionCurrency->code, $expectedCurrency->code);
|
||||
|
||||
$journal->setMeta('foreign_amount', $journal->transaction_amount);
|
||||
$journal->setMeta('foreign_currency_id', $journal->transaction_currency_id);
|
||||
$journal->transaction_currency_id = $expectedCurrency->id;
|
||||
$journal->save();
|
||||
$this->line($line);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* For transfers it's slightly different. Both source and destination
|
||||
* must match the respective currency preference. So we must verify ALL
|
||||
* transactions.
|
||||
*/
|
||||
$set = TransactionJournal
|
||||
::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
|
||||
->where('transaction_types.type', TransactionType::TRANSFER)
|
||||
->get(['transaction_journals.*']);
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($set as $journal) {
|
||||
$updated = false;
|
||||
/** @var Transaction $sourceTransaction */
|
||||
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
|
||||
$sourceCurrency = $repository->find(intval($sourceTransaction->account->getMeta('currency_id')));
|
||||
|
||||
if ($sourceCurrency->id !== $journal->transaction_currency_id) {
|
||||
$updated = true;
|
||||
$journal->transaction_currency_id = $sourceCurrency->id;
|
||||
$journal->save();
|
||||
}
|
||||
|
||||
// destination
|
||||
$destinationTransaction = $journal->transactions()->where('amount', '>', 0)->first();
|
||||
$destinationCurrency = $repository->find(intval($destinationTransaction->account->getMeta('currency_id')));
|
||||
|
||||
if ($destinationCurrency->id !== $journal->transaction_currency_id) {
|
||||
$updated = true;
|
||||
$journal->deleteMeta('foreign_amount');
|
||||
$journal->deleteMeta('foreign_currency_id');
|
||||
$journal->setMeta('foreign_amount', $destinationTransaction->amount);
|
||||
$journal->setMeta('foreign_currency_id', $destinationCurrency->id);
|
||||
}
|
||||
if ($updated) {
|
||||
$line = sprintf($transfer, $journal->id);
|
||||
$this->line($line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console;
|
||||
|
||||
@@ -41,7 +41,6 @@ class Kernel extends ConsoleKernel
|
||||
= [
|
||||
'Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables',
|
||||
'Illuminate\Foundation\Bootstrap\LoadConfiguration',
|
||||
//'FireflyIII\Bootstrap\ConfigureLogging',
|
||||
'Illuminate\Foundation\Bootstrap\HandleExceptions',
|
||||
'Illuminate\Foundation\Bootstrap\RegisterFacades',
|
||||
'Illuminate\Foundation\Bootstrap\SetRequestForConsole',
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
/**
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
@@ -26,7 +26,9 @@ class StoredTransactionJournal extends Event
|
||||
|
||||
use SerializesModels;
|
||||
|
||||
/** @var TransactionJournal */
|
||||
public $journal;
|
||||
/** @var int */
|
||||
public $piggyBankId;
|
||||
|
||||
/**
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
@@ -26,6 +26,7 @@ class UpdatedTransactionJournal extends Event
|
||||
|
||||
use SerializesModels;
|
||||
|
||||
/** @var TransactionJournal */
|
||||
public $journal;
|
||||
|
||||
/**
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
|
||||
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
|
||||
use ErrorException;
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
|
||||
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
|
||||
/**
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
@@ -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',
|
||||
|
||||
]
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Entry;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Exporter;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Exporter;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export\Exporter;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Export;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Basic;
|
||||
|
||||
@@ -81,6 +81,9 @@ class ChartJsGenerator implements GeneratorInterface
|
||||
if (isset($set['fill'])) {
|
||||
$currentSet['fill'] = $set['fill'];
|
||||
}
|
||||
if (isset($set['currency_symbol'])) {
|
||||
$currentSet['currency_symbol'] = $set['currency_symbol'];
|
||||
}
|
||||
|
||||
$chartData['datasets'][] = $currentSet;
|
||||
}
|
||||
@@ -105,7 +108,11 @@ class ChartJsGenerator implements GeneratorInterface
|
||||
],
|
||||
'labels' => [],
|
||||
];
|
||||
$index = 0;
|
||||
|
||||
// sort by value, keep keys.
|
||||
asort($data);
|
||||
|
||||
$index = 0;
|
||||
foreach ($data as $key => $value) {
|
||||
|
||||
// make larger than 0
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Chart\Basic;
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Audit;
|
||||
|
||||
@@ -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;
|
||||
$transactionAmount = $transaction->transaction_amount;
|
||||
|
||||
if ($currency->id === $transaction->foreign_currency_id) {
|
||||
$transactionAmount = $transaction->transaction_foreign_amount;
|
||||
}
|
||||
|
||||
$newBalance = bcadd($startBalance, $transactionAmount);
|
||||
$transaction->after = $newBalance;
|
||||
$startBalance = $newBalance;
|
||||
$transaction->currency = $currency;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Audit;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Audit;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Budget;
|
||||
|
||||
@@ -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;
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Budget;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Budget;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Category;
|
||||
|
||||
@@ -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;
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Category;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Category;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Standard;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Standard;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Standard;
|
||||
|
||||
|
@@ -9,13 +9,12 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
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
|
||||
*/
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Tag;
|
||||
|
||||
@@ -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;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Tag;
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Generator\Report\Tag;
|
||||
|
||||
|
@@ -9,81 +9,100 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
|
||||
@@ -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);
|
||||
|
@@ -9,14 +9,15 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -9,13 +9,16 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
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;
|
||||
|
||||
@@ -27,6 +30,8 @@ use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
class AttachmentHelper implements AttachmentHelperInterface
|
||||
{
|
||||
|
||||
/** @var Collection */
|
||||
public $attachments;
|
||||
/** @var MessageBag */
|
||||
public $errors;
|
||||
/** @var MessageBag */
|
||||
@@ -48,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');
|
||||
}
|
||||
|
||||
@@ -63,6 +69,14 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAttachments(): Collection
|
||||
{
|
||||
return $this->attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MessageBag
|
||||
*/
|
||||
@@ -109,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]);
|
||||
@@ -136,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();
|
||||
@@ -144,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]);
|
||||
@@ -187,6 +205,8 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param UploadedFile $file
|
||||
*
|
||||
* @return bool
|
||||
@@ -217,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;
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -7,13 +7,16 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
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 = [];
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Chart;
|
||||
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Account as AccountModel;
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Account as AccountModel;
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use FireflyIII\Models\Category as CategoryModel;
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collector;
|
||||
|
||||
@@ -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,17 +60,30 @@ 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',
|
||||
@@ -74,6 +92,9 @@ class JournalCollector implements JournalCollectorInterface
|
||||
private $filterInternalTransfers;
|
||||
/** @var bool */
|
||||
private $filterTransfers = false;
|
||||
/** @var array */
|
||||
private $filters = [InternalTransferFilter::class];
|
||||
|
||||
/** @var bool */
|
||||
private $joinedBudget = false;
|
||||
/** @var bool */
|
||||
@@ -95,6 +116,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 +156,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 +164,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 +206,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 +237,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
}
|
||||
|
||||
if ($accounts->count() > 1) {
|
||||
$this->addFilter(TransferFilter::class);
|
||||
$this->filterTransfers = true;
|
||||
}
|
||||
|
||||
@@ -242,6 +261,7 @@ class JournalCollector implements JournalCollectorInterface
|
||||
}
|
||||
|
||||
if ($accounts->count() > 1) {
|
||||
$this->addFilter(TransferFilter::class);
|
||||
$this->filterTransfers = true;
|
||||
}
|
||||
|
||||
@@ -464,7 +484,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,13 +494,15 @@ 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)
|
||||
@@ -560,79 +584,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;
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collector;
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
56
app/Helpers/Filter/AmountFilter.php
Normal file
56
app/Helpers/Filter/AmountFilter.php
Normal 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;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
34
app/Helpers/Filter/EmptyFilter.php
Normal file
34
app/Helpers/Filter/EmptyFilter.php
Normal 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;
|
||||
}
|
||||
}
|
26
app/Helpers/Filter/FilterInterface.php
Normal file
26
app/Helpers/Filter/FilterInterface.php
Normal 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;
|
||||
|
||||
}
|
73
app/Helpers/Filter/InternalTransferFilter.php
Normal file
73
app/Helpers/Filter/InternalTransferFilter.php
Normal 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;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
}
|
47
app/Helpers/Filter/NegativeAmountFilter.php
Normal file
47
app/Helpers/Filter/NegativeAmountFilter.php
Normal 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;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
63
app/Helpers/Filter/OpposingAccountFilter.php
Normal file
63
app/Helpers/Filter/OpposingAccountFilter.php
Normal 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;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
50
app/Helpers/Filter/PositiveAmountFilter.php
Normal file
50
app/Helpers/Filter/PositiveAmountFilter.php
Normal 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;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
58
app/Helpers/Filter/TransferFilter.php
Normal file
58
app/Helpers/Filter/TransferFilter.php
Normal 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;
|
||||
}
|
||||
}
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers;
|
||||
|
||||
|
@@ -9,7 +9,8 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Help;
|
||||
|
||||
/**
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
|
@@ -28,6 +28,37 @@ class PopupReport implements PopupReportInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param $account
|
||||
* @param $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceDifference($account, $attributes): Collection
|
||||
{
|
||||
// row that displays difference
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setTypes([TransactionType::WITHDRAWAL])
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->withoutBudget();
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
|
||||
return $journals->filter(
|
||||
function (Transaction $transaction) {
|
||||
$tags = $transaction->transactionJournal->tags()->where('tagMode', 'balancingAct')->count();
|
||||
if ($tags === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param Account $account
|
||||
@@ -156,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));
|
||||
@@ -165,35 +196,4 @@ class PopupReport implements PopupReportInterface
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $account
|
||||
* @param $attributes
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function balanceDifference($account, $attributes): Collection
|
||||
{
|
||||
// row that displays difference
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setTypes([TransactionType::WITHDRAWAL])
|
||||
->setRange($attributes['startDate'], $attributes['endDate'])
|
||||
->withoutBudget();
|
||||
$journals = $collector->getJournals();
|
||||
|
||||
|
||||
return $journals->filter(
|
||||
function (Transaction $transaction) {
|
||||
$tags = $transaction->transactionJournal->tags()->where('tagMode', 'balancingAct')->count();
|
||||
if ($tags === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Report;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
@@ -22,8 +22,8 @@ use FireflyIII\Http\Requests\AccountFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Account\AccountTaskerInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
@@ -69,12 +69,13 @@ class AccountController extends Controller
|
||||
public function create(Request $request, string $what = 'asset')
|
||||
{
|
||||
/** @var CurrencyRepositoryInterface $repository */
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$currencies = ExpandedForm::makeSelectList($repository->get());
|
||||
$defaultCurrency = Amount::getDefaultCurrency();
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$subTitle = trans('firefly.make_new_' . $what . '_account');
|
||||
$roles = [];
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$allCurrencies = $repository->get();
|
||||
$currencySelectList = ExpandedForm::makeSelectList($allCurrencies);
|
||||
$defaultCurrency = Amount::getDefaultCurrency();
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$subTitle = trans('firefly.make_new_' . $what . '_account');
|
||||
$roles = [];
|
||||
foreach (config('firefly.accountRoles') as $role) {
|
||||
$roles[$role] = strval(trans('firefly.account_role_' . $role));
|
||||
}
|
||||
@@ -91,7 +92,7 @@ class AccountController extends Controller
|
||||
$request->session()->flash('gaEventCategory', 'accounts');
|
||||
$request->session()->flash('gaEventAction', 'create-' . $what);
|
||||
|
||||
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'currencies', 'roles'));
|
||||
return view('accounts.create', compact('subTitleIcon', 'what', 'subTitle', 'currencySelectList', 'allCurrencies', 'roles'));
|
||||
|
||||
}
|
||||
|
||||
@@ -147,14 +148,14 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function edit(Request $request, Account $account)
|
||||
{
|
||||
|
||||
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
|
||||
$subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
/** @var CurrencyRepositoryInterface $repository */
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$currencies = ExpandedForm::makeSelectList($repository->get());
|
||||
$roles = [];
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
$what = config('firefly.shortNamesByFullName')[$account->accountType->type];
|
||||
$subTitle = trans('firefly.edit_' . $what . '_account', ['name' => $account->name]);
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $what);
|
||||
$allCurrencies = $repository->get();
|
||||
$currencySelectList = ExpandedForm::makeSelectList($allCurrencies);
|
||||
$roles = [];
|
||||
foreach (config('firefly.accountRoles') as $role) {
|
||||
$roles[$role] = strval(trans('firefly.account_role_' . $role));
|
||||
}
|
||||
@@ -173,6 +174,7 @@ class AccountController extends Controller
|
||||
$openingBalanceAmount = $account->getOpeningBalanceAmount() === '0' ? '' : $openingBalanceAmount;
|
||||
$openingBalanceDate = $account->getOpeningBalanceDate();
|
||||
$openingBalanceDate = $openingBalanceDate->year === 1900 ? null : $openingBalanceDate->format('Y-m-d');
|
||||
$currency = $repository->find(intval($account->getMeta('currency_id')));
|
||||
|
||||
$preFilled = [
|
||||
'accountNumber' => $account->getMeta('accountNumber'),
|
||||
@@ -183,13 +185,18 @@ class AccountController extends Controller
|
||||
'openingBalanceDate' => $openingBalanceDate,
|
||||
'openingBalance' => $openingBalanceAmount,
|
||||
'virtualBalance' => $account->virtual_balance,
|
||||
'currency_id' => $account->getMeta('currency_id'),
|
||||
'currency_id' => $currency->id,
|
||||
|
||||
];
|
||||
$request->session()->flash('preFilled', $preFilled);
|
||||
$request->session()->flash('gaEventCategory', 'accounts');
|
||||
$request->session()->flash('gaEventAction', 'edit-' . $what);
|
||||
|
||||
return view('accounts.edit', compact('currencies', 'account', 'subTitle', 'subTitleIcon', 'openingBalance', 'what', 'roles'));
|
||||
return view(
|
||||
'accounts.edit', compact(
|
||||
'allCurrencies', 'currencySelectList', 'account', 'currency', 'subTitle', 'subTitleIcon', 'openingBalance', 'what', 'roles'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,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(
|
||||
@@ -242,14 +249,17 @@ class AccountController extends Controller
|
||||
if ($account->accountType->type === AccountType::INITIAL_BALANCE) {
|
||||
return $this->redirectToOriginalAccount($account);
|
||||
}
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$chartUri = route('chart.account.single', [$account->id]);
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
/** @var CurrencyRepositoryInterface $currencyRepos */
|
||||
$currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$subTitleIcon = config('firefly.subIconsByIdentifier.' . $account->accountType->type);
|
||||
$page = intval($request->get('page')) === 0 ? 1 : intval($request->get('page'));
|
||||
$pageSize = intval(Preferences::get('transactionPageSize', 50)->data);
|
||||
$chartUri = route('chart.account.single', [$account->id]);
|
||||
$start = null;
|
||||
$end = null;
|
||||
$periods = new Collection;
|
||||
$currency = $currencyRepos->find(intval($account->getMeta('currency_id')));
|
||||
|
||||
// prep for "all" view.
|
||||
if ($moment === 'all') {
|
||||
@@ -283,9 +293,8 @@ class AccountController extends Controller
|
||||
$periods = $this->getPeriodOverview($account);
|
||||
}
|
||||
|
||||
$accountType = $account->accountType->type;
|
||||
$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) {
|
||||
@@ -316,7 +325,8 @@ class AccountController extends Controller
|
||||
|
||||
|
||||
return view(
|
||||
'accounts.show', compact('account', 'moment', 'accountType', 'periods', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri')
|
||||
'accounts.show',
|
||||
compact('account', 'currency', 'moment', 'periods', 'subTitleIcon', 'journals', 'subTitle', 'start', 'end', 'chartUri')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -331,7 +341,6 @@ class AccountController extends Controller
|
||||
{
|
||||
$data = $request->getAccountData();
|
||||
$account = $repository->store($data);
|
||||
|
||||
$request->session()->flash('success', strval(trans('firefly.stored_new_account', ['name' => $account->name])));
|
||||
Preferences::mark();
|
||||
|
||||
@@ -409,14 +418,11 @@ class AccountController extends Controller
|
||||
{
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
/** @var AccountTaskerInterface $tasker */
|
||||
$tasker = app(AccountTaskerInterface::class);
|
||||
|
||||
$start = $repository->oldestJournalDate($account);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfX(new Carbon, $range);
|
||||
$entries = new Collection;
|
||||
$start = $repository->oldestJournalDate($account);
|
||||
$range = Preferences::get('viewRange', '1M')->data;
|
||||
$start = Navigation::startOfPeriod($start, $range);
|
||||
$end = Navigation::endOfX(new Carbon, $range);
|
||||
$entries = new Collection;
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties;
|
||||
@@ -429,19 +435,28 @@ class AccountController extends Controller
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// only include asset accounts when this account is an asset:
|
||||
$assets = new Collection;
|
||||
if (in_array($account->accountType->type, [AccountType::ASSET, AccountType::DEFAULT])) {
|
||||
$assets = $repository->getAccountsByType([AccountType::ASSET, AccountType::DEFAULT]);
|
||||
}
|
||||
Log::debug('Going to get period expenses and incomes.');
|
||||
while ($end >= $start) {
|
||||
$end = Navigation::startOfPeriod($end, $range);
|
||||
$currentEnd = Navigation::endOfPeriod($end, $range);
|
||||
$spent = $tasker->amountOutInPeriod(new Collection([$account]), $assets, $end, $currentEnd);
|
||||
$earned = $tasker->amountInInPeriod(new Collection([$account]), $assets, $end, $currentEnd);
|
||||
$dateStr = $end->format('Y-m-d');
|
||||
$dateName = Navigation::periodShow($end, $range);
|
||||
|
||||
// try a collector for income:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($end, $currentEnd)
|
||||
->setTypes([TransactionType::DEPOSIT])
|
||||
->withOpposingAccount();
|
||||
$earned = strval($collector->getJournals()->sum('transaction_amount'));
|
||||
|
||||
// try a collector for expenses:
|
||||
/** @var JournalCollectorInterface $collector */
|
||||
$collector = app(JournalCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($end, $currentEnd)
|
||||
->setTypes([TransactionType::WITHDRAWAL])
|
||||
->withOpposingAccount();
|
||||
$spent = strval($collector->getJournals()->sum('transaction_amount'));
|
||||
$dateStr = $end->format('Y-m-d');
|
||||
$dateName = Navigation::periodShow($end, $range);
|
||||
$entries->push(
|
||||
[
|
||||
'string' => $dateStr,
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
|
@@ -125,8 +125,10 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserFormRequest $request
|
||||
* @param User $user
|
||||
* @param UserFormRequest $request
|
||||
* @param User $user
|
||||
*
|
||||
* @param UserRepositoryInterface $repository
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
@@ -98,10 +98,14 @@ 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,6 +153,7 @@ class AttachmentController extends Controller
|
||||
{
|
||||
$image = 'images/page_green.png';
|
||||
|
||||
|
||||
if ($attachment->mime == 'application/pdf') {
|
||||
$image = 'images/page_white_acrobat.png';
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Auth;
|
||||
|
||||
@@ -41,7 +41,9 @@ class ForgotPasswordController extends Controller
|
||||
/**
|
||||
* Send a reset link to the given user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Request $request
|
||||
*
|
||||
* @param UserRepositoryInterface $repository
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Auth;
|
||||
|
||||
@@ -110,7 +110,9 @@ class LoginController extends Controller
|
||||
/**
|
||||
* Show the application login form.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Request $request
|
||||
*
|
||||
* @param CookieJar $cookieJar
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Auth;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user