Compare commits

..

109 Commits

Author SHA1 Message Date
github-actions
19c746a865 Auto commit for release 'v6.2.5' on 2025-02-09 2025-02-09 06:08:12 +01:00
James Cole
503d2aa786 Rename class to stop phpunit complaining. 2025-02-09 05:57:47 +01:00
James Cole
70d83ab501 Fix #9784 2025-02-09 05:52:18 +01:00
James Cole
edab602bb7 Fix #9784 2025-02-09 05:26:37 +01:00
James Cole
f9bcc4b1fa Extra code for #9747 2025-02-08 10:51:52 +01:00
github-actions
f3fe86167c Auto commit for release 'develop' on 2025-02-08 2025-02-08 08:18:18 +01:00
James Cole
2189fb46a2 Disble tests 2025-02-08 08:11:15 +01:00
James Cole
7ff4178c8b Add some basic feature tests. 2025-02-08 08:11:01 +01:00
James Cole
fffd695ef8 Expand changelog. 2025-02-08 07:18:50 +01:00
James Cole
ee592de035 Fix #9769 2025-02-08 07:16:56 +01:00
James Cole
7394e50ae2 Method should be public. 2025-02-08 06:57:26 +01:00
James Cole
f42fcff04a Fix #9783 2025-02-08 06:42:12 +01:00
James Cole
4eb3ce7c14 Fix #9789 2025-02-07 05:26:03 +01:00
James Cole
a977c567ce Fix #9787 2025-02-06 18:28:42 +01:00
James Cole
785bd7e905 Fix #9786 2025-02-06 17:06:48 +01:00
James Cole
df19f699d4 Fix tests. 2025-02-06 08:56:58 +01:00
James Cole
5e6e932e7e Add subscriptions, over bills. 2025-02-06 08:32:22 +01:00
James Cole
5bc397f01a Disable old parser tests. 2025-02-06 08:32:06 +01:00
James Cole
42209e367f Make sure this order is used. #9780 2025-02-06 05:55:46 +01:00
James Cole
d53b1670d3 Fix #9781 2025-02-06 05:51:51 +01:00
James Cole
a6d450ba18 Some fixes for #9747 2025-02-05 18:50:09 +01:00
James Cole
e8c1a95128 Add debug logs to ntfy. 2025-02-05 18:37:00 +01:00
James Cole
edb201f210 Fix #9736 2025-02-05 15:31:53 +01:00
github-actions
fe57367a8c Auto commit for release 'v6.2.4' on 2025-02-05 2025-02-05 08:03:34 +01:00
James Cole
134194a95b Fix search code here too. 2025-02-05 07:46:26 +01:00
github-actions
41c0e6fe2d Auto commit for release 'develop' on 2025-02-05 2025-02-05 07:43:04 +01:00
James Cole
c07914e733 Update changelog 2025-02-05 07:39:53 +01:00
James Cole
52e2302f4f Fix search code. 2025-02-05 07:37:22 +01:00
github-actions
0a6b34b4f2 Auto commit for release 'v6.2.3' on 2025-02-05 2025-02-05 07:25:30 +01:00
github-actions
1e06b4dd0b Merge branch 'develop' 2025-02-05 06:23:14 +00:00
James Cole
5701f95e0b Expand changelog 2025-02-05 07:22:00 +01:00
James Cole
60d3572d37 Expand changelog 2025-02-05 07:21:31 +01:00
github-actions
ffa6e6a571 Auto commit for release 'develop' on 2025-02-05 2025-02-05 06:50:00 +01:00
James Cole
d6453cd735 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-02-05 06:46:35 +01:00
James Cole
fd79f9df44 Expand changelog, fix migration. 2025-02-05 06:46:27 +01:00
github-actions
4587340293 Auto commit for release 'develop' on 2025-02-05 2025-02-05 06:41:08 +01:00
James Cole
90bfdc7573 Fix #9754 2025-02-05 06:36:51 +01:00
James Cole
eca12f661f Fix #9327 2025-02-05 06:31:15 +01:00
James Cole
f85878b843 Final tweaks in account balance logic. 2025-02-05 06:29:07 +01:00
James Cole
6499b5eaab Rename variable for consistency. 2025-02-05 06:03:57 +01:00
James Cole
7e4fece63d add some checks and balances to migrations. 2025-02-05 05:58:53 +01:00
James Cole
512eddf8be Fix #9736 2025-02-05 05:51:22 +01:00
github-actions
f0fa93a811 Auto commit for release 'develop' on 2025-02-04 2025-02-04 21:38:20 +01:00
James Cole
3c8de21709 Fix balance and native balance lists. 2025-02-04 21:34:46 +01:00
James Cole
81173e8340 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop
# Conflicts:
#	app/Support/Steam.php
2025-02-04 21:28:43 +01:00
James Cole
35a8fa5f02 Fix balance in range. 2025-02-04 21:27:24 +01:00
James Cole
443036936d Update changelog. 2025-02-04 21:26:53 +01:00
James Cole
ac88007593 Replace steam call. 2025-02-04 21:26:40 +01:00
github-actions
2297589dca Auto commit for release 'develop' on 2025-02-04 2025-02-04 19:48:38 +01:00
James Cole
6ada5fa560 Fix #9751 2025-02-04 19:43:53 +01:00
Sander Dorigo
8f6eefb5e7 Fix #9745 2025-02-04 08:45:08 +01:00
Sander Dorigo
b36a50381b Fix #9747 2025-02-04 08:42:54 +01:00
Sander Dorigo
51f84b3060 Fix #9762 2025-02-04 08:37:02 +01:00
Sander Dorigo
72132a19b0 Fix #9736 2025-02-04 08:30:27 +01:00
Sander Dorigo
065d165211 Fix #9713 2025-02-04 08:28:43 +01:00
James Cole
cabedf39b2 Merge pull request #9750 from firefly-iii/dependabot/github_actions/aws-actions/closed-issue-message-2
Bump aws-actions/closed-issue-message from 1 to 2
2025-02-03 08:03:16 +01:00
dependabot[bot]
5d3806fcd4 Bump aws-actions/closed-issue-message from 1 to 2
Bumps [aws-actions/closed-issue-message](https://github.com/aws-actions/closed-issue-message) from 1 to 2.
- [Release notes](https://github.com/aws-actions/closed-issue-message/releases)
- [Commits](https://github.com/aws-actions/closed-issue-message/compare/v1...v2)

---
updated-dependencies:
- dependency-name: aws-actions/closed-issue-message
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-03 03:34:11 +00:00
github-actions
01695b3342 Auto commit for release 'develop' on 2025-02-03 2025-02-03 04:08:56 +01:00
James Cole
71fb5fe077 Fix changelog. 2025-02-02 16:24:10 +01:00
github-actions
3bec106840 Auto commit for release 'v6.2.2' on 2025-02-02 2025-02-02 16:20:11 +01:00
James Cole
fb01c36be1 Update changelog and manifest [skip ci] 2025-02-02 16:14:32 +01:00
James Cole
26d851e69e Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-02-02 16:14:09 +01:00
James Cole
28c18c046b Fix #9744 2025-02-02 16:13:56 +01:00
github-actions
318cef7e3b Auto commit for release 'develop' on 2025-02-02 2025-02-02 16:06:22 +01:00
James Cole
e8dc8f25be Update changelog [skip ci] 2025-02-02 16:02:45 +01:00
James Cole
10ccc30240 Fix #9738 2025-02-02 16:02:17 +01:00
James Cole
5adc877d5e Merge pull request #9743 from mansehr/feature-nordic-currencies
Feature nordic currencies
2025-02-02 15:23:05 +01:00
SoftBrix
30923afb2b Added ISK 2025-02-02 14:48:01 +01:00
SoftBrix
4eb6813b43 Added NOK 2025-02-02 14:46:26 +01:00
James Cole
7521a31619 Expand changelog. 2025-02-02 06:48:57 +01:00
James Cole
fc05beb452 Fix #9727 2025-02-02 06:24:10 +01:00
James Cole
1103428a83 Smaller issue replies. 2025-02-02 05:41:54 +01:00
James Cole
d06d521bf0 Merge branch 'main' into develop 2025-02-02 05:39:41 +01:00
James Cole
8f64f1c0eb Expand explanation. 2025-02-02 05:39:33 +01:00
James Cole
d11c232171 Fix https://github.com/firefly-iii/firefly-iii/issues/9736 2025-02-02 05:38:47 +01:00
SoftBrix
93c73248de Added SEK 2025-02-02 00:03:31 +01:00
James Cole
5bed081ab9 Fix https://github.com/firefly-iii/firefly-iii/issues/9731 2025-02-01 21:14:28 +01:00
James Cole
c5188c503e Fix https://github.com/firefly-iii/firefly-iii/issues/9713 2025-02-01 21:06:06 +01:00
James Cole
98ffcac7b6 Fix https://github.com/firefly-iii/firefly-iii/issues/9729 2025-02-01 20:58:35 +01:00
James Cole
df1e81d611 Fix https://github.com/firefly-iii/firefly-iii/issues/9730 2025-02-01 20:52:41 +01:00
James Cole
9711170b08 Fix https://github.com/firefly-iii/firefly-iii/issues/9732 2025-02-01 20:43:20 +01:00
github-actions
e43264bdce Auto commit for release 'develop' on 2025-02-01 2025-02-01 19:12:18 +01:00
github-actions
e0643bed7a Auto commit for release 'v6.2.1' on 2025-02-01 2025-02-01 19:06:02 +01:00
James Cole
7f0eb3b064 Expand changelog. 2025-02-01 19:01:17 +01:00
James Cole
f38e510526 Fix https://github.com/firefly-iii/firefly-iii/issues/9714 2025-02-01 18:59:55 +01:00
James Cole
25f99b23b2 Merge branch 'main' into develop 2025-02-01 18:40:00 +01:00
James Cole
44281fc8a0 Respond to "fixed" label. 2025-02-01 18:39:51 +01:00
James Cole
eed3902cb7 Fix https://github.com/firefly-iii/firefly-iii/issues/9726 2025-02-01 18:37:26 +01:00
James Cole
94a3bb0443 Limit the number of recurring transactions returned. 2025-02-01 15:39:34 +01:00
James Cole
8dcc36880e Fix https://github.com/firefly-iii/firefly-iii/issues/9722 2025-02-01 13:03:19 +01:00
James Cole
695bb31894 Fix https://github.com/firefly-iii/firefly-iii/issues/9723 2025-02-01 13:01:13 +01:00
James Cole
f8ded66869 Fix https://github.com/firefly-iii/firefly-iii/issues/9721 2025-02-01 12:53:34 +01:00
James Cole
8e4bdbc584 Fix https://github.com/firefly-iii/firefly-iii/issues/9720 2025-02-01 12:50:48 +01:00
James Cole
f7b14b01bc Fix https://github.com/firefly-iii/firefly-iii/issues/9717 2025-02-01 12:01:50 +01:00
James Cole
705b9bf0f2 Fix https://github.com/firefly-iii/firefly-iii/issues/9719 2025-02-01 11:44:56 +01:00
James Cole
f0226dbc54 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-02-01 11:29:21 +01:00
James Cole
1b1dfb0d7b Fix https://github.com/firefly-iii/firefly-iii/issues/9718 2025-02-01 11:28:39 +01:00
github-actions
8ed5092a76 Auto commit for release 'develop' on 2025-02-01 2025-02-01 06:23:31 +01:00
James Cole
d609821be6 Expand debug table. 2025-02-01 06:18:58 +01:00
github-actions
cd0201074c Auto commit for release 'v6.2.0' on 2025-01-31 2025-01-31 20:35:34 +01:00
James Cole
1d8feec7bc Update changelog. 2025-01-31 20:28:17 +01:00
James Cole
d941472c84 Merge branch 'main' into develop 2025-01-29 20:12:19 +01:00
James Cole
674a118fac Merge pull request #9709 from firefly-iii/dependabot/composer/composer-aeff1b7291
Bump twig/twig from 3.18.0 to 3.19.0 in the composer group across 1 directory
2025-01-29 20:11:54 +01:00
dependabot[bot]
1334d793f6 Bump twig/twig in the composer group across 1 directory
Bumps the composer group with 1 update in the / directory: [twig/twig](https://github.com/twigphp/Twig).


Updates `twig/twig` from 3.18.0 to 3.19.0
- [Changelog](https://github.com/twigphp/Twig/blob/3.x/CHANGELOG)
- [Commits](https://github.com/twigphp/Twig/compare/v3.18.0...v3.19.0)

---
updated-dependencies:
- dependency-name: twig/twig
  dependency-type: indirect
  dependency-group: composer
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-29 18:44:41 +00:00
James Cole
60354c0202 Fix https://github.com/firefly-iii/firefly-iii/issues/9704 2025-01-29 08:40:16 +01:00
James Cole
22081d3f0a Add skip help text 2025-01-29 07:52:16 +01:00
James Cole
4b3f8fc78d Remove logging [skip ci] 2025-01-29 07:48:43 +01:00
github-actions
4bd1aab86d Auto commit for release 'develop' on 2025-01-27 2025-01-27 04:08:46 +01:00
James Cole
60362cb60c Remove debug header, does not work. 2025-01-26 17:07:45 +01:00
131 changed files with 2070 additions and 1304 deletions

View File

@@ -406,16 +406,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.68.1",
"version": "v3.68.5",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "b9db2b2ea3cdba7201067acee46f984ef2397cff"
"reference": "7bedb718b633355272428c60736dc97fb96daf27"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/b9db2b2ea3cdba7201067acee46f984ef2397cff",
"reference": "b9db2b2ea3cdba7201067acee46f984ef2397cff",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7bedb718b633355272428c60736dc97fb96daf27",
"reference": "7bedb718b633355272428c60736dc97fb96daf27",
"shasum": ""
},
"require": {
@@ -497,7 +497,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.68.1"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.5"
},
"funding": [
{
@@ -505,7 +505,7 @@
"type": "github"
}
],
"time": "2025-01-17T09:20:36+00:00"
"time": "2025-01-30T17:00:50+00:00"
},
{
"name": "psr/container",

View File

@@ -1,6 +1,19 @@
# Configuration for Label Actions - https://github.com/dessant/label-actions
# The `feature` label is added to issues
fixed:
issues:
# Post a comment, `{issue-author}` is an optional placeholder
comment: |
Hi there!
This is an automatic reply. `Share and enjoy`
This issue has been marked as fixed. Thanks for reporting! A new version will be released in due time. Unfortunately, [I cannot give an estimate](https://docs.firefly-iii.org/references/faq/firefly-iii/general/#when-will-you-release-version-the-next-version), but [the roadmap](https://roadmap.firefly-iii.org/) is available for your reading pleasure.
There is no need to close the issue. It will be closed automatically.
Thank you for your contributions.
feature:
issues:
# Post a comment, `{issue-author}` is an optional placeholder
@@ -10,7 +23,7 @@ feature:
This is an automatic reply. `Share and enjoy`
This issue has been marked as a feature request. The requested (new) feature will become a part of Firefly III or the data importer in due course.
This issue has been marked as a feature request.
If you come across this issue, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. You can subscribe to this issue to get updates.
@@ -41,7 +54,7 @@ enhancement:
This is an automatic reply. `Share and enjoy`
This issue has been marked as an enhancement. The requested enhancement to an existing feature will become a part of Firefly III or the data importer in due course.
This issue has been marked as an enhancement.
If you come across this issue, please be aware there is NO need to reply with "+1" or "me too" or "I need this too" or whatever. Such comments are not helpful, and do not influence [the roadmap](https://roadmap.firefly-iii.org/). Your comment may be :skull: deleted. You can subscribe to this issue to get updates.

View File

@@ -8,7 +8,7 @@ jobs:
command_and_close:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/closed-issue-message@v1
- uses: aws-actions/closed-issue-message@v2
with:
message: |
Hi there! This is an automatic reply. `Share and enjoy`

View File

@@ -3,6 +3,9 @@
Over time, many people have contributed to Firefly III. Their efforts are not always visible, but always remembered and appreciated.
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
## 2025
- SoftBrix
## 2024
- Sobuno
- TasneemTantawy

View File

@@ -41,7 +41,8 @@ use Illuminate\Http\JsonResponse;
class AccountController extends Controller
{
use AccountFilter;
protected array $accepts = ['application/json'];
// this array only exists to test if the constructor will use it properly.
protected array $accepts = ['application/json', 'application/vnd.api+json'];
/** @var array<int, string> */
private array $balanceTypes;
@@ -82,6 +83,9 @@ class AccountController extends Controller
$return = [];
$result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
// set date to end-of-day for account balance.
$date->endOfDay();
/** @var Account $account */
foreach ($result as $account) {
$nameWithBalance = $account->name;
@@ -109,6 +113,11 @@ class AccountController extends Controller
'currency_code' => $useCurrency->code,
'currency_symbol' => $useCurrency->symbol,
'currency_decimal_places' => $useCurrency->decimal_places,
'account_currency_id' => (string) $currency->id,
'account_currency_name' => $currency->name,
'account_currency_code' => $currency->code,
'account_currency_symbol' => $currency->symbol,
'account_currency_decimal_places' => $currency->decimal_places,
];
}

View File

@@ -32,6 +32,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\ApiSupport;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -80,6 +81,10 @@ class AccountController extends Controller
/** @var Carbon $end */
$end = $dates['end'];
// set dates to end of day + start of day:
$start->startOfDay();
$end->endOfDay();
// user's preferences
$defaultSet = $this->repository->getAccountsByType([AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
@@ -113,7 +118,7 @@ class AccountController extends Controller
];
// TODO this code is also present in the V2 chart account controller so this method is due to be deprecated.
$currentStart = clone $start;
$range = app('steam')->finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
$range = Steam::finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
$previous = array_values($range)[0][$field];
while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d');

View File

@@ -67,7 +67,7 @@ abstract class Controller extends BaseController
protected array $allowedSort;
protected ParameterBag $parameters;
protected bool $convertToNative = false;
protected array $accepts = ['application/json'];
protected array $accepts = ['application/json', 'application/vnd.api+json'];
protected TransactionCurrency $nativeCurrency;
/**

View File

@@ -57,11 +57,11 @@ class IndexController extends Controller
public function index(): JsonResponse
{
$piggies = $this->repository->getAll();
$entries = $this->repository->getAll();
$pageSize = $this->parameters->get('limit');
$count = $piggies->count();
$piggies = $piggies->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($piggies, $count, $pageSize, $this->parameters->get('page'));
$count = $entries->count();
$entries = $entries->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($entries, $count, $pageSize, $this->parameters->get('page'));
$transformer = new ExchangeRateTransformer();
$transformer->setParameters($this->parameters); // give params to transformer

View File

@@ -72,13 +72,6 @@ class UpdateController extends Controller
{
app('log')->debug('Now in update routine for transaction group');
$data = $request->getAll();
// Fixes 8750.
$transactions = $data['transactions'] ?? [];
foreach ($transactions as $index => $info) {
unset($data['transactions'][$index]['type']);
}
$transactionGroup = $this->groupRepository->update($transactionGroup, $data);
$manager = $this->getManager();

View File

@@ -236,7 +236,7 @@ class ListController extends Controller
// get list of budgets. Count it and split it.
/** @var RecurringRepositoryInterface $recurringRepos */
$recurringRepos = app(RecurringRepositoryInterface::class);
$unfiltered = $recurringRepos->getAll();
$unfiltered = $recurringRepos->get();
// filter selection
$collection = $unfiltered->filter(

View File

@@ -31,6 +31,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Support\Chart\ChartData;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\CleansChartData;
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
@@ -118,7 +119,7 @@ class AccountController extends Controller
'native_entries' => [],
];
$currentStart = clone $params['start'];
$range = app('steam')->finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
$previous = array_values($range)[0]['balance'];
$previousNative = array_values($range)[0]['native_balance'];

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Correction;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Models\AutoBudget;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\Bill;
@@ -33,8 +34,14 @@ use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class CorrectsAmounts extends Command
{
@@ -45,6 +52,8 @@ class CorrectsAmounts extends Command
public function handle(): int
{
// transfers must not have foreign currency info if both accounts have the same currency.
$this->correctTransfers();
// auto budgets must be positive
$this->fixAutoBudgets();
// available budgets must be positive
@@ -62,6 +71,7 @@ class CorrectsAmounts extends Command
// rule_triggers must be positive or zero (amount_less, amount_more, amount_is)
$this->fixRuleTriggers();
return 0;
}
@@ -182,4 +192,63 @@ class CorrectsAmounts extends Command
return false;
}
private function correctTransfers(): void
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$type = TransactionType::where('type', TransactionTypeEnum::TRANSFER->value)->first();
$journals = TransactionJournal::where('transaction_type_id', $type->id)->get();
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$repository->setUser($journal->user);
$native = Amount::getNativeCurrencyByUserGroup($journal->userGroup);
/** @var null|Transaction $source */
$source = $journal->transactions()->where('amount', '<', 0)->first();
/** @var null|Transaction $destination */
$destination = $journal->transactions()->where('amount', '>', 0)->first();
if (null === $source || null === $destination) {
continue;
}
if (null === $source->foreign_currency_id || null === $destination->foreign_currency_id) {
continue;
}
$sourceAccount = $source->account;
$destAccount = $destination->account;
if (null === $sourceAccount || null === $destAccount) {
continue;
}
$sourceCurrency = $repository->getAccountCurrency($sourceAccount) ?? $native;
$destCurrency = $repository->getAccountCurrency($destAccount) ?? $native;
if ($sourceCurrency->id === $destCurrency->id) {
Log::debug('Both accounts have the same currency. Removing foreign currency info.');
$source->foreign_currency_id = null;
$source->foreign_amount = null;
$source->save();
$destination->foreign_currency_id = null;
$destination->foreign_amount = null;
$destination->save();
continue;
}
// validate source
if ($destCurrency->id !== $source->foreign_currency_id) {
Log::debug(sprintf('Journal #%d: Transaction #%d refers to "%s" but should refer to "%s".', $journal->id, $source->id, $source->foreignCurrency->code, $destCurrency->code));
$source->foreign_currency_id = $destCurrency->id;
$source->save();
}
// validate destination:
if ($sourceCurrency->id !== $destination->foreign_currency_id) {
Log::debug(sprintf('Journal #%d: Transaction #%d refers to "%s" but should refer to "%s".', $journal->id, $destination->id, $destination->foreignCurrency->code, $sourceCurrency->code));
$destination->foreign_currency_id = $sourceCurrency->id;
$destination->save();
}
}
}
}

View File

@@ -102,7 +102,14 @@ class CorrectsNativeAmounts extends Command
{
$set = $userGroup->accounts()->where(function (EloquentBuilder $q): void {
$q->whereNotNull('virtual_balance');
// this needs a different piece of code for postgres.
if ('pgsql' === config('database.default')) {
$q->orWhere(DB::raw('CAST(virtual_balance AS TEXT)'), '!=', '');
}
if ('pgsql' !== config('database.default')) {
$q->orWhere('virtual_balance', '!=', '');
}
})->get();
/** @var Account $account */
@@ -218,7 +225,6 @@ class CorrectsNativeAmounts extends Command
$set = DB::table('transactions')
->join('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.user_group_id', $userGroup->id)
->where(function (DatabaseBuilder $q1) use ($currency): void {
$q1->where(function (DatabaseBuilder $q2) use ($currency): void {
$q2->whereNot('transactions.transaction_currency_id', $currency->id)->whereNull('transactions.foreign_currency_id');

View File

@@ -57,7 +57,7 @@ class ExportsData extends Command
{--export-tags : Create a file with all your tags and some meta data.}
{--export-recurring : Create a file with all your recurring transactions and some meta data.}
{--export-rules : Create a file with all your rules and some meta data.}
{--export-bills : Create a file with all your bills and some meta data.}
{--export-subscriptions : Create a file with all your subscriptions and some meta data.}
{--export-piggies : Create a file with all your piggy banks and some meta data.}
{--force : Force overwriting of previous exports if found.}';
private AccountRepositoryInterface $accountRepository;
@@ -106,7 +106,7 @@ class ExportsData extends Command
$exporter->setExportTags($options['export']['tags']);
$exporter->setExportRecurring($options['export']['recurring']);
$exporter->setExportRules($options['export']['rules']);
$exporter->setExportBills($options['export']['bills']);
$exporter->setExportBills($options['export']['subscriptions']);
$exporter->setExportPiggies($options['export']['piggies']);
$data = $exporter->export();
if (0 === count($data)) {
@@ -157,7 +157,7 @@ class ExportsData extends Command
'tags' => $this->option('export-tags'),
'recurring' => $this->option('export-recurring'),
'rules' => $this->option('export-rules'),
'bills' => $this->option('export-bills'),
'bills' => $this->option('export-subscriptions'),
'piggies' => $this->option('export-piggies'),
],
'start' => $start,

View File

@@ -54,6 +54,9 @@ class MonthReportGenerator implements ReportGeneratorInterface
$dayBefore = clone $this->start;
$dayBefore->subDay();
// move to end of day
$dayBefore->endOfDay();
/** @var Account $account */
foreach ($this->accounts as $account) {
// balance the day before:

View File

@@ -61,8 +61,12 @@ class PreferencesEventHandler
$this->resetTransactions($event->userGroup);
// fire laravel command to recalculate them all.
if (Amount::convertToNative()) {
Log::debug('Will now convert to native.');
Artisan::call('correction:recalculate-native-amounts');
return;
}
Log::debug('Will NOT convert to native.');
}
private function resetPiggyBanks(UserGroup $userGroup): void

View File

@@ -38,10 +38,17 @@ use Illuminate\Support\Collection;
*/
class StoredGroupEventHandler
{
public function runAllHandlers(StoredTransactionGroup $event): void
{
$this->processRules($event);
$this->recalculateCredit($event);
$this->triggerWebhooks($event);
}
/**
* This method grabs all the users rules and processes them.
*/
public function processRules(StoredTransactionGroup $storedGroupEvent): void
private function processRules(StoredTransactionGroup $storedGroupEvent): void
{
if (false === $storedGroupEvent->applyRules) {
app('log')->info(sprintf('Will not run rules on group #%d', $storedGroupEvent->transactionGroup->id));
@@ -76,7 +83,7 @@ class StoredGroupEventHandler
$newRuleEngine->fire();
}
public function recalculateCredit(StoredTransactionGroup $event): void
private function recalculateCredit(StoredTransactionGroup $event): void
{
$group = $event->transactionGroup;
@@ -89,7 +96,7 @@ class StoredGroupEventHandler
/**
* This method processes all webhooks that respond to the "stored transaction group" trigger (100)
*/
public function triggerWebhooks(StoredTransactionGroup $storedGroupEvent): void
private function triggerWebhooks(StoredTransactionGroup $storedGroupEvent): void
{
app('log')->debug(__METHOD__);
$group = $storedGroupEvent->transactionGroup;

View File

@@ -41,10 +41,19 @@ use Illuminate\Support\Collection;
*/
class UpdatedGroupEventHandler
{
public function runAllHandlers(UpdatedTransactionGroup $event): void
{
$this->unifyAccounts($event);
$this->processRules($event);
$this->recalculateCredit($event);
$this->triggerWebhooks($event);
}
/**
* This method will check all the rules when a journal is updated.
*/
public function processRules(UpdatedTransactionGroup $updatedGroupEvent): void
private function processRules(UpdatedTransactionGroup $updatedGroupEvent): void
{
if (false === $updatedGroupEvent->applyRules) {
app('log')->info(sprintf('Will not run rules on group #%d', $updatedGroupEvent->transactionGroup->id));
@@ -76,7 +85,7 @@ class UpdatedGroupEventHandler
$newRuleEngine->fire();
}
public function recalculateCredit(UpdatedTransactionGroup $event): void
private function recalculateCredit(UpdatedTransactionGroup $event): void
{
$group = $event->transactionGroup;
@@ -86,7 +95,7 @@ class UpdatedGroupEventHandler
$object->recalculate();
}
public function triggerWebhooks(UpdatedTransactionGroup $updatedGroupEvent): void
private function triggerWebhooks(UpdatedTransactionGroup $updatedGroupEvent): void
{
app('log')->debug(__METHOD__);
$group = $updatedGroupEvent->transactionGroup;

View File

@@ -26,6 +26,7 @@ namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Account;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
@@ -52,6 +53,7 @@ class AccountObserver
$currency = $repository->getAccountCurrency($account);
if (null !== $currency && $currency->id !== $userCurrency->id && '' !== (string) $account->virtual_balance && 0 !== bccomp($account->virtual_balance, '0')) {
$converter = new ExchangeRateConverter();
$converter->setUserGroup($account->user->userGroup);
$converter->setIgnoreSettings(true);
$account->native_virtual_balance = $converter->convert($currency, $userCurrency, today(), $account->virtual_balance);
@@ -72,12 +74,15 @@ class AccountObserver
// app('log')->debug('Observe "deleting" of an account.');
$account->accountMeta()->delete();
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($account->user);
/** @var PiggyBank $piggy */
foreach ($account->piggyBanks()->get() as $piggy) {
$piggy->accounts()->detach($account);
}
foreach ($account->attachments()->get() as $attachment) {
$attachment->delete();
$repository->destroy($attachment);
}
foreach ($account->transactions()->get() as $transaction) {
$transaction->delete();

View File

@@ -52,6 +52,7 @@ class AutoBudgetObserver
$autoBudget->native_amount = null;
if ($autoBudget->transactionCurrency->id !== $userCurrency->id) {
$converter = new ExchangeRateConverter();
$converter->setUserGroup($autoBudget->budget->user->userGroup);
$converter->setIgnoreSettings(true);
$autoBudget->native_amount = $converter->convert($autoBudget->transactionCurrency, $userCurrency, today(), $autoBudget->amount);
}

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\Log;
@@ -41,9 +42,12 @@ class BillObserver
public function deleting(Bill $bill): void
{
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($bill->user);
// app('log')->debug('Observe "deleting" of a bill.');
foreach ($bill->attachments()->get() as $attachment) {
$attachment->delete();
$repository->destroy($attachment);
}
$bill->notes()->delete();
}
@@ -64,6 +68,7 @@ class BillObserver
$bill->native_amount_max = null;
if ($bill->transactionCurrency->id !== $userCurrency->id) {
$converter = new ExchangeRateConverter();
$converter->setUserGroup($bill->user->userGroup);
$converter->setIgnoreSettings(true);
$bill->native_amount_min = $converter->convert($bill->transactionCurrency, $userCurrency, today(), $bill->amount_min);
$bill->native_amount_max = $converter->convert($bill->transactionCurrency, $userCurrency, today(), $bill->amount_max);

View File

@@ -54,6 +54,7 @@ class BudgetLimitObserver
$budgetLimit->native_amount = null;
if ($budgetLimit->transactionCurrency->id !== $userCurrency->id) {
$converter = new ExchangeRateConverter();
$converter->setUserGroup($budgetLimit->budget->user->userGroup);
$converter->setIgnoreSettings(true);
$budgetLimit->native_amount = $converter->convert($budgetLimit->transactionCurrency, $userCurrency, today(), $budgetLimit->amount);
}

View File

@@ -25,6 +25,7 @@ namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
/**
* Class BudgetObserver
@@ -34,8 +35,12 @@ class BudgetObserver
public function deleting(Budget $budget): void
{
app('log')->debug('Observe "deleting" of a budget.');
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($budget->user);
foreach ($budget->attachments()->get() as $attachment) {
$attachment->delete();
$repository->destroy($attachment);
}
$budgetLimits = $budget->budgetlimits()->get();

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
/**
* Class CategoryObserver
@@ -33,8 +34,12 @@ class CategoryObserver
public function deleting(Category $category): void
{
app('log')->debug('Observe "deleting" of a category.');
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($category->user);
foreach ($category->attachments()->get() as $attachment) {
$attachment->delete();
$repository->destroy($attachment);
}
$category->notes()->delete();
}

View File

@@ -52,6 +52,7 @@ class PiggyBankEventObserver
$event->native_amount = null;
if ($event->piggyBank->transactionCurrency->id !== $userCurrency->id) {
$converter = new ExchangeRateConverter();
$converter->setUserGroup($event->piggyBank->accounts()->first()->user->userGroup);
$converter->setIgnoreSettings(true);
$event->native_amount = $converter->convert($event->piggyBank->transactionCurrency, $userCurrency, today(), $event->amount);
}

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Facades\Log;
@@ -46,8 +47,11 @@ class PiggyBankObserver
{
app('log')->debug('Observe "deleting" of a piggy bank.');
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($piggyBank->accounts()->first()->user);
foreach ($piggyBank->attachments()->get() as $attachment) {
$attachment->delete();
$repository->destroy($attachment);
}
$piggyBank->piggyBankEvents()->delete();

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
/**
* Class RecurrenceObserver
@@ -33,8 +34,12 @@ class RecurrenceObserver
public function deleting(Recurrence $recurrence): void
{
app('log')->debug('Observe "deleting" of a recurrence.');
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($recurrence->user);
foreach ($recurrence->attachments()->get() as $attachment) {
$attachment->delete();
$repository->destroy($attachment);
}
$recurrence->recurrenceRepetitions()->delete();

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
/**
* Class TagObserver
@@ -34,8 +35,11 @@ class TagObserver
{
app('log')->debug('Observe "deleting" of a tag.');
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($tag->user);
foreach ($tag->attachments()->get() as $attachment) {
$attachment->delete();
$repository->destroy($attachment);
}
$tag->locations()->delete();

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Handlers\Observer;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
/**
* Class TransactionJournalObserver
@@ -34,6 +35,10 @@ class TransactionJournalObserver
{
app('log')->debug('Observe "deleting" of a transaction journal.');
$repository = app(AttachmentRepositoryInterface::class);
$repository->setUser($transactionJournal->user);
// to make sure the listener doesn't get back to use and loop
TransactionJournal::withoutEvents(static function () use ($transactionJournal): void {
foreach ($transactionJournal->transactions()->get() as $transaction) {
@@ -41,7 +46,7 @@ class TransactionJournalObserver
}
});
foreach ($transactionJournal->attachments()->get() as $attachment) {
$attachment->delete();
$repository->destroy($attachment);
}
$transactionJournal->locations()->delete();
$transactionJournal->sourceJournalLinks()->delete();

View File

@@ -167,6 +167,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id');
$this->query->where('journal_meta.data', '!=', sprintf('%s', json_encode($externalId)));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -405,6 +406,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereLike('journal_meta.data', sprintf('%%%s%%', $internalReference));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -417,6 +419,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s%%', $internalReference));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -429,6 +432,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereNotLike('journal_meta.data', sprintf('%%%s"', $internalReference));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -441,6 +445,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereLike('journal_meta.data', sprintf('"%s%%', $internalReference));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -453,6 +458,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereLike('journal_meta.data', sprintf('%%%s"', $internalReference));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -465,6 +471,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->whereLike('journal_meta.data', sprintf('"%s%%', $internalReference));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -697,6 +704,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id');
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($externalId)));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -706,6 +714,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->where('journal_meta.data', '=', json_encode($url));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -718,6 +727,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'internal_reference');
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($internalReference)));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -727,6 +737,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'recurrence_id');
$this->query->where('journal_meta.data', '=', sprintf('%s', json_encode($recurringId)));
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -862,6 +873,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_id');
$this->query->whereNotNull('journal_meta.data');
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -871,6 +883,7 @@ trait MetaCollection
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', 'external_url');
$this->query->whereNotNull('journal_meta.data');
$this->query->whereNull('journal_meta.deleted_at');
return $this;
}
@@ -915,10 +928,13 @@ trait MetaCollection
$q1->where(static function (Builder $q2): void {
$q2->where('journal_meta.name', '=', 'external_id');
$q2->whereNull('journal_meta.data');
$q2->whereNull('journal_meta.deleted_at');
})->orWhere(static function (Builder $q3): void {
$q3->where('journal_meta.name', '!=', 'external_id');
$q3->whereNull('journal_meta.deleted_at');
})->orWhere(static function (Builder $q4): void {
$q4->whereNull('journal_meta.name');
$q4->whereNull('journal_meta.deleted_at');
});
});
@@ -933,10 +949,13 @@ trait MetaCollection
$q1->where(static function (Builder $q2): void {
$q2->where('journal_meta.name', '=', 'external_url');
$q2->whereNull('journal_meta.data');
$q2->whereNull('journal_meta.deleted_at');
})->orWhere(static function (Builder $q3): void {
$q3->where('journal_meta.name', '!=', 'external_url');
$q3->whereNull('journal_meta.deleted_at');
})->orWhere(static function (Builder $q4): void {
$q4->whereNull('journal_meta.name');
$q4->whereNull('journal_meta.deleted_at');
});
});

View File

@@ -100,7 +100,7 @@ class GroupCollector implements GroupCollectorInterface
'category_id',
'budget_id',
];
$this->stringFields = ['amount', 'foreign_amount'];
$this->stringFields = ['amount', 'foreign_amount', 'native_amount', 'native_foreign_amount'];
$this->total = 0;
$this->fields = [
// group
@@ -714,6 +714,9 @@ class GroupCollector implements GroupCollectorInterface
if (null === $transaction['amount']) {
throw new FireflyException(sprintf('Amount is NULL for a transaction in group #%d, please investigate.', $groudId));
}
$nativeAmount = (string) ('' === $transaction['native_amount'] ? '0' : $transaction['native_amount']);
$nativeForeignAmount = (string) ('' === $transaction['native_foreign_amount'] ? '0' : $transaction['native_foreign_amount']);
$foreignAmount = (string) ('' === $transaction['foreign_amount'] ? '0' : $transaction['foreign_amount']);
// set default:
if (!array_key_exists($currencyId, $groups[$groudId]['sums'])) {
@@ -722,8 +725,10 @@ class GroupCollector implements GroupCollectorInterface
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['currency_symbol'];
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['currency_decimal_places'];
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
$groups[$groudId]['sums'][$currencyId]['native_amount'] = '0';
}
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['amount']);
$groups[$groudId]['sums'][$currencyId]['native_amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['native_amount'], $nativeAmount);
if (null !== $transaction['foreign_amount'] && null !== $transaction['foreign_currency_id']) {
$currencyId = (int) $transaction['foreign_currency_id'];
@@ -735,8 +740,10 @@ class GroupCollector implements GroupCollectorInterface
$groups[$groudId]['sums'][$currencyId]['currency_symbol'] = $transaction['foreign_currency_symbol'];
$groups[$groudId]['sums'][$currencyId]['currency_decimal_places'] = $transaction['foreign_currency_decimal_places'];
$groups[$groudId]['sums'][$currencyId]['amount'] = '0';
$groups[$groudId]['sums'][$currencyId]['native_amount'] = '0';
}
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $transaction['foreign_amount']);
$groups[$groudId]['sums'][$currencyId]['amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $foreignAmount);
$groups[$groudId]['sums'][$currencyId]['native_amount'] = bcadd($groups[$groudId]['sums'][$currencyId]['amount'], $nativeForeignAmount);
}
}
}

View File

@@ -108,11 +108,14 @@ class ReconcileController extends Controller
if ($end->lt($start)) {
[$start, $end] = [$end, $start];
}
// move dates to end of day and start of day:
$start->startOfDay();
$end->endOfDay();
$startDate = clone $start;
$startDate->subDay();
$startBalance = Steam::finalAccountBalance($account, $startDate)['balance'];
$endBalance = Steam::finalAccountBalance($account, $end)['balance'];
$startDate->subDay()->endOfDay();
$startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
$endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);

View File

@@ -93,6 +93,11 @@ class ShowController extends Controller
if ($end->lt($start)) {
[$start, $end] = [$end, $start];
}
// make sure dates are end of day and start of day:
$start->startOfDay();
$end->endOfDay();
$location = $this->repository->getLocation($account);
$attachments = $this->repository->getAttachments($account);
$today = today(config('app.timezone'));
@@ -181,6 +186,8 @@ class ShowController extends Controller
$subTitle = (string) trans('firefly.all_journals_for_account', ['name' => $account->name]);
$periods = new Collection();
$end->endOfDay();
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setLimit($pageSize)->setPage($page)->withAccountInformation()->withCategoryInformation();

View File

@@ -109,8 +109,8 @@ class AccountController extends Controller
$accountNames = $this->extractNames($accounts);
// grab all balances
$startBalances = app('steam')->finalAccountsBalance($accounts, $start);
$endBalances = app('steam')->finalAccountsBalance($accounts, $end);
$startBalances = Steam::finalAccountsBalance($accounts, $start);
$endBalances = Steam::finalAccountsBalance($accounts, $end);
// loop the accounts, then check for balance and currency info.
foreach ($accounts as $account) {
@@ -139,6 +139,7 @@ class AccountController extends Controller
}
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToNative ? $this->defaultCurrency->code : $key;
$searchCode = 'balance' === $searchCode || 'native_balance' === $searchCode ? $this->defaultCurrency->code : $searchCode;
// Log::debug(sprintf('Search code is %s', $searchCode));
// see if there is an accompanying start amount.
// grab the difference and find the currency.
@@ -334,7 +335,7 @@ class AccountController extends Controller
$start = clone session('start', today(config('app.timezone'))->startOfMonth());
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
$defaultSet = $repository->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
Log::debug('Default set is ', $defaultSet);
// Log::debug('Default set is ', $defaultSet);
$frontpage = app('preferences')->get('frontpageAccounts', $defaultSet);
$frontpageArray = !is_array($frontpage->data) ? [] : $frontpage->data;
Log::debug('Frontpage preference set is ', $frontpageArray);
@@ -344,6 +345,9 @@ class AccountController extends Controller
}
$accounts = $repository->getAccountsById($frontpageArray);
// move to end of day for $end.
$end->endOfDay();
return response()->json($this->accountBalanceChart($accounts, $start, $end));
}
@@ -416,7 +420,9 @@ class AccountController extends Controller
*/
public function period(Account $account, Carbon $start, Carbon $end): JsonResponse
{
Log::debug(sprintf('Now in period("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d')));
$start->startOfDay();
$end->endOfDay();
Log::debug(sprintf('Now in period("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$chartData = [];
$cache = new CacheProperties();
$cache->addProperty('chart.account.period');
@@ -431,7 +437,7 @@ class AccountController extends Controller
// collect and filter balances for the entire period.
$step = $this->calculateStep($start, $end);
Log::debug(sprintf('Step is %s', $step));
$locale = app('steam')->getLocale();
$locale = Steam::getLocale();
$return = [];
// fix for issue https://github.com/firefly-iii/firefly-iii/issues/8041
@@ -442,11 +448,8 @@ class AccountController extends Controller
$format = (string) trans('config.month_and_day_js', [], $locale);
$accountCurrency = $this->accountRepository->getAccountCurrency($account);
Log::debug('One');
$range = Steam::finalAccountBalanceInRange($account, $start, $end, $this->convertToNative);
Log::debug('Two');
$range = Steam::filterAccountBalances($range, $account, $this->convertToNative, $accountCurrency);
Log::debug('Three');
// temp, get end balance.
Log::debug('temp get end balance');
@@ -462,25 +465,32 @@ class AccountController extends Controller
Log::debug('Balances exist at:');
foreach ($range as $key => $value) {
$newRange[] = ['date' => $key, 'info' => $value];
Log::debug(sprintf(' - %s', $key));
Log::debug(sprintf('%d - %s (%s)', count($newRange) - 1, $key, json_encode($value)));
}
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[0]['date']);
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[0]['date'])->endOfDay();
Log::debug(sprintf('Start of loop, $carbon is %s', $carbon->format('Y-m-d H:i:s')));
while ($end->gte($current)) {
$momentBalance = $previous;
$theDate = $current->format('Y-m-d');
while ($carbon->lte($current) && array_key_exists($expectedIndex, $newRange)) {
$momentBalance = $newRange[$expectedIndex]['info'];
Log::debug(sprintf('Expected index is %d!, date is %s, current is %s', $expectedIndex, $carbon->format('Y-m-d'), $current->format('Y-m-d')));
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[$expectedIndex]['date']);
++$expectedIndex;
}
// $theDate = $current->format('Y-m-d');
Log::debug(sprintf('Now at %s, with momentBalance %s', $current->format('Y-m-d H:i:s'), json_encode($momentBalance)));
// loop over the array with balances, find one that is earlier or on the same day.
while ($carbon->lte($current) && array_key_exists($expectedIndex, $newRange)) {
Log::debug(sprintf('[a] Expected index is %d, $carbon is %s, current is %s', $expectedIndex, $carbon->format('Y-m-d H:i:s'), $current->format('Y-m-d H:i:s')));
// grab the balance from that particular $expectedIndex
$momentBalance = $newRange[$expectedIndex]['info'];
++$expectedIndex;
// make new carbon based on the next found date. this should stop the loop.
if (array_key_exists($expectedIndex, $newRange)) {
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[$expectedIndex]['date'])->endOfDay();
}
}
Log::debug(sprintf('momentBalance is now %s', json_encode($momentBalance)));
$return = $this->updateChartKeys($return, $momentBalance);
$previous = $momentBalance;
Log::debug(sprintf('Now at %s', $theDate), $momentBalance);
// process each balance thing.
foreach ($momentBalance as $key => $amount) {
$label = $current->isoFormat($format);
@@ -489,8 +499,6 @@ class AccountController extends Controller
$current = app('navigation')->addPeriod($current, $step, 0);
// here too, to fix #8041, the data is corrected to the end of the period.
$current = app('navigation')->endOfX($current, $step, null);
Log::debug(sprintf('Next moment is %s', $current->format('Y-m-d')));
}
Log::debug('End of chart loop.');
// second loop (yes) to create nice array with info! Yay!
@@ -567,8 +575,8 @@ class AccountController extends Controller
$accountNames = $this->extractNames($accounts);
// grab all balances
$startBalances = app('steam')->finalAccountsBalance($accounts, $start);
$endBalances = app('steam')->finalAccountsBalance($accounts, $end);
$startBalances = Steam::finalAccountsBalance($accounts, $start);
$endBalances = Steam::finalAccountsBalance($accounts, $end);
// loop the accounts, then check for balance and currency info.
@@ -598,6 +606,7 @@ class AccountController extends Controller
}
// Log::debug(sprintf('Will process expense array "%s" with amount %s', $key, $endBalance));
$searchCode = $this->convertToNative ? $this->defaultCurrency->code : $key;
$searchCode = 'balance' === $searchCode || 'native_balance' === $searchCode ? $this->defaultCurrency->code : $searchCode;
// Log::debug(sprintf('Search code is %s', $searchCode));
// see if there is an accompanying start amount.
// grab the difference and find the currency.

View File

@@ -381,6 +381,7 @@ class DebugController extends Controller
'user_count' => User::count(),
'user_flags' => $userFlags,
'user_agent' => $userAgent,
'native' => Amount::getNativeCurrency(),
'convert_to_native' => Amount::convertToNative(),
'locale_attempts' => $localeAttempts,
'locale' => Steam::getLocale(),

View File

@@ -27,6 +27,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Http\JsonResponse;
/**
@@ -43,10 +44,14 @@ class FrontpageController extends Controller
{
$set = $repository->getPiggyBanks();
$info = [];
$native = Amount::getNativeCurrency();
$convertToNative = Amount::convertToNative();
/** @var PiggyBank $piggyBank */
foreach ($set as $piggyBank) {
$amount = $repository->getCurrentAmount($piggyBank);
$nativeAmount = $repository->getCurrentNativeAmount($piggyBank);
if (1 === bccomp($amount, '0')) {
// percentage!
$pct = 0;
@@ -58,8 +63,16 @@ class FrontpageController extends Controller
'id' => $piggyBank->id,
'name' => $piggyBank->name,
'amount' => $amount,
'native_amount' => $nativeAmount,
'target' => $piggyBank->target_amount,
'native_target' => $piggyBank->native_target_amount,
'percentage' => $pct,
// currency:
'currency_symbol' => $piggyBank->transactionCurrency->symbol,
'currency_decimal_places' => $piggyBank->transactionCurrency->decimal_places,
'native_currency_symbol' => $native->symbol,
'native_currency_decimal_places' => $native->decimal_places,
];
$info[] = $entry;
@@ -74,11 +87,10 @@ class FrontpageController extends Controller
}
);
$html = '';
if (0 !== count($info)) {
try {
$html = view('json.piggy-banks', compact('info'))->render();
$html = view('json.piggy-banks', compact('info', 'convertToNative', 'native'))->render();
} catch (\Throwable $e) {
app('log')->error(sprintf('Cannot render json.piggy-banks: %s', $e->getMessage()));
app('log')->error($e->getTraceAsString());

View File

@@ -189,13 +189,14 @@ class ReconcileController extends Controller
if ($end->lt($start)) {
[$end, $start] = [$start, $end];
}
$start->endOfDay();
$end->endOfDay();
$startDate = clone $start;
$startDate->subDay();
$end->endOfDay();
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->defaultCurrency;
$startBalance = Steam::finalAccountBalance($account, $startDate)['balance'];
$endBalance = Steam::finalAccountBalance($account, $end)['balance'];
$startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
$endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
// get the transactions
$selectionStart = clone $start;

View File

@@ -68,14 +68,16 @@ class AmountController extends Controller
*/
public function add(PiggyBank $piggyBank)
{
/** @var Carbon $date */
$date = session('end', today(config('app.timezone')));
$accounts = [];
$total = '0';
$totalSaved = $this->piggyRepos->getCurrentAmount($piggyBank);
$leftToSave = bcsub($piggyBank->target_amount, $totalSaved);
foreach ($piggyBank->accounts as $account) {
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, today(config('app.timezone'))->endOfDay());
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftToSave : min($leftOnAccount, $leftToSave);
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave);
$accounts[] = [
'account' => $account,
'left_on_account' => $leftOnAccount,
@@ -105,12 +107,13 @@ class AmountController extends Controller
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $account, $date);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank, $account);
$leftToSave = bcsub($piggyBank->target_amount, $savedSoFar);
$maxAmount = 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave);
$accounts[] = [
'account' => $account,
'left_on_account' => $leftOnAccount,
'saved_so_far' => $savedSoFar,
'left_to_save' => $leftToSave,
'max_amount' => 0 === bccomp($piggyBank->target_amount, '0') ? $leftOnAccount : min($leftOnAccount, $leftToSave),
'max_amount' => $maxAmount,
];
$total = bcadd($total, $leftOnAccount);
}

View File

@@ -120,7 +120,7 @@ class PreferencesController extends Controller
$pushoverUserToken = (string) Preferences::getEncrypted('pushover_user_token', '')->data;
$ntfyServer = Preferences::getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
$ntfyTopic = (string) Preferences::getEncrypted('ntfy_topic', '')->data;
$ntfyAuth = Preferences::get('ntfy_auth', false)->data;
$ntfyAuth = '1' === Preferences::get('ntfy_auth', false)->data;
$ntfyUser = Preferences::getEncrypted('ntfy_user', '')->data;
$ntfyPass = (string) Preferences::getEncrypted('ntfy_pass', '')->data;
$channels = config('notifications.channels');
@@ -264,6 +264,7 @@ class PreferencesController extends Controller
if ($convertToNative && !$this->convertToNative) {
// set to true!
Log::debug('User sets convertToNative to true.');
Preferences::set('convert_to_native', $convertToNative);
event(new UserGroupChangedDefaultCurrency(auth()->user()->userGroup));
}
Preferences::set('convert_to_native', $convertToNative);

View File

@@ -83,6 +83,8 @@ class ReportController extends Controller
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
}
$this->repository->cleanupBudgets();
$start->endOfDay(); // end of day so the final balance is at the end of that day.
$end->endOfDay();
app('view')->share(
'subTitle',
@@ -114,6 +116,8 @@ class ReportController extends Controller
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
}
$this->repository->cleanupBudgets();
$start->endOfDay(); // end of day so the final balance is at the end of that day.
$end->endOfDay();
app('view')->share(
'subTitle',
@@ -146,6 +150,8 @@ class ReportController extends Controller
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
}
$this->repository->cleanupBudgets();
$start->endOfDay(); // end of day so the final balance is at the end of that day.
$end->endOfDay();
app('view')->share(
'subTitle',
@@ -179,6 +185,8 @@ class ReportController extends Controller
}
$this->repository->cleanupBudgets();
$start->endOfDay(); // end of day so the final balance is at the end of that day.
$end->endOfDay();
app('view')->share(
'subTitle',
@@ -211,6 +219,8 @@ class ReportController extends Controller
}
$this->repository->cleanupBudgets();
$start->endOfDay(); // end of day so the final balance is at the end of that day.
$end->endOfDay();
app('view')->share(
'subTitle',
@@ -367,6 +377,8 @@ class ReportController extends Controller
return view('error')->with('message', (string) trans('firefly.end_after_start_date'));
}
$this->repository->cleanupBudgets();
$start->endOfDay(); // end of day so the final balance is at the end of that day.
$end->endOfDay();
app('view')->share(
'subTitle',

View File

@@ -112,6 +112,11 @@ class TransactionJournal extends Model
return $this->belongsTo(User::class);
}
public function userGroup(): BelongsTo
{
return $this->belongsTo(UserGroup::class);
}
public function attachments(): MorphMany
{
return $this->morphMany(Attachment::class, 'attachable');

View File

@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Support\Facades\Log;
class ReturnsSettings
{
@@ -42,6 +43,7 @@ class ReturnsSettings
private static function getNtfySettings(string $type, ?User $user): array
{
Log::debug(sprintf('Getting Ntfy settings for %s and user #%d', $type, $user?->id));
$settings = [
'ntfy_server' => 'https://ntfy.sh',
'ntfy_topic' => '',
@@ -56,6 +58,7 @@ class ReturnsSettings
$settings['ntfy_auth'] = Preferences::getForUser($user, 'ntfy_auth', false)->data;
$settings['ntfy_user'] = Preferences::getEncryptedForUser($user, 'ntfy_user', '')->data;
$settings['ntfy_pass'] = Preferences::getEncryptedForUser($user, 'ntfy_pass', '')->data;
Log::debug(sprintf('Auth is %s, user = "%s"', var_export($settings['ntfy_auth'], true), $settings['ntfy_user']));
}
if ('owner' === $type) {
$settings['ntfy_server'] = FireflyConfig::getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
@@ -63,6 +66,7 @@ class ReturnsSettings
$settings['ntfy_auth'] = FireflyConfig::get('ntfy_auth', false)->data;
$settings['ntfy_user'] = FireflyConfig::getEncrypted('ntfy_user', '')->data;
$settings['ntfy_pass'] = FireflyConfig::getEncrypted('ntfy_pass', '')->data;
Log::debug(sprintf('Auth is %s, user = "%s"', var_export($settings['ntfy_auth'], true), $settings['ntfy_user']));
}
// overrule config.
@@ -74,7 +78,9 @@ class ReturnsSettings
config(['ntfy-notification-channel.authentication.enabled' => true]);
config(['ntfy-notification-channel.authentication.username' => $settings['ntfy_user']]);
config(['ntfy-notification-channel.authentication.password' => $settings['ntfy_pass']]);
Log::debug('Authentication enabled for Ntfy.');
}
Log::debug('Return ntfy settings.');
return $settings;
}

View File

@@ -23,9 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Providers;
use Barryvdh\Debugbar\DataCollector\QueryCollector;
use Barryvdh\Debugbar\Facades\Debugbar;
use DebugBar\DebugBarException;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Route;
@@ -53,17 +50,6 @@ class AppServiceProvider extends ServiceProvider
$headers['X-Trace-Id'] = $uuid;
}
if (config('app.debug')) {
try {
/** @var QueryCollector $collector */
$collector = Debugbar::getCollector('queries');
$info = $collector->collect();
$headers['X-Debug-QueryCount'] = $info['nb_statements'] ?? 0;
} catch (DebugBarException $e) {
// ignore error.
}
}
return response()
->json($value)
->withHeaders($headers)

View File

@@ -169,16 +169,11 @@ class EventServiceProvider extends ServiceProvider
// is a Transaction Journal related event.
StoredTransactionGroup::class => [
'FireflyIII\Handlers\Events\StoredGroupEventHandler@processRules',
'FireflyIII\Handlers\Events\StoredGroupEventHandler@recalculateCredit',
'FireflyIII\Handlers\Events\StoredGroupEventHandler@triggerWebhooks',
'FireflyIII\Handlers\Events\StoredGroupEventHandler@runAllHandlers',
],
// is a Transaction Journal related event.
UpdatedTransactionGroup::class => [
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@unifyAccounts',
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@processRules',
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@recalculateCredit',
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@triggerWebhooks',
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@runAllHandlers',
],
DestroyedTransactionGroup::class => [
'FireflyIII\Handlers\Events\DestroyedGroupEventHandler@triggerWebhooks',

View File

@@ -57,7 +57,7 @@ class CurrencyRepository implements CurrencyRepositoryInterface
*/
public function getCompleteSet(): Collection
{
return TransactionCurrency::orderBy('code', 'ASC')->get();
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
}
/**

View File

@@ -308,6 +308,24 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return $sum;
}
/**
* Get current amount saved in piggy bank.
*/
public function getCurrentNativeAmount(PiggyBank $piggyBank, ?Account $account = null): string
{
$sum = '0';
foreach ($piggyBank->accounts as $current) {
if (null !== $account && $account->id !== $current->id) {
continue;
}
$amount = (string) $current->pivot->native_current_amount;
$amount = '' === $amount ? '0' : $amount;
$sum = bcadd($sum, $amount);
}
return $sum;
}
public function getRepetition(PiggyBank $piggyBank, bool $overrule = false): ?PiggyBankRepetition
{
if (false === $overrule) {

View File

@@ -40,6 +40,8 @@ interface PiggyBankRepositoryInterface
{
public function addAmount(PiggyBank $piggyBank, Account $account, string $amount, ?TransactionJournal $journal = null): bool;
public function getCurrentNativeAmount(PiggyBank $piggyBank, ?Account $account = null): string;
public function addAmountToPiggyBank(PiggyBank $piggyBank, string $amount, TransactionJournal $journal): void;
public function canAddAmount(PiggyBank $piggyBank, Account $account, string $amount): bool;

View File

@@ -93,7 +93,7 @@ class RecurringRepository implements RecurringRepositoryInterface
}
/**
* Returns all of the user's recurring transactions.
* Returns all the user's recurring transactions.
*/
public function get(): Collection
{

View File

@@ -108,6 +108,6 @@ class ExchangeRateRepository implements ExchangeRateRepositoryInterface
#[\Override]
public function getAll(): Collection
{
return $this->userGroup->currencyExchangeRates()->get();
return $this->userGroup->currencyExchangeRates()->orderBy('date', 'ASC')->get();
}
}

View File

@@ -513,7 +513,7 @@ class ExportDataGenerator
'currency_code', 'foreign_currency_code', 'source_name', 'source_type', 'destination_name', 'destination_type', 'amount', 'foreign_amount', 'category', 'budget', 'piggy_bank', 'tags',
];
$records = [];
$recurrences = $recurringRepos->getAll();
$recurrences = $recurringRepos->get();
/** @var Recurrence $recurrence */
foreach ($recurrences as $recurrence) {

View File

@@ -88,6 +88,11 @@ class ExchangeRateConverter
return '1';
}
if ($from->id === $to->id) {
Log::debug('ExchangeRateConverter: From and to are the same, return "1".');
return '1';
}
$rate = $this->getRate($from, $to, $date);
return '0' === $rate ? '1' : $rate;
@@ -103,7 +108,7 @@ class ExchangeRateConverter
// find in cache
if (null !== $res) {
Log::debug(sprintf('ExchangeRateConverter: Return cached rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
Log::debug(sprintf('ExchangeRateConverter: Return cached rate from %s to %s on %s.', $from->code, $to->code, $date->format('Y-m-d')));
return $res;
}
@@ -112,7 +117,7 @@ class ExchangeRateConverter
$rate = $this->getFromDB($from->id, $to->id, $date->format('Y-m-d'));
if (null !== $rate) {
Cache::forever($key, $rate);
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from %s to %s on %s.', $from->code, $to->code, $date->format('Y-m-d')));
return $rate;
}
@@ -122,7 +127,7 @@ class ExchangeRateConverter
if (null !== $rate) {
$rate = bcdiv('1', $rate);
Cache::forever($key, $rate);
Log::debug(sprintf('ExchangeRateConverter: Return inverse DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
Log::debug(sprintf('ExchangeRateConverter: Return inverse DB rate from %s to %s on %s.', $from->code, $to->code, $date->format('Y-m-d')));
return $rate;
}
@@ -133,14 +138,14 @@ class ExchangeRateConverter
// combined (if present), they can be used to calculate the necessary conversion rate.
if (0 === bccomp('0', $first) || 0 === bccomp('0', $second)) {
Log::warning(sprintf('$first is "%s" and $second is "%s"', $first, $second));
Log::warning(sprintf('There is not enough information to convert %s to %s on date %s', $from->code, $to->code, $date->format('Y-m-d')));
return '1';
}
$second = bcdiv('1', $second);
$rate = bcmul($first, $second);
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from #%d to #%d on %s.', $from->id, $to->id, $date->format('Y-m-d')));
Log::debug(sprintf('ExchangeRateConverter: Return DB rate from %s to %s on %s.', $from->code, $to->code, $date->format('Y-m-d')));
Cache::forever($key, $rate);
return $rate;
@@ -154,6 +159,8 @@ class ExchangeRateConverter
private function getFromDB(int $from, int $to, string $date): ?string
{
if ($from === $to) {
Log::debug('ExchangeRateConverter: From and to are the same, return "1".');
return '1';
}
$key = sprintf('cer-%d-%d-%s', $from, $to, $date);
@@ -173,7 +180,7 @@ class ExchangeRateConverter
if ('' === $rate) {
return null;
}
Log::debug(sprintf('ExchangeRateConverter: Found !cached! rate from #%d to #%d on %s.', $from, $to, $date));
Log::debug(sprintf('ExchangeRateConverter: Found cached rate from #%d to #%d on %s.', $from, $to, $date));
return $rate;
}

View File

@@ -33,6 +33,7 @@ use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Trait ChartGeneration
@@ -57,7 +58,7 @@ trait ChartGeneration
if ($cache->has()) {
return $cache->get();
}
app('log')->debug('Regenerate chart.account.account-balance-chart from scratch.');
Log::debug('Regenerate chart.account.account-balance-chart from scratch.');
$locale = app('steam')->getLocale();
/** @var GeneratorInterface $generator */
@@ -69,8 +70,11 @@ trait ChartGeneration
$default = app('amount')->getNativeCurrency();
$chartData = [];
Log::debug(sprintf('Start of accountBalanceChart(list, %s, %s)', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
/** @var Account $account */
foreach ($accounts as $account) {
Log::debug(sprintf('Now at account #%d ("%s)', $account->id, $account->name));
$currency = $accountRepos->getAccountCurrency($account) ?? $default;
$useNative = $convertToNative && $default->id !== $currency->id;
$field = $useNative ? 'native_balance' : 'balance';
@@ -82,8 +86,9 @@ trait ChartGeneration
];
$currentStart = clone $start;
$range = Steam::finalAccountBalanceInRange($account, $start, clone $end, $this->convertToNative);
$range = Steam::finalAccountBalanceInRange($account, clone $start, clone $end, $this->convertToNative);
$previous = array_values($range)[0];
Log::debug(sprintf('Start balance for account #%d ("%s) is', $account->id, $account->name), $previous);
while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d');
$label = trim($currentStart->isoFormat((string) trans('config.month_and_day_js', [], $locale)));

View File

@@ -203,11 +203,10 @@ trait PeriodOverview
$currencySymbol = $journal['currency_symbol'];
$currencyDecimalPlaces = $journal['currency_decimal_places'];
$foreignCurrencyId = $journal['foreign_currency_id'];
$amount = $journal['amount'];
$amount = $journal['amount'] ?? '0';
if ($this->convertToNative && $currencyId !== $this->defaultCurrency->id && $foreignCurrencyId !== $this->defaultCurrency->id) {
$amount = $journal['native_amount'];
$amount = $journal['native_amount'] ?? '0';
$currencyId = $this->defaultCurrency->id;
$currencyCode = $this->defaultCurrency->code;
$currencyName = $this->defaultCurrency->name;
@@ -220,7 +219,7 @@ trait PeriodOverview
$currencyName = $journal['foreign_currency_name'];
$currencySymbol = $journal['foreign_currency_symbol'];
$currencyDecimalPlaces = $journal['foreign_currency_decimal_places'];
$amount = $journal['foreign_amount'];
$amount = $journal['foreign_amount'] ?? '0';
}
$return[$currencyId] ??= [
'amount' => '0',

View File

@@ -202,7 +202,7 @@ class Preferences
return null;
}
if ('' === $result->data) {
Log::warning(sprintf('Empty encrypted preference found: "%s"', $name));
// Log::warning(sprintf('Empty encrypted preference found: "%s"', $name));
return $result;
}
@@ -214,7 +214,7 @@ class Preferences
Log::debug('Set data to NULL');
$result->data = null;
}
Log::error(sprintf('Could not decrypt preference "%s": %s', $name, $e->getMessage()));
// Log::error(sprintf('Could not decrypt preference "%s": %s', $name, $e->getMessage()));
return $result;
}
@@ -226,7 +226,7 @@ class Preferences
{
$result = $this->getForUser($user, $name, $default);
if ('' === $result->data) {
Log::warning(sprintf('Empty encrypted preference found: "%s"', $name));
// Log::warning(sprintf('Empty encrypted preference found: "%s"', $name));
return $result;
}
@@ -238,7 +238,7 @@ class Preferences
Log::debug('Set data to NULL');
$result->data = null;
}
Log::error(sprintf('Could not decrypt preference "%s": %s', $name, $e->getMessage()));
// Log::error(sprintf('Could not decrypt preference "%s": %s', $name, $e->getMessage()));
return $result;
}

View File

@@ -55,4 +55,43 @@ abstract class Node
return $this->prohibited;
}
public function equals(self $compare): bool
{
if ($compare->isProhibited(false) !== $this->isProhibited(false)) {
Log::debug('Return false because prohibited status is different');
return false;
}
if ($compare instanceof NodeGroup) {
if (count($compare->getNodes()) !== count($this->getNodes())) {
Log::debug(sprintf('Return false because node count is different. Original is %d, compare is %d', count($this->getNodes()), count($compare->getNodes())));
// var_dump($this);
// var_dump($compare);
// exit;
return false;
}
/**
* @var int $index
* @var Node $node
*/
foreach ($this->getNodes() as $index => $node) {
if (false === $node->equals($compare->getNodes()[$index])) {
Log::debug('Return false because nodes are different!');
var_dump($this);
var_dump($compare);
exit;
return false;
}
}
return true;
}
return true;
}
}

View File

@@ -71,6 +71,7 @@ class QueryParser implements QueryParserInterface
while ($this->position < strlen($this->query)) {
$char = $this->query[$this->position];
// Log::debug(sprintf('Char #%d: %s', $this->position, $char));
// If we're in a quoted string, we treat all characters except another quote as ordinary characters
if ($inQuotes) {
@@ -150,15 +151,19 @@ class QueryParser implements QueryParserInterface
case ':':
if ('' !== $tokenUnderConstruction) {
$skipNext = false;
if ('' === $tokenUnderConstruction) { // @phpstan-ignore-line
// In any other location, it's just a normal character
$tokenUnderConstruction .= $char;
$skipNext = true;
}
if ('' !== $tokenUnderConstruction && !$skipNext) {
Log::debug(sprintf('Turns out that "%s" is a field name. Reset the token.', $tokenUnderConstruction));
// If we meet a colon with a left-hand side string, we know we're in a field and are about to set up the value
$fieldName = $tokenUnderConstruction;
$tokenUnderConstruction = '';
}
if ('' === $tokenUnderConstruction) { // @phpstan-ignore-line
// In any other location, it's just a normal character
$tokenUnderConstruction .= $char;
}
break;

View File

@@ -28,10 +28,11 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use FireflyIII\Support\Facades\Amount;
/**
* Class Steam.
@@ -58,8 +59,8 @@ class Steam
public function finalAccountBalanceInRange(Account $account, Carbon $start, Carbon $end, bool $convertToNative): array
{
// expand period.
$start->subDay()->startOfDay();
$end->addDay()->endOfDay();
$start->startOfDay();
$end->endOfDay();
Log::debug(sprintf('finalAccountBalanceInRange(#%d, %s, %s)', $account->id, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// set up cache
@@ -75,100 +76,84 @@ class Steam
$balances = [];
$formatted = $start->format('Y-m-d');
$startBalance = $this->finalAccountBalance($account, $start);
$defaultCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
$nativeCurrency = app('amount')->getNativeCurrencyByUserGroup($account->user->userGroup);
$accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = null !== $accountCurrency;
$currency = $accountCurrency ?? $defaultCurrency;
$currency = $accountCurrency ?? $nativeCurrency;
Log::debug(sprintf('Currency is %s', $currency->code));
// set start balances:
$startBalance[$currency->code] ??= '0';
if ($hasCurrency) {
$startBalance[$accountCurrency->code] ??= '0';
}
if (!$hasCurrency) {
Log::debug(sprintf('Also set start balance in %s', $defaultCurrency->code));
$startBalance[$defaultCurrency->code] ??= '0';
Log::debug(sprintf('Also set start balance in %s', $nativeCurrency->code));
$startBalance[$nativeCurrency->code] ??= '0';
}
$currencies = [
$currency->id => $currency,
$defaultCurrency->id => $defaultCurrency,
$nativeCurrency->id => $nativeCurrency,
];
$startBalance[$currency->code] ??= '0';
$balances[$formatted] = $startBalance;
Log::debug('Final start balance: ', $startBalance);
// sums up the balance changes per day, for foreign, native and normal amounts.
// sums up the balance changes per day.
Log::debug(sprintf('Date >= %s and <= %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$set = $account->transactions()
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transaction_journals.date', '>=', $start->format('Y-m-d H:i:s'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s'))
->groupBy('transaction_journals.date')
->groupBy('transactions.transaction_currency_id')
->groupBy('transactions.foreign_currency_id')
->orderBy('transaction_journals.date', 'ASC')
->whereNull('transaction_journals.deleted_at')
->get(
[ // @phpstan-ignore-line
'transaction_journals.date',
'transactions.transaction_currency_id',
DB::raw('SUM(transactions.amount) AS modified'),
'transactions.foreign_currency_id',
DB::raw('SUM(transactions.foreign_amount) AS modified_foreign'),
DB::raw('SUM(transactions.native_amount) AS modified_native'),
DB::raw('SUM(transactions.amount) AS sum_of_day'),
]
)
;
$currentBalance = $startBalance;
$converter = new ExchangeRateConverter();
/** @var Transaction $entry */
foreach ($set as $entry) {
// normal, native and foreign amount
// get date object
$carbon = new Carbon($entry->date, $entry->date_tz);
$modified = (string) (null === $entry->modified ? '0' : $entry->modified);
$foreignModified = (string) (null === $entry->modified_foreign ? '0' : $entry->modified_foreign);
$nativeModified = (string) (null === $entry->modified_native ? '0' : $entry->modified_native);
$carbonKey = $carbon->format('Y-m-d');
// make sure sum is a string:
$sumOfDay = (string) (null === $entry->sum_of_day ? '0' : $entry->sum_of_day);
// find currency of this entry.
// find currency of this entry, does not have to exist.
$currencies[$entry->transaction_currency_id] ??= TransactionCurrency::find($entry->transaction_currency_id);
// make sure this $entry has its own $entryCurrency
/** @var TransactionCurrency $entryCurrency */
$entryCurrency = $currencies[$entry->transaction_currency_id];
Log::debug(sprintf('Processing transaction(s) on date %s', $carbon->format('Y-m-d H:i:s')));
Log::debug(sprintf('Processing transaction(s) on moment %s', $carbon->format('Y-m-d H:i:s')));
$currentBalance[$entryCurrency->code] ??= '0';
$currentBalance[$entryCurrency->code] = bcadd($sumOfDay, $currentBalance[$entryCurrency->code]);
// if convert to native, if NOT convert to native.
if ($convertToNative) {
Log::debug(sprintf('Amount is %s %s, foreign amount is %s, native amount is %s', $entryCurrency->code, $this->bcround($modified, 2), $this->bcround($foreignModified, 2), $this->bcround($nativeModified, 2)));
// if the currency is the default currency add to native balance + currency balance
if ($entry->transaction_currency_id === $defaultCurrency->id) {
Log::debug('Add amount to native.');
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $modified);
}
// add to native balance.
if ($entry->foreign_currency_id !== $defaultCurrency->id) {
// this check is not necessary, because if the foreign currency is the same as the default currency, the native amount is zero.
// so adding this would mean nothing.
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeModified);
}
if ($entry->foreign_currency_id === $defaultCurrency->id) {
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $foreignModified);
}
// add to balance if is the same.
if ($entry->transaction_currency_id === $accountCurrency?->id) {
$currentBalance['balance'] = bcadd($currentBalance['balance'], $modified);
}
// add currency balance
$currentBalance[$entryCurrency->code] = bcadd($currentBalance[$entryCurrency->code] ?? '0', $modified);
}
// if not convert to native, add the amount to "balance", do nothing else.
if (!$convertToNative) {
Log::debug(sprintf('Amount is %s %s, foreign amount is %s, native amount is %s', $entryCurrency->code, $modified, $foreignModified, $nativeModified));
// add to balance, as expected.
$currentBalance['balance'] = bcadd($currentBalance['balance'] ?? '0', $modified);
// add to GBP, as expected.
$currentBalance[$entryCurrency->code] = bcadd($currentBalance[$entryCurrency->code] ?? '0', $modified);
$currentBalance['balance'] = bcadd($currentBalance['balance'], $sumOfDay);
}
$balances[$carbon->format('Y-m-d')] = $currentBalance;
Log::debug('Updated entry', $currentBalance);
// if convert to native add the converted amount to "native_balance".
if ($convertToNative) {
$nativeSumOfDay = $converter->convert($entryCurrency, $nativeCurrency, $carbon, $sumOfDay);
$currentBalance['native_balance'] = bcadd($currentBalance['native_balance'], $nativeSumOfDay);
}
// just set it.
$balances[$carbonKey] = $currentBalance;
Log::debug(sprintf('Updated entry [%s]', $carbonKey), $currentBalance);
}
$cache->store($balances);
Log::debug('End of method');
@@ -275,83 +260,37 @@ class Steam
/**
* Returns the balance of an account at exact moment given. Array with at least one value.
* Always returns:
* "balance": balance in the account's currency OR user's native currency if the account has no currency
* "EUR": balance in EUR (or whatever currencies the account has balance in)
*
* "balance" the balance in whatever currency the account has, so the sum of all transaction that happen to have
* THAT currency.
* "native_balance" the balance according to the "native_amount" + "native_foreign_amount" fields.
* "ABC" the balance in this particular currency code (may repeat for each found currency).
*
* Het maakt niet uit of de native currency wel of niet gelijk is aan de account currency.
* Optelsom zou hetzelfde moeten zijn. Als het EUR is en de rekening ook is native_amount 0.
* Zo niet is amount 0 en native_amount het bedrag.
*
* Eerst een som van alle transacties in de native currency. Alle EUR bij elkaar opgeteld.
* Om te weten wat er nog meer op de rekening gebeurt, pak alles waar currency niet EUR is, en de foreign ook niet,
* en tel native_amount erbij op.
* Daarna pak je alle transacties waar currency niet EUR is, en de foreign wel, en tel foreign_amount erbij op.
*
* Wil je niks weten van native currencies, pak je:
*
* Eerst een som van alle transacties gegroepeerd op currency. Einde.
* If the user has $convertToNative:
* "balance": balance in the account's currency OR user's native currency if the account has no currency
* --> "native_balance": balance in the user's native balance, with all amounts converted to native.
* "EUR": balance in EUR (or whatever currencies the account has balance in)
*/
public function finalAccountBalance(Account $account, Carbon $date): array
{
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty($date);
if ($cache->has()) {
return $cache->get();
// Log::debug(sprintf('CACHED finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
// return $cache->get();
}
Log::debug(sprintf('Now in finalAccountBalance(#%d, "%s", "%s")', $account->id, $account->name, $date->format('Y-m-d H:i:s')));
Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
$native = Amount::getNativeCurrencyByUserGroup($account->user->userGroup);
$convertToNative = Amount::convertToNative($account->user);
$accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = null !== $accountCurrency;
$currency = $hasCurrency ? $accountCurrency : $native;
$return = [];
// first, the "balance", as described earlier.
if ($convertToNative) {
// normal balance
$return['balance'] = (string) $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
->where('transactions.transaction_currency_id', $native->id)
->sum('transactions.amount')
;
// plus virtual balance, if the account has a virtual_balance in the native currency
if ($native->id === $accountCurrency?->id) {
$return['balance'] = bcadd('' === (string) $account->virtual_balance ? '0' : $account->virtual_balance, $return['balance']);
}
// Log::debug(sprintf('balance is (%s only) %s (with virtual balance)', $native->code, $this->bcround($return['balance'], 2)));
// native balance
$return['native_balance'] = (string) $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
->whereNot('transactions.transaction_currency_id', $native->id)
->sum('transactions.native_amount')
;
// plus native virtual balance.
$return['native_balance'] = bcadd('' === (string) $account->native_virtual_balance ? '0' : $account->native_virtual_balance, $return['native_balance']);
// Log::debug(sprintf('native_balance is (all transactions to %s) %s (with virtual balance)', $native->code, $this->bcround($return['native_balance'])));
// plus foreign transactions in THIS currency.
$sum = (string) $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
->whereNot('transactions.transaction_currency_id', $native->id)
->where('transactions.foreign_currency_id', $native->id)
->sum('transactions.foreign_amount')
;
$return['native_balance'] = bcadd($return['native_balance'], $sum);
// Log::debug(sprintf('Foreign amount transactions add (%s only) %s, total native_balance is now %s', $native->code, $this->bcround($sum), $this->bcround($return['native_balance'])));
}
// balance(s) in other (all) currencies.
$return = [
'native_balance' => '0',
'balance' => '0', // this key is overwritten right away, but I must remember it is always created.
];
// balance(s) in all currencies.
$array = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
@@ -360,31 +299,38 @@ class Steam
;
$others = $this->groupAndSumTransactions($array, 'code', 'amount');
// Log::debug('All balances are (joined)', $others);
// if the account has no own currency preference, drop balance in favor of native balance
if ($hasCurrency && !$convertToNative) {
// if there is no request to convert, take this as "balance" and "native_balance".
$return['balance'] = $others[$currency->code] ?? '0';
$return['native_balance'] = $others[$currency->code] ?? '0';
// Log::debug(sprintf('Set balance + native_balance to %s', $return['balance']));
if (!$convertToNative) {
unset($return['native_balance']);
// Log::debug(sprintf('Set balance to %s, unset native_balance', $return['balance']));
}
// if there is a request to convert, convert to "native_balance" and use "balance" for whichever amount is in the native currency.
if ($convertToNative) {
$return['native_balance'] = $this->convertAllBalances($others, $native, $date); // todo sum all and convert.
// Log::debug(sprintf('Set native_balance to %s', $return['native_balance']));
}
// if the currency is the same as the native currency, set the native_balance to the balance for consistency.
// if($currency->id === $native->id) {
// $return['native_balance'] = $return['balance'];
// }
// either way, the balance is always combined with the virtual balance:
$virtualBalance = (string) ('' === (string) $account->virtual_balance ? '0' : $account->virtual_balance);
if (!$hasCurrency && array_key_exists('balance', $return)) {
// Log::debug('Account has no currency preference, dropping balance in favor of native balance.');
$sum = bcadd($return['balance'], $return['native_balance']);
// Log::debug(sprintf('%s + %s = %s', $return['balance'], $return['native_balance'], $sum));
$return['native_balance'] = $sum;
unset($return['balance']);
if ($convertToNative) {
// the native balance is combined with a converted virtual_balance:
$converter = new ExchangeRateConverter();
$nativeVirtualBalance = $converter->convert($currency, $native, $date, $virtualBalance);
$return['native_balance'] = bcadd($nativeVirtualBalance, $return['native_balance']);
// Log::debug(sprintf('Native virtual balance makes the native total %s', $return['native_balance']));
}
if (!$convertToNative) {
// if not, also increase the balance + native balance for consistency.
$return['balance'] = bcadd($return['balance'], $virtualBalance);
// Log::debug(sprintf('Virtual balance makes the (native) total %s', $return['balance']));
}
$final = array_merge($return, $others);
// Log::debug('Return is', $final);
Log::debug('Final balance is', $final);
$cache->store($final);
return array_merge($return, $others);
// Log::debug('Return is', $final);
return $final;
}
public function filterAccountBalances(array $total, Account $account, bool $convertToNative, ?TransactionCurrency $currency = null): array
@@ -410,17 +356,18 @@ class Steam
$defaultCurrency = app('amount')->getNativeCurrency();
if ($convertToNative) {
if ($defaultCurrency->id === $currency?->id) {
Log::debug(sprintf('Unset "native_balance" and "%s" for account #%d', $defaultCurrency->code, $account->id));
Log::debug(sprintf('Unset "native_balance" and [%s] for account #%d', $defaultCurrency->code, $account->id));
unset($set['native_balance'], $set[$defaultCurrency->code]);
}
// todo rethink this logic.
if (null !== $currency && $defaultCurrency->id !== $currency->id) {
Log::debug(sprintf('Unset balance for account #%d', $account->id));
unset($set['balance']);
}
if (null === $currency) {
Log::debug(sprintf('TEMP DO NOT Drop defaultCurrency balance for account #%d', $account->id));
// unset($set[$this->defaultCurrency->code]);
Log::debug(sprintf('Unset balance for account #%d', $account->id));
unset($set['balance']);
}
}
@@ -428,16 +375,15 @@ class Steam
if (null === $currency) {
Log::debug(sprintf('Unset native_balance and make defaultCurrency balance the balance for account #%d', $account->id));
$set['balance'] = $set[$defaultCurrency->code] ?? '0';
unset($set['native_balance'], $set[$defaultCurrency->code]);
unset($set[$defaultCurrency->code]);
}
if (null !== $currency) {
Log::debug(sprintf('Unset native_balance + defaultCurrency + currencyCode balance for account #%d', $account->id));
unset($set['native_balance'], $set[$defaultCurrency->code], $set[$currency->code]);
Log::debug(sprintf('Unset [%s] + [%s] balance for account #%d', $defaultCurrency->code, $currency->code, $account->id));
unset($set[$defaultCurrency->code], $set[$currency->code]);
}
}
// put specific value first in array.
if (array_key_exists('native_balance', $set)) {
$set = ['native_balance' => $set['native_balance']] + $set;
@@ -687,4 +633,21 @@ class Steam
return $amount;
}
private function convertAllBalances(array $others, TransactionCurrency $native, Carbon $date): string
{
$total = '0';
$converter = new ExchangeRateConverter();
foreach ($others as $key => $amount) {
$currency = TransactionCurrency::where('code', $key)->first();
if (null === $currency) {
continue;
}
$current = $converter->convert($currency, $native, $date, $amount);
Log::debug(sprintf('Convert %s %s to %s %s', $currency->code, $amount, $native->code, $current));
$total = bcadd($current, $total);
}
return $total;
}
}

View File

@@ -26,6 +26,8 @@ namespace FireflyIII\Support\Twig;
use FireflyIII\Models\Account as AccountModel;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use Illuminate\Support\Facades\Log;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
@@ -114,6 +116,11 @@ class AmountFormat extends AbstractExtension
/** @var TransactionCurrency $currency */
$currency = TransactionCurrency::whereCode($code)->first();
if (null === $currency) {
Log::error(sprintf('Could not find currency with code "%s". Fallback to native currency.', $code));
$currency = Amount::getNativeCurrency();
Log::error(sprintf('Fallback currency is "%s".', $currency->code));
}
return app('amount')->formatAnything($currency, $amount, $coloured);
},

View File

@@ -72,6 +72,7 @@ class General extends AbstractExtension
$default = Amount::getNativeCurrency();
$convertToNative = Amount::convertToNative();
$useNative = $convertToNative && $default->id !== $currency->id;
$currency = null === $currency ? $default : $currency;
$strings = [];
foreach ($info as $key => $balance) {
if ('balance' === $key) {

View File

@@ -99,10 +99,8 @@ class PiggyBankTransformer extends AbstractTransformer
'id' => (string) $piggyBank->id,
'created_at' => $piggyBank->created_at->toAtomString(),
'updated_at' => $piggyBank->updated_at->toAtomString(),
'accounts' => $this->renderAccounts($piggyBank),
// 'account_id' => (string)$piggyBank->account_id,
// 'account_name' => $piggyBank->account->name,
'name' => $piggyBank->name,
'accounts' => $this->renderAccounts($piggyBank),
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
@@ -134,9 +132,10 @@ class PiggyBankTransformer extends AbstractTransformer
$return = [];
foreach ($piggyBank->accounts()->get() as $account) {
$return[] = [
'id' => $account->id,
'id' => (string) $account->id,
'name' => $account->name,
'current_amount' => (string) $account->pivot->current_amount,
'native_current_amount' => (string) $account->pivot->native_current_amount,
// TODO add balance, add left to save.
];
}

View File

@@ -35,6 +35,7 @@ use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\Account\AccountRepository;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\User;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/**
@@ -52,12 +53,12 @@ trait TransactionValidation
if ($validator->errors()->count() > 0) {
return;
}
app('log')->debug('Now in validateAccountInformation (TransactionValidation) ()');
Log::debug('Now in validateAccountInformation (TransactionValidation) ()');
$transactions = $this->getTransactionsArray($validator);
$data = $validator->getData();
$transactionType = $data['type'] ?? 'invalid';
app('log')->debug(sprintf('Going to loop %d transaction(s)', count($transactions)));
Log::debug(sprintf('Going to loop %d transaction(s)', count($transactions)));
/**
* @var int|string $index
@@ -75,15 +76,15 @@ trait TransactionValidation
protected function getTransactionsArray(Validator $validator): array
{
app('log')->debug('Now in getTransactionsArray');
Log::debug('Now in getTransactionsArray');
$data = $validator->getData();
$transactions = [];
if (array_key_exists('transactions', $data) && is_array($data['transactions'])) {
app('log')->debug('Transactions key exists and is array.');
Log::debug('Transactions key exists and is array.');
$transactions = $data['transactions'];
}
if (array_key_exists('transactions', $data) && !is_array($data['transactions'])) {
app('log')->debug(sprintf('Transactions key exists but is NOT array, its a %s', gettype($data['transactions'])));
Log::debug(sprintf('Transactions key exists but is NOT array, its a %s', gettype($data['transactions'])));
}
return $transactions;
@@ -94,7 +95,7 @@ trait TransactionValidation
*/
protected function validateSingleAccount(Validator $validator, int $index, string $transactionType, array $transaction): void
{
app('log')->debug(sprintf('Now in validateSingleAccount(%d)', $index));
Log::debug(sprintf('Now in validateSingleAccount(%d)', $index));
/** @var AccountValidator $accountValidator */
$accountValidator = app(AccountValidator::class);
@@ -158,11 +159,11 @@ trait TransactionValidation
*/
protected function sanityCheckReconciliation(Validator $validator, string $transactionType, int $index, array $source, array $destination): void
{
app('log')->debug('Now in sanityCheckReconciliation');
Log::debug('Now in sanityCheckReconciliation');
if (TransactionTypeEnum::RECONCILIATION->value === ucfirst($transactionType)
&& null === $source['id'] && null === $source['name'] && null === $destination['id'] && null === $destination['name']
) {
app('log')->debug('Both are NULL, error!');
Log::debug('Both are NULL, error!');
$validator->errors()->add(sprintf('transactions.%d.source_id', $index), trans('validation.reconciliation_either_account'));
$validator->errors()->add(sprintf('transactions.%d.source_name', $index), trans('validation.reconciliation_either_account'));
$validator->errors()->add(sprintf('transactions.%d.destination_id', $index), trans('validation.reconciliation_either_account'));
@@ -172,7 +173,7 @@ trait TransactionValidation
if (TransactionTypeEnum::RECONCILIATION->value === $transactionType
&& (null !== $source['id'] || null !== $source['name'])
&& (null !== $destination['id'] || null !== $destination['name'])) {
app('log')->debug('Both are not NULL, error!');
Log::debug('Both are not NULL, error!');
$validator->errors()->add(sprintf('transactions.%d.source_id', $index), trans('validation.reconciliation_either_account'));
$validator->errors()->add(sprintf('transactions.%d.source_name', $index), trans('validation.reconciliation_either_account'));
$validator->errors()->add(sprintf('transactions.%d.destination_id', $index), trans('validation.reconciliation_either_account'));
@@ -193,30 +194,30 @@ trait TransactionValidation
string $transactionType,
int $index
): void {
app('log')->debug('Now in sanityCheckForeignCurrency()');
Log::debug('Now in sanityCheckForeignCurrency()');
if (0 !== $validator->errors()->count()) {
app('log')->debug('Already have errors, return');
Log::debug('Already have errors, return');
return;
}
if (null === $accountValidator->source) {
app('log')->debug('No source, return');
Log::debug('No source, return');
return;
}
if (null === $accountValidator->destination) {
app('log')->debug('No destination, return');
Log::debug('No destination, return');
return;
}
$source = $accountValidator->source;
$destination = $accountValidator->destination;
app('log')->debug(sprintf('Source: #%d "%s (%s)"', $source->id, $source->name, $source->accountType->type));
app('log')->debug(sprintf('Destination: #%d "%s" (%s)', $destination->id, $destination->name, $source->accountType->type));
Log::debug(sprintf('Source: #%d "%s (%s)"', $source->id, $source->name, $source->accountType->type));
Log::debug(sprintf('Destination: #%d "%s" (%s)', $destination->id, $destination->name, $source->accountType->type));
if (!$this->isLiabilityOrAsset($source) || !$this->isLiabilityOrAsset($destination)) {
app('log')->debug('Any account must be liability or asset account to continue.');
Log::debug('Any account must be liability or asset account to continue.');
return;
}
@@ -228,17 +229,17 @@ trait TransactionValidation
$destinationCurrency = $accountRepository->getAccountCurrency($destination) ?? $defaultCurrency;
// if both accounts have the same currency, continue.
if ($sourceCurrency->code === $destinationCurrency->code) {
app('log')->debug('Both accounts have the same currency, continue.');
Log::debug('Both accounts have the same currency, continue.');
return;
}
app('log')->debug(sprintf('Source account expects %s', $sourceCurrency->code));
app('log')->debug(sprintf('Destination account expects %s', $destinationCurrency->code));
Log::debug(sprintf('Source account expects %s', $sourceCurrency->code));
Log::debug(sprintf('Destination account expects %s', $destinationCurrency->code));
app('log')->debug(sprintf('Amount is %s', $transaction['amount']));
Log::debug(sprintf('Amount is %s', $transaction['amount']));
if (TransactionTypeEnum::DEPOSIT->value === ucfirst($transactionType)) {
app('log')->debug(sprintf('Processing as a "%s"', $transactionType));
Log::debug(sprintf('Processing as a "%s"', $transactionType));
// use case: deposit from liability account to an asset account
// the foreign amount must be in the currency of the source
// the amount must be in the currency of the destination
@@ -253,7 +254,7 @@ trait TransactionValidation
// wrong currency information is present
$foreignCurrencyCode = $transaction['foreign_currency_code'] ?? false;
$foreignCurrencyId = (int) ($transaction['foreign_currency_id'] ?? 0);
app('log')->debug(sprintf('Foreign currency code seems to be #%d "%s"', $foreignCurrencyId, $foreignCurrencyCode), $transaction);
Log::debug(sprintf('Foreign currency code seems to be #%d "%s"', $foreignCurrencyId, $foreignCurrencyCode), $transaction);
if ($foreignCurrencyCode !== $sourceCurrency->code && $foreignCurrencyId !== $sourceCurrency->id) {
$validator->errors()->add(sprintf('transactions.%d.foreign_currency_code', $index), (string) trans('validation.require_foreign_src'));
@@ -261,7 +262,7 @@ trait TransactionValidation
}
}
if (TransactionTypeEnum::TRANSFER->value === ucfirst($transactionType) || TransactionTypeEnum::WITHDRAWAL->value === ucfirst($transactionType)) {
app('log')->debug(sprintf('Processing as a "%s"', $transactionType));
Log::debug(sprintf('Processing as a "%s"', $transactionType));
// use case: withdrawal from asset account to a liability account.
// the foreign amount must be in the currency of the destination
// the amount must be in the currency of the source
@@ -280,10 +281,10 @@ trait TransactionValidation
// wrong currency information is present
$foreignCurrencyCode = $transaction['foreign_currency_code'] ?? false;
$foreignCurrencyId = (int) ($transaction['foreign_currency_id'] ?? 0);
app('log')->debug(sprintf('Foreign currency code seems to be #%d "%s"', $foreignCurrencyId, $foreignCurrencyCode), $transaction);
Log::debug(sprintf('Foreign currency code seems to be #%d "%s"', $foreignCurrencyId, $foreignCurrencyCode), $transaction);
if ($foreignCurrencyCode !== $destinationCurrency->code && $foreignCurrencyId !== $destinationCurrency->id) {
app('log')->debug(sprintf('No match on code, "%s" vs "%s"', $foreignCurrencyCode, $destinationCurrency->code));
app('log')->debug(sprintf('No match on ID, #%d vs #%d', $foreignCurrencyId, $destinationCurrency->id));
Log::debug(sprintf('No match on code, "%s" vs "%s"', $foreignCurrencyCode, $destinationCurrency->code));
Log::debug(sprintf('No match on ID, #%d vs #%d', $foreignCurrencyId, $destinationCurrency->id));
$validator->errors()->add(sprintf('transactions.%d.foreign_amount', $index), (string) trans('validation.require_foreign_dest'));
}
}
@@ -336,9 +337,9 @@ trait TransactionValidation
*/
public function validateAccountInformationUpdate(Validator $validator, TransactionGroup $transactionGroup): void
{
app('log')->debug('Now in validateAccountInformationUpdate()');
Log::debug('Now in validateAccountInformationUpdate()');
if ($validator->errors()->count() > 0) {
app('log')->debug('Validator already has errors, so return.');
Log::debug('Validator already has errors, so return.');
return;
}
@@ -359,7 +360,7 @@ trait TransactionValidation
protected function validateSingleUpdate(Validator $validator, int $index, array $transaction, TransactionGroup $transactionGroup): void
{
app('log')->debug('Now validating single account update in validateSingleUpdate()');
Log::debug('Now validating single account update in validateSingleUpdate()');
// if no account types are given, just skip the check.
if (
@@ -367,7 +368,7 @@ trait TransactionValidation
&& !array_key_exists('source_name', $transaction)
&& !array_key_exists('destination_id', $transaction)
&& !array_key_exists('destination_name', $transaction)) {
app('log')->debug('No account data has been submitted so will not validating account info.');
Log::debug('No account data has been submitted so will not validating account info.');
return;
}
@@ -376,8 +377,13 @@ trait TransactionValidation
/** @var AccountValidator $accountValidator */
$accountValidator = app(AccountValidator::class);
// 2025-01-29 grab the transaction type from the update array.
$originalType = $this->getTransactionType($transactionGroup, []);
$transactionType = $transaction['type'] ?? $originalType;
Log::debug(sprintf('Determined transaction type to be "%s"', $transactionType));
// get the transaction type using the original transaction group:
$accountValidator->setTransactionType($this->getTransactionType($transactionGroup, []));
$accountValidator->setTransactionType($transactionType);
// validate if the submitted source ID/name/iban/number are valid
if (
@@ -386,7 +392,7 @@ trait TransactionValidation
|| array_key_exists('source_iban', $transaction)
|| array_key_exists('source_number', $transaction)
) {
app('log')->debug('Will try to validate source account information.');
Log::debug('Will try to validate source account information.');
$sourceId = (int) ($transaction['source_id'] ?? 0);
$sourceName = $transaction['source_name'] ?? null;
$sourceIban = $transaction['source_iban'] ?? null;
@@ -397,15 +403,20 @@ trait TransactionValidation
// do something with result:
if (false === $validSource) {
app('log')->warning('Looks like the source account is not valid so complain to the user about it.');
Log::warning('Looks like the source account is not valid so complain to the user about it.');
$validator->errors()->add(sprintf('transactions.%d.source_id', $index), $accountValidator->sourceError);
$validator->errors()->add(sprintf('transactions.%d.source_name', $index), $accountValidator->sourceError);
$validator->errors()->add(sprintf('transactions.%d.source_iban', $index), $accountValidator->sourceError);
$validator->errors()->add(sprintf('transactions.%d.source_number', $index), $accountValidator->sourceError);
// also add an error for the transaction type, if it is different.
if ($originalType !== $transactionType) {
$validator->errors()->add(sprintf('transactions.%d.type', $index), (string) trans('validation.transaction_type_changed'));
}
return;
}
app('log')->debug('Source account info is valid.');
Log::debug('Source account info is valid.');
}
if (
@@ -414,15 +425,15 @@ trait TransactionValidation
|| array_key_exists('destination_iban', $transaction)
|| array_key_exists('destination_number', $transaction)
) {
app('log')->debug('Will try to validate destination account information.');
Log::debug('Will try to validate destination account information.');
// at this point the validator may not have a source account, because it was never submitted for validation.
// must add it ourselves or the validator can never check if the destination is correct.
// the $transaction array must have a journal id or it's just one, this was validated before.
if (null === $accountValidator->source) {
app('log')->debug('Account validator has no source account, must find it.');
Log::debug('Account validator has no source account, must find it.');
$source = $this->getOriginalSource($transaction, $transactionGroup);
if (null !== $source) {
app('log')->debug('Found a source!');
Log::debug('Found a source!');
$accountValidator->source = $source;
}
}
@@ -434,13 +445,17 @@ trait TransactionValidation
$validDestination = $accountValidator->validateDestination($array);
// do something with result:
if (false === $validDestination) {
app('log')->warning('Looks like the destination account is not valid so complain to the user about it.');
Log::warning('Looks like the destination account is not valid so complain to the user about it.');
$validator->errors()->add(sprintf('transactions.%d.destination_id', $index), $accountValidator->destError);
$validator->errors()->add(sprintf('transactions.%d.destination_name', $index), $accountValidator->destError);
// also add an error for the transaction type, if it is different.
if ($originalType !== $transactionType) {
$validator->errors()->add(sprintf('transactions.%d.type', $index), (string) trans('validation.transaction_type_changed'));
}
app('log')->debug('Destination account info is valid.');
}
app('log')->debug('Done with validateSingleUpdate().');
Log::debug('Destination account info is valid.');
}
Log::debug('Done with validateSingleUpdate().');
}
private function getTransactionType(TransactionGroup $group, array $transactions): string
@@ -472,7 +487,7 @@ trait TransactionValidation
*/
public function validateOneRecurrenceTransaction(Validator $validator): void
{
app('log')->debug('Now in validateOneRecurrenceTransaction()');
Log::debug('Now in validateOneRecurrenceTransaction()');
$transactions = $this->getTransactionsArray($validator);
// need at least one transaction
@@ -486,9 +501,9 @@ trait TransactionValidation
*/
public function validateOneTransaction(Validator $validator): void
{
app('log')->debug('Now in validateOneTransaction');
Log::debug('Now in validateOneTransaction');
if ($validator->errors()->count() > 0) {
app('log')->debug('Validator already has errors, so return.');
Log::debug('Validator already has errors, so return.');
return;
}
@@ -496,11 +511,11 @@ trait TransactionValidation
// need at least one transaction
if (0 === count($transactions)) {
$validator->errors()->add('transactions.0.description', (string) trans('validation.at_least_one_transaction'));
app('log')->debug('Added error: at_least_one_transaction.');
Log::debug('Added error: at_least_one_transaction.');
return;
}
app('log')->debug('Added NO errors.');
Log::debug('Added NO errors.');
}
public function validateTransactionArray(Validator $validator): void
@@ -512,7 +527,7 @@ trait TransactionValidation
foreach (array_keys($transactions) as $key) {
if (!is_int($key)) {
$validator->errors()->add('transactions.0.description', (string) trans('validation.at_least_one_transaction'));
app('log')->debug('Added error: at_least_one_transaction.');
Log::debug('Added error: at_least_one_transaction.');
return;
}
@@ -527,7 +542,7 @@ trait TransactionValidation
if ($validator->errors()->count() > 0) {
return;
}
app('log')->debug('Now in validateTransactionTypes()');
Log::debug('Now in validateTransactionTypes()');
$transactions = $this->getTransactionsArray($validator);
$types = [];
@@ -551,7 +566,7 @@ trait TransactionValidation
*/
public function validateTransactionTypesForUpdate(Validator $validator): void
{
app('log')->debug('Now in validateTransactionTypesForUpdate()');
Log::debug('Now in validateTransactionTypesForUpdate()');
$transactions = $this->getTransactionsArray($validator);
$types = [];
foreach ($transactions as $transaction) {
@@ -561,12 +576,12 @@ trait TransactionValidation
}
$unique = array_unique($types);
if (count($unique) > 1) {
app('log')->warning('Add error for mismatch transaction types.');
Log::warning('Add error for mismatch transaction types.');
$validator->errors()->add('transactions.0.type', (string) trans('validation.transaction_types_equal'));
return;
}
app('log')->debug('No errors in validateTransactionTypesForUpdate()');
Log::debug('No errors in validateTransactionTypesForUpdate()');
}
private function getOriginalType(int $journalId): string
@@ -589,7 +604,7 @@ trait TransactionValidation
if ($validator->errors()->count() > 0) {
return;
}
app('log')->debug('Now in validateEqualAccounts()');
Log::debug('Now in validateEqualAccounts()');
$transactions = $this->getTransactionsArray($validator);
// needs to be split
@@ -635,16 +650,16 @@ trait TransactionValidation
private function validateEqualAccountsForUpdate(Validator $validator, TransactionGroup $transactionGroup): void
{
if ($validator->errors()->count() > 0) {
app('log')->debug('Validator already has errors, so return.');
Log::debug('Validator already has errors, so return.');
return;
}
app('log')->debug('Now in validateEqualAccountsForUpdate()');
Log::debug('Now in validateEqualAccountsForUpdate()');
$transactions = $this->getTransactionsArray($validator);
if (2 !== count($transactions)) {
app('log')->debug('Less than 2 transactions, do nothing.');
Log::debug('Less than 2 transactions, do nothing.');
return;
}
@@ -668,11 +683,11 @@ trait TransactionValidation
$validator->errors()->add('transactions.0.source_id', (string) trans('validation.all_accounts_equal'));
$validator->errors()->add('transactions.0.destination_id', (string) trans('validation.all_accounts_equal'));
}
app('log')->warning('Add error about equal accounts.');
Log::warning('Add error about equal accounts.');
return;
}
app('log')->debug('No errors found in validateEqualAccountsForUpdate');
Log::debug('No errors found in validateEqualAccountsForUpdate');
}
private function collectComparisonData(array $transactions): array

View File

@@ -3,9 +3,96 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 6.2.0 - 2025-01-26 (or later)
## 6.2.5 - 2025-02-08
*This release comes with many changes, small and large. I expect you will run into issue, and I appreciate your feedback and your patience as I fix them. I've tested many things, but I'm 100% sure I've missed things. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems.
### Fixed
- [Issue 9736](https://github.com/firefly-iii/firefly-iii/issues/9736) (Wrong `finalAccountBalance` result) reported by @gthbusrr
- [Issue 9747](https://github.com/firefly-iii/firefly-iii/issues/9747) (Data entry issues with exchange rates) reported by @Azmodeszer
- [Issue 9769](https://github.com/firefly-iii/firefly-iii/issues/9769) ("Your accounts" graph shows changes at wrong dates - not fixed by v6.2.4) reported by @SteffoSpieler
- [Discussion 9780](https://github.com/orgs/firefly-iii/discussions/9780) (Rules or webhook precedence?) started by @joeshmoe57
- [Issue 9781](https://github.com/firefly-iii/firefly-iii/issues/9781) (Search key `has_any_external_url:false` returns all transactions) reported by @joeshmoe57
- [Issue 9783](https://github.com/firefly-iii/firefly-iii/issues/9783) (Subscriptions: Make "Not expected this period" and "expected x days from now" different colors) reported by @SteffoSpieler
- [Issue 9784](https://github.com/firefly-iii/firefly-iii/issues/9784) (Transfers with external currency not considered for account balance?) reported by @pvieira84
- [Issue 9786](https://github.com/firefly-iii/firefly-iii/issues/9786) (The error 500 information page has non-clickable links to github and the debug page) reported by @tjmv
- [Issue 9787](https://github.com/firefly-iii/firefly-iii/issues/9787) (Twig general template error formatting TransactionCurrency on main page) reported by @tjmv
- [Issue 9789](https://github.com/firefly-iii/firefly-iii/issues/9789) (Can't open expense and revenue accounts view) reported by @puffer-duck
## 6.2.4 - 2025-02-05
> ⚠️ _Most pressing issues are fixed. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems._
### Fixed
- [Issue 9327](https://github.com/firefly-iii/firefly-iii/issues/9327) (Add Link to Search-Page to the help file) reported by @nottheend
- [Issue 9713](https://github.com/firefly-iii/firefly-iii/issues/9713) (Many decimal points in amounts) reported by @memo-567
- [Issue 9736](https://github.com/firefly-iii/firefly-iii/issues/9736) (Wrong `finalAccountBalance` result) reported by @gthbusrr
- [Discussion 9737](https://github.com/orgs/firefly-iii/discussions/9737) (API returns 0 as current balance) started by @eps90
- [Issue 9745](https://github.com/firefly-iii/firefly-iii/issues/9745) (Type mismatch in period overview) reported by @electrofloat
- [Issue 9747](https://github.com/firefly-iii/firefly-iii/issues/9747) (Data entry issues with exchange rates) reported by @Azmodeszer
- [Issue 9751](https://github.com/firefly-iii/firefly-iii/issues/9751) (Net worth changes since 6.2 update) reported by @ahmaddxb
- [Issue 9754](https://github.com/firefly-iii/firefly-iii/issues/9754) (Deleting account - Attachments remain) reported by @memo-567
- [Issue 9762](https://github.com/firefly-iii/firefly-iii/issues/9762) (Piggy bank show: start/target date not displayed) reported by @Simeam
- Various other balance related fixes.
- Hotfix for account charts.
## 6.2.3 - 2025-02-05
> ⚠️ _Most pressing issues are fixed. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems._
### Fixed
- [Issue 9327](https://github.com/firefly-iii/firefly-iii/issues/9327) (Add Link to Search-Page to the help file) reported by @nottheend
- [Issue 9713](https://github.com/firefly-iii/firefly-iii/issues/9713) (Many decimal points in amounts) reported by @memo-567
- [Issue 9736](https://github.com/firefly-iii/firefly-iii/issues/9736) (Wrong `finalAccountBalance` result) reported by @gthbusrr
- [Discussion 9737](https://github.com/orgs/firefly-iii/discussions/9737) (API returns 0 as current balance) started by @eps90
- [Issue 9745](https://github.com/firefly-iii/firefly-iii/issues/9745) (Type mismatch in period overview) reported by @electrofloat
- [Issue 9747](https://github.com/firefly-iii/firefly-iii/issues/9747) (Data entry issues with exchange rates) reported by @Azmodeszer
- [Issue 9751](https://github.com/firefly-iii/firefly-iii/issues/9751) (Net worth changes since 6.2 update) reported by @ahmaddxb
- [Issue 9754](https://github.com/firefly-iii/firefly-iii/issues/9754) (Deleting account - Attachments remain) reported by @memo-567
- [Issue 9762](https://github.com/firefly-iii/firefly-iii/issues/9762) (Piggy bank show: start/target date not displayed) reported by @Simeam
- Various other balance related fixes.
## 6.2.2 - 2025-02-02
> ⚠️ _This release comes with many changes, small and large. I expect you will run into issue, and I appreciate your feedback and your patience as I fix them. I've tested many things, but I'm 100% sure I've missed things. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems._
### Fixed
- [Issue 9713](https://github.com/firefly-iii/firefly-iii/issues/9713) (Many decimal points in amounts) reported by @memo-567
- [Discussion 9727](https://github.com/orgs/firefly-iii/discussions/9727) (Odd behavior from graphs) started by @jbrandwi
- [Issue 9729](https://github.com/firefly-iii/firefly-iii/issues/9729) (Type mismatch in transaction collector) reported by @electrofloat
- [Issue 9730](https://github.com/firefly-iii/firefly-iii/issues/9730) (API: `PiggyBankAccountRead.id` should return string, returns int) reported by @dreautall
- [Issue 9731](https://github.com/firefly-iii/firefly-iii/issues/9731) ($userGroup must not be accessed before initialization) reported by @Azmodeszer
- [Issue 9732](https://github.com/firefly-iii/firefly-iii/issues/9732) (Editing dates of a piggy bank does not save) reported by @Simeam
- [Issue 9736](https://github.com/firefly-iii/firefly-iii/issues/9736) (Wrong `finalAccountBalance` result) reported by @gthbusrr
- [Issue 9738](https://github.com/firefly-iii/firefly-iii/issues/9738) (Missing pagination controls on exchange rate page) reported by @dicksonleong
- [Discussion 9744](https://github.com/orgs/firefly-iii/discussions/9744) (Downloading exchange rates results in 404 error) started by @electrofloat
### Added
- [PR 9743](https://github.com/firefly-iii/firefly-iii/pull/9743) (Feature nordic currencies) reported by @mansehr
## 6.2.1 - 2025-02-01
> ⚠️ _This release comes with many changes, small and large. I expect you will run into issue, and I appreciate your feedback and your patience as I fix them. I've tested many things, but I'm 100% sure I've missed things. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems._
### Fixed
- [Issue 9714](https://github.com/firefly-iii/firefly-iii/issues/9714) (current transaction is aborted, commands ignored until end of transaction block) reported by @captainark
- [Issue 9717](https://github.com/firefly-iii/firefly-iii/issues/9717) (API api/v1/accounts broken) reported by @brot
- [Issue 9719](https://github.com/firefly-iii/firefly-iii/issues/9719) (A couple of TODOs left in resources/views/list/groups.twig) reported by @lostfocus
- [Issue 9720](https://github.com/firefly-iii/firefly-iii/issues/9720) (Piggy Bank with no Target amount: unable to add money) reported by @maxsmooth
- [Issue 9721](https://github.com/firefly-iii/firefly-iii/issues/9721) (Documentation on exchange-rates page leads to non-existent page) reported by @electrofloat
- [Issue 9722](https://github.com/firefly-iii/firefly-iii/issues/9722) (Error 500 on tags page after enabling native currency) reported by @lostfocus
- [Issue 9723](https://github.com/firefly-iii/firefly-iii/issues/9723) (Convert to native routine is not called when convert to native is activated) reported by @JC5
- [Issue 9726](https://github.com/firefly-iii/firefly-iii/issues/9726) (Postgres cannot deal with "virtual_balance" column) reported by @dicksonleong
## 6.2.0 - 2025-01-31
> ⚠️ _This release comes with many changes, small and large. I expect you will run into issue, and I appreciate your feedback and your patience as I fix them. I've tested many things, but I'm 100% sure I've missed things. Please open [an issue here](https://github.com/firefly-iii/firefly-iii/issues/new?template=bug.yml) if you run into problems._
### Added
@@ -45,12 +132,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- [Issue 9532](https://github.com/firefly-iii/firefly-iii/issues/9532) (ReportSum Integrity Check fails due to empty foreign_amount) reported by @SircasticFox
- [Issue 7288](https://github.com/firefly-iii/firefly-iii/issues/7288) (currentMonthStart/currentMonthEnd not working for no-budget view) reported by @bradsk88
- [Issue 9704](https://github.com/firefly-iii/firefly-iii/issues/9704) (Piggy banks widget displays only main currency for different currencies) reported by @vayakovlev
### API
- API changes related to new features are [documented](https://api-docs.firefly-iii.org/).
- New endpoint for multiple financial administrations ("user groups").
- The change from "default currency" (user) to "native currency" (financial administration) is slowly being reflected in the API. Please report issues.
- You can change the "transaction type" of an existing transaction if you submit a new `type` and the correct source and destination account names or IDs.
## 6.1.25 - 2024-12-19

362
composer.lock generated
View File

@@ -1571,16 +1571,16 @@
},
{
"name": "guzzlehttp/uri-template",
"version": "v1.0.3",
"version": "v1.0.4",
"source": {
"type": "git",
"url": "https://github.com/guzzle/uri-template.git",
"reference": "ecea8feef63bd4fef1f037ecb288386999ecc11c"
"reference": "30e286560c137526eccd4ce21b2de477ab0676d2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/uri-template/zipball/ecea8feef63bd4fef1f037ecb288386999ecc11c",
"reference": "ecea8feef63bd4fef1f037ecb288386999ecc11c",
"url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2",
"reference": "30e286560c137526eccd4ce21b2de477ab0676d2",
"shasum": ""
},
"require": {
@@ -1637,7 +1637,7 @@
],
"support": {
"issues": "https://github.com/guzzle/uri-template/issues",
"source": "https://github.com/guzzle/uri-template/tree/v1.0.3"
"source": "https://github.com/guzzle/uri-template/tree/v1.0.4"
},
"funding": [
{
@@ -1653,7 +1653,7 @@
"type": "tidelift"
}
],
"time": "2023-12-03T19:50:20+00:00"
"time": "2025-02-03T10:55:03+00:00"
},
{
"name": "jc5/google2fa-laravel",
@@ -1874,16 +1874,16 @@
},
{
"name": "laravel/framework",
"version": "v11.40.0",
"version": "v11.41.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "599a28196d284fee158cc10086fd56ac625ad7a3"
"reference": "3ef433d5865f30a19b6b1be247586068399b59cc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/599a28196d284fee158cc10086fd56ac625ad7a3",
"reference": "599a28196d284fee158cc10086fd56ac625ad7a3",
"url": "https://api.github.com/repos/laravel/framework/zipball/3ef433d5865f30a19b6b1be247586068399b59cc",
"reference": "3ef433d5865f30a19b6b1be247586068399b59cc",
"shasum": ""
},
"require": {
@@ -2085,34 +2085,34 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-01-24T16:17:42+00:00"
"time": "2025-01-30T13:25:22+00:00"
},
{
"name": "laravel/passport",
"version": "v12.4.0",
"version": "v12.4.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/passport.git",
"reference": "b06a413cb18d07123ced88ba8caa432d40e3bb8c"
"reference": "e9959e07f751ae4a8ad102d5cb51cbe211181ec3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/passport/zipball/b06a413cb18d07123ced88ba8caa432d40e3bb8c",
"reference": "b06a413cb18d07123ced88ba8caa432d40e3bb8c",
"url": "https://api.github.com/repos/laravel/passport/zipball/e9959e07f751ae4a8ad102d5cb51cbe211181ec3",
"reference": "e9959e07f751ae4a8ad102d5cb51cbe211181ec3",
"shasum": ""
},
"require": {
"ext-json": "*",
"firebase/php-jwt": "^6.4",
"illuminate/auth": "^9.21|^10.0|^11.0",
"illuminate/console": "^9.21|^10.0|^11.0",
"illuminate/container": "^9.21|^10.0|^11.0",
"illuminate/contracts": "^9.21|^10.0|^11.0",
"illuminate/cookie": "^9.21|^10.0|^11.0",
"illuminate/database": "^9.21|^10.0|^11.0",
"illuminate/encryption": "^9.21|^10.0|^11.0",
"illuminate/http": "^9.21|^10.0|^11.0",
"illuminate/support": "^9.21|^10.0|^11.0",
"illuminate/auth": "^9.21|^10.0|^11.0|^12.0",
"illuminate/console": "^9.21|^10.0|^11.0|^12.0",
"illuminate/container": "^9.21|^10.0|^11.0|^12.0",
"illuminate/contracts": "^9.21|^10.0|^11.0|^12.0",
"illuminate/cookie": "^9.21|^10.0|^11.0|^12.0",
"illuminate/database": "^9.21|^10.0|^11.0|^12.0",
"illuminate/encryption": "^9.21|^10.0|^11.0|^12.0",
"illuminate/http": "^9.21|^10.0|^11.0|^12.0",
"illuminate/support": "^9.21|^10.0|^11.0|^12.0",
"lcobucci/jwt": "^4.3|^5.0",
"league/oauth2-server": "^8.5.3",
"nyholm/psr7": "^1.5",
@@ -2123,9 +2123,9 @@
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^7.35|^8.14|^9.0",
"orchestra/testbench": "^7.35|^8.14|^9.0|^10.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.3|^10.5"
"phpunit/phpunit": "^9.3|^10.5|^11.5"
},
"type": "library",
"extra": {
@@ -2161,20 +2161,20 @@
"issues": "https://github.com/laravel/passport/issues",
"source": "https://github.com/laravel/passport"
},
"time": "2025-01-13T17:40:20+00:00"
"time": "2025-01-28T15:14:23+00:00"
},
{
"name": "laravel/prompts",
"version": "v0.3.3",
"version": "v0.3.4",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
"reference": "749395fcd5f8f7530fe1f00dfa84eb22c83d94ea"
"reference": "abeaa2ba4294247d5409490d1ca1bc6248087011"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/749395fcd5f8f7530fe1f00dfa84eb22c83d94ea",
"reference": "749395fcd5f8f7530fe1f00dfa84eb22c83d94ea",
"url": "https://api.github.com/repos/laravel/prompts/zipball/abeaa2ba4294247d5409490d1ca1bc6248087011",
"reference": "abeaa2ba4294247d5409490d1ca1bc6248087011",
"shasum": ""
},
"require": {
@@ -2188,7 +2188,7 @@
"laravel/framework": ">=10.17.0 <10.25.0"
},
"require-dev": {
"illuminate/collections": "^10.0|^11.0",
"illuminate/collections": "^10.0|^11.0|^12.0",
"mockery/mockery": "^1.5",
"pestphp/pest": "^2.3|^3.4",
"phpstan/phpstan": "^1.11",
@@ -2218,38 +2218,38 @@
"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.3"
"source": "https://github.com/laravel/prompts/tree/v0.3.4"
},
"time": "2024-12-30T15:53:31+00:00"
"time": "2025-01-24T15:41:01+00:00"
},
{
"name": "laravel/sanctum",
"version": "v4.0.7",
"version": "v4.0.8",
"source": {
"type": "git",
"url": "https://github.com/laravel/sanctum.git",
"reference": "698064236a46df016e64a7eb059b1414e0b281df"
"reference": "ec1dd9ddb2ab370f79dfe724a101856e0963f43c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/698064236a46df016e64a7eb059b1414e0b281df",
"reference": "698064236a46df016e64a7eb059b1414e0b281df",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/ec1dd9ddb2ab370f79dfe724a101856e0963f43c",
"reference": "ec1dd9ddb2ab370f79dfe724a101856e0963f43c",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/console": "^11.0",
"illuminate/contracts": "^11.0",
"illuminate/database": "^11.0",
"illuminate/support": "^11.0",
"illuminate/console": "^11.0|^12.0",
"illuminate/contracts": "^11.0|^12.0",
"illuminate/database": "^11.0|^12.0",
"illuminate/support": "^11.0|^12.0",
"php": "^8.2",
"symfony/console": "^7.0"
},
"require-dev": {
"mockery/mockery": "^1.6",
"orchestra/testbench": "^9.0",
"orchestra/testbench": "^9.0|^10.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.5"
"phpunit/phpunit": "^11.3"
},
"type": "library",
"extra": {
@@ -2284,29 +2284,29 @@
"issues": "https://github.com/laravel/sanctum/issues",
"source": "https://github.com/laravel/sanctum"
},
"time": "2024-12-11T16:40:21+00:00"
"time": "2025-01-26T19:34:36+00:00"
},
{
"name": "laravel/serializable-closure",
"version": "v2.0.1",
"version": "v2.0.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
"reference": "613b2d4998f85564d40497e05e89cb6d9bd1cbe8"
"reference": "2e1a362527783bcab6c316aad51bf36c5513ae44"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/613b2d4998f85564d40497e05e89cb6d9bd1cbe8",
"reference": "613b2d4998f85564d40497e05e89cb6d9bd1cbe8",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/2e1a362527783bcab6c316aad51bf36c5513ae44",
"reference": "2e1a362527783bcab6c316aad51bf36c5513ae44",
"shasum": ""
},
"require": {
"php": "^8.1"
},
"require-dev": {
"illuminate/support": "^10.0|^11.0",
"illuminate/support": "^10.0|^11.0|^12.0",
"nesbot/carbon": "^2.67|^3.0",
"pestphp/pest": "^2.36",
"pestphp/pest": "^2.36|^3.0",
"phpstan/phpstan": "^2.0",
"symfony/var-dumper": "^6.2.0|^7.0.0"
},
@@ -2345,34 +2345,34 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
"time": "2024-12-16T15:26:28+00:00"
"time": "2025-01-24T15:42:37+00:00"
},
{
"name": "laravel/slack-notification-channel",
"version": "v3.4.3",
"version": "v3.4.4",
"source": {
"type": "git",
"url": "https://github.com/laravel/slack-notification-channel.git",
"reference": "336859d1108f3cb9fc598ccca7083cc07081aa09"
"reference": "58890389d6b4b8021c8d34d78246d7dff5a57cb6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/slack-notification-channel/zipball/336859d1108f3cb9fc598ccca7083cc07081aa09",
"reference": "336859d1108f3cb9fc598ccca7083cc07081aa09",
"url": "https://api.github.com/repos/laravel/slack-notification-channel/zipball/58890389d6b4b8021c8d34d78246d7dff5a57cb6",
"reference": "58890389d6b4b8021c8d34d78246d7dff5a57cb6",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^7.0",
"illuminate/http": "^9.0|^10.0|^11.0",
"illuminate/notifications": "^9.0|^10.0|^11.0",
"illuminate/support": "^9.0|^10.0|^11.0",
"illuminate/http": "^9.0|^10.0|^11.0|^12.0",
"illuminate/notifications": "^9.0|^10.0|^11.0|^12.0",
"illuminate/support": "^9.0|^10.0|^11.0|^12.0",
"php": "^8.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^7.0|^8.0|^9.0",
"orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.0|^10.4"
"phpunit/phpunit": "^9.0|^10.4|^11.5"
},
"type": "library",
"extra": {
@@ -2408,35 +2408,35 @@
],
"support": {
"issues": "https://github.com/laravel/slack-notification-channel/issues",
"source": "https://github.com/laravel/slack-notification-channel/tree/v3.4.3"
"source": "https://github.com/laravel/slack-notification-channel/tree/v3.4.4"
},
"time": "2025-01-20T16:59:17+00:00"
"time": "2025-01-24T15:40:14+00:00"
},
{
"name": "laravel/ui",
"version": "v4.6.0",
"version": "v4.6.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/ui.git",
"reference": "a34609b15ae0c0512a0cf47a21695a2729cb7f93"
"reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/ui/zipball/a34609b15ae0c0512a0cf47a21695a2729cb7f93",
"reference": "a34609b15ae0c0512a0cf47a21695a2729cb7f93",
"url": "https://api.github.com/repos/laravel/ui/zipball/7d6ffa38d79f19c9b3e70a751a9af845e8f41d88",
"reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88",
"shasum": ""
},
"require": {
"illuminate/console": "^9.21|^10.0|^11.0",
"illuminate/filesystem": "^9.21|^10.0|^11.0",
"illuminate/support": "^9.21|^10.0|^11.0",
"illuminate/validation": "^9.21|^10.0|^11.0",
"illuminate/console": "^9.21|^10.0|^11.0|^12.0",
"illuminate/filesystem": "^9.21|^10.0|^11.0|^12.0",
"illuminate/support": "^9.21|^10.0|^11.0|^12.0",
"illuminate/validation": "^9.21|^10.0|^11.0|^12.0",
"php": "^8.0",
"symfony/console": "^6.0|^7.0"
},
"require-dev": {
"orchestra/testbench": "^7.35|^8.15|^9.0",
"phpunit/phpunit": "^9.3|^10.4|^11.0"
"orchestra/testbench": "^7.35|^8.15|^9.0|^10.0",
"phpunit/phpunit": "^9.3|^10.4|^11.5"
},
"type": "library",
"extra": {
@@ -2471,9 +2471,9 @@
"ui"
],
"support": {
"source": "https://github.com/laravel/ui/tree/v4.6.0"
"source": "https://github.com/laravel/ui/tree/v4.6.1"
},
"time": "2024-11-21T15:06:41+00:00"
"time": "2025-01-28T15:15:29+00:00"
},
{
"name": "lcobucci/clock",
@@ -2541,16 +2541,16 @@
},
{
"name": "lcobucci/jwt",
"version": "5.4.2",
"version": "5.5.0",
"source": {
"type": "git",
"url": "https://github.com/lcobucci/jwt.git",
"reference": "ea1ce71cbf9741e445a5914e2f67cdbb484ff712"
"reference": "a835af59b030d3f2967725697cf88300f579088e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/ea1ce71cbf9741e445a5914e2f67cdbb484ff712",
"reference": "ea1ce71cbf9741e445a5914e2f67cdbb484ff712",
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/a835af59b030d3f2967725697cf88300f579088e",
"reference": "a835af59b030d3f2967725697cf88300f579088e",
"shasum": ""
},
"require": {
@@ -2598,7 +2598,7 @@
],
"support": {
"issues": "https://github.com/lcobucci/jwt/issues",
"source": "https://github.com/lcobucci/jwt/tree/5.4.2"
"source": "https://github.com/lcobucci/jwt/tree/5.5.0"
},
"funding": [
{
@@ -2610,7 +2610,7 @@
"type": "patreon"
}
],
"time": "2024-11-07T12:54:35+00:00"
"time": "2025-01-26T21:29:45+00:00"
},
{
"name": "league/commonmark",
@@ -6196,16 +6196,16 @@
},
{
"name": "spatie/laravel-html",
"version": "3.11.1",
"version": "3.11.2",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-html.git",
"reference": "167e5b8243103072155b562e5cc396c90a3c1055"
"reference": "248508f3ed50e6538707fc54a4b3b23fb53e8045"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-html/zipball/167e5b8243103072155b562e5cc396c90a3c1055",
"reference": "167e5b8243103072155b562e5cc396c90a3c1055",
"url": "https://api.github.com/repos/spatie/laravel-html/zipball/248508f3ed50e6538707fc54a4b3b23fb53e8045",
"reference": "248508f3ed50e6538707fc54a4b3b23fb53e8045",
"shasum": ""
},
"require": {
@@ -6262,7 +6262,7 @@
"spatie"
],
"support": {
"source": "https://github.com/spatie/laravel-html/tree/3.11.1"
"source": "https://github.com/spatie/laravel-html/tree/3.11.2"
},
"funding": [
{
@@ -6270,7 +6270,7 @@
"type": "custom"
}
],
"time": "2024-10-18T14:37:21+00:00"
"time": "2025-02-05T08:27:24+00:00"
},
{
"name": "spatie/laravel-ignition",
@@ -6365,27 +6365,27 @@
},
{
"name": "spatie/laravel-package-tools",
"version": "1.18.3",
"version": "1.19.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-package-tools.git",
"reference": "ba67eee37d86ed775dab7dad58a7cbaf9a6cfe78"
"reference": "1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/ba67eee37d86ed775dab7dad58a7cbaf9a6cfe78",
"reference": "ba67eee37d86ed775dab7dad58a7cbaf9a6cfe78",
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa",
"reference": "1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa",
"shasum": ""
},
"require": {
"illuminate/contracts": "^9.28|^10.0|^11.0",
"illuminate/contracts": "^9.28|^10.0|^11.0|^12.0",
"php": "^8.0"
},
"require-dev": {
"mockery/mockery": "^1.5",
"orchestra/testbench": "^7.7|^8.0|^9.0",
"pestphp/pest": "^1.22|^2",
"phpunit/phpunit": "^9.5.24|^10.5",
"orchestra/testbench": "^7.7|^8.0|^9.0|^10.0",
"pestphp/pest": "^1.23|^2.1|^3.1",
"phpunit/phpunit": "^9.5.24|^10.5|^11.5",
"spatie/pest-plugin-test-time": "^1.1|^2.2"
},
"type": "library",
@@ -6413,7 +6413,7 @@
],
"support": {
"issues": "https://github.com/spatie/laravel-package-tools/issues",
"source": "https://github.com/spatie/laravel-package-tools/tree/1.18.3"
"source": "https://github.com/spatie/laravel-package-tools/tree/1.19.0"
},
"funding": [
{
@@ -6421,7 +6421,7 @@
"type": "github"
}
],
"time": "2025-01-22T08:51:18+00:00"
"time": "2025-02-06T14:58:20+00:00"
},
{
"name": "spatie/period",
@@ -6479,16 +6479,16 @@
},
{
"name": "symfony/cache",
"version": "v7.2.1",
"version": "v7.2.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "e7e983596b744c4539f31e79b0350a6cf5878a20"
"reference": "8d773a575e446de220dca03d600b2d8e1c1c10ec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/e7e983596b744c4539f31e79b0350a6cf5878a20",
"reference": "e7e983596b744c4539f31e79b0350a6cf5878a20",
"url": "https://api.github.com/repos/symfony/cache/zipball/8d773a575e446de220dca03d600b2d8e1c1c10ec",
"reference": "8d773a575e446de220dca03d600b2d8e1c1c10ec",
"shasum": ""
},
"require": {
@@ -6557,7 +6557,7 @@
"psr6"
],
"support": {
"source": "https://github.com/symfony/cache/tree/v7.2.1"
"source": "https://github.com/symfony/cache/tree/v7.2.3"
},
"funding": [
{
@@ -6573,7 +6573,7 @@
"type": "tidelift"
}
],
"time": "2024-12-07T08:08:50+00:00"
"time": "2025-01-27T11:08:17+00:00"
},
{
"name": "symfony/cache-contracts",
@@ -6952,16 +6952,16 @@
},
{
"name": "symfony/error-handler",
"version": "v7.2.1",
"version": "v7.2.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
"reference": "6150b89186573046167796fa5f3f76601d5145f8"
"reference": "959a74d044a6db21f4caa6d695648dcb5584cb49"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/6150b89186573046167796fa5f3f76601d5145f8",
"reference": "6150b89186573046167796fa5f3f76601d5145f8",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/959a74d044a6db21f4caa6d695648dcb5584cb49",
"reference": "959a74d044a6db21f4caa6d695648dcb5584cb49",
"shasum": ""
},
"require": {
@@ -7007,7 +7007,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/error-handler/tree/v7.2.1"
"source": "https://github.com/symfony/error-handler/tree/v7.2.3"
},
"funding": [
{
@@ -7023,7 +7023,7 @@
"type": "tidelift"
}
],
"time": "2024-12-07T08:50:44+00:00"
"time": "2025-01-07T09:39:55+00:00"
},
{
"name": "symfony/event-dispatcher",
@@ -7311,16 +7311,16 @@
},
{
"name": "symfony/http-client",
"version": "v7.2.2",
"version": "v7.2.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
"reference": "339ba21476eb184290361542f732ad12c97591ec"
"reference": "7ce6078c79a4a7afff931c413d2959d3bffbfb8d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/339ba21476eb184290361542f732ad12c97591ec",
"reference": "339ba21476eb184290361542f732ad12c97591ec",
"url": "https://api.github.com/repos/symfony/http-client/zipball/7ce6078c79a4a7afff931c413d2959d3bffbfb8d",
"reference": "7ce6078c79a4a7afff931c413d2959d3bffbfb8d",
"shasum": ""
},
"require": {
@@ -7386,7 +7386,7 @@
"http"
],
"support": {
"source": "https://github.com/symfony/http-client/tree/v7.2.2"
"source": "https://github.com/symfony/http-client/tree/v7.2.3"
},
"funding": [
{
@@ -7402,7 +7402,7 @@
"type": "tidelift"
}
],
"time": "2024-12-30T18:35:15+00:00"
"time": "2025-01-28T15:51:35+00:00"
},
{
"name": "symfony/http-client-contracts",
@@ -7484,16 +7484,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v7.2.2",
"version": "v7.2.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "62d1a43796ca3fea3f83a8470dfe63a4af3bc588"
"reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/62d1a43796ca3fea3f83a8470dfe63a4af3bc588",
"reference": "62d1a43796ca3fea3f83a8470dfe63a4af3bc588",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/ee1b504b8926198be89d05e5b6fc4c3810c090f0",
"reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0",
"shasum": ""
},
"require": {
@@ -7542,7 +7542,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v7.2.2"
"source": "https://github.com/symfony/http-foundation/tree/v7.2.3"
},
"funding": [
{
@@ -7558,20 +7558,20 @@
"type": "tidelift"
}
],
"time": "2024-12-30T19:00:17+00:00"
"time": "2025-01-17T10:56:55+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v7.2.2",
"version": "v7.2.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "3c432966bd8c7ec7429663105f5a02d7e75b4306"
"reference": "caae9807f8e25a9b43ce8cc6fafab6cf91f0cc9b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/3c432966bd8c7ec7429663105f5a02d7e75b4306",
"reference": "3c432966bd8c7ec7429663105f5a02d7e75b4306",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/caae9807f8e25a9b43ce8cc6fafab6cf91f0cc9b",
"reference": "caae9807f8e25a9b43ce8cc6fafab6cf91f0cc9b",
"shasum": ""
},
"require": {
@@ -7656,7 +7656,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-kernel/tree/v7.2.2"
"source": "https://github.com/symfony/http-kernel/tree/v7.2.3"
},
"funding": [
{
@@ -7672,20 +7672,20 @@
"type": "tidelift"
}
],
"time": "2024-12-31T14:59:40+00:00"
"time": "2025-01-29T07:40:13+00:00"
},
{
"name": "symfony/mailer",
"version": "v7.2.0",
"version": "v7.2.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
"reference": "e4d358702fb66e4c8a2af08e90e7271a62de39cc"
"reference": "f3871b182c44997cf039f3b462af4a48fb85f9d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/e4d358702fb66e4c8a2af08e90e7271a62de39cc",
"reference": "e4d358702fb66e4c8a2af08e90e7271a62de39cc",
"url": "https://api.github.com/repos/symfony/mailer/zipball/f3871b182c44997cf039f3b462af4a48fb85f9d3",
"reference": "f3871b182c44997cf039f3b462af4a48fb85f9d3",
"shasum": ""
},
"require": {
@@ -7736,7 +7736,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/mailer/tree/v7.2.0"
"source": "https://github.com/symfony/mailer/tree/v7.2.3"
},
"funding": [
{
@@ -7752,7 +7752,7 @@
"type": "tidelift"
}
],
"time": "2024-11-25T15:21:05+00:00"
"time": "2025-01-27T11:08:17+00:00"
},
{
"name": "symfony/mailgun-mailer",
@@ -7825,16 +7825,16 @@
},
{
"name": "symfony/mime",
"version": "v7.2.1",
"version": "v7.2.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "7f9617fcf15cb61be30f8b252695ed5e2bfac283"
"reference": "2fc3b4bd67e4747e45195bc4c98bea4628476204"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/7f9617fcf15cb61be30f8b252695ed5e2bfac283",
"reference": "7f9617fcf15cb61be30f8b252695ed5e2bfac283",
"url": "https://api.github.com/repos/symfony/mime/zipball/2fc3b4bd67e4747e45195bc4c98bea4628476204",
"reference": "2fc3b4bd67e4747e45195bc4c98bea4628476204",
"shasum": ""
},
"require": {
@@ -7889,7 +7889,7 @@
"mime-type"
],
"support": {
"source": "https://github.com/symfony/mime/tree/v7.2.1"
"source": "https://github.com/symfony/mime/tree/v7.2.3"
},
"funding": [
{
@@ -7905,7 +7905,7 @@
"type": "tidelift"
}
],
"time": "2024-12-07T08:50:44+00:00"
"time": "2025-01-27T11:08:17+00:00"
},
{
"name": "symfony/options-resolver",
@@ -8832,16 +8832,16 @@
},
{
"name": "symfony/routing",
"version": "v7.2.0",
"version": "v7.2.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
"reference": "e10a2450fa957af6c448b9b93c9010a4e4c0725e"
"reference": "ee9a67edc6baa33e5fae662f94f91fd262930996"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/routing/zipball/e10a2450fa957af6c448b9b93c9010a4e4c0725e",
"reference": "e10a2450fa957af6c448b9b93c9010a4e4c0725e",
"url": "https://api.github.com/repos/symfony/routing/zipball/ee9a67edc6baa33e5fae662f94f91fd262930996",
"reference": "ee9a67edc6baa33e5fae662f94f91fd262930996",
"shasum": ""
},
"require": {
@@ -8893,7 +8893,7 @@
"url"
],
"support": {
"source": "https://github.com/symfony/routing/tree/v7.2.0"
"source": "https://github.com/symfony/routing/tree/v7.2.3"
},
"funding": [
{
@@ -8909,7 +8909,7 @@
"type": "tidelift"
}
],
"time": "2024-11-25T11:08:51+00:00"
"time": "2025-01-17T10:56:55+00:00"
},
{
"name": "symfony/service-contracts",
@@ -9330,16 +9330,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v7.2.0",
"version": "v7.2.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "c6a22929407dec8765d6e2b6ff85b800b245879c"
"reference": "82b478c69745d8878eb60f9a049a4d584996f73a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/c6a22929407dec8765d6e2b6ff85b800b245879c",
"reference": "c6a22929407dec8765d6e2b6ff85b800b245879c",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/82b478c69745d8878eb60f9a049a4d584996f73a",
"reference": "82b478c69745d8878eb60f9a049a4d584996f73a",
"shasum": ""
},
"require": {
@@ -9393,7 +9393,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.2.0"
"source": "https://github.com/symfony/var-dumper/tree/v7.2.3"
},
"funding": [
{
@@ -9409,7 +9409,7 @@
"type": "tidelift"
}
],
"time": "2024-11-08T15:48:14+00:00"
"time": "2025-01-17T11:39:41+00:00"
},
{
"name": "symfony/var-exporter",
@@ -9683,16 +9683,16 @@
},
{
"name": "twig/twig",
"version": "v3.18.0",
"version": "v3.19.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "acffa88cc2b40dbe42eaf3a5025d6c0d4600cc50"
"reference": "d4f8c2b86374f08efc859323dbcd95c590f7124e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/acffa88cc2b40dbe42eaf3a5025d6c0d4600cc50",
"reference": "acffa88cc2b40dbe42eaf3a5025d6c0d4600cc50",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/d4f8c2b86374f08efc859323dbcd95c590f7124e",
"reference": "d4f8c2b86374f08efc859323dbcd95c590f7124e",
"shasum": ""
},
"require": {
@@ -9747,7 +9747,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.18.0"
"source": "https://github.com/twigphp/Twig/tree/v3.19.0"
},
"funding": [
{
@@ -9759,7 +9759,7 @@
"type": "tidelift"
}
],
"time": "2024-12-29T10:51:50+00:00"
"time": "2025-01-29T07:06:14+00:00"
},
{
"name": "verifiedjoseph/ntfy-php-library",
@@ -10398,16 +10398,16 @@
},
{
"name": "composer/class-map-generator",
"version": "1.5.0",
"version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/composer/class-map-generator.git",
"reference": "4b0a223cf5be7c9ee7e0ef1bc7db42b4a97c9915"
"reference": "ffe442c5974c44a9343e37a0abcb1cc37319f5b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/class-map-generator/zipball/4b0a223cf5be7c9ee7e0ef1bc7db42b4a97c9915",
"reference": "4b0a223cf5be7c9ee7e0ef1bc7db42b4a97c9915",
"url": "https://api.github.com/repos/composer/class-map-generator/zipball/ffe442c5974c44a9343e37a0abcb1cc37319f5b9",
"reference": "ffe442c5974c44a9343e37a0abcb1cc37319f5b9",
"shasum": ""
},
"require": {
@@ -10451,7 +10451,7 @@
],
"support": {
"issues": "https://github.com/composer/class-map-generator/issues",
"source": "https://github.com/composer/class-map-generator/tree/1.5.0"
"source": "https://github.com/composer/class-map-generator/tree/1.6.0"
},
"funding": [
{
@@ -10467,7 +10467,7 @@
"type": "tidelift"
}
],
"time": "2024-11-25T16:11:06+00:00"
"time": "2025-02-05T10:05:34+00:00"
},
{
"name": "composer/pcre",
@@ -10664,16 +10664,16 @@
},
{
"name": "larastan/larastan",
"version": "v3.0.2",
"version": "v3.0.4",
"source": {
"type": "git",
"url": "https://github.com/larastan/larastan.git",
"reference": "b2e24e1605cff1d1097ccb6fb8af3bbd1dfe1c6f"
"reference": "b394eba5805727423071fac9b53ea50dd7e920f4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/larastan/larastan/zipball/b2e24e1605cff1d1097ccb6fb8af3bbd1dfe1c6f",
"reference": "b2e24e1605cff1d1097ccb6fb8af3bbd1dfe1c6f",
"url": "https://api.github.com/repos/larastan/larastan/zipball/b394eba5805727423071fac9b53ea50dd7e920f4",
"reference": "b394eba5805727423071fac9b53ea50dd7e920f4",
"shasum": ""
},
"require": {
@@ -10687,7 +10687,7 @@
"illuminate/support": "^11.15.0",
"php": "^8.2",
"phpmyadmin/sql-parser": "^5.9.0",
"phpstan/phpstan": "^2.0.2"
"phpstan/phpstan": "^2.1.3"
},
"require-dev": {
"doctrine/coding-standard": "^12.0",
@@ -10745,7 +10745,7 @@
],
"support": {
"issues": "https://github.com/larastan/larastan/issues",
"source": "https://github.com/larastan/larastan/tree/v3.0.2"
"source": "https://github.com/larastan/larastan/tree/v3.0.4"
},
"funding": [
{
@@ -10753,7 +10753,7 @@
"type": "github"
}
],
"time": "2024-11-26T23:15:21+00:00"
"time": "2025-02-06T21:03:36+00:00"
},
{
"name": "laravel-json-api/testing",
@@ -11344,16 +11344,16 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.2",
"version": "2.1.3",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "7d08f569e582ade182a375c366cbd896eccadd3a"
"reference": "64ae44e48214f3deebdaeebf2694297a10a2bea9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/7d08f569e582ade182a375c366cbd896eccadd3a",
"reference": "7d08f569e582ade182a375c366cbd896eccadd3a",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/64ae44e48214f3deebdaeebf2694297a10a2bea9",
"reference": "64ae44e48214f3deebdaeebf2694297a10a2bea9",
"shasum": ""
},
"require": {
@@ -11398,7 +11398,7 @@
"type": "github"
}
],
"time": "2025-01-21T14:54:06+00:00"
"time": "2025-02-07T15:05:24+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
@@ -11820,16 +11820,16 @@
},
{
"name": "phpunit/phpunit",
"version": "11.5.3",
"version": "11.5.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "30e319e578a7b5da3543073e30002bf82042f701"
"reference": "e1cb706f019e2547039ca2c839898cd5f557ee5d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/30e319e578a7b5da3543073e30002bf82042f701",
"reference": "30e319e578a7b5da3543073e30002bf82042f701",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e1cb706f019e2547039ca2c839898cd5f557ee5d",
"reference": "e1cb706f019e2547039ca2c839898cd5f557ee5d",
"shasum": ""
},
"require": {
@@ -11901,7 +11901,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.3"
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.7"
},
"funding": [
{
@@ -11917,7 +11917,7 @@
"type": "tidelift"
}
],
"time": "2025-01-13T09:36:00+00:00"
"time": "2025-02-06T16:10:05+00:00"
},
{
"name": "sebastian/cli-parser",

View File

@@ -81,7 +81,7 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag.
],
'version' => '6.2.0-beta.1',
'version' => '6.2.5',
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 25,

View File

@@ -110,6 +110,11 @@ return [
'bill' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
'bill_ends' => ['alias' => false, 'needs_context' => true],
'bill_starts' => ['alias' => false, 'needs_context' => true],
'subscription_is' => ['alias' => true, 'alias_for' => 'bill_is', 'needs_context' => true],
'subscription_contains' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
'subscription' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
'subscription_ends' => ['alias' => true, 'alias_for' => 'bill_ends', 'needs_context' => true],
'subscription_starts' => ['alias' => true, 'alias_for' => 'bill_starts', 'needs_context' => true],
'external_id_is' => ['alias' => false, 'needs_context' => true],
'external_id_contains' => ['alias' => false, 'needs_context' => true],
'external_id' => ['alias' => true, 'alias_for' => 'external_id_contains', 'needs_context' => true],

View File

@@ -155,6 +155,8 @@ return [
'is_reconciled',
'split',
'single_split',
'not_enough_currencies',
'not_enough_currencies_enabled',
'transaction_stored_link',
'webhook_stored_link',
'webhook_updated_link',

View File

@@ -25,8 +25,8 @@ declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
return new class () extends Migration {
/**
@@ -37,8 +37,9 @@ return new class () extends Migration {
// make account_id nullable and the relation also nullable.
try {
Schema::table('piggy_banks', static function (Blueprint $table): void {
// 1. drop index
if (self::hasForeign('piggy_banks', 'piggy_banks_account_id_foreign')) {
$table->dropForeign('piggy_banks_account_id_foreign');
}
});
} catch (RuntimeException $e) {
Log::error('Could not drop foreign key "piggy_banks_account_id_foreign". Probably not an issue.');
@@ -49,33 +50,60 @@ return new class () extends Migration {
});
Schema::table('piggy_banks', static function (Blueprint $table): void {
// 3. add currency
if (!Schema::hasColumn('piggy_banks', 'transaction_currency_id')) {
$table->integer('transaction_currency_id', false, true)->after('account_id')->nullable();
}
if (!self::hasForeign('piggy_banks', 'unique_currency')) {
$table->foreign('transaction_currency_id', 'unique_currency')->references('id')->on('transaction_currencies')->onDelete('cascade');
}
});
Schema::table('piggy_banks', static function (Blueprint $table): void {
// 4. rename columns
if (Schema::hasColumn('piggy_banks', 'targetamount') && !Schema::hasColumn('piggy_banks', 'target_amount')) {
$table->renameColumn('targetamount', 'target_amount');
}
if (Schema::hasColumn('piggy_banks', 'startdate') && !Schema::hasColumn('piggy_banks', 'start_date')) {
$table->renameColumn('startdate', 'start_date');
}
if (Schema::hasColumn('piggy_banks', 'targetdate') && !Schema::hasColumn('piggy_banks', 'target_date')) {
$table->renameColumn('targetdate', 'target_date');
}
if (Schema::hasColumn('piggy_banks', 'targetdate') && !Schema::hasColumn('startdate_tz', 'start_date_tz')) {
$table->renameColumn('startdate_tz', 'start_date_tz');
}
if (Schema::hasColumn('piggy_banks', 'targetdate_tz') && !Schema::hasColumn('target_date_tz', 'start_date_tz')) {
$table->renameColumn('targetdate_tz', 'target_date_tz');
}
});
Schema::table('piggy_banks', static function (Blueprint $table): void {
// 5. add new index
if (!self::hasForeign('piggy_banks', 'piggy_banks_account_id_foreign')) {
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('set null');
}
});
// rename some fields in piggy bank reps.
Schema::table('piggy_bank_repetitions', static function (Blueprint $table): void {
// 6. rename columns
if (Schema::hasColumn('piggy_bank_repetitions', 'currentamount') && !Schema::hasColumn('piggy_bank_repetitions', 'current_amount')) {
$table->renameColumn('currentamount', 'current_amount');
}
if (Schema::hasColumn('piggy_bank_repetitions', 'startdate') && !Schema::hasColumn('piggy_bank_repetitions', 'start_date')) {
$table->renameColumn('startdate', 'start_date');
}
if (Schema::hasColumn('piggy_bank_repetitions', 'targetdate') && !Schema::hasColumn('piggy_bank_repetitions', 'target_date')) {
$table->renameColumn('targetdate', 'target_date');
}
if (Schema::hasColumn('piggy_bank_repetitions', 'startdate_tz') && !Schema::hasColumn('piggy_bank_repetitions', 'start_date_tz')) {
$table->renameColumn('startdate_tz', 'start_date_tz');
}
if (Schema::hasColumn('piggy_bank_repetitions', 'targetdate_tz') && !Schema::hasColumn('piggy_bank_repetitions', 'target_date_tz')) {
$table->renameColumn('targetdate_tz', 'target_date_tz');
}
});
// create table account_piggy_bank
if (!Schema::hasTable('account_piggy_bank')) {
Schema::create('account_piggy_bank', static function (Blueprint $table): void {
$table->id();
$table->integer('account_id', false, true);
@@ -85,6 +113,7 @@ return new class () extends Migration {
$table->foreign('piggy_bank_id')->references('id')->on('piggy_banks')->onDelete('cascade');
$table->unique(['account_id', 'piggy_bank_id'], 'unique_piggy_save');
});
}
}
@@ -105,7 +134,9 @@ return new class () extends Migration {
$table->renameColumn('target_date_tz', 'targetdate_tz');
// 3. drop currency again + index
if (self::hasForeign('piggy_banks', 'unique_currency')) {
$table->dropForeign('unique_currency');
}
$table->dropColumn('transaction_currency_id');
// 2. make column non-nullable.
@@ -127,4 +158,17 @@ return new class () extends Migration {
Schema::dropIfExists('account_piggy_bank');
}
protected static function hasForeign(string $table, string $column)
{
$foreignKeysDefinitions = Schema::getForeignKeys($table);
foreach ($foreignKeysDefinitions as $foreignKeyDefinition) {
if ($foreignKeyDefinition['name'] === $column) {
return true;
}
}
return false;
}
};

View File

@@ -41,8 +41,6 @@ return new class () extends Migration {
'piggy_banks' => ['native_target_amount'], // works
'transactions' => ['native_amount', 'native_foreign_amount'], // works
// TODO button to recalculate all native amounts on selected pages?
];
/**
@@ -52,9 +50,11 @@ return new class () extends Migration {
{
foreach ($this->tables as $table => $fields) {
foreach ($fields as $field) {
Schema::table($table, static function (Blueprint $table) use ($field): void {
Schema::table($table, static function (Blueprint $tableObject) use ($table, $field): void {
// add amount column
$table->decimal($field, 32, 12)->nullable();
if (!Schema::hasColumn($table, $field)) {
$tableObject->decimal($field, 32, 12)->nullable();
}
});
}
}

View File

@@ -42,6 +42,9 @@ class TransactionCurrencySeeder extends Seeder
$currencies[] = ['code' => 'PLN', 'name' => 'Polish złoty', 'symbol' => 'zł', 'decimal_places' => 2];
$currencies[] = ['code' => 'TRY', 'name' => 'Turkish lira', 'symbol' => '₺', 'decimal_places' => 2];
$currencies[] = ['code' => 'DKK', 'name' => 'Dansk krone', 'symbol' => 'kr.', 'decimal_places' => 2];
$currencies[] = ['code' => 'ISK', 'name' => 'Íslensk króna', 'symbol' => 'kr.', 'decimal_places' => 2];
$currencies[] = ['code' => 'NOK', 'name' => 'Norsk krone', 'symbol' => 'kr.', 'decimal_places' => 2];
$currencies[] = ['code' => 'SEK', 'name' => 'Svensk krona', 'symbol' => 'kr.', 'decimal_places' => 2];
$currencies[] = ['code' => 'RON', 'name' => 'Romanian leu', 'symbol' => 'lei', 'decimal_places' => 2];
// american currencies

388
package-lock.json generated
View File

@@ -79,9 +79,9 @@
}
},
"node_modules/@babel/compat-data": {
"version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz",
"integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz",
"integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -89,22 +89,23 @@
}
},
"node_modules/@babel/core": {
"version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.7.tgz",
"integrity": "sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.8.tgz",
"integrity": "sha512-l+lkXCHS6tQEc5oUpK28xBOZ6+HwaH7YwoYQbLFiYb4nS2/l1tKnZEtEWkD0GuiYdvArf9qBS0XlQGXzPMsNqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.5",
"@babel/generator": "^7.26.8",
"@babel/helper-compilation-targets": "^7.26.5",
"@babel/helper-module-transforms": "^7.26.0",
"@babel/helpers": "^7.26.7",
"@babel/parser": "^7.26.7",
"@babel/template": "^7.25.9",
"@babel/traverse": "^7.26.7",
"@babel/types": "^7.26.7",
"@babel/parser": "^7.26.8",
"@babel/template": "^7.26.8",
"@babel/traverse": "^7.26.8",
"@babel/types": "^7.26.8",
"@types/gensync": "^1.0.0",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -130,14 +131,14 @@
}
},
"node_modules/@babel/generator": {
"version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz",
"integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.8.tgz",
"integrity": "sha512-ef383X5++iZHWAXX0SXQR6ZyQhw/0KtTkrTz61WXRhFM6dhpHulO/RJz79L8S6ugZHJkOOkUrUdxgdF2YiPFnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.26.5",
"@babel/types": "^7.26.5",
"@babel/parser": "^7.26.8",
"@babel/types": "^7.26.8",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2"
@@ -442,13 +443,13 @@
}
},
"node_modules/@babel/parser": {
"version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz",
"integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.8.tgz",
"integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.26.7"
"@babel/types": "^7.26.8"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -667,15 +668,15 @@
}
},
"node_modules/@babel/plugin-transform-async-generator-functions": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz",
"integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz",
"integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
"@babel/helper-plugin-utils": "^7.26.5",
"@babel/helper-remap-async-to-generator": "^7.25.9",
"@babel/traverse": "^7.25.9"
"@babel/traverse": "^7.26.8"
},
"engines": {
"node": ">=6.9.0"
@@ -1340,14 +1341,14 @@
}
},
"node_modules/@babel/plugin-transform-runtime": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz",
"integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.8.tgz",
"integrity": "sha512-H0jlQxFMI0Q8SyGPsj9pO3ygVQRxPkIGytsL3m1Zqca8KrCPpMlvh+e2dxknqdfS8LFwBw+PpiYPD9qy/FPQpA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.25.9",
"@babel/helper-plugin-utils": "^7.25.9",
"@babel/helper-plugin-utils": "^7.26.5",
"babel-plugin-polyfill-corejs2": "^0.4.10",
"babel-plugin-polyfill-corejs3": "^0.10.6",
"babel-plugin-polyfill-regenerator": "^0.6.1",
@@ -1420,13 +1421,13 @@
}
},
"node_modules/@babel/plugin-transform-template-literals": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz",
"integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz",
"integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9"
"@babel/helper-plugin-utils": "^7.26.5"
},
"engines": {
"node": ">=6.9.0"
@@ -1519,13 +1520,13 @@
}
},
"node_modules/@babel/preset-env": {
"version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.7.tgz",
"integrity": "sha512-Ycg2tnXwixaXOVb29rana8HNPgLVBof8qqtNQ9LE22IoyZboQbGSxI6ZySMdW3K5nAe6gu35IaJefUJflhUFTQ==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.8.tgz",
"integrity": "sha512-um7Sy+2THd697S4zJEfv/U5MHGJzkN2xhtsR3T/SWRbVSic62nbISh51VVfU9JiO/L/Z97QczHTaFVkOU8IzNg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.26.5",
"@babel/compat-data": "^7.26.8",
"@babel/helper-compilation-targets": "^7.26.5",
"@babel/helper-plugin-utils": "^7.26.5",
"@babel/helper-validator-option": "^7.25.9",
@@ -1539,7 +1540,7 @@
"@babel/plugin-syntax-import-attributes": "^7.26.0",
"@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
"@babel/plugin-transform-arrow-functions": "^7.25.9",
"@babel/plugin-transform-async-generator-functions": "^7.25.9",
"@babel/plugin-transform-async-generator-functions": "^7.26.8",
"@babel/plugin-transform-async-to-generator": "^7.25.9",
"@babel/plugin-transform-block-scoped-functions": "^7.26.5",
"@babel/plugin-transform-block-scoping": "^7.25.9",
@@ -1582,7 +1583,7 @@
"@babel/plugin-transform-shorthand-properties": "^7.25.9",
"@babel/plugin-transform-spread": "^7.25.9",
"@babel/plugin-transform-sticky-regex": "^7.25.9",
"@babel/plugin-transform-template-literals": "^7.25.9",
"@babel/plugin-transform-template-literals": "^7.26.8",
"@babel/plugin-transform-typeof-symbol": "^7.26.7",
"@babel/plugin-transform-unicode-escapes": "^7.25.9",
"@babel/plugin-transform-unicode-property-regex": "^7.25.9",
@@ -1590,9 +1591,9 @@
"@babel/plugin-transform-unicode-sets-regex": "^7.25.9",
"@babel/preset-modules": "0.1.6-no-external-plugins",
"babel-plugin-polyfill-corejs2": "^0.4.10",
"babel-plugin-polyfill-corejs3": "^0.10.6",
"babel-plugin-polyfill-corejs3": "^0.11.0",
"babel-plugin-polyfill-regenerator": "^0.6.1",
"core-js-compat": "^3.38.1",
"core-js-compat": "^3.40.0",
"semver": "^6.3.1"
},
"engines": {
@@ -1602,6 +1603,20 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz",
"integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-define-polyfill-provider": "^0.6.3",
"core-js-compat": "^3.40.0"
},
"peerDependencies": {
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
}
},
"node_modules/@babel/preset-env/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -1640,32 +1655,32 @@
}
},
"node_modules/@babel/template": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
"integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz",
"integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.25.9",
"@babel/parser": "^7.25.9",
"@babel/types": "^7.25.9"
"@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.26.8",
"@babel/types": "^7.26.8"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.7.tgz",
"integrity": "sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.8.tgz",
"integrity": "sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.5",
"@babel/parser": "^7.26.7",
"@babel/template": "^7.25.9",
"@babel/types": "^7.26.7",
"@babel/generator": "^7.26.8",
"@babel/parser": "^7.26.8",
"@babel/template": "^7.26.8",
"@babel/types": "^7.26.8",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@@ -1674,9 +1689,9 @@
}
},
"node_modules/@babel/types": {
"version": "7.26.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz",
"integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==",
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.8.tgz",
"integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2591,9 +2606,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.0.tgz",
"integrity": "sha512-G2fUQQANtBPsNwiVFg4zKiPQyjVKZCUdQUol53R8E71J7AsheRMV/Yv/nB8giOcOVqP7//eB5xPqieBYZe9bGg==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.6.tgz",
"integrity": "sha512-+GcCXtOQoWuC7hhX1P00LqjjIiS/iOouHXhMdiDSnq/1DGTox4SpUvO52Xm+div6+106r+TcvOeo/cxvyEyTgg==",
"cpu": [
"arm"
],
@@ -2605,9 +2620,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.0.tgz",
"integrity": "sha512-qhFwQ+ljoymC+j5lXRv8DlaJYY/+8vyvYmVx074zrLsu5ZGWYsJNLjPPVJJjhZQpyAKUGPydOq9hRLLNvh1s3A==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.6.tgz",
"integrity": "sha512-E8+2qCIjciYUnCa1AiVF1BkRgqIGW9KzJeesQqVfyRITGQN+dFuoivO0hnro1DjT74wXLRZ7QF8MIbz+luGaJA==",
"cpu": [
"arm64"
],
@@ -2619,9 +2634,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.0.tgz",
"integrity": "sha512-44n/X3lAlWsEY6vF8CzgCx+LQaoqWGN7TzUfbJDiTIOjJm4+L2Yq+r5a8ytQRGyPqgJDs3Rgyo8eVL7n9iW6AQ==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.6.tgz",
"integrity": "sha512-z9Ib+OzqN3DZEjX7PDQMHEhtF+t6Mi2z/ueChQPLS/qUMKY7Ybn5A2ggFoKRNRh1q1T03YTQfBTQCJZiepESAg==",
"cpu": [
"arm64"
],
@@ -2633,9 +2648,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.0.tgz",
"integrity": "sha512-F9ct0+ZX5Np6+ZDztxiGCIvlCaW87HBdHcozUfsHnj1WCUTBUubAoanhHUfnUHZABlElyRikI0mgcw/qdEm2VQ==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.6.tgz",
"integrity": "sha512-PShKVY4u0FDAR7jskyFIYVyHEPCPnIQY8s5OcXkdU8mz3Y7eXDJPdyM/ZWjkYdR2m0izD9HHWA8sGcXn+Qrsyg==",
"cpu": [
"x64"
],
@@ -2647,9 +2662,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.0.tgz",
"integrity": "sha512-JpsGxLBB2EFXBsTLHfkZDsXSpSmKD3VxXCgBQtlPcuAqB8TlqtLcbeMhxXQkCDv1avgwNjF8uEIbq5p+Cee0PA==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.6.tgz",
"integrity": "sha512-YSwyOqlDAdKqs0iKuqvRHLN4SrD2TiswfoLfvYXseKbL47ht1grQpq46MSiQAx6rQEN8o8URtpXARCpqabqxGQ==",
"cpu": [
"arm64"
],
@@ -2661,9 +2676,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.0.tgz",
"integrity": "sha512-wegiyBT6rawdpvnD9lmbOpx5Sph+yVZKHbhnSP9MqUEDX08G4UzMU+D87jrazGE7lRSyTRs6NEYHtzfkJ3FjjQ==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.6.tgz",
"integrity": "sha512-HEP4CgPAY1RxXwwL5sPFv6BBM3tVeLnshF03HMhJYCNc6kvSqBgTMmsEjb72RkZBAWIqiPUyF1JpEBv5XT9wKQ==",
"cpu": [
"x64"
],
@@ -2675,9 +2690,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.0.tgz",
"integrity": "sha512-3pA7xecItbgOs1A5H58dDvOUEboG5UfpTq3WzAdF54acBbUM+olDJAPkgj1GRJ4ZqE12DZ9/hNS2QZk166v92A==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.6.tgz",
"integrity": "sha512-88fSzjC5xeH9S2Vg3rPgXJULkHcLYMkh8faix8DX4h4TIAL65ekwuQMA/g2CXq8W+NJC43V6fUpYZNjaX3+IIg==",
"cpu": [
"arm"
],
@@ -2689,9 +2704,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.0.tgz",
"integrity": "sha512-Y7XUZEVISGyge51QbYyYAEHwpGgmRrAxQXO3siyYo2kmaj72USSG8LtlQQgAtlGfxYiOwu+2BdbPjzEpcOpRmQ==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.6.tgz",
"integrity": "sha512-wM4ztnutBqYFyvNeR7Av+reWI/enK9tDOTKNF+6Kk2Q96k9bwhDDOlnCUNRPvromlVXo04riSliMBs/Z7RteEg==",
"cpu": [
"arm"
],
@@ -2703,9 +2718,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.0.tgz",
"integrity": "sha512-r7/OTF5MqeBrZo5omPXcTnjvv1GsrdH8a8RerARvDFiDwFpDVDnJyByYM/nX+mvks8XXsgPUxkwe/ltaX2VH7w==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.6.tgz",
"integrity": "sha512-9RyprECbRa9zEjXLtvvshhw4CMrRa3K+0wcp3KME0zmBe1ILmvcVHnypZ/aIDXpRyfhSYSuN4EPdCCj5Du8FIA==",
"cpu": [
"arm64"
],
@@ -2717,9 +2732,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.0.tgz",
"integrity": "sha512-HJbifC9vex9NqnlodV2BHVFNuzKL5OnsV2dvTw6e1dpZKkNjPG6WUq+nhEYV6Hv2Bv++BXkwcyoGlXnPrjAKXw==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.6.tgz",
"integrity": "sha512-qTmklhCTyaJSB05S+iSovfo++EwnIEZxHkzv5dep4qoszUMX5Ca4WM4zAVUMbfdviLgCSQOu5oU8YoGk1s6M9Q==",
"cpu": [
"arm64"
],
@@ -2731,9 +2746,9 @@
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.0.tgz",
"integrity": "sha512-VAEzZTD63YglFlWwRj3taofmkV1V3xhebDXffon7msNz4b14xKsz7utO6F8F4cqt8K/ktTl9rm88yryvDpsfOw==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.6.tgz",
"integrity": "sha512-4Qmkaps9yqmpjY5pvpkfOerYgKNUGzQpFxV6rnS7c/JfYbDSU0y6WpbbredB5cCpLFGJEqYX40WUmxMkwhWCjw==",
"cpu": [
"loong64"
],
@@ -2745,9 +2760,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.0.tgz",
"integrity": "sha512-Sts5DST1jXAc9YH/iik1C9QRsLcCoOScf3dfbY5i4kH9RJpKxiTBXqm7qU5O6zTXBTEZry69bGszr3SMgYmMcQ==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.6.tgz",
"integrity": "sha512-Zsrtux3PuaxuBTX/zHdLaFmcofWGzaWW1scwLU3ZbW/X+hSsFbz9wDIp6XvnT7pzYRl9MezWqEqKy7ssmDEnuQ==",
"cpu": [
"ppc64"
],
@@ -2759,9 +2774,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.0.tgz",
"integrity": "sha512-qhlXeV9AqxIyY9/R1h1hBD6eMvQCO34ZmdYvry/K+/MBs6d1nRFLm6BOiITLVI+nFAAB9kUB6sdJRKyVHXnqZw==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.6.tgz",
"integrity": "sha512-aK+Zp+CRM55iPrlyKiU3/zyhgzWBxLVrw2mwiQSYJRobCURb781+XstzvA8Gkjg/hbdQFuDw44aUOxVQFycrAg==",
"cpu": [
"riscv64"
],
@@ -2773,9 +2788,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.0.tgz",
"integrity": "sha512-8ZGN7ExnV0qjXa155Rsfi6H8M4iBBwNLBM9lcVS+4NcSzOFaNqmt7djlox8pN1lWrRPMRRQ8NeDlozIGx3Omsw==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.6.tgz",
"integrity": "sha512-WoKLVrY9ogmaYPXwTH326+ErlCIgMmsoRSx6bO+l68YgJnlOXhygDYSZe/qbUJCSiCiZAQ+tKm88NcWuUXqOzw==",
"cpu": [
"s390x"
],
@@ -2787,9 +2802,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.0.tgz",
"integrity": "sha512-VDzNHtLLI5s7xd/VubyS10mq6TxvZBp+4NRWoW+Hi3tgV05RtVm4qK99+dClwTN1McA6PHwob6DEJ6PlXbY83A==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.6.tgz",
"integrity": "sha512-Sht4aFvmA4ToHd2vFzwMFaQCiYm2lDFho5rPcvPBT5pCdC+GwHG6CMch4GQfmWTQ1SwRKS0dhDYb54khSrjDWw==",
"cpu": [
"x64"
],
@@ -2801,9 +2816,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.0.tgz",
"integrity": "sha512-qcb9qYDlkxz9DxJo7SDhWxTWV1gFuwznjbTiov289pASxlfGbaOD54mgbs9+z94VwrXtKTu+2RqwlSTbiOqxGg==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.6.tgz",
"integrity": "sha512-zmmpOQh8vXc2QITsnCiODCDGXFC8LMi64+/oPpPx5qz3pqv0s6x46ps4xoycfUiVZps5PFn1gksZzo4RGTKT+A==",
"cpu": [
"x64"
],
@@ -2815,9 +2830,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.0.tgz",
"integrity": "sha512-pFDdotFDMXW2AXVbfdUEfidPAk/OtwE/Hd4eYMTNVVaCQ6Yl8et0meDaKNL63L44Haxv4UExpv9ydSf3aSayDg==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.6.tgz",
"integrity": "sha512-3/q1qUsO/tLqGBaD4uXsB6coVGB3usxw3qyeVb59aArCgedSF66MPdgRStUd7vbZOsko/CgVaY5fo2vkvPLWiA==",
"cpu": [
"arm64"
],
@@ -2829,9 +2844,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.0.tgz",
"integrity": "sha512-/TG7WfrCAjeRNDvI4+0AAMoHxea/USWhAzf9PVDFHbcqrQ7hMMKp4jZIy4VEjk72AAfN5k4TiSMRXRKf/0akSw==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.6.tgz",
"integrity": "sha512-oLHxuyywc6efdKVTxvc0135zPrRdtYVjtVD5GUm55I3ODxhU/PwkQFD97z16Xzxa1Fz0AEe4W/2hzRtd+IfpOA==",
"cpu": [
"ia32"
],
@@ -2843,9 +2858,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.0.tgz",
"integrity": "sha512-5hqO5S3PTEO2E5VjCePxv40gIgyS2KvO7E7/vvC/NbIW4SIRamkMr1hqj+5Y67fbBWv/bQLB6KelBQmXlyCjWA==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.6.tgz",
"integrity": "sha512-0PVwmgzZ8+TZ9oGBmdZoQVXflbvuwzN/HRclujpl4N/q3i+y0lqLw8n1bXA8ru3sApDjlmONaNAuYr38y1Kr9w==",
"cpu": [
"x64"
],
@@ -3007,9 +3022,9 @@
}
},
"node_modules/@types/express-serve-static-core": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.5.tgz",
"integrity": "sha512-GLZPrd9ckqEBFMcVM/qRFAP0Hg3qiVEojgEFsx/N/zKXsBzbGF6z5FBDpZ0+Xhp1xr+qRZYjfGr1cWHB9oFHSA==",
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz",
"integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3032,6 +3047,13 @@
"@types/send": "*"
}
},
"node_modules/@types/gensync": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/gensync/-/gensync-1.0.4.tgz",
"integrity": "sha512-C3YYeRQWp2fmq9OryX+FoDy8nXS6scQ7dPptD8LnFDAUNcKWJjXQKDNJD3HVm+kOUsXhTOkpi69vI4EuAr95bA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
@@ -3051,9 +3073,9 @@
"license": "MIT"
},
"node_modules/@types/http-proxy": {
"version": "1.17.15",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz",
"integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==",
"version": "1.17.16",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz",
"integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3133,9 +3155,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "22.10.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz",
"integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==",
"version": "22.13.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz",
"integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4448,9 +4470,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001695",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz",
"integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==",
"version": "1.0.30001699",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz",
"integrity": "sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w==",
"dev": true,
"funding": [
{
@@ -5663,9 +5685,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.88",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.88.tgz",
"integrity": "sha512-K3C2qf1o+bGzbilTDCTBhTQcMS9KW60yTAaTeeXsfvQuTDDwlokLam/AdqlqcSy9u4UainDgsHV23ksXAOgamw==",
"version": "1.5.96",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.96.tgz",
"integrity": "sha512-8AJUW6dh75Fm/ny8+kZKJzI1pgoE8bKLZlzDU2W1ENd+DXKJrx7I7l9hb8UWR4ojlnb5OlixMt00QWiYJoVw1w==",
"dev": true,
"license": "ISC"
},
@@ -5720,9 +5742,9 @@
}
},
"node_modules/enhanced-resolve": {
"version": "5.18.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz",
"integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==",
"version": "5.18.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
"integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6132,9 +6154,9 @@
}
},
"node_modules/fastq": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
"integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz",
"integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -7159,9 +7181,9 @@
"license": "MIT"
},
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8387,9 +8409,9 @@
}
},
"node_modules/object-inspect": {
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"dev": true,
"license": "MIT",
"engines": {
@@ -9183,9 +9205,9 @@
}
},
"node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz",
"integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -9213,9 +9235,9 @@
}
},
"node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz",
"integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -9987,9 +10009,9 @@
}
},
"node_modules/rollup": {
"version": "4.32.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.0.tgz",
"integrity": "sha512-JmrhfQR31Q4AuNBjjAX4s+a/Pu/Q8Q9iwjWBsjRH1q52SPFE2NqRMK6fUZKKnvKO6id+h7JIRf0oYsph53eATg==",
"version": "4.34.6",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.6.tgz",
"integrity": "sha512-wc2cBWqJgkU3Iz5oztRkQbfVkbxoz5EhnCGOrnJvnLnQ7O0WhQUYyv18qQI79O8L7DdHrrlJNeCHd4VGpnaXKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -10003,25 +10025,25 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.32.0",
"@rollup/rollup-android-arm64": "4.32.0",
"@rollup/rollup-darwin-arm64": "4.32.0",
"@rollup/rollup-darwin-x64": "4.32.0",
"@rollup/rollup-freebsd-arm64": "4.32.0",
"@rollup/rollup-freebsd-x64": "4.32.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.32.0",
"@rollup/rollup-linux-arm-musleabihf": "4.32.0",
"@rollup/rollup-linux-arm64-gnu": "4.32.0",
"@rollup/rollup-linux-arm64-musl": "4.32.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.32.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.32.0",
"@rollup/rollup-linux-riscv64-gnu": "4.32.0",
"@rollup/rollup-linux-s390x-gnu": "4.32.0",
"@rollup/rollup-linux-x64-gnu": "4.32.0",
"@rollup/rollup-linux-x64-musl": "4.32.0",
"@rollup/rollup-win32-arm64-msvc": "4.32.0",
"@rollup/rollup-win32-ia32-msvc": "4.32.0",
"@rollup/rollup-win32-x64-msvc": "4.32.0",
"@rollup/rollup-android-arm-eabi": "4.34.6",
"@rollup/rollup-android-arm64": "4.34.6",
"@rollup/rollup-darwin-arm64": "4.34.6",
"@rollup/rollup-darwin-x64": "4.34.6",
"@rollup/rollup-freebsd-arm64": "4.34.6",
"@rollup/rollup-freebsd-x64": "4.34.6",
"@rollup/rollup-linux-arm-gnueabihf": "4.34.6",
"@rollup/rollup-linux-arm-musleabihf": "4.34.6",
"@rollup/rollup-linux-arm64-gnu": "4.34.6",
"@rollup/rollup-linux-arm64-musl": "4.34.6",
"@rollup/rollup-linux-loongarch64-gnu": "4.34.6",
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.6",
"@rollup/rollup-linux-riscv64-gnu": "4.34.6",
"@rollup/rollup-linux-s390x-gnu": "4.34.6",
"@rollup/rollup-linux-x64-gnu": "4.34.6",
"@rollup/rollup-linux-x64-musl": "4.34.6",
"@rollup/rollup-win32-arm64-msvc": "4.34.6",
"@rollup/rollup-win32-ia32-msvc": "4.34.6",
"@rollup/rollup-win32-x64-msvc": "4.34.6",
"fsevents": "~2.3.2"
}
},
@@ -10077,9 +10099,9 @@
"license": "MIT"
},
"node_modules/sass": {
"version": "1.83.4",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.83.4.tgz",
"integrity": "sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA==",
"version": "1.84.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.84.0.tgz",
"integrity": "sha512-XDAbhEPJRxi7H0SxrnOpiXFQoUJHwkR2u3Zc4el+fK/Tt5Hpzw5kkQ59qVDfvdaUq6gCrEZIbySFBM2T9DNKHg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -10168,9 +10190,9 @@
}
},
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"dev": true,
"license": "ISC",
"bin": {
@@ -10871,9 +10893,9 @@
}
},
"node_modules/terser": {
"version": "5.37.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz",
"integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==",
"version": "5.38.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.38.1.tgz",
"integrity": "sha512-GWANVlPM/ZfYzuPHjq0nxT+EbOEDDN3Jwhwdg1D8TU8oSkktp8w64Uq4auuGLxFSoNTRDncTq2hQHX1Ld9KHkA==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
@@ -11297,15 +11319,15 @@
}
},
"node_modules/vite": {
"version": "6.0.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz",
"integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz",
"integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.24.2",
"postcss": "^8.4.49",
"rollup": "^4.23.0"
"postcss": "^8.5.1",
"rollup": "^4.30.1"
},
"bin": {
"vite": "bin/vite.js"

View File

@@ -45,6 +45,9 @@
<testsuite name="integration">
<directory suffix="Test.php">./tests/integration</directory>
</testsuite>
<testsuite name="feature">
<directory suffix="Test.php">./tests/feature</directory>
</testsuite>
</testsuites>
<source>
<include>

View File

@@ -33,15 +33,33 @@
</div>
</div>
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-12 col-sm-12 col-xs-12">
<div class="col-lg-8 col-lg-offset-2 col-md-12 col-sm-12 col-xs-12" v-if="currencies.length < 2">
<div class="box box-default" v-for="currency in currencies" :key="currency.id">
<div class="box-header with-border">
<h3 class="box-title">{{ $t('firefly.not_enough_currencies') }}</h3>
</div>
<div class="box-body">
<p>
{{ $t('firefly.not_enough_currencies_enabled') }}
</p>
</div>
</div>
</div>
<div class="col-lg-8 col-lg-offset-2 col-md-12 col-sm-12 col-xs-12" v-if="currencies.length > 1">
<div class="box box-default" v-for="currency in currencies" :key="currency.id">
<div class="box-header with-border">
<h3 class="box-title">{{ currency.name }}</h3>
</div>
<div class="box-body">
<ul v-if="currencies.length > 0">
<ul v-if="currencies.length > 1">
<li v-for="sub in currencies" :key="sub.id" v-show="sub.id !== currency.id">
<a :href="'exchange-rates/' + currency.code + '/' + sub.code" :title="$t('firefly.exchange_rates_from_to', {from: currency.name, to: sub.name})">{{ $t('firefly.exchange_rates_from_to', {from: currency.name, to: sub.name}) }}</a>
<a :href="'exchange-rates/' + currency.code + '/' + sub.code"
:title="$t('firefly.exchange_rates_from_to', {from: currency.name, to: sub.name})">{{
$t('firefly.exchange_rates_from_to', {
from: currency.name,
to: sub.name
})
}}</a>
</li>
</ul>
</div>
@@ -57,6 +75,7 @@ export default {
data() {
return {
currencies: [],
page: 1,
};
},
mounted() {
@@ -65,6 +84,7 @@ export default {
methods: {
getCurrencies: function () {
this.currencies = [];
// start with page one, loop for the rest.
this.downloadCurrencies(1);
},
downloadCurrencies: function (page) {
@@ -72,6 +92,7 @@ export default {
for (let i in response.data.data) {
if (response.data.data.hasOwnProperty(i)) {
let current = response.data.data[i];
if (current.attributes.enabled) {
let currency = {
id: current.id,
name: current.attributes.name,
@@ -80,6 +101,7 @@ export default {
this.currencies.push(currency);
}
}
}
if (response.data.meta.pagination.current_page < response.data.meta.pagination.total_pages) {
this.downloadCurrencies(parseInt(response.data.meta.pagination.current_page) + 1);

View File

@@ -42,6 +42,27 @@
<h3 class="box-title">{{ $t('firefly.header_exchange_rates_table') }}</h3>
</div>
<div class="box-body no-padding">
<nav v-if="totalPages > 1">
<ul class="pagination">
<li v-if="1 === this.page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.previous')">
<span class="page-link" aria-hidden="true">&lsaquo;</span>
</li>
<li class="page-item" v-if="1 !== this.page">
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page-1)" rel="prev" :aria-label="$t('pagination.next')">&lsaquo;</a>
</li>
<li v-for="item in this.totalPages" :class="item === page ? 'page-item active' : 'page-item'" aria-current="page">
<span v-if="item === page" class="page-link" v-text="item"></span>
<a v-if="item !== page" class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + item" v-text="item"></a>
</li>
<li v-if="totalPages !== page" class="page-item">
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page+1)" rel="next" :aria-label="$t('pagination.next')">&rsaquo;</a>
</li>
<li v-if="totalPages === page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.next')">
<span class="page-link" aria-hidden="true">&rsaquo;</span>
</li>
</ul>
</nav>
<table class="table table-responsive table-hover">
<thead>
<tr>
@@ -76,10 +97,10 @@
>
</td>
<td>
<input type="number" class="form-control" min="0" v-model="rate.rate">
<input type="number" class="form-control" min="0" step="any" v-model="rate.rate">
</td>
<td>
<input type="number" class="form-control" min="0" v-model="rate.inverse">
<input type="number" class="form-control" min="0" step="any" v-model="rate.inverse">
</td>
<td>
<div class="btn-group">
@@ -98,6 +119,28 @@
</tr>
</tbody>
</table>
<nav v-if="totalPages > 1">
<ul class="pagination">
<li v-if="1 === this.page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.previous')">
<span class="page-link" aria-hidden="true">&lsaquo;</span>
</li>
<li class="page-item" v-if="1 !== this.page">
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page-1)" rel="prev" :aria-label="$t('pagination.next')">&lsaquo;</a>
</li>
<li v-for="item in this.totalPages" :class="item === page ? 'page-item active' : 'page-item'" aria-current="page">
<span v-if="item === page" class="page-link" v-text="item"></span>
<a v-if="item !== page" class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + item" v-text="item"></a>
</li>
<li v-if="totalPages !== page" class="page-item">
<a class="page-link" :href="'/exchange-rates/'+from_code+'/'+to_code+'?page=' + (this.page+1)" rel="next" :aria-label="$t('pagination.next')">&rsaquo;</a>
</li>
<li v-if="totalPages === page" class="page-item disabled" aria-disabled="true" :aria-label="$t('pagination.next')">
<span class="page-link" aria-hidden="true">&rsaquo;</span>
</li>
</ul>
</nav>
</div>
</div>
</div>
@@ -167,16 +210,26 @@ export default {
loading: true,
posting: false,
updating: false,
page: 1,
totalPages: 1,
};
},
mounted() {
// get from and to code from URL
this.newDate = format(new Date, 'yyyy-MM-dd');
let parts = window.location.href.split('/');
this.from_code = parts[parts.length - 2].substring(0, 3);
this.to_code = parts[parts.length - 1].substring(0, 3);
this.from_code = parts[parts.length - 2];
this.to_code = parts[parts.length - 1];
const params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop),
});
this.page = parseInt(params.page ?? 1);
this.downloadCurrencies();
this.downloadRates(1);
this.rates = [];
this.downloadRates(this.page);
},
methods: {
submitRate: function(e) {
@@ -203,16 +256,11 @@ export default {
return ('' === this.rates[index].rate && '' === this.rates[index].inverse) || this.updating;
},
updateRate: function (index) {
// console.log('Update!');
// console.log(this.rates[index].key);
let parts = this.spliceKey(this.rates[index].key);
if (0 === parts.length) {
return;
}
if ('' !== this.rates[index].rate) {
// update rate
// console.log('Rate is ' + this.rates[index].rate);
// console.log('ID is ' + this.rates[index].rate_id);
this.updating = true;
axios.put("./api/v1/exchange-rates/" + this.rates[index].rate_id, {rate: this.rates[index].rate})
.then(() => {
@@ -220,9 +268,6 @@ export default {
});
}
if ('' !== this.rates[index].inverse) {
// update inverse
// console.log('Inverse is ' + this.rates[index].inverse);
// console.log('Inverse ID is ' + this.rates[index].inverse_id);
this.updating = true;
axios.put("./api/v1/exchange-rates/" + this.rates[index].inverse_id, {rate: this.rates[index].inverse})
.then(() => {
@@ -281,7 +326,6 @@ export default {
},
downloadRates: function (page) {
this.tempRates = {};
this.rates = [];
this.loading = true;
axios.get("./api/v1/exchange-rates/rates/" + this.from_code + '/' + this.to_code + '?page=' + page).then((response) => {
for (let i in response.data.data) {
@@ -334,13 +378,10 @@ export default {
}
}
if (parseInt(response.data.meta.pagination.current_page) < parseInt(response.data.meta.pagination.total_pages)) {
this.downloadRates(page + 1);
}
if (parseInt(response.data.meta.pagination.current_page) === parseInt(response.data.meta.pagination.total_pages)) {
this.totalPages = parseInt(response.data.meta.pagination.total_pages);
this.loading = false;
this.rates = Object.values(this.tempRates);
}
// console.log('Do not download more pages. Now on page ' + this.page + ' of ' + this.totalPages);
});
}
},

View File

@@ -36,7 +36,6 @@
class="form-control"
data-role="input"
type="text"
v-on:keypress="handleEnter"
v-on:submit.prevent>
<span class="input-group-btn">
<button
@@ -217,7 +216,7 @@ export default {
}
},
selectedItem: function (e) {
// console.log('In SelectedItem()');
console.log('In SelectedItem()');
if (typeof this.name === 'undefined') {
// console.log('Is undefined');
return;
@@ -239,12 +238,6 @@ export default {
this.name = '';
// some event?
this.$emit('clear:value')
},
handleEnter: function (e) {
// TODO feels sloppy. Can be removed.
if (e.keyCode === 13) {
//e.preventDefault();
}
}
}
}

View File

@@ -922,6 +922,12 @@ export default {
allowed_types: this.transactions[index].source_account.allowed_types,
default_allowed_types: ['Asset account', 'Revenue account', 'Loan', 'Debt', 'Mortgage']
};
if(model.hasOwnProperty('account_currency_id') && null !== model.account_currency_id) {
this.transactions[index].source_account.currency_id = model.account_currency_id;
this.transactions[index].source_account.currency_name = model.account_currency_name;
this.transactions[index].source_account.currency_code = model.account_currency_code;
this.transactions[index].source_account.currency_decimal_places = model.account_currency_decimal_places;
}
// force types on destination selector.
this.transactions[index].destination_account.allowed_types = window.allowedOpposingTypes.source[model.type];
@@ -946,6 +952,12 @@ export default {
allowed_types: this.transactions[index].destination_account.allowed_types,
default_allowed_types: ['Asset account', 'Expense account', 'Loan', 'Debt', 'Mortgage']
};
if(model.hasOwnProperty('account_currency_id') && null !== model.account_currency_id) {
this.transactions[index].destination_account.currency_id = model.account_currency_id;
this.transactions[index].destination_account.currency_name = model.account_currency_name;
this.transactions[index].destination_account.currency_code = model.account_currency_code;
this.transactions[index].destination_account.currency_decimal_places = model.account_currency_decimal_places;
}
// force types on destination selector.
this.transactions[index].source_account.allowed_types = window.allowedOpposingTypes.destination[model.type];

View File

@@ -322,6 +322,12 @@ export default {
currency_decimal_places: model.currency_decimal_places,
allowed_types: this.transactions[index].source_account.allowed_types
};
if(model.hasOwnProperty('account_currency_id') && null !== model.account_currency_id) {
this.transactions[index].source_account.currency_id = model.account_currency_id;
this.transactions[index].source_account.currency_name = model.account_currency_name;
this.transactions[index].source_account.currency_code = model.account_currency_code;
this.transactions[index].source_account.currency_decimal_places = model.account_currency_decimal_places;
}
},
selectedDestinationAccount(index, model) {
if (typeof model === 'string') {
@@ -341,6 +347,12 @@ export default {
currency_decimal_places: model.currency_decimal_places,
allowed_types: this.transactions[index].destination_account.allowed_types
};
if(model.hasOwnProperty('account_currency_id') && null !== model.account_currency_id) {
this.transactions[index].destination_account.currency_id = model.account_currency_id;
this.transactions[index].destination_account.currency_name = model.account_currency_name;
this.transactions[index].destination_account.currency_code = model.account_currency_code;
this.transactions[index].destination_account.currency_decimal_places = model.account_currency_decimal_places;
}
},
clearSource(index) {
// reset source account:
@@ -437,7 +449,7 @@ export default {
//console.log('EditTransaction: processIncomingGroupRow()');
this.setTransactionType(transaction.type);
if(true === transaction.reconciled) {
if (true === transaction.reconciled) {
this.isReconciled = true;
}
@@ -528,7 +540,16 @@ export default {
allowed_types: window.expectedSourceTypes.destination[this.ucFirst(transaction.type)]
}
};
if(null === transaction.foreign_amount) {
// if transaction type is transfer, the destination currency_id etc. MUST match the actual account currency info.
if ('transfer' === transaction.type && null !== transaction.foreign_currency_code) {
result.destination_account.currency_id = transaction.foreign_currency_id;
result.destination_account.currency_name = transaction.foreign_currency_name;
result.destination_account.currency_code = transaction.foreign_currency_code;
result.destination_account.currency_decimal_places = transaction.foreign_currency_decimal_places;
}
if (null === transaction.foreign_amount) {
result.foreign_amount.amount = '';
}
this.transactions.push(result);
@@ -736,7 +757,7 @@ export default {
if (parseInt(row.piggy_bank) > 0) {
currentArray.piggy_bank_id = parseInt(row.piggy_bank);
}
if(this.isReconciled && !this.storeAsNew && true === row.reconciled) {
if (this.isReconciled && !this.storeAsNew && true === row.reconciled) {
// drop content from array:
delete currentArray.source_id;
delete currentArray.source_name;
@@ -748,7 +769,7 @@ export default {
delete currentArray.currency_id;
currentArray.reconciled = true;
}
if(true === row.isReconciled) {
if (true === row.isReconciled) {
this.isReconciled = false;
}
@@ -801,10 +822,16 @@ export default {
this.setDefaultErrors();
// do message if update or new:
if (this.storeAsNew) {
this.success_message = this.$t('firefly.transaction_new_stored_link', {ID: groupId, title: this.escapeHtml(title)});
this.success_message = this.$t('firefly.transaction_new_stored_link', {
ID: groupId,
title: this.escapeHtml(title)
});
this.error_message = '';
} else {
this.success_message = this.$t('firefly.transaction_updated_link', {ID: groupId, title: this.escapeHtml(title)});
this.success_message = this.$t('firefly.transaction_updated_link', {
ID: groupId,
title: this.escapeHtml(title)
});
this.error_message = '';
}
} else {

View File

@@ -42,7 +42,8 @@
</div>
<div class="col-sm-8">
<div class="input-group">
<input v-if="this.enabledCurrencies.length > 0" ref="amount" :placeholder="this.title" :title="this.title" :value="value.amount" autocomplete="off"
<input v-if="this.enabledCurrencies.length > 0" ref="amount" :placeholder="this.title"
:title="this.title" :value="value.amount" autocomplete="off"
class="form-control" name="foreign_amount[]"
step="any" type="number" @input="handleInput">
<span class="input-group-btn">
@@ -67,29 +68,30 @@ export default {
props: ['source', 'destination', 'transactionType', 'value', 'error', 'no_currency', 'title',],
mounted() {
this.liability = false;
// console.log('I am mounted with a ' + this.transactionType + ' transaction type and currency id!');
// console.log(this.value);
this.loadCurrencies();
},
data() {
return {
currencies: [],
enabledCurrencies: [],
exclude: null,
// liability overrules the drop down list if the source or dest is a liability
// liability overrules the drop-down list if the source or dest is a liability
liability: false
}
},
watch: {
source: function () {
//console.log('ForeignAmountSelect watch source');
// console.log('ForeignAmountSelect watch source');
this.changeData();
},
destination: function () {
//console.log('ForeignAmountSelect watch destination');
// console.log('ForeignAmountSelect watch destination');
this.changeData();
},
transactionType: function () {
//console.log('ForeignAmountSelect watch transaction type (is now ' + this.transactionType + ')');
// console.log('ForeignAmountSelect watch transaction type (is now ' + this.transactionType + ')');
this.changeData();
}
},
@@ -105,7 +107,7 @@ export default {
return this.error.length > 0;
},
handleInput(e) {
//console.log('ForeignAmountSelect handleInput');
// console.log('ForeignAmountSelect handleInput');
let obj = {
amount: this.$refs.amount.value,
currency_id: this.$refs.currency_select.value,
@@ -126,7 +128,7 @@ export default {
// console.log(srcType + ' (source) is a liability: ' + sourceIsLiability);
// console.log(destType + ' (dest) is a liability: ' + destIsLiability);
// console.log('tType: ' + tType);
if (tType === 'transfer' || destIsLiability || sourceIsLiability) {
// console.log('Source is liability OR dest is liability, OR transfer. Lock list on currency of destination.');
// console.log('Length of currencies is ' + this.currencies.length);
@@ -135,9 +137,13 @@ export default {
// lock dropdown list on currencyID of destination.
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
// console.log('this.currencies[key].id = ' + this.currencies[key].id);
// console.log('this.destination.currency_id = ' + this.destination.currency_id);
if (parseInt(this.currencies[key].id) === parseInt(this.destination.currency_id)) {
if (
parseInt(this.currencies[key].id) === parseInt(this.destination.currency_id)
) {
// console.log('Enable currency!!');
// console.log(this.destination);
// console.log(this.currencies[key]);
this.enabledCurrencies.push(this.currencies[key]);
}
}
@@ -176,6 +182,7 @@ export default {
}
},
loadCurrencies: function () {
// console.log('loadCurrencies');
// reset list of currencies:
this.currencies = [
{
@@ -199,8 +206,7 @@ export default {
this.getCurrencies(1);
},
getCurrencies: function(page) {
// console.log('loadCurrencies on page ' + page);
getCurrencies: function (page) {
let url = document.getElementsByTagName('base')[0].href + "api/v1/currencies?page=" + page;
axios.get(url, {}).then((res) => {
@@ -213,9 +219,11 @@ export default {
}
}
}
if(res.data.meta.pagination.current_page < res.data.meta.pagination.total_pages) {
if (res.data.meta.pagination.current_page < res.data.meta.pagination.total_pages) {
this.getCurrencies(res.data.meta.pagination.current_page + 1);
return;
}
this.changeData();
});
}
}

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "\u0420\u0430\u0437\u0434\u0435\u043b\u0438",
"single_split": "\u0420\u0430\u0437\u0434\u0435\u043b",
"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}\">\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f #{ID}(\"{title}\")<\/a> \u0431\u0435\u0448\u0435 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u0430.",
"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.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Visit webhook URL",
"reset_webhook_secret": "Reset webhook secret",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Dividir",
"single_split": "Divisi\u00f3",
"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": "La <a href=\"transactions\/show\/{ID}\">Transacci\u00f3 #{ID} (\"{title}\")<\/a> s'ha desat.",
"webhook_stored_link": "S'ha desat <a href=\"webhooks\/show\/{ID}\">el Webook #{ID} (\"{title}\")<\/a> correctament.",
"webhook_updated_link": "S'ha actualitzat el <a href=\"webhooks\/show\/{ID}\">Webook #{ID}<\/a> (\"{title}\").",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Visitar l'URL del webhook",
"reset_webhook_secret": "Reiniciar el secret del webhook",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Rozd\u011blit",
"single_split": "Rozd\u011blit",
"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> byl ulo\u017een.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") byl aktualizov\u00e1n.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Nav\u0161t\u00edvit URL webhooku",
"reset_webhook_secret": "Restartovat tajn\u00fd kl\u00ed\u010d webhooku",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Opdel",
"single_split": "Opdel",
"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.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Bes\u00f8g webhook-URL",
"reset_webhook_secret": "Nulstil webhook-hemmelighed",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Ist abgestimmt",
"split": "Teilen",
"single_split": "Teilen",
"not_enough_currencies": "Nicht gen\u00fcgend W\u00e4hrungen",
"not_enough_currencies_enabled": "Wenn Sie nur eine W\u00e4hrung aktiviert haben, ist es nicht erforderlich, Wechselkurse hinzuzuf\u00fcgen.",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Buchung #{ID} (\"{title}\")<\/a> wurde gespeichert.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> wurde gespeichert.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") wurde aktualisiert.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Webhook-URL besuchen",
"reset_webhook_secret": "Webhook Secret zur\u00fccksetzen",
"header_exchange_rates": "Wechselkurse",
"exchange_rates_intro": "Firefly III unterst\u00fctzt das Herunterladen und Verwenden von Wechselkursen. Lesen Sie mehr dar\u00fcber in <a href=\u201ehttps:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\u201c>der Dokumentation<\/a>.",
"exchange_rates_intro": "Firefly III unterst\u00fctzt das Herunterladen und Verwenden von Wechselkursen. Lesen Sie mehr dar\u00fcber in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\"> der Dokumentation<\/a>.",
"exchange_rates_from_to": "Zwischen {from} und {to} (und umgekehrt)",
"exchange_rates_intro_rates": "Firefly III verwendet die folgenden Wechselkurse. Der Kehrwert wird automatisch berechnet, wenn er nicht angegeben wurde. Wenn f\u00fcr das Datum der Transaktion kein Wechselkurs vorhanden ist, sucht Firefly III in der Vergangenheit nach einem Kurs. Wenn keine vorhanden sind, wird der Kurs \u201e1\u201c verwendet.",
"header_exchange_rates_rates": "Wechselkurse",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "\u0394\u03b9\u03b1\u03c7\u03c9\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2",
"single_split": "\u0394\u03b9\u03b1\u03c7\u03c9\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2",
"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}\">\u0397 \u03c3\u03c5\u03bd\u03b1\u03bb\u03bb\u03b1\u03b3\u03ae #{ID} (\"{title}\")<\/a> \u03ad\u03c7\u03b5\u03b9 \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03c5\u03c4\u03b5\u03af.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> \u03ad\u03c7\u03b5\u03b9 \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03c5\u03c4\u03b5\u03af.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">\u03a4\u03bf Webhook #{ID}<\/a> (\"{title}\") \u03ad\u03c7\u03b5\u03b9 \u03b5\u03bd\u03b7\u03bc\u03b5\u03c1\u03c9\u03b8\u03b5\u03af.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "\u0395\u03c0\u03b9\u03c3\u03ba\u03b5\u03c6\u03b8\u03b5\u03af\u03c4\u03b5 \u03c4\u03bf URL \u03c4\u03bf\u03c5 webhook",
"reset_webhook_secret": "\u0395\u03c0\u03b1\u03bd\u03b1\u03c6\u03bf\u03c1\u03ac \u03bc\u03c5\u03c3\u03c4\u03b9\u03ba\u03bf\u03cd webhook",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Split",
"single_split": "Split",
"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.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Visit webhook URL",
"reset_webhook_secret": "Reset webhook secret",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Split",
"single_split": "Split",
"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.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Visit webhook URL",
"reset_webhook_secret": "Reset webhook secret",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Separar",
"single_split": "Divisi\u00f3n",
"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}\">La transacci\u00f3n #{ID} (\"{title}\")<\/a> ha sido almacenada.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">El webhook #{ID} (\"{title}\")<\/a> ha sido almacenado.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">El webhook #{ID} (\"{title}\")<\/a> ha sido actualizado.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Visita la URL del webhook",
"reset_webhook_secret": "Restablecer secreto del webhook",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Jaa",
"single_split": "Jako",
"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}\">Tapahtuma #{ID} (\"{title}\")<\/a> on tallennettu.",
"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.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Visit webhook URL",
"reset_webhook_secret": "Reset webhook secret",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Est rapproch\u00e9",
"split": "S\u00e9paration",
"single_split": "S\u00e9paration unique",
"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}\">L'op\u00e9ration n\u00b0{ID} (\"{title}\")<\/a> a \u00e9t\u00e9 enregistr\u00e9e.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Le Webhook #{ID} (\"{title}\")<\/a> a \u00e9t\u00e9 enregistr\u00e9.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Le webhook #{ID}<\/a> (\"{title}\") a \u00e9t\u00e9 mis \u00e0 jour.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Visiter l'URL du webhook",
"reset_webhook_secret": "R\u00e9initialiser le secret du webhook",
"header_exchange_rates": "Taux de change",
"exchange_rates_intro": "Firefly III prend en charge le chargement et l'utilisation des taux de change. En savoir plus \u00e0 ce sujet dans <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">la documentation<\/a>.",
"exchange_rates_intro": "Firefly III prend en charge le chargement et l'utilisation des taux de change. En savoir plus \u00e0 ce sujet dans <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">la documentation<\/a>.",
"exchange_rates_from_to": "Entre {from} et {to} (et l'inverse)",
"exchange_rates_intro_rates": "Firefly III utilise les taux de change suivants. L'inverse est calcul\u00e9 automatiquement lorsqu'il n'est pas fourni. Si aucun taux de change n'existe pour la date de la transaction, Firefly III reviendra dans le temps pour en trouver un. Si aucun n'est pr\u00e9sent, le taux \"1\" sera utilis\u00e9.",
"header_exchange_rates_rates": "Taux de change",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Feloszt\u00e1s",
"single_split": "Feloszt\u00e1s",
"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> mentve.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> elt\u00e1rolva.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") friss\u00edtve.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Webhook URL megl\u00e1togat\u00e1sa",
"reset_webhook_secret": "Webhook titok vissza\u00e1ll\u00edt\u00e1sa",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Pisah",
"single_split": "Pisah",
"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.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Visit webhook URL",
"reset_webhook_secret": "Reset webhook secret",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Dividi",
"single_split": "Divisione",
"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": "La <a href=\"transactions\/show\/{ID}\">transazione #{ID} (\"{title}\")<\/a> \u00e8 stata salvata.",
"webhook_stored_link": "Il <a href=\"webhooks\/show\/{ID}\">webhook #{ID} (\"{title}\")<\/a> \u00e8 stato archiviato.",
"webhook_updated_link": "Il <a href=\"webhooks\/show\/{ID}\">webhook #{ID} (\"{title}\")<\/a> \u00e8 stato aggiornato.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Visita URL webhook",
"reset_webhook_secret": "Reimposta il segreto del webhook",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "\u5206\u5272",
"single_split": "\u5206\u5272",
"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}\">\u53d6\u5f15 #{ID}\u300c{title}\u300d<\/a> \u304c\u4fdd\u5b58\u3055\u308c\u307e\u3057\u305f\u3002",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> \u304c\u4fdd\u5b58\u3055\u308c\u307e\u3057\u305f\u3002",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> \u304c\u66f4\u65b0\u3055\u308c\u307e\u3057\u305f\u3002",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Webhook\u306eURL\u3092\u958b\u304f",
"reset_webhook_secret": "Webhook\u306e\u30b7\u30fc\u30af\u30ec\u30c3\u30c8\u3092\u30ea\u30bb\u30c3\u30c8",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "\ub098\ub204\uae30",
"single_split": "\ub098\ub204\uae30",
"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}\">\uac70\ub798 #{ID} (\"{title}\")<\/a>\uac00 \uc800\uc7a5\ub418\uc5c8\uc2b5\ub2c8\ub2e4.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">\uc6f9\ud6c5 #{ID} (\"{title}\")<\/a>\uc774 \uc800\uc7a5\ub418\uc5c8\uc2b5\ub2c8\ub2e4.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">\uc6f9\ud6c5 #{ID}<\/a> (\"{title}\")\uc774 \uc5c5\ub370\uc774\ud2b8 \ub418\uc5c8\uc2b5\ub2c8\ub2e4.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "\uc6f9\ud6c5 URL \ubc29\ubb38",
"reset_webhook_secret": "\uc6f9\ud6c5 \uc2dc\ud06c\ub9bf \uc7ac\uc124\uc815",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Del opp",
"single_split": "Del opp",
"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}\">Transaksjon #{ID} (\"{title}\")<\/a> har blitt lagret.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> er lagret.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") er oppdatert.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Bes\u00f8k URL til webhook",
"reset_webhook_secret": "Tilbakestill Webhook n\u00f8kkel",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is afgestemd",
"split": "Splitsen",
"single_split": "Split",
"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}\">Transactie #{ID} (\"{title}\")<\/a> is opgeslagen.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} ({title})<\/a> is opgeslagen.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} ({title})<\/a> is ge\u00fcpdatet.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Bezoek URL van webhook",
"reset_webhook_secret": "Reset webhook-geheim",
"header_exchange_rates": "Wisselkoersen",
"exchange_rates_intro": "Firefly III kan wisselkoersen downloaden en gebruiken. Lees hier meer over in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">de documentatie<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Tussen {from} en {to} (en andersom)",
"exchange_rates_intro_rates": "Firefly III gebruikt de volgende wisselkoersen. De inverse berekent zichzelf als deze niet is opgegeven. Als er geen wisselkoers bestaat voor de datum van de transactie, gaat Firefly III terug in de tijd om er een te vinden. Als er geen aanwezig is, zal de koers \"1\" gebruikt worden.",
"header_exchange_rates_rates": "Wisselkoersen",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Del opp",
"single_split": "Del opp",
"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}\">Transaksjon #{ID} (\"{title}\")<\/a> har vorte lagra.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> er lagra.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") er oppdatert.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Bes\u00f8k URL til webhook",
"reset_webhook_secret": "Tilbakestill Webhook hemmelegheit",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Podziel",
"single_split": "Podzia\u0142",
"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}\">Transakcja #{ID} (\"{title}\")<\/a> zosta\u0142a zapisana.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> zosta\u0142 zapisany.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") zosta\u0142 zaktualizowany.",
@@ -28,7 +30,7 @@
"apply_rules_checkbox": "Zastosuj regu\u0142y",
"fire_webhooks_checkbox": "Uruchom webhooki",
"no_budget_pointer": "Wygl\u0105da na to, \u017ce nie masz jeszcze bud\u017cet\u00f3w. Powiniene\u015b utworzy\u0107 kilka na stronie <a href=\"budgets\">bud\u017cet\u00f3w<\/a>. Bud\u017cety mog\u0105 Ci pom\u00f3c \u015bledzi\u0107 wydatki.",
"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": "Wygl\u0105da na to, \u017ce nie masz jeszcze subskrypcji. Powiniene\u015b utworzy\u0107 j\u0105 na stronie <a href=\"subscriptions\">subskrypcji<\/a>. Subskrypcje mog\u0105 pom\u00f3c Ci \u015bledzi\u0107 wydatki.",
"source_account": "Konto \u017ar\u00f3d\u0142owe",
"hidden_fields_preferences": "Mo\u017cesz w\u0142\u0105czy\u0107 wi\u0119cej opcji transakcji w swoich <a href=\"preferences\">ustawieniach<\/a>.",
"destination_account": "Konto docelowe",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Odwied\u017a adres URL webhooka",
"reset_webhook_secret": "Resetuj sekret webhooka",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",
@@ -151,7 +153,7 @@
"url": "URL",
"active": "Aktywny",
"interest_date": "Data odsetek",
"administration_currency": "Native currency",
"administration_currency": "Waluta natywna",
"title": "Tytu\u0142",
"date": "Data",
"book_date": "Data ksi\u0119gowania",
@@ -166,12 +168,12 @@
"webhook_delivery": "Dor\u0119czenie",
"from_currency_to_currency": "{from} &rarr; {to}",
"to_currency_from_currency": "{to} &rarr; {from}",
"rate": "Rate"
"rate": "Kurs"
},
"list": {
"title": "Tytu\u0142",
"active": "Jest aktywny?",
"native_currency": "Native currency",
"native_currency": "Waluta natywna",
"trigger": "Wyzwalacz",
"response": "Odpowied\u017a",
"delivery": "Dor\u0119czenie",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Dividir",
"single_split": "Divis\u00e3o",
"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}\">Transa\u00e7\u00e3o #{ID} (\"{title}\")<\/a> foi salva.",
"webhook_stored_link": "<a href=\"transactions\/show\/{ID}\">Webhooh #{ID} (\"{title}\")<\/a> foi salva.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") foi atualizado.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Acesse a URL do webhook",
"reset_webhook_secret": "Redefinir chave do webhook",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "Dividir",
"single_split": "Divis\u00e3o",
"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}\">A transa\u00e7\u00e3o #{ID} (\"{title}\")<\/a> foi guardada.",
"webhook_stored_link": "<a href=\"transactions\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> foi guardado.",
"webhook_updated_link": "<a href=\"transactions\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> foi guardado.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Ir para URL do webhook",
"reset_webhook_secret": "Redefinir segredo webhook",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

View File

@@ -18,6 +18,8 @@
"is_reconciled": "Is reconciled",
"split": "\u00cemparte",
"single_split": "\u00cemparte",
"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}\">Tranzac\u021bia #{ID} (\"{title}\")<\/a> a fost stocat\u0103.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID} (\"{title}\")<\/a> a fost stocat.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") a fost actualizat.",
@@ -138,7 +140,7 @@
"visit_webhook_url": "Vizita\u0163i URL-ul webhook",
"reset_webhook_secret": "Resetare secret webhook",
"header_exchange_rates": "Exchange rates",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/LOL_NOT_FINISHED_YET_TODO\">the documentation<\/a>.",
"exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.",
"exchange_rates_from_to": "Between {from} and {to} (and the other way around)",
"exchange_rates_intro_rates": "Firefly III uses the following exchange rates. The inverse is automatically calculated when it is not provided. If no exchange rate exists for the date of the transaction, Firefly III will go back in time to find one. If none are present, the rate \"1\" will be used.",
"header_exchange_rates_rates": "Exchange rates",

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