Files
backend/src/modules/investments/income/income-analytics.dto.ts
T
ksv741 516e43203e
Backend security / security (push) Successful in 9s
Backend verify / verify (push) Successful in 10m23s
Backend security / security (pull_request) Successful in 8s
Backend verify / verify (pull_request) Successful in 10m39s
Conventional commits / commits (pull_request) Successful in 29s
fix(investments): align roles and date contracts
Identify income dependencies by role and document screen-specific dates.
Convert inclusive calendar days into half-open source ranges while
preserving operation timestamps and existing stored coverage.
2026-09-27 11:38:13 +03:00

188 lines
5.1 KiB
TypeScript

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, Matches } from 'class-validator';
import { MoneyDto } from '../../../common/money.dto';
import { BrokerageOperationDto } from '../operations/operations.api';
import {
InvestmentDependencyDto,
InvestmentReadQueryDto,
InvestmentResourceMetaDto,
} from '../investment-resource.dto';
const dateOnly = /^\d{4}-\d{2}-\d{2}$/;
export class IncomeAnalyticsQueryDto extends InvestmentReadQueryDto {
@ApiPropertyOptional({
format: 'date',
description:
'Inclusive calendar date in Europe/Moscow. Supply both from/to or neither.',
})
@IsOptional()
@Matches(dateOnly)
from?: string;
@ApiPropertyOptional({
format: 'date',
description:
'Inclusive calendar date in Europe/Moscow, no later than today. Supply both from/to or neither.',
})
@IsOptional()
@Matches(dateOnly)
to?: string;
}
export class IncomePeriodDto {
@ApiProperty({ format: 'date' })
declare from: string;
@ApiProperty({ format: 'date' })
declare to: string;
}
export class IncomeCurrencySummaryDto {
@ApiProperty()
declare currency: string;
@ApiProperty({ type: MoneyDto })
declare coupon: MoneyDto;
@ApiProperty({ type: MoneyDto })
declare dividend: MoneyDto;
@ApiProperty({ type: MoneyDto })
declare total: MoneyDto;
}
export class IncomeSummaryDto {
@ApiProperty()
declare accountId: string;
@ApiProperty({ type: IncomePeriodDto })
declare period: IncomePeriodDto;
@ApiProperty({ type: IncomeCurrencySummaryDto, isArray: true })
declare totalsByCurrency: IncomeCurrencySummaryDto[];
@ApiProperty({ format: 'date-time' })
declare calculatedAt: string;
}
export class IncomeComparisonCurrencyDto {
@ApiProperty()
declare currency: string;
@ApiProperty({ type: IncomeCurrencySummaryDto })
declare selected: IncomeCurrencySummaryDto;
@ApiProperty({ type: IncomeCurrencySummaryDto })
declare compared: IncomeCurrencySummaryDto;
@ApiProperty({ type: IncomeCurrencySummaryDto })
declare difference: IncomeCurrencySummaryDto;
}
export class IncomeComparisonDto {
@ApiProperty({ type: IncomePeriodDto })
declare period: IncomePeriodDto;
@ApiProperty({ type: IncomeComparisonCurrencyDto, isArray: true })
declare totalsByCurrency: IncomeComparisonCurrencyDto[];
}
export class IncomeBucketDto {
@ApiProperty({ type: IncomePeriodDto })
declare period: IncomePeriodDto;
@ApiProperty({ type: IncomeCurrencySummaryDto, isArray: true })
declare totalsByCurrency: IncomeCurrencySummaryDto[];
}
export class IncomeInstrumentDto {
@ApiProperty()
declare key: string;
@ApiProperty({ type: String, nullable: true })
declare figi: string | null;
@ApiProperty({ type: String, nullable: true })
declare instrumentUid: string | null;
@ApiProperty({ type: String, nullable: true })
declare ticker: string | null;
@ApiProperty({ type: String, nullable: true })
declare instrumentType: string | null;
@ApiProperty()
declare displayName: string;
@ApiProperty({ type: MoneyDto })
declare coupon: MoneyDto;
@ApiProperty({ type: MoneyDto })
declare dividend: MoneyDto;
@ApiProperty({ type: MoneyDto })
declare total: MoneyDto;
@ApiProperty()
declare receiptCount: number;
}
export class IncomeAnalyticsEntryDto extends BrokerageOperationDto {
@ApiProperty()
declare instrumentKey: string;
}
export class IncomeAnalyticsDto extends IncomeSummaryDto {
@ApiProperty({ type: IncomeComparisonDto, nullable: true })
declare previous: IncomeComparisonDto | null;
@ApiProperty({ type: IncomeComparisonDto, nullable: true })
declare yearComparison: IncomeComparisonDto | null;
@ApiProperty({ enum: ['day', 'week', 'month'] })
declare bucketGranularity: 'day' | 'week' | 'month';
@ApiProperty({ type: IncomeBucketDto, isArray: true })
declare buckets: IncomeBucketDto[];
@ApiProperty({ type: IncomeInstrumentDto, isArray: true })
declare instruments: IncomeInstrumentDto[];
@ApiProperty({ type: IncomeAnalyticsEntryDto, isArray: true })
declare entries: IncomeAnalyticsEntryDto[];
}
export class IncomeSummaryResourceDto {
@ApiProperty({ type: IncomeSummaryDto, nullable: true })
declare data: IncomeSummaryDto | null;
@ApiProperty({ type: InvestmentResourceMetaDto })
declare meta: InvestmentResourceMetaDto;
}
const incomeDependencyRoles = ['selected', 'previous', 'year'] as const;
export class IncomeDependencyDto extends InvestmentDependencyDto {
@ApiProperty({ enum: incomeDependencyRoles })
declare role: (typeof incomeDependencyRoles)[number];
}
export class IncomeAnalyticsMetaDto extends InvestmentResourceMetaDto {
@ApiProperty({
type: IncomeDependencyDto,
isArray: true,
required: true,
description:
'Dependencies identified by role, not array order or resourceKey. A missing role is unavailable.',
})
declare dependencies: IncomeDependencyDto[];
}
export class IncomeAnalyticsResourceDto {
@ApiProperty({ type: IncomeAnalyticsDto, nullable: true })
declare data: IncomeAnalyticsDto | null;
@ApiProperty({ type: IncomeAnalyticsMetaDto })
declare meta: IncomeAnalyticsMetaDto;
}