Compare commits

...

76 Commits

Author SHA1 Message Date
James Cole
4d7909e23d Merge branch 'release/v6.0.30' 2023-10-28 18:21:13 +02:00
James Cole
6f13600fb5 Add missing method. 2023-10-28 18:18:12 +02:00
James Cole
c9fefcd8f4 Add missing method. 2023-10-28 18:08:43 +02:00
James Cole
fa31483b02 Merge branch 'main' into develop 2023-10-28 17:38:50 +02:00
James Cole
e7be0eae8a Add workflow dispatch 2023-10-28 17:38:42 +02:00
James Cole
86c70cf232 Merge tag 'v6.0.29' into develop
v6.0.29
2023-10-28 17:32:00 +02:00
James Cole
a3490e97c0 Merge branch 'release/v6.0.29' 2023-10-28 17:31:59 +02:00
James Cole
85b1768908 Fix issue in release. 2023-10-28 17:31:42 +02:00
James Cole
6ab462a795 Fix issue in bill transformer. 2023-10-28 17:28:54 +02:00
James Cole
70f46338db Merge tag 'v6.0.28' into develop
v6.0.28
2023-10-28 17:18:51 +02:00
James Cole
461b5ad859 Merge branch 'release/v6.0.28' 2023-10-28 17:18:49 +02:00
James Cole
6af62c6be0 Update meta files for new release. 2023-10-28 17:18:02 +02:00
James Cole
78153c2aa4 Update meta files for new release. 2023-10-28 17:17:09 +02:00
James Cole
62458885ce Fix #8103 2023-10-28 16:47:31 +02:00
James Cole
83d64262c8 Refactor currency API 2023-10-28 16:47:11 +02:00
James Cole
0133a7c5db Code cleanup 2023-10-28 15:03:33 +02:00
James Cole
fa920fed4e Introduce missing methods 2023-10-28 14:59:16 +02:00
James Cole
1d138eed8d Refactor currency repository. 2023-10-28 06:58:33 +02:00
James Cole
9e94b9e57e Fix #8099 2023-10-27 18:07:56 +02:00
James Cole
c4c690f44f various fixes 2023-10-27 17:47:24 +02:00
James Cole
902cc21ff0 Debug bill transformer 2023-10-27 17:47:12 +02:00
James Cole
106471877f Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop 2023-10-27 08:48:38 +02:00
James Cole
ccaace707e rename foreign key 2023-10-27 08:48:13 +02:00
James Cole
cc14a4ac57 Merge pull request #8098 from tonicospinelli/testing
Cover preferred format methods of the Navigation class
2023-10-27 05:51:56 +02:00
James Cole
3ca1e6d197 Remove rule title 2023-10-26 08:09:16 +02:00
James Cole
531a6c17de Merge pull request #8070 from Maxco10/patch-1
[Issue #8069] Fixed bug on description field
2023-10-26 08:06:33 +02:00
Maxco10
4b7e1fcdb0 Fixed spelling and replaced quotes
Signed-off-by: Maxco10 <mmagnani93@gmail.com>
2023-10-25 11:58:14 +02:00
Maxco10
5f35bc5ee6 Added check on title and improved the check for description field
Signed-off-by: Maxco10 <mmagnani93@gmail.com>
2023-10-25 11:15:20 +02:00
Antonio Spinelli
8100f68020 Cover preferred format methods of the Navigation class 2023-10-24 22:52:01 -03:00
James Cole
32a36bbb12 Restore missing methods and fix silly bugs. 2023-10-24 18:32:24 +02:00
James Cole
64b9234207 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2023-10-23 20:09:23 +02:00
James Cole
a9d490263b Fix method. 2023-10-23 20:09:10 +02:00
James Cole
8c5a3c9b3e Merge pull request #8086 from tonicospinelli/testing
Cover endOfPeriod method of the Navigation class
2023-10-23 19:51:59 +02:00
Antonio Spinelli
dd2f8d4404 Cover endOfPeriod method of the Navigation class
The custom frequency requires a timezone configuration, forcing it
to run in the integration test scope.

Running the integration tests requires a database connection in the
build process. It enables other case tests.

The API Tests cause interference in other tests, requiring isolating
them.
2023-10-23 10:32:38 -03:00
James Cole
ea82cff0ce Merge pull request #8088 from firefly-iii/dependabot/npm_and_yarn/develop/sass-1.69.4 2023-10-23 07:06:19 +02:00
James Cole
66ef9a919a Merge pull request #8089 from firefly-iii/dependabot/npm_and_yarn/develop/alpinejs-3.13.2 2023-10-23 07:05:42 +02:00
dependabot[bot]
73b912ee8b chore(deps-dev): bump sass from 1.69.3 to 1.69.4
Bumps [sass](https://github.com/sass/dart-sass) from 1.69.3 to 1.69.4.
- [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.69.3...1.69.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 03:48:18 +00:00
James Cole
5960258a89 Merge pull request #8087 from firefly-iii/dependabot/npm_and_yarn/develop/vite-4.5.0 2023-10-23 05:47:37 +02:00
dependabot[bot]
ea7d1f481a chore(deps): bump alpinejs from 3.13.1 to 3.13.2
Bumps [alpinejs](https://github.com/alpinejs/alpine/tree/HEAD/packages/alpinejs) from 3.13.1 to 3.13.2.
- [Release notes](https://github.com/alpinejs/alpine/releases)
- [Commits](https://github.com/alpinejs/alpine/commits/v3.13.2/packages/alpinejs)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 03:46:29 +00:00
dependabot[bot]
d81a0ebba4 chore(deps-dev): bump vite from 4.4.11 to 4.5.0
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.4.11 to 4.5.0.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v4.5.0/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v4.5.0/packages/vite)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 03:46:01 +00:00
James Cole
e90fb98613 Fix https://github.com/firefly-iii/firefly-iii/issues/7204 2023-10-22 19:01:18 +02:00
James Cole
2c34bd36a5 Allow unreconcile and expand API to block reconciled transactions. 2023-10-22 18:44:30 +02:00
James Cole
a86a582d0f Rebuild frontend 2023-10-22 16:27:03 +02:00
James Cole
c7778ce8cb Merge pull request #8084 from JoSchrader/develop
Hide duplicated webhook create button
2023-10-22 16:12:40 +02:00
root
5eaf1f4438 Hide duplicated webhook create button
When there are no webhooks yet the button below the table will be hidden
2023-10-22 14:45:58 +02:00
James Cole
691682bc0c Fix bad math in piggy bank order code 2023-10-22 09:52:43 +02:00
James Cole
8627ee391a Add missing command 2023-10-22 08:50:35 +02:00
James Cole
41089a0a0a Rename workflows. 2023-10-22 08:22:53 +02:00
James Cole
2072a3dd94 Remove old frontend 2023-10-22 08:18:24 +02:00
James Cole
8eec325e0a Merge branch 'main' into develop 2023-10-22 08:17:44 +02:00
James Cole
7ae88b42cf Add label action 2023-10-22 08:16:16 +02:00
James Cole
24e0839c34 Merge branch 'main' into develop 2023-10-22 08:05:48 +02:00
James Cole
c3398d4d51 Fix refactor for field. 2023-10-22 08:05:28 +02:00
James Cole
80237d8bc3 Refactor methods that request the old currency preference. 2023-10-22 07:55:36 +02:00
James Cole
4cec0a9f97 Refactor repository and some commands for upgrading 2023-10-22 07:51:26 +02:00
James Cole
a810eb2cb5 Do error catching etc. 2023-10-22 07:50:46 +02:00
James Cole
7feb4b4aaf Upgrade database version 2023-10-22 07:45:57 +02:00
James Cole
840fd61b04 Update API 2023-10-22 07:45:48 +02:00
James Cole
5425dac180 Update index to handle new fields. 2023-10-22 07:17:53 +02:00
James Cole
0d65e396d4 Update get() methods. 2023-10-22 07:16:05 +02:00
James Cole
704fc24d20 Rename field for less confusion. 2023-10-22 07:12:47 +02:00
James Cole
9b22c16f14 Remove unused logic from home controller 2023-10-22 06:58:17 +02:00
James Cole
2923d1b449 Remove unused methods from currency controller 2023-10-22 06:57:59 +02:00
James Cole
9d5b028a5f Remove routes that enable/disable/default a currency. 2023-10-22 06:57:15 +02:00
James Cole
97dfdd5c5d Link currency to user and user group. 2023-10-22 06:56:46 +02:00
James Cole
eb5ee4d147 Slightly better text. 2023-10-21 10:39:38 +02:00
James Cole
d97581325d Expand YAML once more. 2023-10-21 08:02:43 +02:00
James Cole
2a1e53f32a Slight changes in yaml config. 2023-10-21 08:00:24 +02:00
James Cole
b5e4ac0038 Add label actions things. 2023-10-21 07:58:24 +02:00
James Cole
b032210a33 Small changes to create transaction form 2023-10-21 07:45:28 +02:00
James Cole
24a1d61560 Merge branch 'main' into develop 2023-10-21 07:38:29 +02:00
James Cole
d632c1c7fc Introduce clone and edit button. 2023-10-21 07:38:08 +02:00
James Cole
9c5b3fc030 Merge pull request #8072 from firefly-iii/dependabot/npm_and_yarn/frontend/babel/traverse-7.23.2 2023-10-18 05:07:07 +02:00
dependabot[bot]
90e407b9d0 chore(deps): bump @babel/traverse from 7.17.9 to 7.23.2 in /frontend
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.17.9 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-17 23:03:13 +00:00
Maxco10
dc0a2a2a10 Fixed bug on description field
Signed-off-by: Maxco10 <mmagnani93@gmail.com>
2023-10-17 21:59:56 +02:00
James Cole
b6aa76477e Merge tag 'v6.0.27' into develop
v6.0.27
2023-10-15 13:30:41 +02:00
539 changed files with 5352 additions and 38663 deletions

View File

@@ -226,16 +226,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.35.1", "version": "v3.37.0",
"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": "ec1ccc264994b6764882669973ca435cf05bab08" "reference": "d5ccc3807fd496ac2b448e8e5e57aa0772f0d18b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/ec1ccc264994b6764882669973ca435cf05bab08", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/d5ccc3807fd496ac2b448e8e5e57aa0772f0d18b",
"reference": "ec1ccc264994b6764882669973ca435cf05bab08", "reference": "d5ccc3807fd496ac2b448e8e5e57aa0772f0d18b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -307,7 +307,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.35.1" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.37.0"
}, },
"funding": [ "funding": [
{ {
@@ -315,7 +315,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-10-12T13:47:26+00:00" "time": "2023-10-28T14:49:50+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",

View File

@@ -195,6 +195,16 @@ MAP_DEFAULT_LAT=51.983333
MAP_DEFAULT_LONG=5.916667 MAP_DEFAULT_LONG=5.916667
MAP_DEFAULT_ZOOM=6 MAP_DEFAULT_ZOOM=6
#
# Some objects have room for an URL, like transactions and webhooks.
# By default, the following protocols are allowed:
# http, https, ftp, ftps, mailto
#
# To change this, set your preferred comma separated set below.
# Be sure to include http, https and other default ones if you need to.
#
VALID_URL_PROTOCOLS=
# #
# Firefly III authentication settings # Firefly III authentication settings
# #

37
.github/label-actions.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
# Configuration for Label Actions - https://github.com/dessant/label-actions
# The `feature` label is added to issues
feature:
issues:
# Post a comment, `{issue-author}` is an optional placeholder
comment: |
Hi there! This is an automatic reply. `Share and enjoy`
This issue has been marked as a feature request. The requested (new) feature will become a part of Firefly III or the data importer in due course.
If you come across this issue, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. You can subscribe to this issue to get updates.
Thank you for your contributions.
enhancement:
issues:
# Post a comment, `{issue-author}` is an optional placeholder
comment: |
Hi there! This is an automatic reply. `Share and enjoy`
This issue has been marked as an enhancement. The requested enhancement to an existing feature will become a part of Firefly III or the data importer in due course.
If you come across this issue, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. You can subscribe to this issue to get updates.
Thank you for your contributions.
# The `solved` label is added to discussions
triage:
issues:
# Post a comment, `{issue-author}` is an optional placeholder
comment: |
Hi there! This is an automatic reply. `Share and enjoy`
This issue has been marked as being in triage. The root cause is not known yet, or the issue needs more investigation. You can help by sharing debug information (from `/debug`) if you also have this issue or when you haven't already done so.
Thank you for your contributions.

View File

@@ -1,6 +1,6 @@
# This workflow prunes old workflow runs for an entire repository. # This workflow prunes old workflow runs for an entire repository.
name: Prune old builds name: "Chore - prune old builds"
on: on:
schedule: schedule:
@@ -22,14 +22,14 @@ jobs:
repo: context.repo.repo, repo: context.repo.repo,
status: 'cancelled', status: 'cancelled',
}); });
const skipped = await github.rest.actions.listWorkflowRunsForRepo({ const skipped = await github.rest.actions.listWorkflowRunsForRepo({
owner: context.repo.owner, owner: context.repo.owner,
per_page: 100, per_page: 100,
repo: context.repo.repo, repo: context.repo.repo,
status: 'skipped', status: 'skipped',
}); });
for (const response of [cancelled, skipped]) { for (const response of [cancelled, skipped]) {
for (const run of response.data.workflow_runs) { for (const run of response.data.workflow_runs) {
console.log(`Run id ${run.id} of '${run.name}' is a cancelled/skipped run. Deleting...`); console.log(`Run id ${run.id} of '${run.name}' is a cancelled/skipped run. Deleting...`);
@@ -50,10 +50,10 @@ jobs:
const ms_in_day = 86400000; const ms_in_day = 86400000;
const now = Date.now(); const now = Date.now();
const pages = 5; const pages = 5;
// we don't want to prune old runs from test.yml // we don't want to prune old runs from test.yml
// because we track the duration of runs over time // because we track the duration of runs over time
const workflows = [ const workflows = [
'cleanup.yml', 'cleanup.yml',
'closed-issues.yml', 'closed-issues.yml',
@@ -64,9 +64,9 @@ jobs:
'sonarcloud.yml', 'sonarcloud.yml',
'stale.yml' 'stale.yml'
] ]
let runs_to_delete = []; let runs_to_delete = [];
for (const workflow of workflows) { for (const workflow of workflows) {
for (let page = 0; page < pages; page += 1) { for (let page = 0; page < pages; page += 1) {
let response = await github.rest.actions.listWorkflowRuns({ let response = await github.rest.actions.listWorkflowRuns({
@@ -76,7 +76,7 @@ jobs:
repo: context.repo.repo, repo: context.repo.repo,
workflow_id: workflow workflow_id: workflow
}); });
if (response.data.workflow_runs.length > 0) { if (response.data.workflow_runs.length > 0) {
for (const run of response.data.workflow_runs) { for (const run of response.data.workflow_runs) {
if (now - Date.parse(run.created_at) > ms_in_day * days_to_expiration) { if (now - Date.parse(run.created_at) > ms_in_day * days_to_expiration) {
@@ -86,7 +86,7 @@ jobs:
} }
} }
} }
for (const run of runs_to_delete) { for (const run of runs_to_delete) {
console.log(`Run id ${run[0]} of '${run[1]}' is older than ${days_to_expiration} days. Deleting...`); console.log(`Run id ${run[0]} of '${run[1]}' is older than ${days_to_expiration} days. Deleting...`);
try { try {

View File

@@ -1,4 +1,4 @@
name: "Reply to closed issue" name: "Issues - reply to closed issue"
on: on:
issues: issues:
types: types:

View File

@@ -1,4 +1,4 @@
name: 'Dependency Review' name: 'Code - dependency review'
on: [ pull_request ] on: [ pull_request ]
permissions: permissions:

21
.github/workflows/label-actions.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: 'Issues - reply to specific labels'
on:
issues:
types: [labeled, unlabeled]
pull_request_target:
types: [labeled, unlabeled]
discussion:
types: [labeled, unlabeled]
permissions:
contents: read
issues: write
pull-requests: write
discussions: write
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/label-actions@v3

View File

@@ -1,146 +0,0 @@
name: Firefly III
on:
push:
branches-ignore:
- '**'
jobs:
prepare:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Copy .env
run: test -f .env || cp .ci/.env.ci .env
- name: Prepare dependencies
run: |
set -euxo pipefail
export PATH=$PATH:$HOME/.composer/vendor/bin/
composer global require hirak/prestissimo --no-plugins --no-scripts
composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --no-suggest
touch ./storage/database/database.sqlite
- name: Prepare Firefly III
run: |
chmod -R 777 storage bootstrap/cache
php artisan migrate --seed
php artisan firefly-iii:upgrade-database
- name: Upload database
uses: actions/upload-artifact@v2
with:
name: database
path: storage/database/database.sqlite
- name: Upload cache
uses: actions/upload-artifact@v2
with:
name: cache
path: bootstrap/cache/
- name: Upload composer cache
uses: actions/upload-artifact@v2
with:
name: composer
path: ~/.composer
laravel-tests:
runs-on: ubuntu-latest
needs:
- prepare
steps:
- uses: actions/checkout@v3
- name: Copy .env
run: test -f .env || cp .ci/.env.ci .env
- name: Download database
uses: actions/download-artifact@v2
with:
name: database
path: storage/database/database.sqlite
- name: Download cache
uses: actions/download-artifact@v2
with:
name: cache
path: bootstrap/cache/
- name: Download vendor
uses: actions/download-artifact@v2
with:
name: composer
path: ~/.composer
- name: Install composer
run: composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --no-suggest
- name: PHPUnit tests
uses: php-actions/phpunit@v1
with:
config: phpunit.xml
memory: 512M
coding-standards:
runs-on: ubuntu-latest
needs:
- prepare
steps:
- uses: actions/checkout@v3
- name: Copy .env
run: test -f .env || cp .ci/.env.ci .env
- name: Download database
uses: actions/download-artifact@v2
with:
name: database
path: storage/database/database.sqlite
- name: Download cache
uses: actions/download-artifact@v2
with:
name: cache
path: bootstrap/cache/
- name: Download vendor
uses: actions/download-artifact@v2
with:
name: composer
path: ~/.composer
- name: install depenencies
run: |
composer global require nette/coding-standard
composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --no-suggest
- name: Execute code standard
run: /home/runner/.composer/vendor/bin/ecs check app tests --config ./.ci/firefly-iii-standard.yml
phpstan:
runs-on: ubuntu-latest
needs:
- prepare
steps:
- uses: actions/checkout@v3
- name: Copy .env
run: test -f .env || cp .ci/.env.ci .env
- name: Download database
uses: actions/download-artifact@v2
with:
name: database
path: storage/database/database.sqlite
- name: Download cache
uses: actions/download-artifact@v2
with:
name: cache
path: bootstrap/cache/
- name: Download vendor
uses: actions/download-artifact@v2
with:
name: composer
path: ~/.composer
- name: Install depenencies
run: |
composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --no-suggest
- name: Execute PHPStan
run: vendor/bin/phpstan analyse -c .ci/phpstan.neon

View File

@@ -1,4 +1,4 @@
name: Lock old issues name: 'Issues - Lock old issues'
on: on:
workflow_dispatch: workflow_dispatch:

View File

@@ -1,35 +0,0 @@
name: Qodana
on:
workflow_dispatch:
push:
branches:
- main
- develop
jobs:
qodana:
runs-on: ubuntu-latest
name: 'Qodana Scan'
steps:
- name: Setup PHP with no coverage driver
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
coverage: none
extensions: bcmath, intl
env:
update: true
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Install dependencies
run: |
composer install --no-scripts
cp .env.example .env
php artisan key:generate
php artisan clear-compiled
php artisan ide-helper:generate;
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@main
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}

View File

@@ -1,14 +1,38 @@
name: Sonarcloud name: 'Code - Run Sonarcloud'
on: on:
pull_request: pull_request:
workflow_dispatch:
push: push:
branches: branches:
- main - main
- develop - develop
env:
DB_CONNECTION: mysql
DB_HOST: "127.0.0.1"
DB_DATABASE: firefly
DB_USER: firefly
DB_PASSWORD: secret_firefly_password
jobs: jobs:
sonarcloud: sonarcloud:
name: SonarCloud name: SonarCloud
runs-on: ubuntu-latest runs-on: ubuntu-latest
services:
mariadb:
image: mariadb:latest
ports:
- 3306:3306
env:
MYSQL_ROOT_PASSWORD: yes
MYSQL_USER: ${{ env.DB_USER }}
MYSQL_PASSWORD: ${{ env.DB_PASSWORD }}
MYSQL_DATABASE: ${{ env.DB_DATABASE }}
options: >-
--health-cmd="healthcheck.sh --connect --innodb_initialized"
--health-interval=10s
--health-timeout=5s
--health-retries=3
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@@ -24,16 +48,49 @@ jobs:
with: with:
php-version: '8.2' php-version: '8.2'
coverage: xdebug coverage: xdebug
extensions: >-
bcmath
curl
fileinfo
iconv
intl
json
mbstring
openssl
pdo
session
simplexml
sodium
tokenizer
xml
xmlwriter
- name: Install Composer dependencies - name: Install Composer dependencies
run: composer install --prefer-dist --no-interaction --no-progress --no-scripts run: composer install --prefer-dist --no-interaction --no-progress --no-scripts
- name: Verify Database connection
env:
PORT: ${{ job.services.mariadb.ports[3306] }}
run: |
while ! mysqladmin ping -h"${{env.DB_HOST}}" -P"${PORT}" --silent; do
sleep 1
done
- name: Copy environment file - name: Copy environment file
run: cp .env.example .env run: sed 's@DB_HOST=.*@DB_HOST=${{env.DB_HOST}}@g' .env.example > .env
- name: Generate app key - name: Generate app key
run: php artisan key:generate run: php artisan key:generate
- name: "Create the database"
run: php artisan firefly-iii:create-database
- name: "Upgrades the database to the latest version"
run: php artisan firefly-iii:upgrade-database
- name: "Integrity Database Report"
run: php artisan firefly-iii:report-integrity
- name: "Run tests with coverage" - name: "Run tests with coverage"
run: composer coverage run: composer coverage

View File

@@ -1,4 +1,4 @@
name: "Close stale issues" name: "Issues - close stale issues"
on: on:
schedule: schedule:
- cron: "30 1 * * *" - cron: "30 1 * * *"
@@ -20,13 +20,13 @@ jobs:
stale-issue-message: > stale-issue-message: >
Hi there! This is an automatic reply. `Share and enjoy` Hi there! This is an automatic reply. `Share and enjoy`
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
Thank you for your contributions. Thank you for your contributions.
stale-pr-message: > stale-pr-message: >
Hi there! This is an automatic reply. `Share and enjoy` Hi there! This is an automatic reply. `Share and enjoy`
This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
Thank you for your contributions. Thank you for your contributions.
days-before-stale: 14 days-before-stale: 14

2
.gitignore vendored
View File

@@ -1,8 +1,6 @@
/node_modules /node_modules
/frontend/node_modules
/storage/*.key /storage/*.key
/vendor /vendor
/.vagrant
npm-debug.log npm-debug.log
yarn-error.log yarn-error.log
.env .env

View File

@@ -26,7 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest; use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;

View File

@@ -31,7 +31,6 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\ApiSupport; use FireflyIII\Support\Http\Api\ApiSupport;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -46,8 +45,7 @@ class AccountController extends Controller
{ {
use ApiSupport; use ApiSupport;
private CurrencyRepositoryInterface $currencyRepository; private AccountRepositoryInterface $repository;
private AccountRepositoryInterface $repository;
/** /**
* AccountController constructor. * AccountController constructor.
@@ -64,9 +62,6 @@ class AccountController extends Controller
$this->repository = app(AccountRepositoryInterface::class); $this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser($user); $this->repository->setUser($user);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->currencyRepository->setUser($user);
return $next($request); return $next($request);
} }
); );

View File

@@ -28,7 +28,6 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Insight\GenericRequest; use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Account\OperationsRepositoryInterface; use FireflyIII\Repositories\Account\OperationsRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\ApiSupport; use FireflyIII\Support\Http\Api\ApiSupport;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -43,7 +42,6 @@ class AccountController extends Controller
{ {
use ApiSupport; use ApiSupport;
private CurrencyRepositoryInterface $currencyRepository;
private OperationsRepositoryInterface $opsRepository; private OperationsRepositoryInterface $opsRepository;
private AccountRepositoryInterface $repository; private AccountRepositoryInterface $repository;
@@ -61,9 +59,6 @@ class AccountController extends Controller
$this->repository = app(AccountRepositoryInterface::class); $this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser($user); $this->repository->setUser($user);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->currencyRepository->setUser($user);
$this->opsRepository = app(OperationsRepositoryInterface::class); $this->opsRepository = app(OperationsRepositoryInterface::class);
$this->opsRepository->setUser($user); $this->opsRepository->setUser($user);

View File

@@ -28,7 +28,6 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Insight\GenericRequest; use FireflyIII\Api\V1\Requests\Insight\GenericRequest;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Account\OperationsRepositoryInterface; use FireflyIII\Repositories\Account\OperationsRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\ApiSupport; use FireflyIII\Support\Http\Api\ApiSupport;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -43,7 +42,6 @@ class AccountController extends Controller
{ {
use ApiSupport; use ApiSupport;
private CurrencyRepositoryInterface $currencyRepository;
private OperationsRepositoryInterface $opsRepository; private OperationsRepositoryInterface $opsRepository;
private AccountRepositoryInterface $repository; private AccountRepositoryInterface $repository;
@@ -61,9 +59,6 @@ class AccountController extends Controller
$this->repository = app(AccountRepositoryInterface::class); $this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser($user); $this->repository->setUser($user);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->currencyRepository->setUser($user);
$this->opsRepository = app(OperationsRepositoryInterface::class); $this->opsRepository = app(OperationsRepositoryInterface::class);
$this->opsRepository->setUser($user); $this->opsRepository->setUser($user);

View File

@@ -27,8 +27,8 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionCurrency;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Validator; use Validator;

View File

@@ -38,7 +38,6 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface; use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface; use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface; use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
@@ -65,26 +64,6 @@ class ListController extends Controller
use AccountFilter; use AccountFilter;
use TransactionFilter; use TransactionFilter;
private CurrencyRepositoryInterface $repository;
/**
* CurrencyRepository constructor.
*
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(CurrencyRepositoryInterface::class);
$this->repository->setUser(auth()->user());
return $next($request);
}
);
}
/** /**
* This endpoint is documented at: * This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/listAccountByCurrency * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/listAccountByCurrency

View File

@@ -27,10 +27,11 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionCurrency;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CurrencyTransformer; use FireflyIII\Transformers\CurrencyTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use JsonException; use JsonException;
@@ -81,13 +82,12 @@ class ShowController extends Controller
$pageSize = $this->parameters->get('limit'); $pageSize = $this->parameters->get('limit');
$collection = $this->repository->getAll(); $collection = $this->repository->getAll();
$count = $collection->count(); $count = $collection->count();
// slice them: // slice them:
$currencies = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $currencies = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($currencies, $count, $pageSize, $this->parameters->get('page')); $paginator = new LengthAwarePaginator($currencies, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.currencies.index') . $this->buildParams()); $paginator->setPath(route('api.v1.currencies.index') . $this->buildParams());
$manager = $this->getManager(); $manager = $this->getManager();
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency);
/** @var CurrencyTransformer $transformer */ /** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class); $transformer = app(CurrencyTransformer::class);
@@ -113,10 +113,15 @@ class ShowController extends Controller
*/ */
public function show(TransactionCurrency $currency): JsonResponse public function show(TransactionCurrency $currency): JsonResponse
{ {
/** @var User $user */
$user = auth()->user();
$manager = $this->getManager(); $manager = $this->getManager();
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user()); $defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$this->parameters->set('defaultCurrency', $defaultCurrency); $this->parameters->set('defaultCurrency', $defaultCurrency);
// update fields with user info.
$currency->refreshForUser($user);
/** @var CurrencyTransformer $transformer */ /** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class); $transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);
@@ -138,9 +143,13 @@ class ShowController extends Controller
*/ */
public function showDefault(): JsonResponse public function showDefault(): JsonResponse
{ {
/** @var User $user */
$user = auth()->user();
$manager = $this->getManager(); $manager = $this->getManager();
$currency = app('amount')->getDefaultCurrencyByUser(auth()->user()); $currency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$this->parameters->set('defaultCurrency', $currency);
// update fields with user info.
$currency->refreshForUser($user);
/** @var CurrencyTransformer $transformer */ /** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class); $transformer = app(CurrencyTransformer::class);

View File

@@ -27,10 +27,11 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionCurrency;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\TransactionCurrency\StoreRequest; use FireflyIII\Api\V1\Requests\Models\TransactionCurrency\StoreRequest;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CurrencyTransformer; use FireflyIII\Transformers\CurrencyTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use JsonException; use JsonException;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
@@ -79,12 +80,14 @@ class StoreController extends Controller
{ {
$currency = $this->repository->store($request->getAll()); $currency = $this->repository->store($request->getAll());
if (true === $request->boolean('default')) { if (true === $request->boolean('default')) {
app('preferences')->set('currencyPreference', $currency->code); $this->repository->makeDefault($currency);
app('preferences')->mark(); app('preferences')->mark();
} }
$manager = $this->getManager(); $manager = $this->getManager();
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency); /** @var User $user */
$user = auth()->user();
$currency->refreshForUser($user);
/** @var CurrencyTransformer $transformer */ /** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class); $transformer = app(CurrencyTransformer::class);

View File

@@ -28,10 +28,11 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\TransactionCurrency\UpdateRequest; use FireflyIII\Api\V1\Requests\Models\TransactionCurrency\UpdateRequest;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter; use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CurrencyTransformer; use FireflyIII\Transformers\CurrencyTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use JsonException; use JsonException;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
@@ -82,11 +83,16 @@ class UpdateController extends Controller
if ($this->repository->currencyInUse($currency)) { if ($this->repository->currencyInUse($currency)) {
return response()->json([], 409); return response()->json([], 409);
} }
// must not be the only one in use:
if (1 === $this->repository->get()->count()) {
return response()->json([], 409);
}
/** @var User $user */
$user = auth()->user();
$this->repository->disable($currency); $this->repository->disable($currency);
$manager = $this->getManager(); $manager = $this->getManager();
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user()); $currency->refreshForUser($user);
$this->parameters->set('defaultCurrency', $defaultCurrency);
/** @var CurrencyTransformer $transformer */ /** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class); $transformer = app(CurrencyTransformer::class);
@@ -110,14 +116,15 @@ class UpdateController extends Controller
*/ */
public function makeDefault(TransactionCurrency $currency): JsonResponse public function makeDefault(TransactionCurrency $currency): JsonResponse
{ {
/** @var User $user */
$user = auth()->user();
$this->repository->enable($currency); $this->repository->enable($currency);
$this->repository->makeDefault($currency);
app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark(); app('preferences')->mark();
$manager = $this->getManager(); $manager = $this->getManager();
$currency->refreshForUser($user);
$this->parameters->set('defaultCurrency', $currency);
/** @var CurrencyTransformer $transformer */ /** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class); $transformer = app(CurrencyTransformer::class);
@@ -144,9 +151,10 @@ class UpdateController extends Controller
{ {
$this->repository->enable($currency); $this->repository->enable($currency);
$manager = $this->getManager(); $manager = $this->getManager();
/** @var User $user */
$user = auth()->user();
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user()); $currency->refreshForUser($user);
$this->parameters->set('defaultCurrency', $defaultCurrency);
/** @var CurrencyTransformer $transformer */ /** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class); $transformer = app(CurrencyTransformer::class);
@@ -172,18 +180,23 @@ class UpdateController extends Controller
*/ */
public function update(UpdateRequest $request, TransactionCurrency $currency): JsonResponse public function update(UpdateRequest $request, TransactionCurrency $currency): JsonResponse
{ {
$data = $request->getAll(); $data = $request->getAll();
/** @var User $user */
$user = auth()->user();
// safety catch on currency disablement.
$set = $this->repository->get();
if (array_key_exists('enabled', $data) && false === $data['enabled'] && 1 === count($set) && $set->first()->id === $currency->id) {
return response()->json([], 409);
}
$currency = $this->repository->update($currency, $data); $currency = $this->repository->update($currency, $data);
if (true === $request->boolean('default')) { app('preferences')->mark();
app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark();
}
$manager = $this->getManager(); $manager = $this->getManager();
$currency->refreshForUser($user);
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency);
/** @var CurrencyTransformer $transformer */ /** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class); $transformer = app(CurrencyTransformer::class);

View File

@@ -39,7 +39,7 @@ use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface; use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;

View File

@@ -174,7 +174,7 @@ class StoreRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
Log::debug('Collect rules of TransactionStoreRequest'); Log::debug('Collect rules of TransactionStoreRequest');
$validProtocols = config('firefly.valid_url_protocols');
return [ return [
// basic fields for group: // basic fields for group:
'group_title' => 'between:1,1000|nullable', 'group_title' => 'between:1,1000|nullable',
@@ -233,7 +233,7 @@ class StoreRequest extends FormRequest
'transactions.*.external_id' => 'min:1|max:255|nullable', 'transactions.*.external_id' => 'min:1|max:255|nullable',
'transactions.*.recurrence_id' => 'min:1|max:255|nullable', 'transactions.*.recurrence_id' => 'min:1|max:255|nullable',
'transactions.*.bunq_payment_id' => 'min:1|max:255|nullable', 'transactions.*.bunq_payment_id' => 'min:1|max:255|nullable',
'transactions.*.external_url' => 'min:1|max:255|nullable|url', 'transactions.*.external_url' => sprintf('min:1|max:255|nullable|url:%s', $validProtocols),
// SEPA fields: // SEPA fields:
'transactions.*.sepa_cc' => 'min:1|max:255|nullable', 'transactions.*.sepa_cc' => 'min:1|max:255|nullable',

View File

@@ -321,7 +321,7 @@ class UpdateRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
Log::debug(sprintf('Now in %s', __METHOD__)); Log::debug(sprintf('Now in %s', __METHOD__));
$validProtocols = config('firefly.valid_url_protocols');
return [ return [
// basic fields for group: // basic fields for group:
'group_title' => 'between:1,1000|nullable', 'group_title' => 'between:1,1000|nullable',
@@ -375,7 +375,7 @@ class UpdateRequest extends FormRequest
'transactions.*.external_id' => 'min:1|max:255|nullable', 'transactions.*.external_id' => 'min:1|max:255|nullable',
'transactions.*.recurrence_id' => 'min:1|max:255|nullable', 'transactions.*.recurrence_id' => 'min:1|max:255|nullable',
'transactions.*.bunq_payment_id' => 'min:1|max:255|nullable', 'transactions.*.bunq_payment_id' => 'min:1|max:255|nullable',
'transactions.*.external_url' => 'min:1|max:255|nullable|url', 'transactions.*.external_url' => sprintf('min:1|max:255|nullable|url:%s', $validProtocols),
// SEPA fields: // SEPA fields:
'transactions.*.sepa_cc' => 'min:1|max:255|nullable', 'transactions.*.sepa_cc' => 'min:1|max:255|nullable',
@@ -417,15 +417,22 @@ class UpdateRequest extends FormRequest
// all transaction types must be equal: // all transaction types must be equal:
$this->validateTransactionTypesForUpdate($validator); $this->validateTransactionTypesForUpdate($validator);
// user wants to update a reconciled transaction.
// source, destination, amount + foreign_amount cannot be changed
// and must be omitted from the request.
$this->preventUpdateReconciled($validator, $transactionGroup);
// validate source/destination is equal, depending on the transaction journal type. // validate source/destination is equal, depending on the transaction journal type.
$this->validateEqualAccountsForUpdate($validator, $transactionGroup); $this->validateEqualAccountsForUpdate($validator, $transactionGroup);
// a catch when users submit splits with no source or destination info at all. // see method:
$this->preventNoAccountInfo($validator, ); //$this->preventNoAccountInfo($validator, );
// validate that the currency fits the source and/or destination account. // validate that the currency fits the source and/or destination account.
// validate all account info // validate all account info
$this->validateAccountInformationUpdate($validator, $transactionGroup); $this->validateAccountInformationUpdate($validator, $transactionGroup);
} }
); );
} }

View File

@@ -57,7 +57,6 @@ class UpdateRequest extends FormRequest
]; ];
return $this->getAllData($fields); return $this->getAllData($fields);
// return $return;
} }
/** /**

View File

@@ -71,17 +71,17 @@ class CreateRequest extends FormRequest
*/ */
public function rules(): array public function rules(): array
{ {
$triggers = implode(',', array_keys(Webhook::getTriggersForValidation())); $triggers = implode(',', array_keys(Webhook::getTriggersForValidation()));
$responses = implode(',', array_keys(Webhook::getResponsesForValidation())); $responses = implode(',', array_keys(Webhook::getResponsesForValidation()));
$deliveries = implode(',', array_keys(Webhook::getDeliveriesForValidation())); $deliveries = implode(',', array_keys(Webhook::getDeliveriesForValidation()));
$validProtocols = config('firefly.valid_url_protocols');
return [ return [
'title' => 'required|between:1,512|uniqueObjectForUser:webhooks,title', 'title' => 'required|between:1,512|uniqueObjectForUser:webhooks,title',
'active' => [new IsBoolean()], 'active' => [new IsBoolean()],
'trigger' => sprintf('required|in:%s', $triggers), 'trigger' => sprintf('required|in:%s', $triggers),
'response' => sprintf('required|in:%s', $responses), 'response' => sprintf('required|in:%s', $responses),
'delivery' => sprintf('required|in:%s', $deliveries), 'delivery' => sprintf('required|in:%s', $deliveries),
'url' => ['required', 'url', 'uniqueWebhook'], 'url' => ['required', sprintf('url:%s', $validProtocols), 'uniqueWebhook'],
]; ];
} }
} }

View File

@@ -81,10 +81,10 @@ class UpdateRequest extends FormRequest
*/ */
public function rules(): array public function rules(): array
{ {
$triggers = implode(',', array_keys(Webhook::getTriggersForValidation())); $triggers = implode(',', array_keys(Webhook::getTriggersForValidation()));
$responses = implode(',', array_keys(Webhook::getResponsesForValidation())); $responses = implode(',', array_keys(Webhook::getResponsesForValidation()));
$deliveries = implode(',', array_keys(Webhook::getDeliveriesForValidation())); $deliveries = implode(',', array_keys(Webhook::getDeliveriesForValidation()));
$validProtocols = config('firefly.valid_url_protocols');
/** @var Webhook $webhook */ /** @var Webhook $webhook */
$webhook = $this->route()->parameter('webhook'); $webhook = $this->route()->parameter('webhook');
@@ -94,7 +94,7 @@ class UpdateRequest extends FormRequest
'trigger' => sprintf('in:%s', $triggers), 'trigger' => sprintf('in:%s', $triggers),
'response' => sprintf('in:%s', $responses), 'response' => sprintf('in:%s', $responses),
'delivery' => sprintf('in:%s', $deliveries), 'delivery' => sprintf('in:%s', $deliveries),
'url' => ['url', sprintf('uniqueExistingWebhook:%d', $webhook->id)], 'url' => [sprintf('url:%s', $validProtocols), sprintf('uniqueExistingWebhook:%d', $webhook->id)],
]; ];
} }
} }

View File

@@ -32,7 +32,6 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface; use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter; use FireflyIII\Support\Http\Api\AccountFilter;
use http\Env\Response;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
/** /**

View File

@@ -32,13 +32,12 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit; use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\UserGroups\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Budget\OperationsRepositoryInterface; use FireflyIII\Repositories\UserGroups\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Support\Http\Api\CleansChartData; use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\ExchangeRateConverter; use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait; use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;

View File

@@ -33,7 +33,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface; use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\CleansChartData; use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\ExchangeRateConverter; use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait; use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;

View File

@@ -31,6 +31,8 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
/** /**
* Show = show a single account.
* Index = show all accounts
* Class ShowController * Class ShowController
*/ */
class ShowController extends Controller class ShowController extends Controller

View File

@@ -0,0 +1,87 @@
<?php
/*
* ShowController.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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Model\Bill;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\UserGroups\Bill\BillRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Transformers\V2\BillTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
/**
* Class ShowController
*/
class IndexController extends Controller
{
use ValidatesUserGroupTrait;
private BillRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(BillRepositoryInterface::class);
// new way of user group validation
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
}
return $next($request);
}
);
}
/**
* @param Request $request
*
* TODO see autocomplete/accountcontroller for list.
*
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
$this->repository->correctOrder();
$bills = $this->repository->getBills();
$pageSize = $this->parameters->get('limit');
$count = $bills->count();
$bills = $bills->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page'));
$transformer = new BillTransformer();
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList('subscriptions', $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@@ -30,7 +30,6 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Repositories\UserGroups\Bill\BillRepositoryInterface; use FireflyIII\Repositories\UserGroups\Bill\BillRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait; use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
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;
@@ -63,29 +62,6 @@ class ShowController extends Controller
); );
} }
/**
* @param Request $request
*
* TODO see autocomplete/accountcontroller for list.
*
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
$this->repository->correctOrder();
$bills = $this->repository->getBills();
$pageSize = $this->parameters->get('limit');
$count = $bills->count();
$bills = $bills->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page'));
$transformer = new BillTransformer();
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList('subscriptions', $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE);
}
/** /**
* TODO this endpoint is not documented * TODO this endpoint is not documented
*/ */

View File

@@ -26,7 +26,6 @@ namespace FireflyIII\Api\V2\Controllers\Model\Bill;
use FireflyIII\Api\V2\Controllers\Controller; use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Generic\DateRequest; use FireflyIII\Api\V2\Request\Generic\DateRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\UserGroups\Bill\BillRepositoryInterface; use FireflyIII\Repositories\UserGroups\Bill\BillRepositoryInterface;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait; use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Model\Budget; namespace FireflyIII\Api\V2\Controllers\Model\Budget;
use FireflyIII\Api\V2\Controllers\Controller; use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Transformers\V2\BudgetTransformer; use FireflyIII\Transformers\V2\BudgetTransformer;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -61,7 +62,7 @@ class ListController extends Controller
public function index(Request $request): JsonResponse public function index(Request $request): JsonResponse
{ {
echo 'this needs move to Administration'; echo 'this needs move to Administration';
exit; throw new FireflyException('Needs migration to IndexController');
$collection = $this->repository->getActiveBudgets(); $collection = $this->repository->getActiveBudgets();
$total = $collection->count(); $total = $collection->count();
$collection->slice($this->pageXSize * $this->parameters->get('page'), $this->pXageSize); $collection->slice($this->pageXSize * $this->parameters->get('page'), $this->pXageSize);

View File

@@ -65,6 +65,7 @@ class ShowController extends Controller
*/ */
public function budgeted(DateRequest $request, Budget $budget): JsonResponse public function budgeted(DateRequest $request, Budget $budget): JsonResponse
{ {
throw new FireflyException('Needs refactoring, uses deprecated method.');
$data = $request->getAll(); $data = $request->getAll();
$result = $this->repository->budgetedInPeriodForBudget($budget, $data['start'], $data['end']); $result = $this->repository->budgetedInPeriodForBudget($budget, $data['start'], $data['end']);
$converted = $this->cerSum(array_values($result)); $converted = $this->cerSum(array_values($result));
@@ -79,6 +80,7 @@ class ShowController extends Controller
*/ */
public function spent(DateRequest $request, Budget $budget): JsonResponse public function spent(DateRequest $request, Budget $budget): JsonResponse
{ {
throw new FireflyException('Needs refactoring, uses deprecated method.');
$data = $request->getAll(); $data = $request->getAll();
$result = $this->repository->spentInPeriodForBudget($budget, $data['start'], $data['end']); $result = $this->repository->spentInPeriodForBudget($budget, $data['start'], $data['end']);
$converted = $this->cerSum(array_values($result)); $converted = $this->cerSum(array_values($result));

View File

@@ -65,6 +65,7 @@ class SumController extends Controller
*/ */
public function budgeted(DateRequest $request): JsonResponse public function budgeted(DateRequest $request): JsonResponse
{ {
throw new FireflyException('Needs refactoring, uses deprecated method.');
$data = $request->getAll(); $data = $request->getAll();
$result = $this->repository->budgetedInPeriod($data['start'], $data['end']); $result = $this->repository->budgetedInPeriod($data['start'], $data['end']);
$converted = $this->cerSum(array_values($result)); $converted = $this->cerSum(array_values($result));
@@ -82,6 +83,7 @@ class SumController extends Controller
*/ */
public function spent(DateRequest $request): JsonResponse public function spent(DateRequest $request): JsonResponse
{ {
throw new FireflyException('Needs refactoring, uses deprecated method.');
$data = $request->getAll(); $data = $request->getAll();
$result = $this->repository->spentInPeriod($data['start'], $data['end']); $result = $this->repository->spentInPeriod($data['start'], $data['end']);
$converted = $this->cerSum(array_values($result)); $converted = $this->cerSum(array_values($result));

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V2\Controllers\Model\BudgetLimit;
use FireflyIII\Api\V2\Controllers\Controller; use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Generic\DateRequest; use FireflyIII\Api\V2\Request\Generic\DateRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget; use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Transformers\V2\BudgetLimitTransformer; use FireflyIII\Transformers\V2\BudgetLimitTransformer;
@@ -57,6 +58,7 @@ class ListController extends Controller
*/ */
public function index(DateRequest $request, Budget $budget): JsonResponse public function index(DateRequest $request, Budget $budget): JsonResponse
{ {
throw new FireflyException('Needs refactoring, move to IndexController.');
$pageSize = $this->parameters->get('limit'); $pageSize = $this->parameters->get('limit');
$dates = $request->getAll(); $dates = $request->getAll();
$collection = $this->repository->getBudgetLimits($budget, $dates['start'], $dates['end']); $collection = $this->repository->getBudgetLimits($budget, $dates['start'], $dates['end']);
@@ -67,7 +69,7 @@ class ListController extends Controller
$transformer = new BudgetLimitTransformer(); $transformer = new BudgetLimitTransformer();
return response() return response()
->api($this->jsonApiList('budget_limits', $paginator, $transformer)) ->api($this->jsonApiList('budget-limits', $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE); ->header('Content-Type', self::CONTENT_TYPE);
} }
} }

View File

@@ -0,0 +1,74 @@
<?php
/*
* IndexController.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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Model\Currency;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Transformers\V2\CurrencyTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
/**
* Class IndexController
*/
class IndexController extends Controller
{
private CurrencyRepositoryInterface $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(CurrencyRepositoryInterface::class);
return $next($request);
}
);
}
/**
* TODO This endpoint is not yet documented.
*
* Display a listing of the resource.
*
* @return JsonResponse
*/
public function index(): JsonResponse
{
$bills = $this->repository->getAll();
$pageSize = $this->parameters->get('limit');
$count = $bills->count();
$bills = $bills->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page'));
$transformer = new CurrencyTransformer();
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList('currencies', $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@@ -37,7 +37,7 @@ use Illuminate\Pagination\LengthAwarePaginator;
/** /**
* Class ShowController * Class ShowController
*/ */
class ShowController extends Controller class IndexController extends Controller
{ {
use ValidatesUserGroupTrait; use ValidatesUserGroupTrait;

View File

@@ -30,7 +30,6 @@ use FireflyIII\Api\V2\Request\Model\Transaction\StoreRequest;
use FireflyIII\Events\StoredTransactionGroup; use FireflyIII\Events\StoredTransactionGroup;
use FireflyIII\Exceptions\DuplicateTransactionException; use FireflyIII\Exceptions\DuplicateTransactionException;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use Illuminate\Validation\ValidationException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Rules\IsDuplicateTransaction; use FireflyIII\Rules\IsDuplicateTransaction;
@@ -38,6 +37,7 @@ use FireflyIII\Transformers\V2\TransactionGroupTransformer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
/** /**
* Class StoreController * Class StoreController

View File

@@ -41,7 +41,7 @@ use FireflyIII\Repositories\UserGroups\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Budget\AvailableBudgetRepositoryInterface; use FireflyIII\Repositories\UserGroups\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\UserGroups\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Budget\OperationsRepositoryInterface; use FireflyIII\Repositories\UserGroups\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Api\ExchangeRateConverter; use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait; use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\User; use FireflyIII\User;

View File

@@ -28,9 +28,7 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\User; use FireflyIII\User;
use FireflyIII\Validation\Administration\ValidatesAdministrationAccess;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
/** /**
* Class AutocompleteRequest * Class AutocompleteRequest

View File

@@ -57,6 +57,7 @@ class StoreRequest extends FormRequest
use GroupValidation; use GroupValidation;
use CurrencyValidation; use CurrencyValidation;
use AppendsLocationData; use AppendsLocationData;
protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS]; protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS];
/** /**

View File

@@ -37,6 +37,7 @@ class StoreRequest extends FormRequest
{ {
use ChecksLogin; use ChecksLogin;
use ConvertsDataTypes; use ConvertsDataTypes;
protected array $acceptedRoles = [UserRoleEnum::OWNER, UserRoleEnum::FULL]; protected array $acceptedRoles = [UserRoleEnum::OWNER, UserRoleEnum::FULL];
/** /**

View File

@@ -37,6 +37,7 @@ class UpdateMembershipRequest extends FormRequest
{ {
use ChecksLogin; use ChecksLogin;
use ConvertsDataTypes; use ConvertsDataTypes;
protected array $acceptedRoles = [UserRoleEnum::OWNER, UserRoleEnum::FULL]; protected array $acceptedRoles = [UserRoleEnum::OWNER, UserRoleEnum::FULL];
/** /**

View File

@@ -38,6 +38,7 @@ class UpdateRequest extends FormRequest
{ {
use ChecksLogin; use ChecksLogin;
use ConvertsDataTypes; use ConvertsDataTypes;
protected array $acceptedRoles = [UserRoleEnum::OWNER, UserRoleEnum::FULL]; protected array $acceptedRoles = [UserRoleEnum::OWNER, UserRoleEnum::FULL];
/** /**

View File

@@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Correction; namespace FireflyIII\Console\Commands\Correction;
use Artisan;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Schema; use Schema;

View File

@@ -162,6 +162,6 @@ class CorrectOpeningBalanceCurrencies extends Command
$repos = app(AccountRepositoryInterface::class); $repos = app(AccountRepositoryInterface::class);
$repos->setUser($account->user); $repos->setUser($account->user);
return $repos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUser($account->user); return $repos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUserGroup($account->userGroup);
} }
} }

View File

@@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Integrity; namespace FireflyIII\Console\Commands\Integrity;
use Artisan;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Schema; use Schema;

View File

@@ -83,6 +83,7 @@ class CreateDatabase extends Command
$pdo = new PDO($dsn, env('DB_USERNAME'), env('DB_PASSWORD'), $options); $pdo = new PDO($dsn, env('DB_USERNAME'), env('DB_PASSWORD'), $options);
} catch (PDOException $e) { } catch (PDOException $e) {
$this->friendlyError(sprintf('Error when connecting to DB: %s', $e->getMessage())); $this->friendlyError(sprintf('Error when connecting to DB: %s', $e->getMessage()));
return 1;
} }
// only continue when no error. // only continue when no error.

View File

@@ -34,7 +34,6 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface; use Psr\Container\NotFoundExceptionInterface;
@@ -129,20 +128,7 @@ class AccountCurrencies extends Command
$accounts = $this->accountRepos->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]); $accounts = $this->accountRepos->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
// get user's currency preference: // get user's currency preference:
$defaultCurrencyCode = app('preferences')->getForUser($user, 'currencyPreference', $systemCurrencyCode)->data; $defaultCurrency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
if (!is_string($defaultCurrencyCode)) {
$defaultCurrencyCode = $systemCurrencyCode;
}
/** @var TransactionCurrency|null $defaultCurrency */
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();
if (null === $defaultCurrency) {
Log::error(sprintf('Users currency pref "%s" does not exist!', $defaultCurrencyCode));
$this->friendlyError(sprintf('User has a preference for "%s", but this currency does not exist.', $defaultCurrencyCode));
return;
}
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {

View File

@@ -77,7 +77,7 @@ class BudgetLimitCurrency extends Command
if (null !== $budget) { if (null !== $budget) {
$user = $budget->user; $user = $budget->user;
if (null !== $user) { if (null !== $user) {
$currency = app('amount')->getDefaultCurrencyByUser($user); $currency = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$budgetLimit->transaction_currency_id = $currency->id; $budgetLimit->transaction_currency_id = $currency->id;
$budgetLimit->save(); $budgetLimit->save();
$this->friendlyInfo( $this->friendlyInfo(

View File

@@ -31,7 +31,6 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalCLIRepositoryInterface; use FireflyIII\Repositories\Journal\JournalCLIRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Console\Command; use Illuminate\Console\Command;
@@ -52,7 +51,6 @@ class OtherCurrenciesCorrections extends Command
private AccountRepositoryInterface $accountRepos; private AccountRepositoryInterface $accountRepos;
private JournalCLIRepositoryInterface $cliRepos; private JournalCLIRepositoryInterface $cliRepos;
private int $count; private int $count;
private CurrencyRepositoryInterface $currencyRepos;
private JournalRepositoryInterface $journalRepos; private JournalRepositoryInterface $journalRepos;
/** /**
@@ -93,7 +91,6 @@ class OtherCurrenciesCorrections extends Command
$this->count = 0; $this->count = 0;
$this->accountCurrencies = []; $this->accountCurrencies = [];
$this->accountRepos = app(AccountRepositoryInterface::class); $this->accountRepos = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->journalRepos = app(JournalRepositoryInterface::class); $this->journalRepos = app(JournalRepositoryInterface::class);
$this->cliRepos = app(JournalCLIRepositoryInterface::class); $this->cliRepos = app(JournalCLIRepositoryInterface::class);
} }
@@ -138,7 +135,6 @@ class OtherCurrenciesCorrections extends Command
{ {
$this->accountRepos->setUser($journal->user); $this->accountRepos->setUser($journal->user);
$this->journalRepos->setUser($journal->user); $this->journalRepos->setUser($journal->user);
$this->currencyRepos->setUser($journal->user);
$this->cliRepos->setUser($journal->user); $this->cliRepos->setUser($journal->user);
$leadTransaction = $this->getLeadTransaction($journal); $leadTransaction = $this->getLeadTransaction($journal);

View File

@@ -0,0 +1,175 @@
<?php
/*
* UpgradeCurrencyPreferences.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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands\Upgrade;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
/**
* Class UpgradeCurrencyPreferences
* TODO DONT FORGET TO ADD THIS TO THE DOCKER BUILD
*/
class UpgradeCurrencyPreferences extends Command
{
use ShowsFriendlyMessages;
public const CONFIG_NAME = '610_upgrade_currency_prefs';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Upgrade user currency preferences';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:upgrade-currency-preferences {--F|force : Force the execution of this command.}';
/**
* Execute the console command.
*
* @return int
*/
public function handle(): int
{
if ($this->isExecuted() && true !== $this->option('force')) {
$this->friendlyInfo('This command has already been executed.');
return 0;
}
$this->runUpgrade();
$this->friendlyPositive('Currency preferences migrated.');
//$this->markAsExecuted();
return 0;
}
/**
* @return bool
*/
private function isExecuted(): bool
{
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) {
return (bool)$configVar->data;
}
return false;
}
private function runUpgrade(): void
{
$groups = UserGroup::get();
/** @var UserGroup $group */
foreach ($groups as $group) {
$this->upgradeGroupPreferences($group);
}
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
$this->upgradeUserPreferences($user);
}
}
/**
* @param UserGroup $group
*
* @return void
*/
private function upgradeGroupPreferences(UserGroup $group)
{
$currencies = TransactionCurrency::get();
$enabled = new Collection();
/** @var TransactionCurrency $currency */
foreach ($currencies as $currency) {
if ($currency->enabled) {
$enabled->push($currency);
}
}
$group->currencies()->sync($enabled->pluck('id')->toArray());
}
/**
* @param User $user
*
* @return void
*/
private function upgradeUserPreferences(User $user): void
{
$currencies = TransactionCurrency::get();
$enabled = new Collection();
/** @var TransactionCurrency $currency */
foreach ($currencies as $currency) {
if ($currency->enabled) {
$enabled->push($currency);
}
}
$user->currencies()->sync($enabled->pluck('id')->toArray());
// set the default currency for the user and for the group:
$preference = $this->getPreference($user);
$defaultCurrency = TransactionCurrency::where('code', $preference)->first();
if (null === $currency) {
// get EUR
$defaultCurrency = TransactionCurrency::where('code', 'EUR')->first();
}
$user->currencies()->updateExistingPivot($defaultCurrency->id, ['user_default' => true]);
$user->userGroup->currencies()->updateExistingPivot($defaultCurrency->id, ['group_default' => true]);
}
/**
* @param User $user
*
* @return string
*/
private function getPreference(User $user): string
{
$preference = Preference::where('user_id', $user->id)->where('name', 'currencyPreference')->first(['id', 'user_id', 'name', 'data', 'updated_at', 'created_at']);
if (null !== $preference) {
return (string)$preference->data;
}
return 'EUR';
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}

View File

@@ -25,7 +25,6 @@ namespace FireflyIII\Console\Commands\Upgrade;
set_time_limit(0); set_time_limit(0);
use Artisan;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use Illuminate\Console\Command; use Illuminate\Console\Command;
@@ -72,6 +71,7 @@ class UpgradeDatabase extends Command
// also just in case, some integrity commands: // also just in case, some integrity commands:
'firefly-iii:create-group-memberships', 'firefly-iii:create-group-memberships',
'firefly-iii:upgrade-group-information', 'firefly-iii:upgrade-group-information',
'firefly-iii:upgrade-currency-preferences',
]; ];
$args = []; $args = [];
if ($this->option('force')) { if ($this->option('force')) {

View File

@@ -10,6 +10,7 @@ use Illuminate\Console\Command;
*/ */
class UpgradeSkeleton extends Command class UpgradeSkeleton extends Command
{ {
use ShowsFriendlyMessages;
public const CONFIG_NAME = '480_some_name'; public const CONFIG_NAME = '480_some_name';
/** /**
* The console command description. * The console command description.

View File

@@ -26,7 +26,6 @@ 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

@@ -55,7 +55,7 @@ class BillFactory
Log::debug(sprintf('Now in %s', __METHOD__), $data); Log::debug(sprintf('Now in %s', __METHOD__), $data);
$factory = app(TransactionCurrencyFactory::class); $factory = app(TransactionCurrencyFactory::class);
$currency = $factory->find((int)($data['currency_id'] ?? null), (string)($data['currency_code'] ?? null)) ?? $currency = $factory->find((int)($data['currency_id'] ?? null), (string)($data['currency_code'] ?? null)) ??
app('amount')->getDefaultCurrencyByUser($this->user); app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
try { try {
$skip = array_key_exists('skip', $data) ? $data['skip'] : 0; $skip = array_key_exists('skip', $data) ? $data['skip'] : 0;

View File

@@ -45,7 +45,6 @@ class TransactionCurrencyFactory
$data['symbol'] = e($data['symbol']); $data['symbol'] = e($data['symbol']);
$data['name'] = e($data['name']); $data['name'] = e($data['name']);
$data['decimal_places'] = (int)$data['decimal_places']; $data['decimal_places'] = (int)$data['decimal_places'];
$data['enabled'] = (bool)$data['enabled'];
// if the code already exists (deleted) // if the code already exists (deleted)
// force delete it and then create the transaction: // force delete it and then create the transaction:
$count = TransactionCurrency::withTrashed()->whereCode($data['code'])->count(); $count = TransactionCurrency::withTrashed()->whereCode($data['code'])->count();
@@ -63,7 +62,7 @@ class TransactionCurrencyFactory
'code' => $data['code'], 'code' => $data['code'],
'symbol' => $data['symbol'], 'symbol' => $data['symbol'],
'decimal_places' => $data['decimal_places'], 'decimal_places' => $data['decimal_places'],
'enabled' => $data['enabled'], 'enabled' => false,
] ]
); );
} catch (QueryException $e) { } catch (QueryException $e) {

View File

@@ -39,9 +39,9 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface; use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\JournalDestroyService; use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
use FireflyIII\Services\Internal\Support\JournalServiceTrait; use FireflyIII\Services\Internal\Support\JournalServiceTrait;
use FireflyIII\Support\NullArrayObject; use FireflyIII\Support\NullArrayObject;
@@ -479,7 +479,7 @@ class TransactionJournalFactory
$preference = $this->accountRepository->getAccountCurrency($account); $preference = $this->accountRepository->getAccountCurrency($account);
if (null === $preference && null === $currency) { if (null === $preference && null === $currency) {
// return user's default: // return user's default:
return app('amount')->getDefaultCurrencyByUser($this->user); return app('amount')->getDefaultCurrencyByUserGroup($this->user->userGroup);
} }
$result = ($preference ?? $currency) ?? app('amount')->getSystemCurrency(); $result = ($preference ?? $currency) ?? app('amount')->getSystemCurrency();
Log::debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name)); Log::debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name));

View File

@@ -34,29 +34,29 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
trait CollectorProperties trait CollectorProperties
{ {
public const TEST = 'Test'; public const TEST = 'Test';
private bool $expandGroupSearch; private bool $expandGroupSearch;
private array $fields; private array $fields;
private bool $hasAccountInfo; private bool $hasAccountInfo;
private bool $hasBillInformation; private bool $hasBillInformation;
private bool $hasBudgetInformation; private bool $hasBudgetInformation;
private bool $hasCatInformation; private bool $hasCatInformation;
private bool $hasJoinedAttTables; private bool $hasJoinedAttTables;
private bool $hasJoinedMetaTables; private bool $hasJoinedMetaTables;
private bool $hasJoinedTagTables; private bool $hasJoinedTagTables;
private bool $hasNotesInformation; private bool $hasNotesInformation;
private array $integerFields; private array $integerFields;
private ?int $limit; private ?int $limit;
private ?int $page; private ?int $page;
private array $postFilters; private array $postFilters;
private HasMany $query; private HasMany $query;
private array $stringFields; private array $stringFields;
/* /*
* This array is used to collect ALL tags the user may search for (using 'setTags'). * This array is used to collect ALL tags the user may search for (using 'setTags').
* This way the user can call 'setTags' multiple times and get a joined result. * This way the user can call 'setTags' multiple times and get a joined result.
* *
*/ */
private array $tags; private array $tags;
private int $total; private int $total;
private ?User $user; private ?User $user;
private ?UserGroup $userGroup; private ?UserGroup $userGroup;
} }

View File

@@ -29,8 +29,8 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\UserGroup; use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface; use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Http\Api\ExchangeRateConverter; use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\User; use FireflyIII\User;

View File

@@ -29,8 +29,8 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
/** /**

View File

@@ -32,7 +32,7 @@ use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Controllers\DateCalculation; use FireflyIII\Support\Http\Controllers\DateCalculation;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;

View File

@@ -34,7 +34,7 @@ use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Controllers\DateCalculation; use FireflyIII\Support\Http\Controllers\DateCalculation;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;

View File

@@ -33,7 +33,7 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Http\Controllers\AugumentData; use FireflyIII\Support\Http\Controllers\AugumentData;
use FireflyIII\Support\Http\Controllers\ChartGeneration; use FireflyIII\Support\Http\Controllers\ChartGeneration;

View File

@@ -1,435 +0,0 @@
<?php
/**
* CurrencyController.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\Http\Controllers;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Requests\CurrencyFormRequest;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
/**
* Class CurrencyController.
*/
class CurrencyController extends Controller
{
protected CurrencyRepositoryInterface $repository;
protected UserRepositoryInterface $userRepository;
/**
* CurrencyController constructor.
*
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string)trans('firefly.currencies'));
app('view')->share('mainTitleIcon', 'fa-usd');
$this->repository = app(CurrencyRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Create a currency.
*
* @param Request $request
*
* @return Factory|RedirectResponse|Redirector|View
*/
public function create(Request $request)
{
/** @var User $user */
$user = auth()->user();
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
return redirect(route('currencies.index'));
}
$subTitleIcon = 'fa-plus';
$subTitle = (string)trans('firefly.create_currency');
// put previous url in session if not redirect from store (not "create another").
if (true !== session('currencies.create.fromStore')) {
$this->rememberPreviousUrl('currencies.create.url');
}
$request->session()->forget('currencies.create.fromStore');
Log::channel('audit')->info('Create new currency.');
return view('currencies.create', compact('subTitleIcon', 'subTitle'));
}
/**
* Make currency the default currency.
*
* @param Request $request
*
* @return RedirectResponse|Redirector
* @throws FireflyException
*/
public function defaultCurrency(Request $request)
{
$currencyId = (int)$request->get('id');
if ($currencyId > 0) {
// valid currency?
$currency = $this->repository->find($currencyId);
if (null !== $currency) {
app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark();
Log::channel('audit')->info(sprintf('Make %s the default currency.', $currency->code));
$this->repository->enable($currency);
$request->session()->flash('success', (string)trans('firefly.new_default_currency', ['name' => $currency->name]));
return redirect(route('currencies.index'));
}
}
return redirect(route('currencies.index'));
}
/**
* Deletes a currency.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return Factory|RedirectResponse|Redirector|View
*/
public function delete(Request $request, TransactionCurrency $currency)
{
/** @var User $user */
$user = auth()->user();
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
Log::channel('audit')->info(sprintf('Tried to visit page to delete currency %s but is not site owner.', $currency->code));
return redirect(route('currencies.index'));
}
if ($this->repository->currencyInUse($currency)) {
$location = $this->repository->currencyInUseAt($currency);
$message = (string)trans(sprintf('firefly.cannot_disable_currency_%s', $location), ['name' => e($currency->name)]);
$request->session()->flash('error', $message);
Log::channel('audit')->info(sprintf('Tried to visit page to delete currency %s but currency is in use.', $currency->code));
return redirect(route('currencies.index'));
}
// put previous url in session
$this->rememberPreviousUrl('currencies.delete.url');
$subTitle = (string)trans('form.delete_currency', ['name' => $currency->name]);
Log::channel('audit')->info(sprintf('Visit page to delete currency %s.', $currency->code));
return view('currencies.delete', compact('currency', 'subTitle'));
}
/**
* Destroys a currency.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return RedirectResponse|Redirector
*/
public function destroy(Request $request, TransactionCurrency $currency)
{
/** @var User $user */
$user = auth()->user();
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
Log::channel('audit')->info(sprintf('Tried to delete currency %s but is not site owner.', $currency->code));
return redirect(route('currencies.index'));
}
if ($this->repository->currencyInUse($currency)) {
$request->session()->flash('error', (string)trans('firefly.cannot_delete_currency', ['name' => e($currency->name)]));
Log::channel('audit')->info(sprintf('Tried to delete currency %s but is in use.', $currency->code));
return redirect(route('currencies.index'));
}
if ($this->repository->isFallbackCurrency($currency)) {
$request->session()->flash('error', (string)trans('firefly.cannot_delete_fallback_currency', ['name' => e($currency->name)]));
Log::channel('audit')->info(sprintf('Tried to delete currency %s but is FALLBACK.', $currency->code));
return redirect(route('currencies.index'));
}
Log::channel('audit')->info(sprintf('Deleted currency %s.', $currency->code));
$this->repository->destroy($currency);
$request->session()->flash('success', (string)trans('firefly.deleted_currency', ['name' => $currency->name]));
return redirect($this->getPreviousUrl('currencies.delete.url'));
}
/**
* @param Request $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function disableCurrency(Request $request): JsonResponse
{
$currencyId = (int)$request->get('id');
$currency = $this->repository->find($currencyId);
// valid currency?
if (null === $currency) {
return response()->json([]);
}
app('preferences')->mark();
// user must be "owner"
/** @var User $user */
$user = auth()->user();
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
Log::channel('audit')->info(sprintf('Tried to disable currency %s but is not site owner.', $currency->code));
return response()->json([]);
}
// currency cannot be in use.
if ($this->repository->currencyInUse($currency)) {
$location = $this->repository->currencyInUseAt($currency);
$message = (string)trans(sprintf('firefly.cannot_disable_currency_%s', $location), ['name' => e($currency->name)]);
$request->session()->flash('error', $message);
Log::channel('audit')->info(sprintf('Tried to disable currency %s but is in use.', $currency->code));
return response()->json([]);
}
// currency disabled!
$this->repository->disable($currency);
Log::channel('audit')->info(sprintf('Disabled currency %s.', $currency->code));
$this->repository->ensureMinimalEnabledCurrencies();
// extra warning
if ('EUR' === $currency->code) {
session()->flash('warning', (string)trans('firefly.disable_EUR_side_effects'));
}
session()->flash('success', (string)trans('firefly.currency_is_now_disabled', ['name' => $currency->name]));
return response()->json([]);
}
/**
* Edit a currency.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return Factory|RedirectResponse|Redirector|View
*/
public function edit(Request $request, TransactionCurrency $currency)
{
/** @var User $user */
$user = auth()->user();
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
Log::channel('audit')->info(sprintf('Tried to edit currency %s but is not owner.', $currency->code));
return redirect(route('currencies.index'));
}
$subTitleIcon = 'fa-pencil';
$subTitle = (string)trans('breadcrumbs.edit_currency', ['name' => $currency->name]);
$currency->symbol = htmlentities($currency->symbol);
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');
$preFilled = [
'enabled' => $hasOldInput ? (bool)$request->old('enabled') : $currency->enabled,
];
$request->session()->flash('preFilled', $preFilled);
Log::channel('audit')->info('Edit currency.', $currency->toArray());
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('currencies.edit.fromUpdate')) {
$this->rememberPreviousUrl('currencies.edit.url');
}
$request->session()->forget('currencies.edit.fromUpdate');
return view('currencies.edit', compact('currency', 'subTitle', 'subTitleIcon'));
}
/**
* @param Request $request
*
* @return JsonResponse
*/
public function enableCurrency(Request $request): JsonResponse
{
$currencyId = (int)$request->get('id');
if ($currencyId > 0) {
// valid currency?
$currency = $this->repository->find($currencyId);
if (null !== $currency) {
app('preferences')->mark();
$this->repository->enable($currency);
session()->flash('success', (string)trans('firefly.currency_is_now_enabled', ['name' => $currency->name]));
Log::channel('audit')->info(sprintf('Enabled currency %s.', $currency->code));
}
}
return response()->json([]);
}
/**
* Show overview of currencies.
*
* @param Request $request
*
* @return Factory|View
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function index(Request $request)
{
/** @var User $user */
$user = auth()->user();
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
$collection = $this->repository->getAll();
$total = $collection->count();
$collection = $collection->slice(($page - 1) * $pageSize, $pageSize);
$currencies = new LengthAwarePaginator($collection, $total, $pageSize, $page);
$currencies->setPath(route('currencies.index'));
$defaultCurrency = $this->repository->getCurrencyByPreference(app('preferences')->get('currencyPreference', config('firefly.default_currency', 'EUR')));
$isOwner = true;
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('info', (string)trans('firefly.ask_site_owner', ['owner' => config('firefly.site_owner')]));
$isOwner = false;
}
return view('currencies.index', compact('currencies', 'defaultCurrency', 'isOwner'));
}
/**
* Store new currency.
*
* @param CurrencyFormRequest $request
*
* @return $this|RedirectResponse|Redirector
*/
public function store(CurrencyFormRequest $request)
{
/** @var User $user */
$user = auth()->user();
$data = $request->getCurrencyData();
if (!$this->userRepository->hasRole($user, 'owner')) {
Log::error('User ' . auth()->user()->id . ' is not admin, but tried to store a currency.');
Log::channel('audit')->info('Tried to create (POST) currency without admin rights.', $data);
return redirect($this->getPreviousUrl('currencies.create.url'));
}
$data['enabled'] = true;
try {
$currency = $this->repository->store($data);
} catch (FireflyException $e) {
Log::error($e->getMessage());
Log::channel('audit')->info('Could not store (POST) currency without admin rights.', $data);
$request->session()->flash('error', (string)trans('firefly.could_not_store_currency'));
$currency = null;
}
$redirect = redirect($this->getPreviousUrl('currencies.create.url'));
if (null !== $currency) {
$request->session()->flash('success', (string)trans('firefly.created_currency', ['name' => $currency->name]));
Log::channel('audit')->info('Created (POST) currency.', $data);
if (1 === (int)$request->get('create_another')) {
$request->session()->put('currencies.create.fromStore', true);
$redirect = redirect(route('currencies.create'))->withInput();
}
}
return $redirect;
}
/**
* Updates a currency.
*
* @param CurrencyFormRequest $request
* @param TransactionCurrency $currency
*
* @return RedirectResponse|Redirector
*/
public function update(CurrencyFormRequest $request, TransactionCurrency $currency)
{
/** @var User $user */
$user = auth()->user();
$data = $request->getCurrencyData();
if (false === $data['enabled'] && $this->repository->currencyInUse($currency)) {
$data['enabled'] = true;
}
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
Log::channel('audit')->info('Tried to update (POST) currency without admin rights.', $data);
return redirect(route('currencies.index'));
}
$currency = $this->repository->update($currency, $data);
Log::channel('audit')->info('Updated (POST) currency.', $data);
$request->session()->flash('success', (string)trans('firefly.updated_currency', ['name' => $currency->name]));
app('preferences')->mark();
if (1 === (int)$request->get('return_to_edit')) {
$request->session()->put('currencies.edit.fromUpdate', true);
return redirect(route('currencies.edit', [$currency->id]));
}
return redirect($this->getPreviousUrl('currencies.edit.url'));
}
}

View File

@@ -118,9 +118,6 @@ class HomeController extends Controller
*/ */
public function index(AccountRepositoryInterface $repository): mixed public function index(AccountRepositoryInterface $repository): mixed
{ {
if ('v3' === config('firefly.layout')) {
return view('pwa');
}
$types = config('firefly.accountTypesByIdentifier.asset'); $types = config('firefly.accountTypesByIdentifier.asset');
$count = $repository->count($types); $count = $repository->count($types);
Log::channel('audit')->info('User visits homepage.'); Log::channel('audit')->info('User visits homepage.');

View File

@@ -29,7 +29,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Controllers\GetConfigurationData; use FireflyIII\Support\Http\Controllers\GetConfigurationData;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
@@ -56,13 +56,11 @@ class JavascriptController extends Controller
*/ */
public function accounts(AccountRepositoryInterface $repository, CurrencyRepositoryInterface $currencyRepository): Response public function accounts(AccountRepositoryInterface $repository, CurrencyRepositoryInterface $currencyRepository): Response
{ {
$accounts = $repository->getAccountsByType( $accounts = $repository->getAccountsByType(
[AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD] [AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD]
); );
$preference = app('preferences')->get('currencyPreference', config('firefly.default_currency', 'EUR')); $default = app('amount')->getDefaultCurrency();
$default = $currencyRepository->findByCodeNull((string)$preference->data); $data = ['accounts' => []];
$data = ['accounts' => []];
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {

View File

@@ -35,7 +35,7 @@ use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface; use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;

View File

@@ -27,7 +27,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Requests\NewUserFormRequest; use FireflyIII\Http\Requests\NewUserFormRequest;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Controllers\CreateStuff; use FireflyIII\Support\Http\Controllers\CreateStuff;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
@@ -41,8 +41,7 @@ class NewUserController extends Controller
{ {
use CreateStuff; use CreateStuff;
/** @var AccountRepositoryInterface The account repository */ private AccountRepositoryInterface $repository;
private $repository;
/** /**
* NewUserController constructor. * NewUserController constructor.
@@ -105,7 +104,7 @@ class NewUserController extends Controller
// if is null, set to EUR: // if is null, set to EUR:
if (null === $currency) { if (null === $currency) {
$currency = $currencyRepository->findByCodeNull('EUR'); $currency = $currencyRepository->findByCode('EUR');
} }
$currencyRepository->enable($currency); $currencyRepository->enable($currency);
@@ -114,7 +113,7 @@ class NewUserController extends Controller
$this->createCashWalletAccount($currency, $language); // create cash wallet account $this->createCashWalletAccount($currency, $language); // create cash wallet account
// store currency preference: // store currency preference:
app('preferences')->set('currencyPreference', $currency->code); $currencyRepository->makeDefault($currency);
// store frontpage preferences: // store frontpage preferences:
$accounts = $this->repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray(); $accounts = $this->repository->getAccountsByType([AccountType::ASSET])->pluck('id')->toArray();

View File

@@ -89,6 +89,10 @@ class CreateController extends Controller
session()->flash('success', trans('firefly.stored_journal', ['description' => $title])); session()->flash('success', trans('firefly.stored_journal', ['description' => $title]));
session()->flash('success_url', $link); session()->flash('success_url', $link);
if ('edit' === $request->get('redirect')) {
return response()->json(['redirect' => route('transactions.edit', [$newGroup->id])]);
}
return response()->json(['redirect' => route('transactions.show', [$newGroup->id])]); return response()->json(['redirect' => route('transactions.show', [$newGroup->id])]);
} }
} }

View File

@@ -25,8 +25,11 @@ namespace FireflyIII\Http\Controllers\Transaction;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Redirector; use Illuminate\Routing\Redirector;
use Illuminate\View\View; use Illuminate\View\View;
@@ -36,8 +39,10 @@ use Illuminate\View\View;
*/ */
class EditController extends Controller class EditController extends Controller
{ {
private JournalRepositoryInterface $repository;
/** /**
* EditController constructor. * IndexController constructor.
* *
*/ */
@@ -45,12 +50,14 @@ class EditController extends Controller
{ {
parent::__construct(); parent::__construct();
// some useful repositories: // translations:
$this->middleware( $this->middleware(
static function ($request, $next) { function ($request, $next) {
app('view')->share('title', (string)trans('firefly.transactions')); app('view')->share('title', (string)trans('firefly.transactions'));
app('view')->share('mainTitleIcon', 'fa-exchange'); app('view')->share('mainTitleIcon', 'fa-exchange');
$this->repository = app(JournalRepositoryInterface::class);
return $next($request); return $next($request);
} }
); );
@@ -98,4 +105,15 @@ class EditController extends Controller
) )
); );
} }
/**
* @param TransactionJournal $journal
*
* @return JsonResponse
*/
public function unreconcile(TransactionJournal $journal): JsonResponse
{
$this->repository->unreconcileById($journal->id);
return response()->json([], 204);
}
} }

View File

@@ -0,0 +1,143 @@
<?php
/*
* CreateController.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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\TransactionCurrency;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\CurrencyFormRequest;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
* Class CreateController
*/
class CreateController extends Controller
{
protected CurrencyRepositoryInterface $repository;
protected UserRepositoryInterface $userRepository;
/**
* CurrencyController constructor.
*
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string)trans('firefly.currencies'));
app('view')->share('mainTitleIcon', 'fa-usd');
$this->repository = app(CurrencyRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Create a currency.
*
* @param Request $request
*
* @return Factory|RedirectResponse|Redirector|View
*/
public function create(Request $request)
{
/** @var User $user */
$user = auth()->user();
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
return redirect(route('currencies.index'));
}
$subTitleIcon = 'fa-plus';
$subTitle = (string)trans('firefly.create_currency');
// put previous url in session if not redirect from store (not "create another").
if (true !== session('currencies.create.fromStore')) {
$this->rememberPreviousUrl('currencies.create.url');
}
$request->session()->forget('currencies.create.fromStore');
Log::channel('audit')->info('Create new currency.');
return view('currencies.create', compact('subTitleIcon', 'subTitle'));
}
/**
* Store new currency.
*
* @param CurrencyFormRequest $request
*
* @return $this|RedirectResponse|Redirector
*/
public function store(CurrencyFormRequest $request)
{
/** @var User $user */
$user = auth()->user();
$data = $request->getCurrencyData();
if (!$this->userRepository->hasRole($user, 'owner')) {
Log::error('User ' . auth()->user()->id . ' is not admin, but tried to store a currency.');
Log::channel('audit')->info('Tried to create (POST) currency without admin rights.', $data);
return redirect($this->getPreviousUrl('currencies.create.url'))->withInput();
}
$data['enabled'] = true;
try {
$currency = $this->repository->store($data);
} catch (FireflyException $e) {
Log::error($e->getMessage());
Log::channel('audit')->info('Could not store (POST) currency without admin rights.', $data);
$request->session()->flash('error', (string)trans('firefly.could_not_store_currency'));
$currency = null;
}
$redirect = redirect($this->getPreviousUrl('currencies.create.url'));
if (null !== $currency) {
$request->session()->flash('success', (string)trans('firefly.created_currency', ['name' => $currency->name]));
Log::channel('audit')->info('Created (POST) currency.', $data);
if (1 === (int)$request->get('create_another')) {
$request->session()->put('currencies.create.fromStore', true);
$redirect = redirect(route('currencies.create'))->withInput();
}
}
return $redirect;
}
}

View File

@@ -0,0 +1,147 @@
<?php
/*
* DeleteController.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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\TransactionCurrency;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
* Class DeleteController
*/
class DeleteController extends Controller
{
protected CurrencyRepositoryInterface $repository;
protected UserRepositoryInterface $userRepository;
/**
* CurrencyController constructor.
*
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string)trans('firefly.currencies'));
app('view')->share('mainTitleIcon', 'fa-usd');
$this->repository = app(CurrencyRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Deletes a currency.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return Factory|RedirectResponse|Redirector|View
*/
public function delete(Request $request, TransactionCurrency $currency)
{
/** @var User $user */
$user = auth()->user();
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
Log::channel('audit')->info(sprintf('Tried to visit page to delete currency %s but is not site owner.', $currency->code));
return redirect(route('currencies.index'));
}
if ($this->repository->currencyInUse($currency)) {
$location = $this->repository->currencyInUseAt($currency);
$message = (string)trans(sprintf('firefly.cannot_disable_currency_%s', $location), ['name' => e($currency->name)]);
$request->session()->flash('error', $message);
Log::channel('audit')->info(sprintf('Tried to visit page to delete currency %s but currency is in use.', $currency->code));
return redirect(route('currencies.index'));
}
// put previous url in session
$this->rememberPreviousUrl('currencies.delete.url');
$subTitle = (string)trans('form.delete_currency', ['name' => $currency->name]);
Log::channel('audit')->info(sprintf('Visit page to delete currency %s.', $currency->code));
return view('currencies.delete', compact('currency', 'subTitle'));
}
/**
* Destroys a currency.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return RedirectResponse|Redirector
*/
public function destroy(Request $request, TransactionCurrency $currency)
{
/** @var User $user */
$user = auth()->user();
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
Log::channel('audit')->info(sprintf('Tried to delete currency %s but is not site owner.', $currency->code));
return redirect(route('currencies.index'));
}
if ($this->repository->currencyInUse($currency)) {
$request->session()->flash('error', (string)trans('firefly.cannot_delete_currency', ['name' => e($currency->name)]));
Log::channel('audit')->info(sprintf('Tried to delete currency %s but is in use.', $currency->code));
return redirect(route('currencies.index'));
}
if ($this->repository->isFallbackCurrency($currency)) {
$request->session()->flash('error', (string)trans('firefly.cannot_delete_fallback_currency', ['name' => e($currency->name)]));
Log::channel('audit')->info(sprintf('Tried to delete currency %s but is FALLBACK.', $currency->code));
return redirect(route('currencies.index'));
}
Log::channel('audit')->info(sprintf('Deleted currency %s.', $currency->code));
$this->repository->destroy($currency);
$request->session()->flash('success', (string)trans('firefly.deleted_currency', ['name' => $currency->name]));
return redirect($this->getPreviousUrl('currencies.delete.url'));
}
}

View File

@@ -0,0 +1,151 @@
<?php
/*
* EditController.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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\TransactionCurrency;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\CurrencyFormRequest;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
class EditController extends Controller
{
protected CurrencyRepositoryInterface $repository;
protected UserRepositoryInterface $userRepository;
/**
* CurrencyController constructor.
*
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string)trans('firefly.currencies'));
app('view')->share('mainTitleIcon', 'fa-usd');
$this->repository = app(CurrencyRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Edit a currency.
*
* @param Request $request
* @param TransactionCurrency $currency
*
* @return Factory|RedirectResponse|Redirector|View
*/
public function edit(Request $request, TransactionCurrency $currency)
{
/** @var User $user */
$user = auth()->user();
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
Log::channel('audit')->info(sprintf('Tried to edit currency %s but is not owner.', $currency->code));
return redirect(route('currencies.index'));
}
$subTitleIcon = 'fa-pencil';
$subTitle = (string)trans('breadcrumbs.edit_currency', ['name' => $currency->name]);
$currency->symbol = htmlentities($currency->symbol);
// is currently enabled (for this user?)
$userCurrencies = $this->repository->get()->pluck('id')->toArray();
$enabled = in_array($currency->id, $userCurrencies, true);
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');
$preFilled = [
'enabled' => $hasOldInput ? (bool)$request->old('enabled') : $enabled,
];
$request->session()->flash('preFilled', $preFilled);
Log::channel('audit')->info('Edit currency.', $currency->toArray());
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('currencies.edit.fromUpdate')) {
$this->rememberPreviousUrl('currencies.edit.url');
}
$request->session()->forget('currencies.edit.fromUpdate');
return view('currencies.edit', compact('currency', 'subTitle', 'subTitleIcon'));
}
/**
* Updates a currency.
*
* @param CurrencyFormRequest $request
* @param TransactionCurrency $currency
*
* @return RedirectResponse|Redirector
*/
public function update(CurrencyFormRequest $request, TransactionCurrency $currency)
{
/** @var User $user */
$user = auth()->user();
$data = $request->getCurrencyData();
if (false === $data['enabled'] && $this->repository->currencyInUse($currency)) {
$data['enabled'] = true;
}
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))]));
Log::channel('audit')->info('Tried to update (POST) currency without admin rights.', $data);
return redirect(route('currencies.index'));
}
$currency = $this->repository->update($currency, $data);
Log::channel('audit')->info('Updated (POST) currency.', $data);
$request->session()->flash('success', (string)trans('firefly.updated_currency', ['name' => $currency->name]));
app('preferences')->mark();
if (1 === (int)$request->get('return_to_edit')) {
$request->session()->put('currencies.edit.fromUpdate', true);
return redirect(route('currencies.edit', [$currency->id]));
}
return redirect($this->getPreviousUrl('currencies.edit.url'));
}
}

View File

@@ -0,0 +1,105 @@
<?php
/*
* IndexController.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/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\TransactionCurrency;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class IndexController extends Controller
{
protected CurrencyRepositoryInterface $repository;
protected UserRepositoryInterface $userRepository;
/**
* CurrencyController constructor.
*
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string)trans('firefly.currencies'));
app('view')->share('mainTitleIcon', 'fa-usd');
$this->repository = app(CurrencyRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Show overview of currencies.
*
* @param Request $request
*
* @return Factory|View
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function index(Request $request)
{
/** @var User $user */
$user = auth()->user();
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
$collection = $this->repository->getAll();
$total = $collection->count();
$collection = $collection->slice(($page - 1) * $pageSize, $pageSize);
// order so default is on top:
$collection = $collection->sortBy(
function (TransactionCurrency $currency) {
$default = true === $currency->userDefault ? 0 : 1;
$enabled = true === $currency->userEnabled ? 0 : 1;
return sprintf('%s-%s-%s', $default, $enabled, $currency->code);
}
);
$currencies = new LengthAwarePaginator($collection, $total, $pageSize, $page);
$currencies->setPath(route('currencies.index'));
$isOwner = true;
if (!$this->userRepository->hasRole($user, 'owner')) {
$request->session()->flash('info', (string)trans('firefly.ask_site_owner', ['owner' => config('firefly.site_owner')]));
$isOwner = false;
}
return view('currencies.index', compact('currencies', 'isOwner'));
}
}

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Http\Middleware;
use Closure; use Closure;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\Webhook; use FireflyIII\Models\Webhook;
@@ -68,6 +69,10 @@ class InterestingMessage
Preferences::mark(); Preferences::mark();
$this->handleWebhookMessage($request); $this->handleWebhookMessage($request);
} }
if ($this->currencyMessage($request)) {
Preferences::mark();
$this->handleCurrencyMessage($request);
}
return $next($request); return $next($request);
} }
@@ -221,10 +226,10 @@ class InterestingMessage
private function webhookMessage(Request $request): bool private function webhookMessage(Request $request): bool
{ {
// get parameters from request. // get parameters from request.
$billId = $request->get('webhook_id'); $webhookId = $request->get('webhook_id');
$message = $request->get('message'); $message = $request->get('message');
return null !== $billId && null !== $message; return null !== $webhookId && null !== $message;
} }
/** /**
@@ -252,4 +257,51 @@ class InterestingMessage
session()->flash('success', (string)trans('firefly.stored_new_webhook', ['title' => $webhook->title])); session()->flash('success', (string)trans('firefly.stored_new_webhook', ['title' => $webhook->title]));
} }
} }
/**
* @param Request $request
*
* @return bool
*/
private function currencyMessage(Request $request): bool
{
// get parameters from request.
$code = $request->get('code');
$message = $request->get('message');
return null !== $code && null !== $message;
}
private function handleCurrencyMessage(Request $request): void
{
// params:
// get parameters from request.
$code = $request->get('code');
$message = $request->get('message');
/** @var TransactionCurrency $webhook */
$currency = TransactionCurrency::whereCode($code)->first();
if (null === $currency) {
return;
}
if ('enabled' === $message) {
session()->flash('success', (string)trans('firefly.currency_is_now_enabled', ['name' => $currency->name]));
}
if ('enable_failed' === $message) {
session()->flash('error', (string)trans('firefly.could_not_enable_currency', ['name' => $currency->name]));
}
if ('disabled' === $message) {
session()->flash('success', (string)trans('firefly.currency_is_now_disabled', ['name' => $currency->name]));
}
if ('disable_failed' === $message) {
session()->flash('error', (string)trans('firefly.could_not_disable_currency', ['name' => $currency->name]));
}
if ('default' === $message) {
session()->flash('success', (string)trans('firefly.new_default_currency', ['name' => $currency->name]));
}
if ('default_failed' === $message) {
session()->flash('error', (string)trans('firefly.default_currency_failed', ['name' => $currency->name]));
}
}
} }

View File

@@ -40,6 +40,7 @@ class AccountFormRequest extends FormRequest
use ConvertsDataTypes; use ConvertsDataTypes;
use AppendsLocationData; use AppendsLocationData;
use ChecksLogin; use ChecksLogin;
protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS]; protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS];
/** /**

View File

@@ -45,7 +45,7 @@ class MassEditJournalRequest extends FormRequest
// fixed // fixed
return [ return [
'description.*' => 'required|min:1|max:255', 'description.*' => 'required|min:1|max:1024',
'source_id.*' => 'numeric|belongsToUser:accounts,id', 'source_id.*' => 'numeric|belongsToUser:accounts,id',
'destination_id.*' => 'numeric|belongsToUser:accounts,id', 'destination_id.*' => 'numeric|belongsToUser:accounts,id',
'journals.*' => 'numeric|belongsToUser:transaction_journals,id', 'journals.*' => 'numeric|belongsToUser:transaction_journals,id',

View File

@@ -84,7 +84,7 @@ class DownloadExchangeRates implements ShouldQueue
public function handle(): void public function handle(): void
{ {
Log::debug('Now in handle()'); Log::debug('Now in handle()');
$currencies = $this->repository->get(); $currencies = $this->repository->getCompleteSet();
/** @var TransactionCurrency $currency */ /** @var TransactionCurrency $currency */
foreach ($currencies as $currency) { foreach ($currencies as $currency) {

View File

@@ -42,36 +42,36 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/** /**
* Class Account * Class Account
* *
* @property int $id * @property int $id
* @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Support\Carbon|null $deleted_at * @property \Illuminate\Support\Carbon|null $deleted_at
* @property int $user_id * @property int $user_id
* @property int $account_type_id * @property int $account_type_id
* @property string $name * @property string $name
* @property string|null $virtual_balance * @property string|null $virtual_balance
* @property string|null $iban * @property string|null $iban
* @property bool $active * @property bool $active
* @property bool $encrypted * @property bool $encrypted
* @property int $order * @property int $order
* @property-read Collection|AccountMeta[] $accountMeta * @property-read Collection|AccountMeta[] $accountMeta
* @property-read int|null $account_meta_count * @property-read int|null $account_meta_count
* @property AccountType $accountType * @property AccountType $accountType
* @property-read Collection|Attachment[] $attachments * @property-read Collection|Attachment[] $attachments
* @property-read int|null $attachments_count * @property-read int|null $attachments_count
* @property-read string $account_number * @property-read string $account_number
* @property-read string $edit_name * @property-read string $edit_name
* @property-read Collection|Location[] $locations * @property-read Collection|Location[] $locations
* @property-read int|null $locations_count * @property-read int|null $locations_count
* @property-read Collection|Note[] $notes * @property-read Collection|Note[] $notes
* @property-read int|null $notes_count * @property-read int|null $notes_count
* @property-read Collection|ObjectGroup[] $objectGroups * @property-read Collection|ObjectGroup[] $objectGroups
* @property-read int|null $object_groups_count * @property-read int|null $object_groups_count
* @property-read Collection|PiggyBank[] $piggyBanks * @property-read Collection|PiggyBank[] $piggyBanks
* @property-read int|null $piggy_banks_count * @property-read int|null $piggy_banks_count
* @property-read Collection|Transaction[] $transactions * @property-read Collection|Transaction[] $transactions
* @property-read int|null $transactions_count * @property-read int|null $transactions_count
* @property-read User $user * @property-read User $user
* @method static EloquentBuilder|Account accountTypeIn($types) * @method static EloquentBuilder|Account accountTypeIn($types)
* @method static EloquentBuilder|Account newModelQuery() * @method static EloquentBuilder|Account newModelQuery()
* @method static EloquentBuilder|Account newQuery() * @method static EloquentBuilder|Account newQuery()
@@ -91,18 +91,19 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @method static EloquentBuilder|Account whereVirtualBalance($value) * @method static EloquentBuilder|Account whereVirtualBalance($value)
* @method static Builder|Account withTrashed() * @method static Builder|Account withTrashed()
* @method static Builder|Account withoutTrashed() * @method static Builder|Account withoutTrashed()
* @property Carbon $lastActivityDate * @property Carbon $lastActivityDate
* @property string $startBalance * @property string $startBalance
* @property string $endBalance * @property string $endBalance
* @property string $difference * @property string $difference
* @property string $interest * @property string $interest
* @property string $interestPeriod * @property string $interestPeriod
* @property string $accountTypeString * @property string $accountTypeString
* @property Location $location * @property Location $location
* @property string $liability_direction * @property string $liability_direction
* @property string $current_debt * @property string $current_debt
* @property int|null $user_group_id * @property int|null $user_group_id
* @method static EloquentBuilder|Account whereUserGroupId($value) * @method static EloquentBuilder|Account whereUserGroupId($value)
* @property-read UserGroup|null $userGroup
* @mixin Eloquent * @mixin Eloquent
*/ */
class Account extends Model class Account extends Model
@@ -283,6 +284,14 @@ class Account extends Model
return $this->hasMany(Transaction::class); return $this->hasMany(Transaction::class);
} }
/**
* @return BelongsTo
*/
public function userGroup(): BelongsTo
{
return $this->belongsTo(UserGroup::class);
}
/** /**
* Get the virtual balance * Get the virtual balance
* *

View File

@@ -61,7 +61,7 @@ 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 * @property int|null $user_group_id
* @method static Builder|ObjectGroup whereUserGroupId($value) * @method static Builder|ObjectGroup whereUserGroupId($value)
* @mixin Eloquent * @mixin Eloquent
*/ */

View File

@@ -125,6 +125,14 @@ class Rule extends Model
throw new NotFoundHttpException(); throw new NotFoundHttpException();
} }
/**
* @return BelongsTo
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/** /**
* @return HasMany * @return HasMany
*/ */
@@ -159,14 +167,6 @@ class Rule extends Model
$this->attributes['description'] = e($value); $this->attributes['description'] = e($value);
} }
/**
* @return BelongsTo
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/** /**
* @return BelongsTo * @return BelongsTo
*/ */

View File

@@ -24,8 +24,10 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Eloquent; use Eloquent;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\Builder;
@@ -35,21 +37,23 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/** /**
* FireflyIII\Models\TransactionCurrency * FireflyIII\Models\TransactionCurrency
* *
* @property int $id * @property int $id
* @property Carbon|null $created_at * @property Carbon|null $created_at
* @property Carbon|null $updated_at * @property Carbon|null $updated_at
* @property Carbon|null $deleted_at * @property Carbon|null $deleted_at
* @property bool $enabled * @property bool $enabled
* @property string $code * @property bool $userDefault
* @property string $name * @property bool $userEnabled
* @property string $symbol * @property string $code
* @property int $decimal_places * @property string $name
* @property-read Collection|BudgetLimit[] $budgetLimits * @property string $symbol
* @property-read int|null $budget_limits_count * @property int $decimal_places
* @property-read Collection|TransactionJournal[] $transactionJournals * @property-read Collection|BudgetLimit[] $budgetLimits
* @property-read int|null $transaction_journals_count * @property-read int|null $budget_limits_count
* @property-read Collection|Transaction[] $transactions * @property-read Collection|TransactionJournal[] $transactionJournals
* @property-read int|null $transactions_count * @property-read int|null $transaction_journals_count
* @property-read Collection|Transaction[] $transactions
* @property-read int|null $transactions_count
* @method static \Illuminate\Database\Eloquent\Builder|TransactionCurrency newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|TransactionCurrency newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|TransactionCurrency newQuery() * @method static \Illuminate\Database\Eloquent\Builder|TransactionCurrency newQuery()
* @method static Builder|TransactionCurrency onlyTrashed() * @method static Builder|TransactionCurrency onlyTrashed()
@@ -65,6 +69,10 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @method static \Illuminate\Database\Eloquent\Builder|TransactionCurrency whereUpdatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|TransactionCurrency whereUpdatedAt($value)
* @method static Builder|TransactionCurrency withTrashed() * @method static Builder|TransactionCurrency withTrashed()
* @method static Builder|TransactionCurrency withoutTrashed() * @method static Builder|TransactionCurrency withoutTrashed()
* @property-read Collection<int, UserGroup> $userGroups
* @property-read int|null $user_groups_count
* @property-read Collection<int, User> $users
* @property-read int|null $users_count
* @mixin Eloquent * @mixin Eloquent
*/ */
class TransactionCurrency extends Model class TransactionCurrency extends Model
@@ -101,6 +109,7 @@ class TransactionCurrency extends Model
$currencyId = (int)$value; $currencyId = (int)$value;
$currency = self::find($currencyId); $currency = self::find($currencyId);
if (null !== $currency) { if (null !== $currency) {
$currency->refreshForUser(auth()->user());
return $currency; return $currency;
} }
} }
@@ -115,6 +124,19 @@ class TransactionCurrency extends Model
return $this->hasMany(BudgetLimit::class); return $this->hasMany(BudgetLimit::class);
} }
/**
* @param User $user
*
* @return void
*/
public function refreshForUser(User $user)
{
$current = $user->userGroup->currencies()->where('transaction_currencies.id', $this->id)->first();
$default = app('amount')->getDefaultCurrencyByUserGroup($user->userGroup);
$this->userDefault = (int)$default->id === (int)$this->id;
$this->userEnabled = null !== $current;
}
/** /**
* @return HasMany * @return HasMany
*/ */
@@ -130,4 +152,24 @@ class TransactionCurrency extends Model
{ {
return $this->hasMany(Transaction::class); return $this->hasMany(Transaction::class);
} }
/**
* Link to user groups
*
* @return BelongsToMany
*/
public function userGroups(): BelongsToMany
{
return $this->belongsToMany(UserGroup::class)->withTimestamps()->withPivot('group_default');
}
/**
* Link to users
*
* @return BelongsToMany
*/
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class)->withTimestamps()->withPivot('user_default');
}
} }

View File

@@ -41,50 +41,50 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/** /**
* FireflyIII\Models\TransactionJournal * FireflyIII\Models\TransactionJournal
* *
* @property int $id * @property int $id
* @property Carbon|null $created_at * @property Carbon|null $created_at
* @property Carbon|null $updated_at * @property Carbon|null $updated_at
* @property Carbon|null $deleted_at * @property Carbon|null $deleted_at
* @property int $user_id * @property int $user_id
* @property int $transaction_type_id * @property int $transaction_type_id
* @property int|null $transaction_group_id * @property int|null $transaction_group_id
* @property int|null $bill_id * @property int|null $bill_id
* @property int|null $transaction_currency_id * @property int|null $transaction_currency_id
* @property string $description * @property string $description
* @property Carbon $date * @property Carbon $date
* @property Carbon|null $interest_date * @property Carbon|null $interest_date
* @property Carbon|null $book_date * @property Carbon|null $book_date
* @property Carbon|null $process_date * @property Carbon|null $process_date
* @property int $order * @property int $order
* @property int $tag_count * @property int $tag_count
* @property string $transaction_type_type * @property string $transaction_type_type
* @property bool $encrypted * @property bool $encrypted
* @property bool $completed * @property bool $completed
* @property-read Collection|Attachment[] $attachments * @property-read Collection|Attachment[] $attachments
* @property-read int|null $attachments_count * @property-read int|null $attachments_count
* @property-read Bill|null $bill * @property-read Bill|null $bill
* @property-read Collection|Budget[] $budgets * @property-read Collection|Budget[] $budgets
* @property-read int|null $budgets_count * @property-read int|null $budgets_count
* @property-read Collection|Category[] $categories * @property-read Collection|Category[] $categories
* @property-read int|null $categories_count * @property-read int|null $categories_count
* @property-read Collection|TransactionJournalLink[] $destJournalLinks * @property-read Collection|TransactionJournalLink[] $destJournalLinks
* @property-read int|null $dest_journal_links_count * @property-read int|null $dest_journal_links_count
* @property-read Collection|Note[] $notes * @property-read Collection|Note[] $notes
* @property-read int|null $notes_count * @property-read int|null $notes_count
* @property-read Collection|PiggyBankEvent[] $piggyBankEvents * @property-read Collection|PiggyBankEvent[] $piggyBankEvents
* @property-read int|null $piggy_bank_events_count * @property-read int|null $piggy_bank_events_count
* @property-read Collection|TransactionJournalLink[] $sourceJournalLinks * @property-read Collection|TransactionJournalLink[] $sourceJournalLinks
* @property-read int|null $source_journal_links_count * @property-read int|null $source_journal_links_count
* @property-read Collection|Tag[] $tags * @property-read Collection|Tag[] $tags
* @property-read int|null $tags_count * @property-read int|null $tags_count
* @property-read TransactionCurrency|null $transactionCurrency * @property-read TransactionCurrency|null $transactionCurrency
* @property-read TransactionGroup|null $transactionGroup * @property-read TransactionGroup|null $transactionGroup
* @property-read Collection|TransactionJournalMeta[] $transactionJournalMeta * @property-read Collection|TransactionJournalMeta[] $transactionJournalMeta
* @property-read int|null $transaction_journal_meta_count * @property-read int|null $transaction_journal_meta_count
* @property-read TransactionType $transactionType * @property-read TransactionType $transactionType
* @property-read Collection|Transaction[] $transactions * @property-read Collection|Transaction[] $transactions
* @property-read int|null $transactions_count * @property-read int|null $transactions_count
* @property-read User $user * @property-read User $user
* @method static EloquentBuilder|TransactionJournal after(Carbon $date) * @method static EloquentBuilder|TransactionJournal after(Carbon $date)
* @method static EloquentBuilder|TransactionJournal before(Carbon $date) * @method static EloquentBuilder|TransactionJournal before(Carbon $date)
* @method static EloquentBuilder|TransactionJournal newModelQuery() * @method static EloquentBuilder|TransactionJournal newModelQuery()
@@ -112,13 +112,13 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @method static EloquentBuilder|TransactionJournal whereUserId($value) * @method static EloquentBuilder|TransactionJournal whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|TransactionJournal withTrashed() * @method static \Illuminate\Database\Query\Builder|TransactionJournal withTrashed()
* @method static \Illuminate\Database\Query\Builder|TransactionJournal withoutTrashed() * @method static \Illuminate\Database\Query\Builder|TransactionJournal withoutTrashed()
* @property-read Collection|Location[] $locations * @property-read Collection|Location[] $locations
* @property-read int|null $locations_count * @property-read int|null $locations_count
* @property int $the_count * @property int $the_count
* @property int|null $user_group_id * @property int|null $user_group_id
* @method static EloquentBuilder|TransactionJournal whereUserGroupId($value) * @method static EloquentBuilder|TransactionJournal whereUserGroupId($value)
* @property-read Collection<int, \FireflyIII\Models\AuditLogEntry> $auditLogEntries * @property-read Collection<int, AuditLogEntry> $auditLogEntries
* @property-read int|null $audit_log_entries_count * @property-read int|null $audit_log_entries_count
* @mixin Eloquent * @mixin Eloquent
*/ */
class TransactionJournal extends Model class TransactionJournal extends Model

View File

@@ -30,6 +30,7 @@ use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
@@ -38,13 +39,13 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/** /**
* Class UserGroup * Class UserGroup
* *
* @property int $id * @property int $id
* @property Carbon|null $created_at * @property Carbon|null $created_at
* @property Carbon|null $updated_at * @property Carbon|null $updated_at
* @property string|null $deleted_at * @property string|null $deleted_at
* @property string $title * @property string $title
* @property-read Collection|GroupMembership[] $groupMemberships * @property-read Collection|GroupMembership[] $groupMemberships
* @property-read int|null $group_memberships_count * @property-read int|null $group_memberships_count
* @method static Builder|UserGroup newModelQuery() * @method static Builder|UserGroup newModelQuery()
* @method static Builder|UserGroup newQuery() * @method static Builder|UserGroup newQuery()
* @method static Builder|UserGroup query() * @method static Builder|UserGroup query()
@@ -53,38 +54,40 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @method static Builder|UserGroup whereId($value) * @method static Builder|UserGroup whereId($value)
* @method static Builder|UserGroup whereTitle($value) * @method static Builder|UserGroup whereTitle($value)
* @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, AvailableBudget> $availableBudgets * @property-read Collection<int, AvailableBudget> $availableBudgets
* @property-read int|null $available_budgets_count * @property-read int|null $available_budgets_count
* @property-read Collection<int, Bill> $bills * @property-read Collection<int, Bill> $bills
* @property-read int|null $bills_count * @property-read int|null $bills_count
* @property-read Collection<int, Budget> $budgets * @property-read Collection<int, Budget> $budgets
* @property-read int|null $budgets_count * @property-read int|null $budgets_count
* @property-read Collection<int, PiggyBank> $piggyBanks * @property-read Collection<int, PiggyBank> $piggyBanks
* @property-read int|null $piggy_banks_count * @property-read int|null $piggy_banks_count
* @property-read Collection<int, TransactionJournal> $transactionJournals * @property-read Collection<int, TransactionJournal> $transactionJournals
* @property-read int|null $transaction_journals_count * @property-read int|null $transaction_journals_count
* @property-read Collection<int, \FireflyIII\Models\Attachment> $attachments * @property-read Collection<int, Attachment> $attachments
* @property-read int|null $attachments_count * @property-read int|null $attachments_count
* @property-read Collection<int, \FireflyIII\Models\Category> $categories * @property-read Collection<int, Category> $categories
* @property-read int|null $categories_count * @property-read int|null $categories_count
* @property-read Collection<int, \FireflyIII\Models\CurrencyExchangeRate> $currencyExchangeRates * @property-read Collection<int, CurrencyExchangeRate> $currencyExchangeRates
* @property-read int|null $currency_exchange_rates_count * @property-read int|null $currency_exchange_rates_count
* @property-read Collection<int, \FireflyIII\Models\ObjectGroup> $objectGroups * @property-read Collection<int, ObjectGroup> $objectGroups
* @property-read int|null $object_groups_count * @property-read int|null $object_groups_count
* @property-read Collection<int, \FireflyIII\Models\Recurrence> $recurrences * @property-read Collection<int, Recurrence> $recurrences
* @property-read int|null $recurrences_count * @property-read int|null $recurrences_count
* @property-read Collection<int, \FireflyIII\Models\RuleGroup> $ruleGroups * @property-read Collection<int, RuleGroup> $ruleGroups
* @property-read int|null $rule_groups_count * @property-read int|null $rule_groups_count
* @property-read Collection<int, \FireflyIII\Models\Rule> $rules * @property-read Collection<int, Rule> $rules
* @property-read int|null $rules_count * @property-read int|null $rules_count
* @property-read Collection<int, \FireflyIII\Models\Tag> $tags * @property-read Collection<int, Tag> $tags
* @property-read int|null $tags_count * @property-read int|null $tags_count
* @property-read Collection<int, \FireflyIII\Models\TransactionGroup> $transactionGroups * @property-read Collection<int, TransactionGroup> $transactionGroups
* @property-read int|null $transaction_groups_count * @property-read int|null $transaction_groups_count
* @property-read Collection<int, \FireflyIII\Models\Webhook> $webhooks * @property-read Collection<int, Webhook> $webhooks
* @property-read int|null $webhooks_count * @property-read int|null $webhooks_count
* @property-read Collection<int, TransactionCurrency> $currencies
* @property-read int|null $currencies_count
* @mixin Eloquent * @mixin Eloquent
*/ */
class UserGroup extends Model class UserGroup extends Model
@@ -179,6 +182,16 @@ class UserGroup extends Model
return $this->hasMany(Category::class); return $this->hasMany(Category::class);
} }
/**
* Link to currencies
*
* @return BelongsToMany
*/
public function currencies(): BelongsToMany
{
return $this->belongsToMany(TransactionCurrency::class)->withTimestamps()->withPivot('group_default');
}
/** /**
* Link to exchange rates. * Link to exchange rates.
* *

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Admin; namespace FireflyIII\Notifications\Admin;
use FireflyIII\Support\Notifications\UrlValidator; use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Messages\SlackMessage;

View File

@@ -26,7 +26,6 @@ namespace FireflyIII\Notifications\Admin;
use FireflyIII\Models\InvitedUser; use FireflyIII\Models\InvitedUser;
use FireflyIII\Support\Notifications\UrlValidator; use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Messages\SlackMessage;

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Notifications\Admin; namespace FireflyIII\Notifications\Admin;
use FireflyIII\Support\Notifications\UrlValidator; use FireflyIII\Support\Notifications\UrlValidator;
use FireflyIII\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Messages\SlackMessage;

View File

@@ -29,9 +29,9 @@ 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;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification; use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Notifications\Messages\SlackMessage;
/** /**
* Class UserLogin * Class UserLogin

View File

@@ -28,7 +28,6 @@ use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Laravel\Passport\Passport; use Laravel\Passport\Passport;
use Laravel\Sanctum\Sanctum; use Laravel\Sanctum\Sanctum;
use URL;
/** /**
* Class AppServiceProvider * Class AppServiceProvider

View File

@@ -25,6 +25,8 @@ namespace FireflyIII\Providers;
use FireflyIII\Repositories\Currency\CurrencyRepository; use FireflyIII\Repositories\Currency\CurrencyRepository;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepository as GroupCurrencyRepository;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface as GroupCurrencyRepositoryInterface;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
@@ -55,6 +57,19 @@ class CurrencyServiceProvider extends ServiceProvider
$repository->setUser(auth()->user()); $repository->setUser(auth()->user());
} }
return $repository;
}
);
$this->app->bind(
GroupCurrencyRepositoryInterface::class,
function (Application $app) {
/** @var GroupCurrencyRepository $repository */
$repository = app(GroupCurrencyRepository::class);
// phpstan does not get the reference to auth
if ($app->auth->check()) { // @phpstan-ignore-line
$repository->setUser(auth()->user());
}
return $repository; return $repository;
} }
); );

View File

@@ -31,10 +31,10 @@ use FireflyIII\Repositories\Journal\JournalCLIRepository;
use FireflyIII\Repositories\Journal\JournalCLIRepositoryInterface; use FireflyIII\Repositories\Journal\JournalCLIRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepository; use FireflyIII\Repositories\Journal\JournalRepository;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Journal\JournalRepository as GroupJournalRepository;
use FireflyIII\Repositories\UserGroups\Journal\JournalRepositoryInterface as GroupJournalRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepository; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepository;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Journal\JournalRepository as GroupJournalRepository;
use FireflyIII\Repositories\UserGroups\Journal\JournalRepositoryInterface as GroupJournalRepositoryInterface;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;

View File

@@ -25,10 +25,8 @@ namespace FireflyIII\Providers;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepository; use FireflyIII\Repositories\PiggyBank\PiggyBankRepository;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Repositories\UserGroups\PiggyBank\PiggyBankRepository as AdminPiggyBankRepository; use FireflyIII\Repositories\UserGroups\PiggyBank\PiggyBankRepository as AdminPiggyBankRepository;
use FireflyIII\Repositories\UserGroups\PiggyBank\PiggyBankRepositoryInterface as AdminPiggyBankRepositoryInterface; use FireflyIII\Repositories\UserGroups\PiggyBank\PiggyBankRepositoryInterface as AdminPiggyBankRepositoryInterface;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;

View File

@@ -28,7 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;

View File

@@ -38,7 +38,7 @@ use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleTrigger; use FireflyIII\Models\RuleTrigger;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\BudgetDestroyService; use FireflyIII\Services\Internal\Destroy\BudgetDestroyService;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
@@ -429,12 +429,13 @@ class BudgetRepository implements BudgetRepositoryInterface
// set or update the currency. // set or update the currency.
if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) { if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) {
/** @var CurrencyRepositoryInterface $repos */
$repos = app(CurrencyRepositoryInterface::class); $repos = app(CurrencyRepositoryInterface::class);
$currencyId = (int)($data['currency_id'] ?? 0); $currencyId = (int)($data['currency_id'] ?? 0);
$currencyCode = (string)($data['currency_code'] ?? ''); $currencyCode = (string)($data['currency_code'] ?? '');
$currency = $repos->find($currencyId); $currency = $repos->find($currencyId);
if (null === $currency) { if (null === $currency) {
$currency = $repos->findByCodeNull($currencyCode); $currency = $repos->findByCode($currencyCode);
} }
if (null !== $currency) { if (null !== $currency) {
$autoBudget->transaction_currency_id = $currency->id; $autoBudget->transaction_currency_id = $currency->id;
@@ -837,6 +838,7 @@ class BudgetRepository implements BudgetRepositoryInterface
$type = AutoBudget::AUTO_BUDGET_ADJUSTED; $type = AutoBudget::AUTO_BUDGET_ADJUSTED;
} }
/** @var CurrencyRepositoryInterface $repos */
$repos = app(CurrencyRepositoryInterface::class); $repos = app(CurrencyRepositoryInterface::class);
$currency = null; $currency = null;
if (array_key_exists('currency_id', $data)) { if (array_key_exists('currency_id', $data)) {

View File

@@ -24,25 +24,12 @@ declare(strict_types=1);
namespace FireflyIII\Repositories\Currency; namespace FireflyIII\Repositories\Currency;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\TransactionCurrencyFactory;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\Bill;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\CurrencyExchangeRate; use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\Preference;
use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\CurrencyDestroyService;
use FireflyIII\Services\Internal\Update\CurrencyUpdateService;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use JsonException;
/** /**
* Class CurrencyRepository. * Class CurrencyRepository.
@@ -51,327 +38,6 @@ class CurrencyRepository implements CurrencyRepositoryInterface
{ {
private User $user; private User $user;
/**
* @param TransactionCurrency $currency
*
* @return bool
* @throws FireflyException
*/
public function currencyInUse(TransactionCurrency $currency): bool
{
$result = $this->currencyInUseAt($currency);
return null !== $result;
}
/**
* @param TransactionCurrency $currency
*
* @return string|null
* @throws FireflyException
*/
public function currencyInUseAt(TransactionCurrency $currency): ?string
{
Log::debug(sprintf('Now in currencyInUse() for #%d ("%s")', $currency->id, $currency->code));
$countJournals = $this->countJournals($currency);
if ($countJournals > 0) {
Log::info(sprintf('Count journals is %d, return true.', $countJournals));
return 'journals';
}
// is the only currency left
if (1 === $this->getAll()->count()) {
Log::info('Is the last currency in the system, return true. ');
return 'last_left';
}
// is being used in accounts:
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string)$currency->id))->count();
if ($meta > 0) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// is being used in bills:
$bills = Bill::where('transaction_currency_id', $currency->id)->count();
if ($bills > 0) {
Log::info(sprintf('Used in %d bills as currency, return true. ', $bills));
return 'bills';
}
// is being used in recurring transactions
$recurringAmount = RecurrenceTransaction::where('transaction_currency_id', $currency->id)->count();
$recurringForeign = RecurrenceTransaction::where('foreign_currency_id', $currency->id)->count();
if ($recurringAmount > 0 || $recurringForeign > 0) {
Log::info(sprintf('Used in %d recurring transactions as (foreign) currency id, return true. ', $recurringAmount + $recurringForeign));
return 'recurring';
}
// is being used in accounts (as integer)
$meta = AccountMeta::leftJoin('accounts', 'accounts.id', '=', 'account_meta.account_id')
->whereNull('accounts.deleted_at')
->where('account_meta.name', 'currency_id')->where('account_meta.data', json_encode((int)$currency->id))->count();
if ($meta > 0) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
return 'account_meta';
}
// is being used in available budgets
$availableBudgets = AvailableBudget::where('transaction_currency_id', $currency->id)->count();
if ($availableBudgets > 0) {
Log::info(sprintf('Used in %d available budgets as currency, return true. ', $availableBudgets));
return 'available_budgets';
}
// is being used in budget limits
$budgetLimit = BudgetLimit::where('transaction_currency_id', $currency->id)->count();
if ($budgetLimit > 0) {
Log::info(sprintf('Used in %d budget limits as currency, return true. ', $budgetLimit));
return 'budget_limits';
}
// is the default currency for the user or the system
$defaultCode = app('preferences')->getForUser($this->user, 'currencyPreference', config('firefly.default_currency', 'EUR'))->data;
if ($currency->code === $defaultCode) {
Log::info('Is the default currency of the user, return true.');
return 'current_default';
}
Log::debug('Currency is not used, return false.');
return null;
}
/**
* @param TransactionCurrency $currency
*
* @return int
*/
public function countJournals(TransactionCurrency $currency): int
{
$count = $currency->transactions()->whereNull('deleted_at')->count() + $currency->transactionJournals()->whereNull('deleted_at')->count();
// also count foreign:
return $count + Transaction::where('foreign_currency_id', $currency->id)->count();
}
/**
* @return Collection
*/
public function getAll(): Collection
{
return TransactionCurrency::orderBy('code', 'ASC')->get();
}
/**
* @return Collection
*/
public function get(): Collection
{
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
}
/**
* @param TransactionCurrency $currency
*
* @return bool
*/
public function destroy(TransactionCurrency $currency): bool
{
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
if ($repository->hasRole($this->user, 'owner')) {
/** @var CurrencyDestroyService $service */
$service = app(CurrencyDestroyService::class);
$service->destroy($currency);
}
return true;
}
/**
* Disables a currency
*
* @param TransactionCurrency $currency
*/
public function disable(TransactionCurrency $currency): void
{
$currency->enabled = false;
$currency->save();
}
/**
* @inheritDoc
*/
public function ensureMinimalEnabledCurrencies(): void
{
// if no currencies are enabled, enable the first one in the DB (usually the EUR)
if (0 === $this->get()->count()) {
/** @var TransactionCurrency $first */
$first = $this->getAll()->first();
if (null === $first) {
throw new FireflyException('No currencies found. You broke Firefly III');
}
Log::channel('audit')->info(sprintf('Auto-enabled currency %s.', $first->code));
$this->enable($first);
app('preferences')->set('currencyPreference', $first->code);
app('preferences')->mark();
}
}
/**
* @param TransactionCurrency $currency
* Enables a currency
*/
public function enable(TransactionCurrency $currency): void
{
$currency->enabled = true;
$currency->save();
}
/**
* Find by currency code, return NULL if unfound.
* Used in Import Currency!
*
* @param string $currencyCode
*
* @return TransactionCurrency|null
* @deprecated
*/
public function findByCodeNull(string $currencyCode): ?TransactionCurrency
{
return TransactionCurrency::where('code', $currencyCode)->first();
}
/**
* Find by currency name.
*
* @param string $currencyName
*
* @return TransactionCurrency|null
*/
public function findByName(string $currencyName): ?TransactionCurrency
{
return TransactionCurrency::whereName($currencyName)->first();
}
/**
* Find by currency name or return null.
* Used in Import Currency!
*
* @param string $currencyName
*
* @return TransactionCurrency|null
* @deprecated
*/
public function findByNameNull(string $currencyName): ?TransactionCurrency
{
return TransactionCurrency::whereName($currencyName)->first();
}
/**
* Find by currency symbol.
*
* @param string $currencySymbol
*
* @return TransactionCurrency|null
*/
public function findBySymbol(string $currencySymbol): ?TransactionCurrency
{
return TransactionCurrency::whereSymbol($currencySymbol)->first();
}
/**
* Find by currency symbol or return NULL
* Used in Import Currency!
*
* @param string $currencySymbol
*
* @return TransactionCurrency|null
* @deprecated
*/
public function findBySymbolNull(string $currencySymbol): ?TransactionCurrency
{
return TransactionCurrency::whereSymbol($currencySymbol)->first();
}
/**
* Find by object, ID or code. Returns user default or system default.
*
* @param int|null $currencyId
* @param string|null $currencyCode
*
* @return TransactionCurrency
* @throws FireflyException
* @throws JsonException
*/
public function findCurrency(?int $currencyId, ?string $currencyCode): TransactionCurrency
{
$result = $this->findCurrencyNull($currencyId, $currencyCode);
if (null === $result) {
Log::debug('Grabbing default currency for this user...');
$result = app('amount')->getDefaultCurrencyByUser($this->user);
}
if (null === $result) {
Log::debug('Grabbing EUR as fallback.');
$result = $this->findByCode('EUR');
}
Log::debug(sprintf('Final result: %s', $result->code));
if (false === $result->enabled) {
Log::debug(sprintf('Also enabled currency %s', $result->code));
$this->enable($result);
}
return $result;
}
/**
* Find by object, ID or code. Returns NULL if nothing found.
*
* @param int|null $currencyId
* @param string|null $currencyCode
*
* @return TransactionCurrency|null
*/
public function findCurrencyNull(?int $currencyId, ?string $currencyCode): ?TransactionCurrency
{
Log::debug('Now in findCurrencyNull()');
$result = $this->find((int)$currencyId);
if (null === $result) {
Log::debug(sprintf('Searching for currency with code %s...', $currencyCode));
$result = $this->findByCode((string)$currencyCode);
}
if (null !== $result && false === $result->enabled) {
Log::debug(sprintf('Also enabled currency %s', $result->code));
$this->enable($result);
}
return $result;
}
/**
* Find by ID, return NULL if not found.
*
* @param int $currencyId
*
* @return TransactionCurrency|null
*/
public function find(int $currencyId): ?TransactionCurrency
{
return TransactionCurrency::find($currencyId);
}
/** /**
* Find by currency code, return NULL if unfound. * Find by currency code, return NULL if unfound.
@@ -385,30 +51,18 @@ class CurrencyRepository implements CurrencyRepositoryInterface
return TransactionCurrency::where('code', $currencyCode)->first(); return TransactionCurrency::where('code', $currencyCode)->first();
} }
/** /**
* @param array $ids * Returns the complete set of transactions but needs
* no user object.
* *
* @return Collection * @return Collection
*/ */
public function getByIds(array $ids): Collection public function getCompleteSet(): Collection
{ {
return TransactionCurrency::orderBy('code', 'ASC')->whereIn('id', $ids)->get(); return TransactionCurrency::orderBy('code', 'ASC')->get();
} }
/**
* @param Preference $preference
*
* @return TransactionCurrency
*/
public function getCurrencyByPreference(Preference $preference): TransactionCurrency
{
$preferred = TransactionCurrency::where('code', $preference->data)->first();
if (null === $preferred) {
$preferred = TransactionCurrency::first();
}
return $preferred;
}
/** /**
* Get currency exchange rate. * Get currency exchange rate.
@@ -442,30 +96,6 @@ class CurrencyRepository implements CurrencyRepositoryInterface
return null; return null;
} }
/**
* @inheritDoc
*/
public function isFallbackCurrency(TransactionCurrency $currency): bool
{
return $currency->code === config('firefly.default_currency', 'EUR');
}
/**
* @param string $search
* @param int $limit
*
* @return Collection
*/
public function searchCurrency(string $search, int $limit): Collection
{
$query = TransactionCurrency::where('enabled', true);
if ('' !== $search) {
$query->where('name', 'LIKE', sprintf('%%%s%%', $search));
}
return $query->take($limit)->get();
}
/** /**
* TODO must be a factory * TODO must be a factory
* *
@@ -499,36 +129,4 @@ class CurrencyRepository implements CurrencyRepositoryInterface
} }
} }
/**
* @param array $data
*
* @return TransactionCurrency
* @throws FireflyException
*/
public function store(array $data): TransactionCurrency
{
/** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class);
$result = $factory->create($data);
if (null === $result) {
throw new FireflyException('400004: Could not store new currency.');
}
return $result;
}
/**
* @param TransactionCurrency $currency
* @param array $data
*
* @return TransactionCurrency
*/
public function update(TransactionCurrency $currency, array $data): TransactionCurrency
{
/** @var CurrencyUpdateService $service */
$service = app(CurrencyUpdateService::class);
return $service->update($currency, $data);
}
} }

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