mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-02-14 15:55:45 +00:00
Compare commits
17 Commits
develop-20
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c9dac831a | ||
|
|
e605ddb779 | ||
|
|
4b19ed8f07 | ||
|
|
57bd8e09d4 | ||
|
|
32f1a7c9c2 | ||
|
|
fc5b0db43f | ||
|
|
c2721f3f48 | ||
|
|
96291c9bce | ||
|
|
ab9400aaee | ||
|
|
31d1ee11cb | ||
|
|
694dc3816c | ||
|
|
c647fa7b94 | ||
|
|
022d59bfdd | ||
|
|
057b82b471 | ||
|
|
2872c6592f | ||
|
|
fa02c15f55 | ||
|
|
c74c8a96b8 |
62
.ci/php-cs-fixer/composer.lock
generated
62
.ci/php-cs-fixer/composer.lock
generated
@@ -402,16 +402,16 @@
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.93.1",
|
||||
"version": "v3.94.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "b3546ab487c0762c39f308dc1ec0ea2c461fc21a"
|
||||
"reference": "883b20fb38c7866de9844ab6d0a205c423bde2d4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/b3546ab487c0762c39f308dc1ec0ea2c461fc21a",
|
||||
"reference": "b3546ab487c0762c39f308dc1ec0ea2c461fc21a",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/883b20fb38c7866de9844ab6d0a205c423bde2d4",
|
||||
"reference": "883b20fb38c7866de9844ab6d0a205c423bde2d4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -428,7 +428,7 @@
|
||||
"react/event-loop": "^1.5",
|
||||
"react/socket": "^1.16",
|
||||
"react/stream": "^1.4",
|
||||
"sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
|
||||
"sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0 || ^8.0",
|
||||
"symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0",
|
||||
"symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
|
||||
"symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0",
|
||||
@@ -442,18 +442,18 @@
|
||||
"symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"facile-it/paraunit": "^1.3.1 || ^2.7",
|
||||
"infection/infection": "^0.32",
|
||||
"justinrainbow/json-schema": "^6.6",
|
||||
"facile-it/paraunit": "^1.3.1 || ^2.7.1",
|
||||
"infection/infection": "^0.32.3",
|
||||
"justinrainbow/json-schema": "^6.6.4",
|
||||
"keradus/cli-executor": "^2.3",
|
||||
"mikey179/vfsstream": "^1.6.12",
|
||||
"php-coveralls/php-coveralls": "^2.9",
|
||||
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
|
||||
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
|
||||
"phpunit/phpunit": "^9.6.31 || ^10.5.60 || ^11.5.48",
|
||||
"php-coveralls/php-coveralls": "^2.9.1",
|
||||
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.7",
|
||||
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.7",
|
||||
"phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.51",
|
||||
"symfony/polyfill-php85": "^1.33",
|
||||
"symfony/var-dumper": "^5.4.48 || ^6.4.26 || ^7.4.0 || ^8.0",
|
||||
"symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0"
|
||||
"symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.4",
|
||||
"symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "For handling output formats in XML",
|
||||
@@ -494,7 +494,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.93.1"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -502,7 +502,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-28T23:50:50+00:00"
|
||||
"time": "2026-02-11T16:44:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
@@ -1185,29 +1185,29 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "7.0.0",
|
||||
"version": "8.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "7ab1ea946c012266ca32390913653d844ecd085f"
|
||||
"reference": "a2b6d09d7729ee87d605a439469f9dcc39be5ea3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f",
|
||||
"reference": "7ab1ea946c012266ca32390913653d844ecd085f",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/a2b6d09d7729ee87d605a439469f9dcc39be5ea3",
|
||||
"reference": "a2b6d09d7729ee87d605a439469f9dcc39be5ea3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.3"
|
||||
"php": ">=8.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^12.0",
|
||||
"phpunit/phpunit": "^13.0",
|
||||
"symfony/process": "^7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "7.0-dev"
|
||||
"dev-main": "8.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -1240,15 +1240,27 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||
"security": "https://github.com/sebastianbergmann/diff/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/7.0.0"
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/8.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sebastianbergmann",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/sebastianbergmann",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/sebastianbergmann",
|
||||
"type": "thanks_dev"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/sebastian/diff",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-07T04:55:46+00:00"
|
||||
"time": "2026-02-06T04:42:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace FireflyIII\Console\Commands\Integrity;
|
||||
|
||||
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ValidatesFilePermissions extends Command
|
||||
{
|
||||
@@ -50,26 +51,39 @@ class ValidatesFilePermissions extends Command
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
Log::debug(sprintf('Start of %s', $this->signature));
|
||||
$directories = [storage_path('upload')];
|
||||
$errors = false;
|
||||
|
||||
/** @var string $directory */
|
||||
foreach ($directories as $directory) {
|
||||
Log::debug(sprintf('Processing directory: %s', $directory));
|
||||
if (!is_dir($directory)) {
|
||||
$this->friendlyError(sprintf('Directory "%s" cannot found. It is necessary to allow files to be uploaded.', $directory));
|
||||
$errors = true;
|
||||
$message = sprintf('Directory "%s" cannot found. It is necessary to allow files to be uploaded.', $directory);
|
||||
Log::error($message);
|
||||
$this->friendlyError($message);
|
||||
$errors = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
Log::debug('It is a directory!');
|
||||
if (!is_writable($directory)) {
|
||||
$this->friendlyError(sprintf('Directory "%s" is not writeable. Uploading attachments may fail silently.', $directory));
|
||||
$errors = true;
|
||||
$message = sprintf('Directory "%s" is not writeable. Uploading attachments may fail silently.', $directory);
|
||||
$this->friendlyError($message);
|
||||
Log::error($message);
|
||||
$errors = true;
|
||||
}
|
||||
Log::debug('It is writeable!');
|
||||
Log::debug(sprintf('Done processing %s', $directory));
|
||||
}
|
||||
Log::debug('Done with loop.');
|
||||
if (false === $errors) {
|
||||
Log::debug('No errors.');
|
||||
$this->friendlyInfo('All necessary file paths seem to exist, and are writeable.');
|
||||
}
|
||||
|
||||
Log::debug(sprintf('End of %s', $this->signature));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
42
app/Events/Model/Bill/UpdatedExistingBill.php
Normal file
42
app/Events/Model/Bill/UpdatedExistingBill.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* UpdatedExistingBill.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Events\Model\Bill;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\Bill;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class UpdatedExistingBill extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct(
|
||||
public Bill $bill,
|
||||
public array $oldData
|
||||
) {}
|
||||
}
|
||||
@@ -103,10 +103,11 @@ class IndexController extends Controller
|
||||
$firstJournal = $this->repository->firstNull();
|
||||
$startPeriod = $firstJournal instanceof TransactionJournal ? $firstJournal->date : new Carbon();
|
||||
$endPeriod = clone $end;
|
||||
|
||||
// limit to 3 years for the time being.
|
||||
if (now()->diffInYears($startPeriod, true) > 3) {
|
||||
$startPeriod = now()->subYears(3);
|
||||
$endPeriod->endOfDay();
|
||||
// limit to 6 years for the time being.
|
||||
$max = 6;
|
||||
if (now()->diffInYears($startPeriod, true) > $max) {
|
||||
$startPeriod = now()->subYears($max);
|
||||
}
|
||||
|
||||
$periods = $this->getTransactionPeriodOverview($objectType, $startPeriod, $endPeriod);
|
||||
|
||||
81
app/Listeners/Model/Bill/UpdatesRulesForChangedBill.php
Normal file
81
app/Listeners/Model/Bill/UpdatesRulesForChangedBill.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* UpdatesRulesForChangedBill.php
|
||||
* Copyright (c) 2026 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Listeners\Model\Bill;
|
||||
|
||||
use FireflyIII\Events\Model\Bill\UpdatedExistingBill;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Rule;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\RuleTrigger;
|
||||
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class UpdatesRulesForChangedBill implements ShouldQueue
|
||||
{
|
||||
public function handle(UpdatedExistingBill $event): void
|
||||
{
|
||||
// update rule actions.
|
||||
if ($event->bill->name !== $event->oldData['name']) {
|
||||
$this->updateBillTriggersAndActions($event->bill, $event->oldData);
|
||||
}
|
||||
}
|
||||
|
||||
private function updateBillTriggersAndActions(Bill $bill, array $oldData): void
|
||||
{
|
||||
Log::debug(sprintf('Now in updateBillTriggersAndActions(#%d)', $bill->id));
|
||||
$repository = app(RuleRepositoryInterface::class);
|
||||
$repository->setUser($bill->user);
|
||||
$rules = $repository->getAll();
|
||||
|
||||
/** @var Rule $rule */
|
||||
foreach ($rules as $rule) {
|
||||
$this->updateRule($bill, $rule, $oldData);
|
||||
}
|
||||
}
|
||||
|
||||
private function updateRule(Bill $bill, Rule $rule, array $oldData): void
|
||||
{
|
||||
$triggers = ['bill_is', 'bill_ends', 'bill_starts', 'bill_contains'];
|
||||
|
||||
/** @var RuleTrigger $trigger */
|
||||
foreach ($rule->ruleTriggers as $trigger) {
|
||||
if (in_array($trigger->trigger_type, $triggers, true) && $trigger->trigger_value === $oldData['name']) {
|
||||
Log::debug(sprintf('Updated trigger #%d in rule #%d to new subscription name', $trigger->id, $rule->id));
|
||||
$trigger->trigger_value = $bill->name;
|
||||
$trigger->save();
|
||||
}
|
||||
}
|
||||
|
||||
/** @var RuleAction $action */
|
||||
foreach ($rule->ruleActions as $action) {
|
||||
if ('link_to_bill' === $action->action_type && $action->action_value === $oldData['name']) {
|
||||
Log::debug(sprintf('Updated action #%d in rule #%d to new subscription name', $action->id, $rule->id));
|
||||
$action->action_value = $bill->name;
|
||||
$action->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,12 +149,10 @@ class RecalculatesPrimaryCurrencyAmounts
|
||||
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->where('transaction_journals.user_group_id', $userGroup->id)
|
||||
->where(static function (Builder $q): void {
|
||||
$q
|
||||
->whereNotNull('native_amount')
|
||||
->orWhereNotNull('native_foreign_amount')
|
||||
->orWhere('native_amount', '!=', '')
|
||||
->orWhere('native_foreign_amount', '!=', '')
|
||||
;
|
||||
$q->whereNotNull('native_amount')->orWhereNotNull('native_foreign_amount');
|
||||
if ('pgsql' !== config('database.default')) {
|
||||
$q->orWhere('native_amount', '!=', '')->orWhere('native_foreign_amount', '!=', '');
|
||||
}
|
||||
})
|
||||
->update(['native_amount' => null, 'native_foreign_amount' => null])
|
||||
;
|
||||
|
||||
@@ -96,7 +96,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
|
||||
foreach ($set as $bill) {
|
||||
if ($bill->order !== $current) {
|
||||
$bill->order = $current;
|
||||
$bill->save();
|
||||
$bill->saveQuietly();
|
||||
}
|
||||
++$current;
|
||||
}
|
||||
@@ -613,7 +613,7 @@ class BillRepository implements BillRepositoryInterface, UserGroupInterface
|
||||
public function setOrder(Bill $bill, int $order): void
|
||||
{
|
||||
$bill->order = $order;
|
||||
$bill->save();
|
||||
$bill->saveQuietly();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,9 @@ class PeriodStatisticRepository implements PeriodStatisticRepositoryInterface, U
|
||||
#[Override]
|
||||
public function allInRangeForPrefix(string $prefix, Carbon $start, Carbon $end): Collection
|
||||
{
|
||||
Log::debug(sprintf('Collect all statistics where type starts with "%s"', $prefix));
|
||||
Log::debug(sprintf('Between %s and %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||
|
||||
return $this->userGroup
|
||||
->periodStatistics()
|
||||
->where('type', 'LIKE', sprintf('%s%%', $prefix))
|
||||
@@ -156,6 +159,7 @@ class PeriodStatisticRepository implements PeriodStatisticRepositoryInterface, U
|
||||
int $count,
|
||||
string $amount
|
||||
): PeriodStatistic {
|
||||
Log::debug(sprintf('Store as type "%s"', sprintf('%s_%s', $prefix, $type)));
|
||||
$stat = new PeriodStatistic();
|
||||
$stat->transaction_currency_id = $currencyId;
|
||||
$stat->user_group_id = $this->getUserGroup()->id;
|
||||
|
||||
@@ -102,7 +102,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
|
||||
{
|
||||
return $this->user
|
||||
->rules()
|
||||
->with(['ruleGroup'])
|
||||
->with(['ruleGroup', 'ruleTriggers', 'ruleActions'])
|
||||
->get()
|
||||
;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Rules\UniqueIban;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use Illuminate\Database\UniqueConstraintViolationException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Safe\Exceptions\JsonException;
|
||||
|
||||
@@ -227,7 +228,12 @@ trait JournalServiceTrait
|
||||
$set = array_unique($set);
|
||||
Log::debug('End of loop.');
|
||||
Log::debug(sprintf('Total nr. of tags: %d', count($tags)), $tags);
|
||||
$journal->tags()->sync($set);
|
||||
|
||||
try {
|
||||
$journal->tags()->sync($set);
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
Log::error(sprintf('Firefly III could not sync tags: %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,12 +24,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Services\Internal\Update;
|
||||
|
||||
use FireflyIII\Events\Model\Bill\UpdatedExistingBill;
|
||||
use FireflyIII\Factory\TransactionCurrencyFactory;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Models\Rule;
|
||||
use FireflyIII\Models\RuleTrigger;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups;
|
||||
use FireflyIII\Services\Internal\Support\BillServiceTrait;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
@@ -50,6 +50,7 @@ class BillUpdateService
|
||||
public function update(Bill $bill, array $data): Bill
|
||||
{
|
||||
$this->user = $bill->user;
|
||||
$oldData = $bill->toArray();
|
||||
|
||||
if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) {
|
||||
$factory = app(TransactionCurrencyFactory::class);
|
||||
@@ -68,13 +69,6 @@ class BillUpdateService
|
||||
$bill = $this->updateBillProperties($bill, $data);
|
||||
$bill->save();
|
||||
$bill->refresh();
|
||||
// old values
|
||||
$oldData = [
|
||||
'name' => $bill->name,
|
||||
'amount_min' => $bill->amount_min,
|
||||
'amount_max' => $bill->amount_max,
|
||||
'transaction_currency_name' => $bill->transactionCurrency->name,
|
||||
];
|
||||
// update note:
|
||||
if (array_key_exists('notes', $data)) {
|
||||
$this->updateNote($bill, (string) $data['notes']);
|
||||
@@ -90,12 +84,6 @@ class BillUpdateService
|
||||
}
|
||||
}
|
||||
|
||||
// update rule actions.
|
||||
if (array_key_exists('name', $data)) {
|
||||
$this->updateBillActions($bill, $oldData['name'], $data['name']);
|
||||
$this->updateBillTriggers($bill, $oldData, $data);
|
||||
}
|
||||
|
||||
// update using name:
|
||||
if (array_key_exists('object_group_title', $data)) {
|
||||
$objectGroupTitle = $data['object_group_title'] ?? '';
|
||||
@@ -127,6 +115,7 @@ class BillUpdateService
|
||||
$bill->objectGroups()->sync([]);
|
||||
$bill->save();
|
||||
}
|
||||
event(new UpdatedExistingBill($bill, $oldData));
|
||||
|
||||
return $bill;
|
||||
}
|
||||
@@ -181,39 +170,6 @@ class BillUpdateService
|
||||
return $bill;
|
||||
}
|
||||
|
||||
private function updateBillTriggers(Bill $bill, array $oldData, array $newData): void
|
||||
{
|
||||
Log::debug(sprintf('Now in updateBillTriggers(%d, "%s")', $bill->id, $bill->name));
|
||||
|
||||
/** @var BillRepositoryInterface $repository */
|
||||
$repository = app(BillRepositoryInterface::class);
|
||||
$repository->setUser($bill->user);
|
||||
$rules = $repository->getRulesForBill($bill);
|
||||
if (0 === $rules->count()) {
|
||||
Log::debug('Found no rules.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::debug(sprintf('Found %d rules', $rules->count()));
|
||||
$fields = [
|
||||
'name' => 'description_contains',
|
||||
'amount_min' => 'amount_more',
|
||||
'amount_max' => 'amount_less',
|
||||
'transaction_currency_name' => 'currency_is',
|
||||
];
|
||||
foreach ($fields as $field => $ruleTriggerKey) {
|
||||
if (!array_key_exists($field, $newData)) {
|
||||
continue;
|
||||
}
|
||||
if ($oldData[$field] === $newData[$field]) {
|
||||
Log::debug(sprintf('Field %s is unchanged ("%s"), continue.', $field, $oldData[$field]));
|
||||
|
||||
continue;
|
||||
}
|
||||
$this->updateRules($rules, $ruleTriggerKey, $oldData[$field], $newData[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
private function updateOrder(Bill $bill, int $oldOrder, int $newOrder): void
|
||||
{
|
||||
if ($newOrder > $oldOrder) {
|
||||
|
||||
@@ -40,6 +40,7 @@ class RemoteUserGuard implements Guard
|
||||
{
|
||||
protected Application $application;
|
||||
protected ?User $user = null;
|
||||
private $tried = false;
|
||||
|
||||
/**
|
||||
* Create a new authentication guard.
|
||||
@@ -49,13 +50,14 @@ class RemoteUserGuard implements Guard
|
||||
Application $app
|
||||
) {
|
||||
$app->get('request');
|
||||
// Log::debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri()));
|
||||
Log::debug(sprintf('Created RemoteUserGuard for %s "%s"', $app->get('request')?->getMethod(), $app->get('request')?->getRequestUri()));
|
||||
$this->application = $app;
|
||||
}
|
||||
|
||||
public function authenticate(): void
|
||||
{
|
||||
// Log::debug(sprintf('Now at %s', __METHOD__));
|
||||
$this->tried = true;
|
||||
Log::debug(sprintf('Now at %s', __METHOD__));
|
||||
if ($this->user instanceof User) {
|
||||
Log::debug(sprintf('%s is found: #%d, "%s".', $this->user::class, $this->user->id, $this->user->email));
|
||||
|
||||
@@ -70,6 +72,9 @@ class RemoteUserGuard implements Guard
|
||||
$userID = request()->server($header) ?? apache_request_headers()[$header] ?? null;
|
||||
}
|
||||
|
||||
// test value for development
|
||||
// $userID = 'james@firefly';
|
||||
|
||||
if (null === $userID || '' === $userID) {
|
||||
Log::error(sprintf('No user in header "%s".', $header));
|
||||
|
||||
@@ -145,8 +150,13 @@ class RemoteUserGuard implements Guard
|
||||
|
||||
public function user(): ?User
|
||||
{
|
||||
if (false === $this->tried) {
|
||||
Log::debug('Have not tried authentication, do it now.');
|
||||
$this->authenticate();
|
||||
}
|
||||
// Log::debug(sprintf('Now at %s', __METHOD__));
|
||||
$user = $this->user;
|
||||
|
||||
if (!$user instanceof User) {
|
||||
Log::debug('User is NULL');
|
||||
|
||||
|
||||
@@ -47,6 +47,10 @@ class Calculator
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private static array $intervals = [];
|
||||
|
||||
public function isAvailablePeriodicity(Periodicity $periodicity): bool
|
||||
|
||||
@@ -112,6 +112,14 @@ class ExportDataGenerator
|
||||
|
||||
// @phpstan-ignore-line
|
||||
|
||||
// @phpstan-ignore-line
|
||||
|
||||
// @phpstan-ignore-line
|
||||
|
||||
// @phpstan-ignore-line
|
||||
|
||||
// @phpstan-ignore-line
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->accounts = new Collection();
|
||||
|
||||
@@ -37,7 +37,6 @@ use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\PeriodStatistic\PeriodStatisticRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Navigation;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
@@ -80,41 +79,8 @@ trait PeriodOverview
|
||||
protected TagRepositoryInterface $tagRepository;
|
||||
protected JournalRepositoryInterface $journalRepos;
|
||||
protected PeriodStatisticRepositoryInterface $periodStatisticRepo;
|
||||
private Collection $statistics; // temp data holder
|
||||
// temp data holder
|
||||
// temp data holder
|
||||
// temp data holder
|
||||
// temp data holder
|
||||
// temp data holder
|
||||
// temp data holder
|
||||
// temp data holder
|
||||
// temp data holder
|
||||
// temp data holder
|
||||
// temp data holder
|
||||
// temp data holder
|
||||
private array $transactions; // temp data holder
|
||||
|
||||
// temp data holder
|
||||
|
||||
// temp data holder
|
||||
|
||||
// temp data holder
|
||||
|
||||
// temp data holder
|
||||
|
||||
// temp data holder
|
||||
|
||||
// temp data holder
|
||||
|
||||
// temp data holder
|
||||
|
||||
// temp data holder
|
||||
|
||||
// temp data holder
|
||||
|
||||
// temp data holder
|
||||
|
||||
// temp data holder
|
||||
private Collection $statistics;
|
||||
private array $transactions;
|
||||
|
||||
/**
|
||||
* This method returns "period entries", so nov-2015, dec-2015, etc. (this depends on the users session range)
|
||||
@@ -175,6 +141,34 @@ trait PeriodOverview
|
||||
return $entries;
|
||||
}
|
||||
|
||||
protected function getGenericPeriod(string $type, string $period, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$return = [
|
||||
'title' => Navigation::periodShow($start, $period),
|
||||
'route' => route('transactions.index', [$type, $start->format('Y-m-d'), $end->format('Y-m-d')]),
|
||||
'total_transactions' => 0,
|
||||
];
|
||||
$setTypes = [
|
||||
'withdrawal' => 'spent',
|
||||
'expenses' => 'spent',
|
||||
'deposit' => 'earned',
|
||||
'revenue' => 'earned',
|
||||
'transfer' => 'transferred',
|
||||
'transfers' => 'transferred',
|
||||
];
|
||||
if (!array_key_exists($type, $setTypes)) {
|
||||
throw new FireflyException(sprintf('[c] Cannot deal with type "%s"', $type));
|
||||
}
|
||||
$setType = $setTypes[$type];
|
||||
|
||||
$this->transactions = [];
|
||||
$set = $this->getSingleGenericPeriodByType($start, $end, $type);
|
||||
$return['total_transactions'] += $set['count'];
|
||||
$return[$setType] = $set;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above, but for lists that involve transactions without a budget.
|
||||
*
|
||||
@@ -260,60 +254,18 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$range = Navigation::getViewRange(true);
|
||||
$types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType));
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
// properties for cache
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('transactions-period-entries');
|
||||
$cache->addProperty($transactionType);
|
||||
if ($cache->has()) {
|
||||
return $cache->get();
|
||||
}
|
||||
$this->periodStatisticRepo = app(PeriodStatisticRepositoryInterface::class);
|
||||
$range = Navigation::getViewRange(true);
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
/** @var array $dates */
|
||||
$dates = Navigation::blockPeriods($start, $end, $range);
|
||||
$entries = [];
|
||||
$spent = [];
|
||||
$earned = [];
|
||||
$transferred = [];
|
||||
// collect all journals in this period (regardless of type)
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setTypes($types)->setRange($start, $end);
|
||||
$genericSet = $collector->getExtractedJournals();
|
||||
$loops = 0;
|
||||
$dates = Navigation::blockPeriods($start, $end, $range);
|
||||
$entries = [];
|
||||
$this->statistics = $this->periodStatisticRepo->allInRangeForPrefix('all_', $start, $end);
|
||||
Log::debug(sprintf('Collected %d statistics', $this->statistics->count()));
|
||||
|
||||
foreach ($dates as $currentDate) {
|
||||
$title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
|
||||
|
||||
if ($loops < 10) {
|
||||
// set to correct array
|
||||
if ('expenses' === $transactionType || 'withdrawal' === $transactionType) {
|
||||
$spent = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
|
||||
}
|
||||
if ('revenue' === $transactionType || 'deposit' === $transactionType) {
|
||||
$earned = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
|
||||
}
|
||||
if ('transfer' === $transactionType || 'transfers' === $transactionType) {
|
||||
$transferred = $this->filterJournalsByDate($genericSet, $currentDate['start'], $currentDate['end']);
|
||||
}
|
||||
}
|
||||
$entries[] = [
|
||||
'title' => $title,
|
||||
'route' => route('transactions.index', [
|
||||
$transactionType,
|
||||
$currentDate['start']->format('Y-m-d'),
|
||||
$currentDate['end']->format('Y-m-d'),
|
||||
]),
|
||||
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
||||
'spent' => $this->groupByCurrency($spent),
|
||||
'earned' => $this->groupByCurrency($earned),
|
||||
'transferred' => $this->groupByCurrency($transferred),
|
||||
];
|
||||
++$loops;
|
||||
$entries[] = $this->getGenericPeriod($transactionType, $currentDate['period'], $currentDate['start'], $currentDate['end']);
|
||||
}
|
||||
|
||||
return $entries;
|
||||
@@ -360,10 +312,11 @@ trait PeriodOverview
|
||||
|
||||
return new Collection();
|
||||
}
|
||||
Log::debug(sprintf('Now in filterStatistics("%s")', $type));
|
||||
|
||||
return $this->statistics->filter(
|
||||
static fn (PeriodStatistic $statistic): bool => $statistic->start->eq($start) && $statistic->end->eq($end) && $statistic->type === $type
|
||||
);
|
||||
return $this->statistics->filter(static function (PeriodStatistic $statistic) use ($start, $end, $type): bool {
|
||||
return $statistic->start->isSameSecond($start) && $statistic->end->isSameSecond($end) && $statistic->type === $type;
|
||||
});
|
||||
}
|
||||
|
||||
private function filterTransactionsByType(TransactionTypeEnum $type, Carbon $start, Carbon $end): array
|
||||
@@ -425,21 +378,63 @@ trait PeriodOverview
|
||||
return [$start, $end];
|
||||
}
|
||||
|
||||
private function getSingleGenericPeriodByType(Carbon $start, Carbon $end, string $type): array
|
||||
{
|
||||
$filterType = sprintf('all_%s', $type);
|
||||
$statistics = $this->filterStatistics($start, $end, $filterType);
|
||||
$types = config(sprintf('firefly.transactionTypesByType.%s', $type));
|
||||
// nothing found, regenerate them.
|
||||
if (0 === $statistics->count()) {
|
||||
if (0 === count($this->transactions)) {
|
||||
// get collection!
|
||||
// collect all journals in this period (regardless of type)
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setTypes($types)->setRange($start, $end);
|
||||
$this->transactions = $collector->getExtractedJournals();
|
||||
Log::debug(sprintf('Going to group %d found journal(s)', count($types)));
|
||||
}
|
||||
|
||||
$grouped = $this->groupByCurrency($this->filterJournalsByDate($this->transactions, $start, $end));
|
||||
$this->saveGroupedForPrefix('all', $start, $end, $type, $grouped);
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
$grouped = ['count' => 0];
|
||||
|
||||
/** @var PeriodStatistic $statistic */
|
||||
foreach ($statistics as $statistic) {
|
||||
$id = (int) $statistic->transaction_currency_id;
|
||||
$currency = Amount::getTransactionCurrencyById($id);
|
||||
$grouped[$id] = [
|
||||
'amount' => (string) $statistic->amount,
|
||||
'count' => (int) $statistic->count,
|
||||
'currency_id' => $currency->id,
|
||||
'currency_name' => $currency->name,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
];
|
||||
$grouped['count'] += (int) $statistic->count;
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
private function getSingleModelPeriodByType(Model $model, Carbon $start, Carbon $end, string $type): array
|
||||
{
|
||||
Log::debug(sprintf(
|
||||
'Now in getSingleModelPeriodByType(%s #%d, %s %s, %s)',
|
||||
$model::class,
|
||||
$model->id,
|
||||
$start->format('Y-m-d'),
|
||||
$end->format('Y-m-d'),
|
||||
$start->format('Y-m-d H:i:s.u'),
|
||||
$end->format('Y-m-d H:i:s.u'),
|
||||
$type
|
||||
));
|
||||
$statistics = $this->filterStatistics($start, $end, $type);
|
||||
|
||||
// nothing found, regenerate them.
|
||||
if (0 === $statistics->count()) {
|
||||
Log::debug(sprintf('Found nothing in this period for type "%s"', $type));
|
||||
Log::debug(sprintf('Found nothing between %s and %s for type "%s"', $start->format('Y-m-d H:i:s.u'), $end->format('Y-m-d H:i:s.u'), $type));
|
||||
if (0 === count($this->transactions)) {
|
||||
switch ($model::class) {
|
||||
default:
|
||||
@@ -464,7 +459,7 @@ trait PeriodOverview
|
||||
|
||||
switch ($type) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Cannot deal with category period type %s', $type));
|
||||
throw new FireflyException(sprintf('Cannot deal with type %s', $type));
|
||||
|
||||
case 'spent':
|
||||
$result = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $start, $end);
|
||||
@@ -526,7 +521,7 @@ trait PeriodOverview
|
||||
|
||||
switch ($model) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Cannot deal with model of type "%s"', $model));
|
||||
throw new FireflyException(sprintf('[b] Cannot deal with model of type "%s"', $model));
|
||||
|
||||
case 'budget':
|
||||
// get all expenses without a budget.
|
||||
|
||||
@@ -52,6 +52,10 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private readonly bool $convertToPrimary; // @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
@@ -64,6 +68,10 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private array $currencies = [];
|
||||
private array $currencyIds = [];
|
||||
private array $ids = [];
|
||||
|
||||
@@ -52,6 +52,10 @@ class BudgetLimitEnrichment implements EnrichmentInterface
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private array $currencies = [];
|
||||
private array $currencyIds = [];
|
||||
private Carbon $end;
|
||||
|
||||
@@ -54,6 +54,10 @@ class PiggyBankEnrichment implements EnrichmentInterface
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private array $accounts = []; // @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
@@ -66,6 +70,10 @@ class PiggyBankEnrichment implements EnrichmentInterface
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private array $amounts = [];
|
||||
private Collection $collection;
|
||||
private array $currencies = [];
|
||||
|
||||
@@ -49,6 +49,10 @@ class PiggyBankEventEnrichment implements EnrichmentInterface
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private array $accountIds = []; // @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
@@ -61,6 +65,10 @@ class PiggyBankEventEnrichment implements EnrichmentInterface
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private Collection $collection;
|
||||
private array $currencies = [];
|
||||
private array $groupIds = [];
|
||||
|
||||
@@ -58,6 +58,10 @@ class SubscriptionEnrichment implements EnrichmentInterface
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private readonly bool $convertToPrimary;
|
||||
private ?Carbon $end = null;
|
||||
private array $mappedObjects = [];
|
||||
|
||||
@@ -77,6 +77,14 @@ class TransactionGroupEnrichment implements EnrichmentInterface
|
||||
|
||||
// @phpstan-ignore-line
|
||||
|
||||
// @phpstan-ignore-line
|
||||
|
||||
// @phpstan-ignore-line
|
||||
|
||||
// @phpstan-ignore-line
|
||||
|
||||
// @phpstan-ignore-line
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->dateFields = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date'];
|
||||
|
||||
@@ -54,6 +54,10 @@ class WebhookEnrichment implements EnrichmentInterface
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private array $ids = []; // @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
@@ -66,6 +70,10 @@ class WebhookEnrichment implements EnrichmentInterface
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
// @phpstan-ignore-line
|
||||
private array $responses = [];
|
||||
private array $triggers = [];
|
||||
private array $webhookDeliveries = [];
|
||||
|
||||
16
changelog.md
16
changelog.md
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## v6.4.19
|
||||
|
||||
### Added
|
||||
- The ability to undo the recording of a database migration, which may help with database issues. [See the docs](https://docs.firefly-iii.org/references/faq/firefly-iii/using/#i-get-errors-about-missing-tables-how-do-i-fix-this)
|
||||
- Added dbug logs to file permission checks
|
||||
|
||||
### Fixed
|
||||
- View range issue for subscription overview
|
||||
- Amount log entries were recorded for the transaction group, not the journal
|
||||
- Subscriptions were not being renamed in rules when their names were changed
|
||||
- [Issue 11688](https://github.com/firefly-iii/firefly-iii/issues/11688) (Token endpoints returning 401 unauthorized) reported by @molnarti
|
||||
- [Issue 11694](https://github.com/firefly-iii/firefly-iii/issues/11694) (Foreign currency amount is always positive in transfers) reported by @SledgehammerPL
|
||||
- [Issue 11684](https://github.com/firefly-iii/firefly-iii/issues/11684) (Transaction summary duplicated after more than 10 rows) reported by @jkmf
|
||||
- [Issue 11700](https://github.com/firefly-iii/firefly-iii/issues/11700) (Duplicate entry for key 'tag_transaction_journal_tag_id_transaction_journal_id_unique') reported by @beatbesmer
|
||||
- [Issue 11702](https://github.com/firefly-iii/firefly-iii/issues/11702) (Can't enable displaying primary currency when using Postgres) reported by @absdjfh
|
||||
|
||||
## v6.4.18
|
||||
|
||||
### Fixed
|
||||
|
||||
126
composer.lock
generated
126
composer.lock
generated
@@ -130,16 +130,16 @@
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.14.7",
|
||||
"version": "0.14.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/brick/math.git",
|
||||
"reference": "07ff363b16ef8aca9692bba3be9e73fe63f34e50"
|
||||
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/07ff363b16ef8aca9692bba3be9e73fe63f34e50",
|
||||
"reference": "07ff363b16ef8aca9692bba3be9e73fe63f34e50",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629",
|
||||
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -178,7 +178,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/brick/math/issues",
|
||||
"source": "https://github.com/brick/math/tree/0.14.7"
|
||||
"source": "https://github.com/brick/math/tree/0.14.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -186,7 +186,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-07T10:57:35+00:00"
|
||||
"time": "2026-02-10T14:33:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "carbonphp/carbon-doctrine-types",
|
||||
@@ -1878,16 +1878,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v12.50.0",
|
||||
"version": "v12.51.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "174ffed91d794a35a541a5eb7c3785a02a34aaba"
|
||||
"reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/174ffed91d794a35a541a5eb7c3785a02a34aaba",
|
||||
"reference": "174ffed91d794a35a541a5eb7c3785a02a34aaba",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/ce4de3feb211e47c4f959d309ccf8a2733b1bc16",
|
||||
"reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2096,7 +2096,7 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2026-02-04T18:34:13+00:00"
|
||||
"time": "2026-02-10T18:20:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/passport",
|
||||
@@ -2176,16 +2176,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/prompts",
|
||||
"version": "v0.3.12",
|
||||
"version": "v0.3.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/prompts.git",
|
||||
"reference": "4861ded9003b7f8a158176a0b7666f74ee761be8"
|
||||
"reference": "ed8c466571b37e977532fb2fd3c272c784d7050d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/prompts/zipball/4861ded9003b7f8a158176a0b7666f74ee761be8",
|
||||
"reference": "4861ded9003b7f8a158176a0b7666f74ee761be8",
|
||||
"url": "https://api.github.com/repos/laravel/prompts/zipball/ed8c466571b37e977532fb2fd3c272c784d7050d",
|
||||
"reference": "ed8c466571b37e977532fb2fd3c272c784d7050d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2229,36 +2229,36 @@
|
||||
"description": "Add beautiful and user-friendly forms to your command-line applications.",
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/prompts/issues",
|
||||
"source": "https://github.com/laravel/prompts/tree/v0.3.12"
|
||||
"source": "https://github.com/laravel/prompts/tree/v0.3.13"
|
||||
},
|
||||
"time": "2026-02-03T06:57:26+00:00"
|
||||
"time": "2026-02-06T12:17:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/sanctum",
|
||||
"version": "v4.3.0",
|
||||
"version": "v4.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/sanctum.git",
|
||||
"reference": "c978c82b2b8ab685468a7ca35224497d541b775a"
|
||||
"reference": "e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/sanctum/zipball/c978c82b2b8ab685468a7ca35224497d541b775a",
|
||||
"reference": "c978c82b2b8ab685468a7ca35224497d541b775a",
|
||||
"url": "https://api.github.com/repos/laravel/sanctum/zipball/e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76",
|
||||
"reference": "e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"illuminate/console": "^11.0|^12.0",
|
||||
"illuminate/contracts": "^11.0|^12.0",
|
||||
"illuminate/database": "^11.0|^12.0",
|
||||
"illuminate/support": "^11.0|^12.0",
|
||||
"illuminate/console": "^11.0|^12.0|^13.0",
|
||||
"illuminate/contracts": "^11.0|^12.0|^13.0",
|
||||
"illuminate/database": "^11.0|^12.0|^13.0",
|
||||
"illuminate/support": "^11.0|^12.0|^13.0",
|
||||
"php": "^8.2",
|
||||
"symfony/console": "^7.0"
|
||||
"symfony/console": "^7.0|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.6",
|
||||
"orchestra/testbench": "^9.15|^10.8",
|
||||
"orchestra/testbench": "^9.15|^10.8|^11.0",
|
||||
"phpstan/phpstan": "^1.10"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -2294,7 +2294,7 @@
|
||||
"issues": "https://github.com/laravel/sanctum/issues",
|
||||
"source": "https://github.com/laravel/sanctum"
|
||||
},
|
||||
"time": "2026-01-22T22:27:01+00:00"
|
||||
"time": "2026-02-07T17:19:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/serializable-closure",
|
||||
@@ -3894,16 +3894,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
"version": "v4.1.2",
|
||||
"version": "v4.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5"
|
||||
"reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/f76b5dc3d6c6d3043c8d937df2698515b99cbaf5",
|
||||
"reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe",
|
||||
"reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3915,8 +3915,10 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"jetbrains/phpstorm-attributes": "^1.2",
|
||||
"nette/phpstan-rules": "^1.0",
|
||||
"nette/tester": "^2.5",
|
||||
"phpstan/phpstan": "^2.0@stable",
|
||||
"phpstan/extension-installer": "^1.4@stable",
|
||||
"phpstan/phpstan": "^2.1@stable",
|
||||
"tracy/tracy": "^2.9"
|
||||
},
|
||||
"suggest": {
|
||||
@@ -3977,9 +3979,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nette/utils/issues",
|
||||
"source": "https://github.com/nette/utils/tree/v4.1.2"
|
||||
"source": "https://github.com/nette/utils/tree/v4.1.3"
|
||||
},
|
||||
"time": "2026-02-03T17:21:09+00:00"
|
||||
"time": "2026-02-13T03:05:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nunomaduro/collision",
|
||||
@@ -5120,16 +5122,16 @@
|
||||
},
|
||||
{
|
||||
"name": "predis/predis",
|
||||
"version": "v3.3.0",
|
||||
"version": "v3.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/predis/predis.git",
|
||||
"reference": "153097374b39a2f737fe700ebcd725642526cdec"
|
||||
"reference": "1183f5732e6b10efd33f64984a96726eaecb59aa"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/predis/predis/zipball/153097374b39a2f737fe700ebcd725642526cdec",
|
||||
"reference": "153097374b39a2f737fe700ebcd725642526cdec",
|
||||
"url": "https://api.github.com/repos/predis/predis/zipball/1183f5732e6b10efd33f64984a96726eaecb59aa",
|
||||
"reference": "1183f5732e6b10efd33f64984a96726eaecb59aa",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5171,7 +5173,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/predis/predis/issues",
|
||||
"source": "https://github.com/predis/predis/tree/v3.3.0"
|
||||
"source": "https://github.com/predis/predis/tree/v3.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5179,7 +5181,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-24T17:48:50+00:00"
|
||||
"time": "2026-02-11T17:30:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
@@ -11414,11 +11416,11 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.38",
|
||||
"version": "2.1.39",
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/dfaf1f530e1663aa167bc3e52197adb221582629",
|
||||
"reference": "dfaf1f530e1663aa167bc3e52197adb221582629",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224",
|
||||
"reference": "c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -11463,25 +11465,25 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-30T17:12:46+00:00"
|
||||
"time": "2026-02-11T14:48:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-deprecation-rules",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-deprecation-rules.git",
|
||||
"reference": "468e02c9176891cc901143da118f09dc9505fc2f"
|
||||
"reference": "6b5571001a7f04fa0422254c30a0017ec2f2cacc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/468e02c9176891cc901143da118f09dc9505fc2f",
|
||||
"reference": "468e02c9176891cc901143da118f09dc9505fc2f",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/6b5571001a7f04fa0422254c30a0017ec2f2cacc",
|
||||
"reference": "6b5571001a7f04fa0422254c30a0017ec2f2cacc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"phpstan/phpstan": "^2.1.15"
|
||||
"phpstan/phpstan": "^2.1.39"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
@@ -11506,29 +11508,32 @@
|
||||
"MIT"
|
||||
],
|
||||
"description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.",
|
||||
"keywords": [
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/2.0.3"
|
||||
"source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/2.0.4"
|
||||
},
|
||||
"time": "2025-05-14T10:56:57+00:00"
|
||||
"time": "2026-02-09T13:21:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
"version": "2.0.8",
|
||||
"version": "2.0.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||
"reference": "1ed9e626a37f7067b594422411539aa807190573"
|
||||
"reference": "1aba28b697c1e3b6bbec8a1725f8b11b6d3e5a5f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/1ed9e626a37f7067b594422411539aa807190573",
|
||||
"reference": "1ed9e626a37f7067b594422411539aa807190573",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/1aba28b697c1e3b6bbec8a1725f8b11b6d3e5a5f",
|
||||
"reference": "1aba28b697c1e3b6bbec8a1725f8b11b6d3e5a5f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"phpstan/phpstan": "^2.1.29"
|
||||
"phpstan/phpstan": "^2.1.39"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
@@ -11554,11 +11559,14 @@
|
||||
"MIT"
|
||||
],
|
||||
"description": "Extra strict and opinionated rules for PHPStan",
|
||||
"keywords": [
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.8"
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.10"
|
||||
},
|
||||
"time": "2026-01-27T08:10:25+00:00"
|
||||
"time": "2026-02-11T14:17:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
||||
@@ -78,8 +78,8 @@ return [
|
||||
'running_balance_column' => (bool)envNonEmpty('USE_RUNNING_BALANCE', true), // this is only the default value, is not used.
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => 'develop/2026-02-10',
|
||||
'build_time' => 1770727063,
|
||||
'version' => 'develop/2026-02-14',
|
||||
'build_time' => 1771069444,
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 28, // field is no longer used.
|
||||
|
||||
|
||||
30
package-lock.json
generated
30
package-lock.json
generated
@@ -2152,9 +2152,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-free": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.1.0.tgz",
|
||||
"integrity": "sha512-+WxNld5ZCJHvPQCr/GnzCTVREyStrAJjisUPtUxG5ngDA8TMlPnKp6dddlTpai4+1GNmltAeuk1hJEkBohwZYA==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.2.0.tgz",
|
||||
"integrity": "sha512-3DguDv/oUE+7vjMeTSOjCSG+KeawgVQOHrKRnvUuqYh1mfArrh7s+s8hXW3e4RerBA1+Wh+hBqf8sJNpqNrBWg==",
|
||||
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@@ -3246,9 +3246,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.2.tgz",
|
||||
"integrity": "sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ==",
|
||||
"version": "25.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
|
||||
"integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -7118,9 +7118,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "25.8.4",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.4.tgz",
|
||||
"integrity": "sha512-a9A0MnUjKvzjEN/26ZY1okpra9kA8MEwzYEz1BNm+IyxUKPRH6ihf0p7vj8YvULwZHKHl3zkJ6KOt4hewxBecQ==",
|
||||
"version": "25.8.7",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.7.tgz",
|
||||
"integrity": "sha512-ttxxc5+67S/0hhoeVdEgc1lRklZhdfcUSEPp1//uUG2NB88X3667gRsDar+ZWQFdysnOsnb32bcoMsa4mtzhkQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -9717,9 +9717,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
|
||||
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
|
||||
"version": "6.14.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
|
||||
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
@@ -11801,9 +11801,9 @@
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.105.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz",
|
||||
"integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==",
|
||||
"version": "5.105.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.2.tgz",
|
||||
"integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
"not_enough_currencies": "Not enough currencies",
|
||||
"not_enough_currencies_enabled": "If you have just one currency enabled, there is no need to add exchange rates.",
|
||||
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> has been stored.",
|
||||
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> has been stored.",
|
||||
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") has been updated.",
|
||||
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> er blevet gemt.",
|
||||
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") er blevet opdateret.",
|
||||
"transaction_updated_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID}<\/a> (\"{title}\") has been updated.",
|
||||
"transaction_new_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID}<\/a> has been stored.",
|
||||
"transaction_journal_information": "Transaction information",
|
||||
@@ -31,7 +31,7 @@
|
||||
"apply_rules_checkbox": "Apply rules",
|
||||
"fire_webhooks_checkbox": "Fire webhooks",
|
||||
"no_budget_pointer": "Det ser ud til, at du ikke har oprettet budgetter endnu. Du burde oprette nogle p\u00e5 <a href=\"\/budgets\">budgetsiden<\/a>. Budgetter kan hj\u00e6lpe dig med at holde styr p\u00e5 udgifter.",
|
||||
"no_bill_pointer": "You seem to have no subscription yet. You should create some on the <a href=\"subscriptions\">subscription<\/a>-page. Subscriptions can help you keep track of expenses.",
|
||||
"no_bill_pointer": "Det ser ikke ud til, at du har nogle budgetter endnu. Du burde oprette nogle p\u00e5 <a href=\"\/budgets\">budgetsiden<\/a>. Budgetter kan hj\u00e6lpe dig med at holde styr p\u00e5 udgifter.",
|
||||
"source_account": "Kildekonto",
|
||||
"hidden_fields_preferences": "You can enable more transaction options in your <a href=\"preferences\">preferences<\/a>.",
|
||||
"destination_account": "Destinationskonto",
|
||||
@@ -107,42 +107,42 @@
|
||||
"multi_account_warning_withdrawal": "Husk, at kildekontoen for efterf\u00f8lgende opdelinger vil blive overstyret af hvad der er defineret i den f\u00f8rste opdeling af tilbagetr\u00e6kningen.",
|
||||
"multi_account_warning_deposit": "Husk, at destinationskontoen for efterf\u00f8lgende opdelinger vil blive tilsidesat af hvad der er defineret i den f\u00f8rste opsplitning af depositummet.",
|
||||
"multi_account_warning_transfer": "Husk p\u00e5, at kilden + destination konto for efterf\u00f8lgende opdelinger vil blive overstyret af hvad der er defineret i den f\u00f8rste opdeling af overf\u00f8rslen.",
|
||||
"webhook_trigger_ANY": "After any event",
|
||||
"webhook_trigger_ANY": "Efter enhver begivenhed",
|
||||
"webhook_trigger_STORE_TRANSACTION": "Efter oprettelse af transaktion",
|
||||
"webhook_trigger_UPDATE_TRANSACTION": "Efter opdatering af transaktion",
|
||||
"webhook_trigger_DESTROY_TRANSACTION": "Efter sletning af transaktion",
|
||||
"webhook_trigger_STORE_BUDGET": "After budget creation",
|
||||
"webhook_trigger_UPDATE_BUDGET": "After budget update",
|
||||
"webhook_trigger_DESTROY_BUDGET": "After budget delete",
|
||||
"webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "After budgeted amount change",
|
||||
"webhook_trigger_STORE_BUDGET": "Efter budgetoprettelse",
|
||||
"webhook_trigger_UPDATE_BUDGET": "Efter budgetopdatering",
|
||||
"webhook_trigger_DESTROY_BUDGET": "Efter sletning af budget",
|
||||
"webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "Efter budgetteret bel\u00f8b \u00e6ndring",
|
||||
"webhook_response_TRANSACTIONS": "Transaktionsdetaljer",
|
||||
"webhook_response_RELEVANT": "Relevant details",
|
||||
"webhook_response_RELEVANT": "Relevante oplysninger",
|
||||
"webhook_response_ACCOUNTS": "Kontodetaljer",
|
||||
"webhook_response_NONE": "No details",
|
||||
"webhook_response_NONE": "Ingen detaljer",
|
||||
"webhook_delivery_JSON": "JSON",
|
||||
"actions": "Handlinger",
|
||||
"meta_data": "Meta data",
|
||||
"webhook_messages": "Webhook-besked",
|
||||
"inactive": "Inactive",
|
||||
"no_webhook_messages": "Der er ingen webhook-beskeder",
|
||||
"inspect": "Inspect",
|
||||
"inspect": "Unders\u00f8g",
|
||||
"create_new_webhook": "Opret ny webhook",
|
||||
"webhooks": "Webhooks",
|
||||
"webhook_trigger_form_help": "Indicate on what event the webhook will trigger",
|
||||
"webhook_response_form_help": "Indicate what the webhook must submit to the URL.",
|
||||
"webhook_trigger_form_help": "Indik\u00e9r p\u00e5 hvilken begivenhed webhook vil udl\u00f8se",
|
||||
"webhook_response_form_help": "Angiv, hvad webhook skal indsende til URL.",
|
||||
"webhook_delivery_form_help": "Hvilket format webhook skal levere data i.",
|
||||
"webhook_active_form_help": "Webhooken skal v\u00e6re aktiv, ellers vil den ikke blive kaldt.",
|
||||
"edit_webhook_js": "Rediger webhook \"{title}\"",
|
||||
"webhook_was_triggered": "The webhook was triggered on the indicated transaction. Please wait for results to appear.",
|
||||
"webhook_was_triggered": "Webhooken blev udl\u00f8st p\u00e5 den angivne transaktion. Vent venligst p\u00e5 at resultaterne vises.",
|
||||
"view_message": "Vis besked",
|
||||
"view_attempts": "Vis mislykkede fors\u00f8g",
|
||||
"message_content_title": "Webhook-beskedindhold",
|
||||
"message_content_help": "This is the content of the message that was sent (or tried) using this webhook.",
|
||||
"message_content_help": "Dette er indholdet af den besked, der blev sendt (eller fors\u00f8gt) ved hj\u00e6lp af denne webhook.",
|
||||
"attempt_content_title": "Webhook-fors\u00f8g",
|
||||
"attempt_content_help": "These are all the unsuccessful attempts of this webhook message to submit to the configured URL. After some time, Firefly III will stop trying.",
|
||||
"attempt_content_help": "Disse er alle de mislykkede fors\u00f8g p\u00e5 at sende denne webhook-meddelelse til den konfigurerede URL. Efter et stykke tid vil Firefly III stoppe med at fors\u00f8ge.",
|
||||
"no_attempts": "Der er ingen mislykkede fors\u00f8g. Det er en god ting!",
|
||||
"webhook_attempt_at": "Attempt at {moment}",
|
||||
"logs": "Logs",
|
||||
"webhook_attempt_at": "Fors\u00f8g p\u00e5 {moment}",
|
||||
"logs": "Logfiler",
|
||||
"response": "Svar",
|
||||
"visit_webhook_url": "Bes\u00f8g webhook-URL",
|
||||
"reset_webhook_secret": "Nulstil webhook-hemmelighed",
|
||||
|
||||
@@ -107,18 +107,18 @@
|
||||
"multi_account_warning_withdrawal": "Tenga en cuenta que la cuenta de origen de las divisiones posteriores ser\u00e1 anulada por lo que se defina en la primera divisi\u00f3n del gasto.",
|
||||
"multi_account_warning_deposit": "Tenga en cuenta que la cuenta de destino de las divisiones posteriores ser\u00e1 anulada por lo que se defina en la primera divisi\u00f3n del retiro.",
|
||||
"multi_account_warning_transfer": "Tenga en cuenta que la cuenta de origen + destino de divisiones posteriores ser\u00e1 anulada por lo que se defina en la primera divisi\u00f3n de la transferencia.",
|
||||
"webhook_trigger_ANY": "After any event",
|
||||
"webhook_trigger_ANY": "Despu\u00e9s de cualquier evento",
|
||||
"webhook_trigger_STORE_TRANSACTION": "Despu\u00e9s de crear la transacci\u00f3n",
|
||||
"webhook_trigger_UPDATE_TRANSACTION": "Despu\u00e9s de actualizar la transacci\u00f3n",
|
||||
"webhook_trigger_DESTROY_TRANSACTION": "Despu\u00e9s de eliminar la transacci\u00f3n",
|
||||
"webhook_trigger_STORE_BUDGET": "After budget creation",
|
||||
"webhook_trigger_STORE_BUDGET": "Despu\u00e9s de crear un presupuesto",
|
||||
"webhook_trigger_UPDATE_BUDGET": "After budget update",
|
||||
"webhook_trigger_DESTROY_BUDGET": "After budget delete",
|
||||
"webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "After budgeted amount change",
|
||||
"webhook_response_TRANSACTIONS": "Detalles de la transacci\u00f3n",
|
||||
"webhook_response_RELEVANT": "Relevant details",
|
||||
"webhook_response_ACCOUNTS": "Detalles de la cuenta",
|
||||
"webhook_response_NONE": "No details",
|
||||
"webhook_response_NONE": "Sin detalles",
|
||||
"webhook_delivery_JSON": "JSON",
|
||||
"actions": "Acciones",
|
||||
"meta_data": "Meta Datos",
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
"destination_account_reconciliation": "\uc870\uc815 \uac70\ub798\uc758 \ubaa9\uc801\uc9c0 \uacc4\uc815\uc740 \ud3b8\uc9d1\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.",
|
||||
"source_account_reconciliation": "\uc870\uc815 \uac70\ub798\uc758 \ucd9c\ubc1c\uc9c0 \uacc4\uc815\uc740 \ud3b8\uc9d1\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.",
|
||||
"budget": "\uc608\uc0b0",
|
||||
"bill": "Subscription",
|
||||
"bill": "\uad6c\ub3c5",
|
||||
"you_create_withdrawal": "\ucd9c\uae08\uc744 \uc0dd\uc131\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4.",
|
||||
"you_create_transfer": "\uc804\uc1a1\uc744 \uc0dd\uc131\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4.",
|
||||
"you_create_deposit": "\uc785\uae08\uc744 \uc0dd\uc131\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4.",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"transaction_journal_information": "Informa\u021bii despre tranzac\u021bii",
|
||||
"submission_options": "Op\u0163iuni de depunere",
|
||||
"apply_rules_checkbox": "Aplic\u0103 regulile",
|
||||
"fire_webhooks_checkbox": "Webhook-uri de incendiu",
|
||||
"fire_webhooks_checkbox": "Declan\u0219eaz\u0103 webhook-uri",
|
||||
"no_budget_pointer": "Se pare c\u0103 nu ai \u00eenc\u0103 bugete. Creeaz\u0103-le pe pagina <a href=\"budgets\">bugete<\/a>. Bugetele te ajut\u0103 s\u0103 \u021bii eviden\u021ba cheltuielilor.",
|
||||
"no_bill_pointer": "Se pare c\u0103 nu ai \u00eenc\u0103 abonamente. Creeaz\u0103-le pe pagina <a href=\"subscriptions\">abonamente<\/a>. Abonamentele te ajut\u0103 s\u0103 \u021bii eviden\u021ba cheltuielilor.",
|
||||
"source_account": "Contul surs\u0103",
|
||||
|
||||
@@ -184,11 +184,14 @@
|
||||
{{ formatAmountBySymbol(transaction.amount, transaction.currency_symbol, transaction.currency_decimal_places, false) }}
|
||||
{% endif %}
|
||||
{% if transaction.source_account_id != account.id %}
|
||||
{{ formatAmountBySymbol(transaction.amount*-1, transaction.currency_symbol, transaction.currency_decimal_places, false) }}
|
||||
{{ formatAmountBySymbol(transaction.amount*-1, transaction.currency_symbol, transaction.currency_decimal_places, false) }}
|
||||
{% endif %}
|
||||
|
||||
{# foreign amount of transfer #}
|
||||
{% if null != transaction.foreign_amount %}
|
||||
{% if null != transaction.foreign_amount and transaction.source_account_id == account.id %}
|
||||
({{ formatAmountBySymbol(transaction.foreign_amount, transaction.foreign_currency_symbol, transaction.foreign_currency_decimal_places, false) }})
|
||||
{% endif %}
|
||||
{% if null != transaction.foreign_amount and transaction.source_account_id != account.id %}
|
||||
({{ formatAmountBySymbol(transaction.foreign_amount*-1, transaction.foreign_currency_symbol, transaction.foreign_currency_decimal_places, false) }})
|
||||
{% endif %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user