mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-31 02:36:28 +00:00 
			
		
		
		
	Merge branch 'develop'
This commit is contained in:
		| @@ -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(); | ||||
|   | ||||
| @@ -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(); | ||||
|     } | ||||
|   | ||||
| @@ -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(); | ||||
| 
 | ||||
|   | ||||
| @@ -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(); | ||||
|     } | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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
 | ||||
|   | ||||
| @@ -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)); | ||||
|   | ||||
| @@ -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.
 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										17
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								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._ | ||||
|   | ||||
							
								
								
									
										12
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							| @@ -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", | ||||
|   | ||||
| @@ -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, | ||||
| 
 | ||||
|   | ||||
| @@ -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'); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|   | ||||
| @@ -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(); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|   | ||||
							
								
								
									
										194
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										194
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -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": { | ||||
|   | ||||
| @@ -97,10 +97,10 @@ | ||||
|                                     > | ||||
|                                 </td> | ||||
|                                 <td> | ||||
|                                     <input type="number" class="form-control" min="0" v-model="rate.rate"> | ||||
|                                     <input type="number" class="form-control" min="0" step="any" v-model="rate.rate"> | ||||
|                                 </td> | ||||
|                                 <td> | ||||
|                                     <input type="number" class="form-control" min="0" v-model="rate.inverse"> | ||||
|                                     <input type="number" class="form-control" min="0" step="any" v-model="rate.inverse"> | ||||
|                                 </td> | ||||
|                                 <td> | ||||
|                                     <div class="btn-group"> | ||||
|   | ||||
| @@ -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 <a href=\"budgets\">bud\u017cet\u00f3w<\/a>. Bud\u017cety mog\u0105 Ci pom\u00f3c \u015bledzi\u0107 wydatki.", | ||||
|         "no_bill_pointer": "You seem to have no subscription yet. You should create some on the <a href=\"subscriptions\">subscription<\/a>-page. Subscriptions can help you keep track of expenses.", | ||||
|         "no_bill_pointer": "Wygl\u0105da na to, \u017ce nie masz jeszcze subskrypcji. Powiniene\u015b utworzy\u0107 j\u0105 na stronie <a href=\"subscriptions\">subskrypcji<\/a>. Subskrypcje mog\u0105 pom\u00f3c Ci \u015bledzi\u0107 wydatki.", | ||||
|         "source_account": "Konto \u017ar\u00f3d\u0142owe", | ||||
|         "hidden_fields_preferences": "Mo\u017cesz w\u0142\u0105czy\u0107 wi\u0119cej opcji transakcji w swoich <a href=\"preferences\">ustawieniach<\/a>.", | ||||
|         "destination_account": "Konto docelowe", | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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 <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">the documentation<\/a>.", | ||||
|         "exchange_rates_intro": "Firefly III podpira prenos in uporabo menjalnih te\u010dajev. Preberite ve\u010d o tem v <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">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", | ||||
|   | ||||
| @@ -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. <a href="https://docs.firefly-iii.org/how-to/firefly-iii/features/search/">Make sure you check out the help file</a> because the search is pretty advanced.', | ||||
|     'search_error'                                            => 'Error while searching', | ||||
|     'search_searching'                                        => 'Searching ...', | ||||
|     'search_results'                                          => 'Search results', | ||||
|   | ||||
| @@ -71,8 +71,8 @@ | ||||
|                         <tr> | ||||
|                             <td>{{ 'start_date'|_ }}</td> | ||||
|                             <td> | ||||
|                                 {% if piggyBank.startdate %} | ||||
|                                     {{ piggyBank.startdate.isoFormat(monthAndDayFormat) }} | ||||
|                                 {% if piggyBank.start_date %} | ||||
|                                     {{ piggyBank.start_date.isoFormat(monthAndDayFormat) }} | ||||
|                                 {% else %} | ||||
|                                     <em>{{ 'no_start_date'|_ }}</em> | ||||
|                                 {% endif %} | ||||
| @@ -81,14 +81,14 @@ | ||||
|                         <tr> | ||||
|                             <td>{{ 'target_date'|_ }}</td> | ||||
|                             <td> | ||||
|                                 {% if piggyBank.targetdate %} | ||||
|                                     {{ piggyBank.targetdate.isoFormat(monthAndDayFormat) }} | ||||
|                                 {% if piggyBank.target_date %} | ||||
|                                     {{ piggyBank.target_date.isoFormat(monthAndDayFormat) }} | ||||
|                                 {% else %} | ||||
|                                     <em>{{ 'no_target_date'|_ }}</em> | ||||
|                                 {% endif %} | ||||
|                             </td> | ||||
|                         </tr> | ||||
|                         {% if piggyBank.targetdate and piggy.save_per_month %} | ||||
|                         {% if piggyBank.target_date and piggy.save_per_month %} | ||||
|                             <tr> | ||||
|                                 <td>{{ 'suggested_amount'|_ }}</td> | ||||
|                                 <td> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user