. */ declare(strict_types=1); namespace FireflyIII\Support\Http\Api; use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface; use Illuminate\Support\Facades\Log; class SummaryBalanceGrouped { private const string SUM = 'sum'; private array $amounts = []; private array $currencies; private CurrencyRepositoryInterface $currencyRepository; private TransactionCurrency $default; private array $keys; public function __construct() { $this->keys = [self::SUM]; $this->currencies = []; $this->currencyRepository = app(CurrencyRepositoryInterface::class); } public function groupData(): array { Log::debug('Now going to group data.'); $return = []; foreach ($this->keys as $key) { $title = match ($key) { 'sum' => 'balance', 'expense' => 'spent', 'income' => 'earned', default => 'something' }; $return[] = [ 'key' => sprintf('%s-in-native', $title), 'value' => $this->amounts[$key]['native'] ?? '0', 'currency_id' => (string)$this->default->id, 'currency_code' => $this->default->code, 'currency_symbol' => $this->default->symbol, 'currency_decimal_places' => $this->default->decimal_places, ]; } // loop 3: format amounts: $currencyIds = array_keys($this->amounts[self::SUM] ?? []); foreach ($currencyIds as $currencyId) { if ('native' === $currencyId) { // skip native entries. continue; } $currencyId = (int)$currencyId; $currency = $this->currencies[$currencyId] ?? $this->currencyRepository->find($currencyId); $this->currencies[$currencyId] = $currency; // create objects for big array. foreach ($this->keys as $key) { $title = match ($key) { 'sum' => 'balance', 'expense' => 'spent', 'income' => 'earned', default => 'something' }; $return[] = [ 'key' => sprintf('%s-in-%s', $title, $currency->code), 'value' => $this->amounts[$key][$currencyId] ?? '0', 'currency_id' => (string)$currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, 'currency_decimal_places' => $currency->decimal_places, ]; } } return $return; } public function groupTransactions(string $key, array $journals): void { Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__)); Log::debug(sprintf('Now in groupTransactions with key "%s" and %d journal(s)', $key, count($journals))); $converter = new ExchangeRateConverter(); $this->keys[] = $key; $multiplier = 'income' === $key ? '-1' : '1'; /** @var array $journal */ foreach ($journals as $journal) { // transaction info: $currencyId = (int)$journal['currency_id']; $amount = bcmul($journal['amount'], $multiplier); $currency = $this->currencies[$currencyId] ?? TransactionCurrency::find($currencyId); $this->currencies[$currencyId] = $currency; $nativeAmount = $converter->convert($currency, $this->default, $journal['date'], $amount); if ((int)$journal['foreign_currency_id'] === $this->default->id) { // use foreign amount instead $nativeAmount = $journal['foreign_amount']; } // prep the arrays $this->amounts[$key] ??= []; $this->amounts[$key][$currencyId] ??= '0'; $this->amounts[$key]['native'] ??= '0'; $this->amounts[self::SUM][$currencyId] ??= '0'; $this->amounts[self::SUM]['native'] ??= '0'; // add values: $this->amounts[$key][$currencyId] = bcadd($this->amounts[$key][$currencyId], $amount); $this->amounts[self::SUM][$currencyId] = bcadd($this->amounts[self::SUM][$currencyId], $amount); $this->amounts[$key]['native'] = bcadd($this->amounts[$key]['native'], $nativeAmount); $this->amounts[self::SUM]['native'] = bcadd($this->amounts[self::SUM]['native'], $nativeAmount); } $converter->summarize(); } public function setDefault(TransactionCurrency $default): void { $this->default = $default; } }