mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-09 16:39:36 +00:00
Compare commits
13 Commits
develop-20
...
develop-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4587340293 | ||
|
|
90bfdc7573 | ||
|
|
eca12f661f | ||
|
|
f85878b843 | ||
|
|
6499b5eaab | ||
|
|
7e4fece63d | ||
|
|
512eddf8be | ||
|
|
f0fa93a811 | ||
|
|
3c8de21709 | ||
|
|
81173e8340 | ||
|
|
35a8fa5f02 | ||
|
|
443036936d | ||
|
|
ac88007593 |
@@ -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();
|
||||
|
||||
@@ -113,6 +113,7 @@ class ReconcileController extends Controller
|
||||
$end->endOfDay();
|
||||
|
||||
$startDate = clone $start;
|
||||
$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.
|
||||
|
||||
@@ -76,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);
|
||||
@@ -276,24 +257,14 @@ 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
|
||||
{
|
||||
@@ -301,7 +272,7 @@ class Steam
|
||||
$cache->addProperty($account->id);
|
||||
$cache->addProperty($date);
|
||||
if ($cache->has()) {
|
||||
// return $cache->get();
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Now in finalAccountBalance(#%d, "%s", "%s")', $account->id, $account->name, $date->format('Y-m-d H:i:s')));
|
||||
@@ -312,10 +283,10 @@ class Steam
|
||||
$hasCurrency = null !== $accountCurrency;
|
||||
$currency = $hasCurrency ? $accountCurrency : $native;
|
||||
$return = [
|
||||
'balance' => '0',
|
||||
'native_balance' => '0',
|
||||
'balance' => '0', // this key is overwritten right away, but I must remember it is always created.
|
||||
];
|
||||
// balance(s) in other (all) currencies.
|
||||
// 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')
|
||||
@@ -323,59 +294,39 @@ class Steam
|
||||
->get(['transaction_currencies.code', 'transactions.amount'])->toArray()
|
||||
;
|
||||
$others = $this->groupAndSumTransactions($array, 'code', 'amount');
|
||||
Log::debug('All balances are (joined)', $others);
|
||||
// Log::debug('All balances are (joined)', $others);
|
||||
// if there is no request to convert, take this as "balance" and "native_balance".
|
||||
$return['balance'] = $others[$currency->code] ?? '0';
|
||||
if (!$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']));
|
||||
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['balance'] = $others[$native->code] ?? '0';
|
||||
$return['native_balance'] = $this->convertAllBalances($others, $native, $date); // todo sum all and convert.
|
||||
Log::debug(sprintf('Set balance to %s and native_balance to %s', $return['balance'], $return['native_balance']));
|
||||
// Log::debug(sprintf('Set native_balance to %s', $return['native_balance']));
|
||||
}
|
||||
|
||||
// either way, the balance is always combined with the virtual balance:
|
||||
$virtualBalance = (string) ('' === (string) $account->virtual_balance ? '0' : $account->virtual_balance);
|
||||
$return['balance'] = bcadd($return['balance'], $virtualBalance);
|
||||
Log::debug(sprintf('Virtual balance makes the total %s', $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']));
|
||||
// Log::debug(sprintf('Native virtual balance makes the native total %s', $return['native_balance']));
|
||||
}
|
||||
if (!$convertToNative) {
|
||||
// if not, also increase the native balance for consistency.
|
||||
$return['native_balance'] = bcadd($return['native_balance'], $virtualBalance);
|
||||
Log::debug(sprintf('Virtual balance makes the (native) total %s', $return['balance']));
|
||||
// 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']));
|
||||
}
|
||||
|
||||
// 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'];
|
||||
// }
|
||||
|
||||
// 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']);
|
||||
// }
|
||||
$final = array_merge($return, $others);
|
||||
// // Log::debug('Return is', $final);
|
||||
|
||||
Log::debug('Final balance is', $final);
|
||||
$cache->store($final);
|
||||
|
||||
return $final;
|
||||
|
||||
// return array_merge($return, $others);
|
||||
// Log::debug('Return is', $final);
|
||||
}
|
||||
|
||||
public function filterAccountBalances(array $total, Account $account, bool $convertToNative, ?TransactionCurrency $currency = null): array
|
||||
@@ -401,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;
|
||||
|
||||
13
changelog.md
13
changelog.md
@@ -3,6 +3,19 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 6.2.3
|
||||
|
||||
### 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
|
||||
- [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 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._
|
||||
|
||||
@@ -81,7 +81,7 @@ return [
|
||||
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => 'develop/2025-02-04',
|
||||
'version' => 'develop/2025-02-05',
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 25,
|
||||
|
||||
|
||||
@@ -46,46 +46,76 @@ return new class () extends Migration {
|
||||
}
|
||||
Schema::table('piggy_banks', static function (Blueprint $table): void {
|
||||
// 2. make column nullable.
|
||||
$table->unsignedInteger('account_id')->nullable()->change();
|
||||
if (!Schema::hasColumn('piggy_banks', 'account_id')) {
|
||||
$table->unsignedInteger('account_id')->nullable()->change();
|
||||
}
|
||||
});
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
12
package-lock.json
generated
12
package-lock.json
generated
@@ -5663,9 +5663,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.91",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.91.tgz",
|
||||
"integrity": "sha512-sNSHHyq048PFmZY4S90ax61q+gLCs0X0YmcOII9wG9S2XwbVr+h4VW2wWhnbp/Eys3cCwTxVF292W3qPaxIapQ==",
|
||||
"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"
|
||||
},
|
||||
@@ -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": {
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user