diff --git a/modules/fx-rates/assets/fx-rates.js b/modules/fx-rates/assets/fx-rates.js
index 84e8213..9005900 100644
--- a/modules/fx-rates/assets/fx-rates.js
+++ b/modules/fx-rates/assets/fx-rates.js
@@ -26,16 +26,23 @@
const renderSnapshot = (snapshot) => {
const rates = snapshot && snapshot.rates ? snapshot.rates : null;
const entries = rates ? Object.entries(rates) : [];
+ const visibleCurrencies = preferredCurrencies.length
+ ? new Set(preferredCurrencies)
+ : null;
if (!nodes.ratesBody) {
return;
}
- if (!entries.length) {
+ const filteredEntries = visibleCurrencies
+ ? entries.filter(([code]) => visibleCurrencies.has(String(code || '').trim().toUpperCase()))
+ : entries;
+
+ if (!filteredEntries.length) {
nodes.ratesBody.innerHTML = '
| Noch keine Wechselkurse fuer die ausgewaehlten Waehrungen gespeichert. |
';
return;
}
- nodes.ratesBody.innerHTML = entries.map(([code, rate]) => {
+ nodes.ratesBody.innerHTML = filteredEntries.map(([code, rate]) => {
const formatted = typeof rate === 'number'
? rate.toLocaleString('de-DE', { maximumFractionDigits: 8 })
: 'n/a';
diff --git a/modules/fx-rates/src/Domain/FxRatesService.php b/modules/fx-rates/src/Domain/FxRatesService.php
index 476e23a..33f67de 100644
--- a/modules/fx-rates/src/Domain/FxRatesService.php
+++ b/modules/fx-rates/src/Domain/FxRatesService.php
@@ -214,30 +214,32 @@ final class FxRatesService
}
$inverse = $this->repository->listDirectHistory($toCurrency, $fromCurrency, $this->normalizeTimestamp($from), $this->normalizeTimestamp($to), $limit);
- if ($inverse === []) {
- return [];
- }
+ if ($inverse !== []) {
+ $result = [];
+ foreach ($inverse as $row) {
+ $inverseRate = is_numeric($row['rate'] ?? null) ? (float) $row['rate'] : null;
+ if ($inverseRate === null || $inverseRate <= 0) {
+ continue;
+ }
- $result = [];
- foreach ($inverse as $row) {
- $inverseRate = is_numeric($row['rate'] ?? null) ? (float) $row['rate'] : null;
- if ($inverseRate === null || $inverseRate <= 0) {
- continue;
+ $result[] = [
+ 'fetch_id' => $row['fetch_id'] ?? null,
+ 'base_currency' => $fromCurrency,
+ 'target_currency' => $toCurrency,
+ 'rate' => 1 / $inverseRate,
+ 'rate_date' => $row['rate_date'] ?? null,
+ 'provider' => $row['provider'] ?? null,
+ 'fetched_at' => $row['fetched_at'] ?? null,
+ 'is_exact_pair' => false,
+ ];
}
- $result[] = [
- 'fetch_id' => $row['fetch_id'] ?? null,
- 'base_currency' => $fromCurrency,
- 'target_currency' => $toCurrency,
- 'rate' => 1 / $inverseRate,
- 'rate_date' => $row['rate_date'] ?? null,
- 'provider' => $row['provider'] ?? null,
- 'fetched_at' => $row['fetched_at'] ?? null,
- 'is_exact_pair' => false,
- ];
+ if ($result !== []) {
+ return array_map(fn (array $row): array => $this->localizeRateResult($row), $result);
+ }
}
- return array_map(fn (array $row): array => $this->localizeRateResult($row), $result);
+ return $this->crossHistory($fromCurrency, $toCurrency, $from, $to, $limit);
}
public function runScheduledRefresh(array $context = []): array
@@ -647,6 +649,49 @@ final class FxRatesService
return $filtered;
}
+ private function crossHistory(string $fromCurrency, string $toCurrency, ?string $from = null, ?string $to = null, int $limit = 200): array
+ {
+ $fromAt = $this->normalizeTimestamp($from);
+ $toAt = $this->normalizeTimestamp($to);
+ $candidates = array_reverse($this->repository->listRecentFetches(max($limit * 4, 50)));
+ $result = [];
+
+ foreach ($candidates as $fetch) {
+ $fetchedAt = (string) ($fetch['fetched_at'] ?? '');
+ if ($fetchedAt === '') {
+ continue;
+ }
+
+ if ($fromAt !== null && strcmp($fetchedAt, $fromAt) < 0) {
+ continue;
+ }
+ if ($toAt !== null && strcmp($fetchedAt, $toAt) > 0) {
+ continue;
+ }
+
+ $snapshot = $this->repository->getSnapshotByFetchId((int) ($fetch['id'] ?? 0), [$fromCurrency, $toCurrency]);
+ if ($snapshot === null) {
+ continue;
+ }
+
+ $rates = is_array($snapshot['rates'] ?? null) ? $snapshot['rates'] : [];
+ $resolved = $this->resolveRateFromSnapshot($snapshot, $rates, $fromCurrency, $toCurrency);
+ if ($resolved === null) {
+ continue;
+ }
+
+ $result[] = $this->localizeRateResult($resolved + [
+ 'fetch_id' => $fetch['id'] ?? null,
+ ]);
+
+ if (count($result) >= $limit) {
+ break;
+ }
+ }
+
+ return $result;
+ }
+
private function localizeFetch(?array $fetch): ?array
{
if (!is_array($fetch)) {