From 72974e888f3403ab4bc3e6f3bbb14a46a9fced94 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 25 Sep 2022 15:14:51 +0200 Subject: [PATCH 1/4] Clean up spaces (#1288) --- .../20210605161257_added_symbol_profile/migration.sql | 2 +- .../migrations/20210612110542_added_auth_device/migration.sql | 2 +- .../migration.sql | 2 +- .../20210703194509_added_balance_to_account/migration.sql | 4 ++-- .../migration.sql | 2 +- .../20210807062952_added_is_draft_to_order/migration.sql | 2 +- .../migration.sql | 2 +- .../20210815180121_added_settings_to_settings/migration.sql | 2 +- .../migration.sql | 2 +- .../migration.sql | 2 +- .../migration.sql | 2 +- .../migration.sql | 2 +- .../20220227093650_added_url_to_symbol_profile/migration.sql | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/prisma/migrations/20210605161257_added_symbol_profile/migration.sql b/prisma/migrations/20210605161257_added_symbol_profile/migration.sql index 07c3f5ce0..b1fe9aa42 100644 --- a/prisma/migrations/20210605161257_added_symbol_profile/migration.sql +++ b/prisma/migrations/20210605161257_added_symbol_profile/migration.sql @@ -1,5 +1,5 @@ -- AlterTable -ALTER TABLE "Order" ADD COLUMN "symbolProfileId" TEXT; +ALTER TABLE "Order" ADD COLUMN "symbolProfileId" TEXT; -- CreateTable CREATE TABLE "SymbolProfile" ( diff --git a/prisma/migrations/20210612110542_added_auth_device/migration.sql b/prisma/migrations/20210612110542_added_auth_device/migration.sql index 28d8d7c25..8d8675436 100644 --- a/prisma/migrations/20210612110542_added_auth_device/migration.sql +++ b/prisma/migrations/20210612110542_added_auth_device/migration.sql @@ -1,5 +1,5 @@ -- AlterTable -ALTER TABLE "User" ADD COLUMN "authChallenge" TEXT; +ALTER TABLE "User" ADD COLUMN "authChallenge" TEXT; -- CreateTable CREATE TABLE "AuthDevice" ( diff --git a/prisma/migrations/20210616075245_added_sectors_to_symbol_profile/migration.sql b/prisma/migrations/20210616075245_added_sectors_to_symbol_profile/migration.sql index 39b7baba7..96621b085 100644 --- a/prisma/migrations/20210616075245_added_sectors_to_symbol_profile/migration.sql +++ b/prisma/migrations/20210616075245_added_sectors_to_symbol_profile/migration.sql @@ -1,2 +1,2 @@ -- AlterTable -ALTER TABLE "SymbolProfile" ADD COLUMN "sectors" JSONB; +ALTER TABLE "SymbolProfile" ADD COLUMN "sectors" JSONB; diff --git a/prisma/migrations/20210703194509_added_balance_to_account/migration.sql b/prisma/migrations/20210703194509_added_balance_to_account/migration.sql index 8c3952035..d9a9ffd1c 100644 --- a/prisma/migrations/20210703194509_added_balance_to_account/migration.sql +++ b/prisma/migrations/20210703194509_added_balance_to_account/migration.sql @@ -2,5 +2,5 @@ ALTER TYPE "AccountType" ADD VALUE 'CASH'; -- AlterTable -ALTER TABLE "Account" ADD COLUMN "balance" DOUBLE PRECISION NOT NULL DEFAULT 0, -ADD COLUMN "currency" "Currency" NOT NULL DEFAULT E'USD'; +ALTER TABLE "Account" ADD COLUMN "balance" DOUBLE PRECISION NOT NULL DEFAULT 0, +ADD COLUMN "currency" "Currency" NOT NULL DEFAULT E'USD'; diff --git a/prisma/migrations/20210724160404_added_currency_to_symbol_profile/migration.sql b/prisma/migrations/20210724160404_added_currency_to_symbol_profile/migration.sql index a99c3c1d9..eab96d9fc 100644 --- a/prisma/migrations/20210724160404_added_currency_to_symbol_profile/migration.sql +++ b/prisma/migrations/20210724160404_added_currency_to_symbol_profile/migration.sql @@ -1,2 +1,2 @@ -- AlterTable -ALTER TABLE "SymbolProfile" ADD COLUMN "currency" "Currency"; +ALTER TABLE "SymbolProfile" ADD COLUMN "currency" "Currency"; diff --git a/prisma/migrations/20210807062952_added_is_draft_to_order/migration.sql b/prisma/migrations/20210807062952_added_is_draft_to_order/migration.sql index 51970ec3c..d63f8679d 100644 --- a/prisma/migrations/20210807062952_added_is_draft_to_order/migration.sql +++ b/prisma/migrations/20210807062952_added_is_draft_to_order/migration.sql @@ -1,2 +1,2 @@ -- AlterTable -ALTER TABLE "Order" ADD COLUMN "isDraft" BOOLEAN NOT NULL DEFAULT false; +ALTER TABLE "Order" ADD COLUMN "isDraft" BOOLEAN NOT NULL DEFAULT false; diff --git a/prisma/migrations/20210808075949_added_asset_class_to_symbol_profile/migration.sql b/prisma/migrations/20210808075949_added_asset_class_to_symbol_profile/migration.sql index 5050a9033..da37ab8cb 100644 --- a/prisma/migrations/20210808075949_added_asset_class_to_symbol_profile/migration.sql +++ b/prisma/migrations/20210808075949_added_asset_class_to_symbol_profile/migration.sql @@ -2,4 +2,4 @@ CREATE TYPE "AssetClass" AS ENUM ('CASH', 'COMMODITY', 'EQUITY'); -- AlterTable -ALTER TABLE "SymbolProfile" ADD COLUMN "assetClass" "AssetClass"; +ALTER TABLE "SymbolProfile" ADD COLUMN "assetClass" "AssetClass"; diff --git a/prisma/migrations/20210815180121_added_settings_to_settings/migration.sql b/prisma/migrations/20210815180121_added_settings_to_settings/migration.sql index da863fb73..2e7c357f3 100644 --- a/prisma/migrations/20210815180121_added_settings_to_settings/migration.sql +++ b/prisma/migrations/20210815180121_added_settings_to_settings/migration.sql @@ -1,2 +1,2 @@ -- AlterTable -ALTER TABLE "Settings" ADD COLUMN "settings" JSONB; +ALTER TABLE "Settings" ADD COLUMN "settings" JSONB; diff --git a/prisma/migrations/20210822200534_added_asset_sub_class_to_symbol_profile/migration.sql b/prisma/migrations/20210822200534_added_asset_sub_class_to_symbol_profile/migration.sql index ca1ad3d26..7d1122c88 100644 --- a/prisma/migrations/20210822200534_added_asset_sub_class_to_symbol_profile/migration.sql +++ b/prisma/migrations/20210822200534_added_asset_sub_class_to_symbol_profile/migration.sql @@ -2,4 +2,4 @@ CREATE TYPE "AssetSubClass" AS ENUM ('CRYPTOCURRENCY', 'ETF', 'STOCK'); -- AlterTable -ALTER TABLE "SymbolProfile" ADD COLUMN "assetSubClass" "AssetSubClass"; +ALTER TABLE "SymbolProfile" ADD COLUMN "assetSubClass" "AssetSubClass"; diff --git a/prisma/migrations/20210916182355_added_data_source_to_market_data/migration.sql b/prisma/migrations/20210916182355_added_data_source_to_market_data/migration.sql index 83911236a..720460f57 100644 --- a/prisma/migrations/20210916182355_added_data_source_to_market_data/migration.sql +++ b/prisma/migrations/20210916182355_added_data_source_to_market_data/migration.sql @@ -1,2 +1,2 @@ -- AlterTable -ALTER TABLE "MarketData" ADD COLUMN "dataSource" "DataSource" NOT NULL DEFAULT E'YAHOO'; +ALTER TABLE "MarketData" ADD COLUMN "dataSource" "DataSource" NOT NULL DEFAULT E'YAHOO'; diff --git a/prisma/migrations/20211107082008_added_symbol_mapping_to_symbol_profile/migration.sql b/prisma/migrations/20211107082008_added_symbol_mapping_to_symbol_profile/migration.sql index a6cdeb92c..07f6a3b3d 100644 --- a/prisma/migrations/20211107082008_added_symbol_mapping_to_symbol_profile/migration.sql +++ b/prisma/migrations/20211107082008_added_symbol_mapping_to_symbol_profile/migration.sql @@ -1,2 +1,2 @@ -- AlterTable -ALTER TABLE "SymbolProfile" ADD COLUMN "symbolMapping" JSONB; +ALTER TABLE "SymbolProfile" ADD COLUMN "symbolMapping" JSONB; diff --git a/prisma/migrations/20211107171624_added_scraper_configuration_to_symbol_profile/migration.sql b/prisma/migrations/20211107171624_added_scraper_configuration_to_symbol_profile/migration.sql index 84ca4bb96..ab32cddef 100644 --- a/prisma/migrations/20211107171624_added_scraper_configuration_to_symbol_profile/migration.sql +++ b/prisma/migrations/20211107171624_added_scraper_configuration_to_symbol_profile/migration.sql @@ -1,2 +1,2 @@ -- AlterTable -ALTER TABLE "SymbolProfile" ADD COLUMN "scraperConfiguration" JSONB; +ALTER TABLE "SymbolProfile" ADD COLUMN "scraperConfiguration" JSONB; diff --git a/prisma/migrations/20220227093650_added_url_to_symbol_profile/migration.sql b/prisma/migrations/20220227093650_added_url_to_symbol_profile/migration.sql index 61456216c..b5781f8d1 100644 --- a/prisma/migrations/20220227093650_added_url_to_symbol_profile/migration.sql +++ b/prisma/migrations/20220227093650_added_url_to_symbol_profile/migration.sql @@ -1,2 +1,2 @@ -- AlterTable -ALTER TABLE "SymbolProfile" ADD COLUMN "url" TEXT; +ALTER TABLE "SymbolProfile" ADD COLUMN "url" TEXT; From f01a3f893d89e02756d46e08e11d9ef89633d089 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 25 Sep 2022 18:02:46 +0200 Subject: [PATCH 2/4] Exclude accounts (#1289) * Exclude accounts * Update changelog --- CHANGELOG.md | 6 + .../api/src/app/account/account.controller.ts | 7 +- apps/api/src/app/account/account.service.ts | 12 +- .../api/src/app/account/create-account.dto.ts | 12 +- .../api/src/app/account/update-account.dto.ts | 12 +- apps/api/src/app/order/order.controller.ts | 3 +- apps/api/src/app/order/order.service.ts | 42 ++-- .../src/app/portfolio/portfolio.controller.ts | 64 ++--- .../src/app/portfolio/portfolio.service.ts | 222 ++++++++++++------ .../account-detail-dialog.component.ts | 2 +- .../account-detail-dialog.html | 6 +- .../home-summary/home-summary.component.ts | 50 +++- .../portfolio-summary.component.html | 11 + .../pages/accounts/accounts-page.component.ts | 7 +- .../create-or-update-account-dialog.html | 8 + .../create-or-update-account-dialog.module.ts | 2 + .../portfolio/fire/fire-page.component.ts | 8 +- apps/client/src/app/services/data.service.ts | 36 +-- .../interfaces/portfolio-details.interface.ts | 6 +- .../interfaces/portfolio-summary.interface.ts | 3 +- .../migration.sql | 2 + prisma/schema.prisma | 1 + 22 files changed, 345 insertions(+), 177 deletions(-) create mode 100644 prisma/migrations/20220924175215_added_is_excluded_to_account/migration.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index 20277377b..6fd6c7129 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Added support to exclude an account from analysis + ## 1.197.0 - 24.09.2022 ### Added diff --git a/apps/api/src/app/account/account.controller.ts b/apps/api/src/app/account/account.controller.ts index 524e36f5a..3ef671cc4 100644 --- a/apps/api/src/app/account/account.controller.ts +++ b/apps/api/src/app/account/account.controller.ts @@ -96,7 +96,9 @@ export class AccountController { let accountsWithAggregations = await this.portfolioService.getAccountsWithAggregations( - impersonationUserId || this.request.user.id + impersonationUserId || this.request.user.id, + undefined, + true ); if ( @@ -139,7 +141,8 @@ export class AccountController { let accountsWithAggregations = await this.portfolioService.getAccountsWithAggregations( impersonationUserId || this.request.user.id, - [{ id, type: 'ACCOUNT' }] + [{ id, type: 'ACCOUNT' }], + true ); if ( diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index b9b65716a..7c10fc31f 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -107,15 +107,23 @@ export class AccountService { public async getCashDetails({ currency, filters = [], - userId + userId, + withExcludedAccounts = false }: { currency: string; filters?: Filter[]; userId: string; + withExcludedAccounts?: boolean; }): Promise { let totalCashBalanceInBaseCurrency = new Big(0); - const where: Prisma.AccountWhereInput = { userId }; + const where: Prisma.AccountWhereInput = { + userId + }; + + if (withExcludedAccounts === false) { + where.isExcluded = false; + } const { ACCOUNT: filtersByAccount, diff --git a/apps/api/src/app/account/create-account.dto.ts b/apps/api/src/app/account/create-account.dto.ts index f53a20e76..3ea13e20a 100644 --- a/apps/api/src/app/account/create-account.dto.ts +++ b/apps/api/src/app/account/create-account.dto.ts @@ -1,5 +1,11 @@ import { AccountType } from '@prisma/client'; -import { IsNumber, IsString, ValidateIf } from 'class-validator'; +import { + IsBoolean, + IsNumber, + IsOptional, + IsString, + ValidateIf +} from 'class-validator'; export class CreateAccountDto { @IsString() @@ -11,6 +17,10 @@ export class CreateAccountDto { @IsString() currency: string; + @IsBoolean() + @IsOptional() + isExcluded?: boolean; + @IsString() name: string; diff --git a/apps/api/src/app/account/update-account.dto.ts b/apps/api/src/app/account/update-account.dto.ts index 343f46a7a..0b5737607 100644 --- a/apps/api/src/app/account/update-account.dto.ts +++ b/apps/api/src/app/account/update-account.dto.ts @@ -1,5 +1,11 @@ import { AccountType } from '@prisma/client'; -import { IsNumber, IsString, ValidateIf } from 'class-validator'; +import { + IsBoolean, + IsNumber, + IsOptional, + IsString, + ValidateIf +} from 'class-validator'; export class UpdateAccountDto { @IsString() @@ -14,6 +20,10 @@ export class UpdateAccountDto { @IsString() id: string; + @IsBoolean() + @IsOptional() + isExcluded?: boolean; + @IsString() name: string; diff --git a/apps/api/src/app/order/order.controller.ts b/apps/api/src/app/order/order.controller.ts index e3cafefca..a0c606b8c 100644 --- a/apps/api/src/app/order/order.controller.ts +++ b/apps/api/src/app/order/order.controller.ts @@ -109,7 +109,8 @@ export class OrderController { filters, userCurrency, includeDrafts: true, - userId: impersonationUserId || this.request.user.id + userId: impersonationUserId || this.request.user.id, + withExcludedAccounts: true }); if ( diff --git a/apps/api/src/app/order/order.service.ts b/apps/api/src/app/order/order.service.ts index bf549200e..b95c96975 100644 --- a/apps/api/src/app/order/order.service.ts +++ b/apps/api/src/app/order/order.service.ts @@ -189,13 +189,15 @@ export class OrderService { includeDrafts = false, types, userCurrency, - userId + userId, + withExcludedAccounts = false }: { filters?: Filter[]; includeDrafts?: boolean; types?: TypeOfOrder[]; userCurrency: string; userId: string; + withExcludedAccounts?: boolean; }): Promise { const where: Prisma.OrderWhereInput = { userId }; @@ -284,24 +286,28 @@ export class OrderService { }, orderBy: { date: 'asc' } }) - ).map((order) => { - const value = new Big(order.quantity).mul(order.unitPrice).toNumber(); - - return { - ...order, - value, - feeInBaseCurrency: this.exchangeRateDataService.toCurrency( - order.fee, - order.SymbolProfile.currency, - userCurrency - ), - valueInBaseCurrency: this.exchangeRateDataService.toCurrency( + ) + .filter((order) => { + return withExcludedAccounts || order.Account?.isExcluded === false; + }) + .map((order) => { + const value = new Big(order.quantity).mul(order.unitPrice).toNumber(); + + return { + ...order, value, - order.SymbolProfile.currency, - userCurrency - ) - }; - }); + feeInBaseCurrency: this.exchangeRateDataService.toCurrency( + order.fee, + order.SymbolProfile.currency, + userCurrency + ), + valueInBaseCurrency: this.exchangeRateDataService.toCurrency( + value, + order.SymbolProfile.currency, + userCurrency + ) + }; + }); } public async updateOrder({ diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 66cd408cc..4a017388f 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -148,12 +148,15 @@ export class PortfolioController { }) ]; + let portfolioSummary: PortfolioSummary; + const { accounts, filteredValueInBaseCurrency, filteredValueInPercentage, hasErrors, holdings, + summary, totalValueInBaseCurrency } = await this.portfolioService.getDetails( impersonationId, @@ -166,6 +169,8 @@ export class PortfolioController { hasError = true; } + portfolioSummary = summary; + if ( impersonationId || this.userService.isRestrictedView(this.request.user) @@ -199,6 +204,22 @@ export class PortfolioController { accounts[name].current = current / totalValue; accounts[name].original = original / totalInvestment; } + + portfolioSummary = nullifyValuesInObject(summary, [ + 'cash', + 'committedFunds', + 'currentGrossPerformance', + 'currentNetPerformance', + 'currentValue', + 'dividend', + 'emergencyFund', + 'excludedAccountsAndActivities', + 'fees', + 'items', + 'netWorth', + 'totalBuy', + 'totalSell' + ]); } let hasDetails = true; @@ -224,7 +245,8 @@ export class PortfolioController { filteredValueInPercentage, hasError, holdings, - totalValueInBaseCurrency + totalValueInBaseCurrency, + summary: hasDetails ? portfolioSummary : undefined }; } @@ -420,46 +442,6 @@ export class PortfolioController { return portfolioPublicDetails; } - @Get('summary') - @UseGuards(AuthGuard('jwt')) - public async getSummary( - @Headers('impersonation-id') impersonationId - ): Promise { - if ( - this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - this.request.user.subscription.type === 'Basic' - ) { - throw new HttpException( - getReasonPhrase(StatusCodes.FORBIDDEN), - StatusCodes.FORBIDDEN - ); - } - - let summary = await this.portfolioService.getSummary(impersonationId); - - if ( - impersonationId || - this.userService.isRestrictedView(this.request.user) - ) { - summary = nullifyValuesInObject(summary, [ - 'cash', - 'committedFunds', - 'currentGrossPerformance', - 'currentNetPerformance', - 'currentValue', - 'dividend', - 'emergencyFund', - 'fees', - 'items', - 'netWorth', - 'totalBuy', - 'totalSell' - ]); - } - - return summary; - } - @Get('position/:dataSource/:symbol') @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index c38e2a8d0..a49bda912 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -50,8 +50,11 @@ import type { import { Inject, Injectable } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { + Account, AssetClass, DataSource, + Order, + Platform, Prisma, Tag, Type as TypeOfOrder @@ -106,7 +109,8 @@ export class PortfolioService { public async getAccounts( aUserId: string, - aFilters?: Filter[] + aFilters?: Filter[], + withExcludedAccounts = false ): Promise { const where: Prisma.AccountWhereInput = { userId: aUserId }; @@ -120,7 +124,13 @@ export class PortfolioService { include: { Order: true, Platform: true }, orderBy: { name: 'asc' } }), - this.getDetails(aUserId, aUserId, undefined, aFilters) + this.getDetails( + aUserId, + aUserId, + undefined, + aFilters, + withExcludedAccounts + ) ]); const userCurrency = this.request.user.Settings.settings.baseCurrency; @@ -160,9 +170,14 @@ export class PortfolioService { public async getAccountsWithAggregations( aUserId: string, - aFilters?: Filter[] + aFilters?: Filter[], + withExcludedAccounts = false ): Promise { - const accounts = await this.getAccounts(aUserId, aFilters); + const accounts = await this.getAccounts( + aUserId, + aFilters, + withExcludedAccounts + ); let totalBalanceInBaseCurrency = new Big(0); let totalValueInBaseCurrency = new Big(0); let transactionCount = 0; @@ -410,7 +425,8 @@ export class PortfolioService { aImpersonationId: string, aUserId: string, aDateRange: DateRange = 'max', - aFilters?: Filter[] + aFilters?: Filter[], + withExcludedAccounts = false ): Promise { const userId = await this.getUserId(aImpersonationId, aUserId); const user = await this.userService.user({ id: userId }); @@ -426,6 +442,7 @@ export class PortfolioService { const { orders, portfolioOrders, transactionPoints } = await this.getTransactionPoints({ userId, + withExcludedAccounts, filters: aFilters }); @@ -580,6 +597,7 @@ export class PortfolioService { portfolioItemsNow, userCurrency, userId, + withExcludedAccounts, filters: aFilters }); @@ -588,6 +606,7 @@ export class PortfolioService { return { accounts, holdings, + summary, filteredValueInBaseCurrency: filteredValueInBaseCurrency.toNumber(), filteredValueInPercentage: summary.netWorth ? filteredValueInBaseCurrency.div(summary.netWorth).toNumber() @@ -606,7 +625,11 @@ export class PortfolioService { const userId = await this.getUserId(aImpersonationId, this.request.user.id); const orders = ( - await this.orderService.getOrders({ userCurrency, userId }) + await this.orderService.getOrders({ + userCurrency, + userId, + withExcludedAccounts: true + }) ).filter(({ SymbolProfile }) => { return ( SymbolProfile.dataSource === aDataSource && @@ -1181,74 +1204,6 @@ export class PortfolioService { }; } - public async getSummary(aImpersonationId: string): Promise { - const userCurrency = this.request.user.Settings.settings.baseCurrency; - const userId = await this.getUserId(aImpersonationId, this.request.user.id); - const user = await this.userService.user({ id: userId }); - - const performanceInformation = await this.getPerformance(aImpersonationId); - - const { balanceInBaseCurrency } = await this.accountService.getCashDetails({ - userId, - currency: userCurrency - }); - const orders = await this.orderService.getOrders({ - userCurrency, - userId - }); - const dividend = this.getDividend(orders).toNumber(); - const emergencyFund = new Big( - (user.Settings?.settings as UserSettings)?.emergencyFund ?? 0 - ); - const fees = this.getFees(orders).toNumber(); - const firstOrderDate = orders[0]?.date; - const items = this.getItems(orders).toNumber(); - - const totalBuy = this.getTotalByType(orders, userCurrency, 'BUY'); - const totalSell = this.getTotalByType(orders, userCurrency, 'SELL'); - - const cash = new Big(balanceInBaseCurrency).minus(emergencyFund).toNumber(); - const committedFunds = new Big(totalBuy).minus(totalSell); - - const netWorth = new Big(balanceInBaseCurrency) - .plus(performanceInformation.performance.currentValue) - .plus(items) - .toNumber(); - - const daysInMarket = differenceInDays(new Date(), firstOrderDate); - - const annualizedPerformancePercent = new PortfolioCalculator({ - currency: userCurrency, - currentRateService: this.currentRateService, - orders: [] - }) - .getAnnualizedPerformancePercent({ - daysInMarket, - netPerformancePercent: new Big( - performanceInformation.performance.currentNetPerformancePercent - ) - }) - ?.toNumber(); - - return { - ...performanceInformation.performance, - annualizedPerformancePercent, - cash, - dividend, - fees, - firstOrderDate, - items, - netWorth, - totalBuy, - totalSell, - committedFunds: committedFunds.toNumber(), - emergencyFund: emergencyFund.toNumber(), - ordersCount: orders.filter((order) => { - return order.type === 'BUY' || order.type === 'SELL'; - }).length - }; - } - private async getCashPositions({ cashDetails, emergencyFund, @@ -1424,14 +1379,117 @@ export class PortfolioService { return portfolioStart; } + private async getSummary( + aImpersonationId: string + ): Promise { + const userCurrency = this.request.user.Settings.settings.baseCurrency; + const userId = await this.getUserId(aImpersonationId, this.request.user.id); + const user = await this.userService.user({ id: userId }); + + const performanceInformation = await this.getPerformance(aImpersonationId); + + const { balanceInBaseCurrency } = await this.accountService.getCashDetails({ + userId, + currency: userCurrency + }); + const orders = await this.orderService.getOrders({ + userCurrency, + userId + }); + + const excludedActivities = ( + await this.orderService.getOrders({ + userCurrency, + userId, + withExcludedAccounts: true + }) + ).filter(({ Account: account }) => { + return account?.isExcluded ?? false; + }); + + const dividend = this.getDividend(orders).toNumber(); + const emergencyFund = new Big( + (user.Settings?.settings as UserSettings)?.emergencyFund ?? 0 + ); + const fees = this.getFees(orders).toNumber(); + const firstOrderDate = orders[0]?.date; + const items = this.getItems(orders).toNumber(); + + const totalBuy = this.getTotalByType(orders, userCurrency, 'BUY'); + const totalSell = this.getTotalByType(orders, userCurrency, 'SELL'); + + const cash = new Big(balanceInBaseCurrency).minus(emergencyFund).toNumber(); + const committedFunds = new Big(totalBuy).minus(totalSell); + const totalOfExcludedActivities = new Big( + this.getTotalByType(excludedActivities, userCurrency, 'BUY') + ).minus(this.getTotalByType(excludedActivities, userCurrency, 'SELL')); + + const cashDetailsWithExcludedAccounts = + await this.accountService.getCashDetails({ + userId, + currency: userCurrency, + withExcludedAccounts: true + }); + + const excludedBalanceInBaseCurrency = new Big( + cashDetailsWithExcludedAccounts.balanceInBaseCurrency + ).minus(balanceInBaseCurrency); + + const excludedAccountsAndActivities = excludedBalanceInBaseCurrency + .plus(totalOfExcludedActivities) + .toNumber(); + + const netWorth = new Big(balanceInBaseCurrency) + .plus(performanceInformation.performance.currentValue) + .plus(items) + .plus(excludedAccountsAndActivities) + .toNumber(); + + const daysInMarket = differenceInDays(new Date(), firstOrderDate); + + const annualizedPerformancePercent = new PortfolioCalculator({ + currency: userCurrency, + currentRateService: this.currentRateService, + orders: [] + }) + .getAnnualizedPerformancePercent({ + daysInMarket, + netPerformancePercent: new Big( + performanceInformation.performance.currentNetPerformancePercent + ) + }) + ?.toNumber(); + + return { + ...performanceInformation.performance, + annualizedPerformancePercent, + cash, + dividend, + excludedAccountsAndActivities, + fees, + firstOrderDate, + items, + netWorth, + totalBuy, + totalSell, + committedFunds: committedFunds.toNumber(), + emergencyFund: emergencyFund.toNumber(), + ordersCount: orders.filter((order) => { + return order.type === 'BUY' || order.type === 'SELL'; + }).length + }; + } + private async getTransactionPoints({ filters, includeDrafts = false, - userId + userId, + withExcludedAccounts }: { filters?: Filter[]; includeDrafts?: boolean; userId: string; + withExcludedAccounts?: boolean; }): Promise<{ transactionPoints: TransactionPoint[]; orders: OrderWithAccount[]; @@ -1445,6 +1503,7 @@ export class PortfolioService { includeDrafts, userCurrency, userId, + withExcludedAccounts, types: ['BUY', 'SELL'] }); @@ -1496,17 +1555,22 @@ export class PortfolioService { orders, portfolioItemsNow, userCurrency, - userId + userId, + withExcludedAccounts }: { filters?: Filter[]; orders: OrderWithAccount[]; portfolioItemsNow: { [p: string]: TimelinePosition }; userCurrency: string; userId: string; + withExcludedAccounts?: boolean; }) { const accounts: PortfolioDetails['accounts'] = {}; - let currentAccounts = []; + let currentAccounts: (Account & { + Order?: Order[]; + Platform?: Platform; + })[] = []; if (filters.length === 0) { currentAccounts = await this.accountService.getAccounts(userId); @@ -1526,6 +1590,10 @@ export class PortfolioService { }); } + currentAccounts = currentAccounts.filter((account) => { + return withExcludedAccounts || account.isExcluded === false; + }); + for (const account of currentAccounts) { const ordersByAccount = orders.filter(({ accountId }) => { return accountId === account.id; diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts index ca2f229e7..a0c11bce8 100644 --- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts +++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts @@ -61,7 +61,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit { .subscribe(({ accountType, name, Platform, valueInBaseCurrency }) => { this.accountType = accountType; this.name = name; - this.platformName = Platform?.name; + this.platformName = Platform?.name ?? '-'; this.valueInBaseCurrency = valueInBaseCurrency; this.changeDetectorRef.markForCheck(); diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html index edf111ffc..53a9c76ea 100644 --- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html +++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html @@ -21,10 +21,12 @@
- Account Type + Account Type
- Platform + Platform
diff --git a/apps/client/src/app/components/home-summary/home-summary.component.ts b/apps/client/src/app/components/home-summary/home-summary.component.ts index 106aba6c9..f10f09fe3 100644 --- a/apps/client/src/app/components/home-summary/home-summary.component.ts +++ b/apps/client/src/app/components/home-summary/home-summary.component.ts @@ -1,8 +1,18 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + MatSnackBar, + MatSnackBarRef, + TextOnlySnackBar +} from '@angular/material/snack-bar'; +import { Router } from '@angular/router'; import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; -import { PortfolioSummary, User } from '@ghostfolio/common/interfaces'; +import { + InfoItem, + PortfolioSummary, + User +} from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -14,8 +24,11 @@ import { takeUntil } from 'rxjs/operators'; }) export class HomeSummaryComponent implements OnDestroy, OnInit { public hasImpersonationId: boolean; + public hasPermissionForSubscription: boolean; public hasPermissionToUpdateUserSettings: boolean; + public info: InfoItem; public isLoading = true; + public snackBarRef: MatSnackBarRef; public summary: PortfolioSummary; public user: User; @@ -25,8 +38,17 @@ export class HomeSummaryComponent implements OnDestroy, OnInit { private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, private impersonationStorageService: ImpersonationStorageService, + private router: Router, + private snackBar: MatSnackBar, private userService: UserService ) { + this.info = this.dataService.fetchInfo(); + + this.hasPermissionForSubscription = hasPermission( + this.info?.globalPermissions, + permissions.enableSubscription + ); + this.userService.stateChanged .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((state) => { @@ -50,8 +72,6 @@ export class HomeSummaryComponent implements OnDestroy, OnInit { .subscribe((aId) => { this.hasImpersonationId = !!aId; }); - - this.update(); } public onChangeEmergencyFund(emergencyFund: number) { @@ -81,12 +101,30 @@ export class HomeSummaryComponent implements OnDestroy, OnInit { this.isLoading = true; this.dataService - .fetchPortfolioSummary() + .fetchPortfolioDetails({}) .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe((response) => { - this.summary = response; + .subscribe(({ summary }) => { + this.summary = summary; this.isLoading = false; + if (!this.summary) { + this.snackBarRef = this.snackBar.open( + $localize`This feature requires a subscription.`, + this.hasPermissionForSubscription + ? $localize`Upgrade Plan` + : undefined, + { duration: 6000 } + ); + + this.snackBarRef.afterDismissed().subscribe(() => { + this.snackBarRef = undefined; + }); + + this.snackBarRef.onAction().subscribe(() => { + this.router.navigate(['/pricing']); + }); + } + this.changeDetectorRef.markForCheck(); }); diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html index 577d41741..78e30675c 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -172,6 +172,17 @@ > +
+
Excluded from Analysis
+
+ +
+

diff --git a/apps/client/src/app/pages/accounts/accounts-page.component.ts b/apps/client/src/app/pages/accounts/accounts-page.component.ts index 81c02c2fd..6d7f84555 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -59,8 +59,8 @@ export class AccountsPageComponent implements OnDestroy, OnInit { this.openCreateAccountDialog(); } else if (params['editDialog']) { if (this.accounts) { - const account = this.accounts.find((account) => { - return account.id === params['accountId']; + const account = this.accounts.find(({ id }) => { + return id === params['accountId']; }); this.openUpdateAccountDialog(account); @@ -155,6 +155,7 @@ export class AccountsPageComponent implements OnDestroy, OnInit { balance, currency, id, + isExcluded, name, platformId }: AccountModel): void { @@ -165,6 +166,7 @@ export class AccountsPageComponent implements OnDestroy, OnInit { balance, currency, id, + isExcluded, name, platformId } @@ -231,6 +233,7 @@ export class AccountsPageComponent implements OnDestroy, OnInit { accountType: AccountType.SECURITIES, balance: 0, currency: this.user?.settings?.baseCurrency, + isExcluded: false, name: null, platformId: null } diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html index 971487356..ba2a1cee2 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -50,6 +50,14 @@ +
+ Exclude from Analysis +
Account ID diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.module.ts b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.module.ts index 3a3f2f517..528835f9a 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.module.ts +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.module.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; @@ -15,6 +16,7 @@ import { CreateOrUpdateAccountDialog } from './create-or-update-account-dialog.c CommonModule, FormsModule, MatButtonModule, + MatCheckboxModule, MatDialogModule, MatFormFieldModule, MatInputModule, diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts index d4d6abb26..032cf3b31 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts @@ -37,14 +37,14 @@ export class FirePageComponent implements OnDestroy, OnInit { this.deviceType = this.deviceService.getDeviceInfo().deviceType; this.dataService - .fetchPortfolioSummary() + .fetchPortfolioDetails({}) .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ cash, currentValue }) => { - if (cash === null || currentValue === null) { + .subscribe(({ summary }) => { + if (summary.cash === null || summary.currentValue === null) { return; } - this.fireWealth = new Big(currentValue); + this.fireWealth = new Big(summary.currentValue); this.withdrawalRatePerYear = this.fireWealth.mul(4).div(100); this.withdrawalRatePerMonth = this.withdrawalRatePerYear.div(12); diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index d33faeb74..b725a1d05 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -31,7 +31,6 @@ import { PortfolioPerformanceResponse, PortfolioPublicDetails, PortfolioReport, - PortfolioSummary, UniqueAsset, User } from '@ghostfolio/common/interfaces'; @@ -302,7 +301,11 @@ export class DataService { ); } - public fetchPortfolioDetails({ filters }: { filters?: Filter[] }) { + public fetchPortfolioDetails({ + filters + }: { + filters?: Filter[]; + }): Observable { let params = new HttpParams(); if (filters?.length > 0) { @@ -348,9 +351,20 @@ export class DataService { } } - return this.http.get('/api/v1/portfolio/details', { - params - }); + return this.http + .get('/api/v1/portfolio/details', { + params + }) + .pipe( + map((response) => { + if (response.summary?.firstOrderDate) { + response.summary.firstOrderDate = parseISO( + response.summary.firstOrderDate + ); + } + return response; + }) + ); } public fetchPortfolioPerformance({ @@ -376,18 +390,6 @@ export class DataService { return this.http.get('/api/v1/portfolio/report'); } - public fetchPortfolioSummary(): Observable { - return this.http.get('/api/v1/portfolio/summary').pipe( - map((summary) => { - if (summary.firstOrderDate) { - summary.firstOrderDate = parseISO(summary.firstOrderDate); - } - - return summary; - }) - ); - } - public fetchPositionDetail({ dataSource, symbol diff --git a/libs/common/src/lib/interfaces/portfolio-details.interface.ts b/libs/common/src/lib/interfaces/portfolio-details.interface.ts index cffa3ac0d..d17e4c75e 100644 --- a/libs/common/src/lib/interfaces/portfolio-details.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-details.interface.ts @@ -1,4 +1,7 @@ -import { PortfolioPosition } from '@ghostfolio/common/interfaces'; +import { + PortfolioPosition, + PortfolioSummary +} from '@ghostfolio/common/interfaces'; export interface PortfolioDetails { accounts: { @@ -13,5 +16,6 @@ export interface PortfolioDetails { filteredValueInBaseCurrency?: number; filteredValueInPercentage: number; holdings: { [symbol: string]: PortfolioPosition }; + summary: PortfolioSummary; totalValueInBaseCurrency?: number; } diff --git a/libs/common/src/lib/interfaces/portfolio-summary.interface.ts b/libs/common/src/lib/interfaces/portfolio-summary.interface.ts index b692e9ba9..97a50cfed 100644 --- a/libs/common/src/lib/interfaces/portfolio-summary.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-summary.interface.ts @@ -3,9 +3,10 @@ import { PortfolioPerformance } from './portfolio-performance.interface'; export interface PortfolioSummary extends PortfolioPerformance { annualizedPerformancePercent: number; cash: number; - dividend: number; committedFunds: number; + dividend: number; emergencyFund: number; + excludedAccountsAndActivities: number; fees: number; firstOrderDate: Date; items: number; diff --git a/prisma/migrations/20220924175215_added_is_excluded_to_account/migration.sql b/prisma/migrations/20220924175215_added_is_excluded_to_account/migration.sql new file mode 100644 index 000000000..81245a47a --- /dev/null +++ b/prisma/migrations/20220924175215_added_is_excluded_to_account/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Account" ADD COLUMN "isExcluded" BOOLEAN NOT NULL DEFAULT false; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index bc7ca28f7..11bef3e47 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -27,6 +27,7 @@ model Account { currency String? id String @default(uuid()) isDefault Boolean @default(false) + isExcluded Boolean @default(false) name String? platformId String? updatedAt DateTime @updatedAt From 3006c21b12f50da016e7e4a7fa7feb73b89b243d Mon Sep 17 00:00:00 2001 From: Mitchell Date: Sun, 25 Sep 2022 18:12:33 +0200 Subject: [PATCH 3/4] Add dutch translation (#1291) * Add dutch translation --- angular.json | 17 +- apps/api/src/app/frontend.middleware.ts | 14 + .../pages/account/account-page.component.ts | 2 +- .../src/app/pages/account/account-page.html | 1 + apps/client/src/locales/messages.nl.xlf | 2650 +++++++++++++++++ libs/common/src/lib/helper.ts | 4 +- 6 files changed, 2685 insertions(+), 3 deletions(-) create mode 100644 apps/client/src/locales/messages.nl.xlf diff --git a/angular.json b/angular.json index dd37696ff..991e64c89 100644 --- a/angular.json +++ b/angular.json @@ -140,6 +140,10 @@ "baseHref": "/it/", "localize": ["it"] }, + "development-nl": { + "baseHref": "/nl/", + "localize": ["nl"] + }, "production": { "fileReplacements": [ { @@ -187,6 +191,9 @@ "development-it": { "browserTarget": "client:build:development-it" }, + "development-nl": { + "browserTarget": "client:build:development-nl" + }, "production": { "browserTarget": "client:build:production" } @@ -198,7 +205,11 @@ "browserTarget": "client:build", "includeContext": true, "outputPath": "src/locales", - "targetFiles": ["messages.de.xlf", "messages.it.xlf"] + "targetFiles": [ + "messages.de.xlf", + "messages.it.xlf", + "messages.nl.xlf" + ] } }, "lint": { @@ -225,6 +236,10 @@ "it": { "baseHref": "/it/", "translation": "apps/client/src/locales/messages.it.xlf" + }, + "nl": { + "baseHref": "/nl/", + "translation": "apps/client/src/locales/messages.nl.xlf" } }, "sourceLocale": "en" diff --git a/apps/api/src/app/frontend.middleware.ts b/apps/api/src/app/frontend.middleware.ts index aec14e3ee..876287db4 100644 --- a/apps/api/src/app/frontend.middleware.ts +++ b/apps/api/src/app/frontend.middleware.ts @@ -12,6 +12,7 @@ export class FrontendMiddleware implements NestMiddleware { public indexHtmlDe = ''; public indexHtmlEn = ''; public indexHtmlIt = ''; + public indexHtmlNl = ''; public isProduction: boolean; public constructor( @@ -37,6 +38,10 @@ export class FrontendMiddleware implements NestMiddleware { this.getPathOfIndexHtmlFile('it'), 'utf8' ); + this.indexHtmlNl = fs.readFileSync( + this.getPathOfIndexHtmlFile('nl'), + 'utf8' + ); } catch {} } @@ -75,6 +80,15 @@ export class FrontendMiddleware implements NestMiddleware { rootUrl: this.configurationService.get('ROOT_URL') }) ); + } else if (req.path === '/nl' || req.path.startsWith('/nl/')) { + res.send( + this.interpolate(this.indexHtmlNl, { + featureGraphicPath, + languageCode: 'nl', + path: req.path, + rootUrl: this.configurationService.get('ROOT_URL') + }) + ); } else { res.send( this.interpolate(this.indexHtmlEn, { diff --git a/apps/client/src/app/pages/account/account-page.component.ts b/apps/client/src/app/pages/account/account-page.component.ts index 3f7ec90d5..fee2b2358 100644 --- a/apps/client/src/app/pages/account/account-page.component.ts +++ b/apps/client/src/app/pages/account/account-page.component.ts @@ -54,7 +54,7 @@ export class AccountPageComponent implements OnDestroy, OnInit { public hasPermissionToUpdateViewMode: boolean; public hasPermissionToUpdateUserSettings: boolean; public language = document.documentElement.lang; - public locales = ['de', 'de-CH', 'en-GB', 'en-US', 'it']; + public locales = ['de', 'de-CH', 'en-GB', 'en-US', 'it', 'nl']; public price: number; public priceId: string; public snackBarRef: MatSnackBarRef; diff --git a/apps/client/src/app/pages/account/account-page.html b/apps/client/src/app/pages/account/account-page.html index 12c52f126..aa0983d15 100644 --- a/apps/client/src/app/pages/account/account-page.html +++ b/apps/client/src/app/pages/account/account-page.html @@ -133,6 +133,7 @@ Deutsch English Italiano + Nederlands
diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf new file mode 100644 index 000000000..597b886c0 --- /dev/null +++ b/apps/client/src/locales/messages.nl.xlf @@ -0,0 +1,2650 @@ + + + + + Create Account + Account aanmaken + + apps/client/src/app/pages/register/register-page.html + 27,29 + + + apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html + 2 + + + + The risk of loss in trading can be substantial. It is not advisable to invest money you may need in the short term. + Het risico van verlies in de handel kan aanzienlijk zijn. Het is niet raadzaam om geld te beleggen dat u op korte termijn nodig kunt hebben. + + apps/client/src/app/app.component.html + 55,56 + + + + Grantee + Begunstigde + + apps/client/src/app/components/access-table/access-table.component.html + 10 + + + + Type + Type + + apps/client/src/app/components/access-table/access-table.component.html + 17 + + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 28 + + + apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html + 17 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 13 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 12,14 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 52 + + + + Details + Details + + apps/client/src/app/components/access-table/access-table.component.html + 27 + + + + Revoke + Intrekken + + apps/client/src/app/components/access-table/access-table.component.html + 54 + + + + Do you really want to revoke this granted access? + Wilt u deze verleende toegang echt intrekken? + + apps/client/src/app/components/access-table/access-table.component.ts + 49 + + + + Activities + Activiteiten + + apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html + 33 + + + apps/client/src/app/components/accounts-table/accounts-table.component.html + 58 + + + apps/client/src/app/components/admin-users/admin-users.html + 17 + + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 214 + + + apps/client/src/app/pages/portfolio/portfolio-page.html + 24 + + + apps/client/src/app/pages/portfolio/transactions/transactions-page.html + 4,7 + + + + Name + Naam + + apps/client/src/app/components/accounts-table/accounts-table.component.html + 3 + + + apps/client/src/app/components/positions-table/positions-table.component.html + 36 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 7 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 70,72 + + + + Total + Totaal + + apps/client/src/app/components/accounts-table/accounts-table.component.html + 18 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 47 + + + + Value + Waarde + + apps/client/src/app/components/accounts-table/accounts-table.component.html + 110 + + + apps/client/src/app/components/accounts-table/accounts-table.component.html + 144 + + + apps/client/src/app/components/positions-table/positions-table.component.html + 52 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 221 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 256 + + + + Edit + Bewerken + + apps/client/src/app/components/accounts-table/accounts-table.component.html + 186 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 365 + + + + Delete + Verwijderen + + apps/client/src/app/components/accounts-table/accounts-table.component.html + 194 + + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 132 + + + apps/client/src/app/components/admin-users/admin-users.html + 87 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 381 + + + + Do you really want to delete this account? + Wilt u deze account echt verwijderen? + + apps/client/src/app/components/accounts-table/accounts-table.component.ts + 73 + + + + Delete Jobs + Taken verwijderen + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 21 + + + + Symbol + Symbool + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 29 + + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 24 + + + apps/client/src/app/components/positions-table/positions-table.component.html + 22 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 84 + + + + Data Source + Gegevensbron + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 30 + + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 33 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 86,88 + + + + Attempts + Pogingen + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 31 + + + + Created + Gemaakt + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 32 + + + + Finished + Voltooid + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 33 + + + + Status + Status + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 34 + + + + Asset Profile + Activa Profiel + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 49 + + + + Historical Market Data + Historische marktgegevens + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 54 + + + + View Data + Bekijk gegevens + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 109 + + + + View Stacktrace + Bekijk Stacktrace + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 116 + + + + Delete Job + Taak verwijderen + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 119 + + + + Details for + Details voor + + apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html + 2 + + + + Date + Datum + + apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html + 6 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 92,93 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 40 + + + + Market Price + Marktprijs + + apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html + 26 + + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 75 + + + + Cancel + Annuleren + + apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html + 45 + + + apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html + 25 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 66 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 201,205 + + + apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html + 37 + + + + Save + Opslaan + + apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html + 47 + + + apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html + 32 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 73 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 208,213 + + + + First Activity + Eerste activiteit + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 60 + + + + Activity Count + Activiteitentelling + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 69 + + + apps/client/src/app/components/admin-overview/admin-overview.html + 11 + + + + Historical Data + Historische gegevens + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 78 + + + + Gather Data + Gegevens verzamelen + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 119 + + + + Please add a currency: + Voeg een valuta toe: + + apps/client/src/app/components/admin-overview/admin-overview.component.ts + 106 + + + + Do you really want to delete this coupon? + Wilt u deze coupon echt verwijderen? + + apps/client/src/app/components/admin-overview/admin-overview.component.ts + 120 + + + + Do you really want to delete this currency? + Wilt u deze valuta echt verwijderen? + + apps/client/src/app/components/admin-overview/admin-overview.component.ts + 133 + + + + Do you really want to flush the cache? + Wilt u echt de cache legen? + + apps/client/src/app/components/admin-overview/admin-overview.component.ts + 150 + + + + Please set your system message: + Stel uw systeemboodschap in: + + apps/client/src/app/components/admin-overview/admin-overview.component.ts + 199 + + + + User Count + Aantal gebruikers + + apps/client/src/app/components/admin-overview/admin-overview.html + 7 + + + + per User + per gebruiker + + apps/client/src/app/components/admin-overview/admin-overview.html + 15 + + + + Gather Recent Data + Verzamel recente gegevens + + apps/client/src/app/components/admin-overview/admin-overview.html + 33 + + + + Gather All Data + Alle gegevens verzamelen + + apps/client/src/app/components/admin-overview/admin-overview.html + 46 + + + + Gather Profile Data + Verzamel profielgegevens + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 125 + + + apps/client/src/app/components/admin-overview/admin-overview.html + 60 + + + + Exchange Rates + Wisselkoersen + + apps/client/src/app/components/admin-overview/admin-overview.html + 67 + + + + Add Currency + Valuta toevoegen + + apps/client/src/app/components/admin-overview/admin-overview.html + 106 + + + + System Message + Systeembericht + + apps/client/src/app/components/admin-overview/admin-overview.html + 112 + + + + Set Message + Bericht instellen + + apps/client/src/app/components/admin-overview/admin-overview.html + 134 + + + + Read-only Mode + Alleen lezen + + apps/client/src/app/components/admin-overview/admin-overview.html + 139 + + + + Coupons + Coupons + + apps/client/src/app/components/admin-overview/admin-overview.html + 152 + + + + Add + Toevoegen + + apps/client/src/app/components/admin-overview/admin-overview.html + 183 + + + + Housekeeping + Huishouding + + apps/client/src/app/components/admin-overview/admin-overview.html + 190 + + + + Flush Cache + Cache legen + + apps/client/src/app/components/admin-overview/admin-overview.html + 194 + + + + Do you really want to delete this user? + Wilt u deze gebruiker echt verwijderen? + + apps/client/src/app/components/admin-users/admin-users.component.ts + 59 + + + + User + Gebruiker + + apps/client/src/app/components/admin-users/admin-users.html + 9 + + + apps/client/src/app/components/header/header.component.html + 145 + + + + Registration + Registratie + + apps/client/src/app/components/admin-users/admin-users.html + 11 + + + + Engagement per Day + Betrokkenheid per dag + + apps/client/src/app/components/admin-users/admin-users.html + 20 + + + + Last Request + Laatste verzoek + + apps/client/src/app/components/admin-users/admin-users.html + 22 + + + + Current Market Mood + Huidige marktstemming + + apps/client/src/app/components/fear-and-greed-index/fear-and-greed-index.component.html + 12 + + + + Overview + Overzicht + + apps/client/src/app/components/header/header.component.html + 21 + + + apps/client/src/app/components/header/header.component.html + 157 + + + + Portfolio + Portefeuille + + apps/client/src/app/components/header/header.component.html + 32 + + + apps/client/src/app/components/header/header.component.html + 167 + + + apps/client/src/app/pages/portfolio/portfolio-page.html + 2 + + + + Accounts + Accounts + + apps/client/src/app/components/admin-users/admin-users.html + 14 + + + apps/client/src/app/components/header/header.component.html + 43 + + + apps/client/src/app/components/header/header.component.html + 175 + + + apps/client/src/app/pages/accounts/accounts-page.html + 4 + + + + Admin Control + Beheerderscontrole + + apps/client/src/app/components/header/header.component.html + 55 + + + apps/client/src/app/components/header/header.component.html + 192 + + + + Resources + Middelen + + apps/client/src/app/components/header/header.component.html + 66 + + + apps/client/src/app/components/header/header.component.html + 203 + + + apps/client/src/app/pages/resources/resources-page.html + 4 + + + + Pricing + Prijzen + + apps/client/src/app/components/header/header.component.html + 80 + + + apps/client/src/app/components/header/header.component.html + 214 + + + apps/client/src/app/components/header/header.component.html + 268 + + + + About + Over + + apps/client/src/app/components/header/header.component.html + 91 + + + apps/client/src/app/components/header/header.component.html + 257 + + + + Me + Ik + + apps/client/src/app/components/header/header.component.html + 127 + + + + My Ghostfolio + Mijn Ghostfolio + + apps/client/src/app/components/header/header.component.html + 183 + + + + About Ghostfolio + Over Ghostfolio + + apps/client/src/app/components/header/header.component.html + 222 + + + + Features + Kenmerken + + apps/client/src/app/components/header/header.component.html + 246 + + + + Markets + Markten + + apps/client/src/app/components/header/header.component.html + 280 + + + apps/client/src/app/components/home-market/home-market.html + 2 + + + + Get Started + Aan de slag + + apps/client/src/app/pages/public/public-page.html + 137 + + + + Sign in + Aanmelden + + apps/client/src/app/components/header/header.component.ts + 112 + + + apps/client/src/app/pages/webauthn/webauthn-page-routing.module.ts + 6 + + + + Oops! Incorrect Security Token. + Oeps! Onjuiste beveiligingstoken. + + apps/client/src/app/components/header/header.component.ts + 126 + + + + Manage Activities + Activiteiten beheren + + apps/client/src/app/components/home-holdings/home-holdings.html + 30 + + + apps/client/src/app/pages/portfolio/holdings/holdings-page.html + 31 + + + + Last Days + Laatste Dagen + + apps/client/src/app/components/home-market/home-market.html + 6 + + + + Summary + Samenvatting + + apps/client/src/app/components/home-summary/home-summary.html + 6 + + + + Security Token + Beveiligingstoken + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 10,14 + + + apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html + 10 + + + + or + of + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 20,22 + + + apps/client/src/app/pages/register/register-page.html + 31,33 + + + apps/client/src/app/pages/webauthn/webauthn-page.html + 28 + + + + Sign in with Internet Identity + Aanmelden met Internet Identity + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 30,32 + + + + Sign in with Google + Aanmelden met Google + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 37,43 + + + + Stay signed in + Aangemeld blijven + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 46,52 + + + + Sign in + Aanmelden + + apps/client/src/app/components/header/header.component.html + 289 + + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 56,60 + + + + Time in Market + Tijd in de markt + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 3 + + + + Buy + Kopen + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 12 + + + + Sell + Verkopen + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 23 + + + + Investment + Belegging + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 40 + + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 117 + + + + Absolute Gross Performance + Absoluut bruto rendement + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 51 + + + + Gross Performance (TWR) + Bruto resultaat (TWR) + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 62 + + + + Fees for + Transactiekosten voor + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 77,80 + + + + {VAR_PLURAL, plural, =1 {transaction} other {transactions}} + {VAR_PLURAL, meervoud, =1 {transaction} other {transactions}} + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 78,79 + + + + Absolute Net Performance + Absolute Netto Prestatie + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 95 + + + + Net Performance (TWR) + Netto resultaat (TWR) + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 106 + + + + Total Assets + Totaal Activa + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 122 + + + + Valuables + Kostbaarheden + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 134 + + + + Emergency Fund + Noodfonds + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 145 + + + + Buying Power + Koopkracht + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 165 + + + + Net Worth + Netto Waarde + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 179 + + + + Annualized Performance + Jaarlijks rendement + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 190 + + + + Dividend + Dividend + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 206 + + + + Please enter the amount of your emergency fund: + Voer het bedrag van uw noodfonds in: + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts + 52 + + + + Sectors + Sectoren + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 187 + + + apps/client/src/app/pages/public/public-page.html + 45 + + + + Countries + Landen + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 198 + + + + Tags + Tags + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 234 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 184,186 + + + + Report Data Glitch + Gegevensstoring melden + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 249 + + + + Allocation + Toewijzing + + apps/client/src/app/components/positions-table/positions-table.component.html + 72 + + + + Performance + Prestaties + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 55 + + + apps/client/src/app/components/positions-table/positions-table.component.html + 91 + + + + Show all + Toon alle + + apps/client/src/app/components/positions-table/positions-table.component.html + 137 + + + + Today + Vandaag + + apps/client/src/app/components/toggle/toggle.component.ts + 21 + + + + YTD + YTD + + apps/client/src/app/components/toggle/toggle.component.ts + 22 + + + + 1Y + 1J + + apps/client/src/app/components/toggle/toggle.component.ts + 23 + + + + 5Y + 5J + + apps/client/src/app/components/toggle/toggle.component.ts + 24 + + + + Max + Max + + apps/client/src/app/components/toggle/toggle.component.ts + 25 + + + + This feature requires a subscription. + Voor deze functie is een abonnement vereist. + + apps/client/src/app/core/http-response.interceptor.ts + 67 + + + + Upgrade Plan + Upgrade plan + + apps/client/src/app/core/http-response.interceptor.ts + 69 + + + + Okay + OkƩ + + apps/client/src/app/core/http-response.interceptor.ts + 89 + + + + About + Over + + apps/client/src/app/pages/about/about-page-routing.module.ts + 12 + + + + Privacy Policy + Privacybeleid + + apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html + 4 + + + + Blog + Blog + + apps/client/src/app/pages/blog/blog-page.html + 4 + + + + Changelog & License + Changelog & licentie + + apps/client/src/app/pages/about/changelog/changelog-page-routing.module.ts + 12 + + + + Changelog + Changelog + + apps/client/src/app/pages/about/changelog/changelog-page.html + 4 + + + + License + Licentie + + apps/client/src/app/pages/about/changelog/changelog-page.html + 15 + + + + Privacy Policy + Privacybeleid + + apps/client/src/app/pages/about/privacy-policy/privacy-policy-page-routing.module.ts + 12 + + + + My Ghostfolio + Mijn Ghostfolio + + apps/client/src/app/pages/account/account-page-routing.module.ts + 12 + + + + Please enter your coupon code: + Voer uw couponcode in: + + apps/client/src/app/pages/account/account-page.component.ts + 225 + + + + Could not redeem coupon code + Kon kortingscode niet inwisselen + + apps/client/src/app/pages/account/account-page.component.ts + 235 + + + + Coupon code has been redeemed + Couponcode is ingewisseld + + apps/client/src/app/pages/account/account-page.component.ts + 247 + + + + Reload + Herladen + + apps/client/src/app/pages/account/account-page.component.ts + 248 + + + + Do you really want to remove this sign in method? + Wilt u deze aanmeldingsmethode echt verwijderen? + + apps/client/src/app/pages/account/account-page.component.ts + 294 + + + + Account + Account + + apps/client/src/app/pages/account/account-page.html + 4 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 25,27 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 282 + + + + Membership + Lidmaatschap + + apps/client/src/app/pages/account/account-page.html + 15 + + + + Upgrade + Upgrade + + apps/client/src/app/pages/account/account-page.html + 37 + + + + per year + per jaar + + apps/client/src/app/pages/account/account-page.html + 48 + + + + Try Premium + Probeer Premium + + apps/client/src/app/pages/account/account-page.html + 56 + + + + Redeem Coupon + Coupon inwisselen + + apps/client/src/app/pages/account/account-page.html + 68 + + + + Presenter View + Presentatorweergave + + apps/client/src/app/pages/account/account-page.html + 75 + + + + Hides sensitive values such as absolute performances and quantities. + Verbergt gevoelige waarden zoals absolute prestaties en hoeveelheden. + + apps/client/src/app/pages/account/account-page.html + 76,79 + + + + Base Currency + Basisvaluta + + apps/client/src/app/pages/account/account-page.html + 94 + + + + Locale + Locale + + apps/client/src/app/pages/account/account-page.html + 135 + + + + Date and number format + Formaat datum en getal + + apps/client/src/app/pages/account/account-page.html + 137 + + + + View Mode + Weergavemodus + + apps/client/src/app/pages/account/account-page.html + 160 + + + + Sign in with fingerprint + Aanmelden met vingerafdruk + + apps/client/src/app/pages/account/account-page.html + 181 + + + + User ID + Gebruikers-ID + + apps/client/src/app/pages/account/account-page.html + 208 + + + + Granted Access + Verleende toegang + + apps/client/src/app/pages/account/account-page.html + 217 + + + + Grant access + Toegang verlenen + + apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html + 2 + + + + Public + Openbaar + + apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html + 19 + + + + Accounts + Rekeningen + + apps/client/src/app/pages/accounts/accounts-page-routing.module.ts + 12 + + + + Update account + Rkening bijwerken + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 2 + + + + Add account + Rekening toevoegen + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 3 + + + + Cash + Contant geld + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 15 + + + + Securities + Effecten + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 16 + + + + Currency + Valuta + + apps/client/src/app/components/accounts-table/accounts-table.component.html + 23 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 22 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 76,77 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 109 + + + + Cash Balance + Geldbalans + + apps/client/src/app/components/accounts-table/accounts-table.component.html + 76 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 32 + + + + Platform + Platform + + apps/client/src/app/components/accounts-table/accounts-table.component.html + 35 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 44 + + + + Account ID + Rekening-ID + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 55 + + + + Admin Control + Beheerderscontrole + + apps/client/src/app/pages/admin/admin-page-routing.module.ts + 23 + + + + Blog + Blog + + apps/client/src/app/pages/blog/blog-page-routing.module.ts + 12 + + + + As you are already logged in, you cannot access the demo account. + Aangezien u al ingelogd bent, heeft u geen toegang tot de demo-account. + + apps/client/src/app/pages/demo/demo-page.component.ts + 31 + + + + FAQ + FAQ + + apps/client/src/app/pages/faq/faq-page-routing.module.ts + 12 + + + + Features + Kenmerken + + apps/client/src/app/pages/features/features-page-routing.module.ts + 12 + + + + Overview + Overzicht + + apps/client/src/app/pages/home/home-page-routing.module.ts + 23 + + + apps/client/src/app/pages/zen/zen-page-routing.module.ts + 19 + + + + Markets + Markten + + apps/client/src/app/pages/markets/markets-page-routing.module.ts + 12 + + + + Allocations + Toewijzingen + + apps/client/src/app/pages/portfolio/allocations/allocations-page-routing.module.ts + 12 + + + + Allocations + Toewijzingen + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 4 + + + apps/client/src/app/pages/portfolio/portfolio-page.html + 44 + + + + By Account + Per rekening + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 33 + + + + By Currency + Per valuta + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 58 + + + + By Asset Class + Per activaklasse + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 86 + + + + By Holding + Per participatie + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 114 + + + + By Sector + Per Sector + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 142 + + + + By Continent + Per continent + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 171 + + + + By Country + Per land + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 199 + + + + Regions + Regio's + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 230 + + + apps/client/src/app/pages/public/public-page.html + 76 + + + + Analysis + Analyse + + apps/client/src/app/pages/portfolio/analysis/analysis-page-routing.module.ts + 12 + + + + Analysis + Analyse + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 2 + + + apps/client/src/app/pages/portfolio/portfolio-page.html + 69 + + + + Investment Timeline + Tijdlijn investeringen + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 105 + + + + Top + Top + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 26 + + + + Bottom + Onder + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 62 + + + + FIRE + FIRE + + apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts + 12 + + + + FIRE + FIRE + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 4 + + + apps/client/src/app/pages/portfolio/portfolio-page.html + 115 + + + + Calculator + Rekenmachine + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 6 + + + + 4% Rule + 4% regel + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 20 + + + + Holdings + Participaties + + apps/client/src/app/pages/portfolio/holdings/holdings-page-routing.module.ts + 12 + + + + Holdings + Participaties + + apps/client/src/app/pages/portfolio/holdings/holdings-page.html + 4 + + + apps/client/src/app/pages/portfolio/portfolio-page.html + 6 + + + apps/client/src/app/pages/public/public-page.html + 14 + + + + Get an overview of your current holdings. + Een overzicht van uw huidige participaties. + + apps/client/src/app/pages/portfolio/portfolio-page.html + 7,9 + + + + Open Holdings + Open Participaties + + apps/client/src/app/pages/portfolio/portfolio-page.html + 16 + + + + Manage your activities: stocks, ETFs, cryptocurrencies, dividend, and valuables. + Beheer uw activiteiten: aandelen, ETF's, cryptocurrencies, dividend en kostbaarheden. + + apps/client/src/app/pages/portfolio/portfolio-page.html + 25,28 + + + + Open Activities + Activiteiten openen + + apps/client/src/app/pages/portfolio/portfolio-page.html + 35 + + + + Check the allocations of your portfolio by account, asset class, currency, sector and region. + Controleer de allocaties van uw portefeuille per rekening, activaklasse, valuta, sector en regio. + + apps/client/src/app/pages/portfolio/portfolio-page.html + 50,53 + + + + Open Allocations + Open Allocaties + + apps/client/src/app/pages/portfolio/portfolio-page.html + 60 + + + + Ghostfolio Analysis visualizes your portfolio and shows your top and bottom performers. + Ghostfolio Analysis visualiseert uw portefeuille en toont uw top- en bodempresteerders. + + apps/client/src/app/pages/portfolio/portfolio-page.html + 75,78 + + + + Open Analysis + Open Analyse + + apps/client/src/app/pages/portfolio/portfolio-page.html + 85 + + + + Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. + Ghostfolio X-ray gebruikt statische analyse om potentiƫle problemen en risico's in uw portefeuille te identificeren. + + apps/client/src/app/pages/portfolio/portfolio-page.html + 100,103 + + + + Open X-ray + Open X-ray + + apps/client/src/app/pages/portfolio/portfolio-page.html + 106 + + + + Ghostfolio FIRE calculates metrics for the Financial Independence, Retire Early lifestyle. + Ghostfolio FIRE berekent statistieken voor de Financial Independence, Retire Early levensstijl. + + apps/client/src/app/pages/portfolio/portfolio-page.html + 121,124 + + + + Open FIRE + Open FIRE + + apps/client/src/app/pages/portfolio/portfolio-page.html + 127 + + + + Update activity + Activiteit bijwerken + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 7,8 + + + + Add activity + Activiteit toevoegen + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 8,11 + + + + BUY + KOPEN + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 14,15 + + + + DIVIDEND + DIVIDEND + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 15,17 + + + + ITEM + ITEM + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 16,18 + + + + SELL + VERKOPEN + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 17,21 + + + + Name, symbol or ISIN + Naam, symbool of ISIN + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 37,40 + + + + Quantity + Hoeveelheid + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 107 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 106,107 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 130 + + + + Unit Price + Prijs per eenheid + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 112,113 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 159 + + + + Fee + Transactiekosten + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 131,132 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 188 + + + + Note + Opmerking + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 140,143 + + + + Asset Class + Activaklasse + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 42 + + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 145 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 154,156 + + + + Activities + Activiteiten + + apps/client/src/app/pages/portfolio/transactions/transactions-page-routing.module.ts + 12 + + + + Importing data... + Gegevens importeren... + + apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts + 191 + + + + Import has been completed + Import is voltooid + + apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts + 337 + + + + Pricing + Prijzen + + apps/client/src/app/pages/pricing/pricing-page-routing.module.ts + 12 + + + + Portfolio + Portefeuille + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts + 111 + + + apps/client/src/app/pages/public/public-page-routing.module.ts + 12 + + + + Currencies + Valuta's + + apps/client/src/app/pages/public/public-page.html + 30 + + + + Continents + Continenten + + apps/client/src/app/pages/public/public-page.html + 60 + + + + Ghostfolio empowers you to keep track of your wealth. + Ghostfolio stelt u in staat om uw vermogen bij te houden. + + apps/client/src/app/pages/public/public-page.html + 132,134 + + + + Registration + Registratie + + apps/client/src/app/pages/register/register-page-routing.module.ts + 12 + + + + Continue with Internet Identity + Ga verder met Internet Identity + + apps/client/src/app/pages/register/register-page.html + 41,43 + + + + Continue with Google + Verder met Google + + apps/client/src/app/pages/register/register-page.html + 48,53 + + + + Copy to clipboard + Kopieer naar klembord + + apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html + 26 + + + + I agree to have stored my Security Token from above in a secure place. If I lose it, I cannot get my account back. + Ik ga ermee akkoord dat ik mijn Security Token van hierboven op een veilige plaats heb opgeslagen. Als ik het verlies, kan ik mijn account niet terug krijgen. + + apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html + 31,34 + + + + Agree and continue + Akkoord en doorgaan + + apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html + 44 + + + + Resources + Bronnen + + apps/client/src/app/pages/resources/resources-page-routing.module.ts + 12 + + + + Oops, authentication has failed. + Oeps, authenticatie is mislukt. + + apps/client/src/app/pages/webauthn/webauthn-page.html + 18 + + + + Try again + Probeer opnieuw + + apps/client/src/app/pages/webauthn/webauthn-page.html + 26 + + + + Go back to Home Page + Ga terug naar de startpagina + + apps/client/src/app/pages/webauthn/webauthn-page.html + 30 + + + + Draft + Ontwerp + + libs/ui/src/lib/activities-table/activities-table.component.html + 95 + + + + Import Activities + Activiteiten importeren + + libs/ui/src/lib/activities-table/activities-table.component.html + 319 + + + + Export Activities + Activiteiten exporteren + + libs/ui/src/lib/activities-table/activities-table.component.html + 329 + + + + Export Drafts as ICS + Concepten exporteren als ICS + + libs/ui/src/lib/activities-table/activities-table.component.html + 339 + + + + Clone + Kloon + + libs/ui/src/lib/activities-table/activities-table.component.html + 369 + + + + Export Draft as ICS + Concepten exporteren als ICS + + libs/ui/src/lib/activities-table/activities-table.component.html + 377 + + + + Do you really want to delete this activity? + Wilt u deze activiteit echt verwijderen? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 134 + + + + Index + Index + + libs/ui/src/lib/benchmark/benchmark.component.html + 3 + + + + Change from All Time High + Verandering van All Time High + + libs/ui/src/lib/benchmark/benchmark.component.html + 12 + + + + from ATH + van ATH + + libs/ui/src/lib/benchmark/benchmark.component.html + 14 + + + + Savings Rate + Spaarquote + + libs/ui/src/lib/fire-calculator/fire-calculator.component.html + 10 + + + + per month + per maand + + libs/ui/src/lib/fire-calculator/fire-calculator.component.html + 17 + + + + Investment Horizon + Investeringshorizon + + libs/ui/src/lib/fire-calculator/fire-calculator.component.html + 21 + + + + years + jaren + + libs/ui/src/lib/fire-calculator/fire-calculator.component.html + 23 + + + + Annual Interest Rate + Jaarlijkse rentevoet + + libs/ui/src/lib/fire-calculator/fire-calculator.component.html + 27 + + + + Beta + Beta + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 5 + + + apps/client/src/app/pages/account/account-page.html + 116 + + + + Time to add your first activity. + Tijd om uw eerste activiteit toe te voegen. + + libs/ui/src/lib/no-transactions-info/no-transactions-info.component.html + 12 + + + + Language + Taal + + apps/client/src/app/pages/account/account-page.html + 115 + + + + Data Management + Gegevensbeheer + + apps/client/src/app/components/admin-overview/admin-overview.html + 20 + + + + Get started + Aan de slag + + apps/client/src/app/components/header/header.component.html + 297 + + + + This feature is currently unavailable. + Deze functie is momenteel niet beschikbaar. + + apps/client/src/app/core/http-response.interceptor.ts + 59 + + + + Oops! Something went wrong. + Oeps! Er ging iets mis. + + apps/client/src/app/core/http-response.interceptor.ts + 86 + + + + Please try again later. + Probeer het later nog eens. + + apps/client/src/app/core/http-response.interceptor.ts + 61 + + + apps/client/src/app/core/http-response.interceptor.ts + 88 + + + + Change + Verandering + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 44 + + + + Developed Markets + Ontwikkelde markten + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 256 + + + apps/client/src/app/pages/public/public-page.html + 90 + + + + Asset Sub Class + Activa Subklasse + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 51 + + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 154 + + + apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html + 169,171 + + + + Average Unit Price + Gemiddelde prijs per eenheid + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 65 + + + + Maximum Price + Maximale prijs + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 97 + + + + Other Markets + Andere markten + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 274 + + + apps/client/src/app/pages/public/public-page.html + 108 + + + + Emerging Markets + Opkomende markten + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 265 + + + apps/client/src/app/pages/public/public-page.html + 99 + + + + Sector + Sector + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 169 + + + + Country + Land + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 181 + + + + Minimum Price + Minimale prijs + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 86 + + + + First Buy Date + Eerste aankoopdatum + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 127 + + + + Transactions + Transacties + + apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html + 136 + + + + Projected Total Amount + Verwacht totaalbedrag + + libs/ui/src/lib/fire-calculator/fire-calculator.component.html + 44 + + + + Savings + Besparingen + + libs/ui/src/lib/fire-calculator/fire-calculator.component.ts + 296 + + + + Accumulating + Accumuleren + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 39 + + + + Initial + Aanvankelijk + + apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts + 57 + + + + Interest + Rente + + libs/ui/src/lib/fire-calculator/fire-calculator.component.ts + 286 + + + + Deposit + Storting + + apps/client/src/app/components/investment-chart/investment-chart.component.ts + 132 + + + libs/ui/src/lib/fire-calculator/fire-calculator.component.ts + 276 + + + + Current + Huidige + + apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts + 58 + + + + Monthly + Maandelijks + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 38 + + + + Sectors Count + Sectoren tellen + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 96 + + + + Countries Count + Landen Telling + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 87 + + + + Fear + Angst + + apps/client/src/app/components/home-market/home-market.component.ts + 24 + + + + Greed + Hebzucht + + apps/client/src/app/components/home-market/home-market.component.ts + 25 + + + + Filter by account or tag... + Filter op account of tag... + + apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts + 136 + + + apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts + 87 + + + + Filter by... + Filter op... + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 128 + + + + Filter by account, currency, symbol or type... + Filter op rekening, valuta, symbool of type... + + libs/ui/src/lib/activities-table/activities-table.component.ts + 291 + + + + Hello, has shared a Portfolio with you! + Hallo, heeft een Portefeuille met u gedeeld! + + apps/client/src/app/pages/public/public-page.html + 4,7 + + + + Alias + Alias + + apps/client/src/app/components/access-table/access-table.component.html + 3 + + + apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html + 6 + + + + Experimental Features + Experimentele functies + + apps/client/src/app/pages/account/account-page.html + 196 + + + + Benchmark + Benchmark + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts + 120 + + + + Benchmarks + Benchmarks + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 4 + + + + Compare with... + Vergelijk met... + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 14 + + + + Proportion of Net Worth + Verhouding van nettowaarde + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 17 + + + + + diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 693e2183b..790fb8ac0 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -1,7 +1,7 @@ import * as currencies from '@dinero.js/currencies'; import { DataSource } from '@prisma/client'; import { getDate, getMonth, getYear, parse, subDays } from 'date-fns'; -import { de, it } from 'date-fns/locale'; +import { de, it, nl } from 'date-fns/locale'; import { ghostfolioScraperApiSymbolPrefix, locale } from './config'; import { Benchmark } from './interfaces'; @@ -77,6 +77,8 @@ export function getDateFnsLocale(aLanguageCode: string) { return de; } else if (aLanguageCode === 'it') { return it; + } else if (aLanguageCode === 'nl') { + return nl; } return undefined; From 333b63bfe22fae0c80208b511b7c891404064bb8 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 25 Sep 2022 21:46:19 +0200 Subject: [PATCH 4/4] Release 1.198.0 (#1294) --- CHANGELOG.md | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fd6c7129..e54a1f590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 1.198.0 - 25.09.2022 ### Added - Added support to exclude an account from analysis +- Set up the language localization for Nederlands (`nl`) ## 1.197.0 - 24.09.2022 diff --git a/package.json b/package.json index a11af30b0..88bf4b784 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "1.197.0", + "version": "1.198.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "scripts": {