- MAI-018 Bidding module: entities, services, controllers, DTOs - Opportunity, Tender, Proposal, Vendor management - Bid calendar, documents, analytics - Earned Value Management: Curva S, SPI/CPI reports - earned-value.service.ts with EV, PV, AC calculations - earned-value.controller.ts with 9 endpoints - DTOs for modules: assets, contracts, documents, purchase, quality - 28 new DTO files with class-validator decorators - Storage module: service and controller implementation - Multi-provider support (local, S3, GCS, Azure) - File management, upload/download URLs - Multiple entity and service fixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
467 lines
7.1 KiB
TypeScript
467 lines
7.1 KiB
TypeScript
/**
|
|
* Contract DTOs - Data Transfer Objects para Contratos
|
|
*
|
|
* Contratos con clientes y subcontratistas.
|
|
*
|
|
* @module Contracts (MAI-012)
|
|
*/
|
|
|
|
import {
|
|
IsString,
|
|
IsUUID,
|
|
IsOptional,
|
|
IsEnum,
|
|
IsNumber,
|
|
IsDateString,
|
|
MinLength,
|
|
MaxLength,
|
|
Min,
|
|
Max,
|
|
} from 'class-validator';
|
|
|
|
/**
|
|
* Tipo de contrato
|
|
*/
|
|
export enum ContractTypeEnum {
|
|
CLIENT = 'client',
|
|
SUBCONTRACTOR = 'subcontractor',
|
|
}
|
|
|
|
/**
|
|
* Estado del contrato
|
|
*/
|
|
export enum ContractStatusEnum {
|
|
DRAFT = 'draft',
|
|
REVIEW = 'review',
|
|
APPROVED = 'approved',
|
|
ACTIVE = 'active',
|
|
COMPLETED = 'completed',
|
|
TERMINATED = 'terminated',
|
|
}
|
|
|
|
/**
|
|
* Tipo de contrato cliente
|
|
*/
|
|
export enum ClientContractTypeEnum {
|
|
DESARROLLO = 'desarrollo',
|
|
LLAVE_EN_MANO = 'llave_en_mano',
|
|
ADMINISTRACION = 'administracion',
|
|
}
|
|
|
|
/**
|
|
* DTO para crear un nuevo contrato
|
|
*/
|
|
export class CreateContractDto {
|
|
@IsString()
|
|
@MinLength(3)
|
|
@MaxLength(50)
|
|
contractNumber: string;
|
|
|
|
@IsEnum(ContractTypeEnum)
|
|
type: ContractTypeEnum;
|
|
|
|
@IsString()
|
|
@MinLength(5)
|
|
@MaxLength(255)
|
|
title: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
description?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
partnerId?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
fraccionamientoId?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
projectId?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
subcontractorId?: string;
|
|
|
|
@IsDateString()
|
|
startDate: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
endDate?: string;
|
|
|
|
@IsNumber()
|
|
@Min(0)
|
|
contractAmount: number;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(3)
|
|
currency?: string;
|
|
|
|
@IsOptional()
|
|
@IsEnum(ClientContractTypeEnum)
|
|
clientContractType?: ClientContractTypeEnum;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(255)
|
|
clientName?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(13)
|
|
clientRfc?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
clientAddress?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(50)
|
|
specialty?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
paymentTerms?: string;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(0)
|
|
@Max(100)
|
|
retentionPercentage?: number;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(0)
|
|
@Max(100)
|
|
advancePercentage?: number;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
notes?: string;
|
|
}
|
|
|
|
/**
|
|
* DTO para actualizar un contrato existente
|
|
*/
|
|
export class UpdateContractDto {
|
|
@IsOptional()
|
|
@IsString()
|
|
@MinLength(3)
|
|
@MaxLength(50)
|
|
contractNumber?: string;
|
|
|
|
@IsOptional()
|
|
@IsEnum(ContractTypeEnum)
|
|
type?: ContractTypeEnum;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MinLength(5)
|
|
@MaxLength(255)
|
|
title?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
description?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
partnerId?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
fraccionamientoId?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
projectId?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
subcontractorId?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
startDate?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
endDate?: string;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(0)
|
|
contractAmount?: number;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(3)
|
|
currency?: string;
|
|
|
|
@IsOptional()
|
|
@IsEnum(ClientContractTypeEnum)
|
|
clientContractType?: ClientContractTypeEnum;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(255)
|
|
clientName?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(13)
|
|
clientRfc?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
clientAddress?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(50)
|
|
specialty?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
paymentTerms?: string;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(0)
|
|
@Max(100)
|
|
retentionPercentage?: number;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(0)
|
|
@Max(100)
|
|
advancePercentage?: number;
|
|
|
|
@IsOptional()
|
|
@IsEnum(ContractStatusEnum)
|
|
status?: ContractStatusEnum;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
documentUrl?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
signedDocumentUrl?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
notes?: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
terminationReason?: string;
|
|
}
|
|
|
|
/**
|
|
* DTO para filtrar contratos en listados
|
|
*/
|
|
export class ContractFiltersDto {
|
|
@IsOptional()
|
|
@IsEnum(ContractTypeEnum)
|
|
type?: ContractTypeEnum;
|
|
|
|
@IsOptional()
|
|
@IsEnum(ContractStatusEnum)
|
|
status?: ContractStatusEnum;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
partnerId?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
fraccionamientoId?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
projectId?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID()
|
|
subcontractorId?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
dateFrom?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
dateTo?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
startDateFrom?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
startDateTo?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
endDateFrom?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
endDateTo?: string;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(0)
|
|
amountMin?: number;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(0)
|
|
amountMax?: number;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
search?: string;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(1)
|
|
page?: number;
|
|
|
|
@IsOptional()
|
|
@IsNumber()
|
|
@Min(1)
|
|
limit?: number;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
sortBy?: string;
|
|
|
|
@IsOptional()
|
|
@IsEnum(['ASC', 'DESC'])
|
|
sortOrder?: 'ASC' | 'DESC';
|
|
}
|
|
|
|
/**
|
|
* DTO para aprobar un contrato
|
|
*/
|
|
export class ApproveContractDto {
|
|
@IsOptional()
|
|
@IsString()
|
|
notes?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
approvalDate?: string;
|
|
}
|
|
|
|
/**
|
|
* DTO para aprobacion legal del contrato
|
|
*/
|
|
export class LegalApproveContractDto {
|
|
@IsOptional()
|
|
@IsString()
|
|
notes?: string;
|
|
}
|
|
|
|
/**
|
|
* DTO para terminar un contrato
|
|
*/
|
|
export class TerminateContractDto {
|
|
@IsString()
|
|
@MinLength(10)
|
|
reason: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
terminationDate?: string;
|
|
}
|
|
|
|
/**
|
|
* DTO para firmar un contrato
|
|
*/
|
|
export class SignContractDto {
|
|
@IsOptional()
|
|
@IsString()
|
|
@MaxLength(500)
|
|
signedDocumentUrl?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString()
|
|
signedDate?: string;
|
|
}
|
|
|
|
/**
|
|
* DTO de respuesta para un contrato
|
|
*/
|
|
export class ContractResponseDto {
|
|
id: string;
|
|
tenantId: string;
|
|
projectId?: string;
|
|
project?: {
|
|
id: string;
|
|
code: string;
|
|
name: string;
|
|
};
|
|
fraccionamientoId?: string;
|
|
fraccionamiento?: {
|
|
id: string;
|
|
code: string;
|
|
name: string;
|
|
};
|
|
contractNumber: string;
|
|
contractType: ContractTypeEnum;
|
|
clientContractType?: ClientContractTypeEnum;
|
|
name: string;
|
|
description?: string;
|
|
clientName?: string;
|
|
clientRfc?: string;
|
|
clientAddress?: string;
|
|
subcontractorId?: string;
|
|
subcontractor?: {
|
|
id: string;
|
|
code: string;
|
|
businessName: string;
|
|
};
|
|
specialty?: string;
|
|
startDate: Date;
|
|
endDate: Date;
|
|
contractAmount: string;
|
|
currency: string;
|
|
paymentTerms?: string;
|
|
retentionPercentage: string;
|
|
advancePercentage: string;
|
|
status: ContractStatusEnum;
|
|
submittedAt?: Date;
|
|
legalApprovedAt?: Date;
|
|
approvedAt?: Date;
|
|
signedAt?: Date;
|
|
terminatedAt?: Date;
|
|
terminationReason?: string;
|
|
documentUrl?: string;
|
|
signedDocumentUrl?: string;
|
|
progressPercentage: string;
|
|
invoicedAmount: string;
|
|
paidAmount: string;
|
|
remainingAmount?: string;
|
|
isExpiring?: boolean;
|
|
notes?: string;
|
|
addendumsCount?: number;
|
|
createdAt: Date;
|
|
createdById?: string;
|
|
createdBy?: {
|
|
id: string;
|
|
firstName: string;
|
|
lastName: string;
|
|
};
|
|
updatedAt: Date;
|
|
}
|