mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-12 23:45:10 +00:00
Optimize balance collection.
This commit is contained in:
@@ -118,7 +118,7 @@ class AccountController extends Controller
|
|||||||
Log::debug(sprintf('expenseAccounts: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
|
Log::debug(sprintf('expenseAccounts: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
|
||||||
$startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
|
$startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
|
||||||
$endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
|
$endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
|
||||||
|
Log::debug('Done collecting balances');
|
||||||
// loop the accounts, then check for balance and currency info.
|
// loop the accounts, then check for balance and currency info.
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
// Log::debug(sprintf('[a] Now in account #%d ("%s")', $account->id, $account->name));
|
// Log::debug(sprintf('[a] Now in account #%d ("%s")', $account->id, $account->name));
|
||||||
|
@@ -38,7 +38,6 @@ use Illuminate\Support\Facades\DB;
|
|||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use ValueError;
|
use ValueError;
|
||||||
|
|
||||||
use function Safe\parse_url;
|
use function Safe\parse_url;
|
||||||
use function Safe\preg_replace;
|
use function Safe\preg_replace;
|
||||||
|
|
||||||
@@ -66,10 +65,10 @@ class Steam
|
|||||||
// Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision));
|
// Log::debug(sprintf('Trying bcround("%s",%d)', $number, $precision));
|
||||||
if (str_contains($number, '.')) {
|
if (str_contains($number, '.')) {
|
||||||
if ('-' !== $number[0]) {
|
if ('-' !== $number[0]) {
|
||||||
return bcadd($number, '0.'.str_repeat('0', $precision).'5', $precision);
|
return bcadd($number, '0.' . str_repeat('0', $precision) . '5', $precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bcsub($number, '0.'.str_repeat('0', $precision).'5', $precision);
|
return bcsub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $number;
|
return $number;
|
||||||
@@ -266,8 +265,7 @@ class Steam
|
|||||||
'transactions.transaction_currency_id',
|
'transactions.transaction_currency_id',
|
||||||
DB::raw('SUM(transactions.amount) AS sum_of_day'),
|
DB::raw('SUM(transactions.amount) AS sum_of_day'),
|
||||||
]
|
]
|
||||||
)
|
);
|
||||||
;
|
|
||||||
|
|
||||||
$currentBalance = $startBalance;
|
$currentBalance = $startBalance;
|
||||||
$converter = new ExchangeRateConverter();
|
$converter = new ExchangeRateConverter();
|
||||||
@@ -322,45 +320,52 @@ class Steam
|
|||||||
|
|
||||||
public function accountsBalancesOptimized(Collection $accounts, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array
|
public function accountsBalancesOptimized(Collection $accounts, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array
|
||||||
{
|
{
|
||||||
Log::debug(sprintf('accountsBalancesOptimized: Called with date/time "%s"', $date->toIso8601String()));
|
Log::debug(sprintf('accountsBalancesOptimized: Called for %d account(s) with date/time "%s"', $accounts->count(), $date->toIso8601String()));
|
||||||
$result = [];
|
$result = [];
|
||||||
$convertToPrimary ??= Amount::convertToPrimary();
|
$convertToPrimary ??= Amount::convertToPrimary();
|
||||||
$primary ??= Amount::getPrimaryCurrency();
|
$primary ??= Amount::getPrimaryCurrency();
|
||||||
$currencies = $this->getCurrencies($accounts);
|
$currencies = $this->getCurrencies($accounts);
|
||||||
|
|
||||||
// balance(s) in all currencies for ALL accounts.
|
// balance(s) in all currencies for ALL accounts.
|
||||||
$array = Transaction::whereIn('account_id', $accounts->pluck('id')->toArray())
|
$arrayOfSums = Transaction::whereIn('account_id', $accounts->pluck('id')->toArray())
|
||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
|
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
|
||||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
||||||
->get(['transactions.account_id', 'transaction_currencies.code', 'transactions.amount'])->toArray()
|
->groupBy(['transactions.account_id', 'transaction_currencies.code'])
|
||||||
;
|
->get(['transactions.account_id', 'transaction_currencies.code', DB::raw('SUM(transactions.amount) as sum_of_amount')])->toArray();
|
||||||
|
|
||||||
/** @var Account $account */
|
/** @var Account $account */
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
// filter array back to this account:
|
|
||||||
$filtered = array_filter($array, function ($item) use ($account) {
|
|
||||||
return (int)$item['account_id'] === $account->id;
|
|
||||||
});
|
|
||||||
$currency = $currencies[$account->id];
|
|
||||||
// this array is PER account, so we wait a bit before we change code here.
|
// this array is PER account, so we wait a bit before we change code here.
|
||||||
$return = [
|
$return = [
|
||||||
'pc_balance' => '0',
|
'pc_balance' => '0',
|
||||||
'balance' => '0', // this key is overwritten right away, but I must remember it is always created.
|
'balance' => '0', // this key is overwritten right away, but I must remember it is always created.
|
||||||
];
|
];
|
||||||
|
$currency = $currencies[$account->id];
|
||||||
|
|
||||||
|
// second array
|
||||||
|
$accountSum = array_filter($arrayOfSums, function ($entry) use ($account) {
|
||||||
|
return $entry['account_id'] === $account->id;
|
||||||
|
});
|
||||||
|
if(0 === count($accountSum)) {
|
||||||
|
$result[$account->id] = $return;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$accountSum = array_values($accountSum)[0];
|
||||||
|
$sumsByCode = [
|
||||||
|
$accountSum['code'] => $accountSum['sum_of_amount'],
|
||||||
|
];
|
||||||
|
|
||||||
// balance(s) in all currencies.
|
|
||||||
$others = $this->groupAndSumTransactions($filtered, '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 "pc_balance".
|
// if there is no request to convert, take this as "balance" and "pc_balance".
|
||||||
$return['balance'] = $others[$currency->code] ?? '0';
|
$return['balance'] = $sumsByCode[$currency->code] ?? '0';
|
||||||
if (!$convertToPrimary) {
|
if (!$convertToPrimary) {
|
||||||
unset($return['pc_balance']);
|
unset($return['pc_balance']);
|
||||||
// Log::debug(sprintf('Set balance to %s, unset pc_balance', $return['balance']));
|
// Log::debug(sprintf('Set balance to %s, unset pc_balance', $return['balance']));
|
||||||
}
|
}
|
||||||
// if there is a request to convert, convert to "pc_balance" and use "balance" for whichever amount is in the primary currency.
|
// if there is a request to convert, convert to "pc_balance" and use "balance" for whichever amount is in the primary currency.
|
||||||
if ($convertToPrimary) {
|
if ($convertToPrimary) {
|
||||||
$return['pc_balance'] = $this->convertAllBalances($others, $primary, $date); // todo sum all and convert.
|
$return['pc_balance'] = $this->convertAllBalances($sumsByCode, $primary, $date);
|
||||||
// Log::debug(sprintf('Set pc_balance to %s', $return['pc_balance']));
|
// Log::debug(sprintf('Set pc_balance to %s', $return['pc_balance']));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,7 +384,7 @@ class Steam
|
|||||||
$return['balance'] = bcadd($return['balance'], $virtualBalance);
|
$return['balance'] = bcadd($return['balance'], $virtualBalance);
|
||||||
// Log::debug(sprintf('Virtual balance makes the (primary currency) total %s', $return['balance']));
|
// Log::debug(sprintf('Virtual balance makes the (primary currency) total %s', $return['balance']));
|
||||||
}
|
}
|
||||||
$final = array_merge($return, $others);
|
$final = array_merge($return, $sumsByCode);
|
||||||
$result[$account->id] = $final;
|
$result[$account->id] = $final;
|
||||||
// Log::debug('Final balance is', $final);
|
// Log::debug('Final balance is', $final);
|
||||||
}
|
}
|
||||||
@@ -438,8 +443,7 @@ class Steam
|
|||||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||||
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
|
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
|
||||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
||||||
->get(['transaction_currencies.code', 'transactions.amount'])->toArray()
|
->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);
|
// Log::debug('All balances are (joined)', $others);
|
||||||
// if there is no request to convert, take this as "balance" and "pc_balance".
|
// if there is no request to convert, take this as "balance" and "pc_balance".
|
||||||
|
Reference in New Issue
Block a user