import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Transform, Type } from 'class-transformer'; import { IsArray, IsDateString, IsEnum, IsInt, IsOptional, IsString, IsUUID, Max, MaxLength, Min, } from 'class-validator'; import { MoneyDto } from '../../../../common/money.dto'; import { AccountReferenceDto } from '../../account-reference.dto'; import { InvestmentResourceMetaDto } from '../../investment-resource.dto'; const MIN_OPERATIONS_PAGE_SIZE = 1; const MAX_CURSOR_LENGTH = 4096; const MAX_OPERATIONS_PAGE_SIZE = 1000; export const DEFAULT_OPERATIONS_PAGE_SIZE = 100; export const operationCategories = [ 'trade', 'income', 'tax', 'fee', 'transfer', 'other', ] as const; export type OperationCategory = (typeof operationCategories)[number]; export class BrokerageOperationsQueryDto { @ApiPropertyOptional({ format: 'uuid', description: 'Instrument UID. Without from, includes history since the earliest available account opening.', }) @IsOptional() @IsUUID() instrumentUid?: string; @ApiPropertyOptional({ format: 'date-time' }) @IsOptional() @IsDateString() from?: string; @ApiPropertyOptional({ format: 'date-time' }) @IsOptional() @IsDateString() to?: string; @ApiPropertyOptional({ enum: operationCategories, isArray: true }) @IsOptional() @Transform(({ value }: { value: unknown }) => typeof value === 'string' ? value.split(',').filter(Boolean) : value, ) @IsArray() @IsEnum(operationCategories, { each: true }) categories?: OperationCategory[]; @ApiPropertyOptional() @IsOptional() @IsString() @MaxLength(MAX_CURSOR_LENGTH) cursor?: string; @ApiPropertyOptional({ minimum: MIN_OPERATIONS_PAGE_SIZE, maximum: MAX_OPERATIONS_PAGE_SIZE, default: DEFAULT_OPERATIONS_PAGE_SIZE, }) @IsOptional() @Type(() => Number) @IsInt() @Min(MIN_OPERATIONS_PAGE_SIZE) @Max(MAX_OPERATIONS_PAGE_SIZE) limit?: number; } export class BrokerageOperationDto { @ApiPropertyOptional({ type: AccountReferenceDto }) account?: AccountReferenceDto; @ApiProperty() declare id: string; @ApiProperty({ format: 'date-time' }) declare occurredAt: string; @ApiProperty() declare type: string; @ApiProperty({ enum: operationCategories }) declare category: OperationCategory; @ApiProperty() declare description: string; @ApiProperty({ type: String, nullable: true }) declare figi: null | string; @ApiProperty({ type: String, nullable: true }) declare instrumentUid: null | string; @ApiProperty({ type: String, nullable: true }) declare ticker: null | string; @ApiProperty({ type: String, nullable: true }) declare instrumentType: null | string; @ApiProperty({ type: String, nullable: true }) declare logoName: null | string; @ApiProperty({ type: MoneyDto, nullable: true }) declare payment: MoneyDto | null; @ApiProperty({ type: String, nullable: true }) declare quantity: null | string; @ApiProperty({ type: MoneyDto, nullable: true }) declare price: MoneyDto | null; @ApiProperty({ type: MoneyDto, nullable: true }) declare accruedInterest: MoneyDto | null; @ApiProperty({ type: MoneyDto, nullable: true }) declare commission: MoneyDto | null; } export class BrokerageOperationsPageDto { @ApiProperty() declare accountId: string; @ApiProperty({ type: BrokerageOperationDto, isArray: true }) declare items: BrokerageOperationDto[]; @ApiProperty({ type: String, nullable: true }) declare nextCursor: null | string; @ApiProperty() declare hasNext: boolean; @ApiProperty({ format: 'date-time' }) declare observedAt: string; } export class BrokerageOperationsResourceDto { @ApiProperty({ type: BrokerageOperationsPageDto, nullable: true }) declare data: BrokerageOperationsPageDto | null; @ApiProperty({ type: InvestmentResourceMetaDto }) declare meta: InvestmentResourceMetaDto; }