This commit is contained in:
James Cole
2023-12-22 06:14:14 +01:00
parent 669aedeea3
commit f69072d293
15 changed files with 161 additions and 56 deletions

View File

@@ -101,7 +101,11 @@ class BasicController extends Controller
$billData = $this->getBillInformation($start, $end); $billData = $this->getBillInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end); $spentData = $this->getLeftToSpendInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($start, $end); $netWorthData = $this->getNetWorthInfo($start, $end);
$total = array_merge($balanceData, $billData, $spentData, $netWorthData); // $balanceData = [];
// $billData = [];
// $spentData = [];
// $netWorthData = [];
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
// give new keys // give new keys
$return = []; $return = [];
@@ -154,7 +158,7 @@ class BasicController extends Controller
/** @var array $transactionJournal */ /** @var array $transactionJournal */
foreach ($set as $transactionJournal) { foreach ($set as $transactionJournal) {
$currencyId = (int)$transactionJournal['currency_id']; $currencyId = (int) $transactionJournal['currency_id'];
$incomes[$currencyId] ??= '0'; $incomes[$currencyId] ??= '0';
$incomes[$currencyId] = bcadd( $incomes[$currencyId] = bcadd(
$incomes[$currencyId], $incomes[$currencyId],
@@ -178,7 +182,7 @@ class BasicController extends Controller
/** @var array $transactionJournal */ /** @var array $transactionJournal */
foreach ($set as $transactionJournal) { foreach ($set as $transactionJournal) {
$currencyId = (int)$transactionJournal['currency_id']; $currencyId = (int) $transactionJournal['currency_id'];
$expenses[$currencyId] ??= '0'; $expenses[$currencyId] ??= '0';
$expenses[$currencyId] = bcadd($expenses[$currencyId], $transactionJournal['amount']); $expenses[$currencyId] = bcadd($expenses[$currencyId], $transactionJournal['amount']);
$sums[$currencyId] ??= '0'; $sums[$currencyId] ??= '0';
@@ -197,7 +201,7 @@ class BasicController extends Controller
'key' => sprintf('balance-in-%s', $currency->code), 'key' => sprintf('balance-in-%s', $currency->code),
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]), 'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $sums[$currencyId] ?? '0', 'monetary_value' => $sums[$currencyId] ?? '0',
'currency_id' => (string)$currency->id, 'currency_id' => (string) $currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -210,7 +214,7 @@ class BasicController extends Controller
'key' => sprintf('spent-in-%s', $currency->code), 'key' => sprintf('spent-in-%s', $currency->code),
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]), 'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $expenses[$currencyId] ?? '0', 'monetary_value' => $expenses[$currencyId] ?? '0',
'currency_id' => (string)$currency->id, 'currency_id' => (string) $currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -222,7 +226,7 @@ class BasicController extends Controller
'key' => sprintf('earned-in-%s', $currency->code), 'key' => sprintf('earned-in-%s', $currency->code),
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]), 'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
'monetary_value' => $incomes[$currencyId] ?? '0', 'monetary_value' => $incomes[$currencyId] ?? '0',
'currency_id' => (string)$currency->id, 'currency_id' => (string) $currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
@@ -256,7 +260,7 @@ class BasicController extends Controller
'key' => sprintf('bills-paid-in-%s', $info['code']), 'key' => sprintf('bills-paid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]), 'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]),
'monetary_value' => $amount, 'monetary_value' => $amount,
'currency_id' => (string)$info['id'], 'currency_id' => (string) $info['id'],
'currency_code' => $info['code'], 'currency_code' => $info['code'],
'currency_symbol' => $info['symbol'], 'currency_symbol' => $info['symbol'],
'currency_decimal_places' => $info['decimal_places'], 'currency_decimal_places' => $info['decimal_places'],
@@ -275,7 +279,7 @@ class BasicController extends Controller
'key' => sprintf('bills-unpaid-in-%s', $info['code']), 'key' => sprintf('bills-unpaid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]), 'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]),
'monetary_value' => $amount, 'monetary_value' => $amount,
'currency_id' => (string)$info['id'], 'currency_id' => (string) $info['id'],
'currency_code' => $info['code'], 'currency_code' => $info['code'],
'currency_symbol' => $info['symbol'], 'currency_symbol' => $info['symbol'],
'currency_decimal_places' => $info['decimal_places'], 'currency_decimal_places' => $info['decimal_places'],
@@ -302,21 +306,21 @@ class BasicController extends Controller
foreach ($spent as $row) { foreach ($spent as $row) {
// either an amount was budgeted or 0 is available. // either an amount was budgeted or 0 is available.
$amount = (string)($available[$row['currency_id']] ?? '0'); $amount = (string) ($available[$row['currency_id']] ?? '0');
$spentInCurrency = $row['sum']; $spentInCurrency = $row['sum'];
$leftToSpend = bcadd($amount, $spentInCurrency); $leftToSpend = bcadd($amount, $spentInCurrency);
$days = $today->diffInDays($end) + 1; $days = $today->diffInDays($end) + 1;
$perDay = '0'; $perDay = '0';
if (0 !== $days && bccomp($leftToSpend, '0') > -1) { if (0 !== $days && bccomp($leftToSpend, '0') > -1) {
$perDay = bcdiv($leftToSpend, (string)$days); $perDay = bcdiv($leftToSpend, (string) $days);
} }
$return[] = [ $return[] = [
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']), 'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]), 'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]),
'monetary_value' => $leftToSpend, 'monetary_value' => $leftToSpend,
'currency_id' => (string)$row['currency_id'], 'currency_id' => (string) $row['currency_id'],
'currency_code' => $row['currency_code'], 'currency_code' => $row['currency_code'],
'currency_symbol' => $row['currency_symbol'], 'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'], 'currency_decimal_places' => $row['currency_decimal_places'],
@@ -376,7 +380,7 @@ class BasicController extends Controller
'key' => sprintf('net-worth-in-%s', $data['currency_code']), 'key' => sprintf('net-worth-in-%s', $data['currency_code']),
'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $data['currency_symbol']]), 'title' => trans('firefly.box_net_worth_in_currency', ['currency' => $data['currency_symbol']]),
'monetary_value' => $amount, 'monetary_value' => $amount,
'currency_id' => (string)$data['currency_id'], 'currency_id' => (string) $data['currency_id'],
'currency_code' => $data['currency_code'], 'currency_code' => $data['currency_code'],
'currency_symbol' => $data['currency_symbol'], 'currency_symbol' => $data['currency_symbol'],
'currency_decimal_places' => $data['currency_decimal_places'], 'currency_decimal_places' => $data['currency_decimal_places'],

View File

@@ -225,6 +225,7 @@ class BudgetController extends Controller
$return[$currencyId]['native_spent'] = bcadd($return[$currencyId]['native_spent'], $convertedAmount); $return[$currencyId]['native_spent'] = bcadd($return[$currencyId]['native_spent'], $convertedAmount);
} }
} }
$converter->summarize();
return $return; return $return;
} }
@@ -288,6 +289,7 @@ class BudgetController extends Controller
$result[$limitCurrencyId]['native_overspent'] = app('steam')->positive(bcadd($convertedLimitAmount, $result[$limitCurrencyId]['native_spent'])); $result[$limitCurrencyId]['native_overspent'] = app('steam')->positive(bcadd($convertedLimitAmount, $result[$limitCurrencyId]['native_spent']));
} }
} }
$converter->summarize();
return $result; return $result;
} }

View File

@@ -137,6 +137,7 @@ class CategoryController extends Controller
usort($return, static function (array $a, array $b) { usort($return, static function (array $a, array $b) {
return (float)$a['native_amount'] < (float)$b['native_amount'] ? 1 : -1; return (float)$a['native_amount'] < (float)$b['native_amount'] ? 1 : -1;
}); });
$converter->summarize();
return response()->json($this->clean($return)); return response()->json($this->clean($return));
} }

View File

@@ -278,7 +278,6 @@ class BasicController extends Controller
*/ */
foreach ($spent as $currencyId => $row) { foreach ($spent as $currencyId => $row) {
app('log')->debug(sprintf('Processing spent array in currency #%d', $currencyId)); app('log')->debug(sprintf('Processing spent array in currency #%d', $currencyId));
$currencyId = $currencyId;
$spent = '0'; $spent = '0';
$spentNative = '0'; $spentNative = '0';
@@ -351,6 +350,7 @@ class BasicController extends Controller
} }
$return[] = $nativeLeft; $return[] = $nativeLeft;
$return[] = $nativePerDay; $return[] = $nativePerDay;
$converter->summarize();
return $return; return $return;
} }

View File

@@ -927,7 +927,7 @@ class GroupCollector implements GroupCollectorInterface
{ {
$currentCollection = $collection; $currentCollection = $collection;
app('log')->debug(sprintf('GroupCollector: postFilterCollection has %d filter(s) and %d transaction(s).', count($this->postFilters), count($currentCollection))); // app('log')->debug(sprintf('GroupCollector: postFilterCollection has %d filter(s) and %d transaction(s).', count($this->postFilters), count($currentCollection)));
/** /**
* @var \Closure $function * @var \Closure $function

View File

@@ -138,6 +138,7 @@ class NetWorth implements NetWorthInterface
$netWorth['native']['native_balance'] = bcadd($nativeBalance, $netWorth['native']['native_balance']); $netWorth['native']['native_balance'] = bcadd($nativeBalance, $netWorth['native']['native_balance']);
} }
$cache->store($netWorth); $cache->store($netWorth);
$converter->summarize();
return $netWorth; return $netWorth;
} }

View File

@@ -118,6 +118,7 @@ class BillRepository implements BillRepositoryInterface
} }
} }
} }
$converter->summarize();
return $return; return $return;
} }
@@ -167,6 +168,7 @@ class BillRepository implements BillRepositoryInterface
$return[$currencyId]['native_sum'] = bcadd($return[$currencyId]['native_sum'], bcmul($nativeAverage, (string)$total)); $return[$currencyId]['native_sum'] = bcadd($return[$currencyId]['native_sum'], bcmul($nativeAverage, (string)$total));
} }
} }
$converter->summarize();
return $return; return $return;
} }

View File

@@ -67,6 +67,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
$return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $availableBudget->amount); $return[$currencyId]['amount'] = bcadd($return[$currencyId]['amount'], $availableBudget->amount);
$return[$currencyId]['native_amount'] = bcadd($return[$currencyId]['native_amount'], $nativeAmount); $return[$currencyId]['native_amount'] = bcadd($return[$currencyId]['native_amount'], $nativeAmount);
} }
$converter->summarize();
return $return; return $return;
} }

View File

@@ -193,6 +193,7 @@ class AccountBalanceGrouped
$convertedKey = sprintf('native_%s', $key); $convertedKey = sprintf('native_%s', $key);
$this->data[$currencyId][$period][$convertedKey] = bcadd($this->data[$currencyId][$period][$convertedKey], $amountConverted); $this->data[$currencyId][$period][$convertedKey] = bcadd($this->data[$currencyId][$period][$convertedKey], $amountConverted);
} }
$converter->summarize();
} }
public function setAccounts(Collection $accounts): void public function setAccounts(Collection $accounts): void

View File

@@ -37,6 +37,8 @@ use Illuminate\Support\Facades\Log;
class ExchangeRateConverter class ExchangeRateConverter
{ {
// use ConvertsExchangeRates; // use ConvertsExchangeRates;
private int $queryCount = 0;
private array $prepared = [];
/** /**
* @throws FireflyException * @throws FireflyException
@@ -48,6 +50,56 @@ class ExchangeRateConverter
return bcmul($amount, $rate); return bcmul($amount, $rate);
} }
public function prepare(TransactionCurrency $from, TransactionCurrency $to, Carbon $start, Carbon $end): void
{
$start->startOfDay();
$end->endOfDay();
Log::debug(sprintf('Preparing for %s to %s between %s and %s', $from->code, $to->code, $start->format('Y-m-d'), $end->format('Y-m-d')));
$set = auth()->user()
->currencyExchangeRates()
->where('from_currency_id', $from->id)
->where('to_currency_id', $to->id)
->where('date', '<=', $end->format('Y-m-d'))
->where('date', '>=', $start->format('Y-m-d'))
->orderBy('date', 'DESC')->get()
;
$fallback = $this->getRate($from, $to, $start);
++$this->queryCount;
if (0 === $set->count()) {
Log::debug('No rates found in this period.');
return;
}
/*
* Je moet een fallback rate hebben van voor de periode zodat je die altijd kan gebruiken.
* Dus de laatste met de meest recente datum voor je periode.
* Dan moet je gaan loopen per dag, en als er iets in $temp zit toevallig gebruik je die.
*/
$temp = [];
$count = 0;
foreach ($set as $rate) {
$date = $rate->date->format('Y-m-d');
$temp[$date] ??= [
$from->id => [
$to->id => $rate->rate,
],
];
++$count;
}
Log::debug(sprintf('Found %d rates in this period.', $count));
$currentStart = clone $start;
while ($currentStart->lte($end)) {
$currentDate = $currentStart->format('Y-m-d');
$this->prepared[$currentDate] ??= [];
$fallback = $temp[$currentDate][$from->id][$to->id] ?? $fallback;
if (0 === count($this->prepared[$currentDate])) {
// fill from temp or fallback or from temp (see before)
$this->prepared[$currentDate][$from->id][$to->id] = $fallback;
}
$currentStart->addDay();
}
}
/** /**
* @throws FireflyException * @throws FireflyException
*/ */
@@ -58,6 +110,11 @@ class ExchangeRateConverter
return '0' === $rate ? '1' : $rate; return '0' === $rate ? '1' : $rate;
} }
public function summarize(): void
{
Log::info(sprintf('ExchangeRateConverter ran %d queries.', $this->queryCount));
}
/** /**
* @throws FireflyException * @throws FireflyException
*/ */
@@ -94,6 +151,12 @@ class ExchangeRateConverter
{ {
$key = sprintf('cer-%d-%d-%s', $from, $to, $date); $key = sprintf('cer-%d-%d-%s', $from, $to, $date);
// perhaps the rate has been cached during this particular run
$preparedRate = $this->prepared[$date][$from][$to] ?? null;
if (null !== $preparedRate) {
return $preparedRate;
}
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($key); $cache->addProperty($key);
if ($cache->has()) { if ($cache->has()) {
@@ -115,8 +178,23 @@ class ExchangeRateConverter
->orderBy('date', 'DESC') ->orderBy('date', 'DESC')
->first() ->first()
; ;
$rate = (string) $result?->rate; ++$this->queryCount;
$rate = (string) $result?->rate;
$cache->store($rate); $cache->store($rate);
// if the rate has not been cached during this particular run, save it
$this->prepared[$date] ??= [
$from => [
$to => $rate,
],
];
// also save the exchange rate the other way around:
$this->prepared[$date] ??= [
$to => [
$from => bcdiv('1', $rate),
],
];
if ('' === $rate) { if ('' === $rate) {
return null; return null;
} }
@@ -168,6 +246,7 @@ class ExchangeRateConverter
return (int) $cache->get(); return (int) $cache->get();
} }
$euro = TransactionCurrency::whereCode('EUR')->first(); $euro = TransactionCurrency::whereCode('EUR')->first();
++$this->queryCount;
if (null === $euro) { if (null === $euro) {
throw new FireflyException('Cannot find EUR in system, cannot do currency conversion.'); throw new FireflyException('Cannot find EUR in system, cannot do currency conversion.');
} }

View File

@@ -79,6 +79,7 @@ class SummaryBalanceGrouped
} }
app('log')->debug(sprintf('this->amounts[%s][native] is now %s', $key, $this->amounts[$key]['native'])); app('log')->debug(sprintf('this->amounts[%s][native] is now %s', $key, $this->amounts[$key]['native']));
app('log')->debug(sprintf('this->amounts[%s][native] is now %s', self::SUM, $this->amounts[$key]['native'])); app('log')->debug(sprintf('this->amounts[%s][native] is now %s', self::SUM, $this->amounts[$key]['native']));
$converter->summarize();
} }
public function groupData(): array public function groupData(): array

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Support; namespace FireflyIII\Support;
use Carbon\Carbon; use Carbon\Carbon;
use Exception;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
@@ -47,7 +46,7 @@ class Steam
$repository = app(AccountRepositoryInterface::class); $repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user); $repository->setUser($account->user);
$currencyId = (int)$repository->getMetaValue($account, 'currency_id'); $currencyId = (int) $repository->getMetaValue($account, 'currency_id');
$transactions = $account->transactions() $transactions = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') ->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59')) ->where('transaction_journals.date', '<=', $date->format('Y-m-d 23:59:59'))
@@ -76,7 +75,7 @@ class Steam
/** @var array $transaction */ /** @var array $transaction */
foreach ($transactions as $transaction) { foreach ($transactions as $transaction) {
$value = (string)($transaction[$key] ?? '0'); $value = (string) ($transaction[$key] ?? '0');
$value = '' === $value ? '0' : $value; $value = '' === $value ? '0' : $value;
$sum = bcadd($sum, $value); $sum = bcadd($sum, $value);
} }
@@ -146,18 +145,18 @@ class Steam
/** @var Transaction $entry */ /** @var Transaction $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
// normal amount and foreign amount // normal amount and foreign amount
$modified = (string)(null === $entry->modified ? '0' : $entry->modified); $modified = (string) (null === $entry->modified ? '0' : $entry->modified);
$foreignModified = (string)(null === $entry->modified_foreign ? '0' : $entry->modified_foreign); $foreignModified = (string) (null === $entry->modified_foreign ? '0' : $entry->modified_foreign);
$amount = '0'; $amount = '0';
if ($currencyId === (int)$entry->transaction_currency_id || 0 === $currencyId) { if ($currencyId === (int) $entry->transaction_currency_id || 0 === $currencyId) {
// use normal amount: // use normal amount:
$amount = $modified; $amount = $modified;
} }
if ($currencyId === (int)$entry->foreign_currency_id) { if ($currencyId === (int) $entry->foreign_currency_id) {
// use foreign amount: // use foreign amount:
$amount = $foreignModified; $amount = $foreignModified;
} }
Log::debug(sprintf('Trying to add %s and %s.', var_export($currentBalance, true), var_export($amount, true))); // Log::debug(sprintf('Trying to add %s and %s.', var_export($currentBalance, true), var_export($amount, true)));
$currentBalance = bcadd($currentBalance, $amount); $currentBalance = bcadd($currentBalance, $amount);
$carbon = new Carbon($entry->date, config('app.timezone')); $carbon = new Carbon($entry->date, config('app.timezone'));
$date = $carbon->format('Y-m-d'); $date = $carbon->format('Y-m-d');
@@ -276,7 +275,7 @@ class Steam
} }
$format = $day->format('Y-m-d'); $format = $day->format('Y-m-d');
// if the transaction is in the expected currency, change nothing. // if the transaction is in the expected currency, change nothing.
if ((int)$transaction['transaction_currency_id'] === $native->id) { if ((int) $transaction['transaction_currency_id'] === $native->id) {
// change the current balance, set it to today, continue the loop. // change the current balance, set it to today, continue the loop.
$currentBalance = bcadd($currentBalance, $transaction['amount']); $currentBalance = bcadd($currentBalance, $transaction['amount']);
$balances[$format] = $currentBalance; $balances[$format] = $currentBalance;
@@ -285,7 +284,7 @@ class Steam
continue; continue;
} }
// if foreign currency is in the expected currency, do nothing: // if foreign currency is in the expected currency, do nothing:
if ((int)$transaction['foreign_currency_id'] === $native->id) { if ((int) $transaction['foreign_currency_id'] === $native->id) {
$currentBalance = bcadd($currentBalance, $transaction['foreign_amount']); $currentBalance = bcadd($currentBalance, $transaction['foreign_amount']);
$balances[$format] = $currentBalance; $balances[$format] = $currentBalance;
app('log')->debug(sprintf('%s: transaction in %s (foreign), new balance is %s.', $format, $native->code, $currentBalance)); app('log')->debug(sprintf('%s: transaction in %s (foreign), new balance is %s.', $format, $native->code, $currentBalance));
@@ -293,7 +292,7 @@ class Steam
continue; continue;
} }
// otherwise, convert 'amount' to the necessary currency: // otherwise, convert 'amount' to the necessary currency:
$currencyId = (int)$transaction['transaction_currency_id']; $currencyId = (int) $transaction['transaction_currency_id'];
$currency = $currencies[$currencyId] ?? TransactionCurrency::find($currencyId); $currency = $currencies[$currencyId] ?? TransactionCurrency::find($currencyId);
$currencies[$currencyId] = $currency; $currencies[$currencyId] = $currency;
@@ -315,6 +314,7 @@ class Steam
} }
$cache->store($balances); $cache->store($balances);
$converter->summarize();
return $balances; return $balances;
} }
@@ -327,15 +327,15 @@ class Steam
*/ */
public function balanceConverted(Account $account, Carbon $date, TransactionCurrency $native): string public function balanceConverted(Account $account, Carbon $date, TransactionCurrency $native): string
{ {
app('log')->debug(sprintf('Now in balanceConverted (%s) for account #%d, converting to %s', $date->format('Y-m-d'), $account->id, $native->code)); // app('log')->debug(sprintf('Now in balanceConverted (%s) for account #%d, converting to %s', $date->format('Y-m-d'), $account->id, $native->code));
// abuse chart properties:
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($account->id); $cache->addProperty($account->id);
$cache->addProperty('balance'); $cache->addProperty('balance');
$cache->addProperty($date); $cache->addProperty($date);
$cache->addProperty($native->id); $cache->addProperty($native->id);
if ($cache->has()) { if ($cache->has()) {
return $cache->get(); // Log::debug('Cached!');
// return $cache->get();
} }
/** @var AccountRepositoryInterface $repository */ /** @var AccountRepositoryInterface $repository */
@@ -343,6 +343,7 @@ class Steam
$currency = $repository->getAccountCurrency($account); $currency = $repository->getAccountCurrency($account);
$currency = null === $currency ? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup) : $currency; $currency = null === $currency ? app('amount')->getDefaultCurrencyByUserGroup($account->user->userGroup) : $currency;
if ($native->id === $currency->id) { if ($native->id === $currency->id) {
// Log::debug('No conversion necessary!');
return $this->balance($account, $date); return $this->balance($account, $date);
} }
@@ -424,34 +425,43 @@ class Steam
// need to convert the others. All sets use the "amount" value as their base (that's easy) // need to convert the others. All sets use the "amount" value as their base (that's easy)
// but we need to convert each transaction separately because the date difference may // but we need to convert each transaction separately because the date difference may
// incur huge currency changes. // incur huge currency changes.
$start = clone $date;
$end = clone $date;
$converter = new ExchangeRateConverter(); $converter = new ExchangeRateConverter();
foreach ($new as $set) { foreach ($new as $set) {
foreach ($set as $transaction) { foreach ($set as $transaction) {
$date = Carbon::createFromFormat('Y-m-d H:i:s', $transaction['date']); $currentDate = Carbon::createFromFormat('Y-m-d H:i:s', $transaction['date']);
if (false === $date) { if (false === $currentDate) {
$date = today(config('app.timezone')); $currentDate = today(config('app.timezone'));
} }
$rate = $converter->getCurrencyRate($currency, $native, $date); if ($currentDate->lte($start)) {
$start = clone $currentDate;
}
}
}
unset($currentDate);
$converter->prepare($currency, $native, $start, $end);
foreach ($new as $set) {
foreach ($set as $transaction) {
$currentDate = Carbon::createFromFormat('Y-m-d H:i:s', $transaction['date']);
if (false === $currentDate) {
$currentDate = today(config('app.timezone'));
}
$rate = $converter->getCurrencyRate($currency, $native, $currentDate);
$convertedAmount = bcmul($transaction['amount'], $rate); $convertedAmount = bcmul($transaction['amount'], $rate);
$balance = bcadd($balance, $convertedAmount); $balance = bcadd($balance, $convertedAmount);
// app('log')->debug(sprintf('Date: %s, rate: %s, amount: %s %s, new: %s %s',
// $date->format('Y-m-d'),
// $rate,
// $currency->code,
// $transaction['amount'],
// $native->code,
// $convertedAmount
// ));
} }
// app('log')->debug(sprintf('Balance from new set #%d is %f', $index, $balance));
} }
// add virtual balance (also needs conversion) // add virtual balance (also needs conversion)
$virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance; $virtual = null === $account->virtual_balance ? '0' : $account->virtual_balance;
$virtual = $converter->convert($currency, $native, $account->created_at, $virtual); $virtual = $converter->convert($currency, $native, $account->created_at, $virtual);
$balance = bcadd($balance, $virtual); $balance = bcadd($balance, $virtual);
$converter->summarize();
$cache->store($balance); $cache->store($balance);
$converter->summarize();
return $balance; return $balance;
} }
@@ -565,11 +575,11 @@ class Steam
->groupBy('transactions.transaction_currency_id') ->groupBy('transactions.transaction_currency_id')
; ;
$balances = $query->get(['transactions.transaction_currency_id', \DB::raw('SUM(transactions.amount) as sum_for_currency')]); // @phpstan-ignore-line $balances = $query->get(['transactions.transaction_currency_id', \DB::raw('SUM(transactions.amount) as sum_for_currency')]); // @phpstan-ignore-line
$return = []; $return = [];
/** @var \stdClass $entry */ /** @var \stdClass $entry */
foreach ($balances as $entry) { foreach ($balances as $entry) {
$return[(int)$entry->transaction_currency_id] = (string)$entry->sum_for_currency; $return[(int) $entry->transaction_currency_id] = (string) $entry->sum_for_currency;
} }
$cache->store($return); $cache->store($return);
@@ -672,7 +682,7 @@ class Steam
throw new FireflyException($e->getMessage(), 0, $e); throw new FireflyException($e->getMessage(), 0, $e);
} }
return (string)$hostName; return (string) $hostName;
} }
public function getLastActivities(array $accounts): array public function getLastActivities(array $accounts): array
@@ -707,7 +717,7 @@ class Steam
if ('equal' === $locale) { if ('equal' === $locale) {
$locale = $this->getLanguage(); $locale = $this->getLanguage();
} }
$locale = (string)$locale; $locale = (string) $locale;
// Check for Windows to replace the locale correctly. // Check for Windows to replace the locale correctly.
if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) { if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) {
@@ -808,20 +818,20 @@ class Steam
return $value; return $value;
} }
$number = substr($value, 0, (int)strpos($value, 'E')); $number = substr($value, 0, (int) strpos($value, 'E'));
if (str_contains($number, '.')) { if (str_contains($number, '.')) {
$post = strlen(substr($number, (int)strpos($number, '.') + 1)); $post = strlen(substr($number, (int) strpos($number, '.') + 1));
$mantis = substr($value, (int)strpos($value, 'E') + 1); $mantis = substr($value, (int) strpos($value, 'E') + 1);
if ($mantis < 0) { if ($mantis < 0) {
$post += abs((int)$mantis); $post += abs((int) $mantis);
} }
// TODO careless float could break financial math. // TODO careless float could break financial math.
return number_format((float)$value, $post, '.', ''); return number_format((float) $value, $post, '.', '');
} }
// TODO careless float could break financial math. // TODO careless float could break financial math.
return number_format((float)$value, 0, '.', ''); return number_format((float) $value, 0, '.', '');
} }
public function opposite(string $amount = null): ?string public function opposite(string $amount = null): ?string
@@ -841,24 +851,24 @@ class Steam
// has a K in it, remove the K and multiply by 1024. // has a K in it, remove the K and multiply by 1024.
$bytes = bcmul(rtrim($string, 'k'), '1024'); $bytes = bcmul(rtrim($string, 'k'), '1024');
return (int)$bytes; return (int) $bytes;
} }
if (false !== stripos($string, 'm')) { if (false !== stripos($string, 'm')) {
// has a M in it, remove the M and multiply by 1048576. // has a M in it, remove the M and multiply by 1048576.
$bytes = bcmul(rtrim($string, 'm'), '1048576'); $bytes = bcmul(rtrim($string, 'm'), '1048576');
return (int)$bytes; return (int) $bytes;
} }
if (false !== stripos($string, 'g')) { if (false !== stripos($string, 'g')) {
// has a G in it, remove the G and multiply by (1024)^3. // has a G in it, remove the G and multiply by (1024)^3.
$bytes = bcmul(rtrim($string, 'g'), '1073741824'); $bytes = bcmul(rtrim($string, 'g'), '1073741824');
return (int)$bytes; return (int) $bytes;
} }
return (int)$string; return (int) $string;
} }
public function positive(string $amount): string public function positive(string $amount): string

View File

@@ -192,6 +192,7 @@ class BillTransformer extends AbstractTransformer
$date = null === $startParam ? today() : clone $startParam; $date = null === $startParam ? today() : clone $startParam;
$nextExpectedMatchDiff = $this->getNextExpectedMatchDiff($nextExpectedMatch, $payDates); $nextExpectedMatchDiff = $this->getNextExpectedMatchDiff($nextExpectedMatch, $payDates);
$this->converter->summarize();
return [ return [
'id' => $bill->id, 'id' => $bill->id,

View File

@@ -193,6 +193,7 @@ class PiggyBankTransformer extends AbstractTransformer
$savePerMonth = $this->getSuggestedMonthlyAmount($currentAmount, $targetAmount, $piggyBank->startdate, $piggyBank->targetdate); $savePerMonth = $this->getSuggestedMonthlyAmount($currentAmount, $targetAmount, $piggyBank->startdate, $piggyBank->targetdate);
$nativeSavePerMonth = $this->converter->convert($this->default, $currency, today(), $savePerMonth); $nativeSavePerMonth = $this->converter->convert($this->default, $currency, today(), $savePerMonth);
} }
$this->converter->summarize();
return [ return [
'id' => (string)$piggyBank->id, 'id' => (string)$piggyBank->id,

View File

@@ -161,6 +161,7 @@ class TransactionGroupTransformer extends AbstractTransformer
$foreignAmount = app('steam')->positive($transaction['foreign_amount']); $foreignAmount = app('steam')->positive($transaction['foreign_amount']);
$nativeForeignAmount = $this->converter->convert($this->default, $this->currencies[$foreignCurrencyId], $transaction['date'], $foreignAmount); $nativeForeignAmount = $this->converter->convert($this->default, $this->currencies[$foreignCurrencyId], $transaction['date'], $foreignAmount);
} }
$this->converter->summarize();
return [ return [
'user' => (string)$transaction['user_id'], 'user' => (string)$transaction['user_id'],