From c2ab6a6c440d3656c9f8c8eee2ece9d3fccc86de Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 19 Aug 2021 21:44:10 +0200 Subject: [PATCH] Feature/improve portfolio details endpoint (#302) * Make details endpoint fault tolerant (do not throw error) * Update changelog --- CHANGELOG.md | 4 ++++ .../src/app/portfolio/portfolio.controller.ts | 15 ++++-------- .../src/app/portfolio/portfolio.service.ts | 24 +++++++++---------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47ed33d50..b3e35c53d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Changed + +- Improved the fault tolerance of the portfolio details endpoint + ### Fixed - Fixed the node engine version mismatch in `package.json` diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 0646f9995..ce0e736ee 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -125,17 +125,12 @@ export class PortfolioController { @Query('range') range, @Res() res: Response ): Promise<{ [symbol: string]: PortfolioPosition }> { - let details: { [symbol: string]: PortfolioPosition } = {}; - - try { - details = await this.portfolioService.getDetails(impersonationId, range); - } catch (error) { - console.error(error); - - res.status(StatusCodes.ACCEPTED); - } + const { details, hasErrors } = await this.portfolioService.getDetails( + impersonationId, + range + ); - if (hasNotDefinedValuesInObject(details)) { + if (hasErrors || hasNotDefinedValuesInObject(details)) { res.status(StatusCodes.ACCEPTED); } diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index f5d904e38..a3f76b804 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -154,7 +154,10 @@ export class PortfolioService { public async getDetails( aImpersonationId: string, aDateRange: DateRange = 'max' - ): Promise<{ [symbol: string]: PortfolioPosition }> { + ): Promise<{ + details: { [symbol: string]: PortfolioPosition }; + hasErrors: boolean; + }> { const userId = await this.getUserId(aImpersonationId); const userCurrency = this.request.user.Settings.currency; @@ -168,7 +171,7 @@ export class PortfolioService { }); if (transactionPoints?.length <= 0) { - return {}; + return { details: {}, hasErrors: false }; } portfolioCalculator.setTransactionPoints(transactionPoints); @@ -179,16 +182,12 @@ export class PortfolioService { startDate ); - if (currentPositions.hasErrors) { - throw new Error('Missing information'); - } - const cashDetails = await this.accountService.getCashDetails( userId, userCurrency ); - const result: { [symbol: string]: PortfolioPosition } = {}; + const details: { [symbol: string]: PortfolioPosition } = {}; const totalInvestment = currentPositions.totalInvestment.plus( cashDetails.balance ); @@ -218,7 +217,7 @@ export class PortfolioService { const value = item.quantity.mul(item.marketPrice); const symbolProfile = symbolProfileMap[item.symbol]; const dataProviderResponse = dataProviderResponses[item.symbol]; - result[item.symbol] = { + details[item.symbol] = { accounts, allocationCurrent: value.div(totalValue).toNumber(), allocationInvestment: item.investment.div(totalInvestment).toNumber(), @@ -226,8 +225,9 @@ export class PortfolioService { countries: symbolProfile.countries, currency: item.currency, exchange: dataProviderResponse.exchange, - grossPerformance: item.grossPerformance.toNumber(), - grossPerformancePercent: item.grossPerformancePercentage.toNumber(), + grossPerformance: item.grossPerformance?.toNumber() ?? 0, + grossPerformancePercent: + item.grossPerformancePercentage?.toNumber() ?? 0, investment: item.investment.toNumber(), marketPrice: item.marketPrice, marketState: dataProviderResponse.marketState, @@ -241,13 +241,13 @@ export class PortfolioService { } // TODO: Add a cash position for each currency - result[ghostfolioCashSymbol] = await this.getCashPosition({ + details[ghostfolioCashSymbol] = await this.getCashPosition({ cashDetails, investment: totalInvestment, value: totalValue }); - return result; + return { details, hasErrors: currentPositions.hasErrors }; } public async getPosition(