Compare commits

..

58 Commits

Author SHA1 Message Date
github-actions
9d1a127200 Auto commit for release 'develop' on 2024-04-21 2024-04-21 17:23:16 +02:00
James Cole
3fdde2d1c8 Removed for now, needs dynamic configuration. 2024-04-21 17:18:35 +02:00
James Cole
cdc0b8dd2c Add index options 2024-04-21 17:09:15 +02:00
James Cole
1a1e06e6e8 Fix tests 2024-04-21 07:07:06 +02:00
James Cole
6d39b8468c Add two buttons and options for them 2024-04-21 06:57:57 +02:00
James Cole
bdee3947b2 Add debugbar settings 2024-04-21 06:56:14 +02:00
James Cole
2317037655 Clean up transactions, first attempt at navigation. 2024-04-21 06:26:17 +02:00
James Cole
dcea6b757b Better button response in category overview. 2024-04-20 17:08:30 +02:00
James Cole
bd7fe92818 Expand accounts page. 2024-04-20 16:18:41 +02:00
James Cole
850e47d8db Fix https://github.com/firefly-iii/firefly-iii/issues/8776 2024-04-20 08:15:17 +02:00
James Cole
96fe62400f Fix undefined index 2024-04-20 07:38:05 +02:00
James Cole
5d07fcdcb6 Add user roles. 2024-04-20 07:36:53 +02:00
James Cole
fd5d2d57a8 Fix https://github.com/firefly-iii/firefly-iii/issues/8804 2024-04-20 07:19:15 +02:00
James Cole
8e7d42201f Merge branch 'main' into develop 2024-04-20 07:18:51 +02:00
James Cole
f26bd3cb31 Fix https://github.com/firefly-iii/firefly-iii/issues/8613 2024-04-19 19:59:42 +02:00
James Cole
36915cdace Fix https://github.com/firefly-iii/firefly-iii/issues/8752 2024-04-19 19:58:32 +02:00
James Cole
8a5cecd2a0 Fix https://github.com/firefly-iii/firefly-iii/issues/8781 2024-04-19 19:58:09 +02:00
James Cole
78da1b22bb Update vite.config.js
Signed-off-by: James Cole <james@firefly-iii.org>
2024-04-19 08:28:31 +02:00
github-actions
6d970a9794 Auto commit for release 'develop' on 2024-04-18 2024-04-18 10:25:45 +02:00
Sander D
8bb7739f05 Update release.yml
Signed-off-by: Sander D <git@sanderdorigo.nl>
2024-04-18 10:20:47 +02:00
James Cole
7788bb4b33 Update composer.lock 2024-04-18 09:52:01 +02:00
James Cole
2ecb4bb3b7 Update composer.json 2024-04-18 09:51:45 +02:00
James Cole
4a783d3c3c Drop a specific preference from the return of Firefly III 2024-04-18 05:54:57 +02:00
github-actions
e16645ae87 Auto commit for release 'develop' on 2024-04-18 2024-04-18 05:09:58 +02:00
github-actions
9d3189be7e Auto commit for release 'develop' on 2024-04-15 2024-04-15 07:59:54 +02:00
James Cole
07fca78293 Merge pull request #8791 from firefly-iii/dependabot/npm_and_yarn/develop/i18next-23.11.2
Bump i18next from 23.11.1 to 23.11.2
2024-04-15 07:55:47 +02:00
James Cole
82080501c7 Merge pull request #8790 from firefly-iii/dependabot/npm_and_yarn/develop/sass-1.75.0
Bump sass from 1.74.1 to 1.75.0
2024-04-15 07:55:37 +02:00
James Cole
d93d6bfc66 Update phpcs.sh
Signed-off-by: James Cole <james@firefly-iii.org>
2024-04-15 07:54:52 +02:00
dependabot[bot]
a41326ef94 Bump i18next from 23.11.1 to 23.11.2
Bumps [i18next](https://github.com/i18next/i18next) from 23.11.1 to 23.11.2.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v23.11.1...v23.11.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-15 03:55:25 +00:00
dependabot[bot]
90b77845c3 Bump sass from 1.74.1 to 1.75.0
Bumps [sass](https://github.com/sass/dart-sass) from 1.74.1 to 1.75.0.
- [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.74.1...1.75.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-15 03:55:12 +00:00
James Cole
57af80d820 Merge pull request #8788 from firefly-iii/dependabot/composer/develop/larastan/larastan-2.9.4 2024-04-15 05:45:30 +02:00
James Cole
fc4d5a1dfd Merge pull request #8787 from firefly-iii/dependabot/composer/develop/phpunit/phpunit-10.5.18 2024-04-15 05:45:21 +02:00
dependabot[bot]
8ab9ab8d21 Bump larastan/larastan from 2.9.2 to 2.9.4
Bumps [larastan/larastan](https://github.com/larastan/larastan) from 2.9.2 to 2.9.4.
- [Release notes](https://github.com/larastan/larastan/releases)
- [Changelog](https://github.com/larastan/larastan/blob/2.x/RELEASE.md)
- [Commits](https://github.com/larastan/larastan/compare/v2.9.2...v2.9.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-15 03:01:51 +00:00
dependabot[bot]
75674b5793 Bump phpunit/phpunit from 10.5.17 to 10.5.18
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.5.17 to 10.5.18.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.5.18/ChangeLog-10.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/10.5.17...10.5.18)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-15 03:01:41 +00:00
James Cole
a7d6f26051 Sign release 2024-04-14 13:34:41 +02:00
James Cole
eb540ce148 New PR template 2024-04-14 13:32:56 +02:00
James Cole
a3077fe43b Merge branch 'main' into develop 2024-04-14 08:52:38 +02:00
James Cole
63bb84d375 Workflow runs on "main" 2024-04-14 08:52:27 +02:00
James Cole
e5f5aa628e Small changes in CI script and vite config 2024-04-14 08:51:59 +02:00
James Cole
c54f84dc8e Fix https://github.com/firefly-iii/firefly-iii/issues/8779 2024-04-13 05:50:26 +02:00
github-actions
c2e562623c Auto commit for release 'develop' on 2024-04-11 2024-04-11 05:10:20 +02:00
James Cole
c8d5e8a9dc Add roles 2024-04-10 19:45:08 +02:00
James Cole
963f017be3 Merge branch 'main' into develop 2024-04-08 07:46:41 +02:00
James Cole
0e0eeb736f Point to single source of truth for view name. 2024-04-08 07:45:58 +02:00
James Cole
e8d9b8fa49 Merge pull request #8768 from firefly-iii/dependabot/github_actions/github/command-1.1.1
Bump github/command from 1.1.0 to 1.1.1
2024-04-08 07:39:05 +02:00
James Cole
c166b9242e Merge pull request #8766 from firefly-iii/dependabot/npm_and_yarn/develop/date-fns-3.6.0
Bump date-fns from 2.30.0 to 3.6.0
2024-04-08 07:34:35 +02:00
dependabot[bot]
8ff8efced2 Bump date-fns from 2.30.0 to 3.6.0
Bumps [date-fns](https://github.com/date-fns/date-fns) from 2.30.0 to 3.6.0.
- [Release notes](https://github.com/date-fns/date-fns/releases)
- [Changelog](https://github.com/date-fns/date-fns/blob/main/CHANGELOG.md)
- [Commits](https://github.com/date-fns/date-fns/compare/v2.30.0...v3.6.0)

---
updated-dependencies:
- dependency-name: date-fns
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 04:54:48 +00:00
James Cole
0b4fb9a806 Revert to v8, also update other packages. 2024-04-08 06:53:51 +02:00
James Cole
ba9fef9410 Merge pull request #8765 from firefly-iii/dependabot/npm_and_yarn/develop/laravel-vite-plugin-1.0.2
Bump laravel-vite-plugin from 0.8.1 to 1.0.2
2024-04-08 06:29:54 +02:00
James Cole
f7d94d17cd Merge pull request #8764 from firefly-iii/dependabot/npm_and_yarn/develop/vue-i18n-9.11.0
Bump vue-i18n from 8.28.2 to 9.11.0
2024-04-08 06:23:42 +02:00
dependabot[bot]
1fea9c6817 Bump github/command from 1.1.0 to 1.1.1
Bumps [github/command](https://github.com/github/command) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/github/command/releases)
- [Commits](https://github.com/github/command/compare/v1.1.0...v1.1.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 04:03:50 +00:00
dependabot[bot]
a88c8bedbe Bump laravel-vite-plugin from 0.8.1 to 1.0.2
Bumps [laravel-vite-plugin](https://github.com/laravel/vite-plugin) from 0.8.1 to 1.0.2.
- [Release notes](https://github.com/laravel/vite-plugin/releases)
- [Changelog](https://github.com/laravel/vite-plugin/blob/1.x/CHANGELOG.md)
- [Upgrade guide](https://github.com/laravel/vite-plugin/blob/1.x/UPGRADE.md)
- [Commits](https://github.com/laravel/vite-plugin/compare/v0.8.1...v1.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 03:27:28 +00:00
dependabot[bot]
fbf3468053 Bump vue-i18n from 8.28.2 to 9.11.0
Bumps [vue-i18n](https://github.com/intlify/vue-i18n-next/tree/HEAD/packages/vue-i18n) from 8.28.2 to 9.11.0.
- [Release notes](https://github.com/intlify/vue-i18n-next/releases)
- [Changelog](https://github.com/intlify/vue-i18n-next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n-next/commits/v9.11.0/packages/vue-i18n)

---
updated-dependencies:
- dependency-name: vue-i18n
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 03:27:11 +00:00
github-actions
2a3ba9799e Auto commit for release 'develop' on 2024-04-08 2024-04-08 05:09:59 +02:00
James Cole
d121aad28f Check the directory, not the file. 2024-04-07 16:27:15 +02:00
github-actions
dc808fa807 Auto commit for release 'develop' on 2024-04-07 2024-04-07 16:22:39 +02:00
James Cole
a1be6ff62b Limit the number of error messages Firefly III will send. 2024-04-07 16:12:41 +02:00
James Cole
20dc5b0256 Fix layout errors. 2024-04-07 15:57:51 +02:00
128 changed files with 2184 additions and 1231 deletions

View File

@@ -226,16 +226,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.52.1",
"version": "v3.54.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "6e77207f0d851862ceeb6da63e6e22c01b1587bc"
"reference": "2aecbc8640d7906c38777b3dcab6f4ca79004d08"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/6e77207f0d851862ceeb6da63e6e22c01b1587bc",
"reference": "6e77207f0d851862ceeb6da63e6e22c01b1587bc",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2aecbc8640d7906c38777b3dcab6f4ca79004d08",
"reference": "2aecbc8640d7906c38777b3dcab6f4ca79004d08",
"shasum": ""
},
"require": {
@@ -259,6 +259,7 @@
},
"require-dev": {
"facile-it/paraunit": "^1.3 || ^2.0",
"infection/infection": "^0.27.11",
"justinrainbow/json-schema": "^5.2",
"keradus/cli-executor": "^2.1",
"mikey179/vfsstream": "^1.6.11",
@@ -306,7 +307,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.52.1"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.54.0"
},
"funding": [
{
@@ -314,7 +315,7 @@
"type": "github"
}
],
"time": "2024-03-19T21:02:43+00:00"
"time": "2024-04-17T08:12:13+00:00"
},
{
"name": "psr/container",

View File

@@ -20,23 +20,8 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# Install composer packages
#composer install --no-scripts --no-ansi
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# enable test .env file.
# cp .ci/.env.ci .env
OUTPUT_FORMAT=txt
EXTRA_PARAMS=""
if [[ $GITHUB_ACTIONS = "true" ]]
then
OUTPUT_FORMAT=txt
EXTRA_PARAMS=""
fi
# clean up php code
cd $SCRIPT_DIR/php-cs-fixer
composer update --quiet
@@ -44,8 +29,8 @@ rm -f .php-cs-fixer.cache
PHP_CS_FIXER_IGNORE_ENV=true
./vendor/bin/php-cs-fixer fix \
--config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php \
--format=$OUTPUT_FORMAT \
--allow-risky=yes $EXTRA_PARAMS
--format=txt \
--allow-risky=yes
EXIT_CODE=$?

View File

@@ -1,13 +1,13 @@
<!--
Thank you for submitting new code to Firefly III, or any of the related projects. Please read the following rules carefully.
- Do not submit solutions for problems that are not already reported in an issue
- Firefly III can't be your learning experience. If you're new to all of this, please go be new somewhere else
- Do not open PRs to "discuss" possible solutions or to "get feedback" on your code. I don't have time for that.
- Please do not submit solutions for problems that are not already reported in an issue.
- Unfortunately, Firefly III can't be your learning experience. If you're new to all of this, please open an issue first.
- Please do not open PRs to "discuss" possible solutions or to "get feedback" on your code. I simply don't have time for that.
- Pull requests for the MAIN branch will be closed.
- DO NOT include translated strings in your PR.
Perhaps open an issue first, before you open a PR?
If it feels necessary to open an issue first, please do so, before you open a PR.
See also: https://docs.firefly-iii.org/explanation/support/#contributing-code

View File

@@ -13,7 +13,7 @@ jobs:
close_duplicates:
runs-on: ubuntu-latest
steps:
- uses: github/command@v1.1.0
- uses: github/command@v1.1.1
id: command
with:
allowed_contexts: "issue"

View File

@@ -51,7 +51,7 @@ jobs:
CROWDIN_TOKEN: ${{ secrets.CROWDIN_TOKEN }}
- name: Cleanup translations
id: cleanup-transactions
uses: JC5/firefly-iii-dev@v38
uses: JC5/firefly-iii-dev@main
with:
action: 'ff3:crowdin-warning'
output: ''
@@ -60,7 +60,7 @@ jobs:
GH_TOKEN: ''
- name: Cleanup changelog
id: cleanup-changelog
uses: JC5/firefly-iii-dev@v38
uses: JC5/firefly-iii-dev@main
with:
action: 'ff3:changelog'
output: ''
@@ -69,7 +69,7 @@ jobs:
GH_TOKEN: ${{ secrets.CHANGELOG_TOKEN }}
- name: Extract changelog
id: extract-changelog
uses: JC5/firefly-iii-dev@v38
uses: JC5/firefly-iii-dev@main
with:
action: 'ff3:extract-changelog'
output: 'output'
@@ -78,7 +78,7 @@ jobs:
GH_TOKEN: ""
- name: Replace version
id: replace-version
uses: JC5/firefly-iii-dev@v38
uses: JC5/firefly-iii-dev@main
with:
action: 'ff3:version'
output: ''
@@ -88,7 +88,7 @@ jobs:
FF_III_VERSION: ${{ github.event_name == 'schedule' && 'develop' || github.event.inputs.version }}
- name: Generate JSON v1
id: json-v1
uses: JC5/firefly-iii-dev@v38
uses: JC5/firefly-iii-dev@main
with:
action: 'ff3:json-translations v1'
output: ''
@@ -97,7 +97,7 @@ jobs:
GH_TOKEN: ''
- name: Generate JSON v2
id: json-v2
uses: JC5/firefly-iii-dev@v38
uses: JC5/firefly-iii-dev@main
with:
action: 'ff3:json-translations v2'
output: ''
@@ -106,7 +106,7 @@ jobs:
GH_TOKEN: ''
- name: Code cleanup
id: code-cleanup
uses: JC5/firefly-iii-dev@v38
uses: JC5/firefly-iii-dev@main
with:
action: 'ff3:code'
output: ''
@@ -122,10 +122,14 @@ jobs:
- name: Run CI
run: |
rm -rf vendor composer.lock
composer validate --strict
composer update --no-dev --no-scripts --no-plugins -q
sudo chown -R runner:docker resources/lang
.ci/phpcs.sh
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.PASSPHRASE }}
- name: Release
run: |
# do some configuration
@@ -141,7 +145,6 @@ jobs:
tarName=FireflyIII-$version.tar.gz
# update composer (again)
composer validate --strict
composer update --no-dev --no-scripts --no-plugins
composer dump-autoload
@@ -191,6 +194,10 @@ jobs:
sha256sum -b $zipName > $zipName.sha256
sha256sum -b $tarName > $tarName.sha256
# add signatures:
gpg --armor --detach-sign $zipName
gpg --armor --detach-sign $tarName
# create a development (nightly) release:
if [[ "develop" == "$version" ]]; then
echo 'Develop release.'
@@ -198,7 +205,7 @@ jobs:
rm output.txt
echo "Bi-weekly development release of Firefly III with the latest fixes, translations and features. Docker users can find this release under the \`develop\` tag." >> output.txt
echo "" >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible." >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo "" >> output.txt
echo "* Please read the installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
@@ -221,6 +228,10 @@ jobs:
gh release upload $releaseName $zipName.sha256
gh release upload $releaseName $tarName.sha256
# add signatures to release
gh release upload $releaseName $zipName.asc
gh release upload $releaseName $tarName.asc
# get current HEAD and add as file to the release
HEAD=$(git rev-parse HEAD)
echo $HEAD > HEAD.txt
@@ -234,6 +245,7 @@ jobs:
echo '' >> output.txt
echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)."
echo "Create default release."
git tag -a $releaseName -m "Here be changelog"
@@ -248,6 +260,10 @@ jobs:
gh release upload $releaseName $zipName.sha256
gh release upload $releaseName $tarName.sha256
# add signatures to release
gh release upload $releaseName $zipName.asc
gh release upload $releaseName $tarName.asc
# get current HEAD and add as file to the release
HEAD=$(git rev-parse HEAD)
echo $HEAD > HEAD.txt

View File

@@ -73,7 +73,8 @@ class UpdateController extends Controller
$data = $request->getAll();
// Fixes 8750.
foreach ($data['transactions'] as $index => $info) {
$transactions = $data['transactions'] ?? [];
foreach ($transactions as $index => $info) {
unset($data['transactions'][$index]['type']);
}

View File

@@ -84,6 +84,10 @@ class PreferencesController extends Controller
{
$manager = $this->getManager();
if ('currencyPreference' === $preference->name) {
throw new FireflyException('Please use api/v1/currencies/default instead.');
}
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
$transformer->setParameters($this->parameters);
@@ -103,6 +107,11 @@ class PreferencesController extends Controller
{
$manager = $this->getManager();
$data = $request->getAll();
if ('currencyPreference' === $data['name']) {
throw new FireflyException('Please use api/v1/currencies/default instead.');
}
$pref = app('preferences')->set($data['name'], $data['data']);
/** @var PreferenceTransformer $transformer */
@@ -122,6 +131,10 @@ class PreferencesController extends Controller
*/
public function update(PreferenceUpdateRequest $request, Preference $preference): JsonResponse
{
if ('currencyPreference' === $preference->name) {
throw new FireflyException('Please use api/v1/currencies/default instead.');
}
$manager = $this->getManager();
$data = $request->getAll();
$pref = app('preferences')->set($preference->name, $data['data']);

View File

@@ -71,8 +71,9 @@ class StoreRequest extends FormRequest
if (is_array($triggers)) {
foreach ($triggers as $trigger) {
$return[] = [
'type' => $trigger['type'],
'value' => $trigger['value'],
'type' => $trigger['type'] ?? '',
'value' => $trigger['value'] ?? null,
'prohibited' => $this->convertBoolean((string)($trigger['prohibited'] ?? 'false')),
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')),
];

View File

@@ -81,10 +81,12 @@ class UpdateRequest extends FormRequest
if (is_array($triggers)) {
foreach ($triggers as $trigger) {
$active = array_key_exists('active', $trigger) ? $trigger['active'] : true;
$prohibited = array_key_exists('prohibited', $trigger) ? $trigger['prohibited'] : false;
$stopProcessing = array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false;
$return[] = [
'type' => $trigger['type'],
'value' => $trigger['value'],
'prohibited' => $prohibited,
'active' => $active,
'stop_processing' => $stopProcessing,
];

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V2\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Chart\BalanceChartRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionCurrency;
@@ -42,6 +43,7 @@ use Illuminate\Support\Collection;
class BalanceController extends Controller
{
use CleansChartData;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/**
* The code is practically a duplicate of ReportController::operations.

View File

@@ -122,6 +122,9 @@ class Controller extends BaseController
$obj = null;
}
}
if (null !== $date && 'end' === $field) {
$obj->endOfDay();
}
$bag->set($field, $obj);
}

View File

@@ -25,7 +25,6 @@ namespace FireflyIII\Api\V2\Controllers\Model\Account;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Model\Account\IndexRequest;
use FireflyIII\Api\V2\Request\Model\Transaction\InfiniteListRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Transformers\V2\AccountTransformer;
@@ -58,7 +57,7 @@ class IndexController extends Controller
}
/**
* TODO see autocomplete/accountcontroller for list.
* TODO see autocomplete/account controller for list.
*/
public function index(IndexRequest $request): JsonResponse
{
@@ -80,25 +79,4 @@ class IndexController extends Controller
->header('Content-Type', self::CONTENT_TYPE)
;
}
public function infiniteList(InfiniteListRequest $request): JsonResponse
{
$this->repository->resetAccountOrder();
// get accounts of the specified type, and return.
$types = $request->getAccountTypes();
// get from repository
$accounts = $this->repository->getAccountsInOrder($types, $request->getSortInstructions('accounts'), $request->getStartRow(), $request->getEndRow());
$total = $this->repository->countAccounts($types);
$count = $request->getEndRow() - $request->getStartRow();
$paginator = new LengthAwarePaginator($accounts, $total, $count, $this->parameters->get('page'));
$transformer = new AccountTransformer();
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Request\Chart;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
@@ -39,6 +40,7 @@ class BalanceChartRequest extends FormRequest
use ChecksLogin;
use ConvertsDataTypes;
use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/**
* Get all data from the request.

View File

@@ -44,14 +44,11 @@ class IndexRequest extends FormRequest
public function getAccountTypes(): array
{
$type = (string)$this->get('type', 'default');
$type = (string) $this->get('type', 'default');
return $this->mapAccountTypes($type);
}
/**
* Get all data from the request.
*/
public function getDate(): Carbon
{
return $this->getCarbonDate('date');
@@ -63,7 +60,9 @@ class IndexRequest extends FormRequest
public function rules(): array
{
return [
'date' => 'date|after:1900-01-01|before:2099-12-31',
'date' => 'date|after:1900-01-01|before:2099-12-31',
'start' => 'date|after:1900-01-01|before:2099-12-31|before:end|required_with:end',
'end' => 'date|after:1900-01-01|before:2099-12-31|after:start|required_with:start',
];
}
}

View File

@@ -106,7 +106,7 @@ class ShowController extends Controller
$periods = $this->getAccountPeriodOverview($account, $firstTransaction, $end);
// if layout = v2, overrule the page title.
if ('v1' !== config('firefly.layout')) {
if ('v1' !== config('view.layout')) {
$subTitle = (string)trans('firefly.all_journals_for_account', ['name' => $account->name]);
}

View File

@@ -31,6 +31,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
@@ -106,6 +107,8 @@ class ForgotPasswordController extends Controller
}
$host = request()->host();
if ($configuredHost !== $host) {
Log::error(sprintf('Host header is "%s", APP_URL is "%s".', $host, $configuredHost));
throw new FireflyException('The Host-header does not match the host in the APP_URL environment variable. Please make sure these match. See also: https://bit.ly/FF3-host-header');
}
}

View File

@@ -70,7 +70,7 @@ abstract class Controller extends BaseController
$logoutUrl = config('firefly.custom_logout_url');
// overrule v2 layout back to v1.
if ('true' === request()->get('force_default_layout') && 'v2' === config('firefly.layout')) {
if ('true' === request()->get('force_default_layout') && 'v2' === config('view.layout')) {
app('view')->getFinder()->setPaths([realpath(base_path('resources/views'))]); // @phpstan-ignore-line
}

View File

@@ -25,6 +25,7 @@ namespace FireflyIII\Http\Middleware;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Vite;
use Barryvdh\Debugbar\Facades\Debugbar;
/**
* Class SecureHeaders
@@ -43,6 +44,9 @@ class SecureHeaders
// generate and share nonce.
$nonce = base64_encode(random_bytes(16));
Vite::useCspNonce($nonce);
if (class_exists('Barryvdh\Debugbar\Facades\Debugbar')) {
Debugbar::getJavascriptRenderer()->setCspNonce($nonce);
}
app('view')->share('JS_NONCE', $nonce);
$response = $next($request);
@@ -55,14 +59,29 @@ class SecureHeaders
"base-uri 'self'",
"font-src 'self' data:",
sprintf("connect-src 'self' %s", $trackingScriptSrc),
sprintf("img-src 'self' 'nonce-%1s'", $nonce),
sprintf("img-src 'self' data: 'nonce-%1s' ", $nonce),
"manifest-src 'self'",
];
// overrule in development mode
if (true === env('IS_LOCAL_DEV')) {
$csp = [
"default-src 'none'",
"object-src 'none'",
sprintf("script-src 'unsafe-eval' 'strict-dynamic' 'nonce-%1s' https://firefly.sd.internal/_debugbar/assets", $nonce),
"style-src 'unsafe-inline' 'self' https://10.0.0.15:5173/",
"base-uri 'self'",
"font-src 'self' data: https://10.0.0.15:5173/",
sprintf("connect-src 'self' %s https://10.0.0.15:5173/ wss://10.0.0.15:5173/", $trackingScriptSrc),
sprintf("img-src 'self' data: 'nonce-%1s'", $nonce),
"manifest-src 'self'",
];
}
$route = $request->route();
$customUrl = '';
$authGuard = (string)config('firefly.authentication_guard');
$logoutUrl = (string)config('firefly.custom_logout_url');
$authGuard = (string) config('firefly.authentication_guard');
$logoutUrl = (string) config('firefly.custom_logout_url');
if ('remote_user_guard' === $authGuard && '' !== $logoutUrl) {
$customUrl = $logoutUrl;
}
@@ -110,8 +129,8 @@ class SecureHeaders
*/
private function getTrackingScriptSource(): string
{
if ('' !== (string)config('firefly.tracker_site_id') && '' !== (string)config('firefly.tracker_url')) {
return (string)config('firefly.tracker_url');
if ('' !== (string) config('firefly.tracker_site_id') && '' !== (string) config('firefly.tracker_url')) {
return (string) config('firefly.tracker_url');
}
return '';

View File

@@ -27,6 +27,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Message;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Symfony\Component\Mailer\Exception\TransportException;
/**
@@ -68,6 +69,14 @@ class MailError extends Job implements ShouldQueue
$args['user'] = $this->userData;
$args['ip'] = $this->ipAddress;
$args['token'] = config('firefly.ipinfo_token');
// limit number of error mails that can be sent.
if ($this->reachedLimit()) {
Log::info('MailError: reached limit, not sending email.');
return;
}
if ($this->attempts() < 3 && '' !== $email) {
try {
\Mail::send(
@@ -96,4 +105,62 @@ class MailError extends Job implements ShouldQueue
}
}
}
private function reachedLimit(): bool
{
Log::debug('reachedLimit()');
$types = [
'5m' => ['limit' => 5, 'reset' => 5 * 60],
'1h' => ['limit' => 15, 'reset' => 60 * 60],
'24h' => ['limit' => 15, 'reset' => 24 * 60 * 60],
];
$file = storage_path('framework/cache/error-count.json');
$directory = storage_path('framework/cache');
$limits = [];
if (!is_writable($directory)) {
Log::error(sprintf('MailError: cannot write to "%s", cannot rate limit errors!', $directory));
return false;
}
if (!file_exists($file)) {
Log::debug(sprintf('Wrote new file in "%s"', $file));
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
}
if (file_exists($file)) {
Log::debug(sprintf('Read file in "%s"', $file));
$limits = json_decode(file_get_contents($file), true);
}
// limit reached?
foreach ($types as $type => $info) {
Log::debug(sprintf('Now checking limit "%s"', $type), $info);
if (!isset($limits[$type])) {
Log::debug(sprintf('Limit "%s" reset to zero, did not exist yet.', $type));
$limits[$type] = [
'time' => time(),
'sent' => 0,
];
}
if (time() - $limits[$type]['time'] > $info['reset']) {
Log::debug(sprintf('Time past for this limit is %d seconds, exceeding %d seconds. Reset to zero.', time() - $limits[$type]['time'], $info['reset']));
$limits[$type] = [
'time' => time(),
'sent' => 0,
];
}
if ($limits[$type]['sent'] > $info['limit']) {
Log::warning(sprintf('Sent %d emails in %s, return true.', $limits[$type]['sent'], $type));
return true;
}
++$limits[$type]['sent'];
}
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
Log::debug('No limits reached, return FALSE.');
return false;
}
}

View File

@@ -295,4 +295,16 @@ class UserGroupRepository implements UserGroupRepositoryInterface
$this->user->user_group_id = $userGroup->id;
$this->user->save();
}
#[\Override]
public function getMembershipsFromGroupId(int $groupId): Collection
{
return $this->user->groupMemberships()->where('user_group_id', $groupId)->get();
}
#[\Override]
public function getById(int $id): ?UserGroup
{
return UserGroup::find($id);
}
}

View File

@@ -36,8 +36,12 @@ interface UserGroupRepositoryInterface
{
public function destroy(UserGroup $userGroup): void;
public function getMembershipsFromGroupId(int $groupId): Collection;
public function get(): Collection;
public function getById(int $id): ?UserGroup;
public function getAll(): Collection;
public function setUser(null|Authenticatable|User $user): void;

View File

@@ -27,11 +27,13 @@ namespace FireflyIII\Repositories\UserGroups\Account;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Services\Internal\Update\AccountUpdateService;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
/**
* Class AccountRepository
@@ -121,7 +123,7 @@ class AccountRepository implements AccountRepositoryInterface
if (!in_array($type, $list, true)) {
return null;
}
$currencyId = (int)$this->getMetaValue($account, 'currency_id');
$currencyId = (int) $this->getMetaValue($account, 'currency_id');
if ($currencyId > 0) {
return TransactionCurrency::find($currencyId);
}
@@ -143,7 +145,7 @@ class AccountRepository implements AccountRepositoryInterface
return null;
}
if (1 === $result->count()) {
return (string)$result->first()->data;
return (string) $result->first()->data;
}
return null;
@@ -228,7 +230,7 @@ class AccountRepository implements AccountRepositoryInterface
continue;
}
if ($index !== (int)$account->order) {
if ($index !== (int) $account->order) {
app('log')->debug(sprintf('Account #%d ("%s"): order should %d be but is %d.', $account->id, $account->name, $index, $account->order));
$account->order = $index;
$account->save();
@@ -305,4 +307,34 @@ class AccountRepository implements AccountRepositoryInterface
return $service->update($account, $data);
}
#[\Override]
public function getMetaValues(Collection $accounts, array $fields): Collection
{
$query = AccountMeta::whereIn('account_id', $accounts->pluck('id')->toArray());
if (count($fields) > 0) {
$query->whereIn('name', $fields);
}
return $query->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data']);
}
#[\Override]
public function getAccountTypes(Collection $accounts): Collection
{
return AccountType::leftJoin('accounts', 'accounts.account_type_id', '=', 'account_types.id')
->whereIn('accounts.id', $accounts->pluck('id')->toArray())
->get(['accounts.id', 'account_types.type'])
;
}
#[\Override]
public function getLastActivity(Collection $accounts): array
{
return Transaction::whereIn('account_id', $accounts->pluck('id')->toArray())
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
->groupBy('transactions.account_id')
->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) as date_max')])->toArray() // @phpstan-ignore-line
;
}
}

View File

@@ -37,6 +37,12 @@ interface AccountRepositoryInterface
{
public function countAccounts(array $types): int;
public function getAccountTypes(Collection $accounts): Collection;
public function getLastActivity(Collection $accounts): array;
public function getMetaValues(Collection $accounts, array $fields): Collection;
public function find(int $accountId): ?Account;
public function findByAccountNumber(string $number, array $types): ?Account;

View File

@@ -24,12 +24,13 @@ declare(strict_types=1);
namespace FireflyIII\Support\Http\Api;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\User;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/**
* Trait ValidatesUserGroupTrait
@@ -42,63 +43,64 @@ trait ValidatesUserGroupTrait
*/
protected function validateUserGroup(Request $request): UserGroup
{
app('log')->debug(sprintf('validateUserGroup: %s', static::class));
Log::debug(sprintf('validateUserGroup: %s', static::class));
if (!auth()->check()) {
app('log')->debug('validateUserGroup: user is not logged in, return NULL.');
Log::debug('validateUserGroup: user is not logged in, return NULL.');
throw new AuthenticationException();
}
/** @var User $user */
$user = auth()->user();
$groupId = 0;
$user = auth()->user();
$groupId = 0;
if (!$request->has('user_group_id')) {
$groupId = $user->user_group_id;
app('log')->debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $groupId));
Log::debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $groupId));
}
if ($request->has('user_group_id')) {
$groupId = (int)$request->get('user_group_id');
app('log')->debug(sprintf('validateUserGroup: user group submitted, search for memberships in group #%d.', $groupId));
$groupId = (int) $request->get('user_group_id');
Log::debug(sprintf('validateUserGroup: user group submitted, search for memberships in group #%d.', $groupId));
}
/** @var null|GroupMembership $membership */
$membership = $user->groupMemberships()->where('user_group_id', $groupId)->first();
/** @var UserGroupRepositoryInterface $repository */
$repository = app(UserGroupRepositoryInterface::class);
$repository->setUser($user);
$memberships = $repository->getMembershipsFromGroupId($groupId);
if (null === $membership) {
app('log')->debug(sprintf('validateUserGroup: user has no access to group #%d.', $groupId));
if (0 === $memberships->count()) {
Log::debug(sprintf('validateUserGroup: user has no access to group #%d.', $groupId));
throw new AuthorizationException((string)trans('validation.no_access_group'));
throw new AuthorizationException((string) trans('validation.no_access_group'));
}
// need to get the group from the membership:
/** @var null|UserGroup $group */
$group = $membership->userGroup;
$group = $repository->getById($groupId);
if (null === $group) {
app('log')->debug(sprintf('validateUserGroup: group #%d does not exist.', $groupId));
Log::debug(sprintf('validateUserGroup: group #%d does not exist.', $groupId));
throw new AuthorizationException((string)trans('validation.belongs_user_or_user_group'));
throw new AuthorizationException((string) trans('validation.belongs_user_or_user_group'));
}
app('log')->debug(sprintf('validateUserGroup: validate access of user to group #%d ("%s").', $groupId, $group->title));
$roles = property_exists($this, 'acceptedRoles') ? $this->acceptedRoles : [];
Log::debug(sprintf('validateUserGroup: validate access of user to group #%d ("%s").', $groupId, $group->title));
$roles = property_exists($this, 'acceptedRoles') ? $this->acceptedRoles : [];
if (0 === count($roles)) {
app('log')->debug('validateUserGroup: no roles defined, so no access.');
Log::debug('validateUserGroup: no roles defined, so no access.');
throw new AuthorizationException((string)trans('validation.no_accepted_roles_defined'));
throw new AuthorizationException((string) trans('validation.no_accepted_roles_defined'));
}
app('log')->debug(sprintf('validateUserGroup: have %d roles to check.', count($roles)), $roles);
Log::debug(sprintf('validateUserGroup: have %d roles to check.', count($roles)), $roles);
/** @var UserRoleEnum $role */
foreach ($roles as $role) {
if ($user->hasRoleInGroupOrOwner($group, $role)) {
app('log')->debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return the group.', $role->value, $groupId));
Log::debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return the group.', $role->value, $groupId));
return $group;
}
app('log')->debug(sprintf('validateUserGroup: User does NOT have role "%s" in group #%d, continue searching.', $role->value, $groupId));
Log::debug(sprintf('validateUserGroup: User does NOT have role "%s" in group #%d, continue searching.', $role->value, $groupId));
}
app('log')->debug('validateUserGroup: User does NOT have enough rights to access endpoint.');
Log::debug('validateUserGroup: User does NOT have enough rights to access endpoint.');
throw new AuthorizationException((string)trans('validation.belongs_user_or_user_group'));
throw new AuthorizationException((string) trans('validation.belongs_user_or_user_group'));
}
}

View File

@@ -464,14 +464,15 @@ class Navigation
$increment = 'addDay';
$format = $this->preferredCarbonFormat($start, $end);
$displayFormat = (string)trans('config.month_and_day_js', [], $locale);
$diff = $start->diffInMonths($end, true);
// increment by month (for year)
if ($start->diffInMonths($end, true) > 1) {
if ($diff >= 1.0001) {
$increment = 'addMonth';
$displayFormat = (string)trans('config.month_js');
}
// increment by year (for multi-year)
if ($start->diffInMonths($end, true) > 12) {
if ($diff >= 12.0001) {
$increment = 'addYear';
$displayFormat = (string)trans('config.year_js');
}
@@ -494,11 +495,15 @@ class Navigation
public function preferredCarbonFormat(Carbon $start, Carbon $end): string
{
$format = 'Y-m-d';
if ((int)$start->diffInMonths($end, true) > 1) {
$diff = $start->diffInMonths($end, true);
Log::debug(sprintf('preferredCarbonFormat(%s, %s) = %f', $start->format('Y-m-d'), $end->format('Y-m-d'), $diff));
if ($diff >= 1.001) {
Log::debug(sprintf('Return Y-m because %s', $diff));
$format = 'Y-m';
}
if ((int)$start->diffInMonths($end, true) > 12) {
if ($diff >= 12.001) {
Log::debug(sprintf('Return Y because %s', $diff));
$format = 'Y';
}

View File

@@ -44,6 +44,7 @@ class Preferences
}
return Preference::where('user_id', $user->id)
->where('name', '!=', 'currencyPreference')
->where(function (Builder $q) use ($user): void {
$q->whereNull('user_group_id');
$q->orWhere('user_group_id', $user->user_group_id);

View File

@@ -159,6 +159,10 @@ class OperatorQuerySearch implements SearchInterface
foreach ($query1->getNodes() as $searchNode) {
$this->handleSearchNode($searchNode);
}
// add missing information
$this->collector->withBillInformation();
$this->collector->setSearchWords($this->words);
$this->collector->excludeSearchWords($this->prohibitedWords);
}

View File

@@ -49,6 +49,7 @@ class Translation extends AbstractExtension
{
return [
$this->journalLinkTranslation(),
$this->laravelTranslation(),
];
}
@@ -68,4 +69,19 @@ class Translation extends AbstractExtension
['is_safe' => ['html']]
);
}
public function laravelTranslation(): TwigFunction
{
return new TwigFunction(
'__',
static function (string $key) {
$translation = trans($key);
if ($key === $translation) {
return $key;
}
return $translation;
}
);
}
}

View File

@@ -34,8 +34,7 @@ use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
*/
class RuleTransformer extends AbstractTransformer
{
/** @var RuleRepositoryInterface */
private $ruleRepository;
private RuleRepositoryInterface $ruleRepository;
/**
* CurrencyTransformer constructor.
@@ -109,8 +108,16 @@ class RuleTransformer extends AbstractTransformer
if ('user_action' === $ruleTrigger->trigger_type) {
continue;
}
$triggerType = (string) $ruleTrigger->trigger_type;
$triggerValue = (string)$ruleTrigger->trigger_value;
$needsContext = config(sprintf('search.operators.%s.needs_context', $ruleTrigger->trigger_type), true);
$prohibited = false;
if (str_starts_with($triggerType, '-')) {
$prohibited = true;
$triggerType = substr($triggerType, 1);
}
$needsContext = config(sprintf('search.operators.%s.needs_context', $triggerType), true);
if (false === $needsContext) {
$triggerValue = 'true';
}
@@ -119,8 +126,9 @@ class RuleTransformer extends AbstractTransformer
'id' => (string)$ruleTrigger->id,
'created_at' => $ruleTrigger->created_at->toAtomString(),
'updated_at' => $ruleTrigger->updated_at->toAtomString(),
'type' => $ruleTrigger->trigger_type,
'type' => $triggerType,
'value' => $triggerValue,
'prohibited' => $prohibited,
'order' => $ruleTrigger->order,
'active' => $ruleTrigger->active,
'stop_processing' => $ruleTrigger->stop_processing,

View File

@@ -27,13 +27,12 @@ namespace FireflyIII\Transformers\V2;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* Class AccountTransformer
@@ -42,118 +41,45 @@ class AccountTransformer extends AbstractTransformer
{
private array $accountMeta;
private array $accountTypes;
private array $balances;
private array $balanceDifferences;
private array $convertedBalances;
private array $currencies;
private TransactionCurrency $default;
private array $lastActivity;
/**
* @throws FireflyException
* This method collects meta-data for one or all accounts in the transformer's collection.
*/
public function collectMetaData(Collection $objects): Collection
{
// TODO separate methods
$this->currencies = [];
$this->accountMeta = [];
$this->accountTypes = [];
$this->lastActivity = [];
$this->balances = app('steam')->balancesByAccounts($objects, $this->getDate());
$this->convertedBalances = app('steam')->balancesByAccountsConverted($objects, $this->getDate());
$this->currencies = [];
$this->accountMeta = [];
$this->accountTypes = [];
$this->lastActivity = [];
$this->convertedBalances = [];
$this->balanceDifferences = [];
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$this->default = app('amount')->getDefaultCurrency();
// get balances of all accounts
$this->getMetaBalances($objects);
// get currencies:
$accountIds = $objects->pluck('id')->toArray();
// TODO move query to repository
$meta = AccountMeta::whereIn('account_id', $accountIds)
->whereIn('name', ['currency_id', 'account_role', 'account_number'])
->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data'])
;
$currencyIds = $meta->where('name', 'currency_id')->pluck('data')->toArray();
// get default currency:
$this->getDefaultCurrency();
// collect currency and other meta-data:
$this->collectAccountMetaData($objects);
$currencies = $repository->getByIds($currencyIds);
foreach ($currencies as $currency) {
$id = $currency->id;
$this->currencies[$id] = $currency;
}
foreach ($meta as $entry) {
$id = $entry->account_id;
$this->accountMeta[$id][$entry->name] = $entry->data;
}
// get account types:
// select accounts.id, account_types.type from account_types left join accounts on accounts.account_type_id = account_types.id;
// TODO move query to repository
$accountTypes = AccountType::leftJoin('accounts', 'accounts.account_type_id', '=', 'account_types.id')
->whereIn('accounts.id', $accountIds)
->get(['accounts.id', 'account_types.type'])
;
$this->collectAccountTypes($objects);
/** @var AccountType $row */
foreach ($accountTypes as $row) {
$this->accountTypes[$row->id] = (string)config(sprintf('firefly.shortNamesByFullName.%s', $row->type));
// get last activity:
$this->getLastActivity($objects);
// TODO add balance difference
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$this->getBalanceDifference($objects, $this->parameters->get('start'), $this->parameters->get('end'));
}
// get last activity
// TODO move query to repository
$array = Transaction::whereIn('account_id', $accountIds)
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
->groupBy('transactions.account_id')
->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) as date_max')])->toArray() // @phpstan-ignore-line
;
foreach ($array as $row) {
$this->lastActivity[(int)$row['account_id']] = Carbon::parse($row['date_max'], config('app.timezone'));
}
// TODO needs separate method.
/** @var null|array $sort */
$sort = $this->parameters->get('sort');
if (null !== $sort && count($sort) > 0) {
foreach ($sort as $column => $direction) {
// account_number + iban
if ('iban' === $column) {
$meta = $this->accountMeta;
$objects = $objects->sort(function (Account $left, Account $right) use ($meta, $direction) {
$leftIban = trim(sprintf('%s%s', $left->iban, $meta[$left->id]['account_number'] ?? ''));
$rightIban = trim(sprintf('%s%s', $right->iban, $meta[$right->id]['account_number'] ?? ''));
if ('asc' === $direction) {
return strcasecmp($leftIban, $rightIban);
}
return strcasecmp($rightIban, $leftIban);
});
}
if ('balance' === $column) {
$balances = $this->convertedBalances;
$objects = $objects->sort(function (Account $left, Account $right) use ($balances, $direction) {
$leftBalance = (float)($balances[$left->id]['native_balance'] ?? 0);
$rightBalance = (float)($balances[$right->id]['native_balance'] ?? 0);
if ('asc' === $direction) {
return $leftBalance <=> $rightBalance;
}
return $rightBalance <=> $leftBalance;
});
}
if ('last_activity' === $column) {
$dates = $this->lastActivity;
$objects = $objects->sort(function (Account $left, Account $right) use ($dates, $direction) {
$leftDate = $dates[$left->id] ?? Carbon::create(1900, 1, 1, 0, 0, 0);
$rightDate = $dates[$right->id] ?? Carbon::create(1900, 1, 1, 0, 0, 0);
if ('asc' === $direction) {
return $leftDate->gt($rightDate) ? 1 : -1;
}
return $rightDate->gt($leftDate) ? 1 : -1;
});
}
}
}
// $objects = $objects->sortByDesc('name');
return $objects;
return $this->sortAccounts($objects);
}
private function getDate(): Carbon
@@ -171,44 +97,56 @@ class AccountTransformer extends AbstractTransformer
*/
public function transform(Account $account): array
{
$id = $account->id;
$id = $account->id;
// various meta
$accountRole = $this->accountMeta[$id]['account_role'] ?? null;
$accountType = $this->accountTypes[$id];
$order = $account->order;
$accountRole = $this->accountMeta[$id]['account_role'] ?? null;
$accountType = $this->accountTypes[$id];
$order = $account->order;
// no currency? use default
$currency = $this->default;
if (array_key_exists($id, $this->accountMeta) && 0 !== (int)($this->accountMeta[$id]['currency_id'] ?? 0)) {
$currency = $this->currencies[(int)$this->accountMeta[$id]['currency_id']];
$currency = $this->default;
if (array_key_exists($id, $this->accountMeta) && 0 !== (int) ($this->accountMeta[$id]['currency_id'] ?? 0)) {
$currency = $this->currencies[(int) $this->accountMeta[$id]['currency_id']];
}
// amounts and calculation.
$balance = $this->balances[$id] ?? null;
$nativeBalance = $this->convertedBalances[$id]['native_balance'] ?? null;
$balance = $this->balances[$id]['balance'] ?? null;
$nativeBalance = $this->convertedBalances[$id]['native_balance'] ?? null;
// no order for some accounts:
if (!in_array(strtolower($accountType), ['liability', 'liabilities', 'asset'], true)) {
$order = null;
}
// balance difference
$diffStart = null;
$diffEnd = null;
$balanceDiff = null;
$nativeBalanceDiff = null;
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$diffStart = $this->parameters->get('start')->toAtomString();
$diffEnd = $this->parameters->get('end')->toAtomString();
$balanceDiff = $this->balanceDifferences[$id]['balance'] ?? null;
$nativeBalanceDiff = $this->balanceDifferences[$id]['native_balance'] ?? null;
}
return [
'id' => (string)$account->id,
'id' => (string) $account->id,
'created_at' => $account->created_at->toAtomString(),
'updated_at' => $account->updated_at->toAtomString(),
'active' => $account->active,
'order' => $order,
'name' => $account->name,
'iban' => '' === (string)$account->iban ? null : $account->iban,
'iban' => '' === (string) $account->iban ? null : $account->iban,
'account_number' => $this->accountMeta[$id]['account_number'] ?? null,
'type' => strtolower($accountType),
'account_role' => $accountRole,
'currency_id' => (string)$currency->id,
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'native_currency_id' => (string)$this->default->id,
'native_currency_id' => (string) $this->default->id,
'native_currency_code' => $this->default->code,
'native_currency_symbol' => $this->default->symbol,
'native_currency_decimal_places' => $this->default->decimal_places,
@@ -218,6 +156,12 @@ class AccountTransformer extends AbstractTransformer
'native_current_balance' => $nativeBalance,
'current_balance_date' => $this->getDate()->endOfDay()->toAtomString(),
// balance difference
'balance_difference' => $balanceDiff,
'native_balance_difference' => $nativeBalanceDiff,
'balance_difference_start' => $diffStart,
'balance_difference_end' => $diffEnd,
// more meta
'last_activity' => array_key_exists($id, $this->lastActivity) ? $this->lastActivity[$id]->toAtomString() : null,
@@ -246,4 +190,179 @@ class AccountTransformer extends AbstractTransformer
],
];
}
private function getMetaBalances(Collection $accounts): void
{
try {
$this->convertedBalances = app('steam')->balancesByAccountsConverted($accounts, $this->getDate());
} catch (FireflyException $e) {
Log::error($e->getMessage());
}
}
private function getDefaultCurrency(): void
{
$this->default = app('amount')->getDefaultCurrency();
}
private function collectAccountMetaData(Collection $accounts): void
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$metaFields = $accountRepository->getMetaValues($accounts, ['currency_id', 'account_role', 'account_number']);
$currencyIds = $metaFields->where('name', 'currency_id')->pluck('data')->toArray();
$currencies = $repository->getByIds($currencyIds);
foreach ($currencies as $currency) {
$id = $currency->id;
$this->currencies[$id] = $currency;
}
foreach ($metaFields as $entry) {
$id = $entry->account_id;
$this->accountMeta[$id][$entry->name] = $entry->data;
}
}
private function collectAccountTypes(Collection $accounts): void
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$accountTypes = $accountRepository->getAccountTypes($accounts);
/** @var AccountType $row */
foreach ($accountTypes as $row) {
$this->accountTypes[$row->id] = (string) config(sprintf('firefly.shortNamesByFullName.%s', $row->type));
}
}
private function getLastActivity(Collection $accounts): void
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$lastActivity = $accountRepository->getLastActivity($accounts);
foreach ($lastActivity as $row) {
$this->lastActivity[(int) $row['account_id']] = Carbon::parse($row['date_max'], config('app.timezone'));
}
}
private function sortAccounts(Collection $accounts): Collection
{
/** @var null|array $sort */
$sort = $this->parameters->get('sort');
if (null === $sort || 0 === count($sort)) {
return $accounts;
}
/**
* @var string $column
* @var string $direction
*/
foreach ($sort as $column => $direction) {
// account_number + iban
if ('iban' === $column) {
$accounts = $this->sortByIban($accounts, $direction);
}
if ('balance' === $column) {
$accounts = $this->sortByBalance($accounts, $direction);
}
if ('last_activity' === $column) {
$accounts = $this->sortByLastActivity($accounts, $direction);
}
if ('balance_difference' === $column) {
$accounts = $this->sortByBalanceDifference($accounts, $direction);
}
}
return $accounts;
}
private function sortByIban(Collection $accounts, string $direction): Collection
{
$meta = $this->accountMeta;
return $accounts->sort(function (Account $left, Account $right) use ($meta, $direction) {
$leftIban = trim(sprintf('%s%s', $left->iban, $meta[$left->id]['account_number'] ?? ''));
$rightIban = trim(sprintf('%s%s', $right->iban, $meta[$right->id]['account_number'] ?? ''));
if ('asc' === $direction) {
return strcasecmp($leftIban, $rightIban);
}
return strcasecmp($rightIban, $leftIban);
});
}
private function sortByBalance(Collection $accounts, string $direction): Collection
{
$balances = $this->convertedBalances;
return $accounts->sort(function (Account $left, Account $right) use ($balances, $direction) {
$leftBalance = (float) ($balances[$left->id]['native_balance'] ?? 0);
$rightBalance = (float) ($balances[$right->id]['native_balance'] ?? 0);
if ('asc' === $direction) {
return $leftBalance <=> $rightBalance;
}
return $rightBalance <=> $leftBalance;
});
}
private function sortByLastActivity(Collection $accounts, string $direction): Collection
{
$dates = $this->lastActivity;
return $accounts->sort(function (Account $left, Account $right) use ($dates, $direction) {
$leftDate = $dates[$left->id] ?? Carbon::create(1900, 1, 1, 0, 0, 0);
$rightDate = $dates[$right->id] ?? Carbon::create(1900, 1, 1, 0, 0, 0);
if ('asc' === $direction) {
return $leftDate->gt($rightDate) ? 1 : -1;
}
return $rightDate->gt($leftDate) ? 1 : -1;
});
}
private function getBalanceDifference(Collection $accounts, Carbon $start, Carbon $end): void
{
// collect balances, start and end for both native and converted.
// yes the b is usually used for boolean by idiots but here it's for balance.
$bStart = [];
$bEnd = [];
try {
$bStart = app('steam')->balancesByAccountsConverted($accounts, $start);
$bEnd = app('steam')->balancesByAccountsConverted($accounts, $end);
} catch (FireflyException $e) {
Log::error($e->getMessage());
}
/** @var Account $account */
foreach ($accounts as $account) {
$id = $account->id;
if (array_key_exists($id, $bStart) && array_key_exists($id, $bEnd)) {
$this->balanceDifferences[$id] = [
'balance' => bcsub($bEnd[$id]['balance'], $bStart[$id]['balance']),
'native_balance' => bcsub($bEnd[$id]['native_balance'], $bStart[$id]['native_balance']),
];
}
}
}
private function sortByBalanceDifference(Collection $accounts, string $direction): Collection
{
$balances = $this->balanceDifferences;
return $accounts->sort(function (Account $left, Account $right) use ($balances, $direction) {
$leftBalance = (float) ($balances[$left->id]['native_balance'] ?? 0);
$rightBalance = (float) ($balances[$right->id]['native_balance'] ?? 0);
if ('asc' === $direction) {
return $leftBalance <=> $rightBalance;
}
return $rightBalance <=> $leftBalance;
});
}
}

View File

@@ -381,10 +381,7 @@ class User extends Authenticatable
$dbRolesTitles = $dbRoles->pluck('title')->toArray();
/** @var Collection $groupMemberships */
$groupMemberships = $this->groupMemberships()
->whereIn('user_role_id', $dbRolesIds)
->where('user_group_id', $userGroup->id)->get()
;
$groupMemberships = $this->groupMemberships()->whereIn('user_role_id', $dbRolesIds)->where('user_group_id', $userGroup->id)->get();
if (0 === $groupMemberships->count()) {
app('log')->error(sprintf(
'User #%d "%s" does not have roles %s in user group #%d "%s"',

View File

@@ -101,6 +101,7 @@
"psr/log": "<4",
"ramsey/uuid": "^4.7",
"rcrowe/twigbridge": "^0.14",
"twig/twig": "3.8.0",
"spatie/laravel-html": "^3.2",
"spatie/laravel-ignition": "^2",
"spatie/period": "^2.4",

190
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "90c32aa5ed2c60408abbdd7edf8100db",
"content-hash": "be35d14f371e7f8bc178ae6f7a615e5c",
"packages": [
{
"name": "bacon/bacon-qr-code",
@@ -1670,16 +1670,16 @@
},
{
"name": "laravel/framework",
"version": "v11.2.0",
"version": "v11.4.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "a1750156b671f37cba702380107e2d22161c31e3"
"reference": "c1dc67c28811dc5be524a30b18f29ce62126716a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/a1750156b671f37cba702380107e2d22161c31e3",
"reference": "a1750156b671f37cba702380107e2d22161c31e3",
"url": "https://api.github.com/repos/laravel/framework/zipball/c1dc67c28811dc5be524a30b18f29ce62126716a",
"reference": "c1dc67c28811dc5be524a30b18f29ce62126716a",
"shasum": ""
},
"require": {
@@ -1698,7 +1698,7 @@
"fruitcake/php-cors": "^1.3",
"guzzlehttp/guzzle": "^7.8",
"guzzlehttp/uri-template": "^1.0",
"laravel/prompts": "^0.1.15",
"laravel/prompts": "^0.1.18",
"laravel/serializable-closure": "^1.3",
"league/commonmark": "^2.2.1",
"league/flysystem": "^3.8.0",
@@ -1871,20 +1871,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2024-04-02T14:01:33+00:00"
"time": "2024-04-16T14:38:51+00:00"
},
{
"name": "laravel/passport",
"version": "v12.0.2",
"version": "v12.1.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/passport.git",
"reference": "21099f1aff81706781578a19335d8a4c7c96422a"
"reference": "ff4742c71c58a4941b8738496ba96dabdf5e395b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/passport/zipball/21099f1aff81706781578a19335d8a4c7c96422a",
"reference": "21099f1aff81706781578a19335d8a4c7c96422a",
"url": "https://api.github.com/repos/laravel/passport/zipball/ff4742c71c58a4941b8738496ba96dabdf5e395b",
"reference": "ff4742c71c58a4941b8738496ba96dabdf5e395b",
"shasum": ""
},
"require": {
@@ -1947,20 +1947,20 @@
"issues": "https://github.com/laravel/passport/issues",
"source": "https://github.com/laravel/passport"
},
"time": "2024-03-21T18:44:57+00:00"
"time": "2024-04-15T18:49:04+00:00"
},
{
"name": "laravel/prompts",
"version": "v0.1.17",
"version": "v0.1.19",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
"reference": "8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5"
"reference": "0ab75ac3434d9f610c5691758a6146a3d1940c18"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5",
"reference": "8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5",
"url": "https://api.github.com/repos/laravel/prompts/zipball/0ab75ac3434d9f610c5691758a6146a3d1940c18",
"reference": "0ab75ac3434d9f610c5691758a6146a3d1940c18",
"shasum": ""
},
"require": {
@@ -2002,22 +2002,22 @@
],
"support": {
"issues": "https://github.com/laravel/prompts/issues",
"source": "https://github.com/laravel/prompts/tree/v0.1.17"
"source": "https://github.com/laravel/prompts/tree/v0.1.19"
},
"time": "2024-03-13T16:05:43+00:00"
"time": "2024-04-16T14:20:35+00:00"
},
{
"name": "laravel/sanctum",
"version": "v4.0.1",
"version": "v4.0.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/sanctum.git",
"reference": "d1de99bf8d31199aaf93881561622489ab91ba58"
"reference": "9cfc0ce80cabad5334efff73ec856339e8ec1ac1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/d1de99bf8d31199aaf93881561622489ab91ba58",
"reference": "d1de99bf8d31199aaf93881561622489ab91ba58",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/9cfc0ce80cabad5334efff73ec856339e8ec1ac1",
"reference": "9cfc0ce80cabad5334efff73ec856339e8ec1ac1",
"shasum": ""
},
"require": {
@@ -2068,7 +2068,7 @@
"issues": "https://github.com/laravel/sanctum/issues",
"source": "https://github.com/laravel/sanctum"
},
"time": "2024-03-19T20:09:38+00:00"
"time": "2024-04-10T19:39:58+00:00"
},
{
"name": "laravel/serializable-closure",
@@ -2324,16 +2324,16 @@
},
{
"name": "lcobucci/jwt",
"version": "5.2.0",
"version": "5.3.0",
"source": {
"type": "git",
"url": "https://github.com/lcobucci/jwt.git",
"reference": "0ba88aed12c04bd2ed9924f500673f32b67a6211"
"reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/0ba88aed12c04bd2ed9924f500673f32b67a6211",
"reference": "0ba88aed12c04bd2ed9924f500673f32b67a6211",
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/08071d8d2c7f4b00222cc4b1fb6aa46990a80f83",
"reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83",
"shasum": ""
},
"require": {
@@ -2381,7 +2381,7 @@
],
"support": {
"issues": "https://github.com/lcobucci/jwt/issues",
"source": "https://github.com/lcobucci/jwt/tree/5.2.0"
"source": "https://github.com/lcobucci/jwt/tree/5.3.0"
},
"funding": [
{
@@ -2393,7 +2393,7 @@
"type": "patreon"
}
],
"time": "2023-11-20T21:17:42+00:00"
"time": "2024-04-11T23:07:54+00:00"
},
{
"name": "league/commonmark",
@@ -2728,16 +2728,16 @@
},
{
"name": "league/flysystem",
"version": "3.26.0",
"version": "3.27.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "072735c56cc0da00e10716dd90d5a7f7b40b36be"
"reference": "4729745b1ab737908c7d055148c9a6b3e959832f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/072735c56cc0da00e10716dd90d5a7f7b40b36be",
"reference": "072735c56cc0da00e10716dd90d5a7f7b40b36be",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4729745b1ab737908c7d055148c9a6b3e959832f",
"reference": "4729745b1ab737908c7d055148c9a6b3e959832f",
"shasum": ""
},
"require": {
@@ -2802,7 +2802,7 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.26.0"
"source": "https://github.com/thephpleague/flysystem/tree/3.27.0"
},
"funding": [
{
@@ -2814,7 +2814,7 @@
"type": "github"
}
],
"time": "2024-03-25T11:49:53+00:00"
"time": "2024-04-07T19:17:50+00:00"
},
{
"name": "league/flysystem-local",
@@ -3265,16 +3265,16 @@
},
{
"name": "monolog/monolog",
"version": "3.5.0",
"version": "3.6.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448"
"reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/c915e2634718dbc8a4a15c61b0e62e7a44e14448",
"reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/4b18b21a5527a3d5ffdac2fd35d3ab25a9597654",
"reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654",
"shasum": ""
},
"require": {
@@ -3297,7 +3297,7 @@
"phpstan/phpstan": "^1.9",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-strict-rules": "^1.4",
"phpunit/phpunit": "^10.1",
"phpunit/phpunit": "^10.5.17",
"predis/predis": "^1.1 || ^2",
"ruflin/elastica": "^7",
"symfony/mailer": "^5.4 || ^6",
@@ -3350,7 +3350,7 @@
],
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/3.5.0"
"source": "https://github.com/Seldaek/monolog/tree/3.6.0"
},
"funding": [
{
@@ -3362,20 +3362,20 @@
"type": "tidelift"
}
],
"time": "2023-10-27T15:32:31+00:00"
"time": "2024-04-12T21:02:21+00:00"
},
{
"name": "nesbot/carbon",
"version": "3.2.4",
"version": "3.3.0",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"reference": "82c28278c1c8f7b82dcdab25692237f052ffc8d8"
"reference": "7219739c4e01d4680c980545821733b6ed8ee880"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/82c28278c1c8f7b82dcdab25692237f052ffc8d8",
"reference": "82c28278c1c8f7b82dcdab25692237f052ffc8d8",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7219739c4e01d4680c980545821733b6ed8ee880",
"reference": "7219739c4e01d4680c980545821733b6ed8ee880",
"shasum": ""
},
"require": {
@@ -3468,7 +3468,7 @@
"type": "tidelift"
}
],
"time": "2024-04-05T09:58:10+00:00"
"time": "2024-04-18T16:35:06+00:00"
},
{
"name": "nette/schema",
@@ -5320,16 +5320,16 @@
},
{
"name": "spatie/ignition",
"version": "1.13.1",
"version": "1.13.2",
"source": {
"type": "git",
"url": "https://github.com/spatie/ignition.git",
"reference": "889bf1dfa59e161590f677728b47bf4a6893983b"
"reference": "952798e239d9969e4e694b124c2cc222798dbb28"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/ignition/zipball/889bf1dfa59e161590f677728b47bf4a6893983b",
"reference": "889bf1dfa59e161590f677728b47bf4a6893983b",
"url": "https://api.github.com/repos/spatie/ignition/zipball/952798e239d9969e4e694b124c2cc222798dbb28",
"reference": "952798e239d9969e4e694b124c2cc222798dbb28",
"shasum": ""
},
"require": {
@@ -5399,7 +5399,7 @@
"type": "github"
}
],
"time": "2024-03-29T14:03:47+00:00"
"time": "2024-04-16T08:49:17+00:00"
},
{
"name": "spatie/laravel-html",
@@ -5481,16 +5481,16 @@
},
{
"name": "spatie/laravel-ignition",
"version": "2.5.1",
"version": "2.5.2",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-ignition.git",
"reference": "0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9"
"reference": "c93fcadcc4629775c839ac9a90916f07a660266f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9",
"reference": "0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9",
"url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/c93fcadcc4629775c839ac9a90916f07a660266f",
"reference": "c93fcadcc4629775c839ac9a90916f07a660266f",
"shasum": ""
},
"require": {
@@ -5500,7 +5500,7 @@
"illuminate/support": "^10.0|^11.0",
"php": "^8.1",
"spatie/flare-client-php": "^1.3.5",
"spatie/ignition": "^1.13",
"spatie/ignition": "^1.13.2",
"symfony/console": "^6.2.3|^7.0",
"symfony/var-dumper": "^6.2.3|^7.0"
},
@@ -5569,7 +5569,7 @@
"type": "github"
}
],
"time": "2024-04-02T06:30:22+00:00"
"time": "2024-04-16T08:57:16+00:00"
},
{
"name": "spatie/period",
@@ -8900,16 +8900,16 @@
"packages-dev": [
{
"name": "barryvdh/laravel-debugbar",
"version": "v3.13.3",
"version": "v3.13.4",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "241e9bddb04ab42a04a5fe8b2b9654374c864229"
"reference": "00201bcd1eaf9b1d3debddcdc13c219e4835fb61"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/241e9bddb04ab42a04a5fe8b2b9654374c864229",
"reference": "241e9bddb04ab42a04a5fe8b2b9654374c864229",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/00201bcd1eaf9b1d3debddcdc13c219e4835fb61",
"reference": "00201bcd1eaf9b1d3debddcdc13c219e4835fb61",
"shasum": ""
},
"require": {
@@ -8968,7 +8968,7 @@
],
"support": {
"issues": "https://github.com/barryvdh/laravel-debugbar/issues",
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.13.3"
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.13.4"
},
"funding": [
{
@@ -8980,7 +8980,7 @@
"type": "github"
}
],
"time": "2024-04-04T02:42:49+00:00"
"time": "2024-04-10T09:15:45+00:00"
},
{
"name": "barryvdh/laravel-ide-helper",
@@ -9507,16 +9507,16 @@
},
{
"name": "larastan/larastan",
"version": "v2.9.2",
"version": "v2.9.5",
"source": {
"type": "git",
"url": "https://github.com/larastan/larastan.git",
"reference": "a79b46b96060504b400890674b83f66aa7f5db6d"
"reference": "101f1a4470f87326f4d3995411d28679d8800abe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/larastan/larastan/zipball/a79b46b96060504b400890674b83f66aa7f5db6d",
"reference": "a79b46b96060504b400890674b83f66aa7f5db6d",
"url": "https://api.github.com/repos/larastan/larastan/zipball/101f1a4470f87326f4d3995411d28679d8800abe",
"reference": "101f1a4470f87326f4d3995411d28679d8800abe",
"shasum": ""
},
"require": {
@@ -9529,15 +9529,15 @@
"illuminate/pipeline": "^9.52.16 || ^10.28.0 || ^11.0",
"illuminate/support": "^9.52.16 || ^10.28.0 || ^11.0",
"php": "^8.0.2",
"phpmyadmin/sql-parser": "^5.8.2",
"phpstan/phpstan": "^1.10.50"
"phpmyadmin/sql-parser": "^5.9.0",
"phpstan/phpstan": "^1.10.66"
},
"require-dev": {
"doctrine/coding-standard": "^12.0",
"nikic/php-parser": "^4.17.1",
"orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.0",
"orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.0",
"phpunit/phpunit": "^9.6.13 || ^10.5"
"nikic/php-parser": "^4.19.1",
"orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.2",
"orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.3",
"phpunit/phpunit": "^9.6.13 || ^10.5.16"
},
"suggest": {
"orchestra/testbench": "Using Larastan for analysing a package needs Testbench"
@@ -9585,7 +9585,7 @@
],
"support": {
"issues": "https://github.com/larastan/larastan/issues",
"source": "https://github.com/larastan/larastan/tree/v2.9.2"
"source": "https://github.com/larastan/larastan/tree/v2.9.5"
},
"funding": [
{
@@ -9605,7 +9605,7 @@
"type": "patreon"
}
],
"time": "2024-02-27T03:16:03+00:00"
"time": "2024-04-16T19:13:34+00:00"
},
{
"name": "maximebf/debugbar",
@@ -10285,16 +10285,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.10.66",
"version": "1.10.67",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "94779c987e4ebd620025d9e5fdd23323903950bd"
"reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/94779c987e4ebd620025d9e5fdd23323903950bd",
"reference": "94779c987e4ebd620025d9e5fdd23323903950bd",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/16ddbe776f10da6a95ebd25de7c1dbed397dc493",
"reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493",
"shasum": ""
},
"require": {
@@ -10337,13 +10337,9 @@
{
"url": "https://github.com/phpstan",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
"type": "tidelift"
}
],
"time": "2024-03-28T16:17:31+00:00"
"time": "2024-04-16T07:22:02+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
@@ -10395,16 +10391,16 @@
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "1.5.3",
"version": "1.5.5",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "568210bd301f94a0d4b1e5a0808c374c1b9cf11b"
"reference": "2e193a07651a6f4be3baa44ddb21d822681f5918"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/568210bd301f94a0d4b1e5a0808c374c1b9cf11b",
"reference": "568210bd301f94a0d4b1e5a0808c374c1b9cf11b",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/2e193a07651a6f4be3baa44ddb21d822681f5918",
"reference": "2e193a07651a6f4be3baa44ddb21d822681f5918",
"shasum": ""
},
"require": {
@@ -10438,9 +10434,9 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.3"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.5"
},
"time": "2024-04-06T07:43:25+00:00"
"time": "2024-04-19T15:12:26+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -10765,16 +10761,16 @@
},
{
"name": "phpunit/phpunit",
"version": "10.5.17",
"version": "10.5.19",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "c1f736a473d21957ead7e94fcc029f571895abf5"
"reference": "c726f0de022368f6ed103e452a765d3304a996a4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c1f736a473d21957ead7e94fcc029f571895abf5",
"reference": "c1f736a473d21957ead7e94fcc029f571895abf5",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c726f0de022368f6ed103e452a765d3304a996a4",
"reference": "c726f0de022368f6ed103e452a765d3304a996a4",
"shasum": ""
},
"require": {
@@ -10846,7 +10842,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.17"
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.19"
},
"funding": [
{
@@ -10862,7 +10858,7 @@
"type": "tidelift"
}
],
"time": "2024-04-05T04:39:01+00:00"
"time": "2024-04-17T14:06:18+00:00"
},
{
"name": "sebastian/cli-parser",

326
config/debugbar.php Normal file
View File

@@ -0,0 +1,326 @@
<?php
declare(strict_types=1);
return [
/*
|--------------------------------------------------------------------------
| Debugbar Settings
|--------------------------------------------------------------------------
|
| Debugbar is enabled by default, when debug is set to true in app.php.
| You can override the value by setting enable to true or false instead of null.
|
| You can provide an array of URI's that must be ignored (eg. 'api/*')
|
*/
'enabled' => env('DEBUGBAR_ENABLED', null),
'except' => [
'telescope*',
'horizon*',
],
/*
|--------------------------------------------------------------------------
| Storage settings
|--------------------------------------------------------------------------
|
| DebugBar stores data for session/ajax requests.
| You can disable this, so the debugbar stores data in headers/session,
| but this can cause problems with large data collectors.
| By default, file storage (in the storage folder) is used. Redis and PDO
| can also be used. For PDO, run the package migrations first.
|
| Warning: Enabling storage.open will allow everyone to access previous
| request, do not enable open storage in publicly available environments!
| Specify a callback if you want to limit based on IP or authentication.
| Leaving it to null will allow localhost only.
*/
'storage' => [
'enabled' => true,
'open' => env('DEBUGBAR_OPEN_STORAGE'), // bool/callback.
'driver' => 'file', // redis, file, pdo, socket, custom
'path' => storage_path('debugbar'), // For file driver
'connection' => null, // Leave null for default connection (Redis/PDO)
'provider' => '', // Instance of StorageInterface for custom driver
'hostname' => '127.0.0.1', // Hostname to use with the "socket" driver
'port' => 2304, // Port to use with the "socket" driver
],
/*
|--------------------------------------------------------------------------
| Editor
|--------------------------------------------------------------------------
|
| Choose your preferred editor to use when clicking file name.
|
| Supported: "phpstorm", "vscode", "vscode-insiders", "vscode-remote",
| "vscode-insiders-remote", "vscodium", "textmate", "emacs",
| "sublime", "atom", "nova", "macvim", "idea", "netbeans",
| "xdebug", "espresso"
|
*/
'editor' => env('DEBUGBAR_EDITOR') ?: env('IGNITION_EDITOR', 'phpstorm'),
/*
|--------------------------------------------------------------------------
| Remote Path Mapping
|--------------------------------------------------------------------------
|
| If you are using a remote dev server, like Laravel Homestead, Docker, or
| even a remote VPS, it will be necessary to specify your path mapping.
|
| Leaving one, or both of these, empty or null will not trigger the remote
| URL changes and Debugbar will treat your editor links as local files.
|
| "remote_sites_path" is an absolute base path for your sites or projects
| in Homestead, Vagrant, Docker, or another remote development server.
|
| Example value: "/home/vagrant/Code"
|
| "local_sites_path" is an absolute base path for your sites or projects
| on your local computer where your IDE or code editor is running on.
|
| Example values: "/Users/<name>/Code", "C:\Users\<name>\Documents\Code"
|
*/
'remote_sites_path' => env('DEBUGBAR_REMOTE_SITES_PATH'),
'local_sites_path' => env('DEBUGBAR_LOCAL_SITES_PATH', env('IGNITION_LOCAL_SITES_PATH')),
/*
|--------------------------------------------------------------------------
| Vendors
|--------------------------------------------------------------------------
|
| Vendor files are included by default, but can be set to false.
| This can also be set to 'js' or 'css', to only include javascript or css vendor files.
| Vendor files are for css: font-awesome (including fonts) and highlight.js (css files)
| and for js: jquery and highlight.js
| So if you want syntax highlighting, set it to true.
| jQuery is set to not conflict with existing jQuery scripts.
|
*/
'include_vendors' => true,
/*
|--------------------------------------------------------------------------
| Capture Ajax Requests
|--------------------------------------------------------------------------
|
| The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors),
| you can use this option to disable sending the data through the headers.
|
| Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools.
|
| Note for your request to be identified as ajax requests they must either send the header
| X-Requested-With with the value XMLHttpRequest (most JS libraries send this), or have application/json as a Accept header.
|
| By default `ajax_handler_auto_show` is set to true allowing ajax requests to be shown automatically in the Debugbar.
| Changing `ajax_handler_auto_show` to false will prevent the Debugbar from reloading.
*/
'capture_ajax' => true,
'add_ajax_timing' => false,
'ajax_handler_auto_show' => true,
'ajax_handler_enable_tab' => true,
/*
|--------------------------------------------------------------------------
| Custom Error Handler for Deprecated warnings
|--------------------------------------------------------------------------
|
| When enabled, the Debugbar shows deprecated warnings for Symfony components
| in the Messages tab.
|
*/
'error_handler' => false,
/*
|--------------------------------------------------------------------------
| Clockwork integration
|--------------------------------------------------------------------------
|
| The Debugbar can emulate the Clockwork headers, so you can use the Chrome
| Extension, without the server-side code. It uses Debugbar collectors instead.
|
*/
'clockwork' => false,
/*
|--------------------------------------------------------------------------
| DataCollectors
|--------------------------------------------------------------------------
|
| Enable/disable DataCollectors
|
*/
'collectors' => [
'phpinfo' => true, // Php version
'messages' => true, // Messages
'time' => true, // Time Datalogger
'memory' => true, // Memory usage
'exceptions' => true, // Exception displayer
'log' => true, // Logs from Monolog (merged in messages if enabled)
'db' => true, // Show database (PDO) queries and bindings
'views' => true, // Views with their data
'route' => true, // Current route information
'auth' => false, // Display Laravel authentication status
'gate' => true, // Display Laravel Gate checks
'session' => true, // Display session data
'symfony_request' => true, // Only one can be enabled..
'mail' => true, // Catch mail messages
'laravel' => false, // Laravel version and environment
'events' => false, // All events fired
'default_request' => false, // Regular or special Symfony request logger
'logs' => false, // Add the latest log messages
'files' => false, // Show the included files
'config' => false, // Display config settings
'cache' => false, // Display cache events
'models' => true, // Display models
'livewire' => true, // Display Livewire (when available)
'jobs' => false, // Display dispatched jobs
],
/*
|--------------------------------------------------------------------------
| Extra options
|--------------------------------------------------------------------------
|
| Configure some DataCollectors
|
*/
'options' => [
'time' => [
'memory_usage' => false, // Calculated by subtracting memory start and end, it may be inaccurate
],
'messages' => [
'trace' => true, // Trace the origin of the debug message
],
'memory' => [
'reset_peak' => false, // run memory_reset_peak_usage before collecting
'with_baseline' => false, // Set boot memory usage as memory peak baseline
'precision' => 0, // Memory rounding precision
],
'auth' => [
'show_name' => true, // Also show the users name/email in the debugbar
'show_guards' => true, // Show the guards that are used
],
'db' => [
'with_params' => true, // Render SQL with the parameters substituted
'backtrace' => true, // Use a backtrace to find the origin of the query in your files.
'backtrace_exclude_paths' => [], // Paths to exclude from backtrace. (in addition to defaults)
'timeline' => false, // Add the queries to the timeline
'duration_background' => true, // Show shaded background on each query relative to how long it took to execute.
'explain' => [ // Show EXPLAIN output on queries
'enabled' => false,
'types' => ['SELECT'], // Deprecated setting, is always only SELECT
],
'hints' => false, // Show hints for common mistakes
'show_copy' => false, // Show copy button next to the query,
'slow_threshold' => false, // Only track queries that last longer than this time in ms
'memory_usage' => false, // Show queries memory usage
'soft_limit' => 100, // After the soft limit, no parameters/backtrace are captured
'hard_limit' => 500, // After the hard limit, queries are ignored
],
'mail' => [
'timeline' => false, // Add mails to the timeline
'show_body' => true,
],
'views' => [
'timeline' => false, // Add the views to the timeline (Experimental)
'data' => false, // true for all data, 'keys' for only names, false for no parameters.
'group' => 50, // Group duplicate views. Pass value to auto-group, or true/false to force
'exclude_paths' => [ // Add the paths which you don't want to appear in the views
'vendor/filament', // Exclude Filament components by default
],
],
'route' => [
'label' => true, // show complete route on bar
],
'session' => [
'hiddens' => [], // hides sensitive values using array paths
],
'symfony_request' => [
'hiddens' => [], // hides sensitive values using array paths, example: request_request.password
],
'events' => [
'data' => false, // collect events data, listeners
],
'logs' => [
'file' => null,
],
'cache' => [
'values' => true, // collect cache values
],
],
/*
|--------------------------------------------------------------------------
| Inject Debugbar in Response
|--------------------------------------------------------------------------
|
| Usually, the debugbar is added just before </body>, by listening to the
| Response after the App is done. If you disable this, you have to add them
| in your template yourself. See http://phpdebugbar.com/docs/rendering.html
|
*/
'inject' => true,
/*
|--------------------------------------------------------------------------
| DebugBar route prefix
|--------------------------------------------------------------------------
|
| Sometimes you want to set route prefix to be used by DebugBar to load
| its resources from. Usually the need comes from misconfigured web server or
| from trying to overcome bugs like this: http://trac.nginx.org/nginx/ticket/97
|
*/
'route_prefix' => '_debugbar',
/*
|--------------------------------------------------------------------------
| DebugBar route middleware
|--------------------------------------------------------------------------
|
| Additional middleware to run on the Debugbar routes
*/
'route_middleware' => [],
/*
|--------------------------------------------------------------------------
| DebugBar route domain
|--------------------------------------------------------------------------
|
| By default DebugBar route served from the same domain that request served.
| To override default domain, specify it as a non-empty value.
*/
'route_domain' => null,
/*
|--------------------------------------------------------------------------
| DebugBar theme
|--------------------------------------------------------------------------
|
| Switches between light and dark theme. If set to auto it will respect system preferences
| Possible values: auto, light, dark
*/
'theme' => env('DEBUGBAR_THEME', 'auto'),
/*
|--------------------------------------------------------------------------
| Backtrace stack limit
|--------------------------------------------------------------------------
|
| By default, the DebugBar limits the number of frames returned by the 'debug_backtrace()' function.
| If you need larger stacktraces, you can increase this number. Setting it to 0 will result in no limit.
*/
'debug_backtrace_limit' => 50,
];

View File

@@ -117,8 +117,8 @@ return [
'expression_engine' => false,
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2024-04-07',
'api_version' => '2.0.13',
'version' => 'develop/2024-04-21',
'api_version' => '2.0.14',
'db_version' => 24,
// generic settings
@@ -206,7 +206,6 @@ return [
// web configuration:
'trusted_proxies' => env('TRUSTED_PROXIES', ''),
'layout' => envNonEmpty('FIREFLY_III_LAYOUT', 'v1'),
// map configuration
'default_location' => [
@@ -925,7 +924,7 @@ return [
'sorting' => [
'allowed' => [
'transactions' => ['description', 'amount'],
'accounts' => ['name', 'active', 'iban', 'balance', 'last_activity'],
'accounts' => ['name', 'active', 'iban', 'balance', 'last_activity', 'balance_difference'],
],
],
];

691
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -22,95 +22,10 @@ var count = 0;
$(document).ready(function () {
updateListButtons();
addSort();
$('.clone-transaction').click(cloneTransaction);
$('.clone-transaction-and-edit').click(cloneTransactionAndEdit);
});
var fixHelper = function (e, tr) {
"use strict";
var $originals = tr.children();
var $helper = tr.clone();
$helper.children().each(function (index) {
// Set helper cell sizes to match the original sizes
$(this).width($originals.eq(index).width());
});
return $helper;
};
/**
*
*/
function addSort() {
if (typeof $(".table-sortable>tbody").sortable !== "undefined") {
$('.table-sortable>tbody').sortable(
{
items: "tr:not(.unsortable)",
handle: '.object-handle',
stop: sortStop,
start: function (event, ui) {
// Build a placeholder cell that spans all the cells in the row
var cellCount = 0;
$('td, th', ui.helper).each(function () {
// For each TD or TH try and get it's colspan attribute, and add that or 1 to the total
var colspan = 1;
var colspanAttr = $(this).attr('colspan');
if (colspanAttr > 1) {
colspan = colspanAttr;
}
cellCount += colspan;
});
// Add the placeholder UI - note that this is the item's content, so TD rather than TR
ui.placeholder.html('<td colspan="' + cellCount + '">&nbsp;</td>');
}
}
);
}
}
/**
*
* @param event
* @param ui
* @returns {boolean|undefined}
*/
function sortStop(event, ui) {
"use strict";
var current = $(ui.item);
var thisDate = current.data('date');
var originalBG = current.css('backgroundColor');
if (current.prev().data('date') !== thisDate && current.next().data('date') !== thisDate) {
// animate something with color:
current.animate({backgroundColor: "#d9534f"}, 200, function () {
$(this).animate({backgroundColor: originalBG}, 200);
return undefined;
});
return false;
}
//return false;
// do update
var list = $('tr[data-date="' + thisDate + '"]');
var submit = [];
$.each(list, function (i, v) {
var row = $(v);
var id = row.data('id');
submit.push(id);
});
// do extra animation when done?
$.post('transactions/reorder', {items: submit, date: thisDate, _token: token});
current.animate({backgroundColor: "#5cb85c"}, 200, function () {
$(this).animate({backgroundColor: originalBG}, 200);
return undefined;
});
return undefined;
}
/**
*

View File

@@ -103,6 +103,12 @@
.skin-firefly-iii .btn-info {
color: #fff;
}
.skin-firefly-iii .btn-danger {
color: #fff;
}
.skin-firefly-iii .btn-warning {
color: #fff;
}
.skin-firefly-iii .btn-default {
background-color: #55606a;
color: #bec5cb;
@@ -251,6 +257,11 @@
}
.skin-firefly-iii .table > thead > tr > th,
.skin-firefly-iii .table > tbody > tr > th,
.skin-firefly-iii .table > tfoot > tr > th {
border-bottom: 2px #c9d1d9 solid;
}
.skin-firefly-iii .table > thead > tr > th,
.skin-firefly-iii .table > tbody > tr > th,
.skin-firefly-iii .table > tfoot > tr > th,
.skin-firefly-iii .table > thead > tr > td,
.skin-firefly-iii .table > tbody > tr > td,
@@ -480,6 +491,7 @@
.skin-firefly-iii .nav-tabs-custom > .nav-tabs > li.active > a {
border-left-color: #353c42;
border-right-color: #353c42;
color: #bec5cb;
}
.skin-firefly-iii .nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type.active > a {
border-left-color: #353c42;
@@ -511,7 +523,7 @@
background-color: #272c30;
}
.skin-firefly-iii .input-group .input-group-addon {
border-right: 1px solid #272c30;
border: 1px solid #272c30;
}
.skin-firefly-iii .form-control {
border-color: #272c30;

File diff suppressed because one or more lines are too long

View File

@@ -15,22 +15,22 @@
},
"firefly": {
"spent": "Gastat",
"administration_owner": "Administration owner: {{email}}",
"administration_you": "Your role: {{role}}",
"administration_role_owner": "Owner",
"administration_role_ro": "Read-only",
"administration_role_mng_trx": "Manage transactions",
"administration_role_mng_meta": "Manage classification and meta-data",
"administration_role_mng_budgets": "Manage budgets",
"administration_role_mng_piggies": "Manage piggy banks",
"administration_role_mng_subscriptions": "Manage subscriptions",
"administration_role_mng_rules": "Manage rules",
"administration_role_mng_recurring": "Manage recurring transactions ",
"administration_role_mng_webhooks": "Manage webhooks",
"administration_role_mng_currencies": "Manage currencies",
"administration_role_view_reports": "View reports",
"administration_role_full": "Full access",
"new_administration_created": "New financial administration \"{{title}}\" has been created",
"administration_owner": "Propietari de l'administraci\u00f3: {{email}}",
"administration_you": "El teu rol: {{role}}",
"administration_role_owner": "Propietari",
"administration_role_ro": "Nom\u00e9s de lectura",
"administration_role_mng_trx": "Gestionar transaccions",
"administration_role_mng_meta": "Gestionar classificaci\u00f3 i meta-dades",
"administration_role_mng_budgets": "Gestionar pressupostos",
"administration_role_mng_piggies": "Administra guardioles",
"administration_role_mng_subscriptions": "Gestionar subscripcions",
"administration_role_mng_rules": "Gestionar normes",
"administration_role_mng_recurring": "Gestionar transaccions recurrents ",
"administration_role_mng_webhooks": "Gestionar Webhooks",
"administration_role_mng_currencies": "Gestionar divises",
"administration_role_view_reports": "Veure informes",
"administration_role_full": "Acc\u00e9s total",
"new_administration_created": "S'ha creat una nova administraci\u00f3 financera \"{{title}}\"",
"left": "Queda",
"paid": "Pagat",
"errors_submission_v2": "Hi ha hagut un error amb el teu enviament. Per favor, comprova els seg\u00fcents errors: {{errorMessage}}",

View File

@@ -15,22 +15,22 @@
},
"firefly": {
"spent": "Gastat",
"administration_owner": "Administration owner: {{email}}",
"administration_you": "Your role: {{role}}",
"administration_role_owner": "Owner",
"administration_role_ro": "Read-only",
"administration_role_mng_trx": "Manage transactions",
"administration_role_mng_meta": "Manage classification and meta-data",
"administration_role_mng_budgets": "Manage budgets",
"administration_role_mng_piggies": "Manage piggy banks",
"administration_role_mng_subscriptions": "Manage subscriptions",
"administration_role_mng_rules": "Manage rules",
"administration_role_mng_recurring": "Manage recurring transactions ",
"administration_role_mng_webhooks": "Manage webhooks",
"administration_role_mng_currencies": "Manage currencies",
"administration_role_view_reports": "View reports",
"administration_role_full": "Full access",
"new_administration_created": "New financial administration \"{{title}}\" has been created",
"administration_owner": "Propietari de l'administraci\u00f3: {{email}}",
"administration_you": "El teu rol: {{role}}",
"administration_role_owner": "Propietari",
"administration_role_ro": "Nom\u00e9s de lectura",
"administration_role_mng_trx": "Gestionar transaccions",
"administration_role_mng_meta": "Gestionar classificaci\u00f3 i meta-dades",
"administration_role_mng_budgets": "Gestionar pressupostos",
"administration_role_mng_piggies": "Administra guardioles",
"administration_role_mng_subscriptions": "Gestionar subscripcions",
"administration_role_mng_rules": "Gestionar normes",
"administration_role_mng_recurring": "Gestionar transaccions recurrents ",
"administration_role_mng_webhooks": "Gestionar Webhooks",
"administration_role_mng_currencies": "Gestionar divises",
"administration_role_view_reports": "Veure informes",
"administration_role_full": "Acc\u00e9s total",
"new_administration_created": "S'ha creat una nova administraci\u00f3 financera \"{{title}}\"",
"left": "Queda",
"paid": "Pagat",
"errors_submission_v2": "Hi ha hagut un error amb el teu enviament. Per favor, comprova els seg\u00fcents errors: {{errorMessage}}",

View File

@@ -4,7 +4,7 @@
"date_time_fns": "do MMMM yyyy @ HH:mm:ss",
"month_and_day_fns": "d MMMM y",
"does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm"
"date_time_fns_short": "do MMMM yyyy @ HH:mm"
},
"form": {
"title": "Titolo"
@@ -17,10 +17,10 @@
"spent": "Speso",
"administration_owner": "Administration owner: {{email}}",
"administration_you": "Your role: {{role}}",
"administration_role_owner": "Owner",
"administration_role_ro": "Read-only",
"administration_role_mng_trx": "Manage transactions",
"administration_role_mng_meta": "Manage classification and meta-data",
"administration_role_owner": "Proprietario",
"administration_role_ro": "Sola lettura",
"administration_role_mng_trx": "Gestisci le transazioni",
"administration_role_mng_meta": "Gestisci classificazione e meta-dati",
"administration_role_mng_budgets": "Manage budgets",
"administration_role_mng_piggies": "Manage piggy banks",
"administration_role_mng_subscriptions": "Manage subscriptions",
@@ -48,7 +48,7 @@
"unknown_dest_plain": "Conto di destinazione sconosciuto",
"unknown_any_plain": "Conto sconosciuto",
"unknown_budget_plain": "Nessun budget",
"stored_journal_js": "Successfully created new transaction \"{{description}}\"",
"stored_journal_js": "Nuova transazione \"{{description}} \" creata con successo",
"wait_loading_transaction": "Attendi il caricamento del modello",
"nothing_found": "(nessun risultato)",
"wait_loading_data": "Ti preghiamo di attendere il caricamento delle tue informazioni...",

View File

@@ -4,7 +4,7 @@
"date_time_fns": "do MMMM yyyy @ HH:mm:ss",
"month_and_day_fns": "d MMMM y",
"does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm"
"date_time_fns_short": "do MMMM yyyy @ HH:mm"
},
"form": {
"title": "Titolo"
@@ -17,10 +17,10 @@
"spent": "Speso",
"administration_owner": "Administration owner: {{email}}",
"administration_you": "Your role: {{role}}",
"administration_role_owner": "Owner",
"administration_role_ro": "Read-only",
"administration_role_mng_trx": "Manage transactions",
"administration_role_mng_meta": "Manage classification and meta-data",
"administration_role_owner": "Proprietario",
"administration_role_ro": "Sola lettura",
"administration_role_mng_trx": "Gestisci le transazioni",
"administration_role_mng_meta": "Gestisci classificazione e meta-dati",
"administration_role_mng_budgets": "Manage budgets",
"administration_role_mng_piggies": "Manage piggy banks",
"administration_role_mng_subscriptions": "Manage subscriptions",
@@ -48,7 +48,7 @@
"unknown_dest_plain": "Conto di destinazione sconosciuto",
"unknown_any_plain": "Conto sconosciuto",
"unknown_budget_plain": "Nessun budget",
"stored_journal_js": "Successfully created new transaction \"{{description}}\"",
"stored_journal_js": "Nuova transazione \"{{description}} \" creata con successo",
"wait_loading_transaction": "Attendi il caricamento del modello",
"nothing_found": "(nessun risultato)",
"wait_loading_data": "Ti preghiamo di attendere il caricamento delle tue informazioni...",

View File

@@ -4,7 +4,7 @@
"date_time_fns": "dd 'de' MMMM 'de' yyyy, '\u00e0s' HH:mm:ss",
"month_and_day_fns": "d [de] MMMM [de] y",
"does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm"
"date_time_fns_short": "dd\/MMM\/yyyy HH:mm"
},
"form": {
"title": "T\u00edtulo"
@@ -15,25 +15,25 @@
},
"firefly": {
"spent": "Gasto",
"administration_owner": "Administration owner: {{email}}",
"administration_you": "Your role: {{role}}",
"administration_role_owner": "Owner",
"administration_role_ro": "Read-only",
"administration_role_mng_trx": "Manage transactions",
"administration_role_mng_meta": "Manage classification and meta-data",
"administration_role_mng_budgets": "Manage budgets",
"administration_role_mng_piggies": "Manage piggy banks",
"administration_role_mng_subscriptions": "Manage subscriptions",
"administration_role_mng_rules": "Manage rules",
"administration_role_mng_recurring": "Manage recurring transactions ",
"administration_role_mng_webhooks": "Manage webhooks",
"administration_role_mng_currencies": "Manage currencies",
"administration_role_view_reports": "View reports",
"administration_role_full": "Full access",
"new_administration_created": "New financial administration \"{{title}}\" has been created",
"administration_owner": "Propriet\u00e1rio da administra\u00e7\u00e3o: {{email}}",
"administration_you": "Sua fun\u00e7\u00e3o: {{role}}",
"administration_role_owner": "Propriet\u00e1rio",
"administration_role_ro": "Somente leitura",
"administration_role_mng_trx": "Gerenciar transa\u00e7\u00f5es",
"administration_role_mng_meta": "Gerenciar classifica\u00e7\u00e3o e metadados",
"administration_role_mng_budgets": "Gerenciar or\u00e7amentos",
"administration_role_mng_piggies": "Gerenciar cofrinhos",
"administration_role_mng_subscriptions": "Gerenciar assinaturas",
"administration_role_mng_rules": "Gerenciar regras",
"administration_role_mng_recurring": "Gerenciar transa\u00e7\u00f5es recorrentes ",
"administration_role_mng_webhooks": "Gerenciar webhooks",
"administration_role_mng_currencies": "Gerenciar moedas",
"administration_role_view_reports": "Ver relat\u00f3rios",
"administration_role_full": "Acesso completo",
"new_administration_created": "Nova administra\u00e7\u00e3o financeira \"{{title}}\" foi criada",
"left": "Restante",
"paid": "Pago",
"errors_submission_v2": "There was something wrong with your submission. Please check out the errors below: {{errorMessage}}",
"errors_submission_v2": "Algo deu errado com seu envio. Por favor, verifique os erros abaixo: {{errorMessage}}",
"unpaid": "N\u00e3o pago",
"default_group_title_name_plain": "sem grupo",
"subscriptions_in_group": "Assinaturas no grupo \"%{title}\"",
@@ -48,7 +48,7 @@
"unknown_dest_plain": "Conta de destino desconhecida",
"unknown_any_plain": "Conta desconhecida",
"unknown_budget_plain": "Nenhum or\u00e7amento",
"stored_journal_js": "Successfully created new transaction \"{{description}}\"",
"stored_journal_js": "Transa\u00e7\u00e3o \"{{description}}\" criada com sucesso",
"wait_loading_transaction": "Por favor, aguarde o formul\u00e1rio carregar",
"nothing_found": "(nada encontrado)",
"wait_loading_data": "Por favor, aguarde suas informa\u00e7\u00f5es serem carregadas...",

View File

@@ -4,7 +4,7 @@
"date_time_fns": "DO [de] MMMM YYYY, @ HH:mm:ss",
"month_and_day_fns": "d MMMM y",
"does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm"
"date_time_fns_short": "do MMMM yyyy @ HH:mm"
},
"form": {
"title": "T\u00edtulo"

View File

@@ -4,7 +4,7 @@
"date_time_fns": "dd 'de' MMMM 'de' yyyy, '\u00e0s' HH:mm:ss",
"month_and_day_fns": "d [de] MMMM [de] y",
"does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm"
"date_time_fns_short": "dd\/MMM\/yyyy HH:mm"
},
"form": {
"title": "T\u00edtulo"
@@ -15,25 +15,25 @@
},
"firefly": {
"spent": "Gasto",
"administration_owner": "Administration owner: {{email}}",
"administration_you": "Your role: {{role}}",
"administration_role_owner": "Owner",
"administration_role_ro": "Read-only",
"administration_role_mng_trx": "Manage transactions",
"administration_role_mng_meta": "Manage classification and meta-data",
"administration_role_mng_budgets": "Manage budgets",
"administration_role_mng_piggies": "Manage piggy banks",
"administration_role_mng_subscriptions": "Manage subscriptions",
"administration_role_mng_rules": "Manage rules",
"administration_role_mng_recurring": "Manage recurring transactions ",
"administration_role_mng_webhooks": "Manage webhooks",
"administration_role_mng_currencies": "Manage currencies",
"administration_role_view_reports": "View reports",
"administration_role_full": "Full access",
"new_administration_created": "New financial administration \"{{title}}\" has been created",
"administration_owner": "Propriet\u00e1rio da administra\u00e7\u00e3o: {{email}}",
"administration_you": "Sua fun\u00e7\u00e3o: {{role}}",
"administration_role_owner": "Propriet\u00e1rio",
"administration_role_ro": "Somente leitura",
"administration_role_mng_trx": "Gerenciar transa\u00e7\u00f5es",
"administration_role_mng_meta": "Gerenciar classifica\u00e7\u00e3o e metadados",
"administration_role_mng_budgets": "Gerenciar or\u00e7amentos",
"administration_role_mng_piggies": "Gerenciar cofrinhos",
"administration_role_mng_subscriptions": "Gerenciar assinaturas",
"administration_role_mng_rules": "Gerenciar regras",
"administration_role_mng_recurring": "Gerenciar transa\u00e7\u00f5es recorrentes ",
"administration_role_mng_webhooks": "Gerenciar webhooks",
"administration_role_mng_currencies": "Gerenciar moedas",
"administration_role_view_reports": "Ver relat\u00f3rios",
"administration_role_full": "Acesso completo",
"new_administration_created": "Nova administra\u00e7\u00e3o financeira \"{{title}}\" foi criada",
"left": "Restante",
"paid": "Pago",
"errors_submission_v2": "There was something wrong with your submission. Please check out the errors below: {{errorMessage}}",
"errors_submission_v2": "Algo deu errado com seu envio. Por favor, verifique os erros abaixo: {{errorMessage}}",
"unpaid": "N\u00e3o pago",
"default_group_title_name_plain": "sem grupo",
"subscriptions_in_group": "Assinaturas no grupo \"%{title}\"",
@@ -48,7 +48,7 @@
"unknown_dest_plain": "Conta de destino desconhecida",
"unknown_any_plain": "Conta desconhecida",
"unknown_budget_plain": "Nenhum or\u00e7amento",
"stored_journal_js": "Successfully created new transaction \"{{description}}\"",
"stored_journal_js": "Transa\u00e7\u00e3o \"{{description}}\" criada com sucesso",
"wait_loading_transaction": "Por favor, aguarde o formul\u00e1rio carregar",
"nothing_found": "(nada encontrado)",
"wait_loading_data": "Por favor, aguarde suas informa\u00e7\u00f5es serem carregadas...",

View File

@@ -4,7 +4,7 @@
"date_time_fns": "DO [de] MMMM YYYY, @ HH:mm:ss",
"month_and_day_fns": "d MMMM y",
"does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm"
"date_time_fns_short": "do MMMM yyyy @ HH:mm"
},
"form": {
"title": "T\u00edtulo"

View File

@@ -30,7 +30,7 @@
"administration_role_mng_currencies": "Upravljanje valut",
"administration_role_view_reports": "Prikaz poro\u010dil",
"administration_role_full": "Neomejen dostop",
"new_administration_created": "New financial administration \"{{title}}\" has been created",
"new_administration_created": "Ustvarjena je bila nova finan\u010dna administracija \"{{title}}\"",
"left": "Preostalo",
"paid": "Pla\u010dano",
"errors_submission_v2": "Nekaj je bilo narobe z va\u0161o oddajo. Preverite spodnje napake: {{errorMessage}}",

View File

@@ -30,7 +30,7 @@
"administration_role_mng_currencies": "Upravljanje valut",
"administration_role_view_reports": "Prikaz poro\u010dil",
"administration_role_full": "Neomejen dostop",
"new_administration_created": "New financial administration \"{{title}}\" has been created",
"new_administration_created": "Ustvarjena je bila nova finan\u010dna administracija \"{{title}}\"",
"left": "Preostalo",
"paid": "Pla\u010dano",
"errors_submission_v2": "Nekaj je bilo narobe z va\u0161o oddajo. Preverite spodnje napake: {{errorMessage}}",

View File

@@ -10,7 +10,7 @@
"prod": "mix --production"
},
"dependencies": {
"date-fns": "^2.30.0",
"date-fns": "^3.6.0",
"stream-browserify": "^3.0.0"
},
"devDependencies": {

View File

@@ -5,8 +5,8 @@
"flash_warning": "Aten\u00e7\u00e3o!",
"flash_success": "Sucesso!",
"close": "Fechar",
"select_dest_account": "Please select or type a valid destination account name",
"select_source_account": "Please select or type a valid source account name",
"select_dest_account": "Por favor, selecione ou digite um nome de conta de destino v\u00e1lido",
"select_source_account": "Por favor, selecione ou digite um nome de conta de origem v\u00e1lido",
"split_transaction_title": "Descri\u00e7\u00e3o da transa\u00e7\u00e3o dividida",
"errors_submission": "Algo deu errado com seu envio. Por favor, verifique os erros abaixo.",
"split": "Dividir",

View File

@@ -20,6 +20,7 @@
let mix = require('laravel-mix');
mix.webpackConfig({
resolve: {
alias: {

View File

@@ -1,18 +1,19 @@
{
"name": "v2",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"build": "vite build --emptyOutDir",
"postinstall": "patch-package --error-on-fail"
},
"devDependencies": {
"axios": "^1.6.8",
"laravel-vite-plugin": "^0.8.1",
"laravel-vite-plugin": "^1.0.2",
"patch-package": "^8.0.0",
"sass": "^1.72.0",
"vite": "^4.5.3",
"vite-plugin-manifest-sri": "^0.1.0"
"sass": "^1.75.0",
"vite": "^5",
"vite-plugin-manifest-sri": "^0.2.0"
},
"dependencies": {
"@ag-grid-community/client-side-row-model": "^31.0.3",
@@ -30,7 +31,7 @@
"chartjs-adapter-date-fns": "^3.0.0",
"chartjs-chart-sankey": "^0.12.0",
"date-fns": "^3.6.0",
"i18next": "^23.10.1",
"i18next": "^23.11.2",
"i18next-chained-backend": "^4.6.2",
"i18next-http-backend": "^2.4.2",
"i18next-localstorage-backend": "^4.2.0",

View File

@@ -30,6 +30,11 @@ import '../../css/grid-ff3-theme.css';
import Get from "../../api/v2/model/account/get.js";
import Put from "../../api/v2/model/account/put.js";
import AccountRenderer from "../../support/renderers/AccountRenderer.js";
import {showInternalsButton} from "../../support/page-settings/show-internals-button.js";
import {showWizardButton} from "../../support/page-settings/show-wizard-button.js";
import {getVariable} from "../../store/get-variable.js";
import {setVariable} from "../../store/set-variable.js";
// set type from URL
const beforeQuery = window.location.href.split('?');
@@ -47,6 +52,9 @@ sortingColumn = params.column ?? '';
sortDirection = params.direction ?? '';
showInternalsButton();
showWizardButton();
let index = function () {
return {
// notifications
@@ -59,10 +67,64 @@ let index = function () {
show: false, text: '',
}
}, totalPages: 1, page: 1, // available columns:
},
totalPages: 1,
page: 1,
// available columns:
// visible is hard coded, enabled is user-configurable.
tableColumns: {
drag_and_drop: {
visible: true,
enabled: true,
},
active: {
visible: true,
enabled: true,
},
name: {
enabled: true
visible: true,
enabled: true,
},
type: {
visible: true,
enabled: true,
},
liability_type: {
visible: type === 'liabilities',
enabled: true,
},
liability_direction: {
visible: type === 'liabilities',
enabled: true,
},
liability_interest: {
visible: type === 'liabilities',
enabled: true,
},
number: {
visible: true,
enabled: true,
},
current_balance: {
visible: type !== 'liabilities',
enabled: true,
},
amount_due: {
visible: type === 'liabilities',
enabled: true,
},
last_activity: {
visible: true,
enabled: true,
},
balance_difference: {
visible: true,
enabled: true,
},
menu: {
visible: true,
enabled: true,
},
},
editors: {},
@@ -77,7 +139,7 @@ let index = function () {
sort(column) {
this.sortingColumn = column;
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
const url = './accounts/'+type+'?column='+column+'&direction='+this.sortDirection;
const url = './accounts/' + type + '?column=' + column + '&direction=' + this.sortDirection;
window.history.pushState({}, "", url);
@@ -92,11 +154,34 @@ let index = function () {
format(date) {
return format(date, i18next.t('config.date_time_fns'));
},
saveColumnSettings() {
let newSettings = {};
for (let key in this.tableColumns) {
if (this.tableColumns.hasOwnProperty(key)) {
newSettings[key] = this.tableColumns[key].enabled;
}
}
console.log('New settings', newSettings);
setVariable('accts_columns_' + type, newSettings);
},
init() {
this.notifications.wait.show = true;
this.notifications.wait.text = i18next.t('firefly.wait_loading_data')
this.loadAccounts();
const key = 'accts_columns_' + type;
const defaultValue = {"drag_and_drop": false};
getVariable(key, defaultValue).then((response) => {
for (let k in response) {
if (response.hasOwnProperty(k) && this.tableColumns.hasOwnProperty(k)) {
this.tableColumns[k].enabled = response[k] ?? true;
}
}
}).then(() => {
this.loadAccounts();
});
},
renderObjectValue(field, account) {
let renderer = new AccountRenderer();
@@ -140,14 +225,33 @@ let index = function () {
this.accounts[index].nameEditorVisible = true;
},
loadAccounts() {
// sort instructions
const sorting = [{column: this.sortingColumn, direction: this.sortDirection}];
// get start and end from the store:
const start = new Date(window.store.get('start'));
const end = new Date(window.store.get('end'));
let params = {
sorting: sorting,
type: type,
page: this.page,
start: start,
end: end
};
if(!this.tableColumns.balance_difference.enabled){
delete params.start;
delete params.end;
}
this.notifications.wait.show = true;
this.notifications.wait.text = i18next.t('firefly.wait_loading_data')
this.accounts = [];
// sort instructions
// &sorting[0][column]=description&sorting[0][direction]=asc
const sorting = [{column: this.sortingColumn, direction: this.sortDirection}];
// one page only.o
(new Get()).index({sorting: sorting, type: type, page: this.page}).then(response => {
(new Get()).index(params).then(response => {
for (let i = 0; i < response.data.data.length; i++) {
if (response.data.data.hasOwnProperty(i)) {
let current = response.data.data[i];
@@ -165,7 +269,10 @@ let index = function () {
native_current_balance: current.attributes.native_current_balance,
native_currency_code: current.attributes.native_currency_code,
last_activity: null === current.attributes.last_activity ? '' : format(new Date(current.attributes.last_activity), i18next.t('config.month_and_day_fns')),
balance_difference: current.attributes.balance_difference,
native_balance_difference: current.attributes.native_balance_difference
};
console.log(current.attributes.balance_difference);
this.accounts.push(account);
}
}

View File

@@ -23,6 +23,7 @@ import {format} from "date-fns";
import {getVariable} from "../../store/get-variable.js";
import formatMoney from "../../util/format-money.js";
import {getCacheKey} from "../../support/get-cache-key.js";
import {cleanupCache} from "../../support/cleanup-cache.js";
let afterPromises = false;
export default () => ({
@@ -38,6 +39,7 @@ export default () => ({
const start = new Date(window.store.get('start'));
const end = new Date(window.store.get('end'));
const boxesCacheKey = getCacheKey('dashboard-boxes-data', start, end);
cleanupCache();
const cacheValid = window.store.get('cacheValid');
let cachedData = window.store.get(boxesCacheKey);

View File

@@ -69,6 +69,7 @@ let transactions = function () {
resetButton: false,
rulesButton: true,
webhooksButton: true,
categorySelectVisible: false
},
// form behaviour during transaction
@@ -343,7 +344,13 @@ let transactions = function () {
// destination can never be revenue account
this.filters.destination = ['Expense account', 'Loan', 'Debt', 'Mortgage', 'Asset account'];
},
keyUpFromCategory(e) {
if (e.key === 'Enter' && false === this.formStates.categorySelectVisible) {
this.submitTransaction();
return;
}
this.formStates.categorySelectVisible = document.querySelector('input.ac-category').nextSibling.classList.contains('show');
},
submitTransaction() {
// reset all messages:
this.notifications.error.show = false;
@@ -422,7 +429,10 @@ let transactions = function () {
if (this.formStates.returnHereButton) {
this.notifications.success.show = true;
this.notifications.success.url = 'transactions/show/' + this.groupProperties.id;
this.notifications.success.text = i18next.t('firefly.stored_journal_js', {description: this.groupProperties.title, interpolation: { escapeValue: false }});
this.notifications.success.text = i18next.t('firefly.stored_journal_js', {
description: this.groupProperties.title,
interpolation: {escapeValue: false}
});
this.formStates.isSubmitting = false;
// reset group title again
this.groupProperties.title = null;

View File

@@ -72,12 +72,15 @@ let transactions = function () {
resetButton: true,
rulesButton: true,
webhooksButton: true,
},
// form behaviour during transaction
formBehaviour: {
formType: 'edit',
foreignCurrencyEnabled: true,
categorySelectVisible: false,
},
// form data (except transactions) is stored in formData
@@ -111,6 +114,14 @@ let transactions = function () {
}
},
keyUpFromCategory(e) {
if (e.key === 'Enter' && false === this.formBehaviour.categorySelectVisible) {
this.submitTransaction();
return;
}
this.formBehaviour.categorySelectVisible = document.querySelector('input.ac-category').nextSibling.classList.contains('show');
},
// submit the transaction form.
// TODO pretty much duplicate of create.js
submitTransaction() {

View File

@@ -23,217 +23,12 @@ import dates from "../shared/dates.js";
import i18next from "i18next";
import {format} from "date-fns";
import formatMoney from "../../util/format-money.js";
import Put from "../../api/v2/model/transaction/put.js";
import {createGrid, ModuleRegistry} from "@ag-grid-community/core";
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css';
import '../../css/grid-ff3-theme.css';
import Get from "../../api/v2/model/transaction/get.js";
import AmountEditor from "../../support/ag-grid/AmountEditor.js";
import TransactionDataSource from "../../support/ag-grid/TransactionDataSource.js";
import {InfiniteRowModelModule} from '@ag-grid-community/infinite-row-model';
import DateTimeEditor from "../../support/ag-grid/DateTimeEditor.js";
const ds = new TransactionDataSource();
// set type from URL
const urlParts = window.location.href.split('/');
const type = urlParts[urlParts.length - 1];
ds.setType(type);
let dataTable;
const editableFields = ['description', 'amount', 'date'];
const onCellEditRequestMethod = (event) => {
console.log('onCellEditRequestMethod');
const data = event.data;
const field = event.colDef.field;
let newValue = event.newValue;
if (!editableFields.includes(field)) {
console.log('Field ' + field + ' is not editable.');
return;
}
// this needs to be better
if ('amount' === field) {
newValue = event.newValue.amount;
console.log('New value is now' + newValue);
}
console.log('New value for field "' + field + '" in transaction journal #' + data.transaction_journal_id + ' of group #' + data.id + ' is "' + newValue + '"');
data[field] = newValue;
let rowNode = dataTable.getRowNode(String(event.rowIndex));
rowNode.updateData(data);
// then push update to Firefly III over API:
let submission = {
transactions: [
{
transaction_journal_id: data.transaction_journal_id,
}
]
};
submission.transactions[0][field] = newValue;
let putter = new Put();
putter.put(submission, {id: data.id});
};
const gridOptions = {
rowModelType: 'infinite',
datasource: ds,
cacheOverflowSize: 1,
cacheBlockSize: 20,
onCellEditRequest: onCellEditRequestMethod,
readOnlyEdit: true,
getRowId: function (params) {
console.log('getRowId', params.data.id);
return params.data.id;
},
// Row Data: The data to be displayed.
// rowData: [
// { description: "Tesla", model: "Model Y", price: 64950, electric: true },
// { description: "Ford", model: "F-Series", price: 33850, electric: false },
// { description: "Toyota", model: "Corolla", price: 29600, electric: false },
// ],
// Column Definitions: Defines & controls grid columns.
columnDefs: [
{
field: "icon",
editable: false,
headerName: '',
sortable: false,
width: 40,
cellRenderer: function (params) {
if (params.getValue()) {
return '<a href="./transactions/show/' + parseInt(params.value.id) + '"><em class="' + params.value.classes + '"></em></a>';
}
return '';
}
},
{
field: "description",
cellDataType: 'text',
editable: true,
// cellRenderer: function (params) {
// if (params.getValue()) {
// return '<a href="#">' + params.getValue() + '</a>';
// }
// return '';
// }
},
{
field: "amount",
editable: function (params) {
// only when NO foreign amount.
return null === params.data.amount.foreign_amount && null === params.data.amount.foreign_currency_code;
},
cellEditor: AmountEditor,
cellRenderer(params) {
if (params.getValue()) {
let returnString = '';
let amount = parseFloat(params.getValue().amount);
let obj = params.getValue();
let stringClass = 'text-danger';
if (obj.type === 'withdrawal') {
amount = amount * -1;
}
if (obj.type === 'deposit') {
stringClass = 'text-success';
}
if (obj.type === 'transfer') {
stringClass = 'text-info';
}
returnString += '<span class="' + stringClass + '">' + formatMoney(amount, params.getValue().currency_code) + '</span>';
// foreign amount:
if (obj.foreign_amount) {
let foreignAmount = parseFloat(params.getValue().foreign_amount);
if (obj.type === 'withdrawal') {
foreignAmount = foreignAmount * -1;
}
returnString += ' (<span class="' + stringClass + '">' + formatMoney(foreignAmount, obj.foreign_currency_code) + '</span>)';
}
return returnString;
}
return '';
}
},
{
field: "date",
editable: true,
cellDataType: 'date',
cellEditor: DateTimeEditor,
cellEditorPopup: true,
cellEditorPopupPosition: 'under',
cellRenderer(params) {
if (params.getValue()) {
return format(params.getValue(), i18next.t('config.date_time_fns_short'));
}
return '';
}
},
{
field: "from",
cellDataType: 'text',
cellRenderer: function (params) {
if (params.getValue()) {
let obj = params.getValue();
return '<a href="./accounts/show/' + obj.id + '">' + obj.name + '</a>';
}
return '';
}
},
{
field: "to",
cellDataType: 'text',
cellRenderer: function (params) {
if (params.getValue()) {
let obj = params.getValue();
return '<a href="./accounts/show/' + obj.id + '">' + obj.name + '</a>';
}
return '';
}
},
{
field: "category",
cellDataType: 'text',
cellRenderer: function (params) {
if (params.getValue()) {
let obj = params.getValue();
if (null !== obj.id) {
return '<a href="./categories/show/' + obj.id + '">' + obj.name + '</a>';
}
}
return '';
}
},
{
field: "budget",
cellDataType: 'text',
cellRenderer: function (params) {
if (params.getValue()) {
let obj = params.getValue();
if (null !== obj.id) {
return '<a href="./budgets/show/' + obj.id + '">' + obj.name + '</a>';
}
}
return '';
}
},
]
};
ModuleRegistry.registerModules([InfiniteRowModelModule]);
let index = function () {
return {
// notifications
@@ -276,36 +71,56 @@ let index = function () {
return format(date, i18next.t('config.date_time_fns'));
},
init() {
this.notifications.wait.show = true;
this.notifications.wait.text = i18next.t('firefly.wait_loading_data')
// TODO need date range.
// TODO handle page number
//this.getTransactions(this.page);
this.getTransactions(this.page);``
// Your Javascript code to create the grid
dataTable = createGrid(document.querySelector('#grid'), gridOptions);
// dataTable = createGrid(document.querySelector('#grid'), gridOptions);
},
// getTransactions(page) {
// const urlParts = window.location.href.split('/');
// const type = urlParts[urlParts.length - 1];
// let getter = new Get();
//
// getter.list({page: page, type: type}).then(response => {
// this.parseTransactions(response.data.data)
//
// // set meta data
// this.totalPages = response.data.meta.pagination.total_pages;
// this.perPage = response.data.meta.pagination.per_page;
// this.page = response.data.meta.pagination.current_page;
// }).catch(error => {
// // to do this is auto generated
// this.notifications.wait.show = false;
// this.notifications.error.show = true;
// this.notifications.error.text = error.response.data.message;
// });
// },
getTransactions(page) {
this.notifications.wait.show = true;
this.notifications.wait.text = i18next.t('firefly.wait_loading_data')
this.transactions = [];
const urlParts = window.location.href.split('/');
const type = urlParts[urlParts.length - 1];
let getter = new Get();
getter.list({page: page, type: type}).then(response => {
this.parseTransactions(response.data.data)
// set meta data
this.totalPages = response.data.meta.pagination.total_pages;
this.perPage = response.data.meta.pagination.per_page;
this.page = response.data.meta.pagination.current_page;
}).catch(error => {
// to do this is auto generated
this.notifications.wait.show = false;
this.notifications.error.show = true;
this.notifications.error.text = error.response.data.message;
});
},
previousPage() {
if(this.page > 1) {
this.page--;
}
this.getTransactions(this.page);
},
nextPage() {
if(this.page < this.totalPages) {
this.page++;
}
this.getTransactions(this.page);
},
gotoPage(i) {
if(i > 0 && i <= this.totalPages) {
this.page = i;
}
this.getTransactions(this.page);
},
parseTransactions(data) {
// no parse, just save
for (let i in data) {
@@ -321,7 +136,7 @@ let index = function () {
transaction.split = isSplit;
tranaction.icon = 'fa fa-solid fa-arrow-left';
transaction.icon = 'fa fa-solid fa-arrow-left';
transaction.firstSplit = firstSplit;
transaction.group_title = current.attributes.group_title;
transaction.id = current.id;

View File

@@ -22,31 +22,27 @@ import Get from "../api/v1/preferences/index.js";
import Post from "../api/v1/preferences/post.js";
export function getVariable(name, defaultValue = null) {
const validCache = window.store.get('cacheValid');
// currently unused, window.X can be used by the blade template
// to make things available quicker than if the store has to grab it through the API.
// then again, it's not that slow.
if (validCache && window.hasOwnProperty(name)) {
// console.log('Get from window');
return Promise.resolve(window[name]);
}
// load from store2, if it's present.
const fromStore = window.store.get(name);
if (validCache && typeof fromStore !== 'undefined') {
// console.log('Get "' + name + '" from store');
return Promise.resolve(fromStore);
}
let getter = (new Get);
return getter.getByName(name).then((response) => {
// console.log('Get "' + name + '" from API');
return Promise.resolve(parseResponse(name, response));
}).catch(() => {
}).catch((error) => {
// preference does not exist (yet).
// POST it and then return it anyway.
let poster = (new Post);
poster.post(name, defaultValue).then((response) => {
return poster.post(name, defaultValue).then((response) => {
return Promise.resolve(parseResponse(name, response));
});
});
@@ -55,7 +51,6 @@ export function getVariable(name, defaultValue = null) {
export function parseResponse(name, response) {
let value = response.data.data.attributes.data;
window.store.set(name, value);
// console.log('Store "' + name + '" in localStorage');
return value;
}

View File

@@ -0,0 +1,34 @@
/*
* load-translations.js
* 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/>.
*/
import {format} from "date-fns";
import store from "store";
function cleanupCache() {
const localValue = store.get('lastActivity');
store.each(function(value, key) {
if(key.startsWith('dcx') && !key.includes(localValue)) {
store.remove(key);
}
});
}
export {cleanupCache};

View File

@@ -23,7 +23,7 @@ import store from "store";
function getCacheKey(string, start, end) {
const localValue = store.get('lastActivity');
const cacheKey = format(start, 'y-MM-dd') + '_' + format(end, 'y-MM-dd') + '_' + string + localValue;
const cacheKey = 'dcx' + format(start, 'yMMdd')+ format(end, 'yMMdd') + string + localValue;
console.log('getCacheKey: ' + cacheKey);
return String(cacheKey);
}

View File

@@ -0,0 +1,25 @@
/*
* show-internals-button.js
* Copyright (c) 2024 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/.
*/
export function showInternalsButton() {
console.log('showInternalsButton');
document.querySelector('.toggle-page-internals').classList.remove('d-none')
}

View File

@@ -0,0 +1,24 @@
/*
* show-settings-button.js
* Copyright (c) 2024 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/.
*/
export function showWizardButton() {
document.querySelector('.toggle-page-wizard').classList.remove('d-none')
}

View File

@@ -21,6 +21,7 @@
import {defineConfig} from 'vite';
import laravel from 'laravel-vite-plugin';
import manifestSRI from 'vite-plugin-manifest-sri';
import * as fs from "fs";
const host = '127.0.0.1';
@@ -65,20 +66,23 @@ export default defineConfig({
publicDirectory: '../../../public',
refresh: true,
}),
//manifestSRI(),
manifestSRI(),
],
server: {
usePolling: true,
allowedHosts: '*.sd.internal',
host: '0.0.0.0',
hmr: {host},
cors: true
watch: {
usePolling: true,
},
host: '10.0.0.15',
// hmr: {
// protocol: 'wss',
// },
// https: {
// key: fs.readFileSync(`/Users/sander/Sites/vm/tls-certificates/wildcard.sd.local.key`),
// cert: fs.readFileSync(`/Users/sander/Sites/vm/tls-certificates/wildcard.sd.local.crt`),
// key: fs.readFileSync(`/sites/vm/tls-certificates/wildcard.sd.internal.key`),
// cert: fs.readFileSync(`/sites/vm/tls-certificates/wildcard.sd.internal.crt`),
// },
},
});

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Изход',
'logout_other_sessions' => 'Изход от всички други сесии',
'toggleNavigation' => 'Превключване на навигацията',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Търсене...',
'version' => 'Версия',
'dashboard' => 'Основно табло',

View File

@@ -1419,34 +1419,34 @@ return [
// Financial administrations
'administration_index' => 'Administració financera',
'administrations_index_menu' => 'Administració financera',
'administrations_breadcrumb' => 'Financial administrations',
'administrations_page_title' => 'Financial administrations',
'administrations_page_sub_title' => 'Overview',
'create_administration' => 'Create new administration',
'administration_owner' => 'Administration owner: {{email}}',
'administration_you' => 'Your role: {{role}}',
'other_users_in_admin' => 'Other users in this administration',
'administrations_create_breadcrumb' => 'Create new financial administration',
'administrations_page_create_sub_title' => 'Create new financial administration',
'basic_administration_information' => 'Basic administration information',
'new_administration_created' => 'New financial administration "{{title}}" has been created',
'edit_administration_breadcrumb' => 'Edit financial administration ":title"',
'administrations_page_edit_sub_title' => 'Edit financial administration ":title"',
'administrations_breadcrumb' => 'Administracions financeres',
'administrations_page_title' => 'Administracions financeres',
'administrations_page_sub_title' => 'Visió general',
'create_administration' => 'Crea una nova administració',
'administration_owner' => 'Propietari de l\'administració: {{email}}',
'administration_you' => 'El teu rol: {{role}}',
'other_users_in_admin' => 'Altres usuaris a aquesta administració',
'administrations_create_breadcrumb' => 'Crea una nova administració financera',
'administrations_page_create_sub_title' => 'Crea una nova administració financera',
'basic_administration_information' => 'Informació de l\'administració bàsica',
'new_administration_created' => 'S\'ha creat una nova administració financera "{{title}}"',
'edit_administration_breadcrumb' => 'Edita l\'administració financera ":title"',
'administrations_page_edit_sub_title' => 'Edita l\'administració financera ":title"',
// roles
'administration_role_owner' => 'Owner',
'administration_role_ro' => 'Read-only',
'administration_role_mng_trx' => 'Manage transactions',
'administration_role_mng_meta' => 'Manage classification and meta-data',
'administration_role_mng_budgets' => 'Manage budgets',
'administration_role_mng_piggies' => 'Manage piggy banks',
'administration_role_mng_subscriptions' => 'Manage subscriptions',
'administration_role_mng_rules' => 'Manage rules',
'administration_role_mng_recurring' => 'Manage recurring transactions ',
'administration_role_mng_webhooks' => 'Manage webhooks',
'administration_role_mng_currencies' => 'Manage currencies',
'administration_role_view_reports' => 'View reports',
'administration_role_full' => 'Full access',
'administration_role_owner' => 'Propietari',
'administration_role_ro' => 'Només de lectura',
'administration_role_mng_trx' => 'Gestionar transaccions',
'administration_role_mng_meta' => 'Gestionar classificació i meta-dades',
'administration_role_mng_budgets' => 'Gestionar pressupostos',
'administration_role_mng_piggies' => 'Administra guardioles',
'administration_role_mng_subscriptions' => 'Gestionar subscripcions',
'administration_role_mng_rules' => 'Gestionar normes',
'administration_role_mng_recurring' => 'Gestionar transaccions recurrents ',
'administration_role_mng_webhooks' => 'Gestionar Webhooks',
'administration_role_mng_currencies' => 'Gestionar divises',
'administration_role_view_reports' => 'Veure informes',
'administration_role_full' => 'Accés total',
// profile:
'purge_data_title' => 'Purgar dades de Firefly III',
@@ -2144,6 +2144,7 @@ return [
'logout' => 'Tanca la sessió',
'logout_other_sessions' => 'Tanca les altres sessions',
'toggleNavigation' => 'Alternar navegació',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Cerca...',
'version' => 'Versió',
'dashboard' => 'Panell de control',

View File

@@ -68,8 +68,8 @@ return [
'invalid_selection' => 'La selecció és invàlida.',
'belongs_user' => 'Aquest valor està enllaçat a un objecte que sembla que no existeix.',
'belongs_user_or_user_group' => 'Aquest valor està enllaçat a un objecte que sembla no existir a la teva administració financera actual.',
'no_access_group' => 'The user has no access to this user group.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.',
'no_access_group' => 'L\'usuari no té accés a aquest grup d\'usuaris.',
'no_accepted_roles_defined' => 'No s\'ha definit cap rol d\'accés per a aquest endpoint, accés denegat.',
'at_least_one_transaction' => 'Necessites almenys una transacció.',
'recurring_transaction_id' => 'Necessites almenys una transacció.',
'need_id_to_match' => 'Has d\'enviar aquesta entrada amb un ID perquè l\'API sigui capaç de comparar-lo.',
@@ -302,7 +302,7 @@ return [
// no access to administration:
'no_access_user_group' => 'No tens accés a aquesta administració.',
'administration_owner_rename' => 'You can\'t rename your standard administration.',
'administration_owner_rename' => 'No pots canviar el nom de la teva administració estàndard.',
];
/*

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Odhlásit se',
'logout_other_sessions' => 'Logout all other sessions',
'toggleNavigation' => 'Vyp/zap. navigaci',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Hledat…',
'version' => 'Verze',
'dashboard' => 'Přehled',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Logout',
'logout_other_sessions' => 'Logout all other sessions',
'toggleNavigation' => 'Toggle navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Search...',
'version' => 'Version',
'dashboard' => 'Dashboard',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Abmelden',
'logout_other_sessions' => 'Alle anderen Sitzungen abmelden',
'toggleNavigation' => 'Navigation umschalten',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Suchen...',
'version' => 'Version',
'dashboard' => 'Übersicht',

View File

@@ -68,7 +68,7 @@ return [
'invalid_selection' => 'Ihre Auswahl ist ungültig.',
'belongs_user' => 'Dieser Wert verweist auf ein Objekt, das offenbar nicht existiert.',
'belongs_user_or_user_group' => 'Dieser Wert verweist auf ein Objekt, das in Ihrer aktuellen Finanzverwaltung offenbar nicht existiert.',
'no_access_group' => 'The user has no access to this user group.',
'no_access_group' => 'Der Benutzer hat keinen Zugriff auf diese Benutzergruppe.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.',
'at_least_one_transaction' => 'Sie brauchen mindestens eine Transaktion.',
'recurring_transaction_id' => 'Sie benötigen mindestens eine Buchung.',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Αποσύνδεση',
'logout_other_sessions' => 'Αποσυνδέσετε όλες τις άλλες συνεδρίες',
'toggleNavigation' => 'Εναλλαγή περιήγησης',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Αναζήτηση...',
'version' => 'Έκδοση',
'dashboard' => 'Επισκόπηση',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Logout',
'logout_other_sessions' => 'Logout all other sessions',
'toggleNavigation' => 'Toggle navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Search...',
'version' => 'Version',
'dashboard' => 'Dashboard',

View File

@@ -2090,6 +2090,7 @@ return [
'logout' => 'Logout',
'logout_other_sessions' => 'Logout all other sessions',
'toggleNavigation' => 'Toggle navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Search...',
'version' => 'Version',
'dashboard' => 'Dashboard',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Cerrar sesión',
'logout_other_sessions' => 'Desconectar todas las demás sesiones',
'toggleNavigation' => 'Activar navegación',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Buscar...',
'version' => 'Versión',
'dashboard' => 'Panel de control',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Kirjaudu ulos',
'logout_other_sessions' => 'Kirjaudu ulos kaikista muista istunnoista',
'toggleNavigation' => 'Vaihda navigointia',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Hae ...',
'version' => 'Versio',
'dashboard' => 'Etusivu',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Se déconnecter',
'logout_other_sessions' => 'Déconnecter toutes les autres sessions',
'toggleNavigation' => 'Activer navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Rechercher...',
'version' => 'Version',
'dashboard' => 'Tableau de bord',

View File

@@ -68,8 +68,8 @@ return [
'invalid_selection' => 'Votre sélection est invalide.',
'belongs_user' => 'Cette valeur est liée à un objet qui ne semble pas exister.',
'belongs_user_or_user_group' => 'Cette valeur est liée à un objet qui ne semble pas exister dans votre administration financière actuelle.',
'no_access_group' => 'The user has no access to this user group.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.',
'no_access_group' => 'L\'utilisateur n\'a pas accès à ce groupe d\'utilisateurs.',
'no_accepted_roles_defined' => 'Aucun rôle d\'accès n\'a été défini pour ce point d\'accès, accès refusé.',
'at_least_one_transaction' => 'Besoin d\'au moins une opération.',
'recurring_transaction_id' => 'Au moins une opération est nécessaire.',
'need_id_to_match' => 'Vous devez saisir cette entrée avec un identifiant pour que l\'API puisse la faire correspondre.',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Kijelentkezés',
'logout_other_sessions' => 'Minden más munkamenet kijelentkeztetése',
'toggleNavigation' => 'Navigációs mód átkapcsolása',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Keresés...',
'version' => 'Verzió',
'dashboard' => 'Műszerfal',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Keluar',
'logout_other_sessions' => 'Logout all other sessions',
'toggleNavigation' => 'Toggle navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Pencarian...',
'version' => 'Versi',
'dashboard' => 'Dasbor',

View File

@@ -64,7 +64,7 @@ return [
// 'date_time' => '%B %e, %Y, @ %T',
'date_time_js' => 'D MMMM YYYY, HH:mm:ss',
'date_time_fns' => 'do MMMM yyyy @ HH:mm:ss',
'date_time_fns_short' => 'MMMM do, yyyy @ HH:mm',
'date_time_fns_short' => 'do MMMM yyyy @ HH:mm',
// 'specific_day' => '%e %B %Y',
'specific_day_js' => 'D MMMM YYYY',

View File

@@ -42,7 +42,7 @@ return [
'fatal_error' => 'Si è verificato un errore fatale. Controlla i file di login "storage/Los" o usa "Docker Los f [container]" per vedere cosa sta succedendo.',
'maintenance_mode' => 'Firefox III è in modalità di manutenzione.',
'be_right_back' => 'Torno subito!',
'check_back' => 'Firefly III is down for some necessary maintenance. Please check back in a second. If you happen to see this message on the demo site, just wait a few minutes. The database is reset every few hours.',
'check_back' => 'Firefly III non è disponibile per via di una manutenzione necessaria. Per favore riprova tra qualche istante. Se ti capita di vedere questo messaggio sul sito demo, attendi qualche minuto. Il database viene reimpostato ogni poche ore.',
'error_occurred' => 'Oops! Si è verificato un errore.',
'db_error_occurred' => 'Oops! Si è verificato un errore del database.',
'error_not_recoverable' => 'Sfortunatamente questo errore non è riparabile :(. Firefly III è rotto. L\'errore è:',

View File

@@ -896,9 +896,9 @@ return [
'rule_trigger_budget_is' => 'Il budget è ":trigger_value"',
'rule_trigger_tag_is_choice' => 'Qualsiasi tag è..',
'rule_trigger_tag_is' => 'Qualsiasi tag è ":trigger_value"',
'rule_trigger_tag_contains_choice' => 'Any tag contains..',
'rule_trigger_tag_contains' => 'Any tag contains ":trigger_value"',
'rule_trigger_tag_ends_choice' => 'Any tag ends with..',
'rule_trigger_tag_contains_choice' => 'Qualsiasi tag contiene..',
'rule_trigger_tag_contains' => 'Qualsiasi tag contiene ":trigger_value"',
'rule_trigger_tag_ends_choice' => 'Qualsiasi tag finisce con..',
'rule_trigger_tag_ends' => 'Any tag ends with ":trigger_value"',
'rule_trigger_tag_starts_choice' => 'Any tag starts with..',
'rule_trigger_tag_starts' => 'Any tag starts with ":trigger_value"',
@@ -1434,10 +1434,10 @@ return [
'administrations_page_edit_sub_title' => 'Edit financial administration ":title"',
// roles
'administration_role_owner' => 'Owner',
'administration_role_ro' => 'Read-only',
'administration_role_mng_trx' => 'Manage transactions',
'administration_role_mng_meta' => 'Manage classification and meta-data',
'administration_role_owner' => 'Proprietario',
'administration_role_ro' => 'Sola lettura',
'administration_role_mng_trx' => 'Gestisci le transazioni',
'administration_role_mng_meta' => 'Gestisci classificazione e meta-dati',
'administration_role_mng_budgets' => 'Manage budgets',
'administration_role_mng_piggies' => 'Manage piggy banks',
'administration_role_mng_subscriptions' => 'Manage subscriptions',
@@ -2017,7 +2017,7 @@ return [
'deleted_transfer' => 'Trasferimento ":description" eliminato correttamente',
'deleted_reconciliation' => 'Transazione di riconciliazione ":description" elimina con successo',
'stored_journal' => 'Nuova transazione ":description" creata correttamente',
'stored_journal_js' => 'Successfully created new transaction "{{description}}"',
'stored_journal_js' => 'Nuova transazione "{{description}} " creata con successo',
'stored_journal_no_descr' => 'Hai creato con successo la nuova transazione',
'updated_journal_no_descr' => 'Transazione aggiornata con successo',
'select_transactions' => 'Seleziona transazioni',
@@ -2144,6 +2144,7 @@ return [
'logout' => 'Esci',
'logout_other_sessions' => 'Esci da tutte le altre sessioni',
'toggleNavigation' => 'Attiva / disattiva la navigazione',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Cerca...',
'version' => 'Versione',
'dashboard' => 'Cruscotto',
@@ -2325,7 +2326,7 @@ return [
'description' => 'Descrizione',
'sum_of_period' => 'Somma del periodo',
'average_in_period' => 'Media nel periodo',
'no_account_role' => '(no role)',
'no_account_role' => '(nessun ruolo)',
'account_role_defaultAsset' => 'Conto attività predefinito',
'account_role_sharedAsset' => 'Conto attività condiviso',
'account_role_savingAsset' => 'Conto risparmio',
@@ -2490,7 +2491,7 @@ return [
'block_code_bounced' => 'Messaggi email respinti',
'block_code_expired' => 'Conto demo scaduto',
'no_block_code' => 'Nessun motivo per bloccare o non bloccare un utente',
'demo_user_export' => 'The demo user cannot export data',
'demo_user_export' => 'L\'utente demo non può esportare dati',
'block_code_email_changed' => 'L\'utente non ha ancora confermato il nuovo indirizzo emails',
'admin_update_email' => 'Contrariamente alla pagina del profilo, l\'utente NON riceverà alcuna notifica al proprio indirizzo email!',
'update_user' => 'Aggiorna utente',

View File

@@ -70,5 +70,5 @@ return [
'cannot_find_budget' => 'Firefly III non riesce a trovare il budget ":name"',
'cannot_find_category' => 'Firefly III non riesce a trovare la categoria ":name"',
'cannot_set_budget' => 'Firefly III non può impostare il budget ":name" a una transazione di tipo ":type"',
'journal_invalid_amount' => 'Firefly III can\'t set amount ":amount" because it is not a valid number.',
'journal_invalid_amount' => 'Firefly III non può impostare l\'importo ":amount" perché non è un numero valido.',
];

View File

@@ -55,11 +55,11 @@ return [
'reconciled_forbidden_field' => 'Questa transazione è già riconciliata, non è possibile modificare il campo ":field"',
'deleted_user' => 'A causa dei vincoli di sicurezza, non è possibile registrarsi utilizzando questo indirizzo email.',
'rule_trigger_value' => 'Questo valore non è valido per il trigger selezionato.',
'rule_action_expression' => 'Invalid expression. :error',
'rule_action_expression' => 'Espressione non valida. :error',
'rule_action_value' => 'Questo valore non è valido per l\'azione selezionata.',
'file_already_attached' => 'Il file caricato ":name" è già associato a questo oggetto.',
'file_attached' => 'File caricato con successo ":name".',
'file_zero' => 'The file is zero bytes in size.',
'file_zero' => 'Il file ha dimensione zero.',
'must_exist' => 'L\'ID nel campo :attribute non esiste nel database.',
'all_accounts_equal' => 'Tutti i conti in questo campo devono essere uguali.',
'group_title_mandatory' => 'Il titolo del gruppo è obbligatorio quando ci sono più di una transazione.',
@@ -68,8 +68,8 @@ return [
'invalid_selection' => 'La tua selezione non è valida.',
'belongs_user' => 'Questo valore è collegato a un oggetto che non sembra esistere.',
'belongs_user_or_user_group' => 'Questo valore è collegato a un oggetto che non sembra esistere nella tua attuale amministrazione finanziaria.',
'no_access_group' => 'The user has no access to this user group.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.',
'no_access_group' => 'L\'utente non ha accesso a questo gruppo.',
'no_accepted_roles_defined' => 'Nessun ruolo di accesso è stato definito per questo endpoint, accesso negato.',
'at_least_one_transaction' => 'Hai bisogno di almeno una transazione.',
'recurring_transaction_id' => 'Hai bisogno di almeno una transazione.',
'need_id_to_match' => 'È necessario inviare questa voce con un ID affinché l\'API sia in grado di abbinarla.',
@@ -199,7 +199,7 @@ return [
*
*/
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password',
'secure_password' => 'Questa non è una password sicura. Per favore riprova. Per ulteriori informazioni, visita https://bit.ly/FF3-password',
'valid_recurrence_rep_type' => 'Il tipo di ripetizione della transazione ricorrente non è valido.',
'valid_recurrence_rep_moment' => 'Il momento di ripetizione per questo tipo di ripetizione non è valido.',
'invalid_account_info' => 'Informazione sul conto non valida.',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'ログアウト',
'logout_other_sessions' => 'すべてのセッションからログアウト',
'toggleNavigation' => 'ナビゲーションを切り替え',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => '検索...',
'version' => 'バージョン',
'dashboard' => 'ダッシュボード',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => '로그아웃',
'logout_other_sessions' => '다른 모든 세션 로그아웃',
'toggleNavigation' => '토글 내비게이션',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => '검색...',
'version' => '버전',
'dashboard' => '대시보드',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Logg ut',
'logout_other_sessions' => 'Logg ut alle andre økter',
'toggleNavigation' => 'Vis/Skjul navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Søk...',
'version' => 'Versjon',
'dashboard' => 'Startskjerm',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Uitloggen',
'logout_other_sessions' => 'Alle andere sessies afmelden',
'toggleNavigation' => 'Navigatie aan of uit',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Zoeken...',
'version' => 'Versie',
'dashboard' => 'Dashboard',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Logg ut',
'logout_other_sessions' => 'Logg ut alle andre økter',
'toggleNavigation' => 'Vis/Skjul navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Søk...',
'version' => 'Versjon',
'dashboard' => 'Startskjerm',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Wyloguj',
'logout_other_sessions' => 'Wyloguj z pozostałych sesji',
'toggleNavigation' => 'Przełącz nawigację',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Szukaj...',
'version' => 'Wersja',
'dashboard' => 'Kokpit',

View File

@@ -64,7 +64,7 @@ return [
// 'date_time' => '%B %e, %Y, @ %T',
'date_time_js' => 'DD [de] MMMM [de] YYYY, [às] HH:mm:ss',
'date_time_fns' => 'dd \'de\' MMMM \'de\' yyyy, \'às\' HH:mm:ss',
'date_time_fns_short' => 'MMMM do, yyyy @ HH:mm',
'date_time_fns_short' => 'dd/MMM/yyyy HH:mm',
// 'specific_day' => '%e %B %Y',
'specific_day_js' => 'DD [de] MMMM [de] YYYY',

View File

@@ -42,7 +42,7 @@ return [
'fatal_error' => 'Houve um erro fatal. Por favor, verifique os arquivos de log em "storage/logs" ou use "docker logs -f [container]" para ver o que está acontecendo.',
'maintenance_mode' => 'Firefly III está em modo de manutenção.',
'be_right_back' => 'Volta logo!',
'check_back' => 'Firefly III is down for some necessary maintenance. Please check back in a second. If you happen to see this message on the demo site, just wait a few minutes. The database is reset every few hours.',
'check_back' => 'Firefly III está desligado para algumas manutenções necessárias. Volte em um segundo. Se acontecer de você ver esta mensagem no site de demonstração, espere alguns minutos. O banco de dados é reiniciado a cada algumas horas.',
'error_occurred' => 'Ops! Aconteceu um erro.',
'db_error_occurred' => 'Ops! Ocorreu um erro no banco de dados.',
'error_not_recoverable' => 'Infelizmente este erro não é recuperável :(. Firefly III quebrou. O erro é:',

View File

@@ -113,7 +113,7 @@ return [
'two_factor_forgot' => 'Esqueci minha autenticação em duas etapas.',
'two_factor_lost_header' => 'Perdeu sua autenticação em duas etapas?',
'two_factor_lost_intro' => 'Se você perdeu seus códigos de backup também, você tem azar. Isso não é algo que você pode corrigir a partir da interface da web. Você tem duas escolhas.',
'two_factor_lost_fix_self' => 'If you run your own instance of Firefly III, read <a href="https://docs.firefly-iii.org/references/faq/firefly-iii/using/#i-lost-my-2fa-token-generator-or-2fa-has-stopped-working">this entry in the FAQ</a> for instructions.',
'two_factor_lost_fix_self' => 'Se você roda sua própria instância do Firefly III, leia <a href="https://docs.firefly-iii.org/references/faq/firefly-iii/using/#i-lost-my-2fa-token-generator-or-2fa-has-stopped-working>esta seção no FAQ</a> para instruções.',
'two_factor_lost_fix_owner' => 'Caso contrário, entre em contato com o proprietário do site, <a href="mailto::site_owner">:site_owner</a>, e peça que redefina sua autenticação de duas etapas.',
'mfa_backup_code' => 'Você usou um código de backup para acessar o Firefly III. Não pode ser usado novamente, então cruze-o na sua lista.',
'pref_two_factor_new_backup_codes' => 'Obter novos códigos de backup',
@@ -317,8 +317,8 @@ return [
'update_new_version_alert' => 'Uma nova versão do Firefly lll está disponível. Você está utilizando a versão :your_version, e a nova é a :new_version, que foi lançada no dia :date.',
'update_version_beta' => 'Esta versão é uma versão BETA. Você pode encontrar problemas.',
'update_version_alpha' => 'Esta versão é uma versão ALPHA. Você pode encontrar problemas.',
'update_current_dev_older' => 'You are running development release ":version", which is older than the latest release :new_version. Please update!',
'update_current_dev_newer' => 'You are running development release ":version", which is newer than the latest release :new_version.',
'update_current_dev_older' => 'Você está executando a versão de desenvolvimento ":version", que é mais antiga que o último lançamento :new_version. Por favor, atualize!',
'update_current_dev_newer' => 'Você está executando a versão de desenvolvimento ":version", que é mais recente que o último lançamento :new_version.',
'update_current_version_alert' => 'Você está utilizando a versão :version, que é a última disponível.',
'update_newer_version_alert' => 'Você está utilizando a versão :your_version, que é mais nova do que a mais recente :new_version.',
'update_check_error' => 'Ocorreu um erro durante a verificação de atualizações: :error',
@@ -896,12 +896,12 @@ return [
'rule_trigger_budget_is' => 'O orçamento é ":trigger_value"',
'rule_trigger_tag_is_choice' => 'Qualquer tag é..',
'rule_trigger_tag_is' => 'Qualquer tag é ":trigger_value"',
'rule_trigger_tag_contains_choice' => 'Any tag contains..',
'rule_trigger_tag_contains' => 'Any tag contains ":trigger_value"',
'rule_trigger_tag_ends_choice' => 'Any tag ends with..',
'rule_trigger_tag_ends' => 'Any tag ends with ":trigger_value"',
'rule_trigger_tag_starts_choice' => 'Any tag starts with..',
'rule_trigger_tag_starts' => 'Any tag starts with ":trigger_value"',
'rule_trigger_tag_contains_choice' => 'Qualquer tag contém..',
'rule_trigger_tag_contains' => 'Qualquer tag contém ":trigger_value"',
'rule_trigger_tag_ends_choice' => 'Qualquer tag termina com..',
'rule_trigger_tag_ends' => 'Qualquer tag termina com ":trigger_value"',
'rule_trigger_tag_starts_choice' => 'Qualquer tag começa com..',
'rule_trigger_tag_starts' => 'Qualquer tag começa com ":trigger_value"',
'rule_trigger_currency_is_choice' => 'A moeda da transação é..',
'rule_trigger_currency_is' => 'A moeda da transação é ":trigger_value"',
'rule_trigger_foreign_currency_is_choice' => 'A moeda estrangeira da transação é...',
@@ -1203,7 +1203,7 @@ return [
'rule_trigger_not_exists' => 'Transação não existe',
'rule_trigger_not_has_attachments' => 'A transação não tem anexos',
'rule_trigger_not_has_any_category' => 'A transação não tem categoria',
'rule_trigger_not_has_any_budget' => 'Transaction has no budget',
'rule_trigger_not_has_any_budget' => 'A transação não tem orçamento',
'rule_trigger_not_has_any_bill' => 'A transação não tem nenhuma fatura',
'rule_trigger_not_has_any_tag' => 'A transação não tem tags',
'rule_trigger_not_any_notes' => 'A transação não tem notas',
@@ -1286,8 +1286,8 @@ return [
'rule_action_append_notes_to_descr' => 'Adicionar notas à descrição',
'rule_action_move_descr_to_notes' => 'Substituir notas por descrição',
'rule_action_move_notes_to_descr' => 'Substituir descrição por notas',
'rule_action_set_amount_choice' => 'Set amount to ..',
'rule_action_set_amount' => 'Set amount to ":action_value"',
'rule_action_set_amount_choice' => 'Definir valor para ..',
'rule_action_set_amount' => 'Definir valor para ":action_value"',
'rule_action_set_destination_to_cash_choice' => 'Definir a conta destino para (dinheiro)',
'rule_action_set_source_to_cash_choice' => 'Definir a conta de ativo para (dinheiro)',
'rulegroup_for_bills_title' => 'Grupo de regras para faturas',
@@ -1419,34 +1419,34 @@ return [
// Financial administrations
'administration_index' => 'Administração financeira',
'administrations_index_menu' => 'Administração(ões) financeira(s)',
'administrations_breadcrumb' => 'Financial administrations',
'administrations_page_title' => 'Financial administrations',
'administrations_page_sub_title' => 'Overview',
'create_administration' => 'Create new administration',
'administration_owner' => 'Administration owner: {{email}}',
'administration_you' => 'Your role: {{role}}',
'other_users_in_admin' => 'Other users in this administration',
'administrations_create_breadcrumb' => 'Create new financial administration',
'administrations_page_create_sub_title' => 'Create new financial administration',
'basic_administration_information' => 'Basic administration information',
'new_administration_created' => 'New financial administration "{{title}}" has been created',
'edit_administration_breadcrumb' => 'Edit financial administration ":title"',
'administrations_page_edit_sub_title' => 'Edit financial administration ":title"',
'administrations_breadcrumb' => 'Administrações financeira',
'administrations_page_title' => 'Administrações financeiras',
'administrations_page_sub_title' => 'Visão Geral',
'create_administration' => 'Criar nova administração',
'administration_owner' => 'Proprietário da administração: {{email}}',
'administration_you' => 'Sua função: {{role}}',
'other_users_in_admin' => 'Outros usuários nesta administração',
'administrations_create_breadcrumb' => 'Criar nova administração financeira',
'administrations_page_create_sub_title' => 'Criar nova administração financeira',
'basic_administration_information' => 'Informações básicas da administração',
'new_administration_created' => 'Nova administração financeira "{{title}}" foi criada',
'edit_administration_breadcrumb' => 'Editar administração financeira ":title"',
'administrations_page_edit_sub_title' => 'Editar administração financeira ":title"',
// roles
'administration_role_owner' => 'Owner',
'administration_role_ro' => 'Read-only',
'administration_role_mng_trx' => 'Manage transactions',
'administration_role_mng_meta' => 'Manage classification and meta-data',
'administration_role_mng_budgets' => 'Manage budgets',
'administration_role_mng_piggies' => 'Manage piggy banks',
'administration_role_mng_subscriptions' => 'Manage subscriptions',
'administration_role_mng_rules' => 'Manage rules',
'administration_role_mng_recurring' => 'Manage recurring transactions ',
'administration_role_mng_webhooks' => 'Manage webhooks',
'administration_role_mng_currencies' => 'Manage currencies',
'administration_role_view_reports' => 'View reports',
'administration_role_full' => 'Full access',
'administration_role_owner' => 'Proprietário',
'administration_role_ro' => 'Somente leitura',
'administration_role_mng_trx' => 'Gerenciar transações',
'administration_role_mng_meta' => 'Gerenciar classificação e metadados',
'administration_role_mng_budgets' => 'Gerenciar orçamentos',
'administration_role_mng_piggies' => 'Gerenciar cofrinhos',
'administration_role_mng_subscriptions' => 'Gerenciar assinaturas',
'administration_role_mng_rules' => 'Gerenciar regras',
'administration_role_mng_recurring' => 'Gerenciar transações recorrentes ',
'administration_role_mng_webhooks' => 'Gerenciar webhooks',
'administration_role_mng_currencies' => 'Gerenciar moedas',
'administration_role_view_reports' => 'Ver relatórios',
'administration_role_full' => 'Acesso completo',
// profile:
'purge_data_title' => 'Expurgar dados do Firefly III',
@@ -1616,8 +1616,8 @@ return [
'submission_options' => 'Opções de envio',
'apply_rules_checkbox' => 'Aplicar regras',
'fire_webhooks_checkbox' => 'Acionar webhooks',
'select_source_account' => 'Please select or type a valid source account name',
'select_dest_account' => 'Please select or type a valid destination account name',
'select_source_account' => 'Por favor, selecione ou digite um nome de conta de origem válido',
'select_dest_account' => 'Por favor, selecione ou digite um nome de conta de destino válido',
// convert stuff:
'convert_is_already_type_Withdrawal' => 'Esta transação já é uma saída',
@@ -2017,7 +2017,7 @@ return [
'deleted_transfer' => 'Transferência ":description" excluída com sucesso',
'deleted_reconciliation' => 'Transação de reconciliação ":description" excluída com sucesso',
'stored_journal' => 'Transação ":description" incluída com sucesso',
'stored_journal_js' => 'Successfully created new transaction "{{description}}"',
'stored_journal_js' => 'Transação "{{description}}" criada com sucesso',
'stored_journal_no_descr' => 'Transação criada com sucesso',
'updated_journal_no_descr' => 'Transação atualizada com sucesso',
'select_transactions' => 'Selecione as transações',
@@ -2144,6 +2144,7 @@ return [
'logout' => 'Desconectar',
'logout_other_sessions' => 'Sair de todas as outras sessões',
'toggleNavigation' => 'Alternar navegação',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Pesquisar...',
'version' => 'Versão',
'dashboard' => 'Painel de Controle',
@@ -2325,7 +2326,7 @@ return [
'description' => 'Descrição',
'sum_of_period' => 'Soma de período',
'average_in_period' => 'Média do período',
'no_account_role' => '(no role)',
'no_account_role' => '(sem função)',
'account_role_defaultAsset' => 'Conta padrão',
'account_role_sharedAsset' => 'Contas de ativos compartilhadas',
'account_role_savingAsset' => 'Conta poupança',
@@ -2490,7 +2491,7 @@ return [
'block_code_bounced' => 'Mensagem(s) de email devolvidas',
'block_code_expired' => 'Conta de demonstração expirada',
'no_block_code' => 'Nenhuma razão para o bloqueio ou o usuário não está bloqueado',
'demo_user_export' => 'The demo user cannot export data',
'demo_user_export' => 'O usuário de demonstração não pode exportar dados',
'block_code_email_changed' => 'O usuário ainda não confirmou o novo endereço de e-mail',
'admin_update_email' => 'Ao contrário da página de perfil, o usuário NÃO será notificado de que seu endereço de e-mail mudou!',
'update_user' => 'Atualizar usuário',
@@ -2598,9 +2599,9 @@ return [
'store_as_new' => 'Armazene como uma nova transação em vez de atualizar.',
'reset_after' => 'Limpar o formulário após o envio',
'errors_submission' => 'Algo deu errado com seu envio. Por favor, verifique os erros abaixo.',
'errors_submission_v2' => 'There was something wrong with your submission. Please check out the errors below: {{errorMessage}}',
'errors_submission_v2' => 'Algo deu errado com seu envio. Por favor, verifique os erros abaixo: {{errorMessage}}',
'transaction_expand_split' => 'Exibir divisão',
'transaction_remove_split' => 'Remove split',
'transaction_remove_split' => 'Remover divisão',
'transaction_collapse_split' => 'Esconder divisão',
// object groups
@@ -2800,7 +2801,7 @@ return [
'ale_action_add_to_piggy' => 'Cofrinho',
'ale_action_remove_from_piggy' => 'Cofrinho',
'ale_action_add_tag' => 'Tag adicionada',
'ale_action_update_amount' => 'Updated amount',
'ale_action_update_amount' => 'Valor atualizado',
// dashboard
'enable_auto_convert' => 'Habilitar conversão de moeda',

View File

@@ -70,5 +70,5 @@ return [
'cannot_find_budget' => 'O Firefly III não pode encontrar o orçamento ":name"',
'cannot_find_category' => 'O Firefly III não pode encontrar a categoria ":name"',
'cannot_set_budget' => 'O Firefly III não pode definir o orçamento ":name" à transação de tipo ":type"',
'journal_invalid_amount' => 'Firefly III can\'t set amount ":amount" because it is not a valid number.',
'journal_invalid_amount' => 'Firefly III não pode definir o valor ":amount" porque não é um número válido.',
];

View File

@@ -55,11 +55,11 @@ return [
'reconciled_forbidden_field' => 'Esta transação já está reconciliada, você não pode mudar o campo ":field"',
'deleted_user' => 'Devido a restrições de segurança, você não pode se registrar usando este endereço de e-mail.',
'rule_trigger_value' => 'Este valor é inválido para o disparo selecionado.',
'rule_action_expression' => 'Invalid expression. :error',
'rule_action_expression' => 'Expressão inválida. :error',
'rule_action_value' => 'Este valor é inválido para a ação selecionada.',
'file_already_attached' => 'Arquivo ":name" carregado já está anexado para este objeto.',
'file_attached' => 'Arquivo carregado com sucesso ":name".',
'file_zero' => 'The file is zero bytes in size.',
'file_zero' => 'O arquivo tem zero byte de tamanho.',
'must_exist' => 'O ID no campo :attribute não existe no banco de dados.',
'all_accounts_equal' => 'Todas as contas neste campo devem ser iguais.',
'group_title_mandatory' => 'Um título de grupo é obrigatório quando existe mais de uma transação.',
@@ -68,8 +68,8 @@ return [
'invalid_selection' => 'Sua seleção é inválida.',
'belongs_user' => 'Este valor está vinculado a um objeto que aparentemente não existe.',
'belongs_user_or_user_group' => 'Este valor está ligado a um objeto que aparentemente não existe na sua administração financeira atual.',
'no_access_group' => 'The user has no access to this user group.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.',
'no_access_group' => 'O usuário não tem acesso a este grupo de usuários.',
'no_accepted_roles_defined' => 'Nenhuma função de acesso foi definida para esta rota, acesso negado.',
'at_least_one_transaction' => 'Precisa de ao menos uma transação.',
'recurring_transaction_id' => 'Precisa de ao menos uma transação.',
'need_id_to_match' => 'Você precisa enviar esta entrada com um ID para a API poder identificá-la.',
@@ -199,7 +199,7 @@ return [
*
*/
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password',
'secure_password' => 'Esta não é uma senha segura. Por favor, tente novamente. Para mais informações, visite https://bit.ly/FF3-password',
'valid_recurrence_rep_type' => 'Tipo de repetição inválido para transações recorrentes.',
'valid_recurrence_rep_moment' => 'Momento de repetição inválido para esse tipo de repetição.',
'invalid_account_info' => 'Informação de conta inválida.',
@@ -302,7 +302,7 @@ return [
// no access to administration:
'no_access_user_group' => 'Você não direitos de acesso suficientes para esta administração.',
'administration_owner_rename' => 'You can\'t rename your standard administration.',
'administration_owner_rename' => 'Você não pode renomear sua administração padrão.',
];
/*

View File

@@ -64,7 +64,7 @@ return [
// 'date_time' => '%B %e, %Y, @ %T',
'date_time_js' => 'DD [de] MMMM [de] YYYY, @ HH:mm:ss',
'date_time_fns' => 'DO [de] MMMM YYYY, @ HH:mm:ss',
'date_time_fns_short' => 'MMMM do, yyyy @ HH:mm',
'date_time_fns_short' => 'do MMMM yyyy @ HH:mm',
// 'specific_day' => '%e %B %Y',
'specific_day_js' => 'D MMMM YYYY',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Terminar Sessão',
'logout_other_sessions' => 'Terminar todas as outras sessões',
'toggleNavigation' => 'Mostrar/esconder navegação',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Pesquisar...',
'version' => 'Versão',
'dashboard' => 'Painel de controlo',

View File

@@ -55,11 +55,11 @@ return [
'reconciled_forbidden_field' => 'Esta transação já está reconciliada, não pode alterar o ":field"',
'deleted_user' => 'Devido a motivos de segurança, não se pode registar com este email.',
'rule_trigger_value' => 'Este valor é inválido para o gatilho selecionado.',
'rule_action_expression' => 'Invalid expression. :error',
'rule_action_expression' => 'Expressão inválida. :error',
'rule_action_value' => 'Este valor é inválido para a ação selecionada.',
'file_already_attached' => 'O ficheiro ":name" carregado já está anexado a este objeto.',
'file_attached' => 'Ficheiro carregado com sucesso ":name".',
'file_zero' => 'The file is zero bytes in size.',
'file_zero' => 'O tamanho do ficheiro é nulo.',
'must_exist' => 'O ID no campo :attribute não existe na base de dados.',
'all_accounts_equal' => 'Todas as contas neste campo têm de ser iguais.',
'group_title_mandatory' => 'Um título de grupo é obrigatório quando existe mais de uma transação.',
@@ -68,8 +68,8 @@ return [
'invalid_selection' => 'A sua seleção é invalida.',
'belongs_user' => 'Esse valor está ligado a um objeto que parece não existir.',
'belongs_user_or_user_group' => 'Esse valor está ligado a um objeto que parece não existir na sua administração financeira atual.',
'no_access_group' => 'The user has no access to this user group.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.',
'no_access_group' => 'O utilizador não tem acesso a este grupo.',
'no_accepted_roles_defined' => 'Nenhum acesso foi definido para este endpoint, acesso recusado.',
'at_least_one_transaction' => 'Necessita pelo menos de uma transação.',
'recurring_transaction_id' => 'Precisa de pelo menos uma transação.',
'need_id_to_match' => 'Precisa de enviar esta entrada com um ID para corresponder com a API.',
@@ -199,7 +199,7 @@ return [
*
*/
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password',
'secure_password' => 'Palavra-passe não é segura. Por favor, tente novamente. Para mais informações visite https://bit.ly/FF3-password',
'valid_recurrence_rep_type' => 'Tipo de repetição inválido para transações recorrentes.',
'valid_recurrence_rep_moment' => 'Momento inválido para este tipo de repetição.',
'invalid_account_info' => 'Informação de conta inválida.',
@@ -302,7 +302,7 @@ return [
// no access to administration:
'no_access_user_group' => 'Não tem as permissões de acesso necessárias para esta administração.',
'administration_owner_rename' => 'You can\'t rename your standard administration.',
'administration_owner_rename' => 'Não pode modificar o nome da sua administração padrão.',
];
/*

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Ieșire',
'logout_other_sessions' => 'Deconectează toate celelalte sesiuni',
'toggleNavigation' => 'Navigare',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Cautare...',
'version' => 'Versiunea',
'dashboard' => 'Panou de control',

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