import { ArrayMinSize, IsArray, IsIn, IsNumber, IsOptional, IsString, MaxLength, Min, MinLength, ValidateNested, } from 'class-validator'; import { Type } from 'class-transformer'; const INVOICE_STATUSES = [ 'draft', 'issued', 'partially_paid', 'paid', 'canceled', ] as const; const PAYMENT_METHODS = [ 'cash', 'transfer', 'card', 'check', 'other', ] as const; export class InvoiceLineItemInputDto { @IsOptional() @IsString() productId?: string | null; @IsString() @MinLength(1) @MaxLength(200) name!: string; @Type(() => Number) @IsNumber() @Min(0.01) quantity!: number; @Type(() => Number) @IsNumber() @Min(0) unitPrice!: number; @IsOptional() @IsString() @MaxLength(8) currency?: string; } export class InvoiceInstallmentInputDto { @IsString() dueDate!: string; @Type(() => Number) @IsNumber() @Min(0.01) amount!: number; @IsOptional() @IsString() @MaxLength(8) currency?: string; } export class CreateInvoiceDto { @IsString() @MinLength(2) @MaxLength(200) title!: string; @IsOptional() @IsIn(INVOICE_STATUSES) status?: (typeof INVOICE_STATUSES)[number]; @IsOptional() @IsString() @MaxLength(8) currency?: string; @IsOptional() @IsString() @MaxLength(4000) notes?: string; @IsOptional() @IsString() issuedAt?: string | null; @IsOptional() @IsString() dueDate?: string | null; @IsOptional() @IsString() personId?: string | null; @IsOptional() @IsString() companyId?: string | null; @IsOptional() @IsString() dealId?: string | null; @IsOptional() @IsString() quoteId?: string | null; @IsOptional() @IsString() fromDealId?: string | null; @IsOptional() @IsString() fromQuoteId?: string | null; @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => InvoiceLineItemInputDto) @ArrayMinSize(0) lineItems?: InvoiceLineItemInputDto[]; @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => InvoiceInstallmentInputDto) installments?: InvoiceInstallmentInputDto[]; } export class UpdateInvoiceDto { @IsOptional() @IsString() @MinLength(2) @MaxLength(200) title?: string; @IsOptional() @IsIn(INVOICE_STATUSES) status?: (typeof INVOICE_STATUSES)[number]; @IsOptional() @IsString() @MaxLength(8) currency?: string; @IsOptional() @IsString() @MaxLength(4000) notes?: string | null; @IsOptional() @IsString() issuedAt?: string | null; @IsOptional() @IsString() dueDate?: string | null; @IsOptional() @IsString() personId?: string | null; @IsOptional() @IsString() companyId?: string | null; @IsOptional() @IsString() dealId?: string | null; @IsOptional() @IsString() quoteId?: string | null; @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => InvoiceLineItemInputDto) lineItems?: InvoiceLineItemInputDto[]; @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => InvoiceInstallmentInputDto) installments?: InvoiceInstallmentInputDto[]; } export class CreatePaymentDto { @Type(() => Number) @IsNumber() @Min(0.01) amount!: number; @IsOptional() @IsString() @MaxLength(8) currency?: string; @IsOptional() @IsIn(PAYMENT_METHODS) method?: (typeof PAYMENT_METHODS)[number]; @IsOptional() @IsString() paidAt?: string; @IsOptional() @IsString() @MaxLength(2000) notes?: string; @IsOptional() @IsString() installmentId?: string | null; } export class ListInvoicesQueryDto { @IsOptional() @IsString() q?: string; @IsOptional() @IsIn(INVOICE_STATUSES) status?: (typeof INVOICE_STATUSES)[number]; @IsOptional() @IsString() dealId?: string; @IsOptional() @IsString() personId?: string; @IsOptional() @IsString() quoteId?: string; @IsOptional() @Type(() => Number) @IsNumber() @Min(1) page?: number; @IsOptional() @Type(() => Number) @IsNumber() @Min(1) limit?: number; }