From d30fe4d644c17b4dc86ab90d4f801b89bc216891 Mon Sep 17 00:00:00 2001 From: rckrdmrd Date: Mon, 8 Dec 2025 10:46:47 -0600 Subject: [PATCH] feat(construccion): Add HR module entities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Employee entity - Add EmployeeFraccionamiento relationship entity - Add Puesto (position) entity - Add entities index export 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../employee-fraccionamiento.entity.ts | 65 +++++++++ .../modules/hr/entities/employee.entity.ts | 136 ++++++++++++++++++ .../backend/src/modules/hr/entities/index.ts | 8 ++ .../src/modules/hr/entities/puesto.entity.ts | 68 +++++++++ 4 files changed, 277 insertions(+) create mode 100644 projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/employee-fraccionamiento.entity.ts create mode 100644 projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/employee.entity.ts create mode 100644 projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/index.ts create mode 100644 projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/puesto.entity.ts diff --git a/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/employee-fraccionamiento.entity.ts b/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/employee-fraccionamiento.entity.ts new file mode 100644 index 0000000..012f74a --- /dev/null +++ b/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/employee-fraccionamiento.entity.ts @@ -0,0 +1,65 @@ +/** + * EmployeeFraccionamiento Entity + * Asignación de empleados a obras/fraccionamientos + * + * @module HR + * @table hr.employee_fraccionamientos + * @ddl schemas/02-hr-schema-ddl.sql + */ + +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + ManyToOne, + JoinColumn, + Index, +} from 'typeorm'; +import { Tenant } from '../../core/entities/tenant.entity'; +import { Employee } from './employee.entity'; +import { Fraccionamiento } from '../../construction/entities/fraccionamiento.entity'; + +@Entity({ schema: 'hr', name: 'employee_fraccionamientos' }) +@Index(['employeeId', 'fraccionamientoId', 'fechaInicio'], { unique: true }) +export class EmployeeFraccionamiento { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ name: 'tenant_id', type: 'uuid' }) + tenantId: string; + + @Column({ name: 'employee_id', type: 'uuid' }) + employeeId: string; + + @Column({ name: 'fraccionamiento_id', type: 'uuid' }) + fraccionamientoId: string; + + @Column({ name: 'fecha_inicio', type: 'date' }) + fechaInicio: Date; + + @Column({ name: 'fecha_fin', type: 'date', nullable: true }) + fechaFin: Date; + + @Column({ type: 'varchar', length: 50, nullable: true }) + rol: string; + + @Column({ type: 'boolean', default: true }) + activo: boolean; + + @CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) + createdAt: Date; + + // Relations + @ManyToOne(() => Tenant) + @JoinColumn({ name: 'tenant_id' }) + tenant: Tenant; + + @ManyToOne(() => Employee, (e) => e.asignaciones) + @JoinColumn({ name: 'employee_id' }) + employee: Employee; + + @ManyToOne(() => Fraccionamiento) + @JoinColumn({ name: 'fraccionamiento_id' }) + fraccionamiento: Fraccionamiento; +} diff --git a/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/employee.entity.ts b/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/employee.entity.ts new file mode 100644 index 0000000..b4be02f --- /dev/null +++ b/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/employee.entity.ts @@ -0,0 +1,136 @@ +/** + * Employee Entity + * Empleados de la empresa + * + * @module HR + * @table hr.employees + * @ddl schemas/02-hr-schema-ddl.sql + */ + +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + ManyToOne, + OneToMany, + JoinColumn, + Index, +} from 'typeorm'; +import { Tenant } from '../../core/entities/tenant.entity'; +import { User } from '../../core/entities/user.entity'; +import { Puesto } from './puesto.entity'; +import { EmployeeFraccionamiento } from './employee-fraccionamiento.entity'; + +export type EstadoEmpleado = 'activo' | 'inactivo' | 'baja'; +export type Genero = 'M' | 'F'; + +@Entity({ schema: 'hr', name: 'employees' }) +@Index(['tenantId', 'codigo'], { unique: true }) +@Index(['tenantId', 'curp'], { unique: true }) +export class Employee { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ name: 'tenant_id', type: 'uuid' }) + tenantId: string; + + @Column({ type: 'varchar', length: 20 }) + codigo: string; + + @Column({ type: 'varchar', length: 100 }) + nombre: string; + + @Column({ name: 'apellido_paterno', type: 'varchar', length: 100 }) + apellidoPaterno: string; + + @Column({ name: 'apellido_materno', type: 'varchar', length: 100, nullable: true }) + apellidoMaterno: string; + + @Column({ type: 'varchar', length: 18, nullable: true }) + curp: string; + + @Column({ type: 'varchar', length: 13, nullable: true }) + rfc: string; + + @Column({ type: 'varchar', length: 11, nullable: true }) + nss: string; + + @Column({ name: 'fecha_nacimiento', type: 'date', nullable: true }) + fechaNacimiento: Date; + + @Column({ type: 'varchar', length: 1, nullable: true }) + genero: Genero; + + @Column({ type: 'varchar', length: 255, nullable: true }) + email: string; + + @Column({ type: 'varchar', length: 20, nullable: true }) + telefono: string; + + @Column({ type: 'text', nullable: true }) + direccion: string; + + @Column({ name: 'fecha_ingreso', type: 'date' }) + fechaIngreso: Date; + + @Column({ name: 'fecha_baja', type: 'date', nullable: true }) + fechaBaja: Date; + + @Column({ name: 'puesto_id', type: 'uuid', nullable: true }) + puestoId: string; + + @Column({ type: 'varchar', length: 100, nullable: true }) + departamento: string; + + @Column({ name: 'tipo_contrato', type: 'varchar', length: 50, nullable: true }) + tipoContrato: string; + + @Column({ + name: 'salario_diario', + type: 'decimal', + precision: 10, + scale: 2, + nullable: true + }) + salarioDiario: number; + + @Column({ type: 'varchar', length: 20, default: 'activo' }) + estado: EstadoEmpleado; + + @Column({ name: 'foto_url', type: 'varchar', length: 500, nullable: true }) + fotoUrl: string; + + @CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) + createdAt: Date; + + @UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' }) + updatedAt: Date; + + @Column({ name: 'created_by', type: 'uuid', nullable: true }) + createdById: string; + + // Relations + @ManyToOne(() => Tenant) + @JoinColumn({ name: 'tenant_id' }) + tenant: Tenant; + + @ManyToOne(() => Puesto, (p) => p.empleados) + @JoinColumn({ name: 'puesto_id' }) + puesto: Puesto; + + @ManyToOne(() => User) + @JoinColumn({ name: 'created_by' }) + createdBy: User; + + @OneToMany(() => EmployeeFraccionamiento, (ef) => ef.employee) + asignaciones: EmployeeFraccionamiento[]; + + // Computed property + get nombreCompleto(): string { + return [this.nombre, this.apellidoPaterno, this.apellidoMaterno] + .filter(Boolean) + .join(' '); + } +} diff --git a/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/index.ts b/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/index.ts new file mode 100644 index 0000000..48752f0 --- /dev/null +++ b/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/index.ts @@ -0,0 +1,8 @@ +/** + * HR Entities Index + * @module HR + */ + +export * from './puesto.entity'; +export * from './employee.entity'; +export * from './employee-fraccionamiento.entity'; diff --git a/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/puesto.entity.ts b/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/puesto.entity.ts new file mode 100644 index 0000000..26d89f3 --- /dev/null +++ b/projects/erp-suite/apps/verticales/construccion/backend/src/modules/hr/entities/puesto.entity.ts @@ -0,0 +1,68 @@ +/** + * Puesto Entity + * Catálogo de puestos de trabajo + * + * @module HR + * @table hr.puestos + * @ddl schemas/02-hr-schema-ddl.sql + */ + +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + ManyToOne, + OneToMany, + JoinColumn, + Index, +} from 'typeorm'; +import { Tenant } from '../../core/entities/tenant.entity'; +import { Employee } from './employee.entity'; + +@Entity({ schema: 'hr', name: 'puestos' }) +@Index(['tenantId', 'codigo'], { unique: true }) +export class Puesto { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ name: 'tenant_id', type: 'uuid' }) + tenantId: string; + + @Column({ type: 'varchar', length: 20 }) + codigo: string; + + @Column({ type: 'varchar', length: 100 }) + nombre: string; + + @Column({ type: 'text', nullable: true }) + descripcion: string; + + @Column({ name: 'nivel_riesgo', type: 'varchar', length: 20, nullable: true }) + nivelRiesgo: string; + + @Column({ + name: 'requiere_capacitacion_especial', + type: 'boolean', + default: false + }) + requiereCapacitacionEspecial: boolean; + + @Column({ type: 'boolean', default: true }) + activo: boolean; + + @CreateDateColumn({ name: 'created_at', type: 'timestamptz' }) + createdAt: Date; + + @UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' }) + updatedAt: Date; + + // Relations + @ManyToOne(() => Tenant) + @JoinColumn({ name: 'tenant_id' }) + tenant: Tenant; + + @OneToMany(() => Employee, (e) => e.puesto) + empleados: Employee[]; +}