import { Type } from 'class-transformer'; import { Allow, IsArray, IsBoolean, IsDateString, IsIn, IsInt, IsNumber, IsObject, IsOptional, IsString, Max, MaxLength, Min, MinLength, ValidateIf, ValidateNested, } from 'class-validator'; export class CreatePipelineDto { @IsString() @MinLength(2) @MaxLength(120) name!: string; } export class CreatePipelineStageDto { @IsString() @MinLength(1) @MaxLength(80) name!: string; } export class UpdatePipelineStageDto { @IsOptional() @IsString() @MinLength(1) @MaxLength(80) name?: string; } export class ReorderPipelineStagesDto { @IsArray() @IsString({ each: true }) stageIds!: string[]; } export class DealLineItemInputDto { @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @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 CreateDealDto { @IsString() @MinLength(2) @MaxLength(200) title!: string; @IsOptional() @IsString() pipelineId?: string; @IsOptional() @IsString() stageId?: string; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @Type(() => Number) @IsNumber() @Min(0) amount?: number | null; @IsOptional() @IsString() @MaxLength(8) currency?: string; @IsOptional() @IsString() @MaxLength(120) source?: string; @IsOptional() @IsString() @MaxLength(2000) notes?: string; @IsOptional() @IsArray() @IsString({ each: true }) tags?: string[]; @IsOptional() @IsBoolean() isStale?: boolean; @IsOptional() @IsBoolean() isRotten?: boolean; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() @MaxLength(80) code?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @Type(() => Number) @IsInt() @Min(0) @Max(100) probability?: number | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() @MaxLength(200) sourceDetail?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() @MaxLength(200) referrer?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() @MaxLength(2000) lostNote?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsDateString() closedAt?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsDateString() expectedCloseAt?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() personId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() companyId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() ownerId?: string | null; @IsOptional() @IsArray() @IsString({ each: true }) assigneeIds?: string[]; @IsOptional() @IsObject() customFields?: Record; @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => DealLineItemInputDto) lineItems?: DealLineItemInputDto[]; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() @MaxLength(400) lostReason?: string | null; } export class UpdateDealDto { @IsOptional() @IsString() @MinLength(2) @MaxLength(200) title?: string; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @Type(() => Number) @IsNumber() @Min(0) amount?: number | null; @IsOptional() @IsString() @MaxLength(8) currency?: string; @IsOptional() @IsString() @MaxLength(120) source?: string; @IsOptional() @IsString() @MaxLength(2000) notes?: string; @IsOptional() @IsArray() @IsString({ each: true }) tags?: string[]; @IsOptional() @IsBoolean() isStale?: boolean; @IsOptional() @IsBoolean() isRotten?: boolean; @IsOptional() @IsString() @MaxLength(400) lostReason?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() @MaxLength(80) code?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @Type(() => Number) @IsInt() @Min(0) @Max(100) probability?: number | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() @MaxLength(200) sourceDetail?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() @MaxLength(200) referrer?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() @MaxLength(2000) lostNote?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsDateString() closedAt?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsDateString() expectedCloseAt?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() personId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() companyId?: string | null; @IsOptional() @ValidateIf((_, v) => v !== '' && v != null) @IsString() ownerId?: string | null; @IsOptional() @IsArray() @IsString({ each: true }) assigneeIds?: string[]; @IsOptional() @IsObject() customFields?: Record; @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => DealLineItemInputDto) lineItems?: DealLineItemInputDto[]; } /** تکه‌های JSON از ایمپورت مرورگرگرا */ export class ImportDealRowsDto { @IsArray() @Allow() rows!: Array>; @Type(() => Number) @IsInt() @Min(0) offset!: number; @Type(() => Number) @IsInt() @Min(0) total!: number; @IsOptional() @IsString() sessionId?: string; } export class MoveDealDto { @IsString() stageId!: string; @IsOptional() @Type(() => Number) @IsNumber() @Min(0) position?: number; } export class MergePipelineDto { @IsString() @MinLength(1) targetPipelineId!: string; @IsObject() stageMap!: Record; @IsOptional() @IsString() @IsIn(['retarget_all']) leadFormMode?: 'retarget_all'; }