🤖 Auto commit for release 'develop' on 2025-08-07

This commit is contained in:
JC5
2025-08-07 06:05:41 +02:00
parent 4c7789a668
commit af46729372
10 changed files with 140 additions and 133 deletions

View File

@@ -76,7 +76,7 @@ class StoreController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new RecurringEnrichment(); $enrichment = new RecurringEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$recurrence = $enrichment->enrichSingle($recurrence); $recurrence = $enrichment->enrichSingle($recurrence);
/** @var RecurrenceTransformer $transformer */ /** @var RecurrenceTransformer $transformer */
$transformer = app(RecurrenceTransformer::class); $transformer = app(RecurrenceTransformer::class);

View File

@@ -74,7 +74,7 @@ class UpdateController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new RecurringEnrichment(); $enrichment = new RecurringEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$recurrence = $enrichment->enrichSingle($recurrence); $recurrence = $enrichment->enrichSingle($recurrence);
/** @var RecurrenceTransformer $transformer */ /** @var RecurrenceTransformer $transformer */
$transformer = app(RecurrenceTransformer::class); $transformer = app(RecurrenceTransformer::class);

View File

@@ -277,14 +277,14 @@ class ListController extends Controller
} }
); );
$count = $collection->count(); $count = $collection->count();
$recurrences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $recurrences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// enrich // enrich
/** @var User $admin */ /** @var User $admin */
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new RecurringEnrichment(); $enrichment = new RecurringEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$recurrences = $enrichment->enrich($recurrences); $recurrences = $enrichment->enrich($recurrences);
// make paginator: // make paginator:
$paginator = new LengthAwarePaginator($recurrences, $count, $pageSize, $this->parameters->get('page')); $paginator = new LengthAwarePaginator($recurrences, $count, $pageSize, $this->parameters->get('page'));

View File

@@ -96,10 +96,10 @@ class EditController extends Controller
// enrich // enrich
/** @var User $admin */ /** @var User $admin */
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new RecurringEnrichment(); $enrichment = new RecurringEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$recurrence = $enrichment->enrichSingle($recurrence); $recurrence = $enrichment->enrichSingle($recurrence);
/** @var RecurrenceTransformer $transformer */ /** @var RecurrenceTransformer $transformer */
$transformer = app(RecurrenceTransformer::class); $transformer = app(RecurrenceTransformer::class);

View File

@@ -84,10 +84,10 @@ class ShowController extends Controller
// enrich // enrich
/** @var User $admin */ /** @var User $admin */
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new RecurringEnrichment(); $enrichment = new RecurringEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$recurrence = $enrichment->enrichSingle($recurrence); $recurrence = $enrichment->enrichSingle($recurrence);
/** @var RecurrenceTransformer $transformer */ /** @var RecurrenceTransformer $transformer */
$transformer = app(RecurrenceTransformer::class); $transformer = app(RecurrenceTransformer::class);

View File

@@ -82,7 +82,7 @@ class PiggyBankEnrichment implements EnrichmentInterface
$this->ids[] = $id; $this->ids[] = $id;
$this->currencyIds[$id] = (int)$piggy->transaction_currency_id; $this->currencyIds[$id] = (int)$piggy->transaction_currency_id;
} }
$this->ids = array_unique($this->ids); $this->ids = array_unique($this->ids);
// collect currencies. // collect currencies.
$currencies = TransactionCurrency::whereIn('id', $this->currencyIds)->get(); $currencies = TransactionCurrency::whereIn('id', $this->currencyIds)->get();
@@ -91,10 +91,10 @@ class PiggyBankEnrichment implements EnrichmentInterface
} }
// collect accounts // collect accounts
$set = DB::table('account_piggy_bank')->whereIn('piggy_bank_id', $this->ids)->get(['piggy_bank_id', 'account_id', 'current_amount', 'native_current_amount']); $set = DB::table('account_piggy_bank')->whereIn('piggy_bank_id', $this->ids)->get(['piggy_bank_id', 'account_id', 'current_amount', 'native_current_amount']);
foreach ($set as $item) { foreach ($set as $item) {
$id = (int)$item->piggy_bank_id; $id = (int)$item->piggy_bank_id;
$accountId = (int)$item->account_id; $accountId = (int)$item->account_id;
$this->amounts[$id] ??= []; $this->amounts[$id] ??= [];
if (!array_key_exists($id, $this->accountIds)) { if (!array_key_exists($id, $this->accountIds)) {
$this->accountIds[$id] = (int)$item->account_id; $this->accountIds[$id] = (int)$item->account_id;
@@ -112,12 +112,12 @@ class PiggyBankEnrichment implements EnrichmentInterface
} }
// get account currency preference for ALL. // get account currency preference for ALL.
$set = AccountMeta::whereIn('account_id', array_values($this->accountIds))->where('name', 'currency_id')->get(); $set = AccountMeta::whereIn('account_id', array_values($this->accountIds))->where('name', 'currency_id')->get();
/** @var AccountMeta $item */ /** @var AccountMeta $item */
foreach ($set as $item) { foreach ($set as $item) {
$accountId = (int)$item->account_id; $accountId = (int)$item->account_id;
$currencyId = (int)$item->data; $currencyId = (int)$item->data;
if (!array_key_exists($currencyId, $this->currencies)) { if (!array_key_exists($currencyId, $this->currencies)) {
$this->currencies[$currencyId] = TransactionCurrency::find($currencyId); $this->currencies[$currencyId] = TransactionCurrency::find($currencyId);
} }
@@ -125,7 +125,7 @@ class PiggyBankEnrichment implements EnrichmentInterface
} }
// get account info. // get account info.
$set = Account::whereIn('id', array_values($this->accountIds))->get(); $set = Account::whereIn('id', array_values($this->accountIds))->get();
/** @var Account $item */ /** @var Account $item */
foreach ($set as $item) { foreach ($set as $item) {
@@ -140,14 +140,14 @@ class PiggyBankEnrichment implements EnrichmentInterface
private function appendCollectedData(): void private function appendCollectedData(): void
{ {
$this->collection = $this->collection->map(function (PiggyBank $item) { $this->collection = $this->collection->map(function (PiggyBank $item) {
$id = (int)$item->id; $id = (int)$item->id;
$currencyId = (int)$item->transaction_currency_id; $currencyId = (int)$item->transaction_currency_id;
$currency = $this->currencies[$currencyId] ?? $this->primaryCurrency; $currency = $this->currencies[$currencyId] ?? $this->primaryCurrency;
$targetAmount = null; $targetAmount = null;
if (0 !== bccomp($item->target_amount, '0')) { if (0 !== bccomp($item->target_amount, '0')) {
$targetAmount = $item->target_amount; $targetAmount = $item->target_amount;
} }
$meta = [ $meta = [
'notes' => $this->notes[$id] ?? null, 'notes' => $this->notes[$id] ?? null,
'currency' => $this->currencies[$currencyId] ?? null, 'currency' => $this->currencies[$currencyId] ?? null,
// 'auto_budget' => $this->autoBudgets[$id] ?? null, // 'auto_budget' => $this->autoBudgets[$id] ?? null,
@@ -176,17 +176,17 @@ class PiggyBankEnrichment implements EnrichmentInterface
} }
// add current amount(s). // add current amount(s).
foreach ($this->amounts[$id] as $accountId => $row) { foreach ($this->amounts[$id] as $accountId => $row) {
$meta['accounts'][] = [ $meta['accounts'][] = [
'account_id' => (string)$accountId, 'account_id' => (string)$accountId,
'name' => $this->accounts[$accountId]['name'] ?? '', 'name' => $this->accounts[$accountId]['name'] ?? '',
'current_amount' => Steam::bcround($row['current_amount'], $currency->decimal_places), 'current_amount' => Steam::bcround($row['current_amount'], $currency->decimal_places),
'pc_current_amount' => Steam::bcround($row['pc_current_amount'], $this->primaryCurrency->decimal_places), 'pc_current_amount' => Steam::bcround($row['pc_current_amount'], $this->primaryCurrency->decimal_places),
]; ];
$meta['current_amount'] = bcadd($meta['current_amount'], $row['current_amount']); $meta['current_amount'] = bcadd($meta['current_amount'], $row['current_amount']);
// only add pc_current_amount when the pc_current_amount is set // only add pc_current_amount when the pc_current_amount is set
$meta['pc_current_amount'] = null === $row['pc_current_amount'] ? null : bcadd($meta['pc_current_amount'], $row['pc_current_amount']); $meta['pc_current_amount'] = null === $row['pc_current_amount'] ? null : bcadd($meta['pc_current_amount'], $row['pc_current_amount']);
} }
$meta['current_amount'] = Steam::bcround($meta['current_amount'], $currency->decimal_places); $meta['current_amount'] = Steam::bcround($meta['current_amount'], $currency->decimal_places);
// only round this number when pc_current_amount is set. // only round this number when pc_current_amount is set.
$meta['pc_current_amount'] = null === $meta['pc_current_amount'] ? null : Steam::bcround($meta['pc_current_amount'], $this->primaryCurrency->decimal_places); $meta['pc_current_amount'] = null === $meta['pc_current_amount'] ? null : Steam::bcround($meta['pc_current_amount'], $this->primaryCurrency->decimal_places);
@@ -200,7 +200,7 @@ class PiggyBankEnrichment implements EnrichmentInterface
$meta['save_per_month'] = Steam::bcround($this->getSuggestedMonthlyAmount($item->start_date, $item->target_date, $meta['target_amount'], $meta['current_amount']), $currency->decimal_places); $meta['save_per_month'] = Steam::bcround($this->getSuggestedMonthlyAmount($item->start_date, $item->target_date, $meta['target_amount'], $meta['current_amount']), $currency->decimal_places);
$meta['pc_save_per_month'] = Steam::bcround($this->getSuggestedMonthlyAmount($item->start_date, $item->target_date, $meta['pc_target_amount'], $meta['pc_current_amount']), $currency->decimal_places); $meta['pc_save_per_month'] = Steam::bcround($this->getSuggestedMonthlyAmount($item->start_date, $item->target_date, $meta['pc_target_amount'], $meta['pc_current_amount']), $currency->decimal_places);
$item->meta = $meta; $item->meta = $meta;
return $item; return $item;
}); });
@@ -209,9 +209,10 @@ class PiggyBankEnrichment implements EnrichmentInterface
private function collectNotes(): void private function collectNotes(): void
{ {
$notes = Note::query()->whereIn('noteable_id', $this->ids) $notes = Note::query()->whereIn('noteable_id', $this->ids)
->whereNotNull('notes.text') ->whereNotNull('notes.text')
->where('notes.text', '!=', '') ->where('notes.text', '!=', '')
->where('noteable_type', PiggyBank::class)->get(['notes.noteable_id', 'notes.text'])->toArray(); ->where('noteable_type', PiggyBank::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
;
foreach ($notes as $note) { foreach ($notes as $note) {
$this->notes[(int)$note['noteable_id']] = (string)$note['text']; $this->notes[(int)$note['noteable_id']] = (string)$note['text'];
} }
@@ -220,12 +221,13 @@ class PiggyBankEnrichment implements EnrichmentInterface
private function collectObjectGroups(): void private function collectObjectGroups(): void
{ {
$set = DB::table('object_groupables') $set = DB::table('object_groupables')
->whereIn('object_groupable_id', $this->ids) ->whereIn('object_groupable_id', $this->ids)
->where('object_groupable_type', PiggyBank::class) ->where('object_groupable_type', PiggyBank::class)
->get(['object_groupable_id', 'object_group_id']); ->get(['object_groupable_id', 'object_group_id'])
;
$ids = array_unique($set->pluck('object_group_id')->toArray()); $ids = array_unique($set->pluck('object_group_id')->toArray());
foreach ($set as $entry) { foreach ($set as $entry) {
$this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id; $this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id;
@@ -239,9 +241,7 @@ class PiggyBankEnrichment implements EnrichmentInterface
} }
} }
private function collectCurrentAmounts(): void private function collectCurrentAmounts(): void {}
{
}
/** /**
* Returns the suggested amount the user should save per month, or "". * Returns the suggested amount the user should save per month, or "".

View File

@@ -37,6 +37,7 @@ 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;
@@ -64,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;
@@ -203,7 +204,7 @@ class Steam
Log::debug(sprintf('finalAccountBalanceInRange(#%d, %s, %s)', $account->id, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); Log::debug(sprintf('finalAccountBalanceInRange(#%d, %s, %s)', $account->id, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// set up cache // set up cache
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($account->id); $cache->addProperty($account->id);
$cache->addProperty('final-balance-in-range'); $cache->addProperty('final-balance-in-range');
$cache->addProperty($start); $cache->addProperty($start);
@@ -213,21 +214,21 @@ class Steam
return $cache->get(); return $cache->get();
} }
$balances = []; $balances = [];
$formatted = $start->format('Y-m-d'); $formatted = $start->format('Y-m-d');
/* /*
* To make sure the start balance is correct, we need to get the balance at the exact end of the previous day. * To make sure the start balance is correct, we need to get the balance at the exact end of the previous day.
* Since we just did "startOfDay" we can do subDay()->endOfDay() to get the correct moment. * Since we just did "startOfDay" we can do subDay()->endOfDay() to get the correct moment.
* THAT will be the start balance. * THAT will be the start balance.
*/ */
$request = clone $start; $request = clone $start;
$request->subDay()->endOfDay(); $request->subDay()->endOfDay();
Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String())); Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String()));
$startBalance = $this->finalAccountBalance($account, $request); $startBalance = $this->finalAccountBalance($account, $request);
$primaryCurrency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); $primaryCurrency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup);
$accountCurrency = $this->getAccountCurrency($account); $accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = $accountCurrency instanceof TransactionCurrency; $hasCurrency = $accountCurrency instanceof TransactionCurrency;
$currency = $accountCurrency ?? $primaryCurrency; $currency = $accountCurrency ?? $primaryCurrency;
Log::debug(sprintf('Currency is %s', $currency->code)); Log::debug(sprintf('Currency is %s', $currency->code));
@@ -240,7 +241,7 @@ class Steam
Log::debug(sprintf('Also set start balance in %s', $primaryCurrency->code)); Log::debug(sprintf('Also set start balance in %s', $primaryCurrency->code));
$startBalance[$primaryCurrency->code] ??= '0'; $startBalance[$primaryCurrency->code] ??= '0';
} }
$currencies = [ $currencies = [
$currency->id => $currency, $currency->id => $currency,
$primaryCurrency->id => $primaryCurrency, $primaryCurrency->id => $primaryCurrency,
]; ];
@@ -250,47 +251,48 @@ class Steam
// sums up the balance changes per day. // sums up the balance changes per day.
Log::debug(sprintf('Date >= %s and <= %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s'))); Log::debug(sprintf('Date >= %s and <= %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$set = $account->transactions() $set = $account->transactions()
->leftJoin('transaction_journals', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->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', '>=', $start->format('Y-m-d H:i:s'))
->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s')) ->where('transaction_journals.date', '<=', $end->format('Y-m-d H:i:s'))
->groupBy('transaction_journals.date') ->groupBy('transaction_journals.date')
->groupBy('transactions.transaction_currency_id') ->groupBy('transactions.transaction_currency_id')
->orderBy('transaction_journals.date', 'ASC') ->orderBy('transaction_journals.date', 'ASC')
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
->get( ->get(
[ // @phpstan-ignore-line [ // @phpstan-ignore-line
'transaction_journals.date', 'transaction_journals.date',
'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();
/** @var Transaction $entry */ /** @var Transaction $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
// get date object // get date object
$carbon = new Carbon($entry->date, $entry->date_tz); $carbon = new Carbon($entry->date, $entry->date_tz);
$carbonKey = $carbon->format('Y-m-d'); $carbonKey = $carbon->format('Y-m-d');
// make sure sum is a string: // make sure sum is a string:
$sumOfDay = (string)($entry->sum_of_day ?? '0'); $sumOfDay = (string)($entry->sum_of_day ?? '0');
// #10426 make sure sum is not in scientific notation. // #10426 make sure sum is not in scientific notation.
$sumOfDay = $this->floatalize($sumOfDay); $sumOfDay = $this->floatalize($sumOfDay);
// find currency of this entry, does not have to exist. // find currency of this entry, does not have to exist.
$currencies[$entry->transaction_currency_id] ??= TransactionCurrency::find($entry->transaction_currency_id); $currencies[$entry->transaction_currency_id] ??= TransactionCurrency::find($entry->transaction_currency_id);
// make sure this $entry has its own $entryCurrency // make sure this $entry has its own $entryCurrency
/** @var TransactionCurrency $entryCurrency */ /** @var TransactionCurrency $entryCurrency */
$entryCurrency = $currencies[$entry->transaction_currency_id]; $entryCurrency = $currencies[$entry->transaction_currency_id];
Log::debug(sprintf('Processing transaction(s) on moment %s', $carbon->format('Y-m-d H:i:s'))); Log::debug(sprintf('Processing transaction(s) on moment %s', $carbon->format('Y-m-d H:i:s')));
// add amount to current balance in currency code. // add amount to current balance in currency code.
$currentBalance[$entryCurrency->code] ??= '0'; $currentBalance[$entryCurrency->code] ??= '0';
$currentBalance[$entryCurrency->code] = bcadd($sumOfDay, (string)$currentBalance[$entryCurrency->code]); $currentBalance[$entryCurrency->code] = bcadd($sumOfDay, (string)$currentBalance[$entryCurrency->code]);
// if not requested to convert to primary currency, add the amount to "balance", do nothing else. // if not requested to convert to primary currency, add the amount to "balance", do nothing else.
@@ -308,7 +310,7 @@ class Steam
} }
} }
// add to final array. // add to final array.
$balances[$carbonKey] = $currentBalance; $balances[$carbonKey] = $currentBalance;
Log::debug(sprintf('Updated entry [%s]', $carbonKey), $currentBalance); Log::debug(sprintf('Updated entry [%s]', $carbonKey), $currentBalance);
} }
$cache->store($balances); $cache->store($balances);
@@ -319,36 +321,37 @@ 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
{ {
$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()) $array = 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(); ->get(['transactions.account_id', 'transaction_currencies.code', 'transactions.amount'])->toArray()
;
/** @var Account $account */ /** @var Account $account */
foreach ($accounts as $account) { foreach ($accounts as $account) {
// filter array back to this account: // filter array back to this account:
$filtered = array_filter($array, function ($item) use ($account) { $filtered = array_filter($array, function ($item) use ($account) {
return (int)$item['account_id'] === $account->id; return (int)$item['account_id'] === $account->id;
}); });
$currency = $currencies[$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.
]; ];
// balance(s) in all currencies. // balance(s) in all currencies.
$others = $this->groupAndSumTransactions($filtered, 'code', 'amount'); $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'] = $others[$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']));
@@ -360,7 +363,7 @@ class Steam
} }
// either way, the balance is always combined with the virtual balance: // either way, the balance is always combined with the virtual balance:
$virtualBalance = (string)('' === (string)$account->virtual_balance ? '0' : $account->virtual_balance); $virtualBalance = (string)('' === (string)$account->virtual_balance ? '0' : $account->virtual_balance);
if ($convertToPrimary) { if ($convertToPrimary) {
// the primary currency balance is combined with a converted virtual_balance: // the primary currency balance is combined with a converted virtual_balance:
@@ -398,7 +401,7 @@ class Steam
public function finalAccountBalance(Account $account, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array public function finalAccountBalance(Account $account, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array
{ {
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($account->id); $cache->addProperty($account->id);
$cache->addProperty($date); $cache->addProperty($date);
if ($cache->has()) { if ($cache->has()) {
@@ -414,7 +417,7 @@ class Steam
$primary = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); $primary = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup);
} }
// account balance thing. // account balance thing.
$currencyPresent = isset($account->meta) && array_key_exists('currency', $account->meta) && null !== $account->meta['currency']; $currencyPresent = isset($account->meta) && array_key_exists('currency', $account->meta) && null !== $account->meta['currency'];
if ($currencyPresent) { if ($currencyPresent) {
$accountCurrency = $account->meta['currency']; $accountCurrency = $account->meta['currency'];
} }
@@ -422,19 +425,20 @@ class Steam
$accountCurrency = $this->getAccountCurrency($account); $accountCurrency = $this->getAccountCurrency($account);
} }
$hasCurrency = null !== $accountCurrency; $hasCurrency = null !== $accountCurrency;
$currency = $hasCurrency ? $accountCurrency : $primary; $currency = $hasCurrency ? $accountCurrency : $primary;
$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.
]; ];
// balance(s) in all currencies. // balance(s) in all currencies.
$array = $account->transactions() $array = $account->transactions()
->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".
$return['balance'] = $others[$currency->code] ?? '0'; $return['balance'] = $others[$currency->code] ?? '0';
@@ -449,7 +453,7 @@ class Steam
} }
// either way, the balance is always combined with the virtual balance: // either way, the balance is always combined with the virtual balance:
$virtualBalance = (string)('' === (string)$account->virtual_balance ? '0' : $account->virtual_balance); $virtualBalance = (string)('' === (string)$account->virtual_balance ? '0' : $account->virtual_balance);
if ($convertToPrimary) { if ($convertToPrimary) {
// the primary currency balance is combined with a converted virtual_balance: // the primary currency balance is combined with a converted virtual_balance:
@@ -463,7 +467,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, $others);
// Log::debug('Final balance is', $final); // Log::debug('Final balance is', $final);
$cache->store($final); $cache->store($final);
@@ -472,8 +476,8 @@ class Steam
public function getAccountCurrency(Account $account): ?TransactionCurrency public function getAccountCurrency(Account $account): ?TransactionCurrency
{ {
$type = $account->accountType->type; $type = $account->accountType->type;
$list = config('firefly.valid_currency_account_types'); $list = config('firefly.valid_currency_account_types');
// return null if not in this list. // return null if not in this list.
if (!in_array($type, $list, true)) { if (!in_array($type, $list, true)) {
@@ -508,9 +512,9 @@ class Steam
if (null === $currency) { if (null === $currency) {
continue; continue;
} }
$current = $converter->convert($currency, $primary, $date, $amount); $current = $converter->convert($currency, $primary, $date, $amount);
Log::debug(sprintf('Convert %s %s to %s %s', $currency->code, $amount, $primary->code, $current)); Log::debug(sprintf('Convert %s %s to %s %s', $currency->code, $amount, $primary->code, $current));
$total = bcadd($current, $total); $total = bcadd($current, $total);
} }
return $total; return $total;
@@ -552,15 +556,15 @@ class Steam
{ {
$list = []; $list = [];
$set = auth()->user()->transactions() $set = auth()->user()->transactions()
->whereIn('transactions.account_id', $accounts) ->whereIn('transactions.account_id', $accounts)
->groupBy(['transactions.account_id', 'transaction_journals.user_id']) ->groupBy(['transactions.account_id', 'transaction_journals.user_id'])
->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line ->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) AS max_date')]) // @phpstan-ignore-line
; ;
/** @var Transaction $entry */ /** @var Transaction $entry */
foreach ($set as $entry) { foreach ($set as $entry) {
$date = new Carbon($entry->max_date, config('app.timezone')); $date = new Carbon($entry->max_date, config('app.timezone'));
$date->setTimezone(config('app.timezone')); $date->setTimezone(config('app.timezone'));
$list[(int)$entry->account_id] = $date; $list[(int)$entry->account_id] = $date;
} }
@@ -635,9 +639,9 @@ class Steam
public function getSafeUrl(string $unknownUrl, string $safeUrl): string public function getSafeUrl(string $unknownUrl, string $safeUrl): string
{ {
// Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl)); // Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl));
$returnUrl = $safeUrl; $returnUrl = $safeUrl;
$unknownHost = parse_url($unknownUrl, PHP_URL_HOST); $unknownHost = parse_url($unknownUrl, PHP_URL_HOST);
$safeHost = parse_url($safeUrl, PHP_URL_HOST); $safeHost = parse_url($safeUrl, PHP_URL_HOST);
if (null !== $unknownHost && $unknownHost === $safeHost) { if (null !== $unknownHost && $unknownHost === $safeHost) {
$returnUrl = $unknownUrl; $returnUrl = $unknownUrl;
@@ -674,7 +678,7 @@ class Steam
*/ */
public function floatalize(string $value): string public function floatalize(string $value): string
{ {
$value = strtoupper($value); $value = strtoupper($value);
if (!str_contains($value, 'E')) { if (!str_contains($value, 'E')) {
return $value; return $value;
} }
@@ -761,8 +765,8 @@ class Steam
$primary = Amount::getPrimaryCurrency(); $primary = Amount::getPrimaryCurrency();
$currencies[$primary->id] = $primary; $currencies[$primary->id] = $primary;
$ids = $accounts->pluck('id')->toArray(); $ids = $accounts->pluck('id')->toArray();
$result = AccountMeta::whereIn('account_id', $ids)->where('name', 'currency_id')->get(); $result = AccountMeta::whereIn('account_id', $ids)->where('name', 'currency_id')->get();
/** @var AccountMeta $item */ /** @var AccountMeta $item */
foreach ($result as $item) { foreach ($result as $item) {
@@ -772,7 +776,7 @@ class Steam
} }
} }
// collect those currencies, skip primary because we already have it. // collect those currencies, skip primary because we already have it.
$set = TransactionCurrency::whereIn('id', $accountPreferences)->where('id','!=',$primary->id)->get(); $set = TransactionCurrency::whereIn('id', $accountPreferences)->where('id', '!=', $primary->id)->get();
foreach ($set as $item) { foreach ($set as $item) {
$currencies[$item->id] = $item; $currencies[$item->id] = $item;
} }
@@ -783,7 +787,7 @@ class Steam
$currencyPresent = isset($account->meta) && array_key_exists('currency', $account->meta) && null !== $account->meta['currency']; $currencyPresent = isset($account->meta) && array_key_exists('currency', $account->meta) && null !== $account->meta['currency'];
if ($currencyPresent) { if ($currencyPresent) {
$currencyId = $account->meta['currency']->id; $currencyId = $account->meta['currency']->id;
$currencies[$currencyId] ??= $account->meta['currency']; $currencies[$currencyId] ??= $account->meta['currency'];
$accountCurrencies[$accountId] = $account->meta['currency']; $accountCurrencies[$accountId] = $account->meta['currency'];
} }
if (!$currencyPresent && !array_key_exists($accountId, $accountPreferences)) { if (!$currencyPresent && !array_key_exists($accountId, $accountPreferences)) {

21
composer.lock generated
View File

@@ -3878,29 +3878,29 @@
}, },
{ {
"name": "nette/utils", "name": "nette/utils",
"version": "v4.0.7", "version": "v4.0.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nette/utils.git", "url": "https://github.com/nette/utils.git",
"reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2" "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2", "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede",
"reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2", "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "8.0 - 8.4" "php": "8.0 - 8.5"
}, },
"conflict": { "conflict": {
"nette/finder": "<3", "nette/finder": "<3",
"nette/schema": "<1.2.2" "nette/schema": "<1.2.2"
}, },
"require-dev": { "require-dev": {
"jetbrains/phpstorm-attributes": "dev-master", "jetbrains/phpstorm-attributes": "^1.2",
"nette/tester": "^2.5", "nette/tester": "^2.5",
"phpstan/phpstan": "^1.0", "phpstan/phpstan-nette": "^2.0@stable",
"tracy/tracy": "^2.9" "tracy/tracy": "^2.9"
}, },
"suggest": { "suggest": {
@@ -3918,6 +3918,9 @@
} }
}, },
"autoload": { "autoload": {
"psr-4": {
"Nette\\": "src"
},
"classmap": [ "classmap": [
"src/" "src/"
] ]
@@ -3958,9 +3961,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nette/utils/issues", "issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v4.0.7" "source": "https://github.com/nette/utils/tree/v4.0.8"
}, },
"time": "2025-06-03T04:55:08+00:00" "time": "2025-08-06T21:43:34+00:00"
}, },
{ {
"name": "nunomaduro/collision", "name": "nunomaduro/collision",

View File

@@ -78,8 +78,8 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false), 'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag. // see cer.php for exchange rates feature flag.
], ],
'version' => 'develop/2025-08-06', 'version' => 'develop/2025-08-07',
'build_time' => 1754505490, 'build_time' => 1754539423,
'api_version' => '2.1.0', // field is no longer used. 'api_version' => '2.1.0', // field is no longer used.
'db_version' => 26, 'db_version' => 26,

6
package-lock.json generated
View File

@@ -5700,9 +5700,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.197", "version": "1.5.198",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.197.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.198.tgz",
"integrity": "sha512-m1xWB3g7vJ6asIFz+2pBUbq3uGmfmln1M9SSvBe4QIFWYrRHylP73zL/3nMjDmwz8V+1xAXQDfBd6+HPW0WvDQ==", "integrity": "sha512-G5COfnp3w+ydVu80yprgWSfmfQaYRh9DOxfhAxstLyetKaLyl55QrNjx8C38Pc/C+RaDmb1M0Lk8wPEMQ+bGgQ==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },