feat(income): add account income analytics API

This commit is contained in:
2026-08-28 01:25:52 +03:00
parent 924f60f653
commit 7ba4da0d1b
13 changed files with 997 additions and 49 deletions
+136
View File
@@ -0,0 +1,136 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, Matches } from 'class-validator';
import { BrokerageOperationDto } from './brokerage-operation.dto';
import { MoneyDto } from './portfolio.dto';
const dateOnly = /^\d{4}-\d{2}-\d{2}$/;
export class IncomeAnalyticsQueryDto {
@ApiPropertyOptional({ format: 'date' })
@IsOptional()
@Matches(dateOnly)
from?: string;
@ApiPropertyOptional({ format: 'date' })
@IsOptional()
@Matches(dateOnly)
to?: string;
}
export class IncomePeriodDto {
@ApiProperty({ format: 'date' })
from: string;
@ApiProperty({ format: 'date' })
to: string;
}
export class IncomeCurrencySummaryDto {
@ApiProperty()
currency: string;
@ApiProperty({ type: MoneyDto })
coupon: MoneyDto;
@ApiProperty({ type: MoneyDto })
dividend: MoneyDto;
@ApiProperty({ type: MoneyDto })
total: MoneyDto;
}
export class IncomeSummaryDto {
@ApiProperty()
accountId: string;
@ApiProperty({ type: IncomePeriodDto })
period: IncomePeriodDto;
@ApiProperty({ type: IncomeCurrencySummaryDto, isArray: true })
totalsByCurrency: IncomeCurrencySummaryDto[];
@ApiProperty({ format: 'date-time' })
calculatedAt: string;
}
export class IncomeComparisonCurrencyDto {
@ApiProperty()
currency: string;
@ApiProperty({ type: IncomeCurrencySummaryDto })
selected: IncomeCurrencySummaryDto;
@ApiProperty({ type: IncomeCurrencySummaryDto })
compared: IncomeCurrencySummaryDto;
@ApiProperty({ type: IncomeCurrencySummaryDto })
difference: IncomeCurrencySummaryDto;
}
export class IncomeComparisonDto {
@ApiProperty({ type: IncomePeriodDto })
period: IncomePeriodDto;
@ApiProperty({ type: IncomeComparisonCurrencyDto, isArray: true })
totalsByCurrency: IncomeComparisonCurrencyDto[];
}
export class IncomeBucketDto {
@ApiProperty({ type: IncomePeriodDto })
period: IncomePeriodDto;
@ApiProperty({ type: IncomeCurrencySummaryDto, isArray: true })
totalsByCurrency: IncomeCurrencySummaryDto[];
}
export class IncomeInstrumentDto {
@ApiProperty()
key: string;
@ApiProperty({ type: String, nullable: true })
figi: string | null;
@ApiProperty({ type: String, nullable: true })
instrumentUid: string | null;
@ApiProperty({ type: String, nullable: true })
ticker: string | null;
@ApiProperty({ type: String, nullable: true })
instrumentType: string | null;
@ApiProperty()
displayName: string;
@ApiProperty({ type: MoneyDto })
coupon: MoneyDto;
@ApiProperty({ type: MoneyDto })
dividend: MoneyDto;
@ApiProperty({ type: MoneyDto })
total: MoneyDto;
@ApiProperty()
receiptCount: number;
}
export class IncomeAnalyticsDto extends IncomeSummaryDto {
@ApiProperty({ type: IncomeComparisonDto })
previous: IncomeComparisonDto;
@ApiProperty({ type: IncomeComparisonDto, nullable: true })
yearComparison: IncomeComparisonDto | null;
@ApiProperty({ enum: ['day', 'week', 'month'] })
bucketGranularity: 'day' | 'week' | 'month';
@ApiProperty({ type: IncomeBucketDto, isArray: true })
buckets: IncomeBucketDto[];
@ApiProperty({ type: IncomeInstrumentDto, isArray: true })
instruments: IncomeInstrumentDto[];
@ApiProperty({ type: BrokerageOperationDto, isArray: true })
entries: BrokerageOperationDto[];
}