diff --git a/src/modules/projects/dto/create-timesheet.dto.ts b/src/modules/projects/dto/create-timesheet.dto.ts new file mode 100644 index 0000000..b7c92a3 --- /dev/null +++ b/src/modules/projects/dto/create-timesheet.dto.ts @@ -0,0 +1,83 @@ +// Note: Basic CreateTimesheetDto, UpdateTimesheetDto, TimesheetFilters are defined in timesheets.service.ts +// This file contains extended DTOs for additional functionality + +/** + * Respuesta de timesheet con datos relacionados + */ +export interface TimesheetResponse { + id: string; + tenant_id: string; + company_id: string; + project_id: string; + project_name?: string; + task_id: string | null; + task_name?: string; + user_id: string; + user_name?: string; + date: Date; + hours: number; + description: string | null; + billable: boolean; + invoiced: boolean; + invoice_id: string | null; + status: 'draft' | 'submitted' | 'approved' | 'rejected'; + approved_by: string | null; + approved_at: Date | null; + created_at: Date; + created_by: string | null; + updated_at: Date | null; +} + +/** + * Resumen de horas por proyecto + */ +export interface TimesheetSummaryByProject { + project_id: string; + project_name: string; + total_hours: number; + billable_hours: number; + non_billable_hours: number; + invoiced_hours: number; + pending_hours: number; +} + +/** + * Resumen de horas por usuario + */ +export interface TimesheetSummaryByUser { + user_id: string; + user_name: string; + total_hours: number; + billable_hours: number; + approved_hours: number; + pending_approval: number; +} + +/** + * Resumen de horas por tarea + */ +export interface TimesheetSummaryByTask { + task_id: string; + task_name: string; + project_id: string; + project_name: string; + estimated_hours: number; + spent_hours: number; + remaining_hours: number; + progress_percentage: number; +} + +/** + * Resumen general de timesheets + */ +export interface TimesheetSummary { + total_hours: number; + billable_hours: number; + non_billable_hours: number; + invoiced_hours: number; + approved_hours: number; + pending_approval_hours: number; + by_project?: TimesheetSummaryByProject[]; + by_user?: TimesheetSummaryByUser[]; + by_task?: TimesheetSummaryByTask[]; +} diff --git a/src/modules/projects/dto/index.ts b/src/modules/projects/dto/index.ts new file mode 100644 index 0000000..706e496 --- /dev/null +++ b/src/modules/projects/dto/index.ts @@ -0,0 +1,2 @@ +export * from './create-timesheet.dto.js'; +export * from './update-timesheet.dto.js'; diff --git a/src/modules/projects/dto/update-timesheet.dto.ts b/src/modules/projects/dto/update-timesheet.dto.ts new file mode 100644 index 0000000..3e8d372 --- /dev/null +++ b/src/modules/projects/dto/update-timesheet.dto.ts @@ -0,0 +1,42 @@ +// Note: Basic UpdateTimesheetDto is defined in timesheets.service.ts +// This file contains extended DTOs for additional functionality + +/** + * DTO para enviar un timesheet a aprobacion + */ +export interface SubmitTimesheetDto { + /** IDs de los timesheets a enviar */ + timesheet_ids: string[]; +} + +/** + * DTO para aprobar/rechazar timesheets + */ +export interface ApproveTimesheetDto { + /** IDs de los timesheets a aprobar/rechazar */ + timesheet_ids: string[]; + /** Comentario opcional del aprobador */ + comment?: string; +} + +/** + * DTO para marcar timesheets como facturados + */ +export interface MarkInvoicedDto { + /** IDs de los timesheets a marcar */ + timesheet_ids: string[]; + /** ID de la factura */ + invoice_id: string; +} + +/** + * DTO para accion masiva sobre timesheets + */ +export interface BulkTimesheetActionDto { + /** IDs de los timesheets */ + timesheet_ids: string[]; + /** Accion a realizar */ + action: 'submit' | 'approve' | 'reject' | 'delete'; + /** Comentario opcional */ + comment?: string; +} diff --git a/src/modules/projects/entities/index.ts b/src/modules/projects/entities/index.ts new file mode 100644 index 0000000..94033da --- /dev/null +++ b/src/modules/projects/entities/index.ts @@ -0,0 +1 @@ +export * from './timesheet.entity.js'; diff --git a/src/modules/projects/entities/timesheet.entity.ts b/src/modules/projects/entities/timesheet.entity.ts new file mode 100644 index 0000000..3304761 --- /dev/null +++ b/src/modules/projects/entities/timesheet.entity.ts @@ -0,0 +1,95 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + Index, + ManyToOne, + JoinColumn, +} from 'typeorm'; + +export enum TimesheetStatus { + DRAFT = 'draft', + SUBMITTED = 'submitted', + APPROVED = 'approved', + REJECTED = 'rejected', +} + +@Entity({ schema: 'projects', name: 'timesheets' }) +@Index('idx_timesheets_tenant', ['tenantId']) +@Index('idx_timesheets_company', ['companyId']) +@Index('idx_timesheets_project', ['projectId']) +@Index('idx_timesheets_task', ['taskId']) +@Index('idx_timesheets_user', ['userId']) +@Index('idx_timesheets_user_date', ['userId', 'date']) +@Index('idx_timesheets_date', ['date']) +@Index('idx_timesheets_status', ['status']) +export class TimesheetEntity { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ type: 'uuid', nullable: false, name: 'tenant_id' }) + tenantId: string; + + @Column({ type: 'uuid', nullable: false, name: 'company_id' }) + companyId: string; + + @Column({ type: 'uuid', nullable: false, name: 'project_id' }) + projectId: string; + + @Column({ type: 'uuid', nullable: true, name: 'task_id' }) + taskId: string | null; + + @Column({ type: 'uuid', nullable: false, name: 'user_id' }) + userId: string; + + @Column({ type: 'date', nullable: false }) + date: Date; + + @Column({ type: 'decimal', precision: 5, scale: 2, nullable: false }) + hours: number; + + @Column({ type: 'text', nullable: true }) + description: string | null; + + @Column({ type: 'boolean', default: true, nullable: false }) + billable: boolean; + + @Column({ type: 'boolean', default: false, nullable: false }) + invoiced: boolean; + + @Column({ type: 'uuid', nullable: true, name: 'invoice_id' }) + invoiceId: string | null; + + @Column({ + type: 'enum', + enum: TimesheetStatus, + default: TimesheetStatus.DRAFT, + nullable: false, + }) + status: TimesheetStatus; + + @Column({ type: 'uuid', nullable: true, name: 'approved_by' }) + approvedBy: string | null; + + @Column({ type: 'timestamp', nullable: true, name: 'approved_at' }) + approvedAt: Date | null; + + // Audit fields + @CreateDateColumn({ name: 'created_at', type: 'timestamp' }) + createdAt: Date; + + @Column({ type: 'uuid', nullable: true, name: 'created_by' }) + createdBy: string | null; + + @UpdateDateColumn({ + name: 'updated_at', + type: 'timestamp', + nullable: true, + }) + updatedAt: Date | null; + + @Column({ type: 'uuid', nullable: true, name: 'updated_by' }) + updatedBy: string | null; +} diff --git a/src/modules/projects/index.ts b/src/modules/projects/index.ts index 94e7545..c5a5215 100644 --- a/src/modules/projects/index.ts +++ b/src/modules/projects/index.ts @@ -5,3 +5,9 @@ export * from './billing.service.js'; export * from './hr-integration.service.js'; export * from './projects.controller.js'; export { default as projectsRoutes } from './projects.routes.js'; + +// Entities +export * from './entities/index.js'; + +// DTOs +export * from './dto/index.js';