Compare commits

..

7 Commits

Author SHA1 Message Date
github-actions
f909f1d9ff Auto commit for release 'develop' on 2025-02-09 2025-02-09 06:14:15 +01:00
James Cole
55018ca046 Remove duplicate copyright statement. 2025-02-09 06:10:46 +01:00
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
21 changed files with 442 additions and 328 deletions

View File

@@ -104,15 +104,20 @@ class AccountController extends Controller
} }
$return[] = [ $return[] = [
'id' => (string) $account->id, 'id' => (string) $account->id,
'name' => $account->name, 'name' => $account->name,
'name_with_balance' => $nameWithBalance, 'name_with_balance' => $nameWithBalance,
'type' => $account->accountType->type, 'type' => $account->accountType->type,
'currency_id' => (string) $useCurrency->id, 'currency_id' => (string) $useCurrency->id,
'currency_name' => $useCurrency->name, 'currency_name' => $useCurrency->name,
'currency_code' => $useCurrency->code, 'currency_code' => $useCurrency->code,
'currency_symbol' => $useCurrency->symbol, 'currency_symbol' => $useCurrency->symbol,
'currency_decimal_places' => $useCurrency->decimal_places, '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

@@ -21,25 +21,6 @@
*/ */
declare(strict_types=1); declare(strict_types=1);
/*
* ConvertDatesToUTC.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
namespace FireflyIII\Console\Commands\Correction; namespace FireflyIII\Console\Commands\Correction;

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Correction; namespace FireflyIII\Console\Commands\Correction;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Models\AutoBudget; use FireflyIII\Models\AutoBudget;
use FireflyIII\Models\AvailableBudget; use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\Bill; use FireflyIII\Models\Bill;
@@ -33,8 +34,14 @@ use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\RecurrenceTransaction; use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\RuleTrigger; 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\Console\Command;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class CorrectsAmounts extends Command class CorrectsAmounts extends Command
{ {
@@ -45,6 +52,8 @@ class CorrectsAmounts extends Command
public function handle(): int 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 // auto budgets must be positive
$this->fixAutoBudgets(); $this->fixAutoBudgets();
// available budgets must be positive // 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) // rule_triggers must be positive or zero (amount_less, amount_more, amount_is)
$this->fixRuleTriggers(); $this->fixRuleTriggers();
return 0; return 0;
} }
@@ -182,4 +192,63 @@ class CorrectsAmounts extends Command
return false; 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

@@ -21,25 +21,6 @@
*/ */
declare(strict_types=1); declare(strict_types=1);
/*
* AddTimezonesToDates.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
namespace FireflyIII\Console\Commands\Correction; namespace FireflyIII\Console\Commands\Correction;

View File

@@ -335,7 +335,7 @@ class AccountController extends Controller
$start = clone session('start', today(config('app.timezone'))->startOfMonth()); $start = clone session('start', today(config('app.timezone'))->startOfMonth());
$end = clone session('end', today(config('app.timezone'))->endOfMonth()); $end = clone session('end', today(config('app.timezone'))->endOfMonth());
$defaultSet = $repository->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value])->pluck('id')->toArray(); $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); $frontpage = app('preferences')->get('frontpageAccounts', $defaultSet);
$frontpageArray = !is_array($frontpage->data) ? [] : $frontpage->data; $frontpageArray = !is_array($frontpage->data) ? [] : $frontpage->data;
Log::debug('Frontpage preference set is ', $frontpageArray); Log::debug('Frontpage preference set is ', $frontpageArray);

View File

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

View File

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

View File

@@ -58,7 +58,7 @@ trait ChartGeneration
if ($cache->has()) { if ($cache->has()) {
return $cache->get(); 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(); $locale = app('steam')->getLocale();
/** @var GeneratorInterface $generator */ /** @var GeneratorInterface $generator */
@@ -88,6 +88,7 @@ trait ChartGeneration
$currentStart = clone $start; $currentStart = clone $start;
$range = Steam::finalAccountBalanceInRange($account, clone $start, clone $end, $this->convertToNative); $range = Steam::finalAccountBalanceInRange($account, clone $start, clone $end, $this->convertToNative);
$previous = array_values($range)[0]; $previous = array_values($range)[0];
Log::debug(sprintf('Start balance for account #%d ("%s) is', $account->id, $account->name), $previous);
while ($currentStart <= $end) { while ($currentStart <= $end) {
$format = $currentStart->format('Y-m-d'); $format = $currentStart->format('Y-m-d');
$label = trim($currentStart->isoFormat((string) trans('config.month_and_day_js', [], $locale))); $label = trim($currentStart->isoFormat((string) trans('config.month_and_day_js', [], $locale)));

View File

@@ -59,8 +59,8 @@ class Steam
public function finalAccountBalanceInRange(Account $account, Carbon $start, Carbon $end, bool $convertToNative): array public function finalAccountBalanceInRange(Account $account, Carbon $start, Carbon $end, bool $convertToNative): array
{ {
// expand period. // expand period.
$start->subDay()->endOfDay(); // go to END of day to get the balance at the END of the day. $start->startOfDay();
$end->addDay()->startOfDay(); // go to START of day to get the balance at the END of the previous day (see ahead). $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'))); 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 // set up cache
@@ -82,6 +82,7 @@ class Steam
$currency = $accountCurrency ?? $nativeCurrency; $currency = $accountCurrency ?? $nativeCurrency;
Log::debug(sprintf('Currency is %s', $currency->code)); Log::debug(sprintf('Currency is %s', $currency->code));
// set start balances: // set start balances:
$startBalance[$currency->code] ??= '0'; $startBalance[$currency->code] ??= '0';
if ($hasCurrency) { if ($hasCurrency) {
@@ -100,10 +101,11 @@ class Steam
Log::debug('Final start balance: ', $startBalance); Log::debug('Final start balance: ', $startBalance);
// sums up the balance changes per day. // 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() $set = $account->transactions()
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->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', '>=', $start->format('Y-m-d H:i:s'))
->where('transaction_journals.date', '<', $end->format('Y-m-d H:i:s')) ->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s'))
->groupBy('transaction_journals.date') ->groupBy('transaction_journals.date')
->groupBy('transactions.transaction_currency_id') ->groupBy('transactions.transaction_currency_id')
->orderBy('transaction_journals.date', 'ASC') ->orderBy('transaction_journals.date', 'ASC')

View File

@@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- [Discussion 9780](https://github.com/orgs/firefly-iii/discussions/9780) (Rules or webhook precedence?) started by @joeshmoe57 - [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 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 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 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 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 - [Issue 9789](https://github.com/firefly-iii/firefly-iii/issues/9789) (Can't open expense and revenue accounts view) reported by @puffer-duck

View File

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

142
package-lock.json generated
View File

@@ -79,9 +79,9 @@
} }
}, },
"node_modules/@babel/compat-data": { "node_modules/@babel/compat-data": {
"version": "7.26.5", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz",
"integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==", "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -89,22 +89,23 @@
} }
}, },
"node_modules/@babel/core": { "node_modules/@babel/core": {
"version": "7.26.7", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.8.tgz",
"integrity": "sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA==", "integrity": "sha512-l+lkXCHS6tQEc5oUpK28xBOZ6+HwaH7YwoYQbLFiYb4nS2/l1tKnZEtEWkD0GuiYdvArf9qBS0XlQGXzPMsNqQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2", "@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-compilation-targets": "^7.26.5",
"@babel/helper-module-transforms": "^7.26.0", "@babel/helper-module-transforms": "^7.26.0",
"@babel/helpers": "^7.26.7", "@babel/helpers": "^7.26.7",
"@babel/parser": "^7.26.7", "@babel/parser": "^7.26.8",
"@babel/template": "^7.25.9", "@babel/template": "^7.26.8",
"@babel/traverse": "^7.26.7", "@babel/traverse": "^7.26.8",
"@babel/types": "^7.26.7", "@babel/types": "^7.26.8",
"@types/gensync": "^1.0.0",
"convert-source-map": "^2.0.0", "convert-source-map": "^2.0.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",
@@ -130,14 +131,14 @@
} }
}, },
"node_modules/@babel/generator": { "node_modules/@babel/generator": {
"version": "7.26.5", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.8.tgz",
"integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", "integrity": "sha512-ef383X5++iZHWAXX0SXQR6ZyQhw/0KtTkrTz61WXRhFM6dhpHulO/RJz79L8S6ugZHJkOOkUrUdxgdF2YiPFnA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.26.5", "@babel/parser": "^7.26.8",
"@babel/types": "^7.26.5", "@babel/types": "^7.26.8",
"@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25", "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2" "jsesc": "^3.0.2"
@@ -442,13 +443,13 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.26.7", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.8.tgz",
"integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==", "integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.26.7" "@babel/types": "^7.26.8"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@@ -667,15 +668,15 @@
} }
}, },
"node_modules/@babel/plugin-transform-async-generator-functions": { "node_modules/@babel/plugin-transform-async-generator-functions": {
"version": "7.25.9", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz",
"integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "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/helper-remap-async-to-generator": "^7.25.9",
"@babel/traverse": "^7.25.9" "@babel/traverse": "^7.26.8"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1340,14 +1341,14 @@
} }
}, },
"node_modules/@babel/plugin-transform-runtime": { "node_modules/@babel/plugin-transform-runtime": {
"version": "7.25.9", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.8.tgz",
"integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", "integrity": "sha512-H0jlQxFMI0Q8SyGPsj9pO3ygVQRxPkIGytsL3m1Zqca8KrCPpMlvh+e2dxknqdfS8LFwBw+PpiYPD9qy/FPQpA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-module-imports": "^7.25.9", "@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-corejs2": "^0.4.10",
"babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-corejs3": "^0.10.6",
"babel-plugin-polyfill-regenerator": "^0.6.1", "babel-plugin-polyfill-regenerator": "^0.6.1",
@@ -1420,13 +1421,13 @@
} }
}, },
"node_modules/@babel/plugin-transform-template-literals": { "node_modules/@babel/plugin-transform-template-literals": {
"version": "7.25.9", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz",
"integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.25.9" "@babel/helper-plugin-utils": "^7.26.5"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1519,13 +1520,13 @@
} }
}, },
"node_modules/@babel/preset-env": { "node_modules/@babel/preset-env": {
"version": "7.26.7", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.8.tgz",
"integrity": "sha512-Ycg2tnXwixaXOVb29rana8HNPgLVBof8qqtNQ9LE22IoyZboQbGSxI6ZySMdW3K5nAe6gu35IaJefUJflhUFTQ==", "integrity": "sha512-um7Sy+2THd697S4zJEfv/U5MHGJzkN2xhtsR3T/SWRbVSic62nbISh51VVfU9JiO/L/Z97QczHTaFVkOU8IzNg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.26.5", "@babel/compat-data": "^7.26.8",
"@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-compilation-targets": "^7.26.5",
"@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-plugin-utils": "^7.26.5",
"@babel/helper-validator-option": "^7.25.9", "@babel/helper-validator-option": "^7.25.9",
@@ -1539,7 +1540,7 @@
"@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-import-attributes": "^7.26.0",
"@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
"@babel/plugin-transform-arrow-functions": "^7.25.9", "@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-async-to-generator": "^7.25.9",
"@babel/plugin-transform-block-scoped-functions": "^7.26.5", "@babel/plugin-transform-block-scoped-functions": "^7.26.5",
"@babel/plugin-transform-block-scoping": "^7.25.9", "@babel/plugin-transform-block-scoping": "^7.25.9",
@@ -1582,7 +1583,7 @@
"@babel/plugin-transform-shorthand-properties": "^7.25.9", "@babel/plugin-transform-shorthand-properties": "^7.25.9",
"@babel/plugin-transform-spread": "^7.25.9", "@babel/plugin-transform-spread": "^7.25.9",
"@babel/plugin-transform-sticky-regex": "^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-typeof-symbol": "^7.26.7",
"@babel/plugin-transform-unicode-escapes": "^7.25.9", "@babel/plugin-transform-unicode-escapes": "^7.25.9",
"@babel/plugin-transform-unicode-property-regex": "^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/plugin-transform-unicode-sets-regex": "^7.25.9",
"@babel/preset-modules": "0.1.6-no-external-plugins", "@babel/preset-modules": "0.1.6-no-external-plugins",
"babel-plugin-polyfill-corejs2": "^0.4.10", "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", "babel-plugin-polyfill-regenerator": "^0.6.1",
"core-js-compat": "^3.38.1", "core-js-compat": "^3.40.0",
"semver": "^6.3.1" "semver": "^6.3.1"
}, },
"engines": { "engines": {
@@ -1602,6 +1603,20 @@
"@babel/core": "^7.0.0-0" "@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": { "node_modules/@babel/preset-env/node_modules/semver": {
"version": "6.3.1", "version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -1640,32 +1655,32 @@
} }
}, },
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.25.9", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz",
"integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.25.9", "@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.25.9", "@babel/parser": "^7.26.8",
"@babel/types": "^7.25.9" "@babel/types": "^7.26.8"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.26.7", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.8.tgz",
"integrity": "sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==", "integrity": "sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.26.2", "@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.5", "@babel/generator": "^7.26.8",
"@babel/parser": "^7.26.7", "@babel/parser": "^7.26.8",
"@babel/template": "^7.25.9", "@babel/template": "^7.26.8",
"@babel/types": "^7.26.7", "@babel/types": "^7.26.8",
"debug": "^4.3.1", "debug": "^4.3.1",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
@@ -1674,9 +1689,9 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.26.7", "version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.8.tgz",
"integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==", "integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3032,6 +3047,13 @@
"@types/send": "*" "@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": { "node_modules/@types/glob": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
@@ -4448,9 +4470,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001698", "version": "1.0.30001699",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001698.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz",
"integrity": "sha512-xJ3km2oiG/MbNU8G6zIq6XRZ6HtAOVXsbOrP/blGazi52kc5Yy7b6sDA5O+FbROzRrV7BSTllLHuNvmawYUJjw==", "integrity": "sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {

View File

@@ -381,7 +381,7 @@ export default {
this.totalPages = parseInt(response.data.meta.pagination.total_pages); this.totalPages = parseInt(response.data.meta.pagination.total_pages);
this.loading = false; this.loading = false;
this.rates = Object.values(this.tempRates); this.rates = Object.values(this.tempRates);
console.log('Do not download more pages. Now on page ' + this.page + ' of ' + this.totalPages); // console.log('Do not download more pages. Now on page ' + this.page + ' of ' + this.totalPages);
}); });
} }
}, },

View File

@@ -36,7 +36,6 @@
class="form-control" class="form-control"
data-role="input" data-role="input"
type="text" type="text"
v-on:keypress="handleEnter"
v-on:submit.prevent> v-on:submit.prevent>
<span class="input-group-btn"> <span class="input-group-btn">
<button <button
@@ -217,7 +216,7 @@ export default {
} }
}, },
selectedItem: function (e) { selectedItem: function (e) {
// console.log('In SelectedItem()'); console.log('In SelectedItem()');
if (typeof this.name === 'undefined') { if (typeof this.name === 'undefined') {
// console.log('Is undefined'); // console.log('Is undefined');
return; return;
@@ -239,12 +238,6 @@ export default {
this.name = ''; this.name = '';
// some event? // some event?
this.$emit('clear:value') 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, allowed_types: this.transactions[index].source_account.allowed_types,
default_allowed_types: ['Asset account', 'Revenue account', 'Loan', 'Debt', 'Mortgage'] 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. // force types on destination selector.
this.transactions[index].destination_account.allowed_types = window.allowedOpposingTypes.source[model.type]; 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, allowed_types: this.transactions[index].destination_account.allowed_types,
default_allowed_types: ['Asset account', 'Expense account', 'Loan', 'Debt', 'Mortgage'] 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. // force types on destination selector.
this.transactions[index].source_account.allowed_types = window.allowedOpposingTypes.destination[model.type]; this.transactions[index].source_account.allowed_types = window.allowedOpposingTypes.destination[model.type];

View File

@@ -155,8 +155,8 @@
v-bind:title="$t('form.foreign_amount')" v-bind:title="$t('form.foreign_amount')"
></foreign-amount> ></foreign-amount>
<reconciled v-show="isReconciled" <reconciled v-show="isReconciled"
v-model="transaction.reconciled" v-model="transaction.reconciled"
:error="transaction.errors.reconciled" :error="transaction.errors.reconciled"
></reconciled> ></reconciled>
</div> </div>
<div class="col-lg-4"> <div class="col-lg-4">
@@ -322,6 +322,12 @@ export default {
currency_decimal_places: model.currency_decimal_places, currency_decimal_places: model.currency_decimal_places,
allowed_types: this.transactions[index].source_account.allowed_types 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) { selectedDestinationAccount(index, model) {
if (typeof model === 'string') { if (typeof model === 'string') {
@@ -341,6 +347,12 @@ export default {
currency_decimal_places: model.currency_decimal_places, currency_decimal_places: model.currency_decimal_places,
allowed_types: this.transactions[index].destination_account.allowed_types 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) { clearSource(index) {
// reset source account: // reset source account:
@@ -437,7 +449,7 @@ export default {
//console.log('EditTransaction: processIncomingGroupRow()'); //console.log('EditTransaction: processIncomingGroupRow()');
this.setTransactionType(transaction.type); this.setTransactionType(transaction.type);
if(true === transaction.reconciled) { if (true === transaction.reconciled) {
this.isReconciled = true; this.isReconciled = true;
} }
@@ -528,7 +540,16 @@ export default {
allowed_types: window.expectedSourceTypes.destination[this.ucFirst(transaction.type)] 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 = ''; result.foreign_amount.amount = '';
} }
this.transactions.push(result); this.transactions.push(result);
@@ -736,7 +757,7 @@ export default {
if (parseInt(row.piggy_bank) > 0) { if (parseInt(row.piggy_bank) > 0) {
currentArray.piggy_bank_id = parseInt(row.piggy_bank); 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: // drop content from array:
delete currentArray.source_id; delete currentArray.source_id;
delete currentArray.source_name; delete currentArray.source_name;
@@ -748,7 +769,7 @@ export default {
delete currentArray.currency_id; delete currentArray.currency_id;
currentArray.reconciled = true; currentArray.reconciled = true;
} }
if(true === row.isReconciled) { if (true === row.isReconciled) {
this.isReconciled = false; this.isReconciled = false;
} }
@@ -801,10 +822,16 @@ export default {
this.setDefaultErrors(); this.setDefaultErrors();
// do message if update or new: // do message if update or new:
if (this.storeAsNew) { 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 = ''; this.error_message = '';
} else { } 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 = ''; this.error_message = '';
} }
} else { } else {

View File

@@ -19,205 +19,213 @@
--> -->
<template> <template>
<!-- <!--
Show if: Show if:
- one or more currencies. - one or more currencies.
--> -->
<div v-if="this.enabledCurrencies.length >= 1" class="form-group" v-bind:class="{ 'has-error': hasError()}"> <div v-if="this.enabledCurrencies.length >= 1" class="form-group" v-bind:class="{ 'has-error': hasError()}">
<div class="col-sm-8 col-sm-offset-4 text-sm"> <div class="col-sm-8 col-sm-offset-4 text-sm">
{{ $t('form.foreign_amount') }} {{ $t('form.foreign_amount') }}
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<select ref="currency_select" class="form-control" name="foreign_currency[]" @input="handleInput"> <select ref="currency_select" class="form-control" name="foreign_currency[]" @input="handleInput">
<option <option
v-for="currency in this.enabledCurrencies" v-for="currency in this.enabledCurrencies"
:label="currency.attributes.name" :label="currency.attributes.name"
:selected="parseInt(value.currency_id) === parseInt(currency.id)" :selected="parseInt(value.currency_id) === parseInt(currency.id)"
:value="currency.id" :value="currency.id"
> >
{{ currency.attributes.name }} {{ currency.attributes.name }}
</option> </option>
</select> </select>
</div> </div>
<div class="col-sm-8"> <div class="col-sm-8">
<div class="input-group"> <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"
class="form-control" name="foreign_amount[]" :title="this.title" :value="value.amount" autocomplete="off"
step="any" type="number" @input="handleInput"> class="form-control" name="foreign_amount[]"
<span class="input-group-btn"> step="any" type="number" @input="handleInput">
<span class="input-group-btn">
<button <button
class="btn btn-default" class="btn btn-default"
tabIndex="-1" tabIndex="-1"
type="button" type="button"
v-on:click="clearAmount"><i class="fa fa-trash-o"></i></button> v-on:click="clearAmount"><i class="fa fa-trash-o"></i></button>
</span> </span>
</div> </div>
<ul v-for="error in this.error" class="list-unstyled"> <ul v-for="error in this.error" class="list-unstyled">
<li class="text-danger">{{ error }}</li> <li class="text-danger">{{ error }}</li>
</ul> </ul>
</div>
</div> </div>
</div>
</template> </template>
<script> <script>
export default { export default {
name: "ForeignAmountSelect", name: "ForeignAmountSelect",
props: ['source', 'destination', 'transactionType', 'value', 'error', 'no_currency', 'title',], props: ['source', 'destination', 'transactionType', 'value', 'error', 'no_currency', 'title',],
mounted() { mounted() {
this.liability = false; this.liability = false;
this.loadCurrencies(); // 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: false
}
},
watch: {
source: function () {
// console.log('ForeignAmountSelect watch source');
this.changeData();
},
destination: function () {
// console.log('ForeignAmountSelect watch destination');
this.changeData();
},
transactionType: function () {
// console.log('ForeignAmountSelect watch transaction type (is now ' + this.transactionType + ')');
this.changeData();
}
},
methods: {
clearAmount: function () {
this.$refs.amount.value = '';
this.$emit('input', this.$refs.amount.value);
// some event?
this.$emit('clear:amount')
},
hasError: function () {
//console.log('ForeignAmountSelect hasError');
return this.error.length > 0;
},
handleInput(e) {
// console.log('ForeignAmountSelect handleInput');
let obj = {
amount: this.$refs.amount.value,
currency_id: this.$refs.currency_select.value,
};
// console.log(obj);
this.$emit('input', obj
);
},
changeData: function () {
// console.log('ForeignAmountSelect changeData');
this.enabledCurrencies = [];
let destType = this.destination.type ? this.destination.type.toLowerCase() : 'invalid';
let srcType = this.source.type ? this.source.type.toLowerCase() : 'invalid';
let tType = this.transactionType ? this.transactionType.toLowerCase() : 'invalid';
let liabilities = ['loan', 'debt', 'mortgage'];
let sourceIsLiability = liabilities.indexOf(srcType) !== -1;
let destIsLiability = liabilities.indexOf(destType) !== -1;
}, // console.log(srcType + ' (source) is a liability: ' + sourceIsLiability);
data() { // console.log(destType + ' (dest) is a liability: ' + destIsLiability);
return { // console.log('tType: ' + tType);
currencies: [], if (tType === 'transfer' || destIsLiability || sourceIsLiability) {
enabledCurrencies: [], // console.log('Source is liability OR dest is liability, OR transfer. Lock list on currency of destination.');
exclude: null, // console.log('Length of currencies is ' + this.currencies.length);
// liability overrules the drop down list if the source or dest is a liability // console.log(this.currencies);
liability: false this.liability = true;
// 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) {
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]);
}
}
}
// console.log('Enabled currencies length is now ' + this.enabledCurrencies.length);
return;
}
// if type is withdrawal, list all but skip the source account ID.
if (tType === 'withdrawal' && this.source && false === sourceIsLiability) {
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
if (this.source.currency_id !== this.currencies[key].id) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
}
return;
}
// if type is deposit, list all but skip the source account ID.
if (tType === 'deposit' && this.destination) {
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
if (this.destination.currency_id !== this.currencies[key].id) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
}
return;
}
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
},
loadCurrencies: function () {
// console.log('loadCurrencies');
// reset list of currencies:
this.currencies = [
{
id: 0,
attributes: {
name: this.no_currency,
enabled: true
},
}
];
this.enabledCurrencies = [
{
attributes: {
name: this.no_currency,
enabled: true
},
id: 0,
}
];
this.getCurrencies(1);
},
getCurrencies: function (page) {
let url = document.getElementsByTagName('base')[0].href + "api/v1/currencies?page=" + page;
axios.get(url, {}).then((res) => {
for (const key in res.data.data) {
if (res.data.data.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
if (res.data.data[key].attributes.enabled) {
// console.log(res.data.data[key].attributes);
this.currencies.push(res.data.data[key]);
this.enabledCurrencies.push(res.data.data[key]);
}
}
}
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();
});
}
} }
},
watch: {
source: function () {
//console.log('ForeignAmountSelect watch source');
this.changeData();
},
destination: function () {
//console.log('ForeignAmountSelect watch destination');
this.changeData();
},
transactionType: function () {
//console.log('ForeignAmountSelect watch transaction type (is now ' + this.transactionType + ')');
this.changeData();
}
},
methods: {
clearAmount: function () {
this.$refs.amount.value = '';
this.$emit('input', this.$refs.amount.value);
// some event?
this.$emit('clear:amount')
},
hasError: function () {
//console.log('ForeignAmountSelect hasError');
return this.error.length > 0;
},
handleInput(e) {
//console.log('ForeignAmountSelect handleInput');
let obj = {
amount: this.$refs.amount.value,
currency_id: this.$refs.currency_select.value,
};
// console.log(obj);
this.$emit('input', obj
);
},
changeData: function () {
// console.log('ForeignAmountSelect changeData');
this.enabledCurrencies = [];
let destType = this.destination.type ? this.destination.type.toLowerCase() : 'invalid';
let srcType = this.source.type ? this.source.type.toLowerCase() : 'invalid';
let tType = this.transactionType ? this.transactionType.toLowerCase() : 'invalid';
let liabilities = ['loan', 'debt', 'mortgage'];
let sourceIsLiability = liabilities.indexOf(srcType) !== -1;
let destIsLiability = liabilities.indexOf(destType) !== -1;
// console.log(srcType + ' (source) is a liability: ' + sourceIsLiability);
// console.log(destType + ' (dest) is a liability: ' + destIsLiability);
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);
// console.log(this.currencies);
this.liability = true;
// 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)) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
}
// console.log('Enabled currencies length is now ' + this.enabledCurrencies.length);
return;
}
// if type is withdrawal, list all but skip the source account ID.
if (tType === 'withdrawal' && this.source && false === sourceIsLiability) {
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
if (this.source.currency_id !== this.currencies[key].id) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
}
return;
}
// if type is deposit, list all but skip the source account ID.
if (tType === 'deposit' && this.destination) {
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
if (this.destination.currency_id !== this.currencies[key].id) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
}
return;
}
for (const key in this.currencies) {
if (this.currencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
this.enabledCurrencies.push(this.currencies[key]);
}
}
},
loadCurrencies: function () {
// reset list of currencies:
this.currencies = [
{
id: 0,
attributes: {
name: this.no_currency,
enabled: true
},
}
];
this.enabledCurrencies = [
{
attributes: {
name: this.no_currency,
enabled: true
},
id: 0,
}
];
this.getCurrencies(1);
},
getCurrencies: function(page) {
// console.log('loadCurrencies on page ' + page);
let url = document.getElementsByTagName('base')[0].href + "api/v1/currencies?page=" + page;
axios.get(url, {}).then((res) => {
for (const key in res.data.data) {
if (res.data.data.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
if (res.data.data[key].attributes.enabled) {
// console.log(res.data.data[key].attributes);
this.currencies.push(res.data.data[key]);
this.enabledCurrencies.push(res.data.data[key]);
}
}
}
if(res.data.meta.pagination.current_page < res.data.meta.pagination.total_pages) {
this.getCurrencies(res.data.meta.pagination.current_page + 1);
}
});
}
}
} }
</script> </script>

View File

@@ -18,8 +18,8 @@
"is_reconciled": "Ist abgestimmt", "is_reconciled": "Ist abgestimmt",
"split": "Teilen", "split": "Teilen",
"single_split": "Teilen", "single_split": "Teilen",
"not_enough_currencies": "Not enough currencies", "not_enough_currencies": "Nicht gen\u00fcgend W\u00e4hrungen",
"not_enough_currencies_enabled": "If you have just one currency enabled, there is no need to add exchange rates.", "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.", "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_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.", "webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">Webhook #{ID}<\/a> (\"{title}\") wurde aktualisiert.",

View File

@@ -18,8 +18,8 @@
"is_reconciled": "\u0421\u0432\u0435\u0440\u0435\u043d\u043e", "is_reconciled": "\u0421\u0432\u0435\u0440\u0435\u043d\u043e",
"split": "\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c", "split": "\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c",
"single_split": "\u0420\u0430\u0437\u0434\u0435\u043b\u0451\u043d\u043d\u0430\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f", "single_split": "\u0420\u0430\u0437\u0434\u0435\u043b\u0451\u043d\u043d\u0430\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f",
"not_enough_currencies": "Not enough currencies", "not_enough_currencies": "\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0435\u0434\u0438\u043d\u0438\u0446 \u0432\u0430\u043b\u044e\u0442",
"not_enough_currencies_enabled": "If you have just one currency enabled, there is no need to add exchange rates.", "not_enough_currencies_enabled": "\u0415\u0441\u043b\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430 \u0432\u0430\u043b\u044e\u0442\u0430, \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u0443\u0440\u0441\u044b \u0432\u0430\u043b\u044e\u0442.",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f #{ID} (\"{title}\")<\/a> \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0430.", "transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f #{ID} (\"{title}\")<\/a> \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0430.",
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">\u0412\u0435\u0431-\u0445\u0443\u043a #{ID} (\"{title}\")<\/a> \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d.", "webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">\u0412\u0435\u0431-\u0445\u0443\u043a #{ID} (\"{title}\")<\/a> \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d.",
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">\u0412\u0435\u0431-\u0445\u0443\u043a #{ID} (\"{title}\")<\/a> \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d.", "webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">\u0412\u0435\u0431-\u0445\u0443\u043a #{ID} (\"{title}\")<\/a> \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d.",

View File

@@ -11,7 +11,7 @@ use FireflyIII\Support\Search\QueryParser\NodeGroup;
use FireflyIII\Support\Search\QueryParser\Node; use FireflyIII\Support\Search\QueryParser\Node;
use Tests\integration\TestCase; use Tests\integration\TestCase;
abstract class AbstractQueryParserInterfaceParseQueryTest extends TestCase abstract class AbstractQueryParserInterfaceParseQueryTester extends TestCase
{ {
abstract protected function createParser(): QueryParserInterface; abstract protected function createParser(): QueryParserInterface;

View File

@@ -16,7 +16,7 @@ use FireflyIII\Support\Search\QueryParser\QueryParserInterface;
* *
* @coversNothing * @coversNothing
*/ */
final class QueryParserParseQueryTest extends AbstractQueryParserInterfaceParseQueryTest final class QueryParserParseQueryTest extends AbstractQueryParserInterfaceParseQueryTester
{ {
protected function createParser(): QueryParserInterface protected function createParser(): QueryParserInterface
{ {