From 5e7dd96510bda36402ecefc6c112be8d12f9c2cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20G=C3=BCnther?= Date: Tue, 18 Nov 2025 11:54:53 +0100 Subject: [PATCH] =?UTF-8?q?Add=20logic=20to=20detect=20when=20converting?= =?UTF-8?q?=20between=20a=20derived=20currency=20and=20its=20root=20curren?= =?UTF-8?q?cy,=20and=20apply=20the=20fixed=20mathematical=20factor=20direc?= =?UTF-8?q?tly=20(0.01=20for=20GBp=E2=86=92GBP,=20100=20for=20GBP=E2=86=92?= =?UTF-8?q?GBp)=20instead=20of=20trying=20to=20fetch=20exchange=20rates.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exchange-rate-data.service.ts | 146 ++++++++++++------ 1 file changed, 101 insertions(+), 45 deletions(-) diff --git a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts index 47c67c3de..2b108cd5d 100644 --- a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts +++ b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts @@ -271,56 +271,65 @@ export class ExchangeRateDataService { if (aFromCurrency === aToCurrency) { factor = 1; } else { - const dataSource = - this.dataProviderService.getDataSourceForExchangeRates(); - const symbol = `${aFromCurrency}${aToCurrency}`; - - const marketData = await this.marketDataService.get({ - dataSource, - symbol, - date: aDate - }); + const derivedCurrencyFactor = this.getDerivedCurrencyFactor( + aFromCurrency, + aToCurrency + ); - if (marketData?.marketPrice) { - factor = marketData?.marketPrice; + if (derivedCurrencyFactor !== null) { + factor = derivedCurrencyFactor; } else { - // Calculate indirectly via base currency + const dataSource = + this.dataProviderService.getDataSourceForExchangeRates(); + const symbol = `${aFromCurrency}${aToCurrency}`; + + const marketData = await this.marketDataService.get({ + dataSource, + symbol, + date: aDate + }); - let marketPriceBaseCurrencyFromCurrency: number; - let marketPriceBaseCurrencyToCurrency: number; + if (marketData?.marketPrice) { + factor = marketData?.marketPrice; + } else { + // Calculate indirectly via base currency - try { - if (aFromCurrency === DEFAULT_CURRENCY) { - marketPriceBaseCurrencyFromCurrency = 1; - } else { - marketPriceBaseCurrencyFromCurrency = ( - await this.marketDataService.get({ - dataSource, - date: aDate, - symbol: `${DEFAULT_CURRENCY}${aFromCurrency}` - }) - )?.marketPrice; - } - } catch {} + let marketPriceBaseCurrencyFromCurrency: number; + let marketPriceBaseCurrencyToCurrency: number; - try { - if (aToCurrency === DEFAULT_CURRENCY) { - marketPriceBaseCurrencyToCurrency = 1; - } else { - marketPriceBaseCurrencyToCurrency = ( - await this.marketDataService.get({ - dataSource, - date: aDate, - symbol: `${DEFAULT_CURRENCY}${aToCurrency}` - }) - )?.marketPrice; - } - } catch {} + try { + if (aFromCurrency === DEFAULT_CURRENCY) { + marketPriceBaseCurrencyFromCurrency = 1; + } else { + marketPriceBaseCurrencyFromCurrency = ( + await this.marketDataService.get({ + dataSource, + date: aDate, + symbol: `${DEFAULT_CURRENCY}${aFromCurrency}` + }) + )?.marketPrice; + } + } catch {} - // Calculate the opposite direction - factor = - (1 / marketPriceBaseCurrencyFromCurrency) * - marketPriceBaseCurrencyToCurrency; + try { + if (aToCurrency === DEFAULT_CURRENCY) { + marketPriceBaseCurrencyToCurrency = 1; + } else { + marketPriceBaseCurrencyToCurrency = ( + await this.marketDataService.get({ + dataSource, + date: aDate, + symbol: `${DEFAULT_CURRENCY}${aToCurrency}` + }) + )?.marketPrice; + } + } catch {} + + // Calculate the opposite direction + factor = + (1 / marketPriceBaseCurrencyFromCurrency) * + marketPriceBaseCurrencyToCurrency; + } } } @@ -357,7 +366,25 @@ export class ExchangeRateDataService { for (const date of dates) { factors[format(date, DATE_FORMAT)] = 1; } - } else { + return factors; + } + + // Check if this is a conversion between a derived currency and its root currency + const derivedCurrencyFactor = this.getDerivedCurrencyFactor( + currencyFrom, + currencyTo + ); + + if (derivedCurrencyFactor !== null) { + // Use the fixed mathematical factor for derived currencies + for (const date of dates) { + factors[format(date, DATE_FORMAT)] = derivedCurrencyFactor; + } + return factors; + } + + // Continue with standard exchange rate logic + { const dataSource = this.dataProviderService.getDataSourceForExchangeRates(); const symbol = `${currencyFrom}${currencyTo}`; @@ -469,6 +496,35 @@ export class ExchangeRateDataService { return factors; } + private getDerivedCurrencyFactor( + currencyFrom: string, + currencyTo: string + ): number | null { + // Check if currencyFrom is a derived currency of currencyTo + const derivedFrom = DERIVED_CURRENCIES.find( + ({ currency, rootCurrency }) => + currency === currencyFrom && rootCurrency === currencyTo + ); + + if (derivedFrom) { + // e.g., GBp → GBP: factor = 1/100 = 0.01 + return 1 / derivedFrom.factor; + } + + // Check if currencyTo is a derived currency of currencyFrom + const derivedTo = DERIVED_CURRENCIES.find( + ({ currency, rootCurrency }) => + currency === currencyTo && rootCurrency === currencyFrom + ); + + if (derivedTo) { + // e.g., GBP → GBp: factor = 100 + return derivedTo.factor; + } + + return null; + } + private async prepareCurrencies(): Promise { let currencies: string[] = [DEFAULT_CURRENCY];