[CRIT-003] feat(validation): Add class-validator decorators to critical DTOs

- Add @Min(0) to monetary fields (prices, amounts)
- Add @Min(0)/@Max(100) to percentage fields (score, probability, rate)
- Add @IsEmail() to email fields with Spanish messages
- Add @IsUrl() to webhook URL field
- 10 DTOs updated with descriptive error messages in Spanish

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Adrian Flores Cortes 2026-02-03 17:23:09 -06:00
parent ff7fc41449
commit c4262498ee
10 changed files with 364 additions and 364 deletions

View File

@ -11,37 +11,37 @@ import {
import { EntryStatus } from '../entities'; import { EntryStatus } from '../entities';
export class CreateEntryDto { export class CreateEntryDto {
@IsUUID() @IsUUID('4', { message: 'El ID de usuario debe ser un UUID valido' })
userId: string; userId: string;
@IsUUID() @IsUUID('4', { message: 'El ID de esquema debe ser un UUID valido' })
schemeId: string; schemeId: string;
@IsUUID() @IsUUID('4', { message: 'El ID de asignacion debe ser un UUID valido' })
@IsOptional() @IsOptional()
assignmentId?: string; assignmentId?: string;
@IsString() @IsString({ message: 'El tipo de referencia debe ser una cadena de texto' })
@MaxLength(50) @MaxLength(50, { message: 'El tipo de referencia no puede exceder 50 caracteres' })
referenceType: string; referenceType: string;
@IsUUID() @IsUUID('4', { message: 'El ID de referencia debe ser un UUID valido' })
referenceId: string; referenceId: string;
@IsNumber() @IsNumber({}, { message: 'El monto base debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto base debe ser mayor o igual a 0' })
baseAmount: number; baseAmount: number;
@IsString() @IsString({ message: 'La moneda debe ser una cadena de texto' })
@MaxLength(3) @MaxLength(3, { message: 'La moneda no puede exceder 3 caracteres' })
@IsOptional() @IsOptional()
currency?: string; currency?: string;
@IsString() @IsString({ message: 'Las notas deben ser una cadena de texto' })
@IsOptional() @IsOptional()
notes?: string; notes?: string;
@IsObject() @IsObject({ message: 'Los metadatos deben ser un objeto' })
@IsOptional() @IsOptional()
metadata?: Record<string, any>; metadata?: Record<string, any>;
} }
@ -138,14 +138,14 @@ export class PaginatedEntriesDto {
} }
export class CalculateCommissionDto { export class CalculateCommissionDto {
@IsUUID() @IsUUID('4', { message: 'El ID de esquema debe ser un UUID valido' })
schemeId: string; schemeId: string;
@IsUUID() @IsUUID('4', { message: 'El ID de usuario debe ser un UUID valido' })
userId: string; userId: string;
@IsNumber() @IsNumber({}, { message: 'El monto debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto debe ser mayor o igual a 0' })
amount: number; amount: number;
} }

View File

@ -13,131 +13,131 @@ import {
import { SchemeType, AppliesTo } from '../entities'; import { SchemeType, AppliesTo } from '../entities';
export class TierDto { export class TierDto {
@IsNumber() @IsNumber({}, { message: 'El valor desde debe ser un numero' })
@Min(0) @Min(0, { message: 'El valor desde debe ser mayor o igual a 0' })
from: number; from: number;
@IsNumber() @IsNumber({}, { message: 'El valor hasta debe ser un numero' })
@IsOptional() @IsOptional()
to?: number; to?: number;
@IsNumber() @IsNumber({}, { message: 'La tasa debe ser un numero' })
@Min(0) @Min(0, { message: 'La tasa debe ser mayor o igual a 0%' })
@Max(100) @Max(100, { message: 'La tasa debe ser menor o igual a 100%' })
rate: number; rate: number;
} }
export class CreateSchemeDto { export class CreateSchemeDto {
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El nombre no puede exceder 100 caracteres' })
name: string; name: string;
@IsString() @IsString({ message: 'La descripcion debe ser una cadena de texto' })
@IsOptional() @IsOptional()
description?: string; description?: string;
@IsEnum(SchemeType) @IsEnum(SchemeType, { message: 'El tipo de esquema debe ser un valor valido' })
@IsOptional() @IsOptional()
type?: SchemeType; type?: SchemeType;
@IsNumber() @IsNumber({}, { message: 'La tasa debe ser un numero' })
@Min(0) @Min(0, { message: 'La tasa debe ser mayor o igual a 0%' })
@Max(100) @Max(100, { message: 'La tasa debe ser menor o igual a 100%' })
@IsOptional() @IsOptional()
rate?: number; rate?: number;
@IsNumber() @IsNumber({}, { message: 'El monto fijo debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto fijo debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
fixedAmount?: number; fixedAmount?: number;
@IsArray() @IsArray({ message: 'Los niveles deben ser un arreglo' })
@IsOptional() @IsOptional()
tiers?: TierDto[]; tiers?: TierDto[];
@IsEnum(AppliesTo) @IsEnum(AppliesTo, { message: 'La aplicacion debe ser un valor valido' })
@IsOptional() @IsOptional()
appliesTo?: AppliesTo; appliesTo?: AppliesTo;
@IsArray() @IsArray({ message: 'Los IDs de productos deben ser un arreglo' })
@IsUUID('4', { each: true }) @IsUUID('4', { each: true, message: 'Cada ID de producto debe ser un UUID valido' })
@IsOptional() @IsOptional()
productIds?: string[]; productIds?: string[];
@IsArray() @IsArray({ message: 'Los IDs de categorias deben ser un arreglo' })
@IsUUID('4', { each: true }) @IsUUID('4', { each: true, message: 'Cada ID de categoria debe ser un UUID valido' })
@IsOptional() @IsOptional()
categoryIds?: string[]; categoryIds?: string[];
@IsNumber() @IsNumber({}, { message: 'El monto minimo debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto minimo debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
minAmount?: number; minAmount?: number;
@IsNumber() @IsNumber({}, { message: 'El monto maximo debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto maximo debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
maxAmount?: number; maxAmount?: number;
@IsBoolean() @IsBoolean({ message: 'El estado activo debe ser verdadero o falso' })
@IsOptional() @IsOptional()
isActive?: boolean; isActive?: boolean;
} }
export class UpdateSchemeDto { export class UpdateSchemeDto {
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El nombre no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
name?: string; name?: string;
@IsString() @IsString({ message: 'La descripcion debe ser una cadena de texto' })
@IsOptional() @IsOptional()
description?: string; description?: string;
@IsEnum(SchemeType) @IsEnum(SchemeType, { message: 'El tipo de esquema debe ser un valor valido' })
@IsOptional() @IsOptional()
type?: SchemeType; type?: SchemeType;
@IsNumber() @IsNumber({}, { message: 'La tasa debe ser un numero' })
@Min(0) @Min(0, { message: 'La tasa debe ser mayor o igual a 0%' })
@Max(100) @Max(100, { message: 'La tasa debe ser menor o igual a 100%' })
@IsOptional() @IsOptional()
rate?: number; rate?: number;
@IsNumber() @IsNumber({}, { message: 'El monto fijo debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto fijo debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
fixedAmount?: number; fixedAmount?: number;
@IsArray() @IsArray({ message: 'Los niveles deben ser un arreglo' })
@IsOptional() @IsOptional()
tiers?: TierDto[]; tiers?: TierDto[];
@IsEnum(AppliesTo) @IsEnum(AppliesTo, { message: 'La aplicacion debe ser un valor valido' })
@IsOptional() @IsOptional()
appliesTo?: AppliesTo; appliesTo?: AppliesTo;
@IsArray() @IsArray({ message: 'Los IDs de productos deben ser un arreglo' })
@IsUUID('4', { each: true }) @IsUUID('4', { each: true, message: 'Cada ID de producto debe ser un UUID valido' })
@IsOptional() @IsOptional()
productIds?: string[]; productIds?: string[];
@IsArray() @IsArray({ message: 'Los IDs de categorias deben ser un arreglo' })
@IsUUID('4', { each: true }) @IsUUID('4', { each: true, message: 'Cada ID de categoria debe ser un UUID valido' })
@IsOptional() @IsOptional()
categoryIds?: string[]; categoryIds?: string[];
@IsNumber() @IsNumber({}, { message: 'El monto minimo debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto minimo debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
minAmount?: number; minAmount?: number;
@IsNumber() @IsNumber({}, { message: 'El monto maximo debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto maximo debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
maxAmount?: number; maxAmount?: number;
@IsBoolean() @IsBoolean({ message: 'El estado activo debe ser verdadero o falso' })
@IsOptional() @IsOptional()
isActive?: boolean; isActive?: boolean;
} }

View File

@ -14,31 +14,31 @@ import { FlagType, FlagScope } from '../entities/feature-flag.entity';
export class CreateFlagDto { export class CreateFlagDto {
@ApiProperty({ description: 'Unique flag key (lowercase, underscores allowed)' }) @ApiProperty({ description: 'Unique flag key (lowercase, underscores allowed)' })
@IsString() @IsString({ message: 'La clave debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'La clave no puede exceder 100 caracteres' })
@Matches(/^[a-z][a-z0-9_]*$/, { @Matches(/^[a-z][a-z0-9_]*$/, {
message: 'Key must start with lowercase letter and contain only lowercase letters, numbers, and underscores', message: 'La clave debe comenzar con minuscula y contener solo letras minusculas, numeros y guiones bajos',
}) })
key: string; key: string;
@ApiProperty({ description: 'Human-readable flag name' }) @ApiProperty({ description: 'Human-readable flag name' })
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'El nombre no puede exceder 255 caracteres' })
name: string; name: string;
@ApiPropertyOptional({ description: 'Flag description' }) @ApiPropertyOptional({ description: 'Flag description' })
@IsOptional() @IsOptional()
@IsString() @IsString({ message: 'La descripcion debe ser una cadena de texto' })
description?: string; description?: string;
@ApiPropertyOptional({ description: 'Flag value type', enum: FlagType }) @ApiPropertyOptional({ description: 'Flag value type', enum: FlagType })
@IsOptional() @IsOptional()
@IsEnum(FlagType) @IsEnum(FlagType, { message: 'El tipo de flag debe ser un valor valido' })
flag_type?: FlagType = FlagType.BOOLEAN; flag_type?: FlagType = FlagType.BOOLEAN;
@ApiPropertyOptional({ description: 'Flag scope', enum: FlagScope }) @ApiPropertyOptional({ description: 'Flag scope', enum: FlagScope })
@IsOptional() @IsOptional()
@IsEnum(FlagScope) @IsEnum(FlagScope, { message: 'El alcance debe ser un valor valido' })
scope?: FlagScope = FlagScope.GLOBAL; scope?: FlagScope = FlagScope.GLOBAL;
@ApiPropertyOptional({ description: 'Default value for the flag' }) @ApiPropertyOptional({ description: 'Default value for the flag' })
@ -47,7 +47,7 @@ export class CreateFlagDto {
@ApiPropertyOptional({ description: 'Is flag enabled globally' }) @ApiPropertyOptional({ description: 'Is flag enabled globally' })
@IsOptional() @IsOptional()
@IsBoolean() @IsBoolean({ message: 'Habilitado debe ser verdadero o falso' })
is_enabled?: boolean = false; is_enabled?: boolean = false;
@ApiPropertyOptional({ description: 'Targeting rules for conditional evaluation' }) @ApiPropertyOptional({ description: 'Targeting rules for conditional evaluation' })
@ -56,15 +56,15 @@ export class CreateFlagDto {
@ApiPropertyOptional({ description: 'Rollout percentage (0-100)' }) @ApiPropertyOptional({ description: 'Rollout percentage (0-100)' })
@IsOptional() @IsOptional()
@IsNumber() @IsNumber({}, { message: 'El porcentaje de despliegue debe ser un numero' })
@Min(0) @Min(0, { message: 'El porcentaje de despliegue debe ser mayor o igual a 0%' })
@Max(100) @Max(100, { message: 'El porcentaje de despliegue debe ser menor o igual a 100%' })
rollout_percentage?: number; rollout_percentage?: number;
@ApiPropertyOptional({ description: 'Category for grouping flags' }) @ApiPropertyOptional({ description: 'Category for grouping flags' })
@IsOptional() @IsOptional()
@IsString() @IsString({ message: 'La categoria debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'La categoria no puede exceder 100 caracteres' })
category?: string; category?: string;
@ApiPropertyOptional({ description: 'Additional metadata' }) @ApiPropertyOptional({ description: 'Additional metadata' })

View File

@ -10,33 +10,33 @@ import { ProgressSource } from '../entities/progress-log.entity';
export class CreateAssignmentDto { export class CreateAssignmentDto {
@ApiProperty() @ApiProperty()
@IsUUID() @IsUUID('4', { message: 'El ID de definicion debe ser un UUID valido' })
definitionId: string; definitionId: string;
@ApiPropertyOptional({ enum: AssigneeType, default: AssigneeType.USER }) @ApiPropertyOptional({ enum: AssigneeType, default: AssigneeType.USER })
@IsOptional() @IsOptional()
@IsEnum(AssigneeType) @IsEnum(AssigneeType, { message: 'El tipo de asignado debe ser un valor valido' })
assigneeType?: AssigneeType; assigneeType?: AssigneeType;
@ApiPropertyOptional() @ApiPropertyOptional()
@IsOptional() @IsOptional()
@IsUUID() @IsUUID('4', { message: 'El ID de usuario debe ser un UUID valido' })
userId?: string; userId?: string;
@ApiPropertyOptional() @ApiPropertyOptional()
@IsOptional() @IsOptional()
@IsUUID() @IsUUID('4', { message: 'El ID de equipo debe ser un UUID valido' })
teamId?: string; teamId?: string;
@ApiPropertyOptional({ example: 50000 }) @ApiPropertyOptional({ example: 50000 })
@IsOptional() @IsOptional()
@IsNumber() @IsNumber({}, { message: 'El objetivo personalizado debe ser un numero' })
@Min(0) @Min(0, { message: 'El objetivo personalizado debe ser mayor o igual a 0' })
customTarget?: number; customTarget?: number;
@ApiPropertyOptional() @ApiPropertyOptional()
@IsOptional() @IsOptional()
@IsString() @IsString({ message: 'Las notas deben ser una cadena de texto' })
notes?: string; notes?: string;
} }
@ -62,23 +62,23 @@ export class UpdateAssignmentStatusDto {
export class UpdateProgressDto { export class UpdateProgressDto {
@ApiProperty({ example: 25000 }) @ApiProperty({ example: 25000 })
@IsNumber() @IsNumber({}, { message: 'El valor debe ser un numero' })
@Min(0) @Min(0, { message: 'El valor debe ser mayor o igual a 0' })
value: number; value: number;
@ApiPropertyOptional({ enum: ProgressSource, default: ProgressSource.MANUAL }) @ApiPropertyOptional({ enum: ProgressSource, default: ProgressSource.MANUAL })
@IsOptional() @IsOptional()
@IsEnum(ProgressSource) @IsEnum(ProgressSource, { message: 'La fuente de progreso debe ser un valor valido' })
source?: ProgressSource; source?: ProgressSource;
@ApiPropertyOptional() @ApiPropertyOptional()
@IsOptional() @IsOptional()
@IsString() @IsString({ message: 'La referencia de fuente debe ser una cadena de texto' })
sourceReference?: string; sourceReference?: string;
@ApiPropertyOptional() @ApiPropertyOptional()
@IsOptional() @IsOptional()
@IsString() @IsString({ message: 'Las notas deben ser una cadena de texto' })
notes?: string; notes?: string;
} }
@ -159,38 +159,38 @@ export class AssignmentResponseDto {
export class AssignmentFiltersDto { export class AssignmentFiltersDto {
@ApiPropertyOptional() @ApiPropertyOptional()
@IsOptional() @IsOptional()
@IsUUID() @IsUUID('4', { message: 'El ID de definicion debe ser un UUID valido' })
definitionId?: string; definitionId?: string;
@ApiPropertyOptional() @ApiPropertyOptional()
@IsOptional() @IsOptional()
@IsUUID() @IsUUID('4', { message: 'El ID de usuario debe ser un UUID valido' })
userId?: string; userId?: string;
@ApiPropertyOptional({ enum: AssignmentStatus }) @ApiPropertyOptional({ enum: AssignmentStatus })
@IsOptional() @IsOptional()
@IsEnum(AssignmentStatus) @IsEnum(AssignmentStatus, { message: 'El estado debe ser un valor valido' })
status?: AssignmentStatus; status?: AssignmentStatus;
@ApiPropertyOptional({ enum: AssigneeType }) @ApiPropertyOptional({ enum: AssigneeType })
@IsOptional() @IsOptional()
@IsEnum(AssigneeType) @IsEnum(AssigneeType, { message: 'El tipo de asignado debe ser un valor valido' })
assigneeType?: AssigneeType; assigneeType?: AssigneeType;
@ApiPropertyOptional({ description: 'Minimum progress percentage' }) @ApiPropertyOptional({ description: 'Minimum progress percentage' })
@IsOptional() @IsOptional()
@Type(() => Number) @Type(() => Number)
@IsNumber() @IsNumber({}, { message: 'El progreso minimo debe ser un numero' })
@Min(0) @Min(0, { message: 'El progreso minimo debe ser mayor o igual a 0%' })
@Max(100) @Max(100, { message: 'El progreso minimo debe ser menor o igual a 100%' })
minProgress?: number; minProgress?: number;
@ApiPropertyOptional({ description: 'Maximum progress percentage' }) @ApiPropertyOptional({ description: 'Maximum progress percentage' })
@IsOptional() @IsOptional()
@Type(() => Number) @Type(() => Number)
@IsNumber() @IsNumber({}, { message: 'El progreso maximo debe ser un numero' })
@Min(0) @Min(0, { message: 'El progreso maximo debe ser mayor o igual a 0%' })
@Max(100) @Max(100, { message: 'El progreso maximo debe ser menor o igual a 100%' })
maxProgress?: number; maxProgress?: number;
@ApiPropertyOptional({ example: 'progressPercentage' }) @ApiPropertyOptional({ example: 'progressPercentage' })

View File

@ -9,12 +9,12 @@ import { GoalType, MetricType, PeriodType, DataSource, GoalStatus, SourceConfig,
export class MilestoneDto { export class MilestoneDto {
@ApiProperty({ example: 50 }) @ApiProperty({ example: 50 })
@IsNumber() @IsNumber({}, { message: 'El porcentaje debe ser un numero' })
@Min(0) @Min(0, { message: 'El porcentaje debe ser mayor o igual a 0' })
percentage: number; percentage: number;
@ApiProperty({ example: true }) @ApiProperty({ example: true })
@IsBoolean() @IsBoolean({ message: 'Notificar debe ser verdadero o falso' })
notify: boolean; notify: boolean;
} }
@ -55,57 +55,57 @@ export class SourceConfigDto {
export class CreateDefinitionDto { export class CreateDefinitionDto {
@ApiProperty({ example: 'Q1 Sales Target' }) @ApiProperty({ example: 'Q1 Sales Target' })
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
name: string; name: string;
@ApiPropertyOptional({ example: 'Achieve $100,000 in closed deals' }) @ApiPropertyOptional({ example: 'Achieve $100,000 in closed deals' })
@IsOptional() @IsOptional()
@IsString() @IsString({ message: 'La descripcion debe ser una cadena de texto' })
description?: string; description?: string;
@ApiPropertyOptional({ example: 'sales' }) @ApiPropertyOptional({ example: 'sales' })
@IsOptional() @IsOptional()
@IsString() @IsString({ message: 'La categoria debe ser una cadena de texto' })
category?: string; category?: string;
@ApiPropertyOptional({ enum: GoalType, default: GoalType.TARGET }) @ApiPropertyOptional({ enum: GoalType, default: GoalType.TARGET })
@IsOptional() @IsOptional()
@IsEnum(GoalType) @IsEnum(GoalType, { message: 'El tipo de meta debe ser un valor valido' })
type?: GoalType; type?: GoalType;
@ApiPropertyOptional({ enum: MetricType, default: MetricType.NUMBER }) @ApiPropertyOptional({ enum: MetricType, default: MetricType.NUMBER })
@IsOptional() @IsOptional()
@IsEnum(MetricType) @IsEnum(MetricType, { message: 'El tipo de metrica debe ser un valor valido' })
metric?: MetricType; metric?: MetricType;
@ApiProperty({ example: 100000 }) @ApiProperty({ example: 100000 })
@IsNumber() @IsNumber({}, { message: 'El valor objetivo debe ser un numero' })
@Min(0) @Min(0, { message: 'El valor objetivo debe ser mayor o igual a 0' })
targetValue: number; targetValue: number;
@ApiPropertyOptional({ example: 'USD' }) @ApiPropertyOptional({ example: 'USD' })
@IsOptional() @IsOptional()
@IsString() @IsString({ message: 'La unidad debe ser una cadena de texto' })
unit?: string; unit?: string;
@ApiPropertyOptional({ enum: PeriodType, default: PeriodType.MONTHLY }) @ApiPropertyOptional({ enum: PeriodType, default: PeriodType.MONTHLY })
@IsOptional() @IsOptional()
@IsEnum(PeriodType) @IsEnum(PeriodType, { message: 'El tipo de periodo debe ser un valor valido' })
period?: PeriodType; period?: PeriodType;
@ApiProperty({ example: '2026-01-01' }) @ApiProperty({ example: '2026-01-01' })
@Type(() => Date) @Type(() => Date)
@IsDate() @IsDate({ message: 'La fecha de inicio debe ser una fecha valida' })
startsAt: Date; startsAt: Date;
@ApiProperty({ example: '2026-03-31' }) @ApiProperty({ example: '2026-03-31' })
@Type(() => Date) @Type(() => Date)
@IsDate() @IsDate({ message: 'La fecha de fin debe ser una fecha valida' })
endsAt: Date; endsAt: Date;
@ApiPropertyOptional({ enum: DataSource, default: DataSource.MANUAL }) @ApiPropertyOptional({ enum: DataSource, default: DataSource.MANUAL })
@IsOptional() @IsOptional()
@IsEnum(DataSource) @IsEnum(DataSource, { message: 'La fuente de datos debe ser un valor valido' })
source?: DataSource; source?: DataSource;
@ApiPropertyOptional({ type: SourceConfigDto }) @ApiPropertyOptional({ type: SourceConfigDto })
@ -116,20 +116,20 @@ export class CreateDefinitionDto {
@ApiPropertyOptional({ type: [MilestoneDto] }) @ApiPropertyOptional({ type: [MilestoneDto] })
@IsOptional() @IsOptional()
@IsArray() @IsArray({ message: 'Los hitos deben ser un arreglo' })
@ValidateNested({ each: true }) @ValidateNested({ each: true })
@Type(() => MilestoneDto) @Type(() => MilestoneDto)
milestones?: MilestoneDto[]; milestones?: MilestoneDto[];
@ApiPropertyOptional({ enum: GoalStatus, default: GoalStatus.DRAFT }) @ApiPropertyOptional({ enum: GoalStatus, default: GoalStatus.DRAFT })
@IsOptional() @IsOptional()
@IsEnum(GoalStatus) @IsEnum(GoalStatus, { message: 'El estado de la meta debe ser un valor valido' })
status?: GoalStatus; status?: GoalStatus;
@ApiPropertyOptional({ type: [String], example: ['sales', 'q1'] }) @ApiPropertyOptional({ type: [String], example: ['sales', 'q1'] })
@IsOptional() @IsOptional()
@IsArray() @IsArray({ message: 'Las etiquetas deben ser un arreglo' })
@IsString({ each: true }) @IsString({ each: true, message: 'Cada etiqueta debe ser una cadena de texto' })
tags?: string[]; tags?: string[];
} }

View File

@ -14,33 +14,33 @@ import { BonusType } from '../entities/bonus.entity';
export class CalculateCommissionsDto { export class CalculateCommissionsDto {
@ApiProperty({ description: 'Source node ID (who generated the sale)' }) @ApiProperty({ description: 'Source node ID (who generated the sale)' })
@IsUUID() @IsUUID('4', { message: 'El ID del nodo origen debe ser un UUID valido' })
sourceNodeId: string; sourceNodeId: string;
@ApiProperty({ description: 'Amount to calculate commissions on' }) @ApiProperty({ description: 'Amount to calculate commissions on' })
@IsNumber() @IsNumber({}, { message: 'El monto debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto debe ser mayor o igual a 0' })
amount: number; amount: number;
@ApiPropertyOptional({ description: 'Currency', default: 'USD' }) @ApiPropertyOptional({ description: 'Currency', default: 'USD' })
@IsOptional() @IsOptional()
@IsString() @IsString({ message: 'La moneda debe ser una cadena de texto' })
currency?: string; currency?: string;
@ApiPropertyOptional({ description: 'Source reference (sale ID, etc.)' }) @ApiPropertyOptional({ description: 'Source reference (sale ID, etc.)' })
@IsOptional() @IsOptional()
@IsString() @IsString({ message: 'La referencia origen debe ser una cadena de texto' })
sourceReference?: string; sourceReference?: string;
@ApiPropertyOptional({ description: 'Period ID' }) @ApiPropertyOptional({ description: 'Period ID' })
@IsOptional() @IsOptional()
@IsUUID() @IsUUID('4', { message: 'El ID del periodo debe ser un UUID valido' })
periodId?: string; periodId?: string;
} }
export class UpdateCommissionStatusDto { export class UpdateCommissionStatusDto {
@ApiProperty({ description: 'New status', enum: CommissionStatus }) @ApiProperty({ description: 'New status', enum: CommissionStatus })
@IsEnum(CommissionStatus) @IsEnum(CommissionStatus, { message: 'El estado debe ser un valor valido' })
status: CommissionStatus; status: CommissionStatus;
} }

View File

@ -19,57 +19,57 @@ import { PriceType } from '../entities/price.entity';
// ============================================ // ============================================
export class CreateProductDto { export class CreateProductDto {
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'El nombre no puede exceder 255 caracteres' })
name: string; name: string;
@IsString() @IsString({ message: 'El slug debe ser una cadena de texto' })
@MaxLength(280) @MaxLength(280, { message: 'El slug no puede exceder 280 caracteres' })
slug: string; slug: string;
@IsUUID() @IsUUID('4', { message: 'El ID de categoria debe ser un UUID valido' })
@IsOptional() @IsOptional()
categoryId?: string; categoryId?: string;
@IsString() @IsString({ message: 'El SKU debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El SKU no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
sku?: string; sku?: string;
@IsString() @IsString({ message: 'El codigo de barras debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El codigo de barras no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
barcode?: string; barcode?: string;
@IsString() @IsString({ message: 'La descripcion debe ser una cadena de texto' })
@IsOptional() @IsOptional()
description?: string; description?: string;
@IsString() @IsString({ message: 'La descripcion corta debe ser una cadena de texto' })
@MaxLength(500) @MaxLength(500, { message: 'La descripcion corta no puede exceder 500 caracteres' })
@IsOptional() @IsOptional()
shortDescription?: string; shortDescription?: string;
@IsEnum(ProductType) @IsEnum(ProductType, { message: 'El tipo de producto debe ser un valor valido' })
@IsOptional() @IsOptional()
productType?: ProductType; productType?: ProductType;
@IsEnum(ProductStatus) @IsEnum(ProductStatus, { message: 'El estado del producto debe ser un valor valido' })
@IsOptional() @IsOptional()
status?: ProductStatus; status?: ProductStatus;
@IsNumber() @IsNumber({}, { message: 'El precio base debe ser un numero' })
@Min(0) @Min(0, { message: 'El precio base debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
basePrice?: number; basePrice?: number;
@IsNumber() @IsNumber({}, { message: 'El precio de costo debe ser un numero' })
@Min(0) @Min(0, { message: 'El precio de costo debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
costPrice?: number; costPrice?: number;
@IsNumber() @IsNumber({}, { message: 'El precio de comparacion debe ser un numero' })
@Min(0) @Min(0, { message: 'El precio de comparacion debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
compareAtPrice?: number; compareAtPrice?: number;
@ -78,252 +78,252 @@ export class CreateProductDto {
@IsOptional() @IsOptional()
currency?: string; currency?: string;
@IsBoolean() @IsBoolean({ message: 'Seguir inventario debe ser verdadero o falso' })
@IsOptional() @IsOptional()
trackInventory?: boolean; trackInventory?: boolean;
@IsInt() @IsInt({ message: 'La cantidad en stock debe ser un numero entero' })
@Min(0) @Min(0, { message: 'La cantidad en stock debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
stockQuantity?: number; stockQuantity?: number;
@IsInt() @IsInt({ message: 'El umbral de stock bajo debe ser un numero entero' })
@Min(0) @Min(0, { message: 'El umbral de stock bajo debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
lowStockThreshold?: number; lowStockThreshold?: number;
@IsBoolean() @IsBoolean({ message: 'Permitir backorder debe ser verdadero o falso' })
@IsOptional() @IsOptional()
allowBackorder?: boolean; allowBackorder?: boolean;
@IsNumber() @IsNumber({}, { message: 'El peso debe ser un numero' })
@Min(0) @Min(0, { message: 'El peso debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
weight?: number; weight?: number;
@IsString() @IsString({ message: 'La unidad de peso debe ser una cadena de texto' })
@MaxLength(10) @MaxLength(10, { message: 'La unidad de peso no puede exceder 10 caracteres' })
@IsOptional() @IsOptional()
weightUnit?: string; weightUnit?: string;
@IsNumber() @IsNumber({}, { message: 'La longitud debe ser un numero' })
@Min(0) @Min(0, { message: 'La longitud debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
length?: number; length?: number;
@IsNumber() @IsNumber({}, { message: 'El ancho debe ser un numero' })
@Min(0) @Min(0, { message: 'El ancho debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
width?: number; width?: number;
@IsNumber() @IsNumber({}, { message: 'La altura debe ser un numero' })
@Min(0) @Min(0, { message: 'La altura debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
height?: number; height?: number;
@IsString() @IsString({ message: 'La unidad de dimension debe ser una cadena de texto' })
@MaxLength(10) @MaxLength(10, { message: 'La unidad de dimension no puede exceder 10 caracteres' })
@IsOptional() @IsOptional()
dimensionUnit?: string; dimensionUnit?: string;
@IsArray() @IsArray({ message: 'Las imagenes deben ser un arreglo' })
@IsOptional() @IsOptional()
images?: string[]; images?: string[];
@IsString() @IsString({ message: 'La URL de imagen destacada debe ser una cadena de texto' })
@MaxLength(500) @MaxLength(500, { message: 'La URL de imagen destacada no puede exceder 500 caracteres' })
@IsOptional() @IsOptional()
featuredImageUrl?: string; featuredImageUrl?: string;
@IsString() @IsString({ message: 'El titulo meta debe ser una cadena de texto' })
@MaxLength(200) @MaxLength(200, { message: 'El titulo meta no puede exceder 200 caracteres' })
@IsOptional() @IsOptional()
metaTitle?: string; metaTitle?: string;
@IsString() @IsString({ message: 'La descripcion meta debe ser una cadena de texto' })
@IsOptional() @IsOptional()
metaDescription?: string; metaDescription?: string;
@IsArray() @IsArray({ message: 'Las etiquetas deben ser un arreglo' })
@IsOptional() @IsOptional()
tags?: string[]; tags?: string[];
@IsBoolean() @IsBoolean({ message: 'Visibilidad debe ser verdadero o falso' })
@IsOptional() @IsOptional()
isVisible?: boolean; isVisible?: boolean;
@IsBoolean() @IsBoolean({ message: 'Destacado debe ser verdadero o falso' })
@IsOptional() @IsOptional()
isFeatured?: boolean; isFeatured?: boolean;
@IsBoolean() @IsBoolean({ message: 'Tiene variantes debe ser verdadero o falso' })
@IsOptional() @IsOptional()
hasVariants?: boolean; hasVariants?: boolean;
@IsArray() @IsArray({ message: 'Los atributos de variantes deben ser un arreglo' })
@IsOptional() @IsOptional()
variantAttributes?: string[]; variantAttributes?: string[];
@IsObject() @IsObject({ message: 'Los campos personalizados deben ser un objeto' })
@IsOptional() @IsOptional()
customFields?: Record<string, any>; customFields?: Record<string, any>;
} }
export class UpdateProductDto { export class UpdateProductDto {
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'El nombre no puede exceder 255 caracteres' })
@IsOptional() @IsOptional()
name?: string; name?: string;
@IsString() @IsString({ message: 'El slug debe ser una cadena de texto' })
@MaxLength(280) @MaxLength(280, { message: 'El slug no puede exceder 280 caracteres' })
@IsOptional() @IsOptional()
slug?: string; slug?: string;
@IsUUID() @IsUUID('4', { message: 'El ID de categoria debe ser un UUID valido' })
@IsOptional() @IsOptional()
categoryId?: string | null; categoryId?: string | null;
@IsString() @IsString({ message: 'El SKU debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El SKU no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
sku?: string; sku?: string;
@IsString() @IsString({ message: 'El codigo de barras debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El codigo de barras no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
barcode?: string; barcode?: string;
@IsString() @IsString({ message: 'La descripcion debe ser una cadena de texto' })
@IsOptional() @IsOptional()
description?: string; description?: string;
@IsString() @IsString({ message: 'La descripcion corta debe ser una cadena de texto' })
@MaxLength(500) @MaxLength(500, { message: 'La descripcion corta no puede exceder 500 caracteres' })
@IsOptional() @IsOptional()
shortDescription?: string; shortDescription?: string;
@IsEnum(ProductType) @IsEnum(ProductType, { message: 'El tipo de producto debe ser un valor valido' })
@IsOptional() @IsOptional()
productType?: ProductType; productType?: ProductType;
@IsEnum(ProductStatus) @IsEnum(ProductStatus, { message: 'El estado del producto debe ser un valor valido' })
@IsOptional() @IsOptional()
status?: ProductStatus; status?: ProductStatus;
@IsNumber() @IsNumber({}, { message: 'El precio base debe ser un numero' })
@Min(0) @Min(0, { message: 'El precio base debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
basePrice?: number; basePrice?: number;
@IsNumber() @IsNumber({}, { message: 'El precio de costo debe ser un numero' })
@Min(0) @Min(0, { message: 'El precio de costo debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
costPrice?: number; costPrice?: number;
@IsNumber() @IsNumber({}, { message: 'El precio de comparacion debe ser un numero' })
@Min(0) @Min(0, { message: 'El precio de comparacion debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
compareAtPrice?: number; compareAtPrice?: number;
@IsString() @IsString({ message: 'La moneda debe ser una cadena de texto' })
@MaxLength(3) @MaxLength(3, { message: 'La moneda no puede exceder 3 caracteres' })
@IsOptional() @IsOptional()
currency?: string; currency?: string;
@IsBoolean() @IsBoolean({ message: 'Seguir inventario debe ser verdadero o falso' })
@IsOptional() @IsOptional()
trackInventory?: boolean; trackInventory?: boolean;
@IsInt() @IsInt({ message: 'La cantidad en stock debe ser un numero entero' })
@Min(0) @Min(0, { message: 'La cantidad en stock debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
stockQuantity?: number; stockQuantity?: number;
@IsInt() @IsInt({ message: 'El umbral de stock bajo debe ser un numero entero' })
@Min(0) @Min(0, { message: 'El umbral de stock bajo debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
lowStockThreshold?: number; lowStockThreshold?: number;
@IsBoolean() @IsBoolean({ message: 'Permitir backorder debe ser verdadero o falso' })
@IsOptional() @IsOptional()
allowBackorder?: boolean; allowBackorder?: boolean;
@IsNumber() @IsNumber({}, { message: 'El peso debe ser un numero' })
@Min(0) @Min(0, { message: 'El peso debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
weight?: number; weight?: number;
@IsString() @IsString({ message: 'La unidad de peso debe ser una cadena de texto' })
@MaxLength(10) @MaxLength(10, { message: 'La unidad de peso no puede exceder 10 caracteres' })
@IsOptional() @IsOptional()
weightUnit?: string; weightUnit?: string;
@IsNumber() @IsNumber({}, { message: 'La longitud debe ser un numero' })
@Min(0) @Min(0, { message: 'La longitud debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
length?: number; length?: number;
@IsNumber() @IsNumber({}, { message: 'El ancho debe ser un numero' })
@Min(0) @Min(0, { message: 'El ancho debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
width?: number; width?: number;
@IsNumber() @IsNumber({}, { message: 'La altura debe ser un numero' })
@Min(0) @Min(0, { message: 'La altura debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
height?: number; height?: number;
@IsString() @IsString({ message: 'La unidad de dimension debe ser una cadena de texto' })
@MaxLength(10) @MaxLength(10, { message: 'La unidad de dimension no puede exceder 10 caracteres' })
@IsOptional() @IsOptional()
dimensionUnit?: string; dimensionUnit?: string;
@IsArray() @IsArray({ message: 'Las imagenes deben ser un arreglo' })
@IsOptional() @IsOptional()
images?: string[]; images?: string[];
@IsString() @IsString({ message: 'La URL de imagen destacada debe ser una cadena de texto' })
@MaxLength(500) @MaxLength(500, { message: 'La URL de imagen destacada no puede exceder 500 caracteres' })
@IsOptional() @IsOptional()
featuredImageUrl?: string; featuredImageUrl?: string;
@IsString() @IsString({ message: 'El titulo meta debe ser una cadena de texto' })
@MaxLength(200) @MaxLength(200, { message: 'El titulo meta no puede exceder 200 caracteres' })
@IsOptional() @IsOptional()
metaTitle?: string; metaTitle?: string;
@IsString() @IsString({ message: 'La descripcion meta debe ser una cadena de texto' })
@IsOptional() @IsOptional()
metaDescription?: string; metaDescription?: string;
@IsArray() @IsArray({ message: 'Las etiquetas deben ser un arreglo' })
@IsOptional() @IsOptional()
tags?: string[]; tags?: string[];
@IsBoolean() @IsBoolean({ message: 'Visibilidad debe ser verdadero o falso' })
@IsOptional() @IsOptional()
isVisible?: boolean; isVisible?: boolean;
@IsBoolean() @IsBoolean({ message: 'Destacado debe ser verdadero o falso' })
@IsOptional() @IsOptional()
isFeatured?: boolean; isFeatured?: boolean;
@IsBoolean() @IsBoolean({ message: 'Tiene variantes debe ser verdadero o falso' })
@IsOptional() @IsOptional()
hasVariants?: boolean; hasVariants?: boolean;
@IsArray() @IsArray({ message: 'Los atributos de variantes deben ser un arreglo' })
@IsOptional() @IsOptional()
variantAttributes?: string[]; variantAttributes?: string[];
@IsObject() @IsObject({ message: 'Los campos personalizados deben ser un objeto' })
@IsOptional() @IsOptional()
customFields?: Record<string, any>; customFields?: Record<string, any>;
} }
export class UpdateProductStatusDto { export class UpdateProductStatusDto {
@IsEnum(ProductStatus) @IsEnum(ProductStatus, { message: 'El estado del producto debe ser un valor valido' })
status: ProductStatus; status: ProductStatus;
} }

View File

@ -14,195 +14,195 @@ import {
import { LeadStatus, LeadSource } from '../entities'; import { LeadStatus, LeadSource } from '../entities';
export class CreateLeadDto { export class CreateLeadDto {
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El nombre no puede exceder 100 caracteres' })
firstName: string; firstName: string;
@IsString() @IsString({ message: 'El apellido debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El apellido no puede exceder 100 caracteres' })
lastName: string; lastName: string;
@IsEmail() @IsEmail({}, { message: 'El email debe tener un formato valido' })
@IsOptional() @IsOptional()
email?: string; email?: string;
@IsString() @IsString({ message: 'El telefono debe ser una cadena de texto' })
@MaxLength(50) @MaxLength(50, { message: 'El telefono no puede exceder 50 caracteres' })
@IsOptional() @IsOptional()
phone?: string; phone?: string;
@IsString() @IsString({ message: 'La empresa debe ser una cadena de texto' })
@MaxLength(200) @MaxLength(200, { message: 'La empresa no puede exceder 200 caracteres' })
@IsOptional() @IsOptional()
company?: string; company?: string;
@IsString() @IsString({ message: 'El puesto debe ser una cadena de texto' })
@MaxLength(150) @MaxLength(150, { message: 'El puesto no puede exceder 150 caracteres' })
@IsOptional() @IsOptional()
jobTitle?: string; jobTitle?: string;
@IsString() @IsString({ message: 'El sitio web debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'El sitio web no puede exceder 255 caracteres' })
@IsOptional() @IsOptional()
website?: string; website?: string;
@IsEnum(LeadSource) @IsEnum(LeadSource, { message: 'El origen del lead debe ser un valor valido' })
@IsOptional() @IsOptional()
source?: LeadSource; source?: LeadSource;
@IsEnum(LeadStatus) @IsEnum(LeadStatus, { message: 'El estado del lead debe ser un valor valido' })
@IsOptional() @IsOptional()
status?: LeadStatus; status?: LeadStatus;
@IsInt() @IsInt({ message: 'El score debe ser un numero entero' })
@Min(0) @Min(0, { message: 'El score debe ser mayor o igual a 0' })
@Max(100) @Max(100, { message: 'El score debe ser menor o igual a 100' })
@IsOptional() @IsOptional()
score?: number; score?: number;
@IsUUID() @IsUUID('4', { message: 'El ID del asignado debe ser un UUID valido' })
@IsOptional() @IsOptional()
assignedTo?: string; assignedTo?: string;
@IsString() @IsString({ message: 'Las notas deben ser una cadena de texto' })
@IsOptional() @IsOptional()
notes?: string; notes?: string;
@IsString() @IsString({ message: 'La direccion linea 1 debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'La direccion linea 1 no puede exceder 255 caracteres' })
@IsOptional() @IsOptional()
addressLine1?: string; addressLine1?: string;
@IsString() @IsString({ message: 'La direccion linea 2 debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'La direccion linea 2 no puede exceder 255 caracteres' })
@IsOptional() @IsOptional()
addressLine2?: string; addressLine2?: string;
@IsString() @IsString({ message: 'La ciudad debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'La ciudad no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
city?: string; city?: string;
@IsString() @IsString({ message: 'El estado/provincia debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El estado/provincia no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
state?: string; state?: string;
@IsString() @IsString({ message: 'El codigo postal debe ser una cadena de texto' })
@MaxLength(20) @MaxLength(20, { message: 'El codigo postal no puede exceder 20 caracteres' })
@IsOptional() @IsOptional()
postalCode?: string; postalCode?: string;
@IsString() @IsString({ message: 'El pais debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El pais no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
country?: string; country?: string;
@IsObject() @IsObject({ message: 'Los campos personalizados deben ser un objeto' })
@IsOptional() @IsOptional()
customFields?: Record<string, any>; customFields?: Record<string, any>;
} }
export class UpdateLeadDto { export class UpdateLeadDto {
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El nombre no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
firstName?: string; firstName?: string;
@IsString() @IsString({ message: 'El apellido debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El apellido no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
lastName?: string; lastName?: string;
@IsEmail() @IsEmail({}, { message: 'El email debe tener un formato valido' })
@IsOptional() @IsOptional()
email?: string; email?: string;
@IsString() @IsString({ message: 'El telefono debe ser una cadena de texto' })
@MaxLength(50) @MaxLength(50, { message: 'El telefono no puede exceder 50 caracteres' })
@IsOptional() @IsOptional()
phone?: string; phone?: string;
@IsString() @IsString({ message: 'La empresa debe ser una cadena de texto' })
@MaxLength(200) @MaxLength(200, { message: 'La empresa no puede exceder 200 caracteres' })
@IsOptional() @IsOptional()
company?: string; company?: string;
@IsString() @IsString({ message: 'El puesto debe ser una cadena de texto' })
@MaxLength(150) @MaxLength(150, { message: 'El puesto no puede exceder 150 caracteres' })
@IsOptional() @IsOptional()
jobTitle?: string; jobTitle?: string;
@IsString() @IsString({ message: 'El sitio web debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'El sitio web no puede exceder 255 caracteres' })
@IsOptional() @IsOptional()
website?: string; website?: string;
@IsEnum(LeadSource) @IsEnum(LeadSource, { message: 'El origen del lead debe ser un valor valido' })
@IsOptional() @IsOptional()
source?: LeadSource; source?: LeadSource;
@IsEnum(LeadStatus) @IsEnum(LeadStatus, { message: 'El estado del lead debe ser un valor valido' })
@IsOptional() @IsOptional()
status?: LeadStatus; status?: LeadStatus;
@IsInt() @IsInt({ message: 'El score debe ser un numero entero' })
@Min(0) @Min(0, { message: 'El score debe ser mayor o igual a 0' })
@Max(100) @Max(100, { message: 'El score debe ser menor o igual a 100' })
@IsOptional() @IsOptional()
score?: number; score?: number;
@IsUUID() @IsUUID('4', { message: 'El ID del asignado debe ser un UUID valido' })
@IsOptional() @IsOptional()
assignedTo?: string; assignedTo?: string;
@IsString() @IsString({ message: 'Las notas deben ser una cadena de texto' })
@IsOptional() @IsOptional()
notes?: string; notes?: string;
@IsString() @IsString({ message: 'La direccion linea 1 debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'La direccion linea 1 no puede exceder 255 caracteres' })
@IsOptional() @IsOptional()
addressLine1?: string; addressLine1?: string;
@IsString() @IsString({ message: 'La direccion linea 2 debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'La direccion linea 2 no puede exceder 255 caracteres' })
@IsOptional() @IsOptional()
addressLine2?: string; addressLine2?: string;
@IsString() @IsString({ message: 'La ciudad debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'La ciudad no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
city?: string; city?: string;
@IsString() @IsString({ message: 'El estado/provincia debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El estado/provincia no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
state?: string; state?: string;
@IsString() @IsString({ message: 'El codigo postal debe ser una cadena de texto' })
@MaxLength(20) @MaxLength(20, { message: 'El codigo postal no puede exceder 20 caracteres' })
@IsOptional() @IsOptional()
postalCode?: string; postalCode?: string;
@IsString() @IsString({ message: 'El pais debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El pais no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
country?: string; country?: string;
@IsObject() @IsObject({ message: 'Los campos personalizados deben ser un objeto' })
@IsOptional() @IsOptional()
customFields?: Record<string, any>; customFields?: Record<string, any>;
} }
export class ConvertLeadDto { export class ConvertLeadDto {
@IsString() @IsString({ message: 'El nombre de oportunidad debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'El nombre de oportunidad no puede exceder 255 caracteres' })
@IsOptional() @IsOptional()
opportunityName?: string; opportunityName?: string;
@IsNumber() @IsNumber({}, { message: 'El monto debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
amount?: number; amount?: number;

View File

@ -15,158 +15,158 @@ import {
import { OpportunityStage } from '../entities'; import { OpportunityStage } from '../entities';
export class CreateOpportunityDto { export class CreateOpportunityDto {
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'El nombre no puede exceder 255 caracteres' })
name: string; name: string;
@IsString() @IsString({ message: 'La descripcion debe ser una cadena de texto' })
@IsOptional() @IsOptional()
description?: string; description?: string;
@IsUUID() @IsUUID('4', { message: 'El ID del lead debe ser un UUID valido' })
@IsOptional() @IsOptional()
leadId?: string; leadId?: string;
@IsEnum(OpportunityStage) @IsEnum(OpportunityStage, { message: 'La etapa debe ser un valor valido' })
@IsOptional() @IsOptional()
stage?: OpportunityStage; stage?: OpportunityStage;
@IsUUID() @IsUUID('4', { message: 'El ID de etapa debe ser un UUID valido' })
@IsOptional() @IsOptional()
stageId?: string; stageId?: string;
@IsNumber() @IsNumber({}, { message: 'El monto debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
amount?: number; amount?: number;
@IsString() @IsString({ message: 'La moneda debe ser una cadena de texto' })
@MaxLength(3) @MaxLength(3, { message: 'La moneda no puede exceder 3 caracteres' })
@IsOptional() @IsOptional()
currency?: string; currency?: string;
@IsInt() @IsInt({ message: 'La probabilidad debe ser un numero entero' })
@Min(0) @Min(0, { message: 'La probabilidad debe ser mayor o igual a 0%' })
@Max(100) @Max(100, { message: 'La probabilidad debe ser menor o igual a 100%' })
@IsOptional() @IsOptional()
probability?: number; probability?: number;
@IsDateString() @IsDateString({}, { message: 'La fecha esperada de cierre debe ser una fecha valida' })
@IsOptional() @IsOptional()
expectedCloseDate?: string; expectedCloseDate?: string;
@IsUUID() @IsUUID('4', { message: 'El ID del asignado debe ser un UUID valido' })
@IsOptional() @IsOptional()
assignedTo?: string; assignedTo?: string;
@IsString() @IsString({ message: 'El nombre del contacto debe ser una cadena de texto' })
@MaxLength(200) @MaxLength(200, { message: 'El nombre del contacto no puede exceder 200 caracteres' })
@IsOptional() @IsOptional()
contactName?: string; contactName?: string;
@IsEmail() @IsEmail({}, { message: 'El email del contacto debe tener un formato valido' })
@IsOptional() @IsOptional()
contactEmail?: string; contactEmail?: string;
@IsString() @IsString({ message: 'El telefono del contacto debe ser una cadena de texto' })
@MaxLength(50) @MaxLength(50, { message: 'El telefono del contacto no puede exceder 50 caracteres' })
@IsOptional() @IsOptional()
contactPhone?: string; contactPhone?: string;
@IsString() @IsString({ message: 'El nombre de la empresa debe ser una cadena de texto' })
@MaxLength(200) @MaxLength(200, { message: 'El nombre de la empresa no puede exceder 200 caracteres' })
@IsOptional() @IsOptional()
companyName?: string; companyName?: string;
@IsString() @IsString({ message: 'Las notas deben ser una cadena de texto' })
@IsOptional() @IsOptional()
notes?: string; notes?: string;
@IsObject() @IsObject({ message: 'Los campos personalizados deben ser un objeto' })
@IsOptional() @IsOptional()
customFields?: Record<string, any>; customFields?: Record<string, any>;
} }
export class UpdateOpportunityDto { export class UpdateOpportunityDto {
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(255) @MaxLength(255, { message: 'El nombre no puede exceder 255 caracteres' })
@IsOptional() @IsOptional()
name?: string; name?: string;
@IsString() @IsString({ message: 'La descripcion debe ser una cadena de texto' })
@IsOptional() @IsOptional()
description?: string; description?: string;
@IsEnum(OpportunityStage) @IsEnum(OpportunityStage, { message: 'La etapa debe ser un valor valido' })
@IsOptional() @IsOptional()
stage?: OpportunityStage; stage?: OpportunityStage;
@IsUUID() @IsUUID('4', { message: 'El ID de etapa debe ser un UUID valido' })
@IsOptional() @IsOptional()
stageId?: string; stageId?: string;
@IsNumber() @IsNumber({}, { message: 'El monto debe ser un numero' })
@Min(0) @Min(0, { message: 'El monto debe ser mayor o igual a 0' })
@IsOptional() @IsOptional()
amount?: number; amount?: number;
@IsString() @IsString({ message: 'La moneda debe ser una cadena de texto' })
@MaxLength(3) @MaxLength(3, { message: 'La moneda no puede exceder 3 caracteres' })
@IsOptional() @IsOptional()
currency?: string; currency?: string;
@IsInt() @IsInt({ message: 'La probabilidad debe ser un numero entero' })
@Min(0) @Min(0, { message: 'La probabilidad debe ser mayor o igual a 0%' })
@Max(100) @Max(100, { message: 'La probabilidad debe ser menor o igual a 100%' })
@IsOptional() @IsOptional()
probability?: number; probability?: number;
@IsDateString() @IsDateString({}, { message: 'La fecha esperada de cierre debe ser una fecha valida' })
@IsOptional() @IsOptional()
expectedCloseDate?: string; expectedCloseDate?: string;
@IsUUID() @IsUUID('4', { message: 'El ID del asignado debe ser un UUID valido' })
@IsOptional() @IsOptional()
assignedTo?: string; assignedTo?: string;
@IsString() @IsString({ message: 'La razon de perdida debe ser una cadena de texto' })
@MaxLength(500) @MaxLength(500, { message: 'La razon de perdida no puede exceder 500 caracteres' })
@IsOptional() @IsOptional()
lostReason?: string; lostReason?: string;
@IsString() @IsString({ message: 'El nombre del contacto debe ser una cadena de texto' })
@MaxLength(200) @MaxLength(200, { message: 'El nombre del contacto no puede exceder 200 caracteres' })
@IsOptional() @IsOptional()
contactName?: string; contactName?: string;
@IsEmail() @IsEmail({}, { message: 'El email del contacto debe tener un formato valido' })
@IsOptional() @IsOptional()
contactEmail?: string; contactEmail?: string;
@IsString() @IsString({ message: 'El telefono del contacto debe ser una cadena de texto' })
@MaxLength(50) @MaxLength(50, { message: 'El telefono del contacto no puede exceder 50 caracteres' })
@IsOptional() @IsOptional()
contactPhone?: string; contactPhone?: string;
@IsString() @IsString({ message: 'El nombre de la empresa debe ser una cadena de texto' })
@MaxLength(200) @MaxLength(200, { message: 'El nombre de la empresa no puede exceder 200 caracteres' })
@IsOptional() @IsOptional()
companyName?: string; companyName?: string;
@IsString() @IsString({ message: 'Las notas deben ser una cadena de texto' })
@IsOptional() @IsOptional()
notes?: string; notes?: string;
@IsObject() @IsObject({ message: 'Los campos personalizados deben ser un objeto' })
@IsOptional() @IsOptional()
customFields?: Record<string, any>; customFields?: Record<string, any>;
} }
export class UpdateOpportunityStageDto { export class UpdateOpportunityStageDto {
@IsEnum(OpportunityStage) @IsEnum(OpportunityStage, { message: 'La etapa debe ser un valor valido' })
stage: OpportunityStage; stage: OpportunityStage;
@IsString() @IsString({ message: 'Las notas deben ser una cadena de texto' })
@IsOptional() @IsOptional()
notes?: string; notes?: string;
} }

View File

@ -31,52 +31,52 @@ export type WebhookEvent = (typeof WEBHOOK_EVENTS)[number];
// Create webhook DTO // Create webhook DTO
export class CreateWebhookDto { export class CreateWebhookDto {
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El nombre no puede exceder 100 caracteres' })
name: string; name: string;
@IsString() @IsString({ message: 'La descripcion debe ser una cadena de texto' })
@IsOptional() @IsOptional()
description?: string; description?: string;
@IsUrl({ protocols: ['https'], require_protocol: true }) @IsUrl({ protocols: ['https'], require_protocol: true }, { message: 'La URL debe ser HTTPS valida' })
url: string; url: string;
@IsArray() @IsArray({ message: 'Los eventos deben ser un arreglo' })
@ArrayMinSize(1) @ArrayMinSize(1, { message: 'Debe seleccionar al menos un evento' })
@IsString({ each: true }) @IsString({ each: true, message: 'Cada evento debe ser una cadena de texto' })
events: string[]; events: string[];
@IsObject() @IsObject({ message: 'Los headers deben ser un objeto' })
@IsOptional() @IsOptional()
headers?: Record<string, string>; headers?: Record<string, string>;
} }
// Update webhook DTO // Update webhook DTO
export class UpdateWebhookDto { export class UpdateWebhookDto {
@IsString() @IsString({ message: 'El nombre debe ser una cadena de texto' })
@MaxLength(100) @MaxLength(100, { message: 'El nombre no puede exceder 100 caracteres' })
@IsOptional() @IsOptional()
name?: string; name?: string;
@IsString() @IsString({ message: 'La descripcion debe ser una cadena de texto' })
@IsOptional() @IsOptional()
description?: string; description?: string;
@IsUrl({ protocols: ['https'], require_protocol: true }) @IsUrl({ protocols: ['https'], require_protocol: true }, { message: 'La URL debe ser HTTPS valida' })
@IsOptional() @IsOptional()
url?: string; url?: string;
@IsArray() @IsArray({ message: 'Los eventos deben ser un arreglo' })
@IsString({ each: true }) @IsString({ each: true, message: 'Cada evento debe ser una cadena de texto' })
@IsOptional() @IsOptional()
events?: string[]; events?: string[];
@IsObject() @IsObject({ message: 'Los headers deben ser un objeto' })
@IsOptional() @IsOptional()
headers?: Record<string, string>; headers?: Record<string, string>;
@IsBoolean() @IsBoolean({ message: 'Activo debe ser verdadero o falso' })
@IsOptional() @IsOptional()
isActive?: boolean; isActive?: boolean;
} }