refactor: replace ignored numeric literals with constants

This commit is contained in:
2026-09-28 16:37:01 +03:00
committed by ksv741
parent a970eaaf7a
commit b78c215ff1
60 changed files with 510 additions and 283 deletions
@@ -12,6 +12,8 @@ import {
StockSearchResourceDto,
} from '../presentation/stock.dto';
const MIN_LOT_EXCLUSIVE = 0;
type IdentifiedShare = TbankShare & { uid: string };
@Injectable()
@@ -102,7 +104,7 @@ function stock(share: IdentifiedShare): StockDto {
currency: share.currency?.toUpperCase() || null,
shareType: share.shareType || null,
sector: share.sector || null,
lot: share.lot && share.lot > 0 ? share.lot : null,
lot: share.lot && share.lot > MIN_LOT_EXCLUSIVE ? share.lot : null,
historyFrom: timestamp(share.first_1dayCandleDate),
};
}
@@ -5,6 +5,7 @@ import {
formatDecimal,
multiply,
} from '../../../../../common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../../../common/time';
import { decimal } from '../../../../../integrations/tbank/decimal';
import {
TbankAccessService,
@@ -23,6 +24,10 @@ import {
StockDividendsResourceDto,
StockPositionDto,
} from '../presentation/stock.dto';
const INCOME_FORECAST_YEARS = 1;
const ZERO_QUANTITY = 0n;
const ISO_YEAR_LENGTH = 4;
const INCOME_HISTORY_YEARS = 5;
@Injectable()
@@ -49,8 +54,8 @@ export class StockIncomeService {
): Promise<StockDividendsResourceDto> {
const connection = await this.access.local(userId);
const today = moscowDay(new Date().toISOString());
const from = `${Number(today.slice(0, ISO_YEAR_LENGTH)) - INCOME_HISTORY_YEARS}${today.slice(ISO_YEAR_LENGTH)}`;
const to = `${Number(today.slice(0, ISO_YEAR_LENGTH)) + 1}${today.slice(ISO_YEAR_LENGTH)}`;
const from = `${Number(today.slice(ISO_DATE_START, ISO_YEAR_LENGTH)) - INCOME_HISTORY_YEARS}${today.slice(ISO_YEAR_LENGTH)}`;
const to = `${Number(today.slice(ISO_DATE_START, ISO_YEAR_LENGTH)) + INCOME_FORECAST_YEARS}${today.slice(ISO_YEAR_LENGTH)}`;
const portfolio = await this.portfolios.read(userId, 'all', observe);
const sources = await this.sources.readMany(
userId,
@@ -112,15 +117,15 @@ export function stockDividends(
const quantity =
position &&
position.accounts.length &&
position.accounts.every((p) => decimalFromString(p.quantity).value > 0n) ?
position.accounts.every((p) => decimalFromString(p.quantity).value > ZERO_QUANTITY) ?
decimalFromString(position.quantity) :
null;
const dividends: StockDividendDto[] = events
.filter((event) => event.dividendType?.toLowerCase() !== 'cancelled')
.map((event) => {
const recordDate = timestamp(event.recordDate)?.slice(0, 10) ?? null;
const paymentDate = timestamp(event.paymentDate)?.slice(0, 10) ?? null;
const lastBuyDate = timestamp(event.lastBuyDate)?.slice(0, 10) ?? null;
const recordDate = timestamp(event.recordDate)?.slice(ISO_DATE_START, ISO_DATE_LENGTH) ?? null;
const paymentDate = timestamp(event.paymentDate)?.slice(ISO_DATE_START, ISO_DATE_LENGTH) ?? null;
const lastBuyDate = timestamp(event.lastBuyDate)?.slice(ISO_DATE_START, ISO_DATE_LENGTH) ?? null;
const currency = event.dividendNet?.currency?.toUpperCase();
const perShare =
currency && event.dividendNet ?
@@ -7,6 +7,7 @@ import {
multiply,
subtract,
} from '../../../../../common/decimal';
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../../../common/time';
import { decimal } from '../../../../../integrations/tbank/decimal';
import { CandleService } from '../../application/candle.service';
import {
@@ -20,6 +21,8 @@ import {
StockQuoteResourceDto,
} from '../presentation/stock.dto';
const ZERO_AMOUNT = 0n;
const CHANGE_PERCENT_DECIMAL_PLACES = 6;
@Injectable()
export class StockMarketService {
@@ -90,7 +93,7 @@ export function stockQuote(
price,
priceAt,
tradingStatus,
previousCloseDate: timestamp(previous?.time)?.slice(0, 10) ?? null,
previousCloseDate: timestamp(previous?.time)?.slice(ISO_DATE_START, ISO_DATE_LENGTH) ?? null,
previousClose: previousPrice,
change:
difference && currency ?
@@ -99,7 +102,7 @@ export function stockQuote(
changePercent:
difference &&
previousPrice &&
decimalFromString(previousPrice.value).value > 0n ?
decimalFromString(previousPrice.value).value > ZERO_AMOUNT ?
formatDecimal(
divide(
multiply(difference, decimalFromString('100')),
@@ -10,32 +10,36 @@ import {
} from 'class-validator';
import { MoneyDto } from '../../../../../common/money.dto';
import {
MAX_INSTRUMENT_QUERY_LENGTH,
MIN_INSTRUMENT_QUERY_LENGTH,
} from '../../../instrument-query';
import {
InvestmentReadQueryDto,
InvestmentResourceMetaDto,
} from '../../../investment-resource.dto';
import { PortfolioPositionDto } from '../../../portfolio/portfolio.api';
const MAX_INSTRUMENT_QUERY_LENGTH = 80;
const MIN_TICKER_LENGTH = 1;
export class StockSearchQueryDto extends InvestmentReadQueryDto {
@ApiProperty({ minLength: 2, maxLength: MAX_INSTRUMENT_QUERY_LENGTH })
@ApiProperty({ minLength: MIN_INSTRUMENT_QUERY_LENGTH, maxLength: MAX_INSTRUMENT_QUERY_LENGTH })
@Transform(({ value }: { value: unknown }) =>
typeof value === 'string' ? value.trim() : value,
)
@IsString()
@MinLength(2)
@MinLength(MIN_INSTRUMENT_QUERY_LENGTH)
@MaxLength(MAX_INSTRUMENT_QUERY_LENGTH)
declare query: string;
}
export class StockTickerParamsDto {
@ApiProperty({
minLength: 1,
minLength: MIN_TICKER_LENGTH,
maxLength: MAX_INSTRUMENT_QUERY_LENGTH,
pattern: '^[A-Za-z0-9][A-Za-z0-9._@+-]*$',
})
@IsString()
@MinLength(1)
@MinLength(MIN_TICKER_LENGTH)
@MaxLength(MAX_INSTRUMENT_QUERY_LENGTH)
@Matches(/^[A-Z0-9][\w.@+-]*$/i)
declare ticker: string;