Browse Source

Task/improve type safety in exchange rate and portfolio table services (#8391)

Improve type safety
pull/8373/head
Kenrick Tandrian 3 days ago
committed by GitHub
parent
commit
5a6dbac82c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 33
      apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts
  2. 14
      apps/api/src/services/portfolio-table/portfolio-table.service.spec.ts
  3. 13
      apps/api/src/services/portfolio-table/portfolio-table.service.ts

33
apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts

@ -88,7 +88,7 @@ export class ExchangeRateDataService {
); );
const lastDateString = dateStrings.reduce((a, b) => { const lastDateString = dateStrings.reduce((a, b) => {
return a > b ? a : b; return a > b ? a : b;
}, undefined); }, '');
let previousExchangeRate = let previousExchangeRate =
exchangeRatesByCurrency[`${currency}${targetCurrency}`]?.[ exchangeRatesByCurrency[`${currency}${targetCurrency}`]?.[
@ -214,7 +214,7 @@ export class ExchangeRateDataService {
const resultExtended = result; const resultExtended = result;
for (const symbol of Object.keys(result)) { for (const symbol of Object.keys(result)) {
const [currency1, currency2] = symbol.match(/.{1,3}/g); const [currency1, currency2] = symbol.match(/.{1,3}/g) ?? [];
const [date] = Object.keys(result[symbol]); const [date] = Object.keys(result[symbol]);
// Calculate the opposite direction // Calculate the opposite direction
@ -226,7 +226,7 @@ export class ExchangeRateDataService {
} }
for (const symbol of Object.keys(resultExtended)) { for (const symbol of Object.keys(resultExtended)) {
const [currency1, currency2] = symbol.match(/.{1,3}/g); const [currency1, currency2] = symbol.match(/.{1,3}/g) ?? [];
this.exchangeRates[symbol] = this.exchangeRates[symbol] =
resultExtended[symbol]?.[dateStringOfYesterday]?.marketPrice; resultExtended[symbol]?.[dateStringOfYesterday]?.marketPrice;
@ -302,7 +302,7 @@ export class ExchangeRateDataService {
const derivedCurrencyFactor = const derivedCurrencyFactor =
this.derivedCurrencyFactors[`${aFromCurrency}${aToCurrency}`]; this.derivedCurrencyFactors[`${aFromCurrency}${aToCurrency}`];
let factor: number; let factor: number | undefined;
if (aFromCurrency === aToCurrency) { if (aFromCurrency === aToCurrency) {
factor = 1; factor = 1;
@ -324,8 +324,8 @@ export class ExchangeRateDataService {
} else { } else {
// Calculate indirectly via base currency // Calculate indirectly via base currency
let marketPriceBaseCurrencyFromCurrency: number; let marketPriceBaseCurrencyFromCurrency: number | undefined;
let marketPriceBaseCurrencyToCurrency: number; let marketPriceBaseCurrencyToCurrency: number | undefined;
try { try {
if (aFromCurrency === DEFAULT_CURRENCY) { if (aFromCurrency === DEFAULT_CURRENCY) {
@ -337,7 +337,7 @@ export class ExchangeRateDataService {
date: aDate, date: aDate,
symbol: `${DEFAULT_CURRENCY}${aFromCurrency}` symbol: `${DEFAULT_CURRENCY}${aFromCurrency}`
}) })
)?.marketPrice as number; )?.marketPrice;
} }
} catch {} } catch {}
@ -351,14 +351,19 @@ export class ExchangeRateDataService {
date: aDate, date: aDate,
symbol: `${DEFAULT_CURRENCY}${aToCurrency}` symbol: `${DEFAULT_CURRENCY}${aToCurrency}`
}) })
)?.marketPrice as number; )?.marketPrice;
} }
} catch {} } catch {}
// Calculate the opposite direction if (
factor = isNumber(marketPriceBaseCurrencyFromCurrency) &&
(1 / marketPriceBaseCurrencyFromCurrency) * isNumber(marketPriceBaseCurrencyToCurrency)
marketPriceBaseCurrencyToCurrency; ) {
// Calculate the opposite direction
factor =
(1 / marketPriceBaseCurrencyFromCurrency) *
marketPriceBaseCurrencyToCurrency;
}
} }
} }
@ -530,7 +535,9 @@ export class ExchangeRateDataService {
} }
}) })
).forEach(({ currency }) => { ).forEach(({ currency }) => {
currencies.push(currency); if (currency) {
currencies.push(currency);
}
}); });
( (

14
apps/api/src/services/portfolio-table/portfolio-table.service.spec.ts

@ -121,6 +121,7 @@ function createHolding({
assetSubClass = AssetSubClass.STOCK, assetSubClass = AssetSubClass.STOCK,
dataSource = DataSource.YAHOO, dataSource = DataSource.YAHOO,
isin, isin,
name,
symbol = 'AAPL' symbol = 'AAPL'
}: { }: {
allocationInPercentage?: number; allocationInPercentage?: number;
@ -128,6 +129,7 @@ function createHolding({
assetSubClass?: AssetSubClass; assetSubClass?: AssetSubClass;
dataSource?: DataSource; dataSource?: DataSource;
isin?: string | null; isin?: string | null;
name?: string | null;
symbol?: string; symbol?: string;
} = {}) { } = {}) {
return { return {
@ -140,7 +142,7 @@ function createHolding({
isin, isin,
symbol, symbol,
currency: 'CHF', currency: 'CHF',
name: `Name of ${symbol}` name: name === undefined ? `Name of ${symbol}` : name
}, },
dateOfFirstActivity: new Date('2024-01-01'), dateOfFirstActivity: new Date('2024-01-01'),
grossPerformance: 100, grossPerformance: 100,
@ -631,6 +633,16 @@ describe('PortfolioTableService', () => {
expect(row).toContain('| Name of AAPL | | AAPL |'); expect(row).toContain('| Name of AAPL | | AAPL |');
}); });
it('gives an empty name if the asset profile has none', async () => {
const result = await getHoldingsTable([createHolding({ name: null })]);
const [row] = result.split('\n').filter((line) => {
return line.includes('| AAPL |');
});
expect(row).toContain('| | | AAPL |');
});
it('gives the translation of the asset class and of the asset sub class', async () => { it('gives the translation of the asset class and of the asset sub class', async () => {
const result = await getHoldingsTable([createHolding()]); const result = await getHoldingsTable([createHolding()]);

13
apps/api/src/services/portfolio-table/portfolio-table.service.ts

@ -52,7 +52,10 @@ function getDataSourceColumnDefinition<T>(
const dataSource = getDataSource(row); const dataSource = getDataSource(row);
return dataSource return dataSource
? transformDataSourceInResponse({ configurationService, dataSource }) ? (transformDataSourceInResponse({
configurationService,
dataSource
}) ?? '')
: ''; : '';
}, },
name: DATA_SOURCE_COLUMN_NAME name: DATA_SOURCE_COLUMN_NAME
@ -176,7 +179,7 @@ export class PortfolioTableService {
}), }),
{ {
getValue: ({ assetProfile, currency }) => { getValue: ({ assetProfile, currency }) => {
return currency ?? assetProfile.currency; return currency ?? assetProfile.currency ?? '';
}, },
name: 'Currency' name: 'Currency'
}, },
@ -226,7 +229,7 @@ export class PortfolioTableService {
[ [
{ {
getValue: ({ assetProfile }) => { getValue: ({ assetProfile }) => {
return assetProfile.name; return assetProfile.name ?? '';
}, },
name: 'Name' name: 'Name'
}, },
@ -249,7 +252,7 @@ export class PortfolioTableService {
}), }),
{ {
getValue: ({ assetProfile }) => { getValue: ({ assetProfile }) => {
return assetProfile.currency; return assetProfile.currency ?? '';
}, },
name: 'Currency' name: 'Currency'
}, },
@ -696,7 +699,7 @@ export class PortfolioTableService {
const performanceSection = ['## Performance', '']; const performanceSection = ['## Performance', ''];
if (chart?.length > 0) { if (chart && chart.length > 0) {
performanceSection.push( performanceSection.push(
await getMarkdownTable({ await getMarkdownTable({
columnDefinitions: this.getColumnDefinitions({ columnDefinitions: this.getColumnDefinitions({

Loading…
Cancel
Save