import { Injectable } from '@nestjs/common'; import { createHash } from 'node:crypto'; import { investmentResourceMeta } from '../investment-resource.mapper'; import { PortfolioService } from '../portfolio/portfolio.api'; import { BrokerageAccountDto } from './brokerage-account.dto'; @Injectable() export class BrokerageAccountsService { constructor(private readonly portfolio: PortfolioService) {} async list(userId: string, observe = false) { const saved = await this.portfolio.saved(userId, 'all', observe); const data: BrokerageAccountDto[] | null = saved.membership.availability === 'missing' ? null : saved.accounts.map((account) => ({ id: account.id, name: account.name, type: account.type as BrokerageAccountDto['type'], openedOn: account.openedOn, portfolioSummary: account.snapshot ? { totalsByCurrency: account.snapshot.totalsByCurrency, stockPositionCount: account.snapshot.positions.filter( (position) => position.type === 'STOCK', ).length, bondPositionCount: account.snapshot.positions.filter( (position) => position.type === 'BOND', ).length, } : null, })); return { data, meta: investmentResourceMeta({ resourceKey: 'accounts', dataRevision: createHash('sha256') .update( JSON.stringify([ saved.membership.dataRevision, saved.accounts.map((account) => [ account.id, account.meta.dataRevision, ]), ]), ) .digest('base64url'), availability: data === null ? 'missing' : saved.accounts.some((account) => !account.snapshot) ? 'partial' : 'complete', fetchedAt: saved.membership.lastSuccessfulAt ? new Date(saved.membership.lastSuccessfulAt) : null, freshForMs: 300_000, work: saved.membership.sync.id ? { ...saved.membership.sync, id: saved.membership.sync.id } : null, dependencies: saved.accounts.map((account) => account.meta), }), }; } }