From ed67cdfc8b38d13ac18bfb9a97feba8a0db7d37b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 9 Mar 2024 18:46:50 +0100 Subject: [PATCH] Resolve asset class labels, exclude liabilities --- .../src/app/portfolio/portfolio.controller.ts | 1 + .../src/app/portfolio/portfolio.service.ts | 21 ++++++-- .../holdings/holdings-page.component.ts | 2 +- apps/client/src/app/services/data.service.ts | 53 ++++++++++++++----- libs/common/src/lib/helper.ts | 6 ++- 5 files changed, 64 insertions(+), 19 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index be0f42394..d327cfcf3 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -110,6 +110,7 @@ export class PortfolioController { filters, impersonationId, userId: this.request.user.id, + withLiabilities: true, withSummary: true }); diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index fde07354d..caa5b3c00 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -24,7 +24,12 @@ import { MAX_CHART_ITEMS, UNKNOWN_KEY } from '@ghostfolio/common/config'; -import { DATE_FORMAT, getSum, parseDate } from '@ghostfolio/common/helper'; +import { + DATE_FORMAT, + getAllActivityTypes, + getSum, + parseDate +} from '@ghostfolio/common/helper'; import { Accounts, EnhancedSymbolProfile, @@ -141,7 +146,8 @@ export class PortfolioService { filters, withExcludedAccounts, impersonationId: userId, - userId: this.request.user.id + userId: this.request.user.id, + withLiabilities: true }) ]); @@ -333,6 +339,7 @@ export class PortfolioService { impersonationId, userId, withExcludedAccounts = false, + withLiabilities = false, withSummary = false }: { dateRange?: DateRange; @@ -340,6 +347,7 @@ export class PortfolioService { impersonationId: string; userId: string; withExcludedAccounts?: boolean; + withLiabilities?: boolean; withSummary?: boolean; }): Promise { userId = await this.getUserId(impersonationId, userId); @@ -354,7 +362,12 @@ export class PortfolioService { await this.getTransactionPoints({ filters, userId, - withExcludedAccounts + withExcludedAccounts, + types: withLiabilities + ? undefined + : getAllActivityTypes().filter((activityType) => { + return activityType !== 'LIABILITY'; + }) }); const portfolioCalculator = new PortfolioCalculator({ @@ -1949,7 +1962,7 @@ export class PortfolioService { private async getTransactionPoints({ filters, includeDrafts = false, - types = ['BUY', 'DIVIDEND', 'ITEM', 'LIABILITY', 'SELL'], + types = getAllActivityTypes(), userId, withExcludedAccounts = false }: { diff --git a/apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts b/apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts index 352cdaebf..6635393f5 100644 --- a/apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts +++ b/apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts @@ -96,7 +96,7 @@ export class HoldingsPageComponent implements OnDestroy, OnInit { } private fetchHoldings() { - return this.dataService.fetchHoldings({ + return this.dataService.fetchPortfolioHoldings({ filters: this.userService.getFilters() }); } diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 82f0aacf5..7741fd601 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -230,19 +230,6 @@ export class DataService { ); } - public fetchHoldings({ - filters - }: { - filters?: Filter[]; - } = {}) { - return this.http.get( - '/api/v1/portfolio/holdings', - { - params: this.buildFiltersAsQueryParams({ filters }) - } - ); - } - public deleteAccess(aId: string) { return this.http.delete(`/api/v1/access/${aId}`); } @@ -448,6 +435,46 @@ export class DataService { ); } + public fetchPortfolioHoldings({ + filters + }: { + filters?: Filter[]; + } = {}) { + return this.http + .get('/api/v1/portfolio/holdings', { + params: this.buildFiltersAsQueryParams({ filters }) + }) + .pipe( + map((response) => { + if (response.holdings) { + for (const symbol of Object.keys(response.holdings)) { + response.holdings[symbol].assetClassLabel = translate( + response.holdings[symbol].assetClass + ); + + response.holdings[symbol].assetSubClassLabel = translate( + response.holdings[symbol].assetSubClass + ); + + response.holdings[symbol].dateOfFirstActivity = response.holdings[ + symbol + ].dateOfFirstActivity + ? parseISO(response.holdings[symbol].dateOfFirstActivity) + : undefined; + + response.holdings[symbol].value = isNumber( + response.holdings[symbol].value + ) + ? response.holdings[symbol].value + : response.holdings[symbol].valueInPercentage; + } + } + + return response; + }) + ); + } + public fetchPortfolioPerformance({ filters, range, diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index e55800628..c52ec9ca5 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -1,6 +1,6 @@ import * as currencies from '@dinero.js/currencies'; import { NumberParser } from '@internationalized/number'; -import { DataSource, MarketData } from '@prisma/client'; +import { DataSource, MarketData, Type as ActivityType } from '@prisma/client'; import Big from 'big.js'; import { getDate, @@ -138,6 +138,10 @@ export function extractNumberFromString({ } } +export function getAllActivityTypes(): ActivityType[] { + return ['BUY', 'DIVIDEND', 'FEE', 'ITEM', 'LIABILITY', 'SELL']; +} + export function getAssetProfileIdentifier({ dataSource, symbol }: UniqueAsset) { return `${dataSource}-${symbol}`; }