diff --git a/app/Handlers/Observer/AccountObserver.php b/app/Handlers/Observer/AccountObserver.php index f2e4c05725..1ec19fbbbd 100644 --- a/app/Handlers/Observer/AccountObserver.php +++ b/app/Handlers/Observer/AccountObserver.php @@ -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; @@ -73,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(); diff --git a/app/Handlers/Observer/BillObserver.php b/app/Handlers/Observer/BillObserver.php index 792295156b..709d8b25ae 100644 --- a/app/Handlers/Observer/BillObserver.php +++ b/app/Handlers/Observer/BillObserver.php @@ -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(); } diff --git a/app/Handlers/Observer/BudgetObserver.php b/app/Handlers/Observer/BudgetObserver.php index d13abec746..01fc2a937e 100644 --- a/app/Handlers/Observer/BudgetObserver.php +++ b/app/Handlers/Observer/BudgetObserver.php @@ -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(); diff --git a/app/Handlers/Observer/CategoryObserver.php b/app/Handlers/Observer/CategoryObserver.php index 0cc866761a..76decd000d 100644 --- a/app/Handlers/Observer/CategoryObserver.php +++ b/app/Handlers/Observer/CategoryObserver.php @@ -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(); } diff --git a/app/Handlers/Observer/PiggyBankObserver.php b/app/Handlers/Observer/PiggyBankObserver.php index e8e55f8f9f..e2a88158b4 100644 --- a/app/Handlers/Observer/PiggyBankObserver.php +++ b/app/Handlers/Observer/PiggyBankObserver.php @@ -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(); diff --git a/app/Handlers/Observer/RecurrenceObserver.php b/app/Handlers/Observer/RecurrenceObserver.php index c892315f60..cf6a8f6e97 100644 --- a/app/Handlers/Observer/RecurrenceObserver.php +++ b/app/Handlers/Observer/RecurrenceObserver.php @@ -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(); diff --git a/app/Handlers/Observer/TagObserver.php b/app/Handlers/Observer/TagObserver.php index 1994a30aa1..4892ce2ccb 100644 --- a/app/Handlers/Observer/TagObserver.php +++ b/app/Handlers/Observer/TagObserver.php @@ -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(); diff --git a/app/Handlers/Observer/TransactionJournalObserver.php b/app/Handlers/Observer/TransactionJournalObserver.php index 3bb106783e..4b6986b468 100644 --- a/app/Handlers/Observer/TransactionJournalObserver.php +++ b/app/Handlers/Observer/TransactionJournalObserver.php @@ -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(); diff --git a/app/Helpers/Collector/GroupCollector.php b/app/Helpers/Collector/GroupCollector.php index 1c5cb8c91d..7d090996a7 100644 --- a/app/Helpers/Collector/GroupCollector.php +++ b/app/Helpers/Collector/GroupCollector.php @@ -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 diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index a49b1b0c1a..0b7955a42c 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -113,7 +113,7 @@ class ReconcileController extends Controller $end->endOfDay(); $startDate = clone $start; - $startDate->subDay(); + $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)); diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index e220f91807..557f3002a2 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -35,6 +35,7 @@ use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface; use FireflyIII\Support\CacheProperties; +use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Http\Controllers\AugumentData; use FireflyIII\Support\Http\Controllers\ChartGeneration; @@ -108,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) { @@ -426,13 +427,13 @@ class AccountController extends Controller $cache->addProperty($this->convertToNative); $cache->addProperty($account->id); if ($cache->has()) { - // return response()->json($cache->get()); + return response()->json($cache->get()); } // 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 @@ -570,8 +571,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. diff --git a/app/Http/Controllers/Json/ReconcileController.php b/app/Http/Controllers/Json/ReconcileController.php index 7037e7428a..a32c27178b 100644 --- a/app/Http/Controllers/Json/ReconcileController.php +++ b/app/Http/Controllers/Json/ReconcileController.php @@ -195,8 +195,8 @@ class ReconcileController extends Controller $startDate->subDay(); $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; diff --git a/app/Support/Steam.php b/app/Support/Steam.php index 6616f5aebf..2d4cc21547 100644 --- a/app/Support/Steam.php +++ b/app/Support/Steam.php @@ -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. @@ -75,99 +76,80 @@ 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, + $currency->id => $currency, + $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. $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 - $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); + // get date object + $carbon = new Carbon($entry->date, $entry->date_tz); + // 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]; + $entryCurrency = $currencies[$entry->transaction_currency_id]; Log::debug(sprintf('Processing transaction(s) on date %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; + // 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); + } + // add final $currentBalance array to the big one. + $balances[$carbon->format('Y-m-d')] = $currentBalance; Log::debug('Updated entry', $currentBalance); } $cache->store($balances); @@ -275,28 +257,18 @@ 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 = new CacheProperties(); $cache->addProperty($account->id); $cache->addProperty($date); if ($cache->has()) { @@ -305,86 +277,56 @@ class Steam Log::debug(sprintf('Now in finalAccountBalance(#%d, "%s", "%s")', $account->id, $account->name, $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. - $array = $account->transactions() + $native = Amount::getNativeCurrencyByUserGroup($account->user->userGroup); + $convertToNative = Amount::convertToNative($account->user); + $accountCurrency = $this->getAccountCurrency($account); + $hasCurrency = null !== $accountCurrency; + $currency = $hasCurrency ? $accountCurrency : $native; + $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') ->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s')) ->get(['transaction_currencies.code', 'transactions.amount'])->toArray() ; - $others = $this->groupAndSumTransactions($array, 'code', 'amount'); + $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) { - $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 there is no request to convert, take this as "balance" and "native_balance". + $return['balance'] = $others[$currency->code] ?? '0'; + 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'])); } - $final = array_merge($return, $others); - // Log::debug('Return is', $final); + 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('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,34 +352,34 @@ 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)); + 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']); } } if (!$convertToNative) { if (null === $currency) { - // Log::debug(sprintf('Unset native_balance and make defaultCurrency balance the balance for account #%d', $account->id)); + 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 +629,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; + } } diff --git a/changelog.md b/changelog.md index db58039faa..669d4d717d 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## 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._ diff --git a/composer.lock b/composer.lock index a0117c3388..27c5088853 100644 --- a/composer.lock +++ b/composer.lock @@ -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", diff --git a/config/firefly.php b/config/firefly.php index ea8887f5bc..6ccd4bc882 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -81,7 +81,7 @@ return [ 'running_balance_column' => env('USE_RUNNING_BALANCE', false), // see cer.php for exchange rates feature flag. ], - 'version' => '6.2.2', + 'version' => 'develop/2025-02-05', 'api_version' => '2.1.0', // field is no longer used. 'db_version' => 25, diff --git a/database/migrations/2024_11_30_075826_multi_piggy.php b/database/migrations/2024_11_30_075826_multi_piggy.php index 99718041eb..56639a463e 100644 --- a/database/migrations/2024_11_30_075826_multi_piggy.php +++ b/database/migrations/2024_11_30_075826_multi_piggy.php @@ -50,42 +50,70 @@ return new class () extends Migration { }); Schema::table('piggy_banks', static function (Blueprint $table): void { // 3. add currency - $table->integer('transaction_currency_id', false, true)->after('account_id')->nullable(); - $table->foreign('transaction_currency_id', 'unique_currency')->references('id')->on('transaction_currencies')->onDelete('cascade'); + 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 - $table->renameColumn('targetamount', 'target_amount'); - $table->renameColumn('startdate', 'start_date'); - $table->renameColumn('targetdate', 'target_date'); - $table->renameColumn('startdate_tz', 'start_date_tz'); - $table->renameColumn('targetdate_tz', 'target_date_tz'); + 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 - $table->foreign('account_id')->references('id')->on('accounts')->onDelete('set null'); + 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 - $table->renameColumn('currentamount', 'current_amount'); - $table->renameColumn('startdate', 'start_date'); - $table->renameColumn('targetdate', 'target_date'); - $table->renameColumn('startdate_tz', 'start_date_tz'); - $table->renameColumn('targetdate_tz', 'target_date_tz'); + 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 - Schema::create('account_piggy_bank', static function (Blueprint $table): void { - $table->id(); - $table->integer('account_id', false, true); - $table->integer('piggy_bank_id', false, true); - $table->decimal('current_amount', 32, 12)->default('0'); - $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); - $table->foreign('piggy_bank_id')->references('id')->on('piggy_banks')->onDelete('cascade'); - $table->unique(['account_id', 'piggy_bank_id'], 'unique_piggy_save'); - }); + if (!Schema::hasTable('account_piggy_bank')) { + Schema::create('account_piggy_bank', static function (Blueprint $table): void { + $table->id(); + $table->integer('account_id', false, true); + $table->integer('piggy_bank_id', false, true); + $table->decimal('current_amount', 32, 12)->default('0'); + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('piggy_bank_id')->references('id')->on('piggy_banks')->onDelete('cascade'); + $table->unique(['account_id', 'piggy_bank_id'], 'unique_piggy_save'); + }); + } } diff --git a/database/migrations/2024_12_19_061003_add_native_amount_column.php b/database/migrations/2024_12_19_061003_add_native_amount_column.php index 2bbd8e4c97..d910a46213 100644 --- a/database/migrations/2024_12_19_061003_add_native_amount_column.php +++ b/database/migrations/2024_12_19_061003_add_native_amount_column.php @@ -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(); + } }); } } diff --git a/package-lock.json b/package-lock.json index 7cd97b3125..188f535bde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2591,9 +2591,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.0.tgz", - "integrity": "sha512-Eeao7ewDq79jVEsrtWIj5RNqB8p2knlm9fhR6uJ2gqP7UfbLrTrxevudVrEPDM7Wkpn/HpRC2QfazH7MXLz3vQ==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.2.tgz", + "integrity": "sha512-6Fyg9yQbwJR+ykVdT9sid1oc2ewejS6h4wzQltmJfSW53N60G/ah9pngXGANdy9/aaE/TcUFpWosdm7JXS1WTQ==", "cpu": [ "arm" ], @@ -2605,9 +2605,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.0.tgz", - "integrity": "sha512-yVh0Kf1f0Fq4tWNf6mWcbQBCLDpDrDEl88lzPgKhrgTcDrTtlmun92ywEF9dCjmYO3EFiSuJeeo9cYRxl2FswA==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.2.tgz", + "integrity": "sha512-K5GfWe+vtQ3kyEbihrimM38UgX57UqHp+oME7X/EX9Im6suwZfa7Hsr8AtzbJvukTpwMGs+4s29YMSO3rwWtsw==", "cpu": [ "arm64" ], @@ -2619,9 +2619,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.0.tgz", - "integrity": "sha512-gCs0ErAZ9s0Osejpc3qahTsqIPUDjSKIyxK/0BGKvL+Tn0n3Kwvj8BrCv7Y5sR1Ypz1K2qz9Ny0VvkVyoXBVUQ==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.2.tgz", + "integrity": "sha512-PSN58XG/V/tzqDb9kDGutUruycgylMlUE59f40ny6QIRNsTEIZsrNQTJKUN2keMMSmlzgunMFqyaGLmly39sug==", "cpu": [ "arm64" ], @@ -2633,9 +2633,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.0.tgz", - "integrity": "sha512-aIB5Anc8hngk15t3GUkiO4pv42ykXHfmpXGS+CzM9CTyiWyT8HIS5ygRAy7KcFb/wiw4Br+vh1byqcHRTfq2tQ==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.2.tgz", + "integrity": "sha512-gQhK788rQJm9pzmXyfBB84VHViDERhAhzGafw+E5mUpnGKuxZGkMVDa3wgDFKT6ukLC5V7QTifzsUKdNVxp5qQ==", "cpu": [ "x64" ], @@ -2647,9 +2647,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.0.tgz", - "integrity": "sha512-kpdsUdMlVJMRMaOf/tIvxk8TQdzHhY47imwmASOuMajg/GXpw8GKNd8LNwIHE5Yd1onehNpcUB9jHY6wgw9nHQ==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.2.tgz", + "integrity": "sha512-eiaHgQwGPpxLC3+zTAcdKl4VsBl3r0AiJOd1Um/ArEzAjN/dbPK1nROHrVkdnoE6p7Svvn04w3f/jEZSTVHunA==", "cpu": [ "arm64" ], @@ -2661,9 +2661,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.0.tgz", - "integrity": "sha512-D0RDyHygOBCQiqookcPevrvgEarN0CttBecG4chOeIYCNtlKHmf5oi5kAVpXV7qs0Xh/WO2RnxeicZPtT50V0g==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.2.tgz", + "integrity": "sha512-lhdiwQ+jf8pewYOTG4bag0Qd68Jn1v2gO1i0mTuiD+Qkt5vNfHVK/jrT7uVvycV8ZchlzXp5HDVmhpzjC6mh0g==", "cpu": [ "x64" ], @@ -2675,9 +2675,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.0.tgz", - "integrity": "sha512-mCIw8j5LPDXmCOW8mfMZwT6F/Kza03EnSr4wGYEswrEfjTfVsFOxvgYfuRMxTuUF/XmRb9WSMD5GhCWDe2iNrg==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.2.tgz", + "integrity": "sha512-lfqTpWjSvbgQP1vqGTXdv+/kxIznKXZlI109WkIFPbud41bjigjNmOAAKoazmRGx+k9e3rtIdbq2pQZPV1pMig==", "cpu": [ "arm" ], @@ -2689,9 +2689,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.0.tgz", - "integrity": "sha512-AwwldAu4aCJPob7zmjuDUMvvuatgs8B/QiVB0KwkUarAcPB3W+ToOT+18TQwY4z09Al7G0BvCcmLRop5zBLTag==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.2.tgz", + "integrity": "sha512-RGjqULqIurqqv+NJTyuPgdZhka8ImMLB32YwUle2BPTDqDoXNgwFjdjQC59FbSk08z0IqlRJjrJ0AvDQ5W5lpw==", "cpu": [ "arm" ], @@ -2703,9 +2703,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.0.tgz", - "integrity": "sha512-e7kDUGVP+xw05pV65ZKb0zulRploU3gTu6qH1qL58PrULDGxULIS0OSDQJLH7WiFnpd3ZKUU4VM3u/Z7Zw+e7Q==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.2.tgz", + "integrity": "sha512-ZvkPiheyXtXlFqHpsdgscx+tZ7hoR59vOettvArinEspq5fxSDSgfF+L5wqqJ9R4t+n53nyn0sKxeXlik7AY9Q==", "cpu": [ "arm64" ], @@ -2717,9 +2717,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.0.tgz", - "integrity": "sha512-SXYJw3zpwHgaBqTXeAZ31qfW/v50wq4HhNVvKFhRr5MnptRX2Af4KebLWR1wpxGJtLgfS2hEPuALRIY3LPAAcA==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.2.tgz", + "integrity": "sha512-UlFk+E46TZEoxD9ufLKDBzfSG7Ki03fo6hsNRRRHF+KuvNZ5vd1RRVQm8YZlGsjcJG8R252XFK0xNPay+4WV7w==", "cpu": [ "arm64" ], @@ -2731,9 +2731,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.0.tgz", - "integrity": "sha512-e5XiCinINCI4RdyU3sFyBH4zzz7LiQRvHqDtRe9Dt8o/8hTBaYpdPimayF00eY2qy5j4PaaWK0azRgUench6WQ==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.2.tgz", + "integrity": "sha512-hJhfsD9ykx59jZuuoQgYT1GEcNNi3RCoEmbo5OGfG8RlHOiVS7iVNev9rhLKh7UBYq409f4uEw0cclTXx8nh8Q==", "cpu": [ "loong64" ], @@ -2745,9 +2745,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.0.tgz", - "integrity": "sha512-3SWN3e0bAsm9ToprLFBSro8nJe6YN+5xmB11N4FfNf92wvLye/+Rh5JGQtKOpwLKt6e61R1RBc9g+luLJsc23A==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.2.tgz", + "integrity": "sha512-g/O5IpgtrQqPegvqopvmdCF9vneLE7eqYfdPWW8yjPS8f63DNam3U4ARL1PNNB64XHZDHKpvO2Giftf43puB8Q==", "cpu": [ "ppc64" ], @@ -2759,9 +2759,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.0.tgz", - "integrity": "sha512-B1Oqt3GLh7qmhvfnc2WQla4NuHlcxAD5LyueUi5WtMc76ZWY+6qDtQYqnxARx9r+7mDGfamD+8kTJO0pKUJeJA==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.2.tgz", + "integrity": "sha512-bSQijDC96M6PuooOuXHpvXUYiIwsnDmqGU8+br2U7iPoykNi9JtMUpN7K6xml29e0evK0/g0D1qbAUzWZFHY5Q==", "cpu": [ "riscv64" ], @@ -2773,9 +2773,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.0.tgz", - "integrity": "sha512-UfUCo0h/uj48Jq2lnhX0AOhZPSTAq3Eostas+XZ+GGk22pI+Op1Y6cxQ1JkUuKYu2iU+mXj1QjPrZm9nNWV9rg==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.2.tgz", + "integrity": "sha512-49TtdeVAsdRuiUHXPrFVucaP4SivazetGUVH8CIxVsNsaPHV4PFkpLmH9LeqU/R4Nbgky9lzX5Xe1NrzLyraVA==", "cpu": [ "s390x" ], @@ -2787,9 +2787,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.0.tgz", - "integrity": "sha512-chZLTUIPbgcpm+Z7ALmomXW8Zh+wE2icrG+K6nt/HenPLmtwCajhQC5flNSk1Xy5EDMt/QAOz2MhzfOfJOLSiA==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.2.tgz", + "integrity": "sha512-j+jFdfOycLIQ7FWKka9Zd3qvsIyugg5LeZuHF6kFlXo6MSOc6R1w37YUVy8VpAKd81LMWGi5g9J25P09M0SSIw==", "cpu": [ "x64" ], @@ -2801,9 +2801,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.0.tgz", - "integrity": "sha512-jo0UolK70O28BifvEsFD/8r25shFezl0aUk2t0VJzREWHkq19e+pcLu4kX5HiVXNz5qqkD+aAq04Ct8rkxgbyQ==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.2.tgz", + "integrity": "sha512-aDPHyM/D2SpXfSNCVWCxyHmOqN9qb7SWkY1+vaXqMNMXslZYnwh9V/UCudl6psyG0v6Ukj7pXanIpfZwCOEMUg==", "cpu": [ "x64" ], @@ -2815,9 +2815,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.0.tgz", - "integrity": "sha512-Vmg0NhAap2S54JojJchiu5An54qa6t/oKT7LmDaWggpIcaiL8WcWHEN6OQrfTdL6mQ2GFyH7j2T5/3YPEDOOGA==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.2.tgz", + "integrity": "sha512-LQRkCyUBnAo7r8dbEdtNU08EKLCJMgAk2oP5H3R7BnUlKLqgR3dUjrLBVirmc1RK6U6qhtDw29Dimeer8d5hzQ==", "cpu": [ "arm64" ], @@ -2829,9 +2829,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.0.tgz", - "integrity": "sha512-CV2aqhDDOsABKHKhNcs1SZFryffQf8vK2XrxP6lxC99ELZAdvsDgPklIBfd65R8R+qvOm1SmLaZ/Fdq961+m7A==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.2.tgz", + "integrity": "sha512-wt8OhpQUi6JuPFkm1wbVi1BByeag87LDFzeKSXzIdGcX4bMLqORTtKxLoCbV57BHYNSUSOKlSL4BYYUghainYA==", "cpu": [ "ia32" ], @@ -2843,9 +2843,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.0.tgz", - "integrity": "sha512-g2ASy1QwHP88y5KWvblUolJz9rN+i4ZOsYzkEwcNfaNooxNUXG+ON6F5xFo0NIItpHqxcdAyls05VXpBnludGw==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.2.tgz", + "integrity": "sha512-rUrqINax0TvrPBXrFKg0YbQx18NpPN3NNrgmaao9xRNbTwek7lOXObhx8tQy8gelmQ/gLaGy1WptpU2eKJZImg==", "cpu": [ "x64" ], @@ -3133,9 +3133,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.0.tgz", - "integrity": "sha512-ClIbNe36lawluuvq3+YYhnIN2CELi+6q8NpnM7PYp4hBn/TatfboPgVSm2rwKRfnV2M+Ty9GWDFI64KEe+kysA==", + "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 +4448,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001696", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001696.tgz", - "integrity": "sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ==", + "version": "1.0.30001697", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001697.tgz", + "integrity": "sha512-GwNPlWJin8E+d7Gxq96jxM6w0w+VFeyyXRsjU58emtkYqnbwHqXm5uT2uCmO0RQE9htWknOP4xtBlLmM/gWxvQ==", "dev": true, "funding": [ { @@ -5663,9 +5663,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.90", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.90.tgz", - "integrity": "sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug==", + "version": "1.5.92", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.92.tgz", + "integrity": "sha512-BeHgmNobs05N1HMmMZ7YIuHfYBGlq/UmvlsTgg+fsbFs9xVMj+xJHFg19GN04+9Q+r8Xnh9LXqaYIyEWElnNgQ==", "dev": true, "license": "ISC" }, @@ -5720,9 +5720,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": { @@ -8387,9 +8387,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": { @@ -9987,9 +9987,9 @@ } }, "node_modules/rollup": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.0.tgz", - "integrity": "sha512-+4C/cgJ9w6sudisA0nZz0+O7lTP9a3CzNLsoDwaRumM8QHwghUsu6tqHXiTmNUp/rqNiM14++7dkzHDyCRs0Jg==", + "version": "4.34.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.2.tgz", + "integrity": "sha512-sBDUoxZEaqLu9QeNalL8v3jw6WjPku4wfZGyTU7l7m1oC+rpRihXc/n/H+4148ZkGz5Xli8CHMns//fFGKvpIQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10003,25 +10003,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.34.0", - "@rollup/rollup-android-arm64": "4.34.0", - "@rollup/rollup-darwin-arm64": "4.34.0", - "@rollup/rollup-darwin-x64": "4.34.0", - "@rollup/rollup-freebsd-arm64": "4.34.0", - "@rollup/rollup-freebsd-x64": "4.34.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.34.0", - "@rollup/rollup-linux-arm-musleabihf": "4.34.0", - "@rollup/rollup-linux-arm64-gnu": "4.34.0", - "@rollup/rollup-linux-arm64-musl": "4.34.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.34.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.34.0", - "@rollup/rollup-linux-riscv64-gnu": "4.34.0", - "@rollup/rollup-linux-s390x-gnu": "4.34.0", - "@rollup/rollup-linux-x64-gnu": "4.34.0", - "@rollup/rollup-linux-x64-musl": "4.34.0", - "@rollup/rollup-win32-arm64-msvc": "4.34.0", - "@rollup/rollup-win32-ia32-msvc": "4.34.0", - "@rollup/rollup-win32-x64-msvc": "4.34.0", + "@rollup/rollup-android-arm-eabi": "4.34.2", + "@rollup/rollup-android-arm64": "4.34.2", + "@rollup/rollup-darwin-arm64": "4.34.2", + "@rollup/rollup-darwin-x64": "4.34.2", + "@rollup/rollup-freebsd-arm64": "4.34.2", + "@rollup/rollup-freebsd-x64": "4.34.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.2", + "@rollup/rollup-linux-arm-musleabihf": "4.34.2", + "@rollup/rollup-linux-arm64-gnu": "4.34.2", + "@rollup/rollup-linux-arm64-musl": "4.34.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.2", + "@rollup/rollup-linux-riscv64-gnu": "4.34.2", + "@rollup/rollup-linux-s390x-gnu": "4.34.2", + "@rollup/rollup-linux-x64-gnu": "4.34.2", + "@rollup/rollup-linux-x64-musl": "4.34.2", + "@rollup/rollup-win32-arm64-msvc": "4.34.2", + "@rollup/rollup-win32-ia32-msvc": "4.34.2", + "@rollup/rollup-win32-x64-msvc": "4.34.2", "fsevents": "~2.3.2" } }, @@ -10168,9 +10168,9 @@ } }, "node_modules/semver": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", - "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==", + "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": { diff --git a/resources/assets/v1/src/components/exchange-rates/Rates.vue b/resources/assets/v1/src/components/exchange-rates/Rates.vue index 3639830270..150af3e8eb 100644 --- a/resources/assets/v1/src/components/exchange-rates/Rates.vue +++ b/resources/assets/v1/src/components/exchange-rates/Rates.vue @@ -97,10 +97,10 @@ > - + - +
diff --git a/resources/assets/v1/src/locales/pl.json b/resources/assets/v1/src/locales/pl.json index d2f4defc7e..de52232336 100644 --- a/resources/assets/v1/src/locales/pl.json +++ b/resources/assets/v1/src/locales/pl.json @@ -28,7 +28,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 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 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 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 ustawieniach<\/a>.", "destination_account": "Konto docelowe", @@ -151,7 +151,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 +166,12 @@ "webhook_delivery": "Dor\u0119czenie", "from_currency_to_currency": "{from} → {to}", "to_currency_from_currency": "{to} → {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", diff --git a/resources/assets/v1/src/locales/sl.json b/resources/assets/v1/src/locales/sl.json index e513eaf9a5..f7debcad5b 100644 --- a/resources/assets/v1/src/locales/sl.json +++ b/resources/assets/v1/src/locales/sl.json @@ -138,7 +138,7 @@ "visit_webhook_url": "Obi\u0161\u010dite URL webhooka", "reset_webhook_secret": "Ponastavi skrivno kodo webhooka", "header_exchange_rates": "Menjalni te\u010daji", - "exchange_rates_intro": "Firefly III supports downloading and using exchange rates. Read more about this in the documentation<\/a>.", + "exchange_rates_intro": "Firefly III podpira prenos in uporabo menjalnih te\u010dajev. Preberite ve\u010d o tem v dokumentaciji<\/a>.", "exchange_rates_from_to": "Med {from} in {to} (in obratno)", "exchange_rates_intro_rates": "Firefly III uporablja naslednje menjalne te\u010daje. Obratna vrednost se samodejno izra\u010duna, \u010de ni na voljo. \u010ce na dan transakcije ni menjalnega te\u010daja, se bo Firefly III vrnil v preteklost, da bi ga na\u0161el. \u010ce jih ni, se uporabi te\u010daj \"1\".", "header_exchange_rates_rates": "Menjalni te\u010daji", diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index beb8537a8b..ced49e5599 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -733,7 +733,7 @@ return [ // END 'general_search_error' => 'An error occurred while searching. Please check the log files for more information.', 'search_box' => 'Search', - 'search_box_intro' => 'Welcome to the search function of Firefly III. Enter your search query in the box. Make sure you check out the help file because the search is pretty advanced.', + 'search_box_intro' => 'Welcome to the search function of Firefly III. Enter your search query in the box. Make sure you check out the help file because the search is pretty advanced.', 'search_error' => 'Error while searching', 'search_searching' => 'Searching ...', 'search_results' => 'Search results', diff --git a/resources/views/piggy-banks/show.twig b/resources/views/piggy-banks/show.twig index e91db15a5d..9bb716af79 100644 --- a/resources/views/piggy-banks/show.twig +++ b/resources/views/piggy-banks/show.twig @@ -71,8 +71,8 @@ {{ 'start_date'|_ }} - {% if piggyBank.startdate %} - {{ piggyBank.startdate.isoFormat(monthAndDayFormat) }} + {% if piggyBank.start_date %} + {{ piggyBank.start_date.isoFormat(monthAndDayFormat) }} {% else %} {{ 'no_start_date'|_ }} {% endif %} @@ -81,14 +81,14 @@ {{ 'target_date'|_ }} - {% if piggyBank.targetdate %} - {{ piggyBank.targetdate.isoFormat(monthAndDayFormat) }} + {% if piggyBank.target_date %} + {{ piggyBank.target_date.isoFormat(monthAndDayFormat) }} {% else %} {{ 'no_target_date'|_ }} {% endif %} - {% if piggyBank.targetdate and piggy.save_per_month %} + {% if piggyBank.target_date and piggy.save_per_month %} {{ 'suggested_amount'|_ }}