Browse Source

Ignore future-dated account balances in the portfolio calculation

pull/7436/head
Thomas Kaul 1 month ago
parent
commit
7fcbc2e755
  1. 7
      apps/api/src/app/account-balance/account-balance.service.ts
  2. 25
      apps/api/src/app/account/account.service.ts
  3. 5
      apps/api/src/app/activities/activities.service.ts
  4. 8
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts

7
apps/api/src/app/account-balance/account-balance.service.ts

@ -15,7 +15,7 @@ import { Injectable } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { AccountBalance, Prisma } from '@prisma/client';
import { Big } from 'big.js';
import { format, parseISO } from 'date-fns';
import { endOfToday, format, isAfter, parseISO } from 'date-fns';
import { groupBy } from 'lodash';
@Injectable()
@ -116,6 +116,11 @@ export class AccountBalanceService {
const lastBalancesByAccount: { [accountId: string]: Big } = {};
for (const { accountId, date, valueInBaseCurrency } of balances) {
if (isAfter(date, endOfToday())) {
// Skip account balances in the future
continue;
}
const formattedDate = format(date, DATE_FORMAT);
lastBalancesByAccount[accountId] = new Big(valueInBaseCurrency);

25
apps/api/src/app/account/account.service.ts

@ -19,7 +19,7 @@ import {
Tag
} from '@prisma/client';
import { Big } from 'big.js';
import { format } from 'date-fns';
import { endOfToday, format, isAfter } from 'date-fns';
import { groupBy } from 'lodash';
import { CashDetails } from './interfaces/cash-details.interface';
@ -41,7 +41,11 @@ export class AccountService {
include: {
balances: {
orderBy: { date: 'desc' },
take: 1
take: 1,
where: {
// Ignore account balances in the future
date: { lte: endOfToday() }
}
}
},
where: { id_userId }
@ -95,7 +99,15 @@ export class AccountService {
include.balances = {
orderBy: { date: 'desc' },
...(isBalancesIncluded ? {} : { take: 1 })
...(isBalancesIncluded
? {}
: {
take: 1,
where: {
// Ignore account balances in the future
date: { lte: endOfToday() }
}
})
};
if (isTagsIncluded) {
@ -118,7 +130,12 @@ export class AccountService {
return accounts.map((account) => {
const result = {
...account,
balance: account.balances[0]?.value ?? 0,
balance:
// 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());
})?.value ?? 0,
tags: isTagsIncluded
? (account.tags as unknown as { tag: Tag }[]).map(({ tag }) => {
return tag;

5
apps/api/src/app/activities/activities.service.ts

@ -468,6 +468,11 @@ export class ActivitiesService {
let currentBalanceInBaseCurrency = 0;
for (const balanceItem of balances) {
if (isAfter(balanceItem.date, endOfToday())) {
// Skip account balances in the future
continue;
}
const syntheticActivityTemplate: Activity = {
userId,
accountId: account.id,

8
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts

@ -166,6 +166,14 @@ describe('PortfolioCalculator', () => {
id: randomUUID(),
value: 2000,
valueInBaseCurrency: 1800
},
{
// Ignored future account balance
accountId,
date: parseDate('2050-12-31'),
id: randomUUID(),
value: 0,
valueInBaseCurrency: 0
}
]
});

Loading…
Cancel
Save