From 1da63807eb14c4cb9d0d318d12ed97ceb8048cce Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Wed, 29 Apr 2026 01:19:32 +0200 Subject: [PATCH] asdasd --- .../fx-rates/src/Domain/FxRatesService.php | 98 +++++++++++++++++-- 1 file changed, 88 insertions(+), 10 deletions(-) diff --git a/modules/fx-rates/src/Domain/FxRatesService.php b/modules/fx-rates/src/Domain/FxRatesService.php index e020198..8ee8d15 100644 --- a/modules/fx-rates/src/Domain/FxRatesService.php +++ b/modules/fx-rates/src/Domain/FxRatesService.php @@ -37,10 +37,18 @@ final class FxRatesService if ($at === null || trim($at) === '') { $latest = $this->repository->getLatestFetch($base); if ($latest === null) { + $latest = $this->repository->getLatestFetch(null); + if ($latest === null) { + return null; + } + } + + $snapshot = $this->repository->getSnapshotByFetchId((int) $latest['id'], null); + if ($snapshot === null) { return null; } - return $this->repository->getSnapshotByFetchId((int) $latest['id'], $symbols); + return $this->rebaseSnapshot($snapshot, $base, $symbols); } $atUtc = $this->normalizeTimestamp($at); @@ -58,7 +66,12 @@ final class FxRatesService return null; } - return $snapshot + [ + $rebased = $this->rebaseSnapshot($snapshot, $base, $symbols); + if ($rebased === null) { + return null; + } + + return $rebased + [ 'requested_at' => $atUtc, 'distance_seconds' => $nearest['distance_seconds'] ?? null, ]; @@ -129,8 +142,12 @@ final class FxRatesService public function refreshLatestRates(?array $currencies = null, ?string $baseCurrency = null): array { - $base = $this->normalizeCurrency($baseCurrency ?: $this->defaultBaseCurrency()); - $payload = $this->fetchLatestPayload($base, $currencies); + $requestedBase = $this->normalizeCurrency($baseCurrency ?: $this->defaultBaseCurrency()); + $payload = $this->fetchLatestPayload($requestedBase, $currencies); + $base = $this->normalizeCurrency((string) ($payload['base'] ?? $requestedBase)); + if ($base === '') { + $base = $requestedBase !== '' ? $requestedBase : 'USD'; + } $rates = is_array($payload['rates'] ?? null) ? $payload['rates'] : []; $rateDate = $this->normalizeRateDate($payload['date'] ?? null); $saved = $this->repository->saveFetch( @@ -143,6 +160,7 @@ final class FxRatesService return [ 'base' => $base, + 'requested_base' => $requestedBase, 'rate_date' => $rateDate, 'updated_count' => count($saved['rates'] ?? []), 'rates' => $saved['rates'] ?? [], @@ -422,7 +440,7 @@ final class FxRatesService return null; } - $query = ['base_currency=' . rawurlencode($baseCurrency)]; + $query = []; $normalizedCurrencies = []; foreach ($currencies ?? [] as $currency) { $currency = $this->normalizeCurrency((string) $currency); @@ -450,9 +468,8 @@ final class FxRatesService return [ 'url' => sprintf( - '%s/api/v2/rates?base=%s&output=json&key=%s', + '%s/api/v2/rates?output=json&key=%s', $this->apiUrl(), - rawurlencode($baseCurrency), rawurlencode($apiKey) ), 'headers' => ['Accept: application/json'], @@ -531,10 +548,15 @@ final class FxRatesService throw new \RuntimeException($this->extractProviderError($payload, 'FX-Kurse konnten nicht geladen werden.')); } + $resolvedBase = $this->normalizeCurrency((string) ($payload['meta']['base_currency_code'] ?? $payload['base'] ?? $baseCurrency)); + if ($resolvedBase === '') { + $resolvedBase = $baseCurrency; + } + $filter = []; foreach ($currencies ?? [] as $currency) { $currency = $this->normalizeCurrency((string) $currency); - if ($currency !== '' && $currency !== $baseCurrency) { + if ($currency !== '' && $currency !== $resolvedBase) { $filter[$currency] = true; } } @@ -542,7 +564,7 @@ final class FxRatesService $rates = []; foreach ($rawRates as $code => $rateData) { $code = $this->normalizeCurrency((string) $code); - if ($code === '' || $code === $baseCurrency) { + if ($code === '' || $code === $resolvedBase) { continue; } if ($filter !== [] && !isset($filter[$code])) { @@ -558,12 +580,68 @@ final class FxRatesService } return [ - 'base' => $baseCurrency, + 'base' => $resolvedBase, 'date' => $payload['meta']['last_updated_at'] ?? null, 'rates' => $rates, ]; } + private function rebaseSnapshot(array $snapshot, string $requestedBase, ?array $symbols = null): ?array + { + $snapshotBase = $this->normalizeCurrency((string) ($snapshot['base_currency'] ?? '')); + $rates = is_array($snapshot['rates'] ?? null) ? $snapshot['rates'] : []; + + if ($snapshotBase === '') { + return null; + } + + if ($requestedBase === '' || $requestedBase === $snapshotBase) { + return $snapshot + [ + 'base_currency' => $snapshotBase, + 'rates' => $this->filterRates($rates, $symbols), + ]; + } + + $baseRate = $rates[$requestedBase] ?? null; + if (!is_numeric($baseRate) || (float) $baseRate <= 0) { + return null; + } + + $rebasedRates = []; + foreach ($rates as $code => $rate) { + $code = $this->normalizeCurrency((string) $code); + if ($code === '' || $code === $requestedBase || !is_numeric($rate)) { + continue; + } + $rebasedRates[$code] = (float) $rate / (float) $baseRate; + } + + return $snapshot + [ + 'base_currency' => $requestedBase, + 'rates' => $this->filterRates($rebasedRates, $symbols), + 'snapshot_base_currency' => $snapshotBase, + ]; + } + + private function filterRates(array $rates, ?array $symbols = null): array + { + if (!is_array($symbols) || $symbols === []) { + ksort($rates); + return $rates; + } + + $filtered = []; + foreach ($symbols as $symbol) { + $symbol = $this->normalizeCurrency((string) $symbol); + if ($symbol !== '' && isset($rates[$symbol])) { + $filtered[$symbol] = (float) $rates[$symbol]; + } + } + + ksort($filtered); + return $filtered; + } + private function normalizeCurrencyApiComCurrenciesPayload(array $payload): array { $rawCurrencies = is_array($payload['data'] ?? null) ? $payload['data'] : null;