Browse Source

Exclude cash balances from account values filtered by a holding

The accounts section of the holding detail dialog requests the accounts
filtered by the data source and the symbol of the holding. In
getValueOfAccountsAndPlatforms() the value of every account was seeded
with the cash balance of that account, regardless of the filters, so the
allocation percentages were computed from the cash balance plus the
holding instead of the holding alone.

Skip the cash balance if the request is filtered by a holding.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pull/7531/head
Varun Jain 4 weeks ago
parent
commit
c30a9f306b
  1. 4
      CHANGELOG.md
  2. 31
      apps/api/src/app/portfolio/portfolio.service.spec.ts
  3. 13
      apps/api/src/app/portfolio/portfolio.service.ts

4
CHANGELOG.md

@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added the platform logo to the account selector in the create or update activity dialog
### Fixed
- Fixed the allocation percentages in the accounts section of the holding detail dialog by excluding the cash balances
## 3.42.0 - 2026-08-04
### Changed

31
apps/api/src/app/portfolio/portfolio.service.spec.ts

@ -509,5 +509,36 @@ describe('PortfolioService', () => {
expect(accounts[UNKNOWN_KEY]).toBeUndefined();
expect(platforms[UNKNOWN_KEY]).toBeUndefined();
});
it('should exclude the cash balance when filtering by a holding', async () => {
jest
.spyOn(accountService, 'accounts')
.mockResolvedValue([account] as unknown as Account[]);
const { accounts, platforms } = await getValueOfAccountsAndPlatforms({
activities: [
{
account,
accountId: account.id,
assetProfile: { symbol: 'AAPL' },
quantity: 1,
type: 'BUY'
}
],
filters: [
{ id: DataSource.YAHOO, type: 'DATA_SOURCE' },
{ id: 'AAPL', type: 'SYMBOL' }
],
portfolioItemsNow: {
AAPL: { marketPriceInBaseCurrency: 10 }
},
userCurrency: 'USD',
userId: userDummyData.id
});
// 1 * 10 (activity), without the balance of 100
expect(accounts[account.id].valueInBaseCurrency).toBe(10);
expect(platforms[account.platformId].valueInBaseCurrency).toBe(10);
});
});
});

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

@ -2142,6 +2142,15 @@ export class PortfolioService {
const accounts: PortfolioDetails['accounts'] = {};
const platforms: PortfolioDetails['platforms'] = {};
const {
DATA_SOURCE: [filterByDataSource] = [],
SYMBOL: [filterBySymbol] = []
} = groupBy(filters, ({ type }) => {
return type;
});
const isFilteredByHolding = !!(filterByDataSource && filterBySymbol);
let currentAccounts: (Account & {
Order?: Order[];
platform?: Platform;
@ -2185,7 +2194,9 @@ export class PortfolioService {
return account ? accountId === account.id : !accountId;
});
if (account) {
// Skip the cash balance if the request is filtered by a holding, so that
// the values of the accounts and platforms reflect this holding only
if (account && !isFilteredByHolding) {
accounts[account.id] = {
balance: account.balance,
currency: account.currency,

Loading…
Cancel
Save