From bb7fef8deba5252771fd8175ad3a204a93b790d0 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Wed, 17 Jun 2026 14:36:32 +0300 Subject: [PATCH] feat(tbank): add getPositions() method to BrokerPortfolioService --- .../services/broker-portfolio.service.ts | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/modules/tbank/services/broker-portfolio.service.ts b/apps/backend/src/modules/tbank/services/broker-portfolio.service.ts index 7ec14a8..feeae59 100644 --- a/apps/backend/src/modules/tbank/services/broker-portfolio.service.ts +++ b/apps/backend/src/modules/tbank/services/broker-portfolio.service.ts @@ -1,8 +1,8 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { CacheService } from '../../cache/cache.service'; -import { mapBrokerPortfolio } from '../mappers/portfolio.mapper'; +import { mapBrokerPortfolio, mapBrokerPositionsPage } from '../mappers/portfolio.mapper'; import { TBANK_CACHE_KEYS } from '../tbank.config'; -import type { BrokerPortfolio } from '../types/broker.types'; +import type { BrokerPortfolio, BrokerPositionsPage } from '../types/broker.types'; import type { TBankInstrument, TBankPortfolioResponse, @@ -62,6 +62,49 @@ export class BrokerPortfolioService { }; } + async getPositions( + accountId: string, + cursor?: string, + limit = 10, + ): Promise<{ + data: BrokerPositionsPage; + meta: { fromCache: boolean; cachedAt: string | null }; + }> { + const account = await this.accountsService.findById(accountId); + if (!account) throw new NotFoundException('Broker account not found'); + + const result = await this.cacheService.getOrFetch( + TBANK_CACHE_KEYS.positions, + [accountId], + async () => { + const operationsClient = this.tbankClient.getServiceClient('OperationsService') as any; + const portfolio = await this.tbankClient.callUnary< + { accountId: string; currency: string }, + TBankPortfolioResponse + >('OperationsService/GetPortfolio', operationsClient.getPortfolio.bind(operationsClient), { + accountId, + currency: 'RUB', + }); + + const instrumentMap = await this.buildInstrumentMap(portfolio); + + return mapBrokerPositionsPage({ + accountId, + portfolio, + instruments: instrumentMap, + cursor, + limit, + }); + }, + 'tbankPositionsTtl', + ); + + return { + data: result.data, + meta: { fromCache: result.fromCache, cachedAt: result.cachedAt }, + }; + } + private async buildInstrumentMap( portfolio: TBankPortfolioResponse, ): Promise>> {