Compare commits

..

106 Commits

Author SHA1 Message Date
James Cole
88c145ac3e Merge branch 'release/v6.0.24' 2023-09-15 19:55:41 +02:00
James Cole
4aba842624 Meta files for new release. 2023-09-15 19:54:56 +02:00
James Cole
936c2b8888 Fix https://github.com/orgs/firefly-iii/discussions/7963 2023-09-15 18:55:30 +02:00
James Cole
c3e971c419 Rebuild frontend. 2023-09-12 06:09:39 +02:00
James Cole
19fee6a8fb Fix https://github.com/orgs/firefly-iii/discussions/7940 2023-09-12 05:58:39 +02:00
James Cole
477eebdbe7 Merge pull request #7952 from firefly-iii/dependabot/composer/develop/laravel/framework-10.22.0 2023-09-11 05:49:00 +02:00
James Cole
093bff750c Merge pull request #7951 from firefly-iii/dependabot/composer/develop/laravel/sanctum-3.3.0 2023-09-11 05:48:53 +02:00
James Cole
92e679a9ea Merge pull request #7950 from firefly-iii/dependabot/composer/develop/phpstan/phpstan-1.10.33 2023-09-11 05:48:44 +02:00
James Cole
43232ae45c Merge pull request #7949 from firefly-iii/dependabot/npm_and_yarn/develop/i18n-js-4.3.2 2023-09-11 05:48:30 +02:00
dependabot[bot]
1fb13d8697 chore(deps): bump laravel/framework from 10.21.0 to 10.22.0
Bumps [laravel/framework](https://github.com/laravel/framework) from 10.21.0 to 10.22.0.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/10.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v10.21.0...v10.22.0)

---
updated-dependencies:
- dependency-name: laravel/framework
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-11 03:45:18 +00:00
dependabot[bot]
9ac28b93ca chore(deps): bump laravel/sanctum from 3.2.6 to 3.3.0
Bumps [laravel/sanctum](https://github.com/laravel/sanctum) from 3.2.6 to 3.3.0.
- [Release notes](https://github.com/laravel/sanctum/releases)
- [Changelog](https://github.com/laravel/sanctum/blob/3.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/sanctum/compare/v3.2.6...v3.3.0)

---
updated-dependencies:
- dependency-name: laravel/sanctum
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-11 03:45:07 +00:00
dependabot[bot]
067c01ca06 chore(deps-dev): bump phpstan/phpstan from 1.10.32 to 1.10.33
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.10.32 to 1.10.33.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.11.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.10.32...1.10.33)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-11 03:44:57 +00:00
dependabot[bot]
82040c2a5d chore(deps): bump i18n-js from 4.3.0 to 4.3.2
Bumps [i18n-js](https://github.com/fnando/i18n) from 4.3.0 to 4.3.2.
- [Changelog](https://github.com/fnando/i18n/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fnando/i18n/compare/v4.3.0...v4.3.2)

---
updated-dependencies:
- dependency-name: i18n-js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-11 03:26:50 +00:00
James Cole
62502c746c Stringify IDs for #7944 2023-09-09 15:12:24 +02:00
James Cole
6ab79a87fe Update security txt 2023-09-07 06:38:06 +02:00
James Cole
04ee3b4dc1 Update security.txt 2023-09-06 20:49:09 +02:00
James Cole
9c9af79ad5 Fix #7920 2023-09-06 05:45:35 +02:00
James Cole
dd794e409f Fix issues with relative urls 2023-09-05 19:34:46 +02:00
James Cole
67d29b8416 Merge branch 'release/v6.0.23' 2023-09-03 18:09:17 +02:00
James Cole
5ee80dd046 Merge tag 'v6.0.23' into develop
v6.0.23
2023-09-03 18:09:17 +02:00
James Cole
f62e93b487 Add spans to stop parsing 2023-09-03 18:01:12 +02:00
James Cole
a7cc70b975 Remove whitespace 2023-09-03 18:00:07 +02:00
James Cole
60f0d8074a Meta files for new release. 2023-09-03 17:53:22 +02:00
James Cole
ed1fdf9382 Update files for new release 2023-09-03 17:38:54 +02:00
James Cole
9ea3c4224e Remove extra slashes 2023-09-02 10:47:10 +02:00
James Cole
71325de44e Merge branch 'release/v6.0.22' 2023-09-01 19:41:15 +02:00
James Cole
cdb041e647 Merge tag 'v6.0.22' into develop
v6.0.22
2023-09-01 19:41:15 +02:00
James Cole
b9d750bf59 Meta data for new release. 2023-09-01 19:40:17 +02:00
James Cole
461249737e Fix #7917, add missing return statement 2023-09-01 15:23:10 +02:00
James Cole
1aeaa8b77d Merge tag 'v6.0.21' into develop
v6.0.21
2023-09-01 05:33:52 +02:00
James Cole
a59d7ccdc2 Merge branch 'release/v6.0.21' 2023-09-01 05:33:50 +02:00
James Cole
2c1ca428db Update meta files for new release. 2023-09-01 05:33:02 +02:00
James Cole
224970f3bd New version 2023-09-01 05:16:58 +02:00
James Cole
742d934ddb Catch missing key. 2023-09-01 04:42:49 +02:00
James Cole
1699513023 Fix test 2023-08-31 19:18:16 +02:00
James Cole
488a8a7e86 Fix test 2023-08-31 19:13:06 +02:00
James Cole
dd571d6221 Fix test 2023-08-31 19:02:38 +02:00
James Cole
4cc5128b4c Use relative urls see what breaks. 2023-08-31 18:45:11 +02:00
James Cole
2636a6557a Less notice events. 2023-08-30 18:03:47 +02:00
James Cole
0bf97ccf22 Expand logging 2023-08-30 15:57:59 +02:00
James Cole
592fc71b4e Change some logging settings. 2023-08-30 15:38:15 +02:00
James Cole
0e7712d3b8 Add more tracing 2023-08-30 11:58:44 +02:00
James Cole
80f21d2a4f Fix test 2023-08-30 07:06:43 +02:00
James Cole
5513ec068e Fix test 2023-08-30 06:53:46 +02:00
James Cole
14a46a6197 Add more info to error message. 2023-08-30 06:40:12 +02:00
James Cole
b93ee5efd8 Sort accounts properly 2023-08-29 18:28:29 +02:00
James Cole
cdd4dc6065 Rebuild frontend 2023-08-29 07:34:41 +02:00
James Cole
0d8b2ae799 Fix https://github.com/firefly-iii/firefly-iii/issues/7910 2023-08-29 05:47:13 +02:00
James Cole
77dc79b638 Merge pull request #7898 from firefly-iii/dependabot/composer/develop/phpstan/phpstan-1.10.32 2023-08-28 05:51:54 +02:00
dependabot[bot]
f48723db40 chore(deps-dev): bump phpstan/phpstan from 1.10.29 to 1.10.32
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.10.29 to 1.10.32.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.11.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.10.29...1.10.32)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-28 03:50:38 +00:00
James Cole
ebf91078c5 Merge pull request #7899 from firefly-iii/dependabot/composer/develop/guzzlehttp/guzzle-7.8.0 2023-08-28 05:50:17 +02:00
James Cole
90d0d85dd6 Merge pull request #7900 from firefly-iii/dependabot/composer/develop/laravel/framework-10.20.0 2023-08-28 05:50:06 +02:00
James Cole
0c5b4f7f64 Merge pull request #7901 from firefly-iii/dependabot/composer/develop/laravel/sanctum-3.2.6 2023-08-28 05:49:57 +02:00
James Cole
9c4bb08ed1 Merge pull request #7902 from firefly-iii/dependabot/composer/develop/spatie/laravel-ignition-2.3.0 2023-08-28 05:49:46 +02:00
James Cole
1d3bbde4b0 Merge pull request #7903 from firefly-iii/dependabot/npm_and_yarn/develop/axios-1.5.0 2023-08-28 05:49:36 +02:00
James Cole
b6faee033d Merge pull request #7904 from firefly-iii/dependabot/npm_and_yarn/develop/alpinejs-3.13.0 2023-08-28 05:49:27 +02:00
James Cole
05e0f88d11 Merge pull request #7905 from firefly-iii/dependabot/npm_and_yarn/develop/chart.js-4.4.0 2023-08-28 05:49:17 +02:00
dependabot[bot]
ae9a151140 chore(deps): bump chart.js from 4.3.3 to 4.4.0
Bumps [chart.js](https://github.com/chartjs/Chart.js) from 4.3.3 to 4.4.0.
- [Release notes](https://github.com/chartjs/Chart.js/releases)
- [Commits](https://github.com/chartjs/Chart.js/compare/v4.3.3...v4.4.0)

---
updated-dependencies:
- dependency-name: chart.js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-28 03:25:21 +00:00
dependabot[bot]
da633e3c62 chore(deps): bump alpinejs from 3.12.3 to 3.13.0
Bumps [alpinejs](https://github.com/alpinejs/alpine/tree/HEAD/packages/alpinejs) from 3.12.3 to 3.13.0.
- [Release notes](https://github.com/alpinejs/alpine/releases)
- [Commits](https://github.com/alpinejs/alpine/commits/v3.13.0/packages/alpinejs)

---
updated-dependencies:
- dependency-name: alpinejs
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-28 03:25:10 +00:00
dependabot[bot]
8cb384d3cf chore(deps-dev): bump axios from 1.4.0 to 1.5.0
Bumps [axios](https://github.com/axios/axios) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.4.0...v1.5.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-28 03:24:59 +00:00
dependabot[bot]
de2a34c3ec chore(deps): bump spatie/laravel-ignition from 2.2.0 to 2.3.0
Bumps [spatie/laravel-ignition](https://github.com/spatie/laravel-ignition) from 2.2.0 to 2.3.0.
- [Release notes](https://github.com/spatie/laravel-ignition/releases)
- [Changelog](https://github.com/spatie/laravel-ignition/blob/main/CHANGELOG.md)
- [Commits](https://github.com/spatie/laravel-ignition/compare/2.2.0...2.3.0)

---
updated-dependencies:
- dependency-name: spatie/laravel-ignition
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-28 03:06:43 +00:00
dependabot[bot]
b7c65446a8 chore(deps): bump laravel/sanctum from 3.2.5 to 3.2.6
Bumps [laravel/sanctum](https://github.com/laravel/sanctum) from 3.2.5 to 3.2.6.
- [Release notes](https://github.com/laravel/sanctum/releases)
- [Changelog](https://github.com/laravel/sanctum/blob/3.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/sanctum/compare/v3.2.5...v3.2.6)

---
updated-dependencies:
- dependency-name: laravel/sanctum
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-28 03:06:31 +00:00
dependabot[bot]
bc648b187c chore(deps): bump laravel/framework from 10.19.0 to 10.20.0
Bumps [laravel/framework](https://github.com/laravel/framework) from 10.19.0 to 10.20.0.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/10.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v10.19.0...v10.20.0)

---
updated-dependencies:
- dependency-name: laravel/framework
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-28 03:06:19 +00:00
dependabot[bot]
4de0828b5d chore(deps): bump guzzlehttp/guzzle from 7.7.0 to 7.8.0
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.7.0 to 7.8.0.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/7.8/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/7.7.0...7.8.0)

---
updated-dependencies:
- dependency-name: guzzlehttp/guzzle
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-28 03:06:01 +00:00
James Cole
b2364d26ec Various color fixes. 2023-08-27 18:45:06 +02:00
James Cole
83d94cb792 Expand cache 2023-08-27 07:45:09 +02:00
James Cole
66cc3f48bc Mild code cleanup. 2023-08-26 18:42:18 +02:00
James Cole
63297c43b7 Possible fix for https://github.com/firefly-iii/firefly-iii/issues/7891 2023-08-26 18:40:23 +02:00
James Cole
5b0637558f Better error for invalid date 2023-08-24 05:53:17 +02:00
James Cole
e9a8e104be Change URLs to relative URLs 2023-08-24 05:47:28 +02:00
James Cole
0f524e7800 Add relative route 2023-08-23 07:05:41 +02:00
James Cole
969e0bccc9 Remove slash 2023-08-23 07:04:47 +02:00
James Cole
ba3e026927 Add base href 2023-08-23 07:02:30 +02:00
James Cole
0c6868d477 Add relative paths to JS 2023-08-23 07:00:09 +02:00
James Cole
7f70cf47ec Fix https://github.com/firefly-iii/firefly-iii/issues/7883 2023-08-22 16:08:19 +02:00
James Cole
fa4492287d Rebuild frontend 2023-08-22 08:28:52 +02:00
James Cole
60809c688e Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2023-08-22 08:25:16 +02:00
James Cole
2404f5299c New code for transaction processing and frontend 2023-08-22 08:25:06 +02:00
James Cole
21a394eaf5 Merge pull request #7873 from firefly-iii/dependabot/composer/develop/doctrine/dbal-3.6.6
chore(deps): bump doctrine/dbal from 3.6.5 to 3.6.6
2023-08-21 05:41:31 +02:00
dependabot[bot]
419d7846c9 chore(deps): bump doctrine/dbal from 3.6.5 to 3.6.6
Bumps [doctrine/dbal](https://github.com/doctrine/dbal) from 3.6.5 to 3.6.6.
- [Release notes](https://github.com/doctrine/dbal/releases)
- [Commits](https://github.com/doctrine/dbal/compare/3.6.5...3.6.6)

---
updated-dependencies:
- dependency-name: doctrine/dbal
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-21 03:38:59 +00:00
James Cole
0827accc39 Merge pull request #7872 from firefly-iii/dependabot/npm_and_yarn/develop/sass-1.66.1 2023-08-21 05:38:48 +02:00
James Cole
2e53f7d0b7 Merge pull request #7874 from firefly-iii/dependabot/composer/develop/predis/predis-2.2.1 2023-08-21 05:38:27 +02:00
James Cole
bdfcf8ec95 Merge pull request #7875 from firefly-iii/dependabot/composer/develop/laravel/framework-10.19.0 2023-08-21 05:38:18 +02:00
James Cole
6a20170e00 Merge pull request #7876 from firefly-iii/dependabot/composer/develop/phpstan/phpstan-1.10.29 2023-08-21 05:38:00 +02:00
James Cole
0c974f1ff7 Merge pull request #7877 from firefly-iii/dependabot/composer/develop/ergebnis/phpstan-rules-2.1.0 2023-08-21 05:37:48 +02:00
dependabot[bot]
9c098d45c5 chore(deps-dev): bump ergebnis/phpstan-rules from 2.0.0 to 2.1.0
Bumps [ergebnis/phpstan-rules](https://github.com/ergebnis/phpstan-rules) from 2.0.0 to 2.1.0.
- [Release notes](https://github.com/ergebnis/phpstan-rules/releases)
- [Changelog](https://github.com/ergebnis/phpstan-rules/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ergebnis/phpstan-rules/compare/2.0.0...2.1.0)

---
updated-dependencies:
- dependency-name: ergebnis/phpstan-rules
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-21 03:25:35 +00:00
dependabot[bot]
cfdf9aa8dc chore(deps-dev): bump phpstan/phpstan from 1.10.28 to 1.10.29
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.10.28 to 1.10.29.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.11.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.10.28...1.10.29)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-21 03:25:31 +00:00
dependabot[bot]
2ea74542e6 chore(deps): bump laravel/framework from 10.18.0 to 10.19.0
Bumps [laravel/framework](https://github.com/laravel/framework) from 10.18.0 to 10.19.0.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/10.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v10.18.0...v10.19.0)

---
updated-dependencies:
- dependency-name: laravel/framework
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-21 03:25:26 +00:00
dependabot[bot]
7fcaa2b5fb chore(deps): bump predis/predis from 2.2.0 to 2.2.1
Bumps [predis/predis](https://github.com/predis/predis) from 2.2.0 to 2.2.1.
- [Release notes](https://github.com/predis/predis/releases)
- [Changelog](https://github.com/predis/predis/blob/v2.x/CHANGELOG.md)
- [Commits](https://github.com/predis/predis/compare/v2.2.0...v2.2.1)

---
updated-dependencies:
- dependency-name: predis/predis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-21 03:25:12 +00:00
dependabot[bot]
e9e905e495 chore(deps-dev): bump sass from 1.65.1 to 1.66.1
Bumps [sass](https://github.com/sass/dart-sass) from 1.65.1 to 1.66.1.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.65.1...1.66.1)

---
updated-dependencies:
- dependency-name: sass
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-21 03:12:29 +00:00
James Cole
f67ff98d78 More exact search for available budgets. #7853 2023-08-15 18:37:47 +02:00
James Cole
e3c4dde4ff Add cleanup method for issue #7853 and some more debug info. 2023-08-15 17:57:02 +02:00
James Cole
9787561000 Potential solution for #7853 2023-08-15 17:19:50 +02:00
James Cole
cd041b4c75 Add debug info for #7853 2023-08-15 16:22:54 +02:00
James Cole
60ee70c926 Check for rule triggers in #7853 2023-08-15 16:17:54 +02:00
James Cole
00de78b6f1 Also support Discord. 2023-08-15 13:52:30 +02:00
James Cole
33a841b831 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2023-08-15 13:51:51 +02:00
James Cole
df66dcf102 Various UI fixes 2023-08-15 13:51:38 +02:00
James Cole
086a7a0b1e Merge pull request #7848 from firefly-iii/dependabot/npm_and_yarn/develop/laravel-vite-plugin-0.8.0 2023-08-14 06:58:21 +02:00
dependabot[bot]
ec0ba3d212 chore(deps-dev): bump laravel-vite-plugin from 0.7.8 to 0.8.0
Bumps [laravel-vite-plugin](https://github.com/laravel/vite-plugin) from 0.7.8 to 0.8.0.
- [Release notes](https://github.com/laravel/vite-plugin/releases)
- [Changelog](https://github.com/laravel/vite-plugin/blob/main/CHANGELOG.md)
- [Commits](https://github.com/laravel/vite-plugin/compare/v0.7.8...v0.8.0)

---
updated-dependencies:
- dependency-name: laravel-vite-plugin
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-14 03:58:10 +00:00
James Cole
b0ab06b7eb Add rule error reporting to all rules. 2023-08-13 15:01:12 +02:00
James Cole
965acd6d45 Finetune index. 2023-08-13 14:30:16 +02:00
James Cole
4d156870ef Add nonce to scripts 2023-08-13 07:30:19 +02:00
James Cole
499720df46 Fix math issue in summary controller. 2023-08-13 07:24:51 +02:00
James Cole
610bc108e7 Add some slack notifications and a todo to fix the rest 2023-08-12 20:57:51 +02:00
James Cole
53f1b0218c Merge tag 'v6.0.20' into develop
v6.0.20
2023-08-12 19:56:11 +02:00
306 changed files with 8878 additions and 4944 deletions

View File

@@ -79,16 +79,16 @@
}, },
{ {
"name": "composer/semver", "name": "composer/semver",
"version": "3.3.2", "version": "3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/semver.git", "url": "https://github.com/composer/semver.git",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -138,9 +138,9 @@
"versioning" "versioning"
], ],
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues", "issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.3.2" "source": "https://github.com/composer/semver/tree/3.4.0"
}, },
"funding": [ "funding": [
{ {
@@ -156,7 +156,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-04-01T19:23:25+00:00" "time": "2023-08-31T09:50:34+00:00"
}, },
{ {
"name": "composer/xdebug-handler", "name": "composer/xdebug-handler",
@@ -224,178 +224,23 @@
], ],
"time": "2022-02-25T21:32:43+00:00" "time": "2022-02-25T21:32:43+00:00"
}, },
{
"name": "doctrine/annotations",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
"shasum": ""
},
"require": {
"doctrine/lexer": "^2 || ^3",
"ext-tokenizer": "*",
"php": "^7.2 || ^8.0",
"psr/cache": "^1 || ^2 || ^3"
},
"require-dev": {
"doctrine/cache": "^2.0",
"doctrine/coding-standard": "^10",
"phpstan/phpstan": "^1.8.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"symfony/cache": "^5.4 || ^6",
"vimeo/psalm": "^4.10"
},
"suggest": {
"php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Docblock Annotations Parser",
"homepage": "https://www.doctrine-project.org/projects/annotations.html",
"keywords": [
"annotations",
"docblock",
"parser"
],
"support": {
"issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/2.0.1"
},
"time": "2023-02-02T22:02:53+00:00"
},
{
"name": "doctrine/lexer",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "84a527db05647743d50373e0ec53a152f2cde568"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568",
"reference": "84a527db05647743d50373e0ec53a152f2cde568",
"shasum": ""
},
"require": {
"php": "^8.1"
},
"require-dev": {
"doctrine/coding-standard": "^10",
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^9.5",
"psalm/plugin-phpunit": "^0.18.3",
"vimeo/psalm": "^5.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Lexer\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
"keywords": [
"annotations",
"docblock",
"lexer",
"parser",
"php"
],
"support": {
"issues": "https://github.com/doctrine/lexer/issues",
"source": "https://github.com/doctrine/lexer/tree/3.0.0"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
"type": "tidelift"
}
],
"time": "2022-12-15T16:57:16+00:00"
},
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.22.0", "version": "v3.26.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "92b019f6c8d79aa26349d0db7671d37440dc0ff3" "reference": "d023ba6684055f6ea1da1352d8a02baca0426983"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/92b019f6c8d79aa26349d0db7671d37440dc0ff3", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/d023ba6684055f6ea1da1352d8a02baca0426983",
"reference": "92b019f6c8d79aa26349d0db7671d37440dc0ff3", "reference": "d023ba6684055f6ea1da1352d8a02baca0426983",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"composer/semver": "^3.3", "composer/semver": "^3.3",
"composer/xdebug-handler": "^3.0.3", "composer/xdebug-handler": "^3.0.3",
"doctrine/annotations": "^2",
"doctrine/lexer": "^2 || ^3",
"ext-json": "*", "ext-json": "*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": "^7.4 || ^8.0", "php": "^7.4 || ^8.0",
@@ -464,7 +309,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.22.0" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.26.1"
}, },
"funding": [ "funding": [
{ {
@@ -472,56 +317,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-07-16T23:08:06+00:00" "time": "2023-09-08T19:09:07+00:00"
},
{
"name": "psr/cache",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
"keywords": [
"cache",
"psr",
"psr-6"
],
"support": {
"source": "https://github.com/php-fig/cache/tree/3.0.0"
},
"time": "2021-02-03T23:26:27+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@@ -745,16 +541,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v6.3.2", "version": "v6.3.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898" "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/aa5d64ad3f63f2e48964fc81ee45cb318a723898", "url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6",
"reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898", "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -815,7 +611,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v6.3.2" "source": "https://github.com/symfony/console/tree/v6.3.4"
}, },
"funding": [ "funding": [
{ {
@@ -831,7 +627,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-19T20:17:28+00:00" "time": "2023-08-16T10:10:12+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@@ -1252,16 +1048,16 @@
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git", "url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a" "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1276,7 +1072,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1314,7 +1110,7 @@
"portable" "portable"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -1330,20 +1126,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-01-26T09:26:14+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-grapheme", "name": "symfony/polyfill-intl-grapheme",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354" "reference": "875e90aeea2777b6f135677f618529449334a612"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354", "reference": "875e90aeea2777b6f135677f618529449334a612",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1355,7 +1151,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1395,7 +1191,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -1411,20 +1207,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-01-26T09:26:14+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-normalizer", "name": "symfony/polyfill-intl-normalizer",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1436,7 +1232,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1479,7 +1275,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -1495,20 +1291,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-01-26T09:26:14+00:00"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" "reference": "42292d99c55abe617799667f454222c54c60e229"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1523,7 +1319,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1562,7 +1358,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -1578,20 +1374,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-07-28T09:04:16+00:00"
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1600,7 +1396,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1645,7 +1441,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -1661,20 +1457,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-01-26T09:26:14+00:00"
}, },
{ {
"name": "symfony/polyfill-php81", "name": "symfony/polyfill-php81",
"version": "v1.27.0", "version": "v1.28.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php81.git", "url": "https://github.com/symfony/polyfill-php81.git",
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b",
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1683,7 +1479,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.27-dev" "dev-main": "1.28-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@@ -1724,7 +1520,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0"
}, },
"funding": [ "funding": [
{ {
@@ -1740,20 +1536,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2023-01-26T09:26:14+00:00"
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v6.3.2", "version": "v6.3.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "c5ce962db0d9b6e80247ca5eb9af6472bd4d7b5d" "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/c5ce962db0d9b6e80247ca5eb9af6472bd4d7b5d", "url": "https://api.github.com/repos/symfony/process/zipball/0b5c29118f2e980d455d2e34a5659f4579847c54",
"reference": "c5ce962db0d9b6e80247ca5eb9af6472bd4d7b5d", "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1785,7 +1581,7 @@
"description": "Executes commands in sub-processes", "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/process/tree/v6.3.2" "source": "https://github.com/symfony/process/tree/v6.3.4"
}, },
"funding": [ "funding": [
{ {
@@ -1801,7 +1597,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-12T16:00:22+00:00" "time": "2023-08-07T10:39:22+00:00"
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",

View File

@@ -45,12 +45,6 @@ TRUSTED_PROXIES=
# Default setting 'stack' will log to 'daily' and to 'stdout' at the same time. # Default setting 'stack' will log to 'daily' and to 'stdout' at the same time.
LOG_CHANNEL=stack LOG_CHANNEL=stack
#
# Used when logging to papertrail:
#
PAPERTRAIL_HOST=
PAPERTRAIL_PORT=
# Log level. You can set this from least severe to most severe: # Log level. You can set this from least severe to most severe:
# debug, info, notice, warning, error, critical, alert, emergency # debug, info, notice, warning, error, critical, alert, emergency
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably # If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
@@ -58,8 +52,30 @@ PAPERTRAIL_PORT=
APP_LOG_LEVEL=notice APP_LOG_LEVEL=notice
# Audit log level. # Audit log level.
# Set this to "emergency" if you dont want to store audit logs, leave on info otherwise. # The audit log is used to log notable Firefly III events on a separate channel.
AUDIT_LOG_LEVEL=info # These log entries may contain sensitive financial information.
# The audit log is disabled by default.
#
# To enable it, set AUDIT_LOG_LEVEL to "info"
# To disable it, set AUDIT_LOG_LEVEL to "emergency"
AUDIT_LOG_LEVEL=emergency
#
# If you want, you can redirect the audit logs to another channel.
# Set 'audit_stdout', 'audit_syslog', 'audit_errorlog' to log to the system itself.
# Use audit_daily to log to a rotating file.
# Use audit_papertrail to log to papertrail.
#
# If you do this, the audit logs may be mixed with normal logs because the settings for these channels
# are often the same as the settings for the normal logs.
AUDIT_LOG_CHANNEL=
#
# Used when logging to papertrail:
# Also used when audit logs log to papertrail:
#
PAPERTRAIL_HOST=
PAPERTRAIL_PORT=
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III # Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# For other database types, please see the FAQ: https://docs.firefly-iii.org/firefly-iii/faq/self-hosted/#i-want-to-use-sqlite # For other database types, please see the FAQ: https://docs.firefly-iii.org/firefly-iii/faq/self-hosted/#i-want-to-use-sqlite

View File

@@ -105,7 +105,7 @@ class AccountController extends Controller
'name' => $account->name, 'name' => $account->name,
'name_with_balance' => $nameWithBalance, 'name_with_balance' => $nameWithBalance,
'type' => $account->accountType->type, 'type' => $account->accountType->type,
'currency_id' => $currency->id, 'currency_id' => (string)$currency->id,
'currency_name' => $currency->name, 'currency_name' => $currency->name,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,

View File

@@ -102,6 +102,7 @@ abstract class Controller extends BaseController
} catch (BadRequestException $e) { } catch (BadRequestException $e) {
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field)); Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field));
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$value = null; $value = null;
} }
$obj = null; $obj = null;
@@ -130,6 +131,7 @@ abstract class Controller extends BaseController
} catch (BadRequestException $e) { } catch (BadRequestException $e) {
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $integer)); Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $integer));
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$value = null; $value = null;
} }
if (null !== $value) { if (null !== $value) {
@@ -154,6 +156,7 @@ abstract class Controller extends BaseController
} catch (BadRequestException $e) { } catch (BadRequestException $e) {
Log::error('Request field "sort" contains a non-scalar value. Value set to NULL.'); Log::error('Request field "sort" contains a non-scalar value. Value set to NULL.');
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$param = ''; $param = '';
} }
if ('' === $param) { if ('' === $param) {

View File

@@ -190,7 +190,7 @@ class BasicController extends Controller
'key' => sprintf('balance-in-%s', $currency->code), 'key' => sprintf('balance-in-%s', $currency->code),
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]), 'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $sums[$currencyId] ?? '0', 'monetary_value' => $sums[$currencyId] ?? '0',
'currency_id' => $currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -203,7 +203,7 @@ class BasicController extends Controller
'key' => sprintf('spent-in-%s', $currency->code), 'key' => sprintf('spent-in-%s', $currency->code),
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]), 'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $expenses[$currencyId] ?? '0', 'monetary_value' => $expenses[$currencyId] ?? '0',
'currency_id' => $currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -215,7 +215,7 @@ class BasicController extends Controller
'key' => sprintf('earned-in-%s', $currency->code), 'key' => sprintf('earned-in-%s', $currency->code),
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]), 'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $incomes[$currencyId] ?? '0', 'monetary_value' => $incomes[$currencyId] ?? '0',
'currency_id' => $currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -253,7 +253,7 @@ class BasicController extends Controller
'key' => sprintf('bills-paid-in-%s', $info['code']), 'key' => sprintf('bills-paid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]), 'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]),
'monetary_value' => $amount, 'monetary_value' => $amount,
'currency_id' => $info['id'], 'currency_id' => (string)$info['id'],
'currency_code' => $info['code'], 'currency_code' => $info['code'],
'currency_symbol' => $info['symbol'], 'currency_symbol' => $info['symbol'],
'currency_decimal_places' => $info['decimal_places'], 'currency_decimal_places' => $info['decimal_places'],
@@ -272,7 +272,7 @@ class BasicController extends Controller
'key' => sprintf('bills-unpaid-in-%s', $info['code']), 'key' => sprintf('bills-unpaid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]), 'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]),
'monetary_value' => $amount, 'monetary_value' => $amount,
'currency_id' => $info['id'], 'currency_id' => (string)$info['id'],
'currency_code' => $info['code'], 'currency_code' => $info['code'],
'currency_symbol' => $info['symbol'], 'currency_symbol' => $info['symbol'],
'currency_decimal_places' => $info['decimal_places'], 'currency_decimal_places' => $info['decimal_places'],
@@ -302,7 +302,7 @@ class BasicController extends Controller
foreach ($spent as $row) { foreach ($spent as $row) {
// either an amount was budgeted or 0 is available. // either an amount was budgeted or 0 is available.
$amount = $available[$row['currency_id']] ?? '0'; $amount = (string)($available[$row['currency_id']] ?? '0');
$spentInCurrency = $row['sum']; $spentInCurrency = $row['sum'];
$leftToSpend = bcadd($amount, $spentInCurrency); $leftToSpend = bcadd($amount, $spentInCurrency);
@@ -316,7 +316,7 @@ class BasicController extends Controller
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']), 'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]), 'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]),
'monetary_value' => $leftToSpend, 'monetary_value' => $leftToSpend,
'currency_id' => $row['currency_id'], 'currency_id' => (string)$row['currency_id'],
'currency_code' => $row['currency_code'], 'currency_code' => $row['currency_code'],
'currency_symbol' => $row['currency_symbol'], 'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'], 'currency_decimal_places' => $row['currency_decimal_places'],
@@ -381,7 +381,7 @@ class BasicController extends Controller
'key' => sprintf('net-worth-in-%s', $currency->code), 'key' => sprintf('net-worth-in-%s', $currency->code),
'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $currency->symbol]), 'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $amount, 'monetary_value' => $amount,
'currency_id' => $currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,

View File

@@ -104,7 +104,7 @@ class AccountController extends Controller
'name' => $account->name, 'name' => $account->name,
'name_with_balance' => $nameWithBalance, 'name_with_balance' => $nameWithBalance,
'type' => $account->accountType->type, 'type' => $account->accountType->type,
'currency_id' => $currency->id, 'currency_id' => (string)$currency->id,
'currency_name' => $currency->name, 'currency_name' => $currency->name,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,

View File

@@ -114,7 +114,7 @@ class AccountController extends Controller
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
// the default currency of the user (could be the same!) // the default currency of the user (could be the same!)
'native_id' => (int)$default->id, 'native_id' => (string)$default->id,
'native_code' => $default->code, 'native_code' => $default->code,
'native_symbol' => $default->symbol, 'native_symbol' => $default->symbol,
'native_decimal_places' => (int)$default->decimal_places, 'native_decimal_places' => (int)$default->decimal_places,

View File

@@ -112,12 +112,12 @@ class BalanceController extends Controller
// set array for default currency (even if unused later on) // set array for default currency (even if unused later on)
$defaultCurrencyId = (int)$default->id; $defaultCurrencyId = (int)$default->id;
$data[$defaultCurrencyId] = [ $data[$defaultCurrencyId] = [
'currency_id' => $defaultCurrencyId, 'currency_id' => (string)$defaultCurrencyId,
'currency_symbol' => $default->symbol, 'currency_symbol' => $default->symbol,
'currency_code' => $default->code, 'currency_code' => $default->code,
'currency_name' => $default->name, 'currency_name' => $default->name,
'currency_decimal_places' => (int)$default->decimal_places, 'currency_decimal_places' => (int)$default->decimal_places,
'native_id' => $defaultCurrencyId, 'native_id' => (string)$defaultCurrencyId,
'native_symbol' => $default->symbol, 'native_symbol' => $default->symbol,
'native_code' => $default->code, 'native_code' => $default->code,
'native_name' => $default->name, 'native_name' => $default->name,
@@ -138,13 +138,13 @@ class BalanceController extends Controller
// set the array with monetary info, if it does not exist. // set the array with monetary info, if it does not exist.
$data[$currencyId] = $data[$currencyId] ?? [ $data[$currencyId] = $data[$currencyId] ?? [
'currency_id' => $currencyId, 'currency_id' => (string)$currencyId,
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
'currency_decimal_places' => $journal['currency_decimal_places'], 'currency_decimal_places' => $journal['currency_decimal_places'],
// native currency info (could be the same) // native currency info (could be the same)
'native_id' => (int)$default->id, 'native_id' => (string)$default->id,
'native_code' => $default->code, 'native_code' => $default->code,
'native_symbol' => $default->symbol, 'native_symbol' => $default->symbol,
'native_decimal_places' => (int)$default->decimal_places, 'native_decimal_places' => (int)$default->decimal_places,
@@ -203,11 +203,11 @@ class BalanceController extends Controller
// income and expense array prepped: // income and expense array prepped:
$income = [ $income = [
'label' => 'earned', 'label' => 'earned',
'currency_id' => $currency['currency_id'], 'currency_id' => (string)$currency['currency_id'],
'currency_symbol' => $currency['currency_symbol'], 'currency_symbol' => $currency['currency_symbol'],
'currency_code' => $currency['currency_code'], 'currency_code' => $currency['currency_code'],
'currency_decimal_places' => $currency['currency_decimal_places'], 'currency_decimal_places' => $currency['currency_decimal_places'],
'native_id' => $currency['native_id'], 'native_id' => (string)$currency['native_id'],
'native_symbol' => $currency['native_symbol'], 'native_symbol' => $currency['native_symbol'],
'native_code' => $currency['native_code'], 'native_code' => $currency['native_code'],
'native_decimal_places' => $currency['native_decimal_places'], 'native_decimal_places' => $currency['native_decimal_places'],
@@ -219,11 +219,11 @@ class BalanceController extends Controller
]; ];
$expense = [ $expense = [
'label' => 'spent', 'label' => 'spent',
'currency_id' => $currency['currency_id'], 'currency_id' => (string)$currency['currency_id'],
'currency_symbol' => $currency['currency_symbol'], 'currency_symbol' => $currency['currency_symbol'],
'currency_code' => $currency['currency_code'], 'currency_code' => $currency['currency_code'],
'currency_decimal_places' => $currency['currency_decimal_places'], 'currency_decimal_places' => $currency['currency_decimal_places'],
'native_id' => $currency['native_id'], 'native_id' => (string)$currency['native_id'],
'native_symbol' => $currency['native_symbol'], 'native_symbol' => $currency['native_symbol'],
'native_code' => $currency['native_code'], 'native_code' => $currency['native_code'],
'native_decimal_places' => $currency['native_decimal_places'], 'native_decimal_places' => $currency['native_decimal_places'],

View File

@@ -128,11 +128,11 @@ class BudgetController extends Controller
foreach ($rows as $row) { foreach ($rows as $row) {
$current = [ $current = [
'label' => $budget->name, 'label' => $budget->name,
'currency_id' => $row['currency_id'], 'currency_id' => (string)$row['currency_id'],
'currency_code' => $row['currency_code'], 'currency_code' => $row['currency_code'],
'currency_name' => $row['currency_name'], 'currency_name' => $row['currency_name'],
'currency_decimal_places' => $row['currency_decimal_places'], 'currency_decimal_places' => $row['currency_decimal_places'],
'native_id' => $row['native_id'], 'native_id' => (string)$row['native_id'],
'native_code' => $row['native_code'], 'native_code' => $row['native_code'],
'native_name' => $row['native_name'], 'native_name' => $row['native_name'],
'native_decimal_places' => $row['native_decimal_places'], 'native_decimal_places' => $row['native_decimal_places'],
@@ -199,12 +199,12 @@ class BudgetController extends Controller
foreach ($array as $currencyId => $block) { foreach ($array as $currencyId => $block) {
$this->currencies[$currencyId] = $this->currencies[$currencyId] ?? TransactionCurrency::find($currencyId); $this->currencies[$currencyId] = $this->currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
$return[$currencyId] = $return[$currencyId] ?? [ $return[$currencyId] = $return[$currencyId] ?? [
'currency_id' => $currencyId, 'currency_id' => (string)$currencyId,
'currency_code' => $block['currency_code'], 'currency_code' => $block['currency_code'],
'currency_name' => $block['currency_name'], 'currency_name' => $block['currency_name'],
'currency_symbol' => $block['currency_symbol'], 'currency_symbol' => $block['currency_symbol'],
'currency_decimal_places' => (int)$block['currency_decimal_places'], 'currency_decimal_places' => (int)$block['currency_decimal_places'],
'native_id' => (int)$this->currency->id, 'native_id' => (string)$this->currency->id,
'native_code' => $this->currency->code, 'native_code' => $this->currency->code,
'native_name' => $this->currency->name, 'native_name' => $this->currency->name,
'native_symbol' => $this->currency->symbol, 'native_symbol' => $this->currency->symbol,

View File

@@ -103,12 +103,12 @@ class CategoryController extends Controller
// create arrays // create arrays
$return[$key] = $return[$key] ?? [ $return[$key] = $return[$key] ?? [
'label' => $categoryName, 'label' => $categoryName,
'currency_id' => (int)$currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_name' => $currency->name, 'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places, 'currency_decimal_places' => (int)$currency->decimal_places,
'native_id' => (int)$default->id, 'native_id' => (string)$default->id,
'native_code' => $default->code, 'native_code' => $default->code,
'native_name' => $default->name, 'native_name' => $default->name,
'native_symbol' => $default->symbol, 'native_symbol' => $default->symbol,

View File

@@ -99,6 +99,7 @@ class Controller extends BaseController
} catch (BadRequestException $e) { } catch (BadRequestException $e) {
Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field)); Log::error(sprintf('Request field "%s" contains a non-scalar value. Value set to NULL.', $field));
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
} }
if (null !== $date) { if (null !== $date) {
try { try {

View File

@@ -24,7 +24,9 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Model\Bill; namespace FireflyIII\Api\V2\Controllers\Model\Bill;
use FireflyIII\Api\V2\Controllers\Controller; use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Administration\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Administration\Bill\BillRepositoryInterface;
use FireflyIII\Transformers\V2\AccountTransformer;
use FireflyIII\Transformers\V2\BillTransformer; use FireflyIII\Transformers\V2\BillTransformer;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -71,4 +73,17 @@ class ShowController extends Controller
->json($this->jsonApiList('subscriptions', $paginator, $transformer)) ->json($this->jsonApiList('subscriptions', $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE); ->header('Content-Type', self::CONTENT_TYPE);
} }
/**
* TODO this endpoint is not documented
*/
public function show(Request $request, Bill $bill): JsonResponse
{
$transformer = new BillTransformer();
$transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject('subscriptions', $bill, $transformer))
->header('Content-Type', self::CONTENT_TYPE);
}
} }

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
/*
* StoreController.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Api\V2\Controllers\Model\Transaction;
use FireflyIII\Api\V2\Controllers\Controller;
use Illuminate\Http\JsonResponse;
/**
* Class StoreController
*/
class StoreController extends Controller
{
/**
* @return JsonResponse
*/
public function post(): JsonResponse
{
return response()->json([]);
}
}

View File

@@ -105,10 +105,6 @@ class BasicController extends Controller
$end = $this->parameters->get('end'); $end = $this->parameters->get('end');
// balance information: // balance information:
$balanceData = [];
$billData = [];
$spentData = [];
$netWorthData = [];
$balanceData = $this->getBalanceInformation($start, $end); $balanceData = $this->getBalanceInformation($start, $end);
$billData = $this->getBillInformation($start, $end); $billData = $this->getBillInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end); $spentData = $this->getLeftToSpendInfo($start, $end);
@@ -127,9 +123,15 @@ class BasicController extends Controller
private function getBalanceInformation(Carbon $start, Carbon $end): array private function getBalanceInformation(Carbon $start, Carbon $end): array
{ {
// prep some arrays: // prep some arrays:
$incomes = []; $incomes = [
$expenses = []; 'native' => '0',
$sums = []; ];
$expenses = [
'native' => '0',
];
$sums = [
'native' => '0',
];
$return = []; $return = [];
$currencies = []; $currencies = [];
$converter = new ExchangeRateConverter(); $converter = new ExchangeRateConverter();
@@ -218,7 +220,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => 'balance-in-native', 'key' => 'balance-in-native',
'value' => $sums['native'], 'value' => $sums['native'],
'currency_id' => $default->id, 'currency_id' => (string)$default->id,
'currency_code' => $default->code, 'currency_code' => $default->code,
'currency_symbol' => $default->symbol, 'currency_symbol' => $default->symbol,
'currency_decimal_places' => $default->decimal_places, 'currency_decimal_places' => $default->decimal_places,
@@ -226,7 +228,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => 'spent-in-native', 'key' => 'spent-in-native',
'value' => $expenses['native'], 'value' => $expenses['native'],
'currency_id' => $default->id, 'currency_id' => (string)$default->id,
'currency_code' => $default->code, 'currency_code' => $default->code,
'currency_symbol' => $default->symbol, 'currency_symbol' => $default->symbol,
'currency_decimal_places' => $default->decimal_places, 'currency_decimal_places' => $default->decimal_places,
@@ -234,7 +236,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => 'earned-in-native', 'key' => 'earned-in-native',
'value' => $incomes['native'], 'value' => $incomes['native'],
'currency_id' => $default->id, 'currency_id' => (string)$default->id,
'currency_code' => $default->code, 'currency_code' => $default->code,
'currency_symbol' => $default->symbol, 'currency_symbol' => $default->symbol,
'currency_decimal_places' => $default->decimal_places, 'currency_decimal_places' => $default->decimal_places,
@@ -253,7 +255,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('balance-in-%s', $currency->code), 'key' => sprintf('balance-in-%s', $currency->code),
'value' => $sums[$currencyId] ?? '0', 'value' => $sums[$currencyId] ?? '0',
'currency_id' => $currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -261,7 +263,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('spent-in-%s', $currency->code), 'key' => sprintf('spent-in-%s', $currency->code),
'value' => $expenses[$currencyId] ?? '0', 'value' => $expenses[$currencyId] ?? '0',
'currency_id' => $currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -269,7 +271,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('earned-in-%s', $currency->code), 'key' => sprintf('earned-in-%s', $currency->code),
'value' => $incomes[$currencyId] ?? '0', 'value' => $incomes[$currencyId] ?? '0',
'currency_id' => $currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -303,7 +305,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('bills-paid-in-%s', $info['currency_code']), 'key' => sprintf('bills-paid-in-%s', $info['currency_code']),
'value' => $amount, 'value' => $amount,
'currency_id' => $info['currency_id'], 'currency_id' => (string)$info['currency_id'],
'currency_code' => $info['currency_code'], 'currency_code' => $info['currency_code'],
'currency_symbol' => $info['currency_symbol'], 'currency_symbol' => $info['currency_symbol'],
'currency_decimal_places' => $info['currency_decimal_places'], 'currency_decimal_places' => $info['currency_decimal_places'],
@@ -311,7 +313,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => 'bills-paid-in-native', 'key' => 'bills-paid-in-native',
'value' => $nativeAmount, 'value' => $nativeAmount,
'currency_id' => $info['native_id'], 'currency_id' => (string)$info['native_id'],
'currency_code' => $info['native_code'], 'currency_code' => $info['native_code'],
'currency_symbol' => $info['native_symbol'], 'currency_symbol' => $info['native_symbol'],
'currency_decimal_places' => $info['native_decimal_places'], 'currency_decimal_places' => $info['native_decimal_places'],
@@ -327,7 +329,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('bills-unpaid-in-%s', $info['currency_code']), 'key' => sprintf('bills-unpaid-in-%s', $info['currency_code']),
'value' => $amount, 'value' => $amount,
'currency_id' => $info['currency_id'], 'currency_id' => (string)$info['currency_id'],
'currency_code' => $info['currency_code'], 'currency_code' => $info['currency_code'],
'currency_symbol' => $info['currency_symbol'], 'currency_symbol' => $info['currency_symbol'],
'currency_decimal_places' => $info['currency_decimal_places'], 'currency_decimal_places' => $info['currency_decimal_places'],
@@ -335,7 +337,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => 'bills-unpaid-in-native', 'key' => 'bills-unpaid-in-native',
'value' => $nativeAmount, 'value' => $nativeAmount,
'currency_id' => $info['native_id'], 'currency_id' => (string)$info['native_id'],
'currency_code' => $info['native_code'], 'currency_code' => $info['native_code'],
'currency_symbol' => $info['native_symbol'], 'currency_symbol' => $info['native_symbol'],
'currency_decimal_places' => $info['native_decimal_places'], 'currency_decimal_places' => $info['native_decimal_places'],
@@ -354,6 +356,7 @@ class BasicController extends Controller
*/ */
private function getLeftToSpendInfo(Carbon $start, Carbon $end): array private function getLeftToSpendInfo(Carbon $start, Carbon $end): array
{ {
app('log')->debug('Now in getLeftToSpendInfo');
$return = []; $return = [];
$today = today(config('app.timezone')); $today = today(config('app.timezone'));
$available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end); $available = $this->abRepository->getAvailableBudgetWithCurrency($start, $end);
@@ -367,7 +370,7 @@ class BasicController extends Controller
$nativeLeft = [ $nativeLeft = [
'key' => 'left-to-spend-in-native', 'key' => 'left-to-spend-in-native',
'value' => '0', 'value' => '0',
'currency_id' => (int)$default->id, 'currency_id' => (string)$default->id,
'currency_code' => $default->code, 'currency_code' => $default->code,
'currency_symbol' => $default->symbol, 'currency_symbol' => $default->symbol,
'currency_decimal_places' => (int)$default->decimal_places, 'currency_decimal_places' => (int)$default->decimal_places,
@@ -375,7 +378,7 @@ class BasicController extends Controller
$nativePerDay = [ $nativePerDay = [
'key' => 'left-per-day-to-spend-in-native', 'key' => 'left-per-day-to-spend-in-native',
'value' => '0', 'value' => '0',
'currency_id' => (int)$default->id, 'currency_id' => (string)$default->id,
'currency_code' => $default->code, 'currency_code' => $default->code,
'currency_symbol' => $default->symbol, 'currency_symbol' => $default->symbol,
'currency_decimal_places' => (int)$default->decimal_places, 'currency_decimal_places' => (int)$default->decimal_places,
@@ -386,17 +389,20 @@ class BasicController extends Controller
* @var array $row * @var array $row
*/ */
foreach ($spent as $currencyId => $row) { foreach ($spent as $currencyId => $row) {
app('log')->debug(sprintf('Processing spent array in currency #%d', $currencyId));
$currencyId = (int)$currencyId;
$spent = '0'; $spent = '0';
$spentNative = '0'; $spentNative = '0';
// get the sum from the array of transactions (double loop but who cares) // get the sum from the array of transactions (double loop but who cares)
/** @var array $budget */ /** @var array $budget */
foreach ($row['budgets'] as $budget) { foreach ($row['budgets'] as $budget) {
app('log')->debug(sprintf('Processing expenses in budget "%s".', $budget['name']));
/** @var array $journal */ /** @var array $journal */
foreach ($budget['transaction_journals'] as $journal) { foreach ($budget['transaction_journals'] as $journal) {
$journalCurrencyId = $journal['currency_id']; $journalCurrencyId = $journal['currency_id'];
$currency = $currencies[$journalCurrencyId] ?? $this->currencyRepos->find($journalCurrencyId); $currency = $currencies[$journalCurrencyId] ?? $this->currencyRepos->find($journalCurrencyId);
$currencies[$currencyId] = $currency; $currencies[$currencyId] = $currency;
$amount = bcmul($journal['amount'], '-1'); $amount = app('steam')->negative($journal['amount']);
$amountNative = $converter->convert($default, $currency, $start, $amount); $amountNative = $converter->convert($default, $currency, $start, $amount);
if ((int)$journal['foreign_currency_id'] === (int)$default->id) { if ((int)$journal['foreign_currency_id'] === (int)$default->id) {
$amountNative = $journal['foreign_amount']; $amountNative = $journal['foreign_amount'];
@@ -404,15 +410,18 @@ class BasicController extends Controller
$spent = bcadd($spent, $amount); $spent = bcadd($spent, $amount);
$spentNative = bcadd($spentNative, $amountNative); $spentNative = bcadd($spentNative, $amountNative);
} }
app('log')->debug(sprintf('Total spent in budget "%s" is %s', $budget['name'], $spent));
} }
// either an amount was budgeted or 0 is available. // either an amount was budgeted or 0 is available.
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId); $currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
$currencies[$currencyId] = $currency; $currencies[$currencyId] = $currency;
$amount = $available[$currencyId]['amount'] ?? '0'; $amount = $available[$currencyId]['amount'] ?? '0';
$amountNative = $converter->convert($default, $currency, $start, $amount); $amountNative = $available[$currencyId]['native_amount'] ?? '0';
$left = bcadd($amount, $spent); $left = bcadd($amount, $spent);
$leftNative = bcadd($amountNative, $spentNative); $leftNative = bcadd($amountNative, $spentNative);
app('log')->debug(sprintf('Available amount is %s', $amount));
app('log')->debug(sprintf('Amount left is %s', $left));
// how much left per day? // how much left per day?
$days = $today->diffInDays($end) + 1; $days = $today->diffInDays($end) + 1;
@@ -429,10 +438,10 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']), 'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
'value' => $left, 'value' => $left,
'currency_id' => $row['currency_id'], 'currency_id' => (string)$row['currency_id'],
'currency_code' => $row['currency_code'], 'currency_code' => $row['currency_code'],
'currency_symbol' => $row['currency_symbol'], 'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'], 'currency_decimal_places' => (int)$row['currency_decimal_places'],
]; ];
// left (native) // left (native)
$nativeLeft['value'] = $leftNative; $nativeLeft['value'] = $leftNative;
@@ -441,10 +450,10 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('left-per-day-to-spend-in-%s', $row['currency_code']), 'key' => sprintf('left-per-day-to-spend-in-%s', $row['currency_code']),
'value' => $perDay, 'value' => $perDay,
'currency_id' => $row['currency_id'], 'currency_id' => (string)$row['currency_id'],
'currency_code' => $row['currency_code'], 'currency_code' => $row['currency_code'],
'currency_symbol' => $row['currency_symbol'], 'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'], 'currency_decimal_places' => (int)$row['currency_decimal_places'],
]; ];
// left per day (native) // left per day (native)
@@ -495,7 +504,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => 'net-worth-in-native', 'key' => 'net-worth-in-native',
'value' => $netWorthSet['native']['balance'], 'value' => $netWorthSet['native']['balance'],
'currency_id' => $netWorthSet['native']['currency_id'], 'currency_id' => (string)$netWorthSet['native']['currency_id'],
'currency_code' => $netWorthSet['native']['currency_code'], 'currency_code' => $netWorthSet['native']['currency_code'],
'currency_symbol' => $netWorthSet['native']['currency_symbol'], 'currency_symbol' => $netWorthSet['native']['currency_symbol'],
'currency_decimal_places' => $netWorthSet['native']['currency_decimal_places'], 'currency_decimal_places' => $netWorthSet['native']['currency_decimal_places'],
@@ -507,7 +516,7 @@ class BasicController extends Controller
$return[] = [ $return[] = [
'key' => sprintf('net-worth-in-%s', $data['currency_code']), 'key' => sprintf('net-worth-in-%s', $data['currency_code']),
'value' => $data['balance'], 'value' => $data['balance'],
'currency_id' => $data['currency_id'], 'currency_id' => (string)$data['currency_id'],
'currency_code' => $data['currency_code'], 'currency_code' => $data['currency_code'],
'currency_symbol' => $data['currency_symbol'], 'currency_symbol' => $data['currency_symbol'],
'currency_decimal_places' => $data['currency_decimal_places'], 'currency_decimal_places' => $data['currency_decimal_places'],

View File

@@ -42,7 +42,7 @@ class BalanceChartRequest extends FormRequest
{ {
return [ return [
'accounts' => $this->getAccountList(), 'accounts' => $this->getAccountList(),
'period' => $this->string('period'), 'period' => $this->convertString('period'),
]; ];
} }

View File

@@ -34,6 +34,7 @@ use FireflyIII\Models\PiggyBankRepetition;
use FireflyIII\Models\RecurrenceTransaction; use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\RuleTrigger; use FireflyIII\Models\RuleTrigger;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use ValueError;
/** /**
* Class ReportSkeleton * Class ReportSkeleton
@@ -247,7 +248,16 @@ class CorrectAmounts extends Command
/** @var RuleTrigger $item */ /** @var RuleTrigger $item */
foreach ($set as $item) { foreach ($set as $item) {
// basic check: // basic check:
if (-1 === bccomp((string)$item->trigger_value, '0')) { $check = 0;
try {
$check = bccomp((string)$item->trigger_value, '0');
} catch (ValueError $e) {
$this->friendlyError(sprintf('Rule #%d contained invalid %s-trigger "%s". The trigger has been removed, and the rule is disabled.', $item->rule_id, $item->trigger_type, $item->trigger_value));
$item->rule->active = false;
$item->rule->save();
$item->forceDelete();
}
if (-1 === $check) {
$fixed++; $fixed++;
$item->trigger_value = app('steam')->positive((string)$item->trigger_value); $item->trigger_value = app('steam')->positive((string)$item->trigger_value);
$item->save(); $item->save();

View File

@@ -82,6 +82,7 @@ class DeleteEmptyJournals extends Command
TransactionJournal::find((int)$row->transaction_journal_id)->delete(); TransactionJournal::find((int)$row->transaction_journal_id)->delete();
} catch (QueryException $e) { } catch (QueryException $e) {
Log::info(sprintf('Could not delete journal: %s', $e->getMessage())); Log::info(sprintf('Could not delete journal: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
} }
@@ -113,6 +114,7 @@ class DeleteEmptyJournals extends Command
TransactionJournal::find($entry->id)->delete(); TransactionJournal::find($entry->id)->delete();
} catch (QueryException $e) { } catch (QueryException $e) {
Log::info(sprintf('Could not delete entry: %s', $e->getMessage())); Log::info(sprintf('Could not delete entry: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
} }

View File

@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
/*
* RuleActionFailedOnArray.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Events\Model\Rule;
use FireflyIII\Models\RuleAction;
use Illuminate\Queue\SerializesModels;
/**
* Class RuleActionFailedOnArray
*/
class RuleActionFailedOnArray
{
use SerializesModels;
public string $error;
public array $journal;
public RuleAction $ruleAction;
/**
* @param RuleAction $ruleAction
* @param array $journal
* @param string $error
*/
public function __construct(RuleAction $ruleAction, array $journal, string $error)
{
app('log')->debug('Created new RuleActionFailedOnArray');
$this->ruleAction = $ruleAction;
$this->journal = $journal;
$this->error = $error;
}
}

View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
/*
* RuleActionFailedOnArray.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Events\Model\Rule;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Queue\SerializesModels;
/**
* Class RuleActionFailedOnObject
*/
class RuleActionFailedOnObject
{
use SerializesModels;
public string $error;
public TransactionJournal $journal;
public RuleAction $ruleAction;
/**
* @param RuleAction $ruleAction
* @param TransactionJournal $journal
* @param string $error
*/
public function __construct(RuleAction $ruleAction, TransactionJournal $journal, string $error)
{
app('log')->debug('Created new RuleActionFailedOnObject');
$this->ruleAction = $ruleAction;
$this->journal = $journal;
$this->error = $error;
}
}

View File

@@ -218,6 +218,7 @@ class AccountFactory
} }
// create account! // create account!
$account = Account::create($databaseData); $account = Account::create($databaseData);
Log::channel('audit')->info(sprintf('Account #%d ("%s") has been created.', $account->id, $account->name));
// update meta data: // update meta data:
$data = $this->cleanMetaDataArray($account, $data); $data = $this->cleanMetaDataArray($account, $data);
@@ -228,6 +229,7 @@ class AccountFactory
$this->storeOpeningBalance($account, $data); $this->storeOpeningBalance($account, $data);
} catch (FireflyException $e) { } catch (FireflyException $e) {
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
} }
// create credit liability data (only liabilities) // create credit liability data (only liabilities)
@@ -235,6 +237,7 @@ class AccountFactory
$this->storeCreditLiability($account, $data); $this->storeCreditLiability($account, $data);
} catch (FireflyException $e) { } catch (FireflyException $e) {
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
} }
// create notes // create notes

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta; use FireflyIII\Models\AccountMeta;
use Illuminate\Support\Facades\Log;
/** /**
* Class AccountMetaFactory * Class AccountMetaFactory

View File

@@ -77,6 +77,7 @@ class CategoryFactory
); );
} catch (QueryException $e) { } catch (QueryException $e) {
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException('400003: Could not store new category.', 0, $e); throw new FireflyException('400003: Could not store new category.', 0, $e);
} }
} }

View File

@@ -130,6 +130,7 @@ class RecurrenceFactory
$this->createTransactions($recurrence, $data['transactions'] ?? []); $this->createTransactions($recurrence, $data['transactions'] ?? []);
} catch (FireflyException $e) { } catch (FireflyException $e) {
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$recurrence->forceDelete(); $recurrence->forceDelete();
$message = sprintf('Could not create recurring transaction: %s', $e->getMessage()); $message = sprintf('Could not create recurring transaction: %s', $e->getMessage());
$this->errors->add('store', $message); $this->errors->add('store', $message);

View File

@@ -69,6 +69,7 @@ class TransactionCurrencyFactory
} catch (QueryException $e) { } catch (QueryException $e) {
$result = null; $result = null;
Log::error(sprintf('Could not create new currency: %s', $e->getMessage())); Log::error(sprintf('Could not create new currency: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
throw new FireflyException('400004: Could not store new currency.', 0, $e); throw new FireflyException('400004: Could not store new currency.', 0, $e);
} }

View File

@@ -110,7 +110,7 @@ class TransactionFactory
Log::error(sprintf('Could not create transaction: %s', $e->getMessage()), $data); Log::error(sprintf('Could not create transaction: %s', $e->getMessage()), $data);
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString()); Log::error($e->getTraceAsString());
throw new FireflyException('Query exception when creating transaction.', 0, $e); throw new FireflyException(sprintf('Query exception when creating transaction: %s', $e->getMessage()), 0, $e);
} }
if (null === $result) { if (null === $result) {
throw new FireflyException('Transaction is NULL.'); throw new FireflyException('Transaction is NULL.');

View File

@@ -75,6 +75,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
->render(); ->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.account.report: %s', $e->getMessage())); Log::error(sprintf('Cannot render reports.account.report: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = sprintf('Could not render report view: %s', $e->getMessage()); $result = sprintf('Could not render report view: %s', $e->getMessage());
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -77,6 +77,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
->render(); ->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.category.month: %s', $e->getMessage())); Log::error(sprintf('Cannot render reports.category.month: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = sprintf('Could not render report view: %s', $e->getMessage()); $result = sprintf('Could not render report view: %s', $e->getMessage());
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -59,6 +59,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
return view('reports.default.month', compact('accountIds', 'reportType'))->with('start', $this->start)->with('end', $this->end)->render(); return view('reports.default.month', compact('accountIds', 'reportType'))->with('start', $this->start)->with('end', $this->end)->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.default.month: %s', $e->getMessage())); Log::error(sprintf('Cannot render reports.default.month: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = 'Could not render report view.'; $result = 'Could not render report view.';
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -63,6 +63,7 @@ class MultiYearReportGenerator implements ReportGeneratorInterface
)->with('start', $this->start)->with('end', $this->end)->render(); )->with('start', $this->start)->with('end', $this->end)->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.default.multi-year: %s', $e->getMessage())); Log::error(sprintf('Cannot render reports.default.multi-year: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = sprintf('Could not render report view: %s', $e->getMessage()); $result = sprintf('Could not render report view: %s', $e->getMessage());
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -63,6 +63,7 @@ class YearReportGenerator implements ReportGeneratorInterface
)->with('start', $this->start)->with('end', $this->end)->render(); )->with('start', $this->start)->with('end', $this->end)->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.account.report: %s', $e->getMessage())); Log::error(sprintf('Cannot render reports.account.report: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = 'Could not render report view.'; $result = 'Could not render report view.';
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -71,6 +71,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
)->with('start', $this->start)->with('end', $this->end)->with('tags', $this->tags)->with('accounts', $this->accounts)->render(); )->with('start', $this->start)->with('end', $this->end)->with('tags', $this->tags)->with('accounts', $this->accounts)->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.tag.month: %s', $e->getMessage())); Log::error(sprintf('Cannot render reports.tag.month: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = sprintf('Could not render report view: %s', $e->getMessage()); $result = sprintf('Could not render report view: %s', $e->getMessage());
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -174,6 +174,7 @@ class StandardMessageGenerator implements MessageGeneratorInterface
Log::error( Log::error(
sprintf('The transformer could not include the requested transaction group for webhook #%d: %s', $webhook->id, $e->getMessage()) sprintf('The transformer could not include the requested transaction group for webhook #%d: %s', $webhook->id, $e->getMessage())
); );
Log::error($e->getTraceAsString());
return; return;
} }

View File

@@ -63,18 +63,6 @@ class BudgetLimitHandler
private function updateAvailableBudget(BudgetLimit $budgetLimit): void private function updateAvailableBudget(BudgetLimit $budgetLimit): void
{ {
Log::debug(sprintf('Now in updateAvailableBudget(#%d)', $budgetLimit->id)); Log::debug(sprintf('Now in updateAvailableBudget(#%d)', $budgetLimit->id));
// based on the view range of the user (month week quarter etc) the budget limit could
// either overlap multiple available budget periods or be contained in a single one.
// all have to be created or updated.
try {
$viewRange = app('preferences')->get('viewRange', '1M')->data;
} catch (ContainerExceptionInterface | NotFoundExceptionInterface $e) {
$viewRange = '1M';
}
$start = app('navigation')->startOfPeriod($budgetLimit->start_date, $viewRange);
$end = app('navigation')->startOfPeriod($budgetLimit->end_date, $viewRange);
$end = app('navigation')->endOfPeriod($end, $viewRange);
$budget = Budget::find($budgetLimit->budget_id); $budget = Budget::find($budgetLimit->budget_id);
if (null === $budget) { if (null === $budget) {
Log::warning('Budget is null, probably deleted, find deleted version.'); Log::warning('Budget is null, probably deleted, find deleted version.');
@@ -94,8 +82,23 @@ class BudgetLimitHandler
return; return;
} }
// based on the view range of the user (month week quarter etc) the budget limit could
// either overlap multiple available budget periods or be contained in a single one.
// all have to be created or updated.
try {
$viewRange = app('preferences')->getForUser($user, 'viewRange', '1M')->data;
} catch (ContainerExceptionInterface | NotFoundExceptionInterface $e) {
app('log')->error($e->getMessage());
$viewRange = '1M';
}
$start = app('navigation')->startOfPeriod($budgetLimit->start_date, $viewRange);
$end = app('navigation')->startOfPeriod($budgetLimit->end_date, $viewRange);
$end = app('navigation')->endOfPeriod($end, $viewRange);
// limit period in total is: // limit period in total is:
$limitPeriod = Period::make($start, $end, precision: Precision::DAY(), boundaries: Boundaries::EXCLUDE_NONE()); $limitPeriod = Period::make($start, $end, precision: Precision::DAY(), boundaries: Boundaries::EXCLUDE_NONE());
app('log')->debug(sprintf('Limit period is from %s to %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
// from the start until the end of the budget limit, need to loop! // from the start until the end of the budget limit, need to loop!
$current = clone $start; $current = clone $start;
@@ -166,7 +169,7 @@ class BudgetLimitHandler
$availableBudget->end_date->format('Y-m-d') $availableBudget->end_date->format('Y-m-d')
) )
); );
// have to recalc everything just in case. // have to recalculate everything just in case.
$set = $repository->getAllBudgetLimitsByCurrency($availableBudget->transactionCurrency, $availableBudget->start_date, $availableBudget->end_date); $set = $repository->getAllBudgetLimitsByCurrency($availableBudget->transactionCurrency, $availableBudget->start_date, $availableBudget->end_date);
Log::debug(sprintf('Found %d interesting budget limit(s).', $set->count())); Log::debug(sprintf('Found %d interesting budget limit(s).', $set->count()));
/** @var BudgetLimit $budgetLimit */ /** @var BudgetLimit $budgetLimit */
@@ -186,15 +189,18 @@ class BudgetLimitHandler
precision : Precision::DAY(), precision : Precision::DAY(),
boundaries: Boundaries::EXCLUDE_NONE() boundaries: Boundaries::EXCLUDE_NONE()
); );
// if both equal eachother, amount from this BL must be added to the AB // if both equal each other, amount from this BL must be added to the AB
if ($limitPeriod->equals($abPeriod)) { if ($limitPeriod->equals($abPeriod)) {
app('log')->debug('This budget limit is equal to the available budget period.');
$newAmount = bcadd($newAmount, $budgetLimit->amount); $newAmount = bcadd($newAmount, $budgetLimit->amount);
} }
// if budget limit period inside AB period, can be added in full. // if budget limit period is inside AB period, it can be added in full.
if (!$limitPeriod->equals($abPeriod) && $abPeriod->contains($limitPeriod)) { if (!$limitPeriod->equals($abPeriod) && $abPeriod->contains($limitPeriod)) {
app('log')->debug('This budget limit is smaller than the available budget period.');
$newAmount = bcadd($newAmount, $budgetLimit->amount); $newAmount = bcadd($newAmount, $budgetLimit->amount);
} }
if (!$limitPeriod->equals($abPeriod) && $abPeriod->overlapsWith($limitPeriod)) { if (!$limitPeriod->equals($abPeriod) && !$abPeriod->contains($limitPeriod) && $abPeriod->overlapsWith($limitPeriod)) {
app('log')->debug('This budget limit is something else entirely!');
$overlap = $abPeriod->overlap($limitPeriod); $overlap = $abPeriod->overlap($limitPeriod);
if (null !== $overlap) { if (null !== $overlap) {
$length = $overlap->length(); $length = $overlap->length();
@@ -209,7 +215,7 @@ class BudgetLimitHandler
return; return;
} }
Log::debug(sprintf('Concluded new amount for this AB must be %s', $newAmount)); Log::debug(sprintf('Concluded new amount for this AB must be %s', $newAmount));
$availableBudget->amount = $newAmount; $availableBudget->amount = app('steam')->bcround($newAmount, $availableBudget->transactionCurrency->decimal_places);
$availableBudget->save(); $availableBudget->save();
} }

View File

@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
/*
* RuleHandler.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Handlers\Events\Model;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
use FireflyIII\Notifications\User\RuleActionFailed;
use FireflyIII\Support\Facades\Preferences;
use Illuminate\Support\Facades\Notification;
/**
* Class RuleHandler
*/
class RuleHandler
{
/**
* @param RuleActionFailedOnArray $event
*
* @return void
*/
public function ruleActionFailedOnArray(RuleActionFailedOnArray $event): void
{
$ruleAction = $event->ruleAction;
$rule = $ruleAction->rule;
$preference = Preferences::getForUser($rule->user, 'notification_rule_action_failures', true)->data;
if (false === $preference) {
return;
}
app('log')->debug('Now in ruleActionFailedOnArray');
$journal = $event->journal;
$error = $event->error;
$user = $ruleAction->rule->user;
$mainMessage = trans('rules.main_message', ['rule' => $rule->title, 'action' => $ruleAction->action_type, 'group' => $journal['transaction_group_id'], 'error' => $error]);
$groupTitle = $journal['description'] ?? '';
$groupLink = route('transactions.show', [$journal['transaction_group_id']]);
$ruleTitle = $rule->title;
$ruleLink = route('rules.edit', [$rule->id]);
$params = [$mainMessage, $groupTitle, $groupLink, $ruleTitle, $ruleLink];
Notification::send($user, new RuleActionFailed($params));
}
/**
* @param RuleActionFailedOnObject $event
*
* @return void
*/
public function ruleActionFailedOnObject(RuleActionFailedOnObject $event): void
{
$ruleAction = $event->ruleAction;
$rule = $ruleAction->rule;
$preference = Preferences::getForUser($rule->user, 'notification_rule_action_failures', true)->data;
if (false === $preference) {
return;
}
app('log')->debug('Now in ruleActionFailedOnObject');
$journal = $event->journal;
$error = $event->error;
$user = $ruleAction->rule->user;
$mainMessage = trans('rules.main_message', ['rule' => $rule->title, 'action' => $ruleAction->action_type, 'group' => $journal->transaction_group_id, 'error' => $error]);
$groupTitle = $journal->description ?? '';
$groupLink = route('transactions.show', [$journal->transaction_group_id]);
$ruleTitle = $rule->title;
$ruleLink = route('rules.edit', [$rule->id]);
$params = [$mainMessage, $groupTitle, $groupLink, $ruleTitle, $ruleLink];
Notification::send($user, new RuleActionFailed($params));
}
}

View File

@@ -275,6 +275,7 @@ class UserEventHandler
Mail::to($newEmail)->send(new ConfirmEmailChangeMail($newEmail, $oldEmail, $url)); Mail::to($newEmail)->send(new ConfirmEmailChangeMail($newEmail, $oldEmail, $url));
} catch (Exception $e) { // intentional generic exception } catch (Exception $e) { // intentional generic exception
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException($e->getMessage(), 0, $e); throw new FireflyException($e->getMessage(), 0, $e);
} }
} }
@@ -299,6 +300,7 @@ class UserEventHandler
Mail::to($oldEmail)->send(new UndoEmailChangeMail($newEmail, $oldEmail, $url)); Mail::to($oldEmail)->send(new UndoEmailChangeMail($newEmail, $oldEmail, $url));
} catch (Exception $e) { // intentional generic exception } catch (Exception $e) { // intentional generic exception
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException($e->getMessage(), 0, $e); throw new FireflyException($e->getMessage(), 0, $e);
} }
} }
@@ -342,6 +344,7 @@ class UserEventHandler
Mail::to($invitee)->send(new InvitationMail($invitee, $admin, $url)); Mail::to($invitee)->send(new InvitationMail($invitee, $admin, $url));
} catch (Exception $e) { // intentional generic exception } catch (Exception $e) { // intentional generic exception
Log::error($e->getMessage()); Log::error($e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException($e->getMessage(), 0, $e); throw new FireflyException($e->getMessage(), 0, $e);
} }
} }

View File

@@ -57,7 +57,7 @@ class VersionCheckEventHandler
$permission = app('fireflyconfig')->get('permission_update_check', -1); $permission = app('fireflyconfig')->get('permission_update_check', -1);
$value = (int)$permission->data; $value = (int)$permission->data;
if (1 !== $value) { if (1 !== $value) {
Log::info('Update check is not enabled.'); Log::debug('Update check is not enabled.');
$this->warnToCheckForUpdates($event); $this->warnToCheckForUpdates($event);
return; return;

View File

@@ -871,7 +871,7 @@ class GroupCollector implements GroupCollectorInterface
public function setLimit(int $limit): GroupCollectorInterface public function setLimit(int $limit): GroupCollectorInterface
{ {
$this->limit = $limit; $this->limit = $limit;
app('log')->debug(sprintf('GroupCollector: The limit is now %d', $limit)); //app('log')->debug(sprintf('GroupCollector: The limit is now %d', $limit));
return $this; return $this;
} }
@@ -976,7 +976,7 @@ class GroupCollector implements GroupCollectorInterface
{ {
$page = 0 === $page ? 1 : $page; $page = 0 === $page ? 1 : $page;
$this->page = $page; $this->page = $page;
app('log')->debug(sprintf('GroupCollector: page is now %d', $page)); //app('log')->debug(sprintf('GroupCollector: page is now %d', $page));
return $this; return $this;
} }

View File

@@ -27,6 +27,7 @@ use FireflyIII\Events\AdminRequestedTestMessage;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Middleware\IsDemoUser; use FireflyIII\Http\Middleware\IsDemoUser;
use FireflyIII\Support\Facades\FireflyConfig; use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
@@ -99,7 +100,7 @@ class HomeController extends Controller
if ('' === $url) { if ('' === $url) {
FireflyConfig::delete('slack_webhook_url'); FireflyConfig::delete('slack_webhook_url');
} }
if (str_starts_with($url, 'https://hooks.slack.com/services/')) { if (UrlValidator::isValidWebhookURL($url)) {
FireflyConfig::set('slack_webhook_url', $url); FireflyConfig::set('slack_webhook_url', $url);
} }

View File

@@ -146,7 +146,7 @@ class IndexController extends Controller
private function getSums(array $bills): array private function getSums(array $bills): array
{ {
$sums = []; $sums = [];
$range = app('navigation')->getViewRange(false); $range = app('navigation')->getViewRange(true);
/** @var array $group */ /** @var array $group */
foreach ($bills as $groupOrder => $group) { foreach ($bills as $groupOrder => $group) {
@@ -177,7 +177,6 @@ class IndexController extends Controller
$sums[$groupOrder][$currencyId]['per_period'] = bcadd($sums[$groupOrder][$currencyId]['per_period'], $this->amountPerPeriod($bill, $range)); $sums[$groupOrder][$currencyId]['per_period'] = bcadd($sums[$groupOrder][$currencyId]['per_period'], $this->amountPerPeriod($bill, $range));
} }
} }
return $sums; return $sums;
} }

View File

@@ -101,6 +101,7 @@ class IndexController extends Controller
*/ */
public function index(Request $request, Carbon $start = null, Carbon $end = null) public function index(Request $request, Carbon $start = null, Carbon $end = null)
{ {
$this->abRepository->cleanup();
Log::debug(sprintf('Start of IndexController::index("%s", "%s")', $start?->format('Y-m-d'), $end?->format('Y-m-d'))); Log::debug(sprintf('Start of IndexController::index("%s", "%s")', $start?->format('Y-m-d'), $end?->format('Y-m-d')));
// collect some basic vars: // collect some basic vars:
@@ -226,6 +227,7 @@ class IndexController extends Controller
Log::debug(sprintf('Working on budget #%d ("%s")', $current->id, $current->name)); Log::debug(sprintf('Working on budget #%d ("%s")', $current->id, $current->name));
$array = $current->toArray(); $array = $current->toArray();
$array['spent'] = []; $array['spent'] = [];
$array['spent_total'] = [];
$array['budgeted'] = []; $array['budgeted'] = [];
$array['attachments'] = $this->repository->getAttachments($current); $array['attachments'] = $this->repository->getAttachments($current);
$array['auto_budget'] = $this->repository->getAutoBudget($current); $array['auto_budget'] = $this->repository->getAutoBudget($current);
@@ -234,9 +236,10 @@ class IndexController extends Controller
foreach ($budgetLimits as $limit) { foreach ($budgetLimits as $limit) {
Log::debug(sprintf('Working on budget limit #%d', $limit->id)); Log::debug(sprintf('Working on budget limit #%d', $limit->id));
$currency = $limit->transactionCurrency ?? $defaultCurrency; $currency = $limit->transactionCurrency ?? $defaultCurrency;
$amount = app('steam')->bcround($limit->amount, $currency->decimal_places);
$array['budgeted'][] = [ $array['budgeted'][] = [
'id' => $limit->id, 'id' => $limit->id,
'amount' => app('steam')->bcround($limit->amount, $currency->decimal_places), 'amount' => $amount,
'start_date' => $limit->start_date->isoFormat($this->monthAndDayFormat), 'start_date' => $limit->start_date->isoFormat($this->monthAndDayFormat),
'end_date' => $limit->end_date->isoFormat($this->monthAndDayFormat), 'end_date' => $limit->end_date->isoFormat($this->monthAndDayFormat),
'in_range' => $limit->start_date->isSameDay($start) && $limit->end_date->isSameDay($end), 'in_range' => $limit->start_date->isSameDay($start) && $limit->end_date->isSameDay($end),
@@ -245,6 +248,7 @@ class IndexController extends Controller
'currency_name' => $currency->name, 'currency_name' => $currency->name,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
]; ];
Log::debug(sprintf('The amount budgeted for budget limit #%d is %s %s', $limit->id, $currency->code, $amount));
} }
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
@@ -337,6 +341,7 @@ class IndexController extends Controller
*/ */
public function reorder(Request $request, BudgetRepositoryInterface $repository): JsonResponse public function reorder(Request $request, BudgetRepositoryInterface $repository): JsonResponse
{ {
$this->abRepository->cleanup();
$budgetIds = $request->get('budgetIds'); $budgetIds = $request->get('budgetIds');
foreach ($budgetIds as $index => $budgetId) { foreach ($budgetIds as $index => $budgetId) {

View File

@@ -28,7 +28,10 @@ use Exception;
use FireflyConfig; use FireflyConfig;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Middleware\IsDemoUser; use FireflyIII\Http\Middleware\IsDemoUser;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionType;
use FireflyIII\Support\Http\Controllers\GetConfigurationData; use FireflyIII\Support\Http\Controllers\GetConfigurationData;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -37,6 +40,8 @@ use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\View\View; use Illuminate\View\View;
use Monolog\Handler\RotatingFileHandler; use Monolog\Handler\RotatingFileHandler;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
/** /**
* Class DebugController * Class DebugController
@@ -117,86 +122,9 @@ class DebugController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
// basic scope information: $table = $this->generateTable();
$now = now(config('app.timezone'))->format('Y-m-d H:i:s e'); $table = str_replace(["\n", "\t", ' '], '', $table);
$buildNr = '(unknown)'; $now = now(config('app.timezone'))->format('Y-m-d H:i:s');
$buildDate = '(unknown)';
$baseBuildNr = '(unknown)';
$baseBuildDate = '(unknown)';
$expectedDBversion = config('firefly.db_version');
$foundDBversion = FireflyConfig::get('db_version', 1)->data;
try {
if (file_exists('/var/www/counter-main.txt')) {
$buildNr = trim(file_get_contents('/var/www/counter-main.txt'));
}
} catch (Exception $e) { // generic catch for open basedir.
Log::debug('Could not check counter.');
Log::warning($e->getMessage());
}
try {
if (file_exists('/var/www/build-date-main.txt')) {
$buildDate = trim(file_get_contents('/var/www/build-date-main.txt'));
}
} catch (Exception $e) { // generic catch for open basedir.
Log::debug('Could not check date.');
Log::warning($e->getMessage());
}
if ('' !== (string)env('BASE_IMAGE_BUILD')) {
$baseBuildNr = env('BASE_IMAGE_BUILD');
}
if ('' !== (string)env('BASE_IMAGE_DATE')) {
$baseBuildDate = env('BASE_IMAGE_DATE');
}
$phpVersion = PHP_VERSION;
$phpOs = PHP_OS;
// system information
$tz = env('TZ');
$appEnv = config('app.env');
$appDebug = var_export(config('app.debug'), true);
$cacheDriver = config('cache.default');
$logChannel = config('logging.default');
$appLogLevel = config('logging.level');
$maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize'));
$maxPostSize = app('steam')->phpBytes(ini_get('post_max_size'));
$uploadSize = min($maxFileSize, $maxPostSize);
$displayErrors = ini_get('display_errors');
$errorReporting = $this->errorReporting((int)ini_get('error_reporting'));
$interface = PHP_SAPI;
$defaultLanguage = (string)config('firefly.default_language');
$defaultLocale = (string)config('firefly.default_locale');
$bcscale = bcscale();
$drivers = implode(', ', DB::availableDrivers());
$currentDriver = DB::getDriverName();
$trustedProxies = config('firefly.trusted_proxies');
// user info
$loginProvider = config('auth.providers.users.driver');
$userGuard = config('auth.defaults.guard');
$remoteHeader = $userGuard === 'remote_user_guard' ? config('auth.guard_header') : 'N/A';
$remoteMailHeader = $userGuard === 'remote_user_guard' ? config('auth.guard_email') : 'N/A';
$userLanguage = app('steam')->getLanguage();
$userLocale = app('steam')->getLocale();
$userAgent = $request->header('user-agent');
$stateful = join(', ', config('sanctum.stateful'));
// expected + found DB version:
// some new vars.
$isDocker = env('IS_DOCKER', false);
// set languages, see what happens:
$original = setlocale(LC_ALL, 0);
$localeAttempts = [];
$parts = app('steam')->getLocaleArray(app('steam')->getLocale());
foreach ($parts as $code) {
$code = trim($code);
Log::debug(sprintf('Trying to set %s', $code));
$localeAttempts[$code] = var_export(setlocale(LC_ALL, $code), true);
}
setlocale(LC_ALL, $original);
// get latest log file: // get latest log file:
$logger = Log::driver(); $logger = Log::driver();
@@ -213,50 +141,190 @@ class DebugController extends Controller
} }
if ('' !== $logContent) { if ('' !== $logContent) {
// last few lines // last few lines
$logContent = 'Truncated from this point <----|' . substr($logContent, -8192); $logContent = 'Truncated from this point <----|' . substr($logContent, -16384);
} }
return view( return view('debug', compact('table', 'now', 'logContent'));
'debug', }
compact(
'phpVersion', /**
'localeAttempts', * @return string
'expectedDBversion', */
'foundDBversion', private function generateTable(): string
'appEnv', {
'appDebug', // system information:
'logChannel', $system = $this->getSystemInformation();
'stateful', $docker = $this->getBuildInfo();
'tz', $app = $this->getAppInfo();
'uploadSize', $user = $this->getuserInfo();
'appLogLevel',
'remoteHeader', return (string)view('partials.debug-table', compact('system', 'docker', 'app', 'user'));
'remoteMailHeader', }
'now',
'drivers', /**
'currentDriver', * @return array
'userGuard', */
'loginProvider', private function getSystemInformation(): array
'buildNr', {
'buildDate', $maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize'));
'baseBuildNr', $maxPostSize = app('steam')->phpBytes(ini_get('post_max_size'));
'baseBuildDate', $drivers = DB::availableDrivers();
'bcscale', $currentDriver = DB::getDriverName();
'userAgent', return [
'displayErrors', 'db_version' => app('fireflyconfig')->get('db_version', 1)->data,
'errorReporting', 'php_version' => PHP_VERSION,
'phpOs', 'php_os' => PHP_OS,
'interface', 'interface' => PHP_SAPI,
'logContent', 'bcscale' => bcscale(),
'cacheDriver', 'display_errors' => ini_get('display_errors'),
'trustedProxies', 'error_reporting' => $this->errorReporting((int)ini_get('error_reporting')),
'userLanguage', 'upload_size' => min($maxFileSize, $maxPostSize),
'userLocale', 'all_drivers' => $drivers,
'defaultLanguage', 'current_driver' => $currentDriver,
'defaultLocale', ];
'isDocker' }
)
); /**
* @return array
*/
private function getBuildInfo(): array
{
$return = [
'is_docker' => env('IS_DOCKER', false),
'build' => '(unknown)',
'build_date' => '(unknown)',
'base_build' => '(unknown)',
'base_build_date' => '(unknown)',
];
try {
if (file_exists('/var/www/counter-main.txt')) {
$return['build'] = trim(file_get_contents('/var/www/counter-main.txt'));
}
} catch (Exception $e) { // generic catch for open basedir.
Log::debug('Could not check build counter, but thats ok.');
Log::warning($e->getMessage());
}
try {
if (file_exists('/var/www/build-date-main.txt')) {
$return['build_date'] = trim(file_get_contents('/var/www/build-date-main.txt'));
}
} catch (Exception $e) { // generic catch for open basedir.
Log::debug('Could not check build date, but thats ok.');
Log::warning($e->getMessage());
}
if ('' !== (string)env('BASE_IMAGE_BUILD')) {
$return['base_build'] = env('BASE_IMAGE_BUILD');
}
if ('' !== (string)env('BASE_IMAGE_DATE')) {
$return['base_build_date'] = env('BASE_IMAGE_DATE');
}
return $return;
}
/**
* @return array
*/
private function getAppInfo(): array
{
$userGuard = config('auth.defaults.guard');
return [
'tz' => env('TZ'),
'debug' => var_export(config('app.debug'), true),
'log_channel' => env('LOG_CHANNEL'),
'audit_log_channel' => envNonEmpty('AUDIT_LOG_CHANNEL', '(empty)'),
'default_language' => (string)config('firefly.default_language'),
'default_locale' => (string)config('firefly.default_locale'),
'remote_header' => $userGuard === 'remote_user_guard' ? config('auth.guard_header') : 'N/A',
'remote_mail_header' => $userGuard === 'remote_user_guard' ? config('auth.guard_email') : 'N/A',
'stateful_domains' => join(', ', config('sanctum.stateful')),
];
}
/**
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function getuserInfo(): array
{
$userFlags = $this->getUserFlags();
// user info
$userAgent = request()->header('user-agent');
// set languages, see what happens:
$original = setlocale(LC_ALL, 0);
$localeAttempts = [];
$parts = app('steam')->getLocaleArray(app('steam')->getLocale());
foreach ($parts as $code) {
$code = trim($code);
Log::debug(sprintf('Trying to set %s', $code));
$result = setlocale(LC_ALL, $code);
$localeAttempts[$code] = $result === $code;
}
setlocale(LC_ALL, $original);
return [
'user_id' => auth()->user()->id,
'user_count' => User::count(),
'user_flags' => $userFlags,
'user_agent' => $userAgent,
'locale_attempts' => $localeAttempts,
'locale' => app('steam')->getLocale(),
'language' => app('steam')->getLanguage(),
'view_range' => app('preferences')->get('viewRange', '1M')->data,
];
}
/**
* @return string
*/
private function getUserFlags(): string
{
$flags = [];
/** @var User $user */
$user = auth()->user();
// has liabilities
if ($user->accounts()->accountTypeIn([AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE])->count() > 0) {
$flags[] = ':credit_card:';
}
// has piggies
if ($user->piggyBanks()->count() > 0) {
$flags[] = ':pig:';
}
// has stored reconciliations
$type = TransactionType::whereType(TransactionType::RECONCILIATION)->first();
if ($user->transactionJournals()->where('transaction_type_id', $type->id)->count()) {
$flags[] = ':ledger:';
}
// has used importer?
// has rules
if ($user->rules()->count() > 0) {
$flags[] = ':wrench:';
}
// has recurring transactions
if ($user->recurrences()->count() > 0) {
$flags[] = ':clock130:';
}
// has groups
if ($user->objectGroups()->count() > 0) {
$flags[] = ':bookmark_tabs:';
}
// uses bills
if ($user->bills()->count() > 0) {
$flags[] = ':email:';
}
return join(' ', $flags);
} }
/** /**
@@ -275,4 +343,5 @@ class DebugController extends Controller
return redirect(route('home')); return redirect(route('home'));
} }
} }

View File

@@ -138,6 +138,9 @@ class HomeController extends Controller
$accounts = $repository->getAccountsById($frontPage->data); $accounts = $repository->getAccountsById($frontPage->data);
$today = today(config('app.timezone')); $today = today(config('app.timezone'));
// sort frontpage accounts by order
$accounts = $accounts->sortBy('order');
Log::debug('Frontpage accounts are ', $frontPage->data); Log::debug('Frontpage accounts are ', $frontPage->data);
/** @var BillRepositoryInterface $billRepository */ /** @var BillRepositoryInterface $billRepository */

View File

@@ -55,10 +55,12 @@ class BoxController extends Controller
*/ */
public function available(): JsonResponse public function available(): JsonResponse
{ {
app('log')->debug('Now in available()');
/** @var OperationsRepositoryInterface $opsRepository */ /** @var OperationsRepositoryInterface $opsRepository */
$opsRepository = app(OperationsRepositoryInterface::class); $opsRepository = app(OperationsRepositoryInterface::class);
/** @var AvailableBudgetRepositoryInterface $abRepository */ /** @var AvailableBudgetRepositoryInterface $abRepository */
$abRepository = app(AvailableBudgetRepositoryInterface::class); $abRepository = app(AvailableBudgetRepositoryInterface::class);
$abRepository->cleanup();
/** @var Carbon $start */ /** @var Carbon $start */
$start = session('start', today(config('app.timezone'))->startOfMonth()); $start = session('start', today(config('app.timezone'))->startOfMonth());
/** @var Carbon $end */ /** @var Carbon $end */
@@ -73,40 +75,57 @@ class BoxController extends Controller
$cache->addProperty($today); $cache->addProperty($today);
$cache->addProperty('box-available'); $cache->addProperty('box-available');
if ($cache->has()) { if ($cache->has()) {
return response()->json($cache->get()); //return response()->json($cache->get());
} }
$leftPerDayAmount = '0'; $leftPerDayAmount = '0';
$leftToSpendAmount = '0'; $leftToSpendAmount = '0';
$currency = app('amount')->getDefaultCurrency(); $currency = app('amount')->getDefaultCurrency();
$availableBudgets = $abRepository->getAvailableBudgetsByDate($start, $end); app('log')->debug(sprintf('Default currency is %s', $currency->code));
$availableBudgets = $abRepository->getAvailableBudgetsByExactDate($start, $end);
app('log')->debug(sprintf('Found %d available budget(s)', $availableBudgets->count()));
$availableBudgets = $availableBudgets->filter( $availableBudgets = $availableBudgets->filter(
static function (AvailableBudget $availableBudget) use ($currency) { static function (AvailableBudget $availableBudget) use ($currency) {
if ($availableBudget->transaction_currency_id === $currency->id) { if ($availableBudget->transaction_currency_id === $currency->id) {
app('log')->debug(sprintf(
'Will include AB #%d: from %s-%s amount %s',
$availableBudget->id,
$availableBudget->start_date->format('Y-m-d'),
$availableBudget->end_date->format('Y-m-d'),
$availableBudget->amount
));
return $availableBudget; return $availableBudget;
} }
return null; return null;
} }
); );
app('log')->debug(sprintf('Filtered back to %d available budgets', $availableBudgets->count()));
// spent in this period, in budgets, for default currency. // spent in this period, in budgets, for default currency.
// also calculate spent per day. // also calculate spent per day.
$spent = $opsRepository->sumExpenses($start, $end, null, null, $currency); $spent = $opsRepository->sumExpenses($start, $end, null, null, $currency);
$spentAmount = $spent[(int)$currency->id]['sum'] ?? '0'; $spentAmount = $spent[(int)$currency->id]['sum'] ?? '0';
app('log')->debug(sprintf('Spent for default currency for all budgets in this period: %s', $spentAmount));
$days = $today->between($start, $end) ? $today->diffInDays($start) + 1 : $end->diffInDays($start) + 1; $days = $today->between($start, $end) ? $today->diffInDays($start) + 1 : $end->diffInDays($start) + 1;
app('log')->debug(sprintf('Number of days left: %d', $days));
$spentPerDay = bcdiv($spentAmount, (string)$days); $spentPerDay = bcdiv($spentAmount, (string)$days);
app('log')->debug(sprintf('Available to spend per day: %s', $spentPerDay));
if ($availableBudgets->count() > 0) { if ($availableBudgets->count() > 0) {
$display = 0; // assume user overspent $display = 0; // assume user overspent
$boxTitle = (string)trans('firefly.overspent'); $boxTitle = (string)trans('firefly.overspent');
$totalAvailableSum = (string)$availableBudgets->sum('amount'); $totalAvailableSum = (string)$availableBudgets->sum('amount');
app('log')->debug(sprintf('Total available sum is %s', $totalAvailableSum));
// calculate with available budget. // calculate with available budget.
$leftToSpendAmount = bcadd($totalAvailableSum, $spentAmount); $leftToSpendAmount = bcadd($totalAvailableSum, $spentAmount);
app('log')->debug(sprintf('So left to spend is %s', $leftToSpendAmount));
if (1 === bccomp($leftToSpendAmount, '0')) { if (1 === bccomp($leftToSpendAmount, '0')) {
app('log')->debug(sprintf('Left to spend is positive!'));
$boxTitle = (string)trans('firefly.left_to_spend'); $boxTitle = (string)trans('firefly.left_to_spend');
$days = $today->diffInDays($end) + 1; $days = $today->diffInDays($end) + 1;
$display = 1; // not overspent $display = 1; // not overspent
$leftPerDayAmount = bcdiv($leftToSpendAmount, (string)$days); $leftPerDayAmount = bcdiv($leftToSpendAmount, (string)$days);
app('log')->debug(sprintf('Left to spend per day is %s', $leftPerDayAmount));
} }
} }
@@ -118,9 +137,10 @@ class BoxController extends Controller
'left_per_day' => app('amount')->formatAnything($currency, $leftPerDayAmount, false), 'left_per_day' => app('amount')->formatAnything($currency, $leftPerDayAmount, false),
'title' => $boxTitle, 'title' => $boxTitle,
]; ];
app('log')->debug('Final output', $return);
$cache->store($return); $cache->store($return);
app('log')->debug('Now done with available()');
return response()->json($return); return response()->json($return);
} }

View File

@@ -75,6 +75,7 @@ class FrontpageController extends Controller
$html = view('json.piggy-banks', compact('info'))->render(); $html = view('json.piggy-banks', compact('info'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Cannot render json.piggy-banks: %s', $e->getMessage())); Log::error(sprintf('Cannot render json.piggy-banks: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$html = 'Could not render view.'; $html = 'Could not render view.';
throw new FireflyException($html, 0, $e); throw new FireflyException($html, 0, $e);
} }

View File

@@ -157,6 +157,7 @@ class ReconcileController extends Controller
)->render(); )->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('View error: %s', $e->getMessage())); Log::debug(sprintf('View error: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$view = sprintf('Could not render accounts.reconcile.overview: %s', $e->getMessage()); $view = sprintf('Could not render accounts.reconcile.overview: %s', $e->getMessage());
throw new FireflyException($view, 0, $e); throw new FireflyException($view, 0, $e);
} }
@@ -258,6 +259,7 @@ class ReconcileController extends Controller
)->render(); )->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render: %s', $e->getMessage())); Log::debug(sprintf('Could not render: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$html = sprintf('Could not render accounts.reconcile.transactions: %s', $e->getMessage()); $html = sprintf('Could not render accounts.reconcile.transactions: %s', $e->getMessage());
throw new FireflyException($html, 0, $e); throw new FireflyException($html, 0, $e);
} }

View File

@@ -55,6 +55,7 @@ class RuleController extends Controller
$view = view('rules.partials.action', compact('actions', 'count'))->render(); $view = view('rules.partials.action', compact('actions', 'count'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Cannot render rules.partials.action: %s', $e->getMessage())); Log::error(sprintf('Cannot render rules.partials.action: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$view = 'Could not render view.'; $view = 'Could not render view.';
throw new FireflyException($view, 0, $e); throw new FireflyException($view, 0, $e);
} }
@@ -86,6 +87,7 @@ class RuleController extends Controller
$view = view('rules.partials.trigger', compact('triggers', 'count'))->render(); $view = view('rules.partials.trigger', compact('triggers', 'count'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Cannot render rules.partials.trigger: %s', $e->getMessage())); Log::error(sprintf('Cannot render rules.partials.trigger: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$view = 'Could not render view.'; $view = 'Could not render view.';
throw new FireflyException($view, 0, $e); throw new FireflyException($view, 0, $e);
} }

View File

@@ -28,6 +28,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\Preference; use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Notifications\UrlValidator;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -207,7 +208,7 @@ class PreferencesController extends Controller
// slack URL: // slack URL:
if (!auth()->user()->hasRole('demo')) { if (!auth()->user()->hasRole('demo')) {
$url = (string)$request->get('slackUrl'); $url = (string)$request->get('slackUrl');
if (str_starts_with($url, 'https://hooks.slack.com/services/')) { if (UrlValidator::isValidWebhookURL($url)) {
app('preferences')->set('slack_webhook_url', $url); app('preferences')->set('slack_webhook_url', $url);
} }
if ('' === $url) { if ('' === $url) {

View File

@@ -65,7 +65,8 @@ class AccountController extends Controller
try { try {
$result = view('reports.partials.accounts', compact('accountReport'))->render(); $result = view('reports.partials.accounts', compact('accountReport'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.accounts: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.accounts: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = 'Could not render view.'; $result = 'Could not render view.';
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -141,7 +141,8 @@ class BalanceController extends Controller
try { try {
$result = view('reports.partials.balance', compact('report'))->render(); $result = view('reports.partials.balance', compact('report'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.balance: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.balance: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = 'Could not render view.'; $result = 'Could not render view.';
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -61,7 +61,8 @@ class BillController extends Controller
try { try {
$result = view('reports.partials.bills', compact('report'))->render(); $result = view('reports.partials.bills', compact('report'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budgets: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.budgets: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = 'Could not render view.'; $result = 'Could not render view.';
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -195,8 +195,9 @@ class BudgetController extends Controller
try { try {
$result = view('reports.budget.partials.avg-expenses', compact('result'))->render(); $result = view('reports.budget.partials.avg-expenses', compact('result'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
$result = sprintf('Could not render view: %s', $e->getMessage()); $result = sprintf('Could not render view: %s', $e->getMessage());
Log::error($e->getTraceAsString());
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }
@@ -353,7 +354,8 @@ class BudgetController extends Controller
try { try {
$result = view('reports.partials.budget-period', compact('report', 'periods'))->render(); $result = view('reports.partials.budget-period', compact('report', 'periods'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = 'Could not render view.'; $result = 'Could not render view.';
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }
@@ -406,7 +408,7 @@ class BudgetController extends Controller
try { try {
$result = view('reports.budget.partials.top-expenses', compact('result'))->render(); $result = view('reports.budget.partials.top-expenses', compact('result'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
$result = sprintf('Could not render view: %s', $e->getMessage()); $result = sprintf('Could not render view: %s', $e->getMessage());
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -315,7 +315,7 @@ class CategoryController extends Controller
try { try {
$result = view('reports.category.partials.avg-expenses', compact('result'))->render(); $result = view('reports.category.partials.avg-expenses', compact('result'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
$result = sprintf('Could not render view: %s', $e->getMessage()); $result = sprintf('Could not render view: %s', $e->getMessage());
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }
@@ -368,7 +368,7 @@ class CategoryController extends Controller
try { try {
$result = view('reports.category.partials.avg-income', compact('result'))->render(); $result = view('reports.category.partials.avg-income', compact('result'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
$result = sprintf('Could not render view: %s', $e->getMessage()); $result = sprintf('Could not render view: %s', $e->getMessage());
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -115,7 +115,7 @@ class DoubleController extends Controller
try { try {
$result = view('reports.double.partials.avg-expenses', compact('result'))->render(); $result = view('reports.double.partials.avg-expenses', compact('result'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
$result = sprintf('Could not render view: %s', $e->getMessage()); $result = sprintf('Could not render view: %s', $e->getMessage());
throw new FireflyException($e->getMessage(), 0, $e); throw new FireflyException($e->getMessage(), 0, $e);
} }
@@ -168,7 +168,7 @@ class DoubleController extends Controller
try { try {
$result = view('reports.double.partials.avg-income', compact('result'))->render(); $result = view('reports.double.partials.avg-income', compact('result'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
$result = sprintf('Could not render view: %s', $e->getMessage()); $result = sprintf('Could not render view: %s', $e->getMessage());
throw new FireflyException($e->getMessage(), 0, $e); throw new FireflyException($e->getMessage(), 0, $e);
} }
@@ -463,7 +463,7 @@ class DoubleController extends Controller
try { try {
$result = view('reports.double.partials.top-expenses', compact('result'))->render(); $result = view('reports.double.partials.top-expenses', compact('result'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
$result = sprintf('Could not render view: %s', $e->getMessage()); $result = sprintf('Could not render view: %s', $e->getMessage());
throw new FireflyException($e->getMessage(), 0, $e); throw new FireflyException($e->getMessage(), 0, $e);
} }
@@ -514,7 +514,7 @@ class DoubleController extends Controller
try { try {
$result = view('reports.double.partials.top-income', compact('result'))->render(); $result = view('reports.double.partials.top-income', compact('result'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.budget-period: %s', $e->getMessage()));
$result = sprintf('Could not render view: %s', $e->getMessage()); $result = sprintf('Could not render view: %s', $e->getMessage());
throw new FireflyException($e->getMessage(), 0, $e); throw new FireflyException($e->getMessage(), 0, $e);
} }

View File

@@ -85,7 +85,8 @@ class OperationsController extends Controller
try { try {
$result = view('reports.partials.income-expenses', compact('report', 'type'))->render(); $result = view('reports.partials.income-expenses', compact('report', 'type'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.income-expense: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.income-expense: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = 'Could not render view.'; $result = 'Could not render view.';
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }
@@ -121,7 +122,8 @@ class OperationsController extends Controller
try { try {
$result = view('reports.partials.income-expenses', compact('report', 'type'))->render(); $result = view('reports.partials.income-expenses', compact('report', 'type'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.income-expenses: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.income-expenses: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = 'Could not render view.'; $result = 'Could not render view.';
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }
@@ -177,7 +179,8 @@ class OperationsController extends Controller
try { try {
$result = view('reports.partials.operations', compact('sums'))->render(); $result = view('reports.partials.operations', compact('sums'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Could not render reports.partials.operations: %s', $e->getMessage())); Log::error(sprintf('Could not render reports.partials.operations: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$result = 'Could not render view.'; $result = 'Could not render view.';
throw new FireflyException($result, 0, $e); throw new FireflyException($result, 0, $e);
} }

View File

@@ -128,6 +128,7 @@ class SearchController extends Controller
$html = view('search.search', compact('groups', 'hasPages', 'searchTime'))->render(); $html = view('search.search', compact('groups', 'hasPages', 'searchTime'))->render();
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Cannot render search.search: %s', $e->getMessage())); Log::error(sprintf('Cannot render search.search: %s', $e->getMessage()));
Log::error($e->getTraceAsString());
$html = 'Could not render view.'; $html = 'Could not render view.';
throw new FireflyException($html, 0, $e); throw new FireflyException($html, 0, $e);
} }

View File

@@ -158,6 +158,7 @@ class ReportFormRequest extends FormRequest
} catch (Exception $e) { // intentional generic exception } catch (Exception $e) { // intentional generic exception
$error = sprintf('"%s" is not a valid date range: %s', $range, $e->getMessage()); $error = sprintf('"%s" is not a valid date range: %s', $range, $e->getMessage());
Log::error($error); Log::error($error);
Log::error($e->getTraceAsString());
throw new FireflyException($error, 0, $e); throw new FireflyException($error, 0, $e);
} }
return $date; return $date;
@@ -192,6 +193,7 @@ class ReportFormRequest extends FormRequest
} catch (Exception $e) { // intentional generic exception } catch (Exception $e) { // intentional generic exception
$error = sprintf('"%s" is not a valid date range: %s', $range, $e->getMessage()); $error = sprintf('"%s" is not a valid date range: %s', $range, $e->getMessage());
Log::error($error); Log::error($error);
Log::error($e->getTraceAsString());
throw new FireflyException($error, 0, $e); throw new FireflyException($error, 0, $e);
} }
return $date; return $date;
@@ -220,19 +222,18 @@ class ReportFormRequest extends FormRequest
} }
if (!is_array($set)) { if (!is_array($set)) {
Log::error(sprintf('Set is not an array! "%s"', $set)); Log::error(sprintf('Set is not an array! "%s"', $set));
return $collection;
} }
if (is_array($set)) { foreach ($set as $tagTag) {
foreach ($set as $tagTag) { Log::debug(sprintf('Now searching for "%s"', $tagTag));
Log::debug(sprintf('Now searching for "%s"', $tagTag)); $tag = $repository->findByTag($tagTag);
$tag = $repository->findByTag($tagTag); if (null !== $tag) {
if (null !== $tag) { $collection->push($tag);
$collection->push($tag); continue;
continue; }
} $tag = $repository->find((int)$tagTag);
$tag = $repository->find((int)$tagTag); if (null !== $tag) {
if (null !== $tag) { $collection->push($tag);
$collection->push($tag);
}
} }
} }

View File

@@ -61,6 +61,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @method static Builder|ObjectGroup whereTitle($value) * @method static Builder|ObjectGroup whereTitle($value)
* @method static Builder|ObjectGroup whereUpdatedAt($value) * @method static Builder|ObjectGroup whereUpdatedAt($value)
* @method static Builder|ObjectGroup whereUserId($value) * @method static Builder|ObjectGroup whereUserId($value)
* @property int|null $user_group_id
* @method static Builder|ObjectGroup whereUserGroupId($value)
* @mixin Eloquent * @mixin Eloquent
*/ */
class ObjectGroup extends Model class ObjectGroup extends Model

View File

@@ -76,6 +76,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @method static Builder|Rule withoutTrashed() * @method static Builder|Rule withoutTrashed()
* @property int|null $user_group_id * @property int|null $user_group_id
* @method static \Illuminate\Database\Eloquent\Builder|Rule whereUserGroupId($value) * @method static \Illuminate\Database\Eloquent\Builder|Rule whereUserGroupId($value)
* @property-read \FireflyIII\Models\UserGroup|null $userGroup
* @mixin Eloquent * @mixin Eloquent
*/ */
class Rule extends Model class Rule extends Model

View File

@@ -61,6 +61,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @method static Builder|TransactionGroup withoutTrashed() * @method static Builder|TransactionGroup withoutTrashed()
* @property int|null $user_group_id * @property int|null $user_group_id
* @method static \Illuminate\Database\Eloquent\Builder|TransactionGroup whereUserGroupId($value) * @method static \Illuminate\Database\Eloquent\Builder|TransactionGroup whereUserGroupId($value)
* @property-read \FireflyIII\Models\UserGroup|null $userGroup
* @mixin Eloquent * @mixin Eloquent
*/ */
class TransactionGroup extends Model class TransactionGroup extends Model

View File

@@ -52,6 +52,16 @@ use Illuminate\Support\Carbon;
* @method static Builder|UserGroup whereUpdatedAt($value) * @method static Builder|UserGroup whereUpdatedAt($value)
* @property-read Collection<int, Account> $accounts * @property-read Collection<int, Account> $accounts
* @property-read int|null $accounts_count * @property-read int|null $accounts_count
* @property-read Collection<int, \FireflyIII\Models\AvailableBudget> $availableBudgets
* @property-read int|null $available_budgets_count
* @property-read Collection<int, \FireflyIII\Models\Bill> $bills
* @property-read int|null $bills_count
* @property-read Collection<int, \FireflyIII\Models\Budget> $budgets
* @property-read int|null $budgets_count
* @property-read Collection<int, \FireflyIII\Models\PiggyBank> $piggyBanks
* @property-read int|null $piggy_banks_count
* @property-read Collection<int, \FireflyIII\Models\TransactionJournal> $transactionJournals
* @property-read int|null $transaction_journals_count
* @mixin Eloquent * @mixin Eloquent
*/ */
class UserGroup extends Model class UserGroup extends Model

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Admin; namespace FireflyIII\Notifications\Admin;
use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
@@ -99,9 +100,9 @@ class TestNotification extends Notification
public function via($notifiable) public function via($notifiable)
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = auth()->user(); $user = auth()->user();
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data; $slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) { if (UrlValidator::isValidWebhookURL($slackUrl)) {
return ['mail', 'slack']; return ['mail', 'slack'];
} }
return ['mail']; return ['mail'];

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Admin; namespace FireflyIII\Notifications\Admin;
use FireflyIII\Models\InvitedUser; use FireflyIII\Models\InvitedUser;
use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
@@ -102,9 +103,9 @@ class UserInvitation extends Notification
public function via($notifiable) public function via($notifiable)
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = auth()->user(); $user = auth()->user();
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data; $slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) { if (UrlValidator::isValidWebhookURL($slackUrl)) {
return ['mail', 'slack']; return ['mail', 'slack'];
} }
return ['mail']; return ['mail'];

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Admin; namespace FireflyIII\Notifications\Admin;
use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
@@ -99,9 +100,9 @@ class UserRegistration extends Notification
public function via($notifiable) public function via($notifiable)
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = auth()->user(); $user = auth()->user();
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data; $slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) { if (UrlValidator::isValidWebhookURL($slackUrl)) {
return ['mail', 'slack']; return ['mail', 'slack'];
} }
return ['mail']; return ['mail'];

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Admin; namespace FireflyIII\Notifications\Admin;
use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
@@ -87,21 +88,10 @@ class VersionCheckResult extends Notification
*/ */
public function toSlack($notifiable) public function toSlack($notifiable)
{ {
// return (new SlackMessage())->text($this->message)
// ->sectionBlock(function (SectionBlock $block) {
// $button = new ButtonElement('Button');
// $button->url('https://github.com/firefly-iii/firefly-iii/releases');
// $block->accessory($button);
// });
//// ->attachment(function ($attachment) {
//// $attachment->title('Firefly III @ GitHub', 'https://github.com/firefly-iii/firefly-iii/releases');
//// });
return (new SlackMessage())->content($this->message) return (new SlackMessage())->content($this->message)
->attachment(function ($attachment) { ->attachment(function ($attachment) {
$attachment->title('Firefly III @ GitHub', 'https://github.com/firefly-iii/firefly-iii/releases'); $attachment->title('Firefly III @ GitHub', 'https://github.com/firefly-iii/firefly-iii/releases');
}); });
} }
/** /**
@@ -114,9 +104,9 @@ class VersionCheckResult extends Notification
public function via($notifiable) public function via($notifiable)
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = auth()->user(); $user = auth()->user();
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data; $slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) { if (UrlValidator::isValidWebhookURL($slackUrl)) {
return ['mail', 'slack']; return ['mail', 'slack'];
} }
return ['mail']; return ['mail'];

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\User; namespace FireflyIII\Notifications\User;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
@@ -38,8 +39,8 @@ class BillReminder extends Notification
{ {
use Queueable; use Queueable;
private Bill $bill; private Bill $bill;
private int $diff; private int $diff;
private string $field; private string $field;
/** /**
@@ -49,9 +50,9 @@ class BillReminder extends Notification
*/ */
public function __construct(Bill $bill, string $field, int $diff) public function __construct(Bill $bill, string $field, int $diff)
{ {
$this->bill = $bill; $this->bill = $bill;
$this->field = $field; $this->field = $field;
$this->diff = $diff; $this->diff = $diff;
} }
/** /**
@@ -101,7 +102,7 @@ class BillReminder extends Notification
$message = (string)trans(sprintf('email.bill_warning_subject_now_%s', $this->field), ['diff' => $this->diff, 'name' => $this->bill->name]); $message = (string)trans(sprintf('email.bill_warning_subject_now_%s', $this->field), ['diff' => $this->diff, 'name' => $this->bill->name]);
} }
$bill = $this->bill; $bill = $this->bill;
$url = route('bills.show', [$bill->id]); $url = route('bills.show', [$bill->id]);
return (new SlackMessage()) return (new SlackMessage())
->warning() ->warning()
->attachment(function ($attachment) use ($bill, $url) { ->attachment(function ($attachment) use ($bill, $url) {
@@ -120,9 +121,9 @@ class BillReminder extends Notification
public function via($notifiable) public function via($notifiable)
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = auth()->user(); $user = auth()->user();
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data; $slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) { if (UrlValidator::isValidWebhookURL($slackUrl)) {
return ['mail', 'slack']; return ['mail', 'slack'];
} }
return ['mail']; return ['mail'];

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\User; namespace FireflyIII\Notifications\User;
use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
@@ -96,9 +97,9 @@ class NewAccessToken extends Notification
public function via($notifiable) public function via($notifiable)
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = auth()->user(); $user = auth()->user();
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data; $slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) { if (UrlValidator::isValidWebhookURL($slackUrl)) {
return ['mail', 'slack']; return ['mail', 'slack'];
} }
return ['mail']; return ['mail'];

View File

@@ -0,0 +1,117 @@
<?php
/*
* NewAccessToken.php
* Copyright (c) 2022 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Notifications\User;
use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
/**
* Class RuleActionFailed
*/
class RuleActionFailed extends Notification
{
use Queueable;
private string $groupLink;
private string $groupTitle;
private string $message;
private string $ruleLink;
private string $ruleTitle;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct(array $params)
{
[$mainMessage, $groupTitle, $groupLink, $ruleTitle, $ruleLink] = $params;
$this->message = $mainMessage;
$this->groupTitle = $groupTitle;
$this->groupLink = $groupLink;
$this->ruleTitle = $ruleTitle;
$this->ruleLink = $ruleLink;
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
*
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
/**
* Get the Slack representation of the notification.
*
* @param mixed $notifiable
*
* @return SlackMessage
*/
public function toSlack($notifiable)
{
$groupTitle = $this->groupTitle;
$groupLink = $this->groupLink;
$ruleTitle = $this->ruleTitle;
$ruleLink = $this->ruleLink;
return (new SlackMessage())->content($this->message)->attachment(function ($attachment) use ($groupTitle, $groupLink) {
$attachment->title((string)trans('rules.inspect_transaction', ['title' => $groupTitle]), $groupLink);
})->attachment(function ($attachment) use ($ruleTitle, $ruleLink) {
$attachment->title((string)trans('rules.inspect_rule', ['title' => $ruleTitle]), $ruleLink);
});
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
*
* @return array
*/
public function via($notifiable)
{
/** @var User|null $user */
$user = auth()->user();
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
if (UrlValidator::isValidWebhookURL($slackUrl)) {
app('log')->debug('Will send ruleActionFailed through Slack!');
return ['slack'];
}
app('log')->debug('Will NOT send ruleActionFailed through Slack');
return [];
}
}

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\User; namespace FireflyIII\Notifications\User;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
@@ -124,9 +125,9 @@ class UserLogin extends Notification
public function via($notifiable) public function via($notifiable)
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = auth()->user(); $user = auth()->user();
$slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data; $slackUrl = null === $user ? '' : (string)app('preferences')->getForUser(auth()->user(), 'slack_webhook_url', '')->data;
if (str_starts_with($slackUrl, 'https://hooks.slack.com/services/')) { if (UrlValidator::isValidWebhookURL($slackUrl)) {
return ['mail', 'slack']; return ['mail', 'slack'];
} }
return ['mail']; return ['mail'];

View File

@@ -32,6 +32,8 @@ use FireflyIII\Events\DetectedNewIPAddress;
use FireflyIII\Events\Model\BudgetLimit\Created; use FireflyIII\Events\Model\BudgetLimit\Created;
use FireflyIII\Events\Model\BudgetLimit\Deleted; use FireflyIII\Events\Model\BudgetLimit\Deleted;
use FireflyIII\Events\Model\BudgetLimit\Updated; use FireflyIII\Events\Model\BudgetLimit\Updated;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
use FireflyIII\Events\NewVersionAvailable; use FireflyIII\Events\NewVersionAvailable;
use FireflyIII\Events\RegisteredUser; use FireflyIII\Events\RegisteredUser;
use FireflyIII\Events\RequestedNewPassword; use FireflyIII\Events\RequestedNewPassword;
@@ -170,6 +172,14 @@ class EventServiceProvider extends ServiceProvider
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@deleted', 'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@deleted',
], ],
// rule actions
RuleActionFailedOnArray::class => [
'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnArray',
],
RuleActionFailedOnObject::class => [
'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnObject',
],
]; ];
/** /**

View File

@@ -39,6 +39,49 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
{ {
private User $user; private User $user;
/**
* @inheritDoc
*/
public function cleanup(): void
{
$exists = [];
$availableBudgets = $this->user->availableBudgets()->get();
/** @var AvailableBudget $availableBudget */
foreach ($availableBudgets as $availableBudget) {
$start = $availableBudget->start_date->format('Y-m-d');
$end = $availableBudget->end_date->format('Y-m-d');
$key = sprintf('%s-%s-%s', $availableBudget->transaction_currency_id, $start, $end);
if (array_key_exists($key, $exists)) {
app('log')->debug(sprintf('Found duplicate AB: %s %s, %s-%s. Has been deleted', $availableBudget->transaction_currency_id, $availableBudget->amount, $start, $end));
$availableBudget->delete();
}
$exists[$key] = true;
}
}
/**
* Return a list of all available budgets (in all currencies) (for the selected period).
*
* @param Carbon|null $start
* @param Carbon|null $end
*
* @return Collection
*/
public function get(?Carbon $start = null, ?Carbon $end = null): Collection
{
$query = $this->user->availableBudgets()->with(['transactionCurrency']);
if (null !== $start && null !== $end) {
$query->where(
static function (Builder $q1) use ($start, $end) {
$q1->where('start_date', '=', $start->format('Y-m-d'));
$q1->where('end_date', '=', $end->format('Y-m-d'));
}
);
}
return $query->get(['available_budgets.*']);
}
/** /**
* Delete all available budgets. * Delete all available budgets.
*/ */
@@ -122,29 +165,6 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
return $return; return $return;
} }
/**
* Return a list of all available budgets (in all currencies) (for the selected period).
*
* @param Carbon|null $start
* @param Carbon|null $end
*
* @return Collection
*/
public function get(?Carbon $start = null, ?Carbon $end = null): Collection
{
$query = $this->user->availableBudgets()->with(['transactionCurrency']);
if (null !== $start && null !== $end) {
$query->where(
static function (Builder $q1) use ($start, $end) {
$q1->where('start_date', '=', $start->format('Y-m-d'));
$q1->where('end_date', '=', $end->format('Y-m-d'));
}
);
}
return $query->get(['available_budgets.*']);
}
/** /**
* Returns all available budget objects. * Returns all available budget objects.
* *
@@ -180,6 +200,23 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
return $query->get(); return $query->get();
} }
/**
* Returns all available budget objects.
*
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*
*/
public function getAvailableBudgetsByExactDate(Carbon $start, Carbon $end): Collection
{
return $this->user->availableBudgets()
->where('start_date', '=', $start->format('Y-m-d'))
->where('end_date', '=', $end->format('Y-m-d'))
->get();
}
/** /**
* @inheritDoc * @inheritDoc
*/ */

View File

@@ -35,6 +35,11 @@ use Illuminate\Support\Collection;
*/ */
interface AvailableBudgetRepositoryInterface interface AvailableBudgetRepositoryInterface
{ {
/**
* @return void
*/
public function cleanup(): void;
/** /**
* Delete all available budgets. * Delete all available budgets.
*/ */
@@ -111,6 +116,14 @@ interface AvailableBudgetRepositoryInterface
*/ */
public function getAvailableBudgetsByDate(?Carbon $start, ?Carbon $end): Collection; public function getAvailableBudgetsByDate(?Carbon $start, ?Carbon $end): Collection;
/**
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getAvailableBudgetsByExactDate(Carbon $start, Carbon $end): Collection;
/** /**
* Get by transaction currency and date. Should always result in one entry or NULL. * Get by transaction currency and date. Should always result in one entry or NULL.
* *

View File

@@ -83,7 +83,7 @@ class OperationsRepository implements OperationsRepositoryInterface
// info about the currency: // info about the currency:
$array[$currencyId] = $array[$currencyId] ?? [ $array[$currencyId] = $array[$currencyId] ?? [
'categories' => [], 'categories' => [],
'currency_id' => $currencyId, 'currency_id' => (string)$currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
@@ -92,7 +92,7 @@ class OperationsRepository implements OperationsRepositoryInterface
// info about the categories: // info about the categories:
$array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [ $array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [
'id' => $categoryId, 'id' => (string)$categoryId,
'name' => $categoryName, 'name' => $categoryName,
'transaction_journals' => [], 'transaction_journals' => [],
]; ];
@@ -103,13 +103,13 @@ class OperationsRepository implements OperationsRepositoryInterface
$array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [ $array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [
'amount' => app('steam')->negative($journal['amount']), 'amount' => app('steam')->negative($journal['amount']),
'date' => $journal['date'], 'date' => $journal['date'],
'source_account_id' => $journal['source_account_id'], 'source_account_id' => (string)$journal['source_account_id'],
'budget_name' => $journal['budget_name'], 'budget_name' => $journal['budget_name'],
'source_account_name' => $journal['source_account_name'], 'source_account_name' => $journal['source_account_name'],
'destination_account_id' => $journal['destination_account_id'], 'destination_account_id' => (string)$journal['destination_account_id'],
'destination_account_name' => $journal['destination_account_name'], 'destination_account_name' => $journal['destination_account_name'],
'description' => $journal['description'], 'description' => $journal['description'],
'transaction_group_id' => $journal['transaction_group_id'], 'transaction_group_id' => (string)$journal['transaction_group_id'],
]; ];
} }
@@ -179,7 +179,7 @@ class OperationsRepository implements OperationsRepositoryInterface
// info about the currency: // info about the currency:
$array[$currencyId] = $array[$currencyId] ?? [ $array[$currencyId] = $array[$currencyId] ?? [
'categories' => [], 'categories' => [],
'currency_id' => $currencyId, 'currency_id' => (string)$currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
@@ -188,7 +188,7 @@ class OperationsRepository implements OperationsRepositoryInterface
// info about the categories: // info about the categories:
$array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [ $array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [
'id' => $categoryId, 'id' => (string)$categoryId,
'name' => $categoryName, 'name' => $categoryName,
'transaction_journals' => [], 'transaction_journals' => [],
]; ];
@@ -199,12 +199,12 @@ class OperationsRepository implements OperationsRepositoryInterface
$array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [ $array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [
'amount' => app('steam')->positive($journal['amount']), 'amount' => app('steam')->positive($journal['amount']),
'date' => $journal['date'], 'date' => $journal['date'],
'source_account_id' => $journal['source_account_id'], 'source_account_id' => (string)$journal['source_account_id'],
'destination_account_id' => $journal['destination_account_id'], 'destination_account_id' => (string)$journal['destination_account_id'],
'source_account_name' => $journal['source_account_name'], 'source_account_name' => $journal['source_account_name'],
'destination_account_name' => $journal['destination_account_name'], 'destination_account_name' => $journal['destination_account_name'],
'description' => $journal['description'], 'description' => $journal['description'],
'transaction_group_id' => $journal['transaction_group_id'], 'transaction_group_id' => (string)$journal['transaction_group_id'],
]; ];
} }
@@ -243,7 +243,7 @@ class OperationsRepository implements OperationsRepositoryInterface
// info about the currency: // info about the currency:
$array[$currencyId] = $array[$currencyId] ?? [ $array[$currencyId] = $array[$currencyId] ?? [
'categories' => [], 'categories' => [],
'currency_id' => $currencyId, 'currency_id' => (string)$currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
@@ -252,7 +252,7 @@ class OperationsRepository implements OperationsRepositoryInterface
// info about the categories: // info about the categories:
$array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [ $array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [
'id' => $categoryId, 'id' => (string)$categoryId,
'name' => $categoryName, 'name' => $categoryName,
'transaction_journals' => [], 'transaction_journals' => [],
]; ];
@@ -263,13 +263,13 @@ class OperationsRepository implements OperationsRepositoryInterface
$array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [ $array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [
'amount' => app('steam')->positive($journal['amount']), 'amount' => app('steam')->positive($journal['amount']),
'date' => $journal['date'], 'date' => $journal['date'],
'source_account_id' => $journal['source_account_id'], 'source_account_id' => (string)$journal['source_account_id'],
'category_name' => $journal['category_name'], 'category_name' => $journal['category_name'],
'source_account_name' => $journal['source_account_name'], 'source_account_name' => $journal['source_account_name'],
'destination_account_id' => $journal['destination_account_id'], 'destination_account_id' => (string)$journal['destination_account_id'],
'destination_account_name' => $journal['destination_account_name'], 'destination_account_name' => $journal['destination_account_name'],
'description' => $journal['description'], 'description' => $journal['description'],
'transaction_group_id' => $journal['transaction_group_id'], 'transaction_group_id' => (string)$journal['transaction_group_id'],
]; ];
} }
@@ -308,7 +308,7 @@ class OperationsRepository implements OperationsRepositoryInterface
// info about the currency: // info about the currency:
$array[$currencyId] = $array[$currencyId] ?? [ $array[$currencyId] = $array[$currencyId] ?? [
'categories' => [], 'categories' => [],
'currency_id' => $currencyId, 'currency_id' => (string)$currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
@@ -317,7 +317,7 @@ class OperationsRepository implements OperationsRepositoryInterface
// info about the categories: // info about the categories:
$array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [ $array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [
'id' => $categoryId, 'id' => (string)$categoryId,
'name' => $categoryName, 'name' => $categoryName,
'transaction_journals' => [], 'transaction_journals' => [],
]; ];
@@ -328,13 +328,13 @@ class OperationsRepository implements OperationsRepositoryInterface
$array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [ $array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [
'amount' => app('steam')->negative($journal['amount']), 'amount' => app('steam')->negative($journal['amount']),
'date' => $journal['date'], 'date' => $journal['date'],
'source_account_id' => $journal['source_account_id'], 'source_account_id' => (string)$journal['source_account_id'],
'category_name' => $journal['category_name'], 'category_name' => $journal['category_name'],
'source_account_name' => $journal['source_account_name'], 'source_account_name' => $journal['source_account_name'],
'destination_account_id' => $journal['destination_account_id'], 'destination_account_id' => (string)$journal['destination_account_id'],
'destination_account_name' => $journal['destination_account_name'], 'destination_account_name' => $journal['destination_account_name'],
'description' => $journal['description'], 'description' => $journal['description'],
'transaction_group_id' => $journal['transaction_group_id'], 'transaction_group_id' => (string)$journal['transaction_group_id'],
]; ];
} }
@@ -373,7 +373,7 @@ class OperationsRepository implements OperationsRepositoryInterface
$currencyId = (int)$journal['currency_id']; $currencyId = (int)$journal['currency_id'];
$array[$currencyId] = $array[$currencyId] ?? [ $array[$currencyId] = $array[$currencyId] ?? [
'sum' => '0', 'sum' => '0',
'currency_id' => $currencyId, 'currency_id' => (string)$currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
@@ -416,7 +416,7 @@ class OperationsRepository implements OperationsRepositoryInterface
$currencyId = (int)$journal['currency_id']; $currencyId = (int)$journal['currency_id'];
$array[$currencyId] = $array[$currencyId] ?? [ $array[$currencyId] = $array[$currencyId] ?? [
'sum' => '0', 'sum' => '0',
'currency_id' => $currencyId, 'currency_id' => (string)$currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
@@ -459,7 +459,7 @@ class OperationsRepository implements OperationsRepositoryInterface
$currencyId = (int)$journal['currency_id']; $currencyId = (int)$journal['currency_id'];
$array[$currencyId] = $array[$currencyId] ?? [ $array[$currencyId] = $array[$currencyId] ?? [
'sum' => '0', 'sum' => '0',
'currency_id' => $currencyId, 'currency_id' => (string)$currencyId,
'currency_name' => $journal['currency_name'], 'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'], 'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],

View File

@@ -0,0 +1,58 @@
<?php
/**
* AccountList.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Support\Binder;
use FireflyIII\Models\Bill;
use FireflyIII\User;
use Illuminate\Routing\Route;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class UserGroupBill.
*/
class UserGroupBill implements BinderInterface
{
/**
* @param string $value
* @param Route $route
*
* @return Bill
* @throws NotFoundHttpException
*
*/
public static function routeBinder(string $value, Route $route): Bill
{
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$currency = Bill::where('id', (int)$value)
->where('user_group_id', $user->user_group_id)
->first();
if (null !== $currency) {
return $currency;
}
}
throw new NotFoundHttpException();
}
}

View File

@@ -78,7 +78,7 @@ class AutoBudgetCronjob extends AbstractCronjob
{ {
Log::info(sprintf('Will now fire auto budget cron job task for date "%s".', $this->date->format('Y-m-d'))); Log::info(sprintf('Will now fire auto budget cron job task for date "%s".', $this->date->format('Y-m-d')));
/** @var CreateAutoBudgetLimits $job */ /** @var CreateAutoBudgetLimits $job */
$job = app(CreateAutoBudgetLimits::class); $job = app(CreateAutoBudgetLimits::class, [$this->date]);
$job->setDate($this->date); $job->setDate($this->date);
$job->handle(); $job->handle();

View File

@@ -294,7 +294,7 @@ trait RenderPartialViews
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage())); Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage()));
Log::error($e->getTraceAsString()); Log::error($e->getTraceAsString());
throw new FireflyException('Could not render', 0, $e); throw new FireflyException(sprintf('Could not render: %s', $e->getMessage()), 0, $e);
} }
++$index; ++$index;
@@ -349,7 +349,7 @@ trait RenderPartialViews
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage())); Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage()));
Log::error($e->getTraceAsString()); Log::error($e->getTraceAsString());
throw new FireflyException('Could not render', 0, $e); throw new FireflyException(sprintf('Could not render: %s', $e->getMessage()), 0, $e);
} }
++$index; ++$index;

View File

@@ -54,7 +54,7 @@ trait RuleManagement
'rules.partials.action', 'rules.partials.action',
[ [
'oldAction' => $oldAction['type'], 'oldAction' => $oldAction['type'],
'oldValue' => $oldAction['value'], 'oldValue' => $oldAction['value'] ?? '',
'oldChecked' => 1 === (int)($oldAction['stop_processing'] ?? '0'), 'oldChecked' => 1 === (int)($oldAction['stop_processing'] ?? '0'),
'count' => $index + 1, 'count' => $index + 1,
] ]
@@ -62,7 +62,7 @@ trait RuleManagement
} catch (Throwable $e) { } catch (Throwable $e) {
Log::error(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage())); Log::error(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage()));
Log::error($e->getTraceAsString()); Log::error($e->getTraceAsString());
throw new FireflyException('Could not render', 0, $e); throw new FireflyException(sprintf('Could not render: %s', $e->getMessage()), 0, $e);
} }
$index++; $index++;
} }
@@ -109,7 +109,7 @@ trait RuleManagement
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage())); Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
Log::error($e->getTraceAsString()); Log::error($e->getTraceAsString());
throw new FireflyException('Could not render', 0, $e); throw new FireflyException(sprintf('Could not render: %s', $e->getMessage()), 0, $e);
} }
$index++; $index++;
} }
@@ -153,7 +153,7 @@ trait RuleManagement
} catch (Throwable $e) { } catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage())); Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
Log::error($e->getTraceAsString()); Log::error($e->getTraceAsString());
throw new FireflyException('Could not render', 0, $e); throw new FireflyException(sprintf('Could not render: %s', $e->getMessage()), 0, $e);
} }
$index++; $index++;
} }

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
/*
* UrlValidator.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Support\Notifications;
/**
* Class UrlValidator
*/
class UrlValidator
{
/**
* @param string $url
*
* @return bool
*/
public static function isValidWebhookURL(string $url): bool
{
return str_starts_with($url, 'https://hooks.slack.com/services/') || str_starts_with($url, 'https://discord.com/api/webhooks/');
}
}

View File

@@ -1004,151 +1004,151 @@ class OperatorQuerySearch implements SearchInterface
// //
case '-date_on': case '-date_on':
case 'date_on': case 'date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setExactDateParams($range, $prohibited); $this->setExactDateParams($range, $prohibited);
return false; return false;
case 'date_before': case 'date_before':
case '-date_after': case '-date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setDateBeforeParams($range); $this->setDateBeforeParams($range);
return false; return false;
case 'date_after': case 'date_after':
case '-date_before': case '-date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setDateAfterParams($range); $this->setDateAfterParams($range);
return false; return false;
case 'interest_date_on': case 'interest_date_on':
case '-interest_date_on': case '-interest_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('interest_date', $range, $prohibited); $this->setExactMetaDateParams('interest_date', $range, $prohibited);
return false; return false;
case 'interest_date_before': case 'interest_date_before':
case '-interest_date_after': case '-interest_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('interest_date', $range); $this->setMetaDateBeforeParams('interest_date', $range);
return false; return false;
case 'interest_date_after': case 'interest_date_after':
case '-interest_date_before': case '-interest_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('interest_date', $range); $this->setMetaDateAfterParams('interest_date', $range);
return false; return false;
case 'book_date_on': case 'book_date_on':
case '-book_date_on': case '-book_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('book_date', $range, $prohibited); $this->setExactMetaDateParams('book_date', $range, $prohibited);
return false; return false;
case 'book_date_before': case 'book_date_before':
case '-book_date_after': case '-book_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('book_date', $range); $this->setMetaDateBeforeParams('book_date', $range);
return false; return false;
case 'book_date_after': case 'book_date_after':
case '-book_date_before': case '-book_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('book_date', $range); $this->setMetaDateAfterParams('book_date', $range);
return false; return false;
case 'process_date_on': case 'process_date_on':
case '-process_date_on': case '-process_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('process_date', $range, $prohibited); $this->setExactMetaDateParams('process_date', $range, $prohibited);
return false; return false;
case 'process_date_before': case 'process_date_before':
case '-process_date_after': case '-process_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('process_date', $range); $this->setMetaDateBeforeParams('process_date', $range);
return false; return false;
case 'process_date_after': case 'process_date_after':
case '-process_date_before': case '-process_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('process_date', $range); $this->setMetaDateAfterParams('process_date', $range);
return false; return false;
case 'due_date_on': case 'due_date_on':
case '-due_date_on': case '-due_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('due_date', $range, $prohibited); $this->setExactMetaDateParams('due_date', $range, $prohibited);
return false; return false;
case 'due_date_before': case 'due_date_before':
case '-due_date_after': case '-due_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('due_date', $range); $this->setMetaDateBeforeParams('due_date', $range);
return false; return false;
case 'due_date_after': case 'due_date_after':
case '-due_date_before': case '-due_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('due_date', $range); $this->setMetaDateAfterParams('due_date', $range);
return false; return false;
case 'payment_date_on': case 'payment_date_on':
case '-payment_date_on': case '-payment_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('payment_date', $range, $prohibited); $this->setExactMetaDateParams('payment_date', $range, $prohibited);
return false; return false;
case 'payment_date_before': case 'payment_date_before':
case '-payment_date_after': case '-payment_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('payment_date', $range); $this->setMetaDateBeforeParams('payment_date', $range);
return false; return false;
case 'payment_date_after': case 'payment_date_after':
case '-payment_date_before': case '-payment_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('payment_date', $range); $this->setMetaDateAfterParams('payment_date', $range);
return false; return false;
case 'invoice_date_on': case 'invoice_date_on':
case '-invoice_date_on': case '-invoice_date_on':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setExactMetaDateParams('invoice_date', $range, $prohibited); $this->setExactMetaDateParams('invoice_date', $range, $prohibited);
return false; return false;
case 'invoice_date_before': case 'invoice_date_before':
case '-invoice_date_after': case '-invoice_date_after':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateBeforeParams('invoice_date', $range); $this->setMetaDateBeforeParams('invoice_date', $range);
return false; return false;
case 'invoice_date_after': case 'invoice_date_after':
case '-invoice_date_before': case '-invoice_date_before':
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setMetaDateAfterParams('invoice_date', $range); $this->setMetaDateAfterParams('invoice_date', $range);
return false; return false;
case 'created_at_on': case 'created_at_on':
case '-created_at_on': case '-created_at_on':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setExactObjectDateParams('created_at', $range, $prohibited); $this->setExactObjectDateParams('created_at', $range, $prohibited);
return false; return false;
case 'created_at_before': case 'created_at_before':
case '-created_at_after': case '-created_at_after':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setObjectDateBeforeParams('created_at', $range); $this->setObjectDateBeforeParams('created_at', $range);
return false; return false;
case 'created_at_after': case 'created_at_after':
case '-created_at_before': case '-created_at_before':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setObjectDateAfterParams('created_at', $range); $this->setObjectDateAfterParams('created_at', $range);
return false; return false;
case 'updated_at_on': case 'updated_at_on':
case '-updated_at_on': case '-updated_at_on':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setExactObjectDateParams('updated_at', $range, $prohibited); $this->setExactObjectDateParams('updated_at', $range, $prohibited);
return false; return false;
case 'updated_at_before': case 'updated_at_before':
case '-updated_at_after': case '-updated_at_after':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setObjectDateBeforeParams('updated_at', $range); $this->setObjectDateBeforeParams('updated_at', $range);
return false; return false;
case 'updated_at_after': case 'updated_at_after':
case '-updated_at_before': case '-updated_at_before':
Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value)); Log::debug(sprintf('Set "%s" using collector with value "%s"', $operator, $value));
$range = $this->parseDateRange($value); $range = $this->parseDateRange($operator, $value);
$this->setObjectDateAfterParams('updated_at', $range); $this->setObjectDateAfterParams('updated_at', $range);
return false; return false;
// //
@@ -1550,13 +1550,22 @@ class OperatorQuerySearch implements SearchInterface
* @return array * @return array
* @throws FireflyException * @throws FireflyException
*/ */
private function parseDateRange(string $value): array private function parseDateRange(string $type, string $value): array
{ {
$parser = new ParseDateString(); $parser = new ParseDateString();
if ($parser->isDateRange($value)) { if ($parser->isDateRange($value)) {
return $parser->parseRange($value); return $parser->parseRange($value);
} }
$parsedDate = $parser->parseDate($value); try {
$parsedDate = $parser->parseDate($value);
} catch (FireflyException $e) {
Log::debug(sprintf('Could not parse date "%s", will return empty array.', $value));
$this->invalidOperators[] = [
'type' => $type,
'value' => (string)$value,
];
return [];
}
return [ return [
'exact' => $parsedDate, 'exact' => $parsedDate,

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Factory\TagFactory; use FireflyIII\Factory\TagFactory;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
@@ -61,7 +62,7 @@ class AddTag implements ActionInterface
if (null === $tag) { if (null === $tag) {
// could not find, could not create tag. // could not find, could not create tag.
Log::error(sprintf('RuleAction AddTag. Could not find or create tag "%s"', $this->action->action_value)); event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.find_or_create_tag_failed', ['tag' => $this->action->action_value])));
return false; return false;
} }
@@ -78,12 +79,12 @@ class AddTag implements ActionInterface
// event for audit log entry // event for audit log entry
event(new TriggeredAuditLog($this->action->rule, $object, 'add_tag', null, $tag->tag)); event(new TriggeredAuditLog($this->action->rule, $object, 'add_tag', null, $tag->tag));
return true; return true;
} }
Log::debug( Log::debug(
sprintf('RuleAction AddTag fired but tag %d ("%s") was already added to journal %d.', $tag->id, $tag->tag, $journal['transaction_journal_id']) sprintf('RuleAction AddTag fired but tag %d ("%s") was already added to journal %d.', $tag->id, $tag->tag, $journal['transaction_journal_id'])
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.tag_already_added', ['tag' => $this->action->action_value])));
return false; return false;
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
@@ -56,6 +57,7 @@ class AppendDescriptionToNotes implements ActionInterface
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
if (null === $object) { if (null === $object) {
Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id'])); Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_other_user')));
return false; return false;
} }
$note = $object->notes()->first(); $note = $object->notes()->first();

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
@@ -60,6 +61,7 @@ class AppendNotesToDescription implements ActionInterface
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
if (null === $object) { if (null === $object) {
Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id'])); Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_other_user')));
return false; return false;
} }
$note = $object->notes()->first(); $note = $object->notes()->first();
@@ -80,6 +82,7 @@ class AppendNotesToDescription implements ActionInterface
return true; return true;
} }
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.new_notes_empty')));
return false; return false;
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -56,6 +57,7 @@ class ClearBudget implements ActionInterface
$budget = $object->budgets()->first(); $budget = $object->budgets()->first();
if (null === $budget) { if (null === $budget) {
Log::debug(sprintf('RuleAction ClearBudget, no budget in journal #%d.', $journal['transaction_journal_id'])); Log::debug(sprintf('RuleAction ClearBudget, no budget in journal #%d.', $journal['transaction_journal_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_already_no_budget')));
return false; return false;
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -56,6 +57,7 @@ class ClearCategory implements ActionInterface
$category = $object->categories()->first(); $category = $object->categories()->first();
if (null === $category) { if (null === $category) {
Log::debug(sprintf('RuleAction ClearCategory, no category in journal #%d.', $journal['transaction_journal_id'])); Log::debug(sprintf('RuleAction ClearCategory, no category in journal #%d.', $journal['transaction_journal_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_already_no_category')));
return false; return false;
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -55,6 +56,7 @@ class ClearNotes implements ActionInterface
$notes = $object->notes()->first(); $notes = $object->notes()->first();
if (null === $notes) { if (null === $notes) {
Log::debug(sprintf('RuleAction ClearNotes, journal #%d has no notes.', $journal['transaction_journal_id'])); Log::debug(sprintf('RuleAction ClearNotes, journal #%d has no notes.', $journal['transaction_journal_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_already_no_notes')));
return false; return false;
} }
$before = $notes->text; $before = $notes->text;

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\AccountFactory; use FireflyIII\Factory\AccountFactory;
@@ -65,11 +66,13 @@ class ConvertToDeposit implements ActionInterface
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
if (null === $object) { if (null === $object) {
Log::error(sprintf('Cannot find journal #%d, cannot convert to deposit.', $journal['transaction_journal_id'])); Log::error(sprintf('Cannot find journal #%d, cannot convert to deposit.', $journal['transaction_journal_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_not_found')));
return false; return false;
} }
$groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count(); $groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count();
if ($groupCount > 1) { if ($groupCount > 1) {
Log::error(sprintf('Group #%d has more than one transaction in it, cannot convert to deposit.', $journal['transaction_group_id'])); Log::error(sprintf('Group #%d has more than one transaction in it, cannot convert to deposit.', $journal['transaction_group_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.split_group')));
return false; return false;
} }
@@ -77,7 +80,7 @@ class ConvertToDeposit implements ActionInterface
$type = $object->transactionType->type; $type = $object->transactionType->type;
if (TransactionType::DEPOSIT === $type) { if (TransactionType::DEPOSIT === $type) {
Log::error(sprintf('Journal #%d is already a deposit (rule #%d).', $journal['transaction_journal_id'], $this->action->rule_id)); Log::error(sprintf('Journal #%d is already a deposit (rule #%d).', $journal['transaction_journal_id'], $this->action->rule_id));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.is_already_deposit')));
return false; return false;
} }
@@ -89,6 +92,7 @@ class ConvertToDeposit implements ActionInterface
} catch (JsonException | FireflyException $e) { } catch (JsonException | FireflyException $e) {
Log::debug('Could not convert withdrawal to deposit.'); Log::debug('Could not convert withdrawal to deposit.');
Log::error($e->getMessage()); Log::error($e->getMessage());
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
return false; return false;
} }
@@ -104,13 +108,14 @@ class ConvertToDeposit implements ActionInterface
} catch (JsonException | FireflyException $e) { } catch (JsonException | FireflyException $e) {
Log::debug('Could not convert transfer to deposit.'); Log::debug('Could not convert transfer to deposit.');
Log::error($e->getMessage()); Log::error($e->getMessage());
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
return false; return false;
} }
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::TRANSFER, TransactionType::DEPOSIT)); event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::TRANSFER, TransactionType::DEPOSIT));
return $res; return $res;
} }
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.unsupported_transaction_type_deposit', ['type' => $type])));
return false; return false;
} }

View File

@@ -24,6 +24,8 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
@@ -62,11 +64,13 @@ class ConvertToTransfer implements ActionInterface
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
if (null === $object) { if (null === $object) {
Log::error(sprintf('Cannot find journal #%d, cannot convert to transfer.', $journal['transaction_journal_id'])); Log::error(sprintf('Cannot find journal #%d, cannot convert to transfer.', $journal['transaction_journal_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_not_found')));
return false; return false;
} }
$groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count(); $groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count();
if ($groupCount > 1) { if ($groupCount > 1) {
Log::error(sprintf('Group #%d has more than one transaction in it, cannot convert to transfer.', $journal['transaction_group_id'])); Log::error(sprintf('Group #%d has more than one transaction in it, cannot convert to transfer.', $journal['transaction_group_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.split_group')));
return false; return false;
} }
@@ -77,15 +81,19 @@ class ConvertToTransfer implements ActionInterface
Log::error( Log::error(
sprintf('Journal #%d is already a transfer so cannot be converted (rule #%d).', $object->id, $this->action->rule_id) sprintf('Journal #%d is already a transfer so cannot be converted (rule #%d).', $object->id, $this->action->rule_id)
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.is_already_transfer')));
return false; return false;
} }
if (TransactionType::DEPOSIT !== $type && TransactionType::WITHDRAWAL !== $type) {
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.unsupported_transaction_type_transfer', ['type' => $type])));
return false;
}
// find the asset account in the action value. // find the asset account in the action value.
/** @var AccountRepositoryInterface $repository */ /** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$repository->setUser($user); $repository->setUser($user);
$opposing = null;
$expectedType = null; $expectedType = null;
if (TransactionType::WITHDRAWAL === $type) { if (TransactionType::WITHDRAWAL === $type) {
$expectedType = $this->getSourceType($journalId); $expectedType = $this->getSourceType($journalId);
@@ -107,6 +115,7 @@ class ConvertToTransfer implements ActionInterface
$this->action->rule_id $this->action->rule_id
) )
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_valid_opposing', ['name' => $this->action->action_value])));
return false; return false;
} }
@@ -118,9 +127,12 @@ class ConvertToTransfer implements ActionInterface
} catch (FireflyException $e) { } catch (FireflyException $e) {
Log::debug('Could not convert withdrawal to transfer.'); Log::debug('Could not convert withdrawal to transfer.');
Log::error($e->getMessage()); Log::error($e->getMessage());
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
return false; return false;
} }
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::WITHDRAWAL, TransactionType::TRANSFER)); if (false !== $res) {
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::WITHDRAWAL, TransactionType::TRANSFER));
}
return $res; return $res;
} }
if (TransactionType::DEPOSIT === $type) { if (TransactionType::DEPOSIT === $type) {
@@ -130,12 +142,15 @@ class ConvertToTransfer implements ActionInterface
} catch (FireflyException $e) { } catch (FireflyException $e) {
Log::debug('Could not convert deposit to transfer.'); Log::debug('Could not convert deposit to transfer.');
Log::error($e->getMessage()); Log::error($e->getMessage());
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
return false; return false;
} }
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::DEPOSIT, TransactionType::TRANSFER)); if (false !== $res) {
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::DEPOSIT, TransactionType::TRANSFER));
}
return $res; return $res;
} }
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.unsupported_transaction_type_transfer', ['type' => $type])));
return false; return false;
} }
@@ -192,6 +207,7 @@ class ConvertToTransfer implements ActionInterface
[$journal->id, $opposing->name, $this->action->rule_id] [$journal->id, $opposing->name, $this->action->rule_id]
) )
); );
event(new RuleActionFailedOnObject($this->action, $journal, trans('rules.already_has_source_asset', ['name' => $opposing->name])));
return false; return false;
} }
@@ -250,6 +266,7 @@ class ConvertToTransfer implements ActionInterface
[$journal->id, $opposing->name, $this->action->rule_id] [$journal->id, $opposing->name, $this->action->rule_id]
) )
); );
event(new RuleActionFailedOnObject($this->action, $journal, trans('rules.already_has_destination_asset', ['name' => $opposing->name])));
return false; return false;
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\AccountFactory; use FireflyIII\Factory\AccountFactory;
@@ -65,21 +66,26 @@ class ConvertToWithdrawal implements ActionInterface
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
if (null === $object) { if (null === $object) {
Log::error(sprintf('Cannot find journal #%d, cannot convert to withdrawal.', $journal['transaction_journal_id'])); Log::error(sprintf('Cannot find journal #%d, cannot convert to withdrawal.', $journal['transaction_journal_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_not_found')));
return false; return false;
} }
$groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count(); $groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count();
if ($groupCount > 1) { if ($groupCount > 1) {
Log::error(sprintf('Group #%d has more than one transaction in it, cannot convert to withdrawal.', $journal['transaction_group_id'])); Log::error(sprintf('Group #%d has more than one transaction in it, cannot convert to withdrawal.', $journal['transaction_group_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.split_group')));
return false; return false;
} }
$type = $object->transactionType->type; $type = $object->transactionType->type;
if (TransactionType::WITHDRAWAL === $type) { if (TransactionType::WITHDRAWAL === $type) {
Log::error(sprintf('Journal #%d is already a withdrawal (rule #%d).', $journal['transaction_journal_id'], $this->action->rule_id)); Log::error(sprintf('Journal #%d is already a withdrawal (rule #%d).', $journal['transaction_journal_id'], $this->action->rule_id));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.is_already_withdrawal')));
return false;
}
if (TransactionType::DEPOSIT !== $type && TransactionType::TRANSFER !== $type) {
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.unsupported_transaction_type_withdrawal', ['type' => $type])));
return false; return false;
} }
if (TransactionType::DEPOSIT === $type) { if (TransactionType::DEPOSIT === $type) {
Log::debug('Going to transform a deposit to a withdrawal.'); Log::debug('Going to transform a deposit to a withdrawal.');
try { try {
@@ -87,6 +93,7 @@ class ConvertToWithdrawal implements ActionInterface
} catch (JsonException | FireflyException $e) { } catch (JsonException | FireflyException $e) {
Log::debug('Could not convert transfer to deposit.'); Log::debug('Could not convert transfer to deposit.');
Log::error($e->getMessage()); Log::error($e->getMessage());
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
return false; return false;
} }
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::DEPOSIT, TransactionType::WITHDRAWAL)); event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::DEPOSIT, TransactionType::WITHDRAWAL));
@@ -101,13 +108,14 @@ class ConvertToWithdrawal implements ActionInterface
} catch (JsonException | FireflyException $e) { } catch (JsonException | FireflyException $e) {
Log::debug('Could not convert transfer to deposit.'); Log::debug('Could not convert transfer to deposit.');
Log::error($e->getMessage()); Log::error($e->getMessage());
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.complex_error')));
return false; return false;
} }
event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::TRANSFER, TransactionType::WITHDRAWAL)); event(new TriggeredAuditLog($this->action->rule, $object, 'update_transaction_type', TransactionType::TRANSFER, TransactionType::WITHDRAWAL));
return $res; return $res;
} }
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.unsupported_transaction_type_withdrawal', ['type' => $type])));
return false; return false;
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -73,6 +74,7 @@ class LinkToBill implements ActionInterface
$billName $billName
) )
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.already_linked_to_subscription', ['name' => $billName])));
return false; return false;
} }
@@ -97,7 +99,7 @@ class LinkToBill implements ActionInterface
$billName $billName
) )
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_subscription', ['name' => $billName])));
return false; return false;
} }
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
@@ -57,6 +58,7 @@ class MoveDescriptionToNotes implements ActionInterface
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
if (null === $object) { if (null === $object) {
Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id'])); Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_other_user')));
return false; return false;
} }
$note = $object->notes()->first(); $note = $object->notes()->first();

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -63,16 +64,19 @@ class MoveNotesToDescription implements ActionInterface
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
if (null === $object) { if (null === $object) {
Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id'])); Log::error(sprintf('No journal #%d belongs to user #%d.', $journal['transaction_journal_id'], $journal['user_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_other_user')));
return false; return false;
} }
$note = $object->notes()->first(); $note = $object->notes()->first();
if (null === $note) { if (null === $note) {
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_notes_to_move')));
// nothing to move, return null // nothing to move, return null
return false; return false;
} }
if ('' === $note->text) { if ('' === $note->text) {
// nothing to move, return null // nothing to move, return null
$note->delete(); $note->delete();
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_notes_to_move')));
return false; return false;
} }
$before = $object->description; $before = $object->description;

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -55,6 +56,7 @@ class RemoveAllTags implements ActionInterface
$count = DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal['transaction_journal_id'])->count(); $count = DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal['transaction_journal_id'])->count();
if (0 === $count) { if (0 === $count) {
Log::debug(sprintf('RuleAction RemoveAllTags, journal #%d has no tags.', $journal['transaction_journal_id'])); Log::debug(sprintf('RuleAction RemoveAllTags, journal #%d has no tags.', $journal['transaction_journal_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_tags_to_remove')));
return false; return false;
} }
Log::debug(sprintf('RuleAction RemoveAllTags removed all tags from journal %d.', $journal['transaction_journal_id'])); Log::debug(sprintf('RuleAction RemoveAllTags removed all tags from journal %d.', $journal['transaction_journal_id']));

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -61,6 +62,7 @@ class RemoveTag implements ActionInterface
Log::debug( Log::debug(
sprintf('RuleAction RemoveTag tried to remove tag "%s" from journal #%d but no such tag exists.', $name, $journal['transaction_journal_id']) sprintf('RuleAction RemoveTag tried to remove tag "%s" from journal #%d but no such tag exists.', $name, $journal['transaction_journal_id'])
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_tag', ['tag' => $name])));
return false; return false;
} }
$count = DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal['transaction_journal_id'])->where('tag_id', $tag->id)->count(); $count = DB::table('tag_transaction_journal')->where('transaction_journal_id', $journal['transaction_journal_id'])->where('tag_id', $tag->id)->count();
@@ -68,6 +70,7 @@ class RemoveTag implements ActionInterface
Log::debug( Log::debug(
sprintf('RuleAction RemoveTag tried to remove tag "%s" from journal #%d but no such tag is linked.', $name, $journal['transaction_journal_id']) sprintf('RuleAction RemoveTag tried to remove tag "%s" from journal #%d but no such tag is linked.', $name, $journal['transaction_journal_id'])
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_unlink_tag', ['tag' => $name])));
return false; return false;
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -65,7 +66,7 @@ class SetBudget implements ActionInterface
$search $search
) )
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_budget', ['name' => $search])));
return false; return false;
} }
@@ -78,10 +79,21 @@ class SetBudget implements ActionInterface
$journal['transaction_type_type'] $journal['transaction_type_type']
) )
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_set_budget', ['type' => $journal['transaction_type_type'], 'name' => $search])));
return false; return false;
} }
// find previous budget
/** @var TransactionJournal $object */
$object = $user->transactionJournals()->find($journal['transaction_journal_id']);
$oldBudget = $object->budgets()->first();
$oldBudgetName = $oldBudget?->name;
if ((int)$oldBudget?->id === (int)$budget->id) {
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.already_linked_to_budget', ['name' => $budget->name])));
return false;
}
Log::debug( Log::debug(
sprintf('RuleAction SetBudget set the budget of journal #%d to budget #%d ("%s").', $journal['transaction_journal_id'], $budget->id, $budget->name) sprintf('RuleAction SetBudget set the budget of journal #%d to budget #%d ("%s").', $journal['transaction_journal_id'], $budget->id, $budget->name)
); );
@@ -91,7 +103,7 @@ class SetBudget implements ActionInterface
/** @var TransactionJournal $object */ /** @var TransactionJournal $object */
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
event(new TriggeredAuditLog($this->action->rule, $object, 'set_budget', null, $budget->name)); event(new TriggeredAuditLog($this->action->rule, $object, 'set_budget', $oldBudgetName, $budget->name));
return true; return true;
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Factory\CategoryFactory; use FireflyIII\Factory\CategoryFactory;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
@@ -57,7 +58,7 @@ class SetCategory implements ActionInterface
$search = $this->action->action_value; $search = $this->action->action_value;
if (null === $user) { if (null === $user) {
Log::error(sprintf('Journal has no valid user ID so action SetCategory("%s") cannot be applied', $search), $journal); Log::error(sprintf('Journal has no valid user ID so action SetCategory("%s") cannot be applied', $search), $journal);
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_such_journal')));
return false; return false;
} }
@@ -73,7 +74,7 @@ class SetCategory implements ActionInterface
$search $search
) )
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_category', ['name' => $search])));
return false; return false;
} }
@@ -86,12 +87,22 @@ class SetCategory implements ActionInterface
) )
); );
// find previous category
/** @var TransactionJournal $object */
$object = $user->transactionJournals()->find($journal['transaction_journal_id']);
$oldCategory = $object->categories()->first();
$oldCategoryName = $oldCategory?->name;
if ((int)$oldCategory?->id === (int)$category->id) {
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.already_linked_to_category', ['name' => $category->name])));
return false;
}
DB::table('category_transaction_journal')->where('transaction_journal_id', '=', $journal['transaction_journal_id'])->delete(); DB::table('category_transaction_journal')->where('transaction_journal_id', '=', $journal['transaction_journal_id'])->delete();
DB::table('category_transaction_journal')->insert(['transaction_journal_id' => $journal['transaction_journal_id'], 'category_id' => $category->id]); DB::table('category_transaction_journal')->insert(['transaction_journal_id' => $journal['transaction_journal_id'], 'category_id' => $category->id]);
/** @var TransactionJournal $object */ /** @var TransactionJournal $object */
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
event(new TriggeredAuditLog($this->action->rule, $object, 'set_category', null, $category->name)); event(new TriggeredAuditLog($this->action->rule, $object, 'set_category', $oldCategoryName, $category->name));
return true; return true;
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
@@ -65,7 +66,7 @@ class SetDestinationAccount implements ActionInterface
if (null === $object) { if (null === $object) {
Log::error('Could not find journal.'); Log::error('Could not find journal.');
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_such_journal')));
return false; return false;
} }
$type = $object->transactionType->type; $type = $object->transactionType->type;
@@ -81,7 +82,7 @@ class SetDestinationAccount implements ActionInterface
$this->action->action_value $this->action->action_value
) )
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_asset', ['name' => $this->action->action_value])));
return false; return false;
} }
@@ -90,13 +91,13 @@ class SetDestinationAccount implements ActionInterface
$source = $object->transactions()->where('amount', '<', 0)->first(); $source = $object->transactions()->where('amount', '<', 0)->first();
if (null === $source) { if (null === $source) {
Log::error('Could not find source transaction.'); Log::error('Could not find source transaction.');
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_source_transaction')));
return false; return false;
} }
// account must not be deleted (in the meantime): // account must not be deleted (in the meantime):
if (null === $source->account) { if (null === $source->account) {
Log::error('Could not find source transaction account.'); Log::error('Could not find source transaction account.');
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_source_transaction_account')));
return false; return false;
} }
if (null !== $newAccount && (int)$newAccount->id === (int)$source->account_id) { if (null !== $newAccount && (int)$newAccount->id === (int)$source->account_id) {
@@ -108,6 +109,7 @@ class SetDestinationAccount implements ActionInterface
) )
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.already_has_destination', ['name' => $newAccount->name])));
return false; return false;
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
@@ -64,7 +65,7 @@ class SetSourceAccount implements ActionInterface
$this->repository = app(AccountRepositoryInterface::class); $this->repository = app(AccountRepositoryInterface::class);
if (null === $object) { if (null === $object) {
Log::error('Could not find journal.'); Log::error('Could not find journal.');
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_such_journal')));
return false; return false;
} }
$type = $object->transactionType->type; $type = $object->transactionType->type;
@@ -76,7 +77,7 @@ class SetSourceAccount implements ActionInterface
Log::error( Log::error(
sprintf('Cant change source account of journal #%d because no asset account with name "%s" exists.', $object->id, $this->action->action_value) sprintf('Cant change source account of journal #%d because no asset account with name "%s" exists.', $object->id, $this->action->action_value)
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_asset', ['name' => $this->action->action_value])));
return false; return false;
} }
@@ -85,13 +86,13 @@ class SetSourceAccount implements ActionInterface
$destination = $object->transactions()->where('amount', '>', 0)->first(); $destination = $object->transactions()->where('amount', '>', 0)->first();
if (null === $destination) { if (null === $destination) {
Log::error('Could not find destination transaction.'); Log::error('Could not find destination transaction.');
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_destination_transaction')));
return false; return false;
} }
// account must not be deleted (in the meantime): // account must not be deleted (in the meantime):
if (null === $destination->account) { if (null === $destination->account) {
Log::error('Could not find destination transaction account.'); Log::error('Could not find destination transaction account.');
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_destination_transaction_account')));
return false; return false;
} }
if (null !== $newAccount && (int)$newAccount->id === (int)$destination->account_id) { if (null !== $newAccount && (int)$newAccount->id === (int)$destination->account_id) {
@@ -102,12 +103,12 @@ class SetSourceAccount implements ActionInterface
$destination->account_id $destination->account_id
) )
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.already_has_source', ['name' => $newAccount->name])));
return false; return false;
} }
// if this is a deposit, the new source account must be a revenue account and may be created: // if this is a deposit, the new source account must be a revenue account and may be created:
// or its a liability // or it's a liability
if (TransactionType::DEPOSIT === $type) { if (TransactionType::DEPOSIT === $type) {
$newAccount = $this->findDepositSourceAccount(); $newAccount = $this->findDepositSourceAccount();
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use DB; use DB;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
@@ -59,18 +60,20 @@ class SwitchAccounts implements ActionInterface
$object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
if (null === $object) { if (null === $object) {
Log::error(sprintf('Cannot find journal #%d, cannot switch accounts.', $journal['transaction_journal_id'])); Log::error(sprintf('Cannot find journal #%d, cannot switch accounts.', $journal['transaction_journal_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_such_journal')));
return false; return false;
} }
$groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count(); $groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count();
if ($groupCount > 1) { if ($groupCount > 1) {
Log::error(sprintf('Group #%d has more than one transaction in it, cannot switch accounts.', $journal['transaction_group_id'])); Log::error(sprintf('Group #%d has more than one transaction in it, cannot switch accounts.', $journal['transaction_group_id']));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.split_group')));
return false; return false;
} }
$type = $object->transactionType->type; $type = $object->transactionType->type;
if (TransactionType::TRANSFER !== $type) { if (TransactionType::TRANSFER !== $type) {
Log::error(sprintf('Journal #%d is NOT a transfer (rule #%d), cannot switch accounts.', $journal['transaction_journal_id'], $this->action->rule_id)); Log::error(sprintf('Journal #%d is NOT a transfer (rule #%d), cannot switch accounts.', $journal['transaction_journal_id'], $this->action->rule_id));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.is_not_transfer')));
return false; return false;
} }
@@ -80,7 +83,7 @@ class SwitchAccounts implements ActionInterface
$destTransaction = $object->transactions()->where('amount', '>', 0)->first(); $destTransaction = $object->transactions()->where('amount', '>', 0)->first();
if (null === $sourceTransaction || null === $destTransaction) { if (null === $sourceTransaction || null === $destTransaction) {
Log::error(sprintf('Journal #%d has no source or destination transaction (rule #%d), cannot switch accounts.', $journal['transaction_journal_id'], $this->action->rule_id)); Log::error(sprintf('Journal #%d has no source or destination transaction (rule #%d), cannot switch accounts.', $journal['transaction_journal_id'], $this->action->rule_id));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_accounts')));
return false; return false;
} }
$sourceAccountId = (int)$sourceTransaction->account_id; $sourceAccountId = (int)$sourceTransaction->account_id;

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions; namespace FireflyIII\TransactionRules\Actions;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
@@ -61,16 +62,15 @@ class UpdatePiggybank implements ActionInterface
// refresh the transaction type. // refresh the transaction type.
$user = User::find($journal['user_id']); $user = User::find($journal['user_id']);
/** @var TransactionJournal $journalObj */ /** @var TransactionJournal $journalObj */
$journalObj = $user->transactionJournals()->find($journal['transaction_journal_id']); $journalObj = $user->transactionJournals()->find($journal['transaction_journal_id']);
$type = TransactionType::find((int)$journalObj->transaction_type_id); $type = TransactionType::find((int)$journalObj->transaction_type_id);
$journal['transaction_type_type'] = $type->type;
$piggyBank = $this->findPiggyBank($user); $piggyBank = $this->findPiggyBank($user);
if (null === $piggyBank) { if (null === $piggyBank) {
Log::info( Log::info(
sprintf('No piggy bank named "%s", cant execute action #%d of rule #%d', $this->action->action_value, $this->action->id, $this->action->rule_id) sprintf('No piggy bank named "%s", cant execute action #%d of rule #%d', $this->action->action_value, $this->action->id, $this->action->rule_id)
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_piggy', ['name' => $this->action->action_value])));
return false; return false;
} }
@@ -130,7 +130,7 @@ class UpdatePiggybank implements ActionInterface
$destination->account_id $destination->account_id
) )
); );
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.no_link_piggy', ['name' => $this->action->action_value])));
return false; return false;
} }

View File

@@ -28,6 +28,7 @@ use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta; use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -38,6 +39,7 @@ use Illuminate\Support\Collection;
class AccountTransformer extends AbstractTransformer class AccountTransformer extends AbstractTransformer
{ {
private array $accountMeta; private array $accountMeta;
private array $accountTypes;
private array $balances; private array $balances;
private array $convertedBalances; private array $convertedBalances;
private array $currencies; private array $currencies;
@@ -51,6 +53,7 @@ class AccountTransformer extends AbstractTransformer
{ {
$this->currencies = []; $this->currencies = [];
$this->accountMeta = []; $this->accountMeta = [];
$this->accountTypes = [];
$this->balances = app('steam')->balancesByAccounts($objects, $this->getDate()); $this->balances = app('steam')->balancesByAccounts($objects, $this->getDate());
$this->convertedBalances = app('steam')->balancesByAccountsConverted($objects, $this->getDate()); $this->convertedBalances = app('steam')->balancesByAccountsConverted($objects, $this->getDate());
$repository = app(CurrencyRepositoryInterface::class); $repository = app(CurrencyRepositoryInterface::class);
@@ -72,6 +75,15 @@ class AccountTransformer extends AbstractTransformer
$id = (int)$entry->account_id; $id = (int)$entry->account_id;
$this->accountMeta[$id][$entry->name] = $entry->data; $this->accountMeta[$id][$entry->name] = $entry->data;
} }
// get account types:
// select accounts.id, account_types.type from account_types left join accounts on accounts.account_type_id = account_types.id;
$accountTypes = AccountType::leftJoin('accounts', 'accounts.account_type_id', '=', 'account_types.id')
->whereIn('accounts.id', $accountIds)
->get(['accounts.id', 'account_types.type']);
/** @var AccountType $row */
foreach ($accountTypes as $row) {
$this->accountTypes[(int)$row->id] = (string)config(sprintf('firefly.shortNamesByFullName.%s', $row->type));
}
} }
/** /**
@@ -96,10 +108,13 @@ class AccountTransformer extends AbstractTransformer
*/ */
public function transform(Account $account): array public function transform(Account $account): array
{ {
//$fullType = $account->accountType->type;
//$accountType = (string) config(sprintf('firefly.shortNamesByFullName.%s', $fullType));
$id = (int)$account->id; $id = (int)$account->id;
// various meta
$accountRole = $this->accountMeta[$id]['account_role'] ?? null;
$accountType = $this->accountTypes[$id];
$order = (int)$account->order;
// no currency? use default // no currency? use default
$currency = $this->default; $currency = $this->default;
if (0 !== (int)$this->accountMeta[$id]['currency_id']) { if (0 !== (int)$this->accountMeta[$id]['currency_id']) {
@@ -109,16 +124,21 @@ class AccountTransformer extends AbstractTransformer
$balance = $this->balances[$id] ?? null; $balance = $this->balances[$id] ?? null;
$nativeBalance = $this->convertedBalances[$id]['native_balance'] ?? null; $nativeBalance = $this->convertedBalances[$id]['native_balance'] ?? null;
// no order for some accounts:
if (!in_array(strtolower($accountType), ['liability', 'liabilities', 'asset'], true)) {
$order = null;
}
return [ return [
'id' => (string)$account->id, 'id' => (string)$account->id,
'created_at' => $account->created_at->toAtomString(), 'created_at' => $account->created_at->toAtomString(),
'updated_at' => $account->updated_at->toAtomString(), 'updated_at' => $account->updated_at->toAtomString(),
'active' => $account->active, 'active' => $account->active,
//'order' => $order, 'order' => $order,
'name' => $account->name, 'name' => $account->name,
'iban' => '' === $account->iban ? null : $account->iban, 'iban' => '' === $account->iban ? null : $account->iban,
// 'type' => strtolower($accountType), 'type' => strtolower($accountType),
// 'account_role' => $accountRole, 'account_role' => $accountRole,
'currency_id' => (string)$currency->id, 'currency_id' => (string)$currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,

View File

@@ -28,9 +28,11 @@ use Carbon\CarbonInterface;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
use FireflyIII\Models\ObjectGroup; use FireflyIII\Models\ObjectGroup;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Log; use Log;
@@ -40,6 +42,7 @@ use Log;
*/ */
class BillTransformer extends AbstractTransformer class BillTransformer extends AbstractTransformer
{ {
private ExchangeRateConverter $converter;
private array $currencies; private array $currencies;
private TransactionCurrency $default; private TransactionCurrency $default;
private array $groups; private array $groups;
@@ -102,21 +105,71 @@ class BillTransformer extends AbstractTransformer
]; ];
} }
$this->default = app('amount')->getDefaultCurrency(); $this->default = app('amount')->getDefaultCurrency();
$this->converter = new ExchangeRateConverter();
// grab all paid dates: // grab all paid dates:
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$journals = TransactionJournal::whereIn('bill_id', $bills) $journals = TransactionJournal::whereIn('bill_id', $bills)
->where('date', '>=', $this->parameters->get('start')) ->where('date', '>=', $this->parameters->get('start'))
->where('date', '<=', $this->parameters->get('end')) ->where('date', '<=', $this->parameters->get('end'))
->get(['transaction_journals.id', 'transaction_journals.transaction_group_id', 'transaction_journals.date', 'transaction_journals.bill_id']); ->get(['transaction_journals.id', 'transaction_journals.transaction_group_id', 'transaction_journals.date', 'transaction_journals.bill_id']);
$journalIds = $journals->pluck('id')->toArray();
// grab transactions for amount:
$set = Transaction::whereIn('transaction_journal_id', $journalIds)
->where('transactions.amount', '<', 0)
->get(['transactions.id', 'transactions.transaction_journal_id', 'transactions.amount', 'transactions.foreign_amount', 'transactions.transaction_currency_id', 'transactions.foreign_currency_id']);
// convert to array for easy finding:
$transactions = [];
/** @var Transaction $transaction */
foreach ($set as $transaction) {
$journalId = (int)$transaction->transaction_journal_id;
$transactions[$journalId] = $transaction->toArray();
}
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
$billId = (int)$journal->bill_id; $transaction = $transactions[(int)$journal->id] ?? [];
$billId = (int)$journal->bill_id;
$currencyId = (int)$transaction['transaction_currency_id'] ?? 0;
$currencies[$currencyId] = $currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
// foreign currency
$foreignCurrencyId = null;
$foreignCurrencyCode = null;
$foreignCurrencyName = null;
$foreignCurrencySymbol = null;
$foreignCurrencyDp = null;
if (null !== $transaction['foreign_currency_id']) {
$foreignCurrencyId = (int)$transaction['foreign_currency_id'];
$currencies[$foreignCurrencyId] = $currencies[$foreignCurrencyId] ?? TransactionCurrency::find($foreignCurrencyId);
$foreignCurrencyCode = $currencies[$foreignCurrencyId]->code;
$foreignCurrencyName = $currencies[$foreignCurrencyId]->name;
$foreignCurrencySymbol = $currencies[$foreignCurrencyId]->symbol;
$foreignCurrencyDp = (int)$currencies[$foreignCurrencyId]->decimal_places;
}
$this->paidDates[$billId][] = [ $this->paidDates[$billId][] = [
'transaction_group_id' => (string)$journal->id, 'transaction_group_id' => (string)$journal->id,
'transaction_journal_id' => (string)$journal->transaction_group_id, 'transaction_journal_id' => (string)$journal->transaction_group_id,
'date' => $journal->date->toAtomString(), 'date' => $journal->date->toAtomString(),
'currency_id' => (int)$currencies[$currencyId]->id,
'currency_code' => $currencies[$currencyId]->code,
'currency_name' => $currencies[$currencyId]->name,
'currency_symbol' => $currencies[$currencyId]->symbol,
'currency_decimal_places' => (int)$currencies[$currencyId]->decimal_places,
'native_id' => (int)$currencies[$currencyId]->id,
'native_code' => $currencies[$currencyId]->code,
'native_symbol' => $currencies[$currencyId]->symbol,
'native_decimal_places' => (int)$currencies[$currencyId]->decimal_places,
'foreign_currency_id' => $foreignCurrencyId,
'foreign_currency_code' => $foreignCurrencyCode,
'foreign_currency_name' => $foreignCurrencyName,
'foreign_currency_symbol' => $foreignCurrencySymbol,
'foreign_currency_decimal_places' => $foreignCurrencyDp,
'amount' => $transaction['amount'],
'foreign_amount' => $transaction['foreign_amount'],
'native_amount' => $this->converter->convert($currencies[$currencyId], $this->default, $journal->date, $transaction['amount']),
'foreign_native_amount' => null === $transaction['foreign_amount'] ? null : $this->converter->convert($currencies[$foreignCurrencyId], $this->default, $journal->date, $transaction['foreign_amount']),
]; ];
} }
} }
@@ -131,11 +184,19 @@ class BillTransformer extends AbstractTransformer
*/ */
public function transform(Bill $bill): array public function transform(Bill $bill): array
{ {
$paidData = $this->paidDates[(int)$bill->id] ?? []; $paidData = $this->paidDates[(int)$bill->id] ?? [];
$nextExpectedMatch = $this->nextExpectedMatch($bill, $this->paidDates[(int)$bill->id] ?? []); $nextExpectedMatch = $this->nextExpectedMatch($bill, $this->paidDates[(int)$bill->id] ?? []);
$payDates = $this->payDates($bill); $payDates = $this->payDates($bill);
$currency = $this->currencies[(int)$bill->transaction_currency_id]; $currency = $this->currencies[(int)$bill->transaction_currency_id];
$group = $this->groups[(int)$bill->id] ?? null; $group = $this->groups[(int)$bill->id] ?? null;
// date for currency conversion
/** @var Carbon|null $startParam */
$startParam = $this->parameters->get('start');
/** @var Carbon|null $start */
$date = null === $startParam ? today() : clone $startParam;
$nextExpectedMatchDiff = $this->getNextExpectedMatchDiff($nextExpectedMatch, $payDates); $nextExpectedMatchDiff = $this->getNextExpectedMatchDiff($nextExpectedMatch, $payDates);
return [ return [
'id' => (int)$bill->id, 'id' => (int)$bill->id,
@@ -144,10 +205,18 @@ class BillTransformer extends AbstractTransformer
'name' => $bill->name, 'name' => $bill->name,
'amount_min' => app('steam')->bcround($bill->amount_min, $currency->decimal_places), 'amount_min' => app('steam')->bcround($bill->amount_min, $currency->decimal_places),
'amount_max' => app('steam')->bcround($bill->amount_max, $currency->decimal_places), 'amount_max' => app('steam')->bcround($bill->amount_max, $currency->decimal_places),
'native_amount_min' => $this->converter->convert($currency, $this->default, $date, $bill->amount_min),
'native_amount_max' => $this->converter->convert($currency, $this->default, $date, $bill->amount_max),
'currency_id' => (string)$bill->transaction_currency_id, 'currency_id' => (string)$bill->transaction_currency_id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => (int)$currency->decimal_places, 'currency_decimal_places' => (int)$currency->decimal_places,
'native_id' => $this->default->id,
'native_code' => $this->default->code,
'native_name' => $this->default->name,
'native_symbol' => $this->default->symbol,
'native_decimal_places' => (int)$this->default->decimal_places,
'date' => $bill->date->toAtomString(), 'date' => $bill->date->toAtomString(),
'end_date' => $bill->end_date?->toAtomString(), 'end_date' => $bill->end_date?->toAtomString(),
'extension_date' => $bill->extension_date?->toAtomString(), 'extension_date' => $bill->extension_date?->toAtomString(),
@@ -185,8 +254,11 @@ class BillTransformer extends AbstractTransformer
// 2023-07-1 sub one day from the start date to fix a possible bug (see #7704) // 2023-07-1 sub one day from the start date to fix a possible bug (see #7704)
// 2023-07-18 this particular date is used to search for the last paid date. // 2023-07-18 this particular date is used to search for the last paid date.
// 2023-07-18 the cloned $searchDate is used to grab the correct transactions. // 2023-07-18 the cloned $searchDate is used to grab the correct transactions.
/** @var Carbon $start */
$start = clone $this->parameters->get('start'); /** @var Carbon|null $startParam */
$startParam = $this->parameters->get('start');
/** @var Carbon|null $start */
$start = null === $startParam ? today() : clone $startParam;
$start->subDay(); $start->subDay();
$lastPaidDate = $this->lastPaidDate($dates, $start); $lastPaidDate = $this->lastPaidDate($dates, $start);

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