diff --git a/apps/api/src/app/account-balance/account-balance.service.ts b/apps/api/src/app/account-balance/account-balance.service.ts index 51d0c263b5..22dedd9cd0 100644 --- a/apps/api/src/app/account-balance/account-balance.service.ts +++ b/apps/api/src/app/account-balance/account-balance.service.ts @@ -1,5 +1,8 @@ import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; -import { WHERE_ACCOUNT_NOT_EXCLUDED } from '@ghostfolio/api/helper/account.helper'; +import { + WHERE_ACCOUNT_NOT_EXCLUDED, + isAccountBalanceInFuture +} from '@ghostfolio/api/helper/account.helper'; import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; @@ -15,7 +18,7 @@ import { Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { AccountBalance, Prisma } from '@prisma/client'; import { Big } from 'big.js'; -import { endOfToday, format, isAfter, parseISO } from 'date-fns'; +import { endOfToday, format, parseISO } from 'date-fns'; import { groupBy } from 'lodash'; @Injectable() @@ -114,10 +117,10 @@ export class AccountBalanceService { const accumulatedBalancesByDate: { [date: string]: HistoricalDataItem } = {}; const lastBalancesByAccount: { [accountId: string]: Big } = {}; + const endOfTodayDate = endOfToday(); for (const { accountId, date, valueInBaseCurrency } of balances) { - if (isAfter(date, endOfToday())) { - // Skip account balances in the future + if (isAccountBalanceInFuture(date, endOfTodayDate)) { continue; } diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index 7aafe7d332..698e955677 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -1,6 +1,10 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; -import { WHERE_ACCOUNT_NOT_EXCLUDED } from '@ghostfolio/api/helper/account.helper'; +import { + WHERE_ACCOUNT_NOT_EXCLUDED, + getWhereAccountBalanceNotInFuture, + isAccountBalanceInFuture +} from '@ghostfolio/api/helper/account.helper'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service'; @@ -19,7 +23,7 @@ import { Tag } from '@prisma/client'; import { Big } from 'big.js'; -import { endOfToday, format, isAfter } from 'date-fns'; +import { endOfToday, format } from 'date-fns'; import { groupBy } from 'lodash'; import { CashDetails } from './interfaces/cash-details.interface'; @@ -42,10 +46,8 @@ export class AccountService { balances: { orderBy: { date: 'desc' }, take: 1, - where: { - // Ignore account balances in the future - date: { lte: endOfToday() } - } + // Ignore account balances in the future + where: getWhereAccountBalanceNotInFuture() } }, where: { id_userId } @@ -99,14 +101,15 @@ export class AccountService { include.balances = { orderBy: { date: 'desc' }, + // If the balances are included, they are returned as-is (including the + // ones in the future) because the client renders the full history. The + // balance is derived below and skips the account balances in the future. ...(isBalancesIncluded ? {} : { take: 1, - where: { - // Ignore account balances in the future - date: { lte: endOfToday() } - } + // Ignore account balances in the future + where: getWhereAccountBalanceNotInFuture() }) }; @@ -127,6 +130,8 @@ export class AccountService { where }); + const endOfTodayDate = endOfToday(); + return accounts.map((account) => { const result = { ...account, @@ -134,7 +139,7 @@ export class AccountService { // The balances are ordered by date descending, hence the first account // balance which is not in the future reflects the current balance account.balances.find(({ date }) => { - return !isAfter(date, endOfToday()); + return !isAccountBalanceInFuture(date, endOfTodayDate); })?.value ?? 0, tags: isTagsIncluded ? (account.tags as unknown as { tag: Tag }[]).map(({ tag }) => { diff --git a/apps/api/src/app/activities/activities.service.ts b/apps/api/src/app/activities/activities.service.ts index 0e3d3f0c3b..34f67eb5e6 100644 --- a/apps/api/src/app/activities/activities.service.ts +++ b/apps/api/src/app/activities/activities.service.ts @@ -3,7 +3,10 @@ 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 { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; -import { WHERE_ACCOUNT_NOT_EXCLUDED } from '@ghostfolio/api/helper/account.helper'; +import { + WHERE_ACCOUNT_NOT_EXCLUDED, + isAccountBalanceInFuture +} from '@ghostfolio/api/helper/account.helper'; import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; @@ -456,6 +459,7 @@ export class ActivitiesService { } const activities: Activity[] = []; + const endOfTodayDate = endOfToday(); for (const account of cashDetails.accounts) { const { balances } = await this.accountBalanceService.getAccountBalances({ @@ -468,8 +472,7 @@ export class ActivitiesService { let currentBalanceInBaseCurrency = 0; for (const balanceItem of balances) { - if (isAfter(balanceItem.date, endOfToday())) { - // Skip account balances in the future + if (isAccountBalanceInFuture(balanceItem.date, endOfTodayDate)) { continue; } diff --git a/apps/api/src/helper/account.helper.ts b/apps/api/src/helper/account.helper.ts index 0800c022e2..317b0c7ce8 100644 --- a/apps/api/src/helper/account.helper.ts +++ b/apps/api/src/helper/account.helper.ts @@ -1,6 +1,7 @@ import { TAG_ID_EXCLUDE_FROM_ANALYSIS } from '@ghostfolio/common/config'; import { Prisma } from '@prisma/client'; +import { endOfToday, isAfter } from 'date-fns'; export const WHERE_ACCOUNT_NOT_EXCLUDED: Prisma.AccountWhereInput = { isExcluded: false, @@ -10,3 +11,16 @@ export const WHERE_ACCOUNT_NOT_EXCLUDED: Prisma.AccountWhereInput = { } } }; + +export function getWhereAccountBalanceNotInFuture(): Prisma.AccountBalanceWhereInput { + return { + date: { lte: endOfToday() } + }; +} + +export function isAccountBalanceInFuture( + aDate: Date, + aEndOfToday = endOfToday() +) { + return isAfter(aDate, aEndOfToday); +}