Browse Source

fix(api): move getCashOrders to order service

pull/5650/head
KenTandrian 3 weeks ago
parent
commit
7ebef0baf4
  1. 114
      apps/api/src/app/order/order.service.ts
  2. 119
      apps/api/src/app/portfolio/portfolio.service.ts

114
apps/api/src/app/order/order.service.ts

@ -1,7 +1,10 @@
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface';
import { AssetProfileChangedEvent } from '@ghostfolio/api/events/asset-profile-changed.event'; import { AssetProfileChangedEvent } from '@ghostfolio/api/events/asset-profile-changed.event';
import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event';
import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service';
@ -16,6 +19,7 @@ import {
import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; import { getAssetProfileIdentifier } from '@ghostfolio/common/helper';
import { import {
ActivitiesResponse, ActivitiesResponse,
Activity,
AssetProfileIdentifier, AssetProfileIdentifier,
EnhancedSymbolProfile, EnhancedSymbolProfile,
Filter Filter
@ -43,7 +47,9 @@ import { v4 as uuidv4 } from 'uuid';
export class OrderService { export class OrderService {
public constructor( public constructor(
private readonly accountService: AccountService, private readonly accountService: AccountService,
private readonly accountBalanceService: AccountBalanceService,
private readonly dataGatheringService: DataGatheringService, private readonly dataGatheringService: DataGatheringService,
private readonly dataProviderService: DataProviderService,
private readonly eventEmitter: EventEmitter2, private readonly eventEmitter: EventEmitter2,
private readonly exchangeRateDataService: ExchangeRateDataService, private readonly exchangeRateDataService: ExchangeRateDataService,
private readonly prismaService: PrismaService, private readonly prismaService: PrismaService,
@ -317,6 +323,96 @@ export class OrderService {
return count; return count;
} }
public async getCashOrders({
cashDetails,
userCurrency,
userId
}: {
cashDetails: CashDetails;
userCurrency: string;
userId: string;
}): Promise<ActivitiesResponse> {
const activities: Activity[] = [];
for (const account of cashDetails.accounts) {
const { balances } = await this.accountBalanceService.getAccountBalances({
filters: [{ id: account.id, type: 'ACCOUNT' }],
userCurrency,
userId
});
let currentBalance = 0;
let currentBalanceInBaseCurrency = 0;
for (const balanceItem of balances) {
const syntheticActivityTemplate: Activity = {
userId,
accountId: account.id,
accountUserId: account.userId,
comment: account.name,
createdAt: new Date(balanceItem.date),
currency: account.currency,
date: new Date(balanceItem.date),
fee: 0,
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
id: balanceItem.id,
isDraft: false,
quantity: 1,
SymbolProfile: {
activitiesCount: 0,
assetClass: 'LIQUIDITY',
assetSubClass: 'CASH',
countries: [],
createdAt: new Date(balanceItem.date),
currency: account.currency,
dataSource:
this.dataProviderService.getDataSourceForExchangeRates(),
holdings: [],
id: account.currency,
isActive: true,
sectors: [],
symbol: account.currency,
updatedAt: new Date(balanceItem.date)
},
symbolProfileId: account.currency,
type: 'BUY',
unitPrice: 1,
unitPriceInAssetProfileCurrency: 1,
updatedAt: new Date(balanceItem.date),
valueInBaseCurrency: 0,
value: 0
};
if (currentBalance < balanceItem.value) {
// BUY
activities.push({
...syntheticActivityTemplate,
type: 'BUY',
value: balanceItem.value - currentBalance,
valueInBaseCurrency:
balanceItem.valueInBaseCurrency - currentBalanceInBaseCurrency
});
} else if (currentBalance > balanceItem.value) {
// SELL
activities.push({
...syntheticActivityTemplate,
type: 'SELL',
value: currentBalance - balanceItem.value,
valueInBaseCurrency:
currentBalanceInBaseCurrency - balanceItem.valueInBaseCurrency
});
}
currentBalance = balanceItem.value;
currentBalanceInBaseCurrency = balanceItem.valueInBaseCurrency;
}
}
return {
activities,
count: activities.length
};
}
public async getLatestOrder({ dataSource, symbol }: AssetProfileIdentifier) { public async getLatestOrder({ dataSource, symbol }: AssetProfileIdentifier) {
return this.prismaService.order.findFirst({ return this.prismaService.order.findFirst({
orderBy: { orderBy: {
@ -620,12 +716,28 @@ export class OrderService {
userCurrency: string; userCurrency: string;
userId: string; userId: string;
}) { }) {
return this.getOrders({ const cashDetails = await this.accountService.getCashDetails({
filters,
userId,
currency: userCurrency
});
const cashOrders = await this.getCashOrders({
cashDetails,
userCurrency,
userId
});
const nonCashOrders = await this.getOrders({
filters, filters,
userCurrency, userCurrency,
userId, userId,
withExcludedAccountsAndActivities: false // TODO withExcludedAccountsAndActivities: false // TODO
}); });
return {
activities: [...nonCashOrders.activities, ...cashOrders.activities],
count: nonCashOrders.count + cashOrders.count
};
} }
public async getStatisticsByCurrency( public async getStatisticsByCurrency(

119
apps/api/src/app/portfolio/portfolio.service.ts

@ -318,93 +318,6 @@ export class PortfolioService {
}; };
} }
public async getCashActivities({
cashDetails,
userCurrency,
userId
}: {
cashDetails: CashDetails;
userCurrency: string;
userId: string;
}) {
const syntheticActivities: Activity[] = [];
for (const account of cashDetails.accounts) {
const { balances } = await this.accountBalanceService.getAccountBalances({
filters: [{ id: account.id, type: 'ACCOUNT' }],
userCurrency,
userId
});
let currentBalance = 0;
let currentBalanceInBaseCurrency = 0;
for (const balanceItem of balances) {
const syntheticActivityTemplate: Activity = {
userId,
accountId: account.id,
accountUserId: account.userId,
comment: account.name,
createdAt: new Date(balanceItem.date),
currency: account.currency,
date: new Date(balanceItem.date),
fee: 0,
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
id: balanceItem.id,
isDraft: false,
quantity: 1,
SymbolProfile: {
activitiesCount: 0,
assetClass: 'LIQUIDITY',
assetSubClass: 'CASH',
countries: [],
createdAt: new Date(balanceItem.date),
currency: account.currency,
dataSource:
this.dataProviderService.getDataSourceForExchangeRates(),
holdings: [],
id: account.currency,
isActive: true,
sectors: [],
symbol: account.currency,
updatedAt: new Date(balanceItem.date)
},
symbolProfileId: account.currency,
type: 'BUY',
unitPrice: 1,
unitPriceInAssetProfileCurrency: 1,
updatedAt: new Date(balanceItem.date),
valueInBaseCurrency: 0,
value: 0
};
if (currentBalance < balanceItem.value) {
// BUY
syntheticActivities.push({
...syntheticActivityTemplate,
type: 'BUY',
value: balanceItem.value - currentBalance,
valueInBaseCurrency:
balanceItem.valueInBaseCurrency - currentBalanceInBaseCurrency
});
} else if (currentBalance > balanceItem.value) {
// SELL
syntheticActivities.push({
...syntheticActivityTemplate,
type: 'SELL',
value: currentBalance - balanceItem.value,
valueInBaseCurrency:
currentBalanceInBaseCurrency - balanceItem.valueInBaseCurrency
});
}
currentBalance = balanceItem.value;
currentBalanceInBaseCurrency = balanceItem.valueInBaseCurrency;
}
}
return syntheticActivities;
}
public async getDividends({ public async getDividends({
activities, activities,
groupBy groupBy
@ -588,16 +501,11 @@ export class PortfolioService {
userId, userId,
currency: userCurrency currency: userCurrency
}); });
const cashActivities = await this.getCashActivities({
cashDetails,
userCurrency,
userId
});
const portfolioCalculator = this.calculatorFactory.createCalculator({ const portfolioCalculator = this.calculatorFactory.createCalculator({
activities,
filters, filters,
userId, userId,
activities: [...activities, ...cashActivities],
calculationType: this.getUserPerformanceCalculationType(user), calculationType: this.getUserPerformanceCalculationType(user),
currency: userCurrency currency: userCurrency
}); });
@ -715,10 +623,10 @@ export class PortfolioService {
allocationInPercentage: filteredValueInBaseCurrency.eq(0) allocationInPercentage: filteredValueInBaseCurrency.eq(0)
? 0 ? 0
: valueInBaseCurrency.div(filteredValueInBaseCurrency).toNumber(), : valueInBaseCurrency.div(filteredValueInBaseCurrency).toNumber(),
assetClass: assetProfile.assetClass, assetClass: assetProfile?.assetClass,
assetSubClass: assetProfile.assetSubClass, assetSubClass: assetProfile?.assetSubClass,
countries: assetProfile.countries, countries: assetProfile?.countries,
dataSource: assetProfile.dataSource, dataSource: assetProfile?.dataSource,
dateOfFirstActivity: parseDate(firstBuyDate), dateOfFirstActivity: parseDate(firstBuyDate),
dividend: dividend?.toNumber() ?? 0, dividend: dividend?.toNumber() ?? 0,
grossPerformance: grossPerformance?.toNumber() ?? 0, grossPerformance: grossPerformance?.toNumber() ?? 0,
@ -727,8 +635,8 @@ export class PortfolioService {
grossPerformancePercentageWithCurrencyEffect?.toNumber() ?? 0, grossPerformancePercentageWithCurrencyEffect?.toNumber() ?? 0,
grossPerformanceWithCurrencyEffect: grossPerformanceWithCurrencyEffect:
grossPerformanceWithCurrencyEffect?.toNumber() ?? 0, grossPerformanceWithCurrencyEffect?.toNumber() ?? 0,
holdings: assetProfile.holdings.map( holdings:
({ allocationInPercentage, name }) => { assetProfile?.holdings.map(({ allocationInPercentage, name }) => {
return { return {
allocationInPercentage, allocationInPercentage,
name, name,
@ -736,10 +644,9 @@ export class PortfolioService {
.mul(allocationInPercentage) .mul(allocationInPercentage)
.toNumber() .toNumber()
}; };
} }) ?? [],
),
investment: investment.toNumber(), investment: investment.toNumber(),
name: assetProfile.name, name: assetProfile?.name,
netPerformance: netPerformance?.toNumber() ?? 0, netPerformance: netPerformance?.toNumber() ?? 0,
netPerformancePercent: netPerformancePercentage?.toNumber() ?? 0, netPerformancePercent: netPerformancePercentage?.toNumber() ?? 0,
netPerformancePercentWithCurrencyEffect: netPerformancePercentWithCurrencyEffect:
@ -749,8 +656,8 @@ export class PortfolioService {
netPerformanceWithCurrencyEffect: netPerformanceWithCurrencyEffect:
netPerformanceWithCurrencyEffectMap?.[dateRange]?.toNumber() ?? 0, netPerformanceWithCurrencyEffectMap?.[dateRange]?.toNumber() ?? 0,
quantity: quantity.toNumber(), quantity: quantity.toNumber(),
sectors: assetProfile.sectors, sectors: assetProfile?.sectors,
url: assetProfile.url, url: assetProfile?.url,
valueInBaseCurrency: valueInBaseCurrency.toNumber() valueInBaseCurrency: valueInBaseCurrency.toNumber()
}; };
} }
@ -2251,7 +2158,7 @@ export class PortfolioService {
accounts[account?.id || UNKNOWN_KEY] = { accounts[account?.id || UNKNOWN_KEY] = {
balance: 0, balance: 0,
currency: account?.currency, currency: account?.currency,
name: account.name, name: account?.name,
valueInBaseCurrency: currentValueOfSymbolInBaseCurrency valueInBaseCurrency: currentValueOfSymbolInBaseCurrency
}; };
} }
@ -2265,7 +2172,7 @@ export class PortfolioService {
platforms[account?.platformId || UNKNOWN_KEY] = { platforms[account?.platformId || UNKNOWN_KEY] = {
balance: 0, balance: 0,
currency: account?.currency, currency: account?.currency,
name: account.platform?.name, name: account?.platform?.name,
valueInBaseCurrency: currentValueOfSymbolInBaseCurrency valueInBaseCurrency: currentValueOfSymbolInBaseCurrency
}; };
} }

Loading…
Cancel
Save