diff --git a/CHANGELOG.md b/CHANGELOG.md index 608354fda..3d1c6a01e 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 the logic to create and update accounts + ## 0.97.0 - 01.05.2021 ### Added diff --git a/apps/api/src/app/account/account.controller.ts b/apps/api/src/app/account/account.controller.ts index 581e52c0b..78a1a416b 100644 --- a/apps/api/src/app/account/account.controller.ts +++ b/apps/api/src/app/account/account.controller.ts @@ -17,7 +17,7 @@ import { } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; -import { Account as AccountModel } from '@prisma/client'; +import { Account as AccountModel, Order } from '@prisma/client'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { AccountService } from './account.service'; @@ -47,6 +47,23 @@ export class AccountController { ); } + const account = await this.accountService.accountWithOrders( + { + id_userId: { + id, + userId: this.request.user.id + } + }, + { Order: true } + ); + + if (account?.isDefault || account?.Order.length > 0) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + return this.accountService.deleteAccount( { id_userId: { @@ -69,8 +86,8 @@ export class AccountController { ); let accounts = await this.accountService.accounts({ - include: { Platform: true }, - orderBy: { name: 'desc' }, + include: { Order: true, Platform: true }, + orderBy: { name: 'asc' }, where: { userId: impersonationUserId || this.request.user.id } }); @@ -166,6 +183,13 @@ export class AccountController { } }); + if (!originalAccount) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + if (data.platformId) { const platformId = data.platformId; delete data.platformId; diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index 92d39695c..a18d388e0 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -1,6 +1,6 @@ import { PrismaService } from '@ghostfolio/api/services/prisma.service'; import { Injectable } from '@nestjs/common'; -import { Account, Prisma } from '@prisma/client'; +import { Account, Order, Prisma } from '@prisma/client'; import { RedisCacheService } from '../redis-cache/redis-cache.service'; @@ -19,6 +19,20 @@ export class AccountService { }); } + public async accountWithOrders( + accountWhereUniqueInput: Prisma.AccountWhereUniqueInput, + accountInclude: Prisma.AccountInclude + ): Promise< + Account & { + Order?: Order[]; + } + > { + return this.prisma.account.findUnique({ + include: accountInclude, + where: accountWhereUniqueInput + }); + } + public async accounts(params: { include?: Prisma.AccountInclude; skip?: number; diff --git a/apps/api/src/app/account/create-account.dto.ts b/apps/api/src/app/account/create-account.dto.ts index 9134a3f1d..c5e5275ab 100644 --- a/apps/api/src/app/account/create-account.dto.ts +++ b/apps/api/src/app/account/create-account.dto.ts @@ -1,35 +1,14 @@ -import { Currency, DataSource, Type } from '@prisma/client'; -import { IsISO8601, IsNumber, IsString, ValidateIf } from 'class-validator'; +import { AccountType } from '@prisma/client'; +import { IsString, ValidateIf } from 'class-validator'; export class CreateAccountDto { @IsString() - accountId: string; + accountType: AccountType; @IsString() - currency: Currency; - - @IsString() - dataSource: DataSource; - - @IsISO8601() - date: string; - - @IsNumber() - fee: number; + name: string; @IsString() @ValidateIf((object, value) => value !== null) platformId: string | null; - - @IsNumber() - quantity: number; - - @IsString() - symbol: string; - - @IsString() - type: Type; - - @IsNumber() - unitPrice: number; } diff --git a/apps/api/src/app/account/interfaces/order-with-platform.type.ts b/apps/api/src/app/account/interfaces/order-with-platform.type.ts deleted file mode 100644 index 10cc70e1a..000000000 --- a/apps/api/src/app/account/interfaces/order-with-platform.type.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Order, Platform } from '@prisma/client'; - -export type OrderWithPlatform = Order & { Platform?: Platform }; diff --git a/apps/api/src/app/account/update-account.dto.ts b/apps/api/src/app/account/update-account.dto.ts index 9c31ed5df..ee5e21a9e 100644 --- a/apps/api/src/app/account/update-account.dto.ts +++ b/apps/api/src/app/account/update-account.dto.ts @@ -1,38 +1,17 @@ -import { Currency, DataSource, Type } from '@prisma/client'; -import { IsISO8601, IsNumber, IsString, ValidateIf } from 'class-validator'; +import { AccountType } from '@prisma/client'; +import { IsString, ValidateIf } from 'class-validator'; export class UpdateAccountDto { @IsString() - accountId: string; + accountType: AccountType; @IsString() - currency: Currency; + id: string; @IsString() - dataSource: DataSource; - - @IsISO8601() - date: string; - - @IsNumber() - fee: number; + name: string; @IsString() @ValidateIf((object, value) => value !== null) platformId: string | null; - - @IsString() - id: string; - - @IsNumber() - quantity: number; - - @IsString() - symbol: string; - - @IsString() - type: Type; - - @IsNumber() - unitPrice: number; } diff --git a/apps/api/src/app/experimental/experimental.service.ts b/apps/api/src/app/experimental/experimental.service.ts index 30d0a9ff9..5594a8c91 100644 --- a/apps/api/src/app/experimental/experimental.service.ts +++ b/apps/api/src/app/experimental/experimental.service.ts @@ -7,7 +7,7 @@ import { Injectable } from '@nestjs/common'; import { Currency, Type } from '@prisma/client'; import { parseISO } from 'date-fns'; -import { OrderWithPlatform } from '../order/interfaces/order-with-platform.type'; +import { OrderWithAccount } from '../order/interfaces/order-with-account.type'; import { CreateOrderDto } from './create-order.dto'; import { Data } from './interfaces/data.interface'; @@ -33,7 +33,7 @@ export class ExperimentalService { aDate: Date, aBaseCurrency: Currency ): Promise { - const ordersWithPlatform: OrderWithPlatform[] = aOrders.map((order) => { + const ordersWithPlatform: OrderWithAccount[] = aOrders.map((order) => { return { ...order, accountId: undefined, diff --git a/apps/api/src/app/order/interfaces/order-with-account.type.ts b/apps/api/src/app/order/interfaces/order-with-account.type.ts new file mode 100644 index 000000000..d1f5ac552 --- /dev/null +++ b/apps/api/src/app/order/interfaces/order-with-account.type.ts @@ -0,0 +1,3 @@ +import { Account, Order } from '@prisma/client'; + +export type OrderWithAccount = Order & { Account?: Account }; diff --git a/apps/api/src/app/order/interfaces/order-with-platform.type.ts b/apps/api/src/app/order/interfaces/order-with-platform.type.ts deleted file mode 100644 index 10cc70e1a..000000000 --- a/apps/api/src/app/order/interfaces/order-with-platform.type.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Order, Platform } from '@prisma/client'; - -export type OrderWithPlatform = Order & { Platform?: Platform }; diff --git a/apps/api/src/app/order/order.controller.ts b/apps/api/src/app/order/order.controller.ts index 0c459b2a7..fa6d2724d 100644 --- a/apps/api/src/app/order/order.controller.ts +++ b/apps/api/src/app/order/order.controller.ts @@ -184,6 +184,13 @@ export class OrderController { } }); + if (!originalOrder) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + const date = parseISO(data.date); const accountId = data.accountId; diff --git a/apps/api/src/app/order/order.service.ts b/apps/api/src/app/order/order.service.ts index f12e3aa73..ede9ab9e4 100644 --- a/apps/api/src/app/order/order.service.ts +++ b/apps/api/src/app/order/order.service.ts @@ -5,7 +5,7 @@ import { Order, Prisma } from '@prisma/client'; import { CacheService } from '../cache/cache.service'; import { RedisCacheService } from '../redis-cache/redis-cache.service'; -import { OrderWithPlatform } from './interfaces/order-with-platform.type'; +import { OrderWithAccount } from './interfaces/order-with-account.type'; @Injectable() export class OrderService { @@ -31,7 +31,7 @@ export class OrderService { cursor?: Prisma.OrderWhereUniqueInput; where?: Prisma.OrderWhereInput; orderBy?: Prisma.OrderOrderByInput; - }): Promise { + }): Promise { const { include, skip, take, cursor, where, orderBy } = params; return this.prisma.order.findMany({ diff --git a/apps/api/src/app/portfolio/interfaces/portfolio-position.interface.ts b/apps/api/src/app/portfolio/interfaces/portfolio-position.interface.ts index f3e24dfe6..4f3530940 100644 --- a/apps/api/src/app/portfolio/interfaces/portfolio-position.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/portfolio-position.interface.ts @@ -2,6 +2,9 @@ import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces'; import { Currency } from '@prisma/client'; export interface PortfolioPosition { + accounts: { + [name: string]: { current: number; original: number }; + }; currency: Currency; exchange?: string; grossPerformance: number; @@ -13,9 +16,6 @@ export interface PortfolioPosition { marketPrice: number; marketState: MarketState; name: string; - platforms: { - [name: string]: { current: number; original: number }; - }; quantity: number; sector?: string; shareCurrent: number; diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 449badab1..de5f9bf92 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -185,11 +185,11 @@ export class PortfolioController { portfolioPosition.investment = portfolioPosition.investment / totalInvestment; - for (const [platform, { current, original }] of Object.entries( - portfolioPosition.platforms + for (const [account, { current, original }] of Object.entries( + portfolioPosition.accounts )) { - portfolioPosition.platforms[platform].current = current / totalValue; - portfolioPosition.platforms[platform].original = + portfolioPosition.accounts[account].current = current / totalValue; + portfolioPosition.accounts[account].original = original / totalInvestment; } diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 1e1b51248..51965663e 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -73,7 +73,7 @@ export class PortfolioService { // Get portfolio from database const orders = await this.orderService.orders({ include: { - Platform: true + Account: true }, orderBy: { date: 'asc' }, where: { userId: aUserId } diff --git a/apps/api/src/models/order.ts b/apps/api/src/models/order.ts index 28c31d1e3..7c719edbc 100644 --- a/apps/api/src/models/order.ts +++ b/apps/api/src/models/order.ts @@ -1,27 +1,27 @@ -import { Currency, Platform } from '@prisma/client'; +import { Account, Currency, Platform } from '@prisma/client'; import { v4 as uuidv4 } from 'uuid'; import { IOrder } from '../services/interfaces/interfaces'; import { OrderType } from './order-type'; export class Order { + private account: Account; private currency: Currency; private fee: number; private date: string; private id: string; private quantity: number; - private platform: Platform; private symbol: string; private total: number; private type: OrderType; private unitPrice: number; public constructor(data: IOrder) { + this.account = data.account; this.currency = data.currency; this.fee = data.fee; this.date = data.date; this.id = data.id || uuidv4(); - this.platform = data.platform; this.quantity = data.quantity; this.symbol = data.symbol; this.type = data.type; @@ -30,6 +30,10 @@ export class Order { this.total = this.quantity * data.unitPrice; } + public getAccount() { + return this.account; + } + public getCurrency() { return this.currency; } @@ -46,10 +50,6 @@ export class Order { return this.id; } - public getPlatform() { - return this.platform; - } - public getQuantity() { return this.quantity; } diff --git a/apps/api/src/models/portfolio.ts b/apps/api/src/models/portfolio.ts index 9d13923a7..f867363a4 100644 --- a/apps/api/src/models/portfolio.ts +++ b/apps/api/src/models/portfolio.ts @@ -23,7 +23,7 @@ import { cloneDeep, isEmpty } from 'lodash'; import * as roundTo from 'round-to'; import { UserWithSettings } from '../app/interfaces/user-with-settings'; -import { OrderWithPlatform } from '../app/order/interfaces/order-with-platform.type'; +import { OrderWithAccount } from '../app/order/interfaces/order-with-account.type'; import { DateRange } from '../app/portfolio/interfaces/date-range.type'; import { PortfolioPerformance } from '../app/portfolio/interfaces/portfolio-performance.interface'; import { PortfolioPosition } from '../app/portfolio/interfaces/portfolio-position.interface'; @@ -34,14 +34,14 @@ import { IOrder } from '../services/interfaces/interfaces'; import { RulesService } from '../services/rules.service'; import { PortfolioInterface } from './interfaces/portfolio.interface'; import { Order } from './order'; +import { AccountClusterRiskCurrentInvestment } from './rules/account-cluster-risk/current-investment'; +import { AccountClusterRiskInitialInvestment } from './rules/account-cluster-risk/initial-investment'; +import { AccountClusterRiskSingleAccount } from './rules/account-cluster-risk/single-account'; import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from './rules/currency-cluster-risk/base-currency-current-investment'; import { CurrencyClusterRiskBaseCurrencyInitialInvestment } from './rules/currency-cluster-risk/base-currency-initial-investment'; import { CurrencyClusterRiskCurrentInvestment } from './rules/currency-cluster-risk/current-investment'; import { CurrencyClusterRiskInitialInvestment } from './rules/currency-cluster-risk/initial-investment'; import { FeeRatioInitialInvestment } from './rules/fees/fee-ratio-initial-investment'; -import { PlatformClusterRiskCurrentInvestment } from './rules/platform-cluster-risk/current-investment'; -import { PlatformClusterRiskInitialInvestment } from './rules/platform-cluster-risk/initial-investment'; -import { PlatformClusterRiskSinglePlatform } from './rules/platform-cluster-risk/single-platform'; export class Portfolio implements PortfolioInterface { private orders: Order[] = []; @@ -119,11 +119,11 @@ export class Portfolio implements PortfolioInterface { }): Portfolio { orders.forEach( ({ + account, currency, fee, date, id, - platform, quantity, symbol, type, @@ -131,11 +131,11 @@ export class Portfolio implements PortfolioInterface { }) => { this.orders.push( new Order({ + account, currency, fee, date, id, - platform, quantity, symbol, type, @@ -202,7 +202,7 @@ export class Portfolio implements PortfolioInterface { const data = await this.dataProviderService.get(symbols); symbols.forEach((symbol) => { - const platforms: PortfolioPosition['platforms'] = {}; + const accounts: PortfolioPosition['accounts'] = {}; const [portfolioItem] = portfolioItems; const ordersBySymbol = this.getOrders().filter((order) => { @@ -227,15 +227,15 @@ export class Portfolio implements PortfolioInterface { originalValueOfSymbol *= -1; } - if (platforms[orderOfSymbol.getPlatform()?.name || 'Other']?.current) { - platforms[ - orderOfSymbol.getPlatform()?.name || 'Other' + if (accounts[orderOfSymbol.getAccount()?.name || 'Other']?.current) { + accounts[ + orderOfSymbol.getAccount()?.name || 'Other' ].current += currentValueOfSymbol; - platforms[ - orderOfSymbol.getPlatform()?.name || 'Other' + accounts[ + orderOfSymbol.getAccount()?.name || 'Other' ].original += originalValueOfSymbol; } else { - platforms[orderOfSymbol.getPlatform()?.name || 'Other'] = { + accounts[orderOfSymbol.getAccount()?.name || 'Other'] = { current: currentValueOfSymbol, original: originalValueOfSymbol }; @@ -276,7 +276,7 @@ export class Portfolio implements PortfolioInterface { details[symbol] = { ...data[symbol], - platforms, + accounts, symbol, grossPerformance: roundTo( portfolioItemsNow.positions[symbol].quantity * (now - before), @@ -396,32 +396,32 @@ export class Portfolio implements PortfolioInterface { return { rules: { - currencyClusterRisk: await this.rulesService.evaluate( + accountClusterRisk: await this.rulesService.evaluate( this, [ - new CurrencyClusterRiskBaseCurrencyInitialInvestment( + new AccountClusterRiskCurrentInvestment( this.exchangeRateDataService ), - new CurrencyClusterRiskBaseCurrencyCurrentInvestment( + new AccountClusterRiskInitialInvestment( this.exchangeRateDataService ), - new CurrencyClusterRiskInitialInvestment( - this.exchangeRateDataService - ), - new CurrencyClusterRiskCurrentInvestment( - this.exchangeRateDataService - ) + new AccountClusterRiskSingleAccount(this.exchangeRateDataService) ], { baseCurrency: this.user.Settings.currency } ), - platformClusterRisk: await this.rulesService.evaluate( + currencyClusterRisk: await this.rulesService.evaluate( this, [ - new PlatformClusterRiskSinglePlatform(this.exchangeRateDataService), - new PlatformClusterRiskInitialInvestment( + new CurrencyClusterRiskBaseCurrencyInitialInvestment( + this.exchangeRateDataService + ), + new CurrencyClusterRiskBaseCurrencyCurrentInvestment( this.exchangeRateDataService ), - new PlatformClusterRiskCurrentInvestment( + new CurrencyClusterRiskInitialInvestment( + this.exchangeRateDataService + ), + new CurrencyClusterRiskCurrentInvestment( this.exchangeRateDataService ) ], @@ -522,17 +522,17 @@ export class Portfolio implements PortfolioInterface { return isFinite(value) ? value : null; } - public async setOrders(aOrders: OrderWithPlatform[]) { + public async setOrders(aOrders: OrderWithAccount[]) { this.orders = []; // Map data aOrders.forEach((order) => { this.orders.push( new Order({ + account: order.Account, currency: order.currency, date: order.date.toISOString(), fee: order.fee, - platform: order.Platform, quantity: order.quantity, symbol: order.symbol, type: order.type, diff --git a/apps/api/src/models/rules/platform-cluster-risk/current-investment.ts b/apps/api/src/models/rules/account-cluster-risk/current-investment.ts similarity index 72% rename from apps/api/src/models/rules/platform-cluster-risk/current-investment.ts rename to apps/api/src/models/rules/account-cluster-risk/current-investment.ts index b9fb3efa7..bafa05f69 100644 --- a/apps/api/src/models/rules/platform-cluster-risk/current-investment.ts +++ b/apps/api/src/models/rules/account-cluster-risk/current-investment.ts @@ -3,7 +3,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate- import { Rule } from '../../rule'; -export class PlatformClusterRiskCurrentInvestment extends Rule { +export class AccountClusterRiskCurrentInvestment extends Rule { public constructor(public exchangeRateDataService: ExchangeRateDataService) { super(exchangeRateDataService, { name: 'Current Investment' @@ -18,24 +18,22 @@ export class PlatformClusterRiskCurrentInvestment extends Rule { } ) { const ruleSettings = - aRuleSettingsMap[PlatformClusterRiskCurrentInvestment.name]; + aRuleSettingsMap[AccountClusterRiskCurrentInvestment.name]; - const platforms: { + const accounts: { [symbol: string]: Pick & { investment: number; }; } = {}; Object.values(aPositions).forEach((position) => { - for (const [platform, { current }] of Object.entries( - position.platforms - )) { - if (platforms[platform]?.investment) { - platforms[platform].investment += current; + for (const [account, { current }] of Object.entries(position.accounts)) { + if (accounts[account]?.investment) { + accounts[account].investment += current; } else { - platforms[platform] = { + accounts[account] = { investment: current, - name: platform + name: account }; } } @@ -44,17 +42,17 @@ export class PlatformClusterRiskCurrentInvestment extends Rule { let maxItem; let totalInvestment = 0; - Object.values(platforms).forEach((platform) => { + Object.values(accounts).forEach((account) => { if (!maxItem) { - maxItem = platform; + maxItem = account; } // Calculate total investment - totalInvestment += platform.investment; + totalInvestment += account.investment; // Find maximum - if (platform.investment > maxItem?.investment) { - maxItem = platform; + if (account.investment > maxItem?.investment) { + maxItem = account; } }); diff --git a/apps/api/src/models/rules/platform-cluster-risk/initial-investment.ts b/apps/api/src/models/rules/account-cluster-risk/initial-investment.ts similarity index 82% rename from apps/api/src/models/rules/platform-cluster-risk/initial-investment.ts rename to apps/api/src/models/rules/account-cluster-risk/initial-investment.ts index 1bd83d7e0..1913a6d6a 100644 --- a/apps/api/src/models/rules/platform-cluster-risk/initial-investment.ts +++ b/apps/api/src/models/rules/account-cluster-risk/initial-investment.ts @@ -3,7 +3,7 @@ import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-dat import { Rule } from '../../rule'; -export class PlatformClusterRiskInitialInvestment extends Rule { +export class AccountClusterRiskInitialInvestment extends Rule { public constructor(public exchangeRateDataService: ExchangeRateDataService) { super(exchangeRateDataService, { name: 'Initial Investment' @@ -18,7 +18,7 @@ export class PlatformClusterRiskInitialInvestment extends Rule { } ) { const ruleSettings = - aRuleSettingsMap[PlatformClusterRiskInitialInvestment.name]; + aRuleSettingsMap[AccountClusterRiskInitialInvestment.name]; const platforms: { [symbol: string]: Pick & { @@ -27,15 +27,13 @@ export class PlatformClusterRiskInitialInvestment extends Rule { } = {}; Object.values(aPositions).forEach((position) => { - for (const [platform, { original }] of Object.entries( - position.platforms - )) { - if (platforms[platform]?.investment) { - platforms[platform].investment += original; + for (const [account, { original }] of Object.entries(position.accounts)) { + if (platforms[account]?.investment) { + platforms[account].investment += original; } else { - platforms[platform] = { + platforms[account] = { investment: original, - name: platform + name: account }; } } diff --git a/apps/api/src/models/rules/platform-cluster-risk/single-platform.ts b/apps/api/src/models/rules/account-cluster-risk/single-account.ts similarity index 62% rename from apps/api/src/models/rules/platform-cluster-risk/single-platform.ts rename to apps/api/src/models/rules/account-cluster-risk/single-account.ts index 531453909..24d13c95d 100644 --- a/apps/api/src/models/rules/platform-cluster-risk/single-platform.ts +++ b/apps/api/src/models/rules/account-cluster-risk/single-account.ts @@ -3,33 +3,33 @@ import { ExchangeRateDataService } from 'apps/api/src/services/exchange-rate-dat import { Rule } from '../../rule'; -export class PlatformClusterRiskSinglePlatform extends Rule { +export class AccountClusterRiskSingleAccount extends Rule { public constructor(public exchangeRateDataService: ExchangeRateDataService) { super(exchangeRateDataService, { - name: 'Single Platform' + name: 'Single Account' }); } public evaluate(positions: { [symbol: string]: PortfolioPosition }) { - const platforms: string[] = []; + const accounts: string[] = []; Object.values(positions).forEach((position) => { - for (const [platform] of Object.entries(position.platforms)) { - if (!platforms.includes(platform)) { - platforms.push(platform); + for (const [account] of Object.entries(position.accounts)) { + if (!accounts.includes(account)) { + accounts.push(account); } } }); - if (platforms.length === 1) { + if (accounts.length === 1) { return { - evaluation: `All your investment is managed by a single platform`, + evaluation: `All your investment is managed by a single account`, value: false }; } return { - evaluation: `Your investment is managed by ${platforms.length} platforms`, + evaluation: `Your investment is managed by ${accounts.length} accounts`, value: true }; } diff --git a/apps/api/src/services/interfaces/interfaces.ts b/apps/api/src/services/interfaces/interfaces.ts index 62e69fa4f..3200b5290 100644 --- a/apps/api/src/services/interfaces/interfaces.ts +++ b/apps/api/src/services/interfaces/interfaces.ts @@ -1,4 +1,4 @@ -import { Currency, DataSource, Platform } from '@prisma/client'; +import { Account, Currency, DataSource, Platform } from '@prisma/client'; import { OrderType } from '../../models/order-type'; @@ -33,11 +33,11 @@ export const Type = { }; export interface IOrder { + account: Account; currency: Currency; date: string; fee: number; id?: string; - platform: Platform; quantity: number; symbol: string; type: OrderType; diff --git a/apps/api/src/services/rules.service.ts b/apps/api/src/services/rules.service.ts index 39bd9e163..99e657481 100644 --- a/apps/api/src/services/rules.service.ts +++ b/apps/api/src/services/rules.service.ts @@ -2,14 +2,14 @@ import { Injectable } from '@nestjs/common'; import { Portfolio } from '../models/portfolio'; import { Rule } from '../models/rule'; +import { AccountClusterRiskCurrentInvestment } from '../models/rules/account-cluster-risk/current-investment'; +import { AccountClusterRiskInitialInvestment } from '../models/rules/account-cluster-risk/initial-investment'; +import { AccountClusterRiskSingleAccount } from '../models/rules/account-cluster-risk/single-account'; import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from '../models/rules/currency-cluster-risk/base-currency-current-investment'; import { CurrencyClusterRiskBaseCurrencyInitialInvestment } from '../models/rules/currency-cluster-risk/base-currency-initial-investment'; import { CurrencyClusterRiskCurrentInvestment } from '../models/rules/currency-cluster-risk/current-investment'; import { CurrencyClusterRiskInitialInvestment } from '../models/rules/currency-cluster-risk/initial-investment'; import { FeeRatioInitialInvestment } from '../models/rules/fees/fee-ratio-initial-investment'; -import { PlatformClusterRiskCurrentInvestment } from '../models/rules/platform-cluster-risk/current-investment'; -import { PlatformClusterRiskInitialInvestment } from '../models/rules/platform-cluster-risk/initial-investment'; -import { PlatformClusterRiskSinglePlatform } from '../models/rules/platform-cluster-risk/single-platform'; @Injectable() export class RulesService { @@ -39,6 +39,17 @@ export class RulesService { private getDefaultRuleSettings(aUserSettings: { baseCurrency: string }) { return { + [AccountClusterRiskCurrentInvestment.name]: { + baseCurrency: aUserSettings.baseCurrency, + isActive: true, + threshold: 0.5 + }, + [AccountClusterRiskInitialInvestment.name]: { + baseCurrency: aUserSettings.baseCurrency, + isActive: true, + threshold: 0.5 + }, + [AccountClusterRiskSingleAccount.name]: { isActive: true }, [CurrencyClusterRiskBaseCurrencyInitialInvestment.name]: { baseCurrency: aUserSettings.baseCurrency, isActive: true @@ -61,18 +72,7 @@ export class RulesService { baseCurrency: aUserSettings.baseCurrency, isActive: true, threshold: 0.01 - }, - [PlatformClusterRiskCurrentInvestment.name]: { - baseCurrency: aUserSettings.baseCurrency, - isActive: true, - threshold: 0.5 - }, - [PlatformClusterRiskInitialInvestment.name]: { - baseCurrency: aUserSettings.baseCurrency, - isActive: true, - threshold: 0.5 - }, - [PlatformClusterRiskSinglePlatform.name]: { isActive: true } + } }; } } diff --git a/apps/client/src/app/components/accounts-table/accounts-table.component.html b/apps/client/src/app/components/accounts-table/accounts-table.component.html index 5796d82ac..8fd19efe1 100644 --- a/apps/client/src/app/components/accounts-table/accounts-table.component.html +++ b/apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -64,13 +64,25 @@ - + + Transactions + + {{ element.Order?.length }} + + + diff --git a/apps/client/src/app/components/accounts-table/accounts-table.component.ts b/apps/client/src/app/components/accounts-table/accounts-table.component.ts index a35751172..7ee09a12d 100644 --- a/apps/client/src/app/components/accounts-table/accounts-table.component.ts +++ b/apps/client/src/app/components/accounts-table/accounts-table.component.ts @@ -13,7 +13,7 @@ import { MatDialog } from '@angular/material/dialog'; import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; import { ActivatedRoute, Router } from '@angular/router'; -import { Order as OrderModel } from '@prisma/client'; +import { Account as AccountModel } from '@prisma/client'; import { Subject, Subscription } from 'rxjs'; @Component({ @@ -23,18 +23,18 @@ import { Subject, Subscription } from 'rxjs'; styleUrls: ['./accounts-table.component.scss'] }) export class AccountsTableComponent implements OnChanges, OnDestroy, OnInit { - @Input() accounts: OrderModel[]; + @Input() accounts: AccountModel[]; @Input() baseCurrency: string; @Input() deviceType: string; @Input() locale: string; @Input() showActions: boolean; @Output() accountDeleted = new EventEmitter(); - @Output() accountToUpdate = new EventEmitter(); + @Output() accountToUpdate = new EventEmitter(); @ViewChild(MatSort) sort: MatSort; - public dataSource: MatTableDataSource = new MatTableDataSource(); + public dataSource: MatTableDataSource = new MatTableDataSource(); public displayedColumns = []; public isLoading = true; public routeQueryParams: Subscription; @@ -50,14 +50,14 @@ export class AccountsTableComponent implements OnChanges, OnDestroy, OnInit { public ngOnInit() {} public ngOnChanges() { - this.displayedColumns = ['account', 'type', 'platform']; - - this.isLoading = true; + this.displayedColumns = ['account', 'type', 'platform', 'transactions']; if (this.showActions) { this.displayedColumns.push('actions'); } + this.isLoading = true; + if (this.accounts) { this.dataSource = new MatTableDataSource(this.accounts); this.dataSource.sort = this.sort; @@ -74,7 +74,7 @@ export class AccountsTableComponent implements OnChanges, OnDestroy, OnInit { } } - public onUpdateAccount(aAccount: OrderModel) { + public onUpdateAccount(aAccount: AccountModel) { this.accountToUpdate.emit(aAccount); } diff --git a/apps/client/src/app/components/header/header.component.html b/apps/client/src/app/components/header/header.component.html index d48791d07..9f1497436 100644 --- a/apps/client/src/app/components/header/header.component.html +++ b/apps/client/src/app/components/header/header.component.html @@ -163,7 +163,7 @@ i18n mat-menu-item [ngClass]="{ 'font-weight-bold': currentRoute === 'account' }" - >AccountGhostfolio Account { - const transaction: UpdateOrderDto = data?.transaction; + const account: UpdateAccountDto = data?.account; - if (transaction) { - this.dataService.putAccount(transaction).subscribe({ + if (account) { + this.dataService.putAccount(account).subscribe({ next: () => { this.fetchAccounts(); } @@ -179,19 +165,10 @@ export class AccountsPageComponent implements OnInit { private openCreateAccountDialog(): void { const dialogRef = this.dialog.open(CreateOrUpdateAccountDialog, { data: { - accounts: this.user?.accounts, - transaction: { - accountId: this.user?.accounts.find((account) => { - return account.isDefault; - })?.id, - currency: null, - date: new Date(), - fee: 0, - platformId: null, - quantity: null, - symbol: null, - type: 'BUY', - unitPrice: null + account: { + accountType: AccountType.SECURITIES, + name: null, + platformId: null } }, height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', @@ -199,10 +176,10 @@ export class AccountsPageComponent implements OnInit { }); dialogRef.afterClosed().subscribe((data: any) => { - const transaction: UpdateOrderDto = data?.transaction; + const account: CreateAccountDto = data?.account; - if (transaction) { - this.dataService.postAccount(transaction).subscribe({ + if (account) { + this.dataService.postAccount(account).subscribe({ next: () => { this.fetchAccounts(); } diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts index 24a7df79b..1ab5accb3 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts @@ -1,47 +1,25 @@ -import { - ChangeDetectionStrategy, - ChangeDetectorRef, - Component, - Inject -} from '@angular/core'; -import { FormControl, Validators } from '@angular/forms'; -import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { Currency } from '@prisma/client'; -import { Observable, Subject } from 'rxjs'; -import { - debounceTime, - distinctUntilChanged, - startWith, - switchMap, - takeUntil -} from 'rxjs/operators'; +import { Subject } from 'rxjs'; import { DataService } from '../../../services/data.service'; import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces'; @Component({ host: { class: 'h-100' }, - selector: 'create-or-update-account-dialog', + selector: 'gf-create-or-update-account-dialog', changeDetection: ChangeDetectionStrategy.OnPush, styleUrls: ['./create-or-update-account-dialog.scss'], templateUrl: 'create-or-update-account-dialog.html' }) export class CreateOrUpdateAccountDialog { public currencies: Currency[] = []; - public filteredLookupItems: Observable; - public isLoading = false; public platforms: { id: string; name: string }[]; - public searchSymbolCtrl = new FormControl( - this.data.transaction.symbol, - Validators.required - ); private unsubscribeSubject = new Subject(); public constructor( - private cd: ChangeDetectorRef, private dataService: DataService, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateAccountDialogParams @@ -52,51 +30,12 @@ export class CreateOrUpdateAccountDialog { this.currencies = currencies; this.platforms = platforms; }); - - this.filteredLookupItems = this.searchSymbolCtrl.valueChanges.pipe( - startWith(''), - debounceTime(400), - distinctUntilChanged(), - switchMap((aQuery: string) => { - if (aQuery) { - return this.dataService.fetchSymbols(aQuery); - } - - return []; - }) - ); } public onCancel(): void { this.dialogRef.close(); } - public onUpdateSymbol(event: MatAutocompleteSelectedEvent) { - this.isLoading = true; - this.data.transaction.symbol = event.option.value; - - this.dataService - .fetchSymbolItem(this.data.transaction.symbol) - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ currency, dataSource, marketPrice }) => { - this.data.transaction.currency = currency; - this.data.transaction.dataSource = dataSource; - this.data.transaction.unitPrice = marketPrice; - - this.isLoading = false; - - this.cd.markForCheck(); - }); - } - - public onUpdateSymbolByTyping(value: string) { - this.data.transaction.currency = null; - this.data.transaction.dataSource = null; - this.data.transaction.unitPrice = null; - - this.data.transaction.symbol = value; - } - public ngOnDestroy() { this.unsubscribeSubject.next(); this.unsubscribeSubject.complete(); 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 bfadfd8a0..985bd135a 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 @@ -1,145 +1,25 @@
-

Update account

-

Add account

+

Update account

+

Add account

- Symbol or ISIN - - - - - {{ lookupItem.symbol | gfSymbol }}{{ lookupItem.name }} - - - - + Name +
Type - - BUY - SELL - - -
-
- - Currency - - {{ currency }} - - -
-
- - Data Source - - -
-
- - Date - - - - -
-
- - Fee - - -
-
- - Quantity - - -
-
- - Unit Price - - -
-
- - Account - - {{ account.name }} + + SECURITIES
Platform - + {{ platform.name }} Save 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 f0990f4a7..4d7b0da77 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 @@ -1,15 +1,11 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButtonModule } from '@angular/material/button'; -import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSelectModule } from '@angular/material/select'; -import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { CreateOrUpdateAccountDialog } from './create-or-update-account-dialog.component'; @@ -18,15 +14,11 @@ import { CreateOrUpdateAccountDialog } from './create-or-update-account-dialog.c exports: [], imports: [ CommonModule, - GfSymbolModule, FormsModule, - MatAutocompleteModule, MatButtonModule, - MatDatepickerModule, MatDialogModule, MatFormFieldModule, MatInputModule, - MatProgressSpinnerModule, MatSelectModule, ReactiveFormsModule ], diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/interfaces/interfaces.ts b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/interfaces/interfaces.ts index 51cb3bdda..ffe4f14f6 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/interfaces/interfaces.ts @@ -1,9 +1,5 @@ import { Account } from '@prisma/client'; -import { Order } from '../../interfaces/order.interface'; - export interface CreateOrUpdateAccountDialogParams { - accountId: string; - accounts: Account[]; - transaction: Order; + account: Account; } diff --git a/apps/client/src/app/pages/accounts/interfaces/order.interface.ts b/apps/client/src/app/pages/accounts/interfaces/order.interface.ts deleted file mode 100644 index 12f6626a2..000000000 --- a/apps/client/src/app/pages/accounts/interfaces/order.interface.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Currency, DataSource } from '@prisma/client'; - -export interface Order { - accountId: string; - currency: Currency; - dataSource: DataSource; - date: Date; - fee: number; - id: string; - quantity: number; - platformId: string; - symbol: string; - type: string; - unitPrice: number; -} diff --git a/apps/client/src/app/pages/analysis/analysis-page.component.ts b/apps/client/src/app/pages/analysis/analysis-page.component.ts index 795882943..9f889e1e7 100644 --- a/apps/client/src/app/pages/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/analysis/analysis-page.component.ts @@ -16,6 +16,9 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./analysis-page.scss'] }) export class AnalysisPageComponent implements OnDestroy, OnInit { + public accounts: { + [symbol: string]: Pick & { value: number }; + }; public deviceType: string; public period = 'current'; public periodOptions: ToggleOption[] = [ @@ -23,9 +26,6 @@ export class AnalysisPageComponent implements OnDestroy, OnInit { { label: 'Current', value: 'current' } ]; public hasImpersonationId: boolean; - public platforms: { - [symbol: string]: Pick & { value: number }; - }; public portfolioItems: PortfolioItem[]; public portfolioPositions: { [symbol: string]: PortfolioPosition }; public positions: { [symbol: string]: any }; @@ -95,7 +95,7 @@ export class AnalysisPageComponent implements OnDestroy, OnInit { }, aPeriod: string ) { - this.platforms = {}; + this.accounts = {}; this.positions = {}; this.positionsArray = []; @@ -113,16 +113,16 @@ export class AnalysisPageComponent implements OnDestroy, OnInit { }; this.positionsArray.push(position); - for (const [platform, { current, original }] of Object.entries( - position.platforms + for (const [account, { current, original }] of Object.entries( + position.accounts )) { - if (this.platforms[platform]?.value) { - this.platforms[platform].value += + if (this.accounts[account]?.value) { + this.accounts[account].value += aPeriod === 'original' ? original : current; } else { - this.platforms[platform] = { + this.accounts[account] = { value: aPeriod === 'original' ? original : current, - name: platform + name: account }; } } diff --git a/apps/client/src/app/pages/analysis/analysis-page.html b/apps/client/src/app/pages/analysis/analysis-page.html index 77f9b249c..b5336589e 100644 --- a/apps/client/src/app/pages/analysis/analysis-page.html +++ b/apps/client/src/app/pages/analysis/analysis-page.html @@ -36,7 +36,7 @@
- By Platform + By Account diff --git a/apps/client/src/app/pages/report/report-page.component.ts b/apps/client/src/app/pages/report/report-page.component.ts index 7d08956eb..8687798fa 100644 --- a/apps/client/src/app/pages/report/report-page.component.ts +++ b/apps/client/src/app/pages/report/report-page.component.ts @@ -10,9 +10,9 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./report-page.scss'] }) export class ReportPageComponent implements OnInit { + public accountClusterRiskRules: PortfolioReportRule[]; public currencyClusterRiskRules: PortfolioReportRule[]; public feeRules: PortfolioReportRule[]; - public platformClusterRiskRules: PortfolioReportRule[]; private unsubscribeSubject = new Subject(); @@ -32,11 +32,11 @@ export class ReportPageComponent implements OnInit { .fetchPortfolioReport() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((portfolioReport) => { + this.accountClusterRiskRules = + portfolioReport.rules['accountClusterRisk'] || null; this.currencyClusterRiskRules = portfolioReport.rules['currencyClusterRisk'] || null; this.feeRules = portfolioReport.rules['fees'] || null; - this.platformClusterRiskRules = - portfolioReport.rules['platformClusterRisk'] || null; this.cd.markForCheck(); }); diff --git a/apps/client/src/app/pages/report/report-page.html b/apps/client/src/app/pages/report/report-page.html index 57e29a545..6b093119b 100644 --- a/apps/client/src/app/pages/report/report-page.html +++ b/apps/client/src/app/pages/report/report-page.html @@ -18,8 +18,8 @@
-

Platform Cluster Risks

- +

Account Cluster Risks

+

Fees

diff --git a/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html b/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html index 829be07c7..3476ca15e 100644 --- a/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html +++ b/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html @@ -121,11 +121,10 @@ />
-
+
Account
-
- - Platform - - - {{ platform.name }} - - -
diff --git a/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/interfaces/interfaces.ts b/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/interfaces/interfaces.ts index 66a62eecc..89223e404 100644 --- a/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/interfaces/interfaces.ts @@ -1,6 +1,4 @@ -import { Account } from '@prisma/client'; - -import { Order } from '../../interfaces/order.interface'; +import { Account, Order } from '@prisma/client'; export interface CreateOrUpdateTransactionDialogParams { accountId: string; diff --git a/apps/client/src/app/pages/transactions/interfaces/order.interface.ts b/apps/client/src/app/pages/transactions/interfaces/order.interface.ts deleted file mode 100644 index 12f6626a2..000000000 --- a/apps/client/src/app/pages/transactions/interfaces/order.interface.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Currency, DataSource } from '@prisma/client'; - -export interface Order { - accountId: string; - currency: Currency; - dataSource: DataSource; - date: Date; - fee: number; - id: string; - quantity: number; - platformId: string; - symbol: string; - type: string; - unitPrice: number; -} diff --git a/apps/client/src/app/pages/transactions/transactions-page.component.ts b/apps/client/src/app/pages/transactions/transactions-page.component.ts index 10b522316..7e9304d2b 100644 --- a/apps/client/src/app/pages/transactions/transactions-page.component.ts +++ b/apps/client/src/app/pages/transactions/transactions-page.component.ts @@ -1,6 +1,7 @@ import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router } from '@angular/router'; +import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto'; import { UpdateOrderDto } from '@ghostfolio/api/app/order/update-order.dto'; import { User } from '@ghostfolio/api/app/user/interfaces/user.interface'; import { DataService } from '@ghostfolio/client/services/data.service'; @@ -199,7 +200,7 @@ export class TransactionsPageComponent implements OnInit { }); dialogRef.afterClosed().subscribe((data: any) => { - const transaction: UpdateOrderDto = data?.transaction; + const transaction: CreateOrderDto = data?.transaction; if (transaction) { this.dataService.postOrder(transaction).subscribe({ diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index fec978c49..d7232227d 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -1,9 +1,11 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Access } from '@ghostfolio/api/app/access/interfaces/access.interface'; +import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto'; import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto'; import { AdminData } from '@ghostfolio/api/app/admin/interfaces/admin-data.interface'; import { InfoItem } from '@ghostfolio/api/app/info/interfaces/info-item.interface'; +import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto'; import { UpdateOrderDto } from '@ghostfolio/api/app/order/update-order.dto'; import { PortfolioItem } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-item.interface'; import { PortfolioOverview } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-overview.interface'; @@ -20,6 +22,7 @@ import { UserItem } from '@ghostfolio/api/app/user/interfaces/user-item.interfac import { User } from '@ghostfolio/api/app/user/interfaces/user.interface'; import { UpdateUserSettingsDto } from '@ghostfolio/api/app/user/update-user-settings.dto'; import { Order as OrderModel } from '@prisma/client'; +import { Account as AccountModel } from '@prisma/client'; @Injectable({ providedIn: 'root' @@ -30,7 +33,7 @@ export class DataService { public constructor(private http: HttpClient) {} public fetchAccounts() { - return this.http.get('/api/account'); + return this.http.get('/api/account'); } public fetchAdminData() { @@ -117,11 +120,11 @@ export class DataService { return this.http.get(`/api/auth/anonymous/${accessToken}`); } - public postAccount(aAccount: UpdateAccountDto) { + public postAccount(aAccount: CreateAccountDto) { return this.http.post(`/api/account`, aAccount); } - public postOrder(aOrder: UpdateOrderDto) { + public postOrder(aOrder: CreateOrderDto) { return this.http.post(`/api/order`, aOrder); } diff --git a/libs/helper/src/lib/permissions.ts b/libs/helper/src/lib/permissions.ts index 5a2eb313f..8964d770d 100644 --- a/libs/helper/src/lib/permissions.ts +++ b/libs/helper/src/lib/permissions.ts @@ -32,9 +32,12 @@ export function getPermissions(aRole: Role): string[] { case 'ADMIN': return [ permissions.accessAdminControl, + permissions.createAccount, permissions.createOrder, + permissions.deleteAccount, permissions.deleteOrder, permissions.readForeignPortfolio, + permissions.updateAccount, permissions.updateOrder, permissions.updateUserSettings ]; @@ -44,8 +47,11 @@ export function getPermissions(aRole: Role): string[] { case 'USER': return [ + permissions.createAccount, permissions.createOrder, + permissions.deleteAccount, permissions.deleteOrder, + permissions.updateAccount, permissions.updateOrder, permissions.updateUserSettings ];