- 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>
325 lines
9.2 KiB
TypeScript
325 lines
9.2 KiB
TypeScript
import { IsString, IsOptional, IsEnum, IsNumber, IsUUID, Min, Max } from 'class-validator';
|
|
import { Type } from 'class-transformer';
|
|
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
|
import { AssigneeType, AssignmentStatus } from '../entities/assignment.entity';
|
|
import { ProgressSource } from '../entities/progress-log.entity';
|
|
|
|
// ─────────────────────────────────────────────
|
|
// Create Assignment DTO
|
|
// ─────────────────────────────────────────────
|
|
|
|
export class CreateAssignmentDto {
|
|
@ApiProperty()
|
|
@IsUUID('4', { message: 'El ID de definicion debe ser un UUID valido' })
|
|
definitionId: string;
|
|
|
|
@ApiPropertyOptional({ enum: AssigneeType, default: AssigneeType.USER })
|
|
@IsOptional()
|
|
@IsEnum(AssigneeType, { message: 'El tipo de asignado debe ser un valor valido' })
|
|
assigneeType?: AssigneeType;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsUUID('4', { message: 'El ID de usuario debe ser un UUID valido' })
|
|
userId?: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsUUID('4', { message: 'El ID de equipo debe ser un UUID valido' })
|
|
teamId?: string;
|
|
|
|
@ApiPropertyOptional({ example: 50000 })
|
|
@IsOptional()
|
|
@IsNumber({}, { message: 'El objetivo personalizado debe ser un numero' })
|
|
@Min(0, { message: 'El objetivo personalizado debe ser mayor o igual a 0' })
|
|
customTarget?: number;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsString({ message: 'Las notas deben ser una cadena de texto' })
|
|
notes?: string;
|
|
}
|
|
|
|
// ─────────────────────────────────────────────
|
|
// Update Assignment DTO
|
|
// ─────────────────────────────────────────────
|
|
|
|
export class UpdateAssignmentDto extends PartialType(CreateAssignmentDto) {}
|
|
|
|
// ─────────────────────────────────────────────
|
|
// Update Assignment Status DTO
|
|
// ─────────────────────────────────────────────
|
|
|
|
export class UpdateAssignmentStatusDto {
|
|
@ApiProperty({ enum: AssignmentStatus })
|
|
@IsEnum(AssignmentStatus)
|
|
status: AssignmentStatus;
|
|
}
|
|
|
|
// ─────────────────────────────────────────────
|
|
// Update Progress DTO
|
|
// ─────────────────────────────────────────────
|
|
|
|
export class UpdateProgressDto {
|
|
@ApiProperty({ example: 25000 })
|
|
@IsNumber({}, { message: 'El valor debe ser un numero' })
|
|
@Min(0, { message: 'El valor debe ser mayor o igual a 0' })
|
|
value: number;
|
|
|
|
@ApiPropertyOptional({ enum: ProgressSource, default: ProgressSource.MANUAL })
|
|
@IsOptional()
|
|
@IsEnum(ProgressSource, { message: 'La fuente de progreso debe ser un valor valido' })
|
|
source?: ProgressSource;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsString({ message: 'La referencia de fuente debe ser una cadena de texto' })
|
|
sourceReference?: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsString({ message: 'Las notas deben ser una cadena de texto' })
|
|
notes?: string;
|
|
}
|
|
|
|
// ─────────────────────────────────────────────
|
|
// Assignment Response DTO
|
|
// ─────────────────────────────────────────────
|
|
|
|
export class AssignmentResponseDto {
|
|
@ApiProperty()
|
|
id: string;
|
|
|
|
@ApiProperty()
|
|
tenantId: string;
|
|
|
|
@ApiProperty()
|
|
definitionId: string;
|
|
|
|
@ApiProperty({ enum: AssigneeType })
|
|
assigneeType: AssigneeType;
|
|
|
|
@ApiPropertyOptional()
|
|
userId: string | null;
|
|
|
|
@ApiPropertyOptional()
|
|
teamId: string | null;
|
|
|
|
@ApiPropertyOptional()
|
|
customTarget: number | null;
|
|
|
|
@ApiProperty()
|
|
currentValue: number;
|
|
|
|
@ApiProperty()
|
|
progressPercentage: number;
|
|
|
|
@ApiPropertyOptional()
|
|
lastUpdatedAt: Date | null;
|
|
|
|
@ApiProperty({ enum: AssignmentStatus })
|
|
status: AssignmentStatus;
|
|
|
|
@ApiPropertyOptional()
|
|
achievedAt: Date | null;
|
|
|
|
@ApiPropertyOptional()
|
|
notes: string | null;
|
|
|
|
@ApiProperty()
|
|
createdAt: Date;
|
|
|
|
@ApiProperty()
|
|
updatedAt: Date;
|
|
|
|
// Nested objects
|
|
@ApiPropertyOptional()
|
|
definition?: {
|
|
id: string;
|
|
name: string;
|
|
targetValue: number;
|
|
unit: string | null;
|
|
startsAt: Date;
|
|
endsAt: Date;
|
|
};
|
|
|
|
@ApiPropertyOptional()
|
|
user?: {
|
|
id: string;
|
|
email: string;
|
|
firstName: string | null;
|
|
lastName: string | null;
|
|
};
|
|
}
|
|
|
|
// ─────────────────────────────────────────────
|
|
// Assignment Filters DTO
|
|
// ─────────────────────────────────────────────
|
|
|
|
export class AssignmentFiltersDto {
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsUUID('4', { message: 'El ID de definicion debe ser un UUID valido' })
|
|
definitionId?: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsUUID('4', { message: 'El ID de usuario debe ser un UUID valido' })
|
|
userId?: string;
|
|
|
|
@ApiPropertyOptional({ enum: AssignmentStatus })
|
|
@IsOptional()
|
|
@IsEnum(AssignmentStatus, { message: 'El estado debe ser un valor valido' })
|
|
status?: AssignmentStatus;
|
|
|
|
@ApiPropertyOptional({ enum: AssigneeType })
|
|
@IsOptional()
|
|
@IsEnum(AssigneeType, { message: 'El tipo de asignado debe ser un valor valido' })
|
|
assigneeType?: AssigneeType;
|
|
|
|
@ApiPropertyOptional({ description: 'Minimum progress percentage' })
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsNumber({}, { message: 'El progreso minimo debe ser un numero' })
|
|
@Min(0, { message: 'El progreso minimo debe ser mayor o igual a 0%' })
|
|
@Max(100, { message: 'El progreso minimo debe ser menor o igual a 100%' })
|
|
minProgress?: number;
|
|
|
|
@ApiPropertyOptional({ description: 'Maximum progress percentage' })
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsNumber({}, { message: 'El progreso maximo debe ser un numero' })
|
|
@Min(0, { message: 'El progreso maximo debe ser mayor o igual a 0%' })
|
|
@Max(100, { message: 'El progreso maximo debe ser menor o igual a 100%' })
|
|
maxProgress?: number;
|
|
|
|
@ApiPropertyOptional({ example: 'progressPercentage' })
|
|
@IsOptional()
|
|
@IsString()
|
|
sortBy?: string;
|
|
|
|
@ApiPropertyOptional({ enum: ['ASC', 'DESC'], default: 'DESC' })
|
|
@IsOptional()
|
|
@IsString()
|
|
sortOrder?: 'ASC' | 'DESC';
|
|
|
|
@ApiPropertyOptional({ default: 1 })
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsNumber()
|
|
page?: number;
|
|
|
|
@ApiPropertyOptional({ default: 20 })
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsNumber()
|
|
limit?: number;
|
|
}
|
|
|
|
// ─────────────────────────────────────────────
|
|
// Progress Log Response DTO
|
|
// ─────────────────────────────────────────────
|
|
|
|
export class ProgressLogResponseDto {
|
|
@ApiProperty()
|
|
id: string;
|
|
|
|
@ApiProperty()
|
|
assignmentId: string;
|
|
|
|
@ApiPropertyOptional()
|
|
previousValue: number | null;
|
|
|
|
@ApiProperty()
|
|
newValue: number;
|
|
|
|
@ApiPropertyOptional()
|
|
changeAmount: number | null;
|
|
|
|
@ApiProperty({ enum: ProgressSource })
|
|
source: ProgressSource;
|
|
|
|
@ApiPropertyOptional()
|
|
sourceReference: string | null;
|
|
|
|
@ApiPropertyOptional()
|
|
notes: string | null;
|
|
|
|
@ApiProperty()
|
|
loggedAt: Date;
|
|
|
|
@ApiPropertyOptional()
|
|
loggedBy: string | null;
|
|
}
|
|
|
|
// ─────────────────────────────────────────────
|
|
// My Goals Summary DTO
|
|
// ─────────────────────────────────────────────
|
|
|
|
export class MyGoalsSummaryDto {
|
|
@ApiProperty()
|
|
totalAssignments: number;
|
|
|
|
@ApiProperty()
|
|
activeAssignments: number;
|
|
|
|
@ApiProperty()
|
|
achievedAssignments: number;
|
|
|
|
@ApiProperty()
|
|
failedAssignments: number;
|
|
|
|
@ApiProperty()
|
|
averageProgress: number;
|
|
|
|
@ApiProperty()
|
|
atRiskCount: number; // < 50% progress with > 75% time elapsed
|
|
}
|
|
|
|
// ─────────────────────────────────────────────
|
|
// Goal Report DTOs
|
|
// ─────────────────────────────────────────────
|
|
|
|
export class CompletionReportDto {
|
|
@ApiProperty()
|
|
totalGoals: number;
|
|
|
|
@ApiProperty()
|
|
achievedGoals: number;
|
|
|
|
@ApiProperty()
|
|
failedGoals: number;
|
|
|
|
@ApiProperty()
|
|
activeGoals: number;
|
|
|
|
@ApiProperty()
|
|
completionRate: number;
|
|
|
|
@ApiProperty()
|
|
averageProgress: number;
|
|
}
|
|
|
|
export class UserReportDto {
|
|
@ApiProperty()
|
|
userId: string;
|
|
|
|
@ApiPropertyOptional()
|
|
userName: string | null;
|
|
|
|
@ApiProperty()
|
|
totalAssignments: number;
|
|
|
|
@ApiProperty()
|
|
achieved: number;
|
|
|
|
@ApiProperty()
|
|
failed: number;
|
|
|
|
@ApiProperty()
|
|
active: number;
|
|
|
|
@ApiProperty()
|
|
averageProgress: number;
|
|
}
|