refactor: replace deep imports with native node aliases (WealthLedger/backend#165) (#193)
Backend verify / commits (push) Skipped
Backend verify / security (push) Successful in 1m6s
Backend verify / verify (push) Failing after 6m44s

This commit was merged in pull request #193.
This commit is contained in:
2026-11-04 23:22:46 +03:00
parent e3ecb8c15e
commit 07cfd08df9
103 changed files with 322 additions and 230 deletions
@@ -1,6 +1,7 @@
import { ApiProperty } from '@nestjs/swagger';
import { MoneyDto } from '../../../common/money.dto';
import { MoneyDto } from '#src/common/money.dto';
import { InvestmentResourceMetaDto } from '../investment-resource.dto';
import { PortfolioStructureDto } from '../portfolio/portfolio.api';
import { HourlySyncStatusDto } from '../tbank-sync/tbank-sync.dto';
@@ -3,7 +3,8 @@ import type { Request } from 'express';
import { Controller, Get, Req, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { ApiProblemResponses } from '../../../common/decorators/api-safe-error-response.decorator';
import { ApiProblemResponses } from '#src/common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '../../auth/auth.api';
import { BrokerageAccountsResourceDto } from './brokerage-account.dto';
import { BrokerageAccountsService } from './brokerage-accounts.service';
@@ -1,6 +1,7 @@
import { Module } from '@nestjs/common';
import { TbankModule } from '../../../integrations/tbank/tbank.module';
import { TbankModule } from '#src/integrations/tbank/tbank.module';
import { AuthModule } from '../../auth/auth.module';
import { PortfolioModule } from '../portfolio/portfolio.module';
import { TbankSyncRepositoryModule } from '../tbank-sync/tbank-sync-repository.module';
@@ -1,4 +1,4 @@
jest.mock('../../../prisma/prisma.service', () => ({
jest.mock('#src/prisma/prisma.service', () => ({
PrismaService: class {},
}));
import { investmentResourceMeta } from '../investment-resource.mapper';
@@ -7,7 +7,8 @@ import {
formatDecimal,
isZero,
multiply,
} from '../../../common/decimal';
} from '#src/common/decimal';
import { investmentResourceMeta } from '../investment-resource.mapper';
import { sumMoneyByCurrency } from '../portfolio/domain/portfolio-totals';
import { PortfolioPositionDto, PortfolioService } from '../portfolio/portfolio.api';
@@ -3,7 +3,8 @@ import type { Request } from 'express';
import { Controller, Get, Param, Query, Req, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { ApiProblemResponses } from '../../../common/decorators/api-safe-error-response.decorator';
import { ApiProblemResponses } from '#src/common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '../../auth/auth.api';
import { InvestmentReadQueryDto } from '../investment-resource.dto';
import {
@@ -1,7 +1,8 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, Matches } from 'class-validator';
import { MoneyDto } from '../../../common/money.dto';
import { MoneyDto } from '#src/common/money.dto';
import {
InvestmentDependencyDto,
InvestmentReadQueryDto,
@@ -1,4 +1,4 @@
jest.mock('../../../prisma/prisma.service', () => ({
jest.mock('#src/prisma/prisma.service', () => ({
PrismaService: class {},
}));
jest.mock('../operations/application/brokerage-operations.service', () => ({
@@ -6,8 +6,9 @@ import {
compare,
decimalFromString,
formatDecimal,
} from '../../../common/decimal';
import { isTbankProtocolValue, TbankOperationType } from '../../../integrations/tbank/tbank-protocol';
} from '#src/common/decimal';
import { isTbankProtocolValue, TbankOperationType } from '#src/integrations/tbank/tbank-protocol';
import { DateOnlyRange, moscowDate } from '../investment-calendar';
import { investmentResourceMeta } from '../investment-resource.mapper';
import {
@@ -1,6 +1,7 @@
import { BadRequestException } from '@nestjs/common';
import { ISO_DATE_LENGTH, ISO_DATE_START, MILLISECONDS_PER_DAY } from '../../../common/time';
import { ISO_DATE_LENGTH, ISO_DATE_START, MILLISECONDS_PER_DAY } from '#src/common/time';
import {
DateOnlyRange,
dateParts,
@@ -4,7 +4,7 @@ jest.mock('../infrastructure/candle.repository', () => ({
jest.mock('./catalog-enrichment.service', () => ({
CatalogEnrichmentService: class {},
}));
jest.mock('../../../../integrations/tbank/tbank.api', () => ({
jest.mock('#src/integrations/tbank/tbank.api', () => ({
TbankAccessService: class {},
TbankClient: class {},
}));
@@ -5,15 +5,16 @@ import {
} from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import { StructuredLogger } from '../../../../common/logging/structured-logger.service';
import { MILLISECONDS_PER_DAY } from '../../../../common/time';
import { isTbankErrorCode, TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
import { StructuredLogger } from '#src/common/logging/structured-logger.service';
import { MILLISECONDS_PER_DAY } from '#src/common/time';
import { isTbankErrorCode, TbankErrorCode } from '#src/integrations/tbank/tbank-error-code';
import {
TbankAccessService,
TbankClient,
type TbankShare,
type TbankSyncAttempt,
} from '../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import { investmentResourceMeta } from '../../investment-resource.mapper';
import {
candleGaps,
@@ -8,7 +8,8 @@ import {
TbankAccessService,
TbankClient,
tbankSourceTtlMs,
} from '../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import { investmentResourceMeta } from '../../investment-resource.mapper';
import { InstrumentErrorCode } from '../domain/instrument-error-code';
import {
@@ -1,8 +1,8 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import { StructuredLogger } from '../../../../common/logging/structured-logger.service';
import { isTbankErrorCode, TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
import { StructuredLogger } from '#src/common/logging/structured-logger.service';
import { isTbankErrorCode, TbankErrorCode } from '#src/integrations/tbank/tbank-error-code';
import {
TbankAccessService,
TbankClient,
@@ -10,7 +10,8 @@ import {
tbankSourceNeedsRefresh,
tbankSourceTtlMs,
type TbankSyncAttempt,
} from '../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import { investmentResourceMeta } from '../../investment-resource.mapper';
import {
CatalogDiscoveryRepository,
@@ -1,6 +1,6 @@
import type { TbankShare } from '../../../../integrations/tbank/tbank.api';
import type { TbankShare } from '#src/integrations/tbank/tbank.api';
import { TbankInstrumentType } from '../../../../integrations/tbank/tbank-protocol';
import { TbankInstrumentType } from '#src/integrations/tbank/tbank-protocol';
export const catalogSearchLimit = 30;
@@ -3,13 +3,13 @@ import { Injectable } from '@nestjs/common';
import {
decimalFromString,
divide,
} from '../../../../common/decimal';
} from '#src/common/decimal';
import {
MILLISECONDS_PER_DAY,
MILLISECONDS_PER_SECOND,
} from '../../../../common/time';
import { type MoexBondEvent, MoexClient } from '../../../../integrations/moex/moex.api';
import { NcrRatingsClient } from '../../../../integrations/ncr/ncr.api';
} from '#src/common/time';
import { type MoexBondEvent, MoexClient } from '#src/integrations/moex/moex.api';
import { NcrRatingsClient } from '#src/integrations/ncr/ncr.api';
import {
type TbankBond,
type TbankCandle,
@@ -20,7 +20,8 @@ import {
type TbankLastPrice,
type TbankShare,
type TbankSyncAttempt,
} from '../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import { candleGaps, utcDay } from '../domain/candle-coverage';
import { CandleRepository } from '../infrastructure/candle.repository';
import {
@@ -1,9 +1,9 @@
import type {
TbankCandle,
TbankTimestamp,
} from '../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import { ISO_DATE_LENGTH, ISO_DATE_START, MILLISECONDS_PER_SECOND } from '../../../../common/time';
import { ISO_DATE_LENGTH, ISO_DATE_START, MILLISECONDS_PER_SECOND } from '#src/common/time';
const MIN_TIMESTAMP_SECONDS_EXCLUSIVE = 0;
@@ -4,8 +4,9 @@ import {
divide,
formatDecimal,
multiply,
} from '../../../../common/decimal';
import { MoneyDto } from '../../../../common/money.dto';
} from '#src/common/decimal';
import { MoneyDto } from '#src/common/money.dto';
import {
PortfolioDto,
PortfolioPositionDto,
@@ -1,7 +1,7 @@
import type {
TbankBond,
TbankShare,
} from '../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import { publicInstrument } from './public-instrument';
@@ -1,7 +1,7 @@
import type {
TbankBond,
TbankShare,
} from '../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
export function publicInstrument(value: TbankBond | TbankShare) {
const bond = value as TbankBond;
@@ -1,9 +1,10 @@
import { Injectable } from '@nestjs/common';
import type { TbankBond } from '../../../../../integrations/tbank/tbank.api';
import type { TbankBond } from '#src/integrations/tbank/tbank.api';
import { formatDecimal } from '#src/common/decimal';
import { decimal } from '#src/integrations/tbank/decimal';
import { formatDecimal } from '../../../../../common/decimal';
import { decimal } from '../../../../../integrations/tbank/decimal';
import { CatalogDiscoveryService } from '../../application/catalog-discovery.service';
import { timestamp } from '../../application/instrument-market';
import {
@@ -14,7 +15,8 @@ import {
type IdentifiedBond = TbankBond & { uid: string };
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../../../common/time';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '#src/common/time';
import { money } from '../infrastructure/bond-money.mapper';
const MIN_LOT_EXCLUSIVE = 0;
@@ -5,19 +5,20 @@ import {
divide,
formatDecimal,
multiply,
} from '../../../../../common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../../../common/time';
import { isTbankProtocolValue, TbankCouponType } from '../../../../../integrations/tbank/tbank-protocol';
} from '#src/common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '#src/common/time';
import { isTbankProtocolValue, TbankCouponType } from '#src/integrations/tbank/tbank-protocol';
import {
TbankAccessService,
type TbankBond,
type TbankCoupon,
tbankSourceNeedsRefresh,
} from '../../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import {
ForecastService,
PortfolioService,
} from '../../../portfolio/portfolio.api';
} from '#src/modules/investments/portfolio/portfolio.api';
import {
CatalogEnrichmentService,
type CatalogPayload,
@@ -1,6 +1,6 @@
import { Injectable } from '@nestjs/common';
import type { TbankBond } from '../../../../../integrations/tbank/tbank.api';
import type { TbankBond } from '#src/integrations/tbank/tbank.api';
import {
add,
@@ -9,9 +9,10 @@ import {
formatDecimal,
multiply,
subtract,
} from '../../../../../common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../../../common/time';
import { decimal } from '../../../../../integrations/tbank/decimal';
} from '#src/common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '#src/common/time';
import { decimal } from '#src/integrations/tbank/decimal';
import { CandleService } from '../../application/candle.service';
import {
CatalogEnrichmentService,
@@ -1,9 +1,9 @@
import type { PortfolioDto } from '../../../portfolio/portfolio.api';
import type { PortfolioDto } from '#src/modules/investments/portfolio/portfolio.api';
import { instrumentPosition } from '../../application/instrument-position';
import { bondCoupons, bondMetrics } from './bond-income.service';
import { bondQuote } from './bond-market.service';
jest.mock('../../../../../prisma/prisma.service', () => ({
jest.mock('#src/prisma/prisma.service', () => ({
PrismaService: class {},
}));
const time = (value: string) => ({ seconds: String(Date.parse(value) / 1000) });
@@ -1,6 +1,6 @@
import { formatDecimal } from '../../../../../common/decimal';
import { decimal } from '../../../../../integrations/tbank/decimal';
import { type TbankMoney } from '../../../../../integrations/tbank/tbank.api';
import { formatDecimal } from '#src/common/decimal';
import { decimal } from '#src/integrations/tbank/decimal';
import { type TbankMoney } from '#src/integrations/tbank/tbank.api';
export function money(value?: TbankMoney) {
const currency = value?.currency?.toUpperCase();
@@ -11,9 +11,10 @@ import {
} from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { ApiProblemResponses } from '../../../../../common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '../../../../auth/auth.api';
import { InvestmentReadQueryDto } from '../../../investment-resource.dto';
import { ApiProblemResponses } from '#src/common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '#src/modules/auth/auth.api';
import { InvestmentReadQueryDto } from '#src/modules/investments/investment-resource.dto';
import { BondCatalogService } from '../application/bond-catalog.service';
import { BondIncomeService } from '../application/bond-income.service';
import { BondMarketService } from '../application/bond-market.service';
@@ -1,7 +1,8 @@
import { ApiProperty } from '@nestjs/swagger';
import { MoneyDto } from '../../../../../common/money.dto';
import { InvestmentResourceMetaDto } from '../../../investment-resource.dto';
import { MoneyDto } from '#src/common/money.dto';
import { InvestmentResourceMetaDto } from '#src/modules/investments/investment-resource.dto';
import {
StockCandlesDto,
StockCandlesQueryDto,
@@ -1,4 +1,4 @@
import { MILLISECONDS_PER_DAY } from '../../../../common/time';
import { MILLISECONDS_PER_DAY } from '#src/common/time';
const FIRST_RANGE_END_INDEX = 1;
@@ -1,18 +1,19 @@
import { Injectable } from '@nestjs/common';
import { createHash, randomUUID } from 'node:crypto';
import type { Prisma } from '../../../../../generated/prisma/client';
import type { Prisma } from '#generated/prisma/client';
import {
claimSyncWork,
lockConnectionGeneration,
} from '../../../../integrations/tbank/tbank-sync-claim';
} from '#src/integrations/tbank/tbank-sync-claim';
import {
isJoinableRunningAttempt,
type TbankSyncAttempt,
} from '../../../../integrations/tbank/tbank.api';
import { PrismaService } from '../../../../prisma/prisma.service';
import { toJson } from '../../../../prisma/to-json';
} from '#src/integrations/tbank/tbank.api';
import { PrismaService } from '#src/prisma/prisma.service';
import { toJson } from '#src/prisma/to-json';
import {
type CandleRange,
confirmedCandleCoverage,
@@ -2,11 +2,11 @@ import { Injectable } from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import { isDeepStrictEqual } from 'node:util';
import { TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
import { claimSyncWork, lockConnectionGeneration } from '../../../../integrations/tbank/tbank-sync-claim';
import { isJoinableRunningAttempt, type TbankBond, type TbankShare, type TbankSyncAttempt } from '../../../../integrations/tbank/tbank.api';
import { PrismaService } from '../../../../prisma/prisma.service';
import { toJson } from '../../../../prisma/to-json';
import { TbankErrorCode } from '#src/integrations/tbank/tbank-error-code';
import { claimSyncWork, lockConnectionGeneration } from '#src/integrations/tbank/tbank-sync-claim';
import { isJoinableRunningAttempt, type TbankBond, type TbankShare, type TbankSyncAttempt } from '#src/integrations/tbank/tbank.api';
import { PrismaService } from '#src/prisma/prisma.service';
import { toJson } from '#src/prisma/to-json';
const UNCHANGED_REVISION_INCREMENT = 0;
const REVISION_INCREMENT = 1;
@@ -1,8 +1,10 @@
import type { TbankCandle } from '../../../../integrations/tbank/tbank.api';
import type { TbankCandle } from '#src/integrations/tbank/tbank.api';
import { formatDecimal } from '#src/common/decimal';
import { decimal } from '#src/integrations/tbank/decimal';
import type { SavedCandle } from '../domain/candle-coverage';
import { formatDecimal } from '../../../../common/decimal';
import { decimal } from '../../../../integrations/tbank/decimal';
import { timestamp } from '../application/instrument-market';
function toSavedCandle(candle: TbankCandle): SavedCandle {
@@ -1,8 +1,9 @@
import { Module } from '@nestjs/common';
import { MoexModule } from '../../../integrations/moex/moex.module';
import { NcrModule } from '../../../integrations/ncr/ncr.module';
import { TbankModule } from '../../../integrations/tbank/tbank.module';
import { MoexModule } from '#src/integrations/moex/moex.module';
import { NcrModule } from '#src/integrations/ncr/ncr.module';
import { TbankModule } from '#src/integrations/tbank/tbank.module';
import { CandleService } from './application/candle.service';
import { CatalogDiscoveryService } from './application/catalog-discovery.service';
import { CatalogEnrichmentService } from './application/catalog-enrichment.service';
@@ -1,6 +1,7 @@
import { Module } from '@nestjs/common';
import { TbankModule } from '../../../integrations/tbank/tbank.module';
import { TbankModule } from '#src/integrations/tbank/tbank.module';
import { AuthModule } from '../../auth/auth.module';
import { PortfolioModule } from '../portfolio/portfolio.module';
import { BondCatalogService } from './bonds/application/bond-catalog.service';
@@ -1,6 +1,6 @@
import { Injectable } from '@nestjs/common';
import type { TbankFundamentals } from '../../../../../integrations/tbank/tbank.api';
import type { TbankFundamentals } from '#src/integrations/tbank/tbank.api';
import { CatalogEnrichmentService } from '../../application/catalog-enrichment.service';
import {
@@ -1,9 +1,10 @@
import { Injectable } from '@nestjs/common';
import type { TbankShare } from '../../../../../integrations/tbank/tbank.api';
import type { TbankShare } from '#src/integrations/tbank/tbank.api';
import { formatDecimal } from '#src/common/decimal';
import { decimal } from '#src/integrations/tbank/decimal';
import { formatDecimal } from '../../../../../common/decimal';
import { decimal } from '../../../../../integrations/tbank/decimal';
import { CatalogDiscoveryService } from '../../application/catalog-discovery.service';
import { timestamp } from '../../application/instrument-market';
import {
@@ -4,18 +4,19 @@ import {
decimalFromString,
formatDecimal,
multiply,
} from '../../../../../common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../../../common/time';
import { decimal } from '../../../../../integrations/tbank/decimal';
} from '#src/common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '#src/common/time';
import { decimal } from '#src/integrations/tbank/decimal';
import {
TbankAccessService,
type TbankDividend,
tbankSourceNeedsRefresh,
} from '../../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import {
ForecastService,
PortfolioService,
} from '../../../portfolio/portfolio.api';
} from '#src/modules/investments/portfolio/portfolio.api';
import { CatalogEnrichmentService } from '../../application/catalog-enrichment.service';
import { moscowDay, timestamp } from '../../application/instrument-market';
import { instrumentPosition } from '../../application/instrument-position';
@@ -6,9 +6,10 @@ import {
formatDecimal,
multiply,
subtract,
} from '../../../../../common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../../../common/time';
import { decimal } from '../../../../../integrations/tbank/decimal';
} from '#src/common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '#src/common/time';
import { decimal } from '#src/integrations/tbank/decimal';
import { CandleService } from '../../application/candle.service';
import {
CatalogEnrichmentService,
@@ -1,10 +1,10 @@
jest.mock('../../../../../integrations/tbank/tbank.api', () => ({
jest.mock('#src/integrations/tbank/tbank.api', () => ({
TbankAccessService: class {},
}));
import { NotFoundException, ServiceUnavailableException } from '@nestjs/common';
import type { TbankShare } from '../../../../../integrations/tbank/tbank.api';
import type { TbankShare } from '#src/integrations/tbank/tbank.api';
import { StockScreenerService } from './stock-screener.service';
@@ -6,11 +6,12 @@ import {
} from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import type { TbankShare } from '../../../../../integrations/tbank/tbank-market.types';
import type { TbankShare } from '#src/integrations/tbank/tbank-market.types';
import { StructuredLogger } from '#src/common/logging/structured-logger.service';
import { TbankAccessService } from '#src/integrations/tbank/tbank.api';
import { TbankClient } from '#src/integrations/tbank/tbank.client';
import { StructuredLogger } from '../../../../../common/logging/structured-logger.service';
import { TbankAccessService } from '../../../../../integrations/tbank/tbank.api';
import { TbankClient } from '../../../../../integrations/tbank/tbank.client';
import {
selectStockScreenerInstruments,
type StockScreenerConditions,
@@ -2,7 +2,7 @@ import { previousClose } from '../../application/instrument-market';
import { metrics } from './get-stock-company.use-case';
import { stockDividends } from './stock-income.service';
import { stockQuote } from './stock-market.service';
jest.mock('../../../../../prisma/prisma.service', () => ({
jest.mock('#src/prisma/prisma.service', () => ({
PrismaService: class {},
}));
const time = (value: string) => ({ seconds: String(Date.parse(value) / 1000) });
@@ -1,4 +1,4 @@
import type { TbankShare } from '../../../../../integrations/tbank/tbank.api';
import type { TbankShare } from '#src/integrations/tbank/tbank.api';
import { selectStockScreenerInstruments } from './stock-screener-selection.rules';
@@ -1,4 +1,4 @@
import type { TbankShare } from '../../../../../integrations/tbank/tbank.api';
import type { TbankShare } from '#src/integrations/tbank/tbank.api';
export type StockScreenerCatalog = {
asOf: Date;
@@ -17,9 +17,10 @@ import {
} from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import { ApiProblemResponses } from '../../../../../common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '../../../../auth/auth.api';
import { InvestmentReadQueryDto } from '../../../investment-resource.dto';
import { ApiProblemResponses } from '#src/common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '#src/modules/auth/auth.api';
import { InvestmentReadQueryDto } from '#src/modules/investments/investment-resource.dto';
import { GetStockCompanyUseCase } from '../application/get-stock-company.use-case';
import { StockCatalogService } from '../application/stock-catalog.service';
import { StockIncomeService } from '../application/stock-income.service';
@@ -11,16 +11,16 @@ import {
MinLength,
} from 'class-validator';
import { MoneyDto } from '../../../../../common/money.dto';
import { MoneyDto } from '#src/common/money.dto';
import {
MAX_INSTRUMENT_QUERY_LENGTH,
MIN_INSTRUMENT_QUERY_LENGTH,
} from '../../../instrument-query';
} from '#src/modules/investments/instrument-query';
import {
InvestmentReadQueryDto,
InvestmentResourceMetaDto,
} from '../../../investment-resource.dto';
import { PortfolioPositionDto } from '../../../portfolio/portfolio.api';
} from '#src/modules/investments/investment-resource.dto';
import { PortfolioPositionDto } from '#src/modules/investments/portfolio/portfolio.api';
const MIN_TICKER_LENGTH = 1;
const MAX_SCREENER_QUERY_LENGTH = 80;
@@ -1,11 +1,12 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import { StructuredLogger } from '../../../../common/logging/structured-logger.service';
import { MILLISECONDS_PER_SECOND } from '../../../../common/time';
import { isTbankErrorCode, TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
import { TbankOperationState } from '../../../../integrations/tbank/tbank-protocol';
import { TbankAccessService, TbankClient } from '../../../../integrations/tbank/tbank.api';
import { StructuredLogger } from '#src/common/logging/structured-logger.service';
import { MILLISECONDS_PER_SECOND } from '#src/common/time';
import { isTbankErrorCode, TbankErrorCode } from '#src/integrations/tbank/tbank-error-code';
import { TbankOperationState } from '#src/integrations/tbank/tbank-protocol';
import { TbankAccessService, TbankClient } from '#src/integrations/tbank/tbank.api';
import {
type OperationInterval,
operationIntervals,
@@ -7,7 +7,8 @@ import {
TbankAccessService,
type TbankOperationItem,
tbankSourceTtlMs,
} from '../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import { dateOnlyBounds, DateOnlyRange } from '../../investment-calendar';
import { investmentResourceMeta } from '../../investment-resource.mapper';
import { ledgerRange } from '../../investment-sync-plan';
@@ -1,8 +1,9 @@
import { formatDecimal } from '../../../../common/decimal';
import { MILLISECONDS_PER_SECOND } from '../../../../common/time';
import { decimal } from '../../../../integrations/tbank/decimal';
import { TbankOperationType } from '../../../../integrations/tbank/tbank-protocol';
import { TbankMoney, TbankOperationItem } from '../../../../integrations/tbank/tbank.api';
import { formatDecimal } from '#src/common/decimal';
import { MILLISECONDS_PER_SECOND } from '#src/common/time';
import { decimal } from '#src/integrations/tbank/decimal';
import { TbankOperationType } from '#src/integrations/tbank/tbank-protocol';
import { TbankMoney, TbankOperationItem } from '#src/integrations/tbank/tbank.api';
import { type OperationCategory } from '../../operation-category';
import { BrokerageOperationDto } from '../presentation/brokerage-operation.dto';
@@ -5,7 +5,8 @@ import {
} from '@nestjs/common';
import { createHash } from 'node:crypto';
import { PrismaService } from '../../../../prisma/prisma.service';
import { PrismaService } from '#src/prisma/prisma.service';
import {
dateOnlyBounds,
DateOnlyRange,
@@ -2,17 +2,18 @@ import { Injectable, NotFoundException } from '@nestjs/common';
import { createHash, randomUUID } from 'node:crypto';
import { isDeepStrictEqual } from 'node:util';
import type { Prisma } from '../../../../../generated/prisma/client';
import type { Prisma } from '#generated/prisma/client';
import { TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
import { isTbankProtocolValue, TbankOperationState } from '../../../../integrations/tbank/tbank-protocol';
import { claimSyncWork, lockConnectionGeneration } from '../../../../integrations/tbank/tbank-sync-claim';
import { TbankErrorCode } from '#src/integrations/tbank/tbank-error-code';
import { isTbankProtocolValue, TbankOperationState } from '#src/integrations/tbank/tbank-protocol';
import { claimSyncWork, lockConnectionGeneration } from '#src/integrations/tbank/tbank-sync-claim';
import {
isJoinableRunningAttempt,
type TbankOperationItem, type TbankOperationsByCursorResponse,
} from '../../../../integrations/tbank/tbank.api';
import { PrismaService } from '../../../../prisma/prisma.service';
import { toJson } from '../../../../prisma/to-json';
} from '#src/integrations/tbank/tbank.api';
import { PrismaService } from '#src/prisma/prisma.service';
import { toJson } from '#src/prisma/to-json';
import {
decodeInterval,
extendRunningIntent,
@@ -1,6 +1,7 @@
import { Module } from '@nestjs/common';
import { TbankModule } from '../../../integrations/tbank/tbank.module';
import { TbankModule } from '#src/integrations/tbank/tbank.module';
import { AuthModule } from '../../auth/auth.module';
import { TbankSyncRepositoryModule } from '../tbank-sync/tbank-sync-repository.module';
import { BrokerageOperationsSyncService } from './application/brokerage-operations-sync.service';
@@ -13,7 +13,8 @@ import {
Min,
} from 'class-validator';
import { MoneyDto } from '../../../../common/money.dto';
import { MoneyDto } from '#src/common/money.dto';
import { AccountReferenceDto } from '../../account-reference.dto';
import { InvestmentResourceMetaDto } from '../../investment-resource.dto';
import { operationCategories, type OperationCategory } from '../../operation-category';
@@ -1,4 +1,4 @@
jest.mock('../../../../prisma/prisma.service', () => ({
jest.mock('#src/prisma/prisma.service', () => ({
PrismaService: class PrismaService {},
}));
@@ -3,8 +3,9 @@ import type { Request } from 'express';
import { Controller, Get, Param, Query, Req, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { ApiProblemResponses } from '../../../../common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '../../../auth/auth.api';
import { ApiProblemResponses } from '#src/common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '#src/modules/auth/auth.api';
import { BrokerageOperationsService } from '../application/brokerage-operations.service';
import {
BrokerageOperationsQueryDto,
@@ -1,8 +1,9 @@
import { Injectable } from '@nestjs/common';
import { add, decimalFromString, formatDecimal } from '#src/common/decimal';
import type { InvestmentResourceMetaDto } from '../../investment-resource.dto';
import { add, decimalFromString, formatDecimal } from '../../../../common/decimal';
import { investmentResourceMeta } from '../../investment-resource.mapper';
import {
ForecastRepository,
@@ -1,5 +1,5 @@
import assert from 'node:assert/strict';
jest.mock('../../../../prisma/prisma.service', () => ({
jest.mock('#src/prisma/prisma.service', () => ({
PrismaService: class {},
}));
import { PortfolioDto } from '../presentation/portfolio.dto';
@@ -4,10 +4,10 @@ import {
} from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import type { Prisma } from '../../../../../generated/prisma/client';
import type { Prisma } from '#generated/prisma/client';
import { StructuredLogger } from '../../../../common/logging/structured-logger.service';
import { isTbankErrorCode, TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
import { StructuredLogger } from '#src/common/logging/structured-logger.service';
import { isTbankErrorCode, TbankErrorCode } from '#src/integrations/tbank/tbank-error-code';
import {
InstrumentMetadataService,
metadataKey,
@@ -17,7 +17,8 @@ import {
type TbankMoney,
type TbankPortfolio,
tbankSourceTtlMs,
} from '../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import { investmentResourceMeta } from '../../investment-resource.mapper';
import {
hourlyAttempt,
@@ -1,8 +1,9 @@
import { NotFoundException } from '@nestjs/common';
jest.mock('../../../../prisma/prisma.service', () => ({ PrismaService: class {} }));
import { TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
import { InstrumentIdType } from '../../../../integrations/tbank/tbank-protocol';
jest.mock('#src/prisma/prisma.service', () => ({ PrismaService: class {} }));
import { TbankErrorCode } from '#src/integrations/tbank/tbank-error-code';
import { InstrumentIdType } from '#src/integrations/tbank/tbank-protocol';
import { PositionClassificationService } from './position-classification.service';
describe('PositionClassificationService', () => {
@@ -1,12 +1,13 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { isZero } from '../../../../common/decimal';
import { StructuredLogger } from '../../../../common/logging/structured-logger.service';
import { MILLISECONDS_PER_DAY } from '../../../../common/time';
import { decimal } from '../../../../integrations/tbank/decimal';
import { isTbankErrorCode, TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
import { InstrumentIdType } from '../../../../integrations/tbank/tbank-protocol';
import { metadataKey, TbankClient, type TbankPortfolio } from '../../../../integrations/tbank/tbank.api';
import { isZero } from '#src/common/decimal';
import { StructuredLogger } from '#src/common/logging/structured-logger.service';
import { MILLISECONDS_PER_DAY } from '#src/common/time';
import { decimal } from '#src/integrations/tbank/decimal';
import { isTbankErrorCode, TbankErrorCode } from '#src/integrations/tbank/tbank-error-code';
import { InstrumentIdType } from '#src/integrations/tbank/tbank-protocol';
import { metadataKey, TbankClient, type TbankPortfolio } from '#src/integrations/tbank/tbank.api';
import { PositionClassificationRepository } from '../infrastructure/position-classification.repository';
export type Classification = { issuer: null | { id: string; name: string }; sector: null | string };
@@ -1,11 +1,11 @@
import type { Money } from '../../../../common/money.types';
import type { Money } from '#src/common/money.types';
import {
add,
DECIMAL_RADIX,
decimalFromString,
formatDecimal,
} from '../../../../common/decimal';
} from '#src/common/decimal';
const ZERO_AMOUNT = 0n;
const INITIAL_UNVALUED_COUNT = 0;
@@ -1,10 +1,10 @@
import type { Money } from '../../../../common/money.types';
import type { Money } from '#src/common/money.types';
import {
add,
decimalFromString,
formatDecimal,
} from '../../../../common/decimal';
} from '#src/common/decimal';
export function sumMoneyByCurrency(amounts: Money[]): Money[] {
const totals = new Map<string, ReturnType<typeof decimalFromString>>();
@@ -1,10 +1,10 @@
import { Injectable } from '@nestjs/common';
import { isDeepStrictEqual } from 'node:util';
import type { Prisma } from '../../../../../generated/prisma/client';
import type { Prisma } from '#generated/prisma/client';
import { PrismaService } from '../../../../prisma/prisma.service';
import { toJson } from '../../../../prisma/to-json';
import { PrismaService } from '#src/prisma/prisma.service';
import { toJson } from '#src/prisma/to-json';
const FIRST_BATCH_OFFSET = 0;
@@ -1,14 +1,15 @@
import { Injectable } from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import type { Prisma } from '../../../../../generated/prisma/client';
import type { PortfolioDto } from '../presentation/portfolio.dto';
import type { Prisma } from '#generated/prisma/client';
import { TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
import { lockConnectionGeneration } from '../../../../integrations/tbank/tbank-sync-claim';
import { isJoinableRunningAttempt, tbankSourceNeedsRefresh, tbankSourceTtlMs } from '../../../../integrations/tbank/tbank.api';
import { PrismaService } from '../../../../prisma/prisma.service';
import { toJson } from '../../../../prisma/to-json';
import { TbankErrorCode } from '#src/integrations/tbank/tbank-error-code';
import { lockConnectionGeneration } from '#src/integrations/tbank/tbank-sync-claim';
import { isJoinableRunningAttempt, tbankSourceNeedsRefresh, tbankSourceTtlMs } from '#src/integrations/tbank/tbank.api';
import { PrismaService } from '#src/prisma/prisma.service';
import { toJson } from '#src/prisma/to-json';
import type { PortfolioDto } from '../presentation/portfolio.dto';
const EXPECTED_UPDATED_ACCOUNTS = 1;
@@ -1,6 +1,6 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../../../prisma/prisma.service';
import { PrismaService } from '#src/prisma/prisma.service';
@Injectable()
export class PositionClassificationRepository {
@@ -1,6 +1,4 @@
import type { Money } from '../../../../common/money.types';
import type { Classification } from '../application/position-classification.service';
import type { PortfolioDto, PortfolioPositionDto } from '../presentation/portfolio.dto';
import type { Money } from '#src/common/money.types';
import {
add,
@@ -9,15 +7,19 @@ import {
isZero,
multiply,
subtract,
} from '../../../../common/decimal';
import { decimal } from '../../../../integrations/tbank/decimal';
} from '#src/common/decimal';
import { decimal } from '#src/integrations/tbank/decimal';
import {
metadataKey,
type TbankInstrument,
type TbankMoney,
TbankPortfolio,
TbankPositions,
} from '../../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import type { Classification } from '../application/position-classification.service';
import type { PortfolioDto, PortfolioPositionDto } from '../presentation/portfolio.dto';
import { portfolioStructure } from '../domain/portfolio-structure';
const types: Record<string, string> = {
@@ -1,6 +1,7 @@
import { Module } from '@nestjs/common';
import { TbankModule } from '../../../integrations/tbank/tbank.module';
import { TbankModule } from '#src/integrations/tbank/tbank.module';
import { AuthModule } from '../../auth/auth.module';
import { TbankSyncRepositoryModule } from '../tbank-sync/tbank-sync-repository.module';
import { ForecastService } from './application/forecast.service';
@@ -3,8 +3,9 @@ import type { Request } from 'express';
import { Controller, Get, Param, Req, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { ApiProblemResponses } from '../../../../common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '../../../auth/auth.api';
import { ApiProblemResponses } from '#src/common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '#src/modules/auth/auth.api';
import { PortfolioService } from '../application/portfolio.service';
import { PortfolioResourceDto } from './portfolio.dto';
@@ -1,6 +1,7 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { MoneyDto } from '../../../../common/money.dto';
import { MoneyDto } from '#src/common/money.dto';
import { AccountReferenceDto } from '../../account-reference.dto';
import { InvestmentResourceMetaDto } from '../../investment-resource.dto';
@@ -18,7 +18,8 @@ import {
ApiTags,
} from '@nestjs/swagger';
import { ApiProblemResponses } from '../../../common/decorators/api-safe-error-response.decorator';
import { ApiProblemResponses } from '#src/common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '../../auth/auth.api';
import {
PutTbankConnectionDto,
@@ -1,6 +1,7 @@
import { Module } from '@nestjs/common';
import { TbankModule } from '../../../integrations/tbank/tbank.module';
import { TbankModule } from '#src/integrations/tbank/tbank.module';
import { AuthModule } from '../../auth/auth.module';
import { TbankSyncModule } from '../tbank-sync/tbank-sync.module';
import { TbankConnectionController } from './tbank-connection.controller';
@@ -1,12 +1,12 @@
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { HttpErrorCode } from '../../../common/error-code';
import { HttpErrorCode } from '#src/common/error-code';
import {
supportedTbankAccounts,
TbankClient,
TbankTokenService,
} from '../../../integrations/tbank/tbank.api';
import { PrismaService } from '../../../prisma/prisma.service';
} from '#src/integrations/tbank/tbank.api';
import { PrismaService } from '#src/prisma/prisma.service';
type TbankTokenValidator = Pick<TbankClient, 'validateToken'>;
@@ -1,14 +1,15 @@
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import { StructuredLogger } from '../../../common/logging/structured-logger.service';
import { TbankErrorCode } from '../../../integrations/tbank/tbank-error-code';
import { StructuredLogger } from '#src/common/logging/structured-logger.service';
import { TbankErrorCode } from '#src/integrations/tbank/tbank-error-code';
import {
TbankAccessService,
TbankMembershipService,
type TbankSyncAttempt,
} from '../../../integrations/tbank/tbank.api';
import { PrismaService } from '../../../prisma/prisma.service';
} from '#src/integrations/tbank/tbank.api';
import { PrismaService } from '#src/prisma/prisma.service';
import { BrokerageOperationsSyncService } from '../operations/operations.api';
import { PortfolioService } from '../portfolio/portfolio.api';
import { UpcomingEventsService } from '../upcoming-events/upcoming-events.service';
@@ -1,8 +1,9 @@
import { BadRequestException } from '@nestjs/common';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '#src/common/time';
import type { InvestmentScreenDto } from './tbank-sync.dto';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../common/time';
import { MIN_INSTRUMENT_QUERY_LENGTH } from '../instrument-query';
// Reject fields from other screens before reserving any source work.
@@ -8,7 +8,8 @@ import {
ApiTags,
} from '@nestjs/swagger';
import { ApiProblemResponses } from '../../../common/decorators/api-safe-error-response.decorator';
import { ApiProblemResponses } from '#src/common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '../../auth/auth.api';
import {
EventsInvestmentScreenDto,
@@ -1,6 +1,7 @@
import { Module } from '@nestjs/common';
import { TbankModule } from '../../../integrations/tbank/tbank.module';
import { TbankModule } from '#src/integrations/tbank/tbank.module';
import { AuthModule } from '../../auth/auth.module';
import { InstrumentSourcesModule } from '../instruments/instrument-sources.module';
import { OperationsModule } from '../operations/operations.module';
@@ -1,4 +1,4 @@
jest.mock('../../../prisma/prisma.service', () => ({
jest.mock('#src/prisma/prisma.service', () => ({
PrismaService: class {},
}));
@@ -1,14 +1,15 @@
import { Injectable } from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import type { Prisma } from '../../../../generated/prisma/client';
import type { TbankSyncAttempt } from '../../../integrations/tbank/tbank.api';
import type { Prisma } from '#generated/prisma/client';
import type { TbankSyncAttempt } from '#src/integrations/tbank/tbank.api';
import { claimSyncWork, lockConnectionGeneration } from '#src/integrations/tbank/tbank-sync-claim';
import { PrismaService } from '#src/prisma/prisma.service';
import { toJson } from '#src/prisma/to-json';
import type { InvestmentAttemptDto } from '../investment-resource.dto';
import type { InvestmentScreenDto } from './tbank-sync.dto';
import { claimSyncWork, lockConnectionGeneration } from '../../../integrations/tbank/tbank-sync-claim';
import { PrismaService } from '../../../prisma/prisma.service';
import { toJson } from '../../../prisma/to-json';
export type ScreenIntent = { now: string; scope: InvestmentScreenDto };
// Json columns are written only by this repository; a shape check turns corruption into an explicit 500.
@@ -5,7 +5,8 @@ import {
} from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import { TbankAccessService } from '../../../integrations/tbank/tbank.api';
import { TbankAccessService } from '#src/integrations/tbank/tbank.api';
import { BrokerageOperationsSyncService } from '../operations/operations.api';
import { TbankSyncStatusDto } from './tbank-sync.dto';
import { screenIntent, TbankSyncRepository } from './tbank-sync.repository';
@@ -1,13 +1,14 @@
import type { MoexBondEvent } from '../../../integrations/moex/moex.api';
import type { TbankDividend } from '../../../integrations/tbank/tbank.api';
import type { MoexBondEvent } from '#src/integrations/moex/moex.api';
import type { TbankDividend } from '#src/integrations/tbank/tbank.api';
import {
decimalFromString,
formatDecimal,
multiply,
} from '../../../common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START, MILLISECONDS_PER_SECOND } from '../../../common/time';
import { decimal } from '../../../integrations/tbank/decimal';
} from '#src/common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START, MILLISECONDS_PER_SECOND } from '#src/common/time';
import { decimal } from '#src/integrations/tbank/decimal';
import { UpcomingEventDto } from './upcoming-events.dto';
export function dividendEvent(
@@ -1,4 +1,4 @@
jest.mock('../../../prisma/prisma.service', () => ({
jest.mock('#src/prisma/prisma.service', () => ({
PrismaService: class PrismaService {},
}));
@@ -3,7 +3,8 @@ import type { Request } from 'express';
import { Controller, Get, Param, Query, Req, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { ApiProblemResponses } from '../../../common/decorators/api-safe-error-response.decorator';
import { ApiProblemResponses } from '#src/common/decorators/api-safe-error-response.decorator';
import { AccessPayload, JwtAuthGuard } from '../../auth/auth.api';
import {
UpcomingEventsQueryDto,
@@ -1,7 +1,8 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsDateString, IsOptional, Matches } from 'class-validator';
import { MoneyDto } from '../../../common/money.dto';
import { MoneyDto } from '#src/common/money.dto';
import { AccountReferenceDto } from '../account-reference.dto';
import {
InvestmentReadQueryDto,
@@ -1,6 +1,7 @@
import { Module } from '@nestjs/common';
import { TbankModule } from '../../../integrations/tbank/tbank.module';
import { TbankModule } from '#src/integrations/tbank/tbank.module';
import { AuthModule } from '../../auth/auth.module';
import { InstrumentSourcesModule } from '../instruments/instrument-sources.module';
import { PortfolioModule } from '../portfolio/portfolio.module';
@@ -1,6 +1,7 @@
import { decimalFromString } from '../../../common/decimal';
import { decimalFromString } from '#src/common/decimal';
import { bondEvent, dividendEvent } from './upcoming-event.mapper';
jest.mock('../../../prisma/prisma.service', () => ({
jest.mock('#src/prisma/prisma.service', () => ({
PrismaService: class {},
}));
const metadata = {
@@ -6,14 +6,15 @@ import {
decimalFromString,
formatDecimal,
isZero,
} from '../../../common/decimal';
import { MoneyDto } from '../../../common/money.dto';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../common/time';
} from '#src/common/decimal';
import { MoneyDto } from '#src/common/money.dto';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '#src/common/time';
import {
InstrumentMetadataService,
metadataKey,
TbankAccessService,
} from '../../../integrations/tbank/tbank.api';
} from '#src/integrations/tbank/tbank.api';
import { CatalogEnrichmentService } from '../instruments/instruments.api';
import { investmentResourceMeta } from '../investment-resource.mapper';
import {