erp-core/docs/03-fase-vertical/MGN-014-hr/especificaciones/ET-HR-BACKEND.md
rckrdmrd 0086695b4c
Some checks failed
ERP Core CI / Backend Lint (push) Has been cancelled
ERP Core CI / Backend Unit Tests (push) Has been cancelled
ERP Core CI / Backend Integration Tests (push) Has been cancelled
ERP Core CI / Frontend Lint (push) Has been cancelled
ERP Core CI / Frontend Unit Tests (push) Has been cancelled
ERP Core CI / Frontend E2E Tests (push) Has been cancelled
ERP Core CI / Database DDL Validation (push) Has been cancelled
ERP Core CI / Backend Build (push) Has been cancelled
ERP Core CI / Frontend Build (push) Has been cancelled
ERP Core CI / CI Success (push) Has been cancelled
Performance Tests / Lighthouse CI (push) Has been cancelled
Performance Tests / Bundle Size Analysis (push) Has been cancelled
Performance Tests / k6 Load Tests (push) Has been cancelled
Performance Tests / Performance Summary (push) Has been cancelled
[SIMCO-V38] feat: Actualizar a SIMCO v3.8.0 + cambios backend
- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8
- Actualizaciones en modulos CRM y OpenAPI

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 08:53:05 -06:00

40 KiB

ET-HR-BACKEND - Especificacion Tecnica Backend HR

METADATOS

Campo Valor
Modulo MGN-014
Nombre Human Resources (HR)
Version 1.0.0
Fecha 2026-01-10
Ubicacion backend/src/modules/hr/
Schema BD hr
Estado Implementado

SERVICIOS

Resumen de Servicios (7)

# Servicio Archivo Descripcion
1 EmployeesService employees.service.ts Gestion de empleados
2 DepartmentsService departments.service.ts Departamentos y puestos
3 ContractsService contracts.service.ts Contratos laborales
4 LeavesService leaves.service.ts Ausencias y vacaciones
5 SkillsService skills.service.ts Competencias y habilidades
6 ExpensesService expenses.service.ts Gastos de empleados
7 PayslipsService payslips.service.ts Nominas y recibos

1. EmployeesService

Archivo: employees.service.ts

Metodos

Metodo Parametros Retorno Descripcion
findAll tenantId: string, filters: EmployeeFilters Promise<{ data: Employee[]; total: number }> Lista empleados con paginacion y filtros
findById id: string, tenantId: string Promise<Employee> Obtiene empleado por ID
create dto: CreateEmployeeDto, tenantId: string, userId: string Promise<Employee> Crea nuevo empleado
update id: string, dto: UpdateEmployeeDto, tenantId: string, userId: string Promise<Employee> Actualiza empleado
terminate id: string, terminationDate: string, tenantId: string, userId: string Promise<Employee> Da de baja empleado
reactivate id: string, tenantId: string, userId: string Promise<Employee> Reactiva empleado
delete id: string, tenantId: string Promise<void> Elimina empleado
getSubordinates id: string, tenantId: string Promise<Employee[]> Obtiene subordinados

Reglas de Negocio

  • El employee_number debe ser unico por tenant
  • No se puede eliminar un empleado con contratos asociados
  • No se puede eliminar un empleado que es manager de otros
  • Al terminar un empleado, se terminan sus contratos activos

2. DepartmentsService

Archivo: departments.service.ts

Metodos - Departamentos

Metodo Parametros Retorno Descripcion
findAll tenantId: string, filters: DepartmentFilters Promise<{ data: Department[]; total: number }> Lista departamentos
findById id: string, tenantId: string Promise<Department> Obtiene departamento por ID
create dto: CreateDepartmentDto, tenantId: string, userId: string Promise<Department> Crea departamento
update id: string, dto: UpdateDepartmentDto, tenantId: string Promise<Department> Actualiza departamento
delete id: string, tenantId: string Promise<void> Elimina departamento

Metodos - Puestos de Trabajo

Metodo Parametros Retorno Descripcion
getJobPositions tenantId: string, includeInactive?: boolean Promise<JobPosition[]> Lista puestos de trabajo
getJobPositionById id: string, tenantId: string Promise<JobPosition> Obtiene puesto por ID
createJobPosition dto: CreateJobPositionDto, tenantId: string Promise<JobPosition> Crea puesto
updateJobPosition id: string, dto: UpdateJobPositionDto, tenantId: string Promise<JobPosition> Actualiza puesto
deleteJobPosition id: string, tenantId: string Promise<void> Elimina puesto

Reglas de Negocio

  • El nombre del departamento debe ser unico por empresa
  • No se puede eliminar un departamento con empleados
  • No se puede eliminar un departamento con subdepartamentos
  • El nombre del puesto debe ser unico por tenant

3. ContractsService

Archivo: contracts.service.ts

Metodos

Metodo Parametros Retorno Descripcion
findAll tenantId: string, filters: ContractFilters Promise<{ data: Contract[]; total: number }> Lista contratos
findById id: string, tenantId: string Promise<Contract> Obtiene contrato por ID
create dto: CreateContractDto, tenantId: string, userId: string Promise<Contract> Crea contrato
update id: string, dto: UpdateContractDto, tenantId: string, userId: string Promise<Contract> Actualiza contrato
activate id: string, tenantId: string, userId: string Promise<Contract> Activa contrato
terminate id: string, terminationDate: string, tenantId: string, userId: string Promise<Contract> Termina contrato
cancel id: string, tenantId: string, userId: string Promise<Contract> Cancela contrato
delete id: string, tenantId: string Promise<void> Elimina contrato

Flujo de Estados

draft -> active -> expired/terminated
draft -> cancelled

Reglas de Negocio

  • Un empleado solo puede tener un contrato activo
  • Solo se pueden editar contratos en estado draft
  • Solo se pueden eliminar contratos en draft o cancelled
  • Al activar, actualiza el departamento y puesto del empleado

4. LeavesService

Archivo: leaves.service.ts

Metodos - Tipos de Ausencia

Metodo Parametros Retorno Descripcion
getLeaveTypes tenantId: string, includeInactive?: boolean Promise<LeaveTypeConfig[]> Lista tipos de ausencia
getLeaveTypeById id: string, tenantId: string Promise<LeaveTypeConfig> Obtiene tipo por ID
createLeaveType dto: CreateLeaveTypeDto, tenantId: string Promise<LeaveTypeConfig> Crea tipo de ausencia
updateLeaveType id: string, dto: UpdateLeaveTypeDto, tenantId: string Promise<LeaveTypeConfig> Actualiza tipo
deleteLeaveType id: string, tenantId: string Promise<void> Elimina tipo

Metodos - Ausencias

Metodo Parametros Retorno Descripcion
findAll tenantId: string, filters: LeaveFilters Promise<{ data: Leave[]; total: number }> Lista ausencias
findById id: string, tenantId: string Promise<Leave> Obtiene ausencia por ID
create dto: CreateLeaveDto, tenantId: string, userId: string Promise<Leave> Crea ausencia
update id: string, dto: UpdateLeaveDto, tenantId: string, userId: string Promise<Leave> Actualiza ausencia
submit id: string, tenantId: string, userId: string Promise<Leave> Envia solicitud
approve id: string, tenantId: string, userId: string Promise<Leave> Aprueba solicitud
reject id: string, reason: string, tenantId: string, userId: string Promise<Leave> Rechaza solicitud
cancel id: string, tenantId: string, userId: string Promise<Leave> Cancela solicitud
delete id: string, tenantId: string Promise<void> Elimina ausencia

Flujo de Estados

draft -> submitted -> approved
                   -> rejected
draft/submitted/approved -> cancelled

Reglas de Negocio

  • Se calcula automaticamente el numero de dias
  • No se permiten ausencias solapadas
  • Se respeta el maximo de dias por tipo
  • Al aprobar, se actualiza el estado del empleado si corresponde

5. SkillsService

Archivo: skills.service.ts

Metodos - Tipos de Habilidad

Metodo Parametros Retorno Descripcion
findAllSkillTypes tenantId: string, filters: SkillTypeFilters Promise<{ data: SkillType[]; total: number; page: number; limit: number }> Lista tipos
findSkillTypeById id: string, tenantId: string Promise<SkillType | null> Obtiene tipo por ID
createSkillType tenantId: string, dto: CreateSkillTypeDto Promise<SkillType> Crea tipo
updateSkillType id: string, tenantId: string, dto: UpdateSkillTypeDto Promise<SkillType | null> Actualiza tipo
deleteSkillType id: string, tenantId: string Promise<boolean> Elimina tipo

Metodos - Habilidades

Metodo Parametros Retorno Descripcion
findAllSkills tenantId: string, filters: SkillFilters Promise<{ data: Skill[]; total: number; page: number; limit: number }> Lista habilidades
findSkillById id: string, tenantId: string Promise<Skill | null> Obtiene habilidad por ID
createSkill tenantId: string, dto: CreateSkillDto Promise<Skill> Crea habilidad
updateSkill id: string, tenantId: string, dto: UpdateSkillDto Promise<Skill | null> Actualiza habilidad
deleteSkill id: string, tenantId: string Promise<boolean> Elimina habilidad

Metodos - Niveles de Habilidad

Metodo Parametros Retorno Descripcion
findAllSkillLevels tenantId: string, filters: SkillLevelFilters Promise<{ data: SkillLevel[]; total: number; page: number; limit: number }> Lista niveles
findSkillLevelById id: string, tenantId: string Promise<SkillLevel | null> Obtiene nivel por ID
createSkillLevel tenantId: string, dto: CreateSkillLevelDto Promise<SkillLevel> Crea nivel
updateSkillLevel id: string, tenantId: string, dto: UpdateSkillLevelDto Promise<SkillLevel | null> Actualiza nivel
deleteSkillLevel id: string, tenantId: string Promise<boolean> Elimina nivel

Metodos - Habilidades de Empleado

Metodo Parametros Retorno Descripcion
findAllEmployeeSkills tenantId: string, filters: EmployeeSkillFilters Promise<{ data: EmployeeSkill[]; total: number; page: number; limit: number }> Lista habilidades de empleados
findEmployeeSkillById id: string, tenantId: string Promise<EmployeeSkill | null> Obtiene por ID
createEmployeeSkill tenantId: string, dto: CreateEmployeeSkillDto Promise<EmployeeSkill> Asigna habilidad
updateEmployeeSkill id: string, tenantId: string, dto: UpdateEmployeeSkillDto Promise<EmployeeSkill | null> Actualiza asignacion
deleteEmployeeSkill id: string, tenantId: string Promise<boolean> Elimina asignacion
getSkillsByEmployee employeeId: string, tenantId: string Promise<EmployeeSkill[]> Obtiene habilidades de un empleado

6. ExpensesService

Archivo: expenses.service.ts

Metodos - Hojas de Gastos

Metodo Parametros Retorno Descripcion
findAllSheets tenantId: string, filters: ExpenseSheetFilters Promise<{ data: ExpenseSheet[]; total: number; page: number; limit: number }> Lista hojas
findSheetById id: string, tenantId: string Promise<ExpenseSheet | null> Obtiene hoja por ID
createSheet tenantId: string, dto: CreateExpenseSheetDto, userId?: string Promise<ExpenseSheet> Crea hoja
updateSheet id: string, tenantId: string, dto: UpdateExpenseSheetDto Promise<ExpenseSheet | null> Actualiza hoja
submitSheet id: string, tenantId: string Promise<ExpenseSheet | null> Envia hoja
approveSheet id: string, tenantId: string, approvedBy: string Promise<ExpenseSheet | null> Aprueba hoja
rejectSheet id: string, tenantId: string Promise<ExpenseSheet | null> Rechaza hoja
deleteSheet id: string, tenantId: string Promise<boolean> Elimina hoja

Metodos - Gastos

Metodo Parametros Retorno Descripcion
findAllExpenses tenantId: string, filters: ExpenseFilters Promise<{ data: Expense[]; total: number; page: number; limit: number }> Lista gastos
findExpenseById id: string, tenantId: string Promise<Expense | null> Obtiene gasto por ID
createExpense tenantId: string, dto: CreateExpenseDto, userId?: string Promise<Expense> Crea gasto
updateExpense id: string, tenantId: string, dto: UpdateExpenseDto Promise<Expense | null> Actualiza gasto
deleteExpense id: string, tenantId: string Promise<boolean> Elimina gasto
recalculateSheetTotals sheetId: string, tenantId: string Promise<void> Recalcula totales

Flujo de Estados

draft -> submitted -> approved -> posted -> paid
                   -> rejected

Reglas de Negocio

  • Solo se pueden modificar/eliminar gastos en draft
  • total_amount se calcula como unit_amount * quantity
  • Los totales de la hoja se recalculan automaticamente

7. PayslipsService

Archivo: payslips.service.ts

Metodos - Estructuras de Nomina

Metodo Parametros Retorno Descripcion
findAllStructures tenantId: string, filters: PayslipStructureFilters Promise<{ data: PayslipStructure[]; total: number; page: number; limit: number }> Lista estructuras
findStructureById id: string, tenantId: string Promise<PayslipStructure | null> Obtiene estructura por ID
createStructure tenantId: string, dto: CreatePayslipStructureDto Promise<PayslipStructure> Crea estructura
updateStructure id: string, tenantId: string, dto: UpdatePayslipStructureDto Promise<PayslipStructure | null> Actualiza estructura
deleteStructure id: string, tenantId: string Promise<boolean> Elimina estructura

Metodos - Nominas

Metodo Parametros Retorno Descripcion
findAllPayslips tenantId: string, filters: PayslipFilters Promise<{ data: Payslip[]; total: number; page: number; limit: number }> Lista nominas
findPayslipById id: string, tenantId: string Promise<Payslip | null> Obtiene nomina por ID
createPayslip tenantId: string, dto: CreatePayslipDto, userId?: string Promise<Payslip> Crea nomina
updatePayslip id: string, tenantId: string, dto: UpdatePayslipDto Promise<Payslip | null> Actualiza nomina
verifyPayslip id: string, tenantId: string Promise<Payslip | null> Verifica nomina
confirmPayslip id: string, tenantId: string Promise<Payslip | null> Confirma nomina
cancelPayslip id: string, tenantId: string Promise<Payslip | null> Cancela nomina
deletePayslip id: string, tenantId: string Promise<boolean> Elimina nomina

Metodos - Lineas de Nomina

Metodo Parametros Retorno Descripcion
getPayslipLines payslipId: string, tenantId: string Promise<PayslipLine[]> Obtiene lineas
addPayslipLine payslipId: string, tenantId: string, dto: CreatePayslipLineDto Promise<PayslipLine | null> Agrega linea
updatePayslipLine payslipId: string, lineId: string, tenantId: string, dto: UpdatePayslipLineDto Promise<PayslipLine | null> Actualiza linea
removePayslipLine payslipId: string, lineId: string, tenantId: string Promise<boolean> Elimina linea

Flujo de Estados

draft -> verify -> done
draft/verify -> cancel

Reglas de Negocio

  • Solo se pueden modificar nominas en draft
  • Solo se pueden eliminar nominas en draft o cancel
  • Los totales se recalculan al modificar lineas
  • El numero de nomina se genera al confirmar

ENTIDADES

Employee

interface Employee {
  id: string;
  tenant_id: string;
  company_id: string;
  company_name?: string;
  employee_number: string;
  first_name: string;
  last_name: string;
  middle_name?: string;
  full_name?: string;
  user_id?: string;
  birth_date?: Date;
  gender?: string;
  marital_status?: string;
  nationality?: string;
  identification_id?: string;
  identification_type?: string;
  social_security_number?: string;
  tax_id?: string;
  email?: string;
  work_email?: string;
  phone?: string;
  work_phone?: string;
  mobile?: string;
  emergency_contact?: string;
  emergency_phone?: string;
  street?: string;
  city?: string;
  state?: string;
  zip?: string;
  country?: string;
  department_id?: string;
  department_name?: string;
  job_position_id?: string;
  job_position_name?: string;
  manager_id?: string;
  manager_name?: string;
  hire_date: Date;
  termination_date?: Date;
  status: EmployeeStatus;
  bank_name?: string;
  bank_account?: string;
  bank_clabe?: string;
  photo_url?: string;
  notes?: string;
  created_at: Date;
}

type EmployeeStatus = 'active' | 'inactive' | 'on_leave' | 'terminated';

Department

interface Department {
  id: string;
  tenant_id: string;
  company_id: string;
  company_name?: string;
  name: string;
  code?: string;
  parent_id?: string;
  parent_name?: string;
  manager_id?: string;
  manager_name?: string;
  description?: string;
  color?: string;
  active: boolean;
  employee_count?: number;
  created_at: Date;
}

JobPosition

interface JobPosition {
  id: string;
  tenant_id: string;
  name: string;
  department_id?: string;
  department_name?: string;
  description?: string;
  requirements?: string;
  responsibilities?: string;
  min_salary?: number;
  max_salary?: number;
  active: boolean;
  employee_count?: number;
  created_at: Date;
}

Contract

interface Contract {
  id: string;
  tenant_id: string;
  company_id: string;
  company_name?: string;
  employee_id: string;
  employee_name?: string;
  employee_number?: string;
  name: string;
  reference?: string;
  contract_type: ContractType;
  status: ContractStatus;
  job_position_id?: string;
  job_position_name?: string;
  department_id?: string;
  department_name?: string;
  date_start: Date;
  date_end?: Date;
  trial_date_end?: Date;
  wage: number;
  wage_type: string;
  currency_id?: string;
  currency_code?: string;
  hours_per_week: number;
  vacation_days: number;
  christmas_bonus_days: number;
  document_url?: string;
  notes?: string;
  created_at: Date;
}

type ContractStatus = 'draft' | 'active' | 'expired' | 'terminated' | 'cancelled';
type ContractType = 'permanent' | 'temporary' | 'contractor' | 'internship' | 'part_time';

Leave

interface Leave {
  id: string;
  tenant_id: string;
  company_id: string;
  company_name?: string;
  employee_id: string;
  employee_name?: string;
  employee_number?: string;
  leave_type_id: string;
  leave_type_name?: string;
  name?: string;
  date_from: Date;
  date_to: Date;
  number_of_days: number;
  status: LeaveStatus;
  description?: string;
  approved_by?: string;
  approved_by_name?: string;
  approved_at?: Date;
  rejection_reason?: string;
  created_at: Date;
}

type LeaveStatus = 'draft' | 'submitted' | 'approved' | 'rejected' | 'cancelled';
type LeaveType = 'vacation' | 'sick' | 'personal' | 'maternity' | 'paternity' | 'bereavement' | 'unpaid' | 'other';

LeaveTypeConfig

interface LeaveTypeConfig {
  id: string;
  tenant_id: string;
  name: string;
  code?: string;
  leave_type: LeaveType;
  requires_approval: boolean;
  max_days?: number;
  is_paid: boolean;
  color?: string;
  active: boolean;
  created_at: Date;
}

Skill, SkillType, SkillLevel, EmployeeSkill

interface SkillType {
  id: string;
  tenant_id: string;
  name: string;
  skill_levels: string;
  created_at: Date;
}

interface Skill {
  id: string;
  tenant_id: string;
  skill_type_id: string;
  skill_type_name?: string;
  name: string;
  created_at: Date;
}

interface SkillLevel {
  id: string;
  tenant_id: string;
  skill_type_id: string;
  skill_type_name?: string;
  name: string;
  level: number;
  created_at: Date;
}

interface EmployeeSkill {
  id: string;
  employee_id: string;
  employee_name?: string;
  skill_id: string;
  skill_name?: string;
  skill_level_id?: string;
  skill_level_name?: string;
  skill_type_id?: string;
  skill_type_name?: string;
  created_at: Date;
}

ExpenseSheet, Expense

interface ExpenseSheet {
  id: string;
  tenant_id: string;
  company_id: string;
  employee_id: string;
  employee_name?: string;
  name: string;
  state: ExpenseStatus;
  total_amount: number;
  untaxed_amount: number;
  total_amount_taxes: number;
  journal_id?: string;
  account_move_id?: string;
  user_id?: string;
  user_name?: string;
  approved_by?: string;
  approved_by_name?: string;
  approved_date?: Date;
  accounting_date?: Date;
  created_at: Date;
  created_by?: string;
  updated_at?: Date;
}

interface Expense {
  id: string;
  tenant_id: string;
  company_id: string;
  employee_id: string;
  employee_name?: string;
  name: string;
  sheet_id?: string;
  sheet_name?: string;
  product_id?: string;
  product_name?: string;
  unit_amount: number;
  quantity: number;
  total_amount: number;
  untaxed_amount?: number;
  total_amount_taxes?: number;
  currency_id?: string;
  currency_code?: string;
  tax_ids?: string[];
  date: Date;
  description?: string;
  reference?: string;
  analytic_account_id?: string;
  analytic_account_name?: string;
  state: ExpenseStatus;
  payment_mode: string;
  created_at: Date;
  created_by?: string;
  updated_at?: Date;
}

type ExpenseStatus = 'draft' | 'submitted' | 'approved' | 'posted' | 'paid' | 'rejected';

Payslip, PayslipStructure, PayslipLine

interface PayslipStructure {
  id: string;
  tenant_id: string;
  name: string;
  code?: string;
  is_active: boolean;
  note?: string;
  created_at: Date;
}

interface Payslip {
  id: string;
  tenant_id: string;
  company_id: string;
  employee_id: string;
  employee_name?: string;
  employee_number?: string;
  contract_id?: string;
  contract_name?: string;
  name: string;
  number?: string;
  state: PayslipStatus;
  date_from: Date;
  date_to: Date;
  date?: Date;
  structure_id?: string;
  structure_name?: string;
  basic_wage?: number;
  gross_wage?: number;
  net_wage?: number;
  worked_days?: number;
  worked_hours?: number;
  journal_id?: string;
  move_id?: string;
  created_at: Date;
  created_by?: string;
  updated_at?: Date;
}

interface PayslipLine {
  id: string;
  payslip_id: string;
  name: string;
  code: string;
  sequence: number;
  category?: string;
  quantity: number;
  rate: number;
  amount: number;
  total: number;
  appears_on_payslip: boolean;
  created_at: Date;
}

type PayslipStatus = 'draft' | 'verify' | 'done' | 'cancel';

DTOs

Employees DTOs

interface CreateEmployeeDto {
  company_id: string;
  employee_number: string;
  first_name: string;
  last_name: string;
  middle_name?: string;
  user_id?: string;
  birth_date?: string;
  gender?: string;
  marital_status?: string;
  nationality?: string;
  identification_id?: string;
  identification_type?: string;
  social_security_number?: string;
  tax_id?: string;
  email?: string;
  work_email?: string;
  phone?: string;
  work_phone?: string;
  mobile?: string;
  emergency_contact?: string;
  emergency_phone?: string;
  street?: string;
  city?: string;
  state?: string;
  zip?: string;
  country?: string;
  department_id?: string;
  job_position_id?: string;
  manager_id?: string;
  hire_date: string;
  bank_name?: string;
  bank_account?: string;
  bank_clabe?: string;
  photo_url?: string;
  notes?: string;
}

interface UpdateEmployeeDto {
  first_name?: string;
  last_name?: string;
  middle_name?: string | null;
  user_id?: string | null;
  birth_date?: string | null;
  gender?: string | null;
  marital_status?: string | null;
  nationality?: string | null;
  identification_id?: string | null;
  identification_type?: string | null;
  social_security_number?: string | null;
  tax_id?: string | null;
  email?: string | null;
  work_email?: string | null;
  phone?: string | null;
  work_phone?: string | null;
  mobile?: string | null;
  emergency_contact?: string | null;
  emergency_phone?: string | null;
  street?: string | null;
  city?: string | null;
  state?: string | null;
  zip?: string | null;
  country?: string | null;
  department_id?: string | null;
  job_position_id?: string | null;
  manager_id?: string | null;
  bank_name?: string | null;
  bank_account?: string | null;
  bank_clabe?: string | null;
  photo_url?: string | null;
  notes?: string | null;
}

interface EmployeeFilters {
  company_id?: string;
  department_id?: string;
  status?: EmployeeStatus;
  manager_id?: string;
  search?: string;
  page?: number;
  limit?: number;
}

Departments DTOs

interface CreateDepartmentDto {
  company_id: string;
  name: string;
  code?: string;
  parent_id?: string;
  manager_id?: string;
  description?: string;
  color?: string;
}

interface UpdateDepartmentDto {
  name?: string;
  code?: string | null;
  parent_id?: string | null;
  manager_id?: string | null;
  description?: string | null;
  color?: string | null;
  active?: boolean;
}

interface DepartmentFilters {
  company_id?: string;
  active?: boolean;
  search?: string;
  page?: number;
  limit?: number;
}

interface CreateJobPositionDto {
  name: string;
  department_id?: string;
  description?: string;
  requirements?: string;
  responsibilities?: string;
  min_salary?: number;
  max_salary?: number;
}

interface UpdateJobPositionDto {
  name?: string;
  department_id?: string | null;
  description?: string | null;
  requirements?: string | null;
  responsibilities?: string | null;
  min_salary?: number | null;
  max_salary?: number | null;
  active?: boolean;
}

Contracts DTOs

interface CreateContractDto {
  company_id: string;
  employee_id: string;
  name: string;
  reference?: string;
  contract_type: ContractType;
  job_position_id?: string;
  department_id?: string;
  date_start: string;
  date_end?: string;
  trial_date_end?: string;
  wage: number;
  wage_type?: string;
  currency_id?: string;
  hours_per_week?: number;
  vacation_days?: number;
  christmas_bonus_days?: number;
  document_url?: string;
  notes?: string;
}

interface UpdateContractDto {
  reference?: string | null;
  job_position_id?: string | null;
  department_id?: string | null;
  date_end?: string | null;
  trial_date_end?: string | null;
  wage?: number;
  wage_type?: string;
  currency_id?: string | null;
  hours_per_week?: number;
  vacation_days?: number;
  christmas_bonus_days?: number;
  document_url?: string | null;
  notes?: string | null;
}

interface ContractFilters {
  company_id?: string;
  employee_id?: string;
  status?: ContractStatus;
  contract_type?: ContractType;
  search?: string;
  page?: number;
  limit?: number;
}

Leaves DTOs

interface CreateLeaveTypeDto {
  name: string;
  code?: string;
  leave_type: LeaveType;
  requires_approval?: boolean;
  max_days?: number;
  is_paid?: boolean;
  color?: string;
}

interface UpdateLeaveTypeDto {
  name?: string;
  code?: string | null;
  requires_approval?: boolean;
  max_days?: number | null;
  is_paid?: boolean;
  color?: string | null;
  active?: boolean;
}

interface CreateLeaveDto {
  company_id: string;
  employee_id: string;
  leave_type_id: string;
  name?: string;
  date_from: string;
  date_to: string;
  description?: string;
}

interface UpdateLeaveDto {
  leave_type_id?: string;
  name?: string | null;
  date_from?: string;
  date_to?: string;
  description?: string | null;
}

interface LeaveFilters {
  company_id?: string;
  employee_id?: string;
  leave_type_id?: string;
  status?: LeaveStatus;
  date_from?: string;
  date_to?: string;
  search?: string;
  page?: number;
  limit?: number;
}

Skills DTOs

interface CreateSkillTypeDto {
  name: string;
  skill_levels?: string;
}

interface UpdateSkillTypeDto {
  name?: string;
  skill_levels?: string;
}

interface CreateSkillDto {
  skill_type_id: string;
  name: string;
}

interface UpdateSkillDto {
  name?: string;
  skill_type_id?: string;
}

interface CreateSkillLevelDto {
  skill_type_id: string;
  name: string;
  level: number;
}

interface UpdateSkillLevelDto {
  name?: string;
  level?: number;
}

interface CreateEmployeeSkillDto {
  employee_id: string;
  skill_id: string;
  skill_level_id?: string;
  skill_type_id?: string;
}

interface UpdateEmployeeSkillDto {
  skill_level_id?: string | null;
  skill_type_id?: string | null;
}

Expenses DTOs

interface CreateExpenseSheetDto {
  company_id: string;
  employee_id: string;
  name: string;
  user_id?: string;
  accounting_date?: string;
}

interface UpdateExpenseSheetDto {
  name?: string;
  user_id?: string | null;
  accounting_date?: string | null;
}

interface CreateExpenseDto {
  company_id: string;
  employee_id: string;
  name: string;
  sheet_id?: string;
  product_id?: string;
  unit_amount: number;
  quantity?: number;
  currency_id?: string;
  tax_ids?: string[];
  date?: string;
  description?: string;
  reference?: string;
  analytic_account_id?: string;
  payment_mode?: string;
}

interface UpdateExpenseDto {
  name?: string;
  sheet_id?: string | null;
  product_id?: string | null;
  unit_amount?: number;
  quantity?: number;
  currency_id?: string | null;
  tax_ids?: string[];
  date?: string;
  description?: string | null;
  reference?: string | null;
  analytic_account_id?: string | null;
  payment_mode?: string;
}

interface ExpenseSheetFilters {
  company_id?: string;
  employee_id?: string;
  state?: ExpenseStatus;
  date_from?: string;
  date_to?: string;
  search?: string;
  page?: number;
  limit?: number;
}

interface ExpenseFilters {
  company_id?: string;
  employee_id?: string;
  sheet_id?: string;
  state?: ExpenseStatus;
  date_from?: string;
  date_to?: string;
  search?: string;
  page?: number;
  limit?: number;
}

Payslips DTOs

interface CreatePayslipStructureDto {
  name: string;
  code?: string;
  is_active?: boolean;
  note?: string;
}

interface UpdatePayslipStructureDto {
  name?: string;
  code?: string | null;
  is_active?: boolean;
  note?: string | null;
}

interface CreatePayslipDto {
  company_id: string;
  employee_id: string;
  contract_id?: string;
  name: string;
  date_from: string;
  date_to: string;
  date?: string;
  structure_id?: string;
  basic_wage?: number;
  worked_days?: number;
  worked_hours?: number;
}

interface UpdatePayslipDto {
  name?: string;
  date?: string | null;
  structure_id?: string | null;
  basic_wage?: number;
  gross_wage?: number;
  net_wage?: number;
  worked_days?: number;
  worked_hours?: number;
}

interface CreatePayslipLineDto {
  name: string;
  code: string;
  sequence?: number;
  category?: string;
  quantity?: number;
  rate?: number;
  amount: number;
  appears_on_payslip?: boolean;
}

interface UpdatePayslipLineDto {
  name?: string;
  code?: string;
  sequence?: number;
  category?: string;
  quantity?: number;
  rate?: number;
  amount?: number;
  appears_on_payslip?: boolean;
}

interface PayslipStructureFilters {
  is_active?: boolean;
  search?: string;
  page?: number;
  limit?: number;
}

interface PayslipFilters {
  company_id?: string;
  employee_id?: string;
  contract_id?: string;
  structure_id?: string;
  state?: PayslipStatus;
  date_from?: string;
  date_to?: string;
  search?: string;
  page?: number;
  limit?: number;
}

ENDPOINTS

Employees

Metodo Ruta Descripcion
GET /api/hr/employees Listar empleados
GET /api/hr/employees/:id Obtener empleado
POST /api/hr/employees Crear empleado
PUT /api/hr/employees/:id Actualizar empleado
DELETE /api/hr/employees/:id Eliminar empleado
POST /api/hr/employees/:id/terminate Dar de baja
POST /api/hr/employees/:id/reactivate Reactivar
GET /api/hr/employees/:id/subordinates Obtener subordinados

Departments

Metodo Ruta Descripcion
GET /api/hr/departments Listar departamentos
GET /api/hr/departments/:id Obtener departamento
POST /api/hr/departments Crear departamento
PUT /api/hr/departments/:id Actualizar departamento
DELETE /api/hr/departments/:id Eliminar departamento

Job Positions

Metodo Ruta Descripcion
GET /api/hr/job-positions Listar puestos
GET /api/hr/job-positions/:id Obtener puesto
POST /api/hr/job-positions Crear puesto
PUT /api/hr/job-positions/:id Actualizar puesto
DELETE /api/hr/job-positions/:id Eliminar puesto

Contracts

Metodo Ruta Descripcion
GET /api/hr/contracts Listar contratos
GET /api/hr/contracts/:id Obtener contrato
POST /api/hr/contracts Crear contrato
PUT /api/hr/contracts/:id Actualizar contrato
DELETE /api/hr/contracts/:id Eliminar contrato
POST /api/hr/contracts/:id/activate Activar contrato
POST /api/hr/contracts/:id/terminate Terminar contrato
POST /api/hr/contracts/:id/cancel Cancelar contrato

Leaves

Metodo Ruta Descripcion
GET /api/hr/leave-types Listar tipos de ausencia
GET /api/hr/leave-types/:id Obtener tipo
POST /api/hr/leave-types Crear tipo
PUT /api/hr/leave-types/:id Actualizar tipo
DELETE /api/hr/leave-types/:id Eliminar tipo
GET /api/hr/leaves Listar ausencias
GET /api/hr/leaves/:id Obtener ausencia
POST /api/hr/leaves Crear ausencia
PUT /api/hr/leaves/:id Actualizar ausencia
DELETE /api/hr/leaves/:id Eliminar ausencia
POST /api/hr/leaves/:id/submit Enviar solicitud
POST /api/hr/leaves/:id/approve Aprobar solicitud
POST /api/hr/leaves/:id/reject Rechazar solicitud
POST /api/hr/leaves/:id/cancel Cancelar solicitud

Skills

Metodo Ruta Descripcion
GET /api/hr/skill-types Listar tipos de habilidad
GET /api/hr/skill-types/:id Obtener tipo
POST /api/hr/skill-types Crear tipo
PUT /api/hr/skill-types/:id Actualizar tipo
DELETE /api/hr/skill-types/:id Eliminar tipo
GET /api/hr/skills Listar habilidades
GET /api/hr/skills/:id Obtener habilidad
POST /api/hr/skills Crear habilidad
PUT /api/hr/skills/:id Actualizar habilidad
DELETE /api/hr/skills/:id Eliminar habilidad
GET /api/hr/skill-levels Listar niveles
GET /api/hr/skill-levels/:id Obtener nivel
POST /api/hr/skill-levels Crear nivel
PUT /api/hr/skill-levels/:id Actualizar nivel
DELETE /api/hr/skill-levels/:id Eliminar nivel
GET /api/hr/employee-skills Listar habilidades de empleados
GET /api/hr/employee-skills/:id Obtener asignacion
POST /api/hr/employee-skills Asignar habilidad
PUT /api/hr/employee-skills/:id Actualizar asignacion
DELETE /api/hr/employee-skills/:id Eliminar asignacion
GET /api/hr/employees/:id/skills Habilidades de empleado

Expenses

Metodo Ruta Descripcion
GET /api/hr/expense-sheets Listar hojas de gastos
GET /api/hr/expense-sheets/:id Obtener hoja
POST /api/hr/expense-sheets Crear hoja
PUT /api/hr/expense-sheets/:id Actualizar hoja
DELETE /api/hr/expense-sheets/:id Eliminar hoja
POST /api/hr/expense-sheets/:id/submit Enviar hoja
POST /api/hr/expense-sheets/:id/approve Aprobar hoja
POST /api/hr/expense-sheets/:id/reject Rechazar hoja
GET /api/hr/expenses Listar gastos
GET /api/hr/expenses/:id Obtener gasto
POST /api/hr/expenses Crear gasto
PUT /api/hr/expenses/:id Actualizar gasto
DELETE /api/hr/expenses/:id Eliminar gasto

Payslips

Metodo Ruta Descripcion
GET /api/hr/payslip-structures Listar estructuras
GET /api/hr/payslip-structures/:id Obtener estructura
POST /api/hr/payslip-structures Crear estructura
PUT /api/hr/payslip-structures/:id Actualizar estructura
DELETE /api/hr/payslip-structures/:id Eliminar estructura
GET /api/hr/payslips Listar nominas
GET /api/hr/payslips/:id Obtener nomina
POST /api/hr/payslips Crear nomina
PUT /api/hr/payslips/:id Actualizar nomina
DELETE /api/hr/payslips/:id Eliminar nomina
POST /api/hr/payslips/:id/verify Verificar nomina
POST /api/hr/payslips/:id/confirm Confirmar nomina
POST /api/hr/payslips/:id/cancel Cancelar nomina
GET /api/hr/payslips/:id/lines Obtener lineas
POST /api/hr/payslips/:id/lines Agregar linea
PUT /api/hr/payslips/:id/lines/:lineId Actualizar linea
DELETE /api/hr/payslips/:id/lines/:lineId Eliminar linea

TESTS

Ubicacion de Tests

backend/src/modules/hr/__tests__/
  employees.test.ts
  departments.test.ts
  contracts.test.ts
  leaves.test.ts
  skills.test.ts
  expenses.test.ts
  payslips.test.ts

Casos de Prueba Requeridos

EmployeesService

  • Crear empleado con datos validos
  • Error al crear empleado con numero duplicado
  • Obtener empleado existente
  • Error al obtener empleado inexistente
  • Listar empleados con filtros
  • Actualizar empleado
  • Dar de baja empleado
  • Error al dar de baja empleado ya dado de baja
  • Reactivar empleado
  • Error al eliminar empleado con contratos
  • Error al eliminar empleado que es manager
  • Obtener subordinados

DepartmentsService

  • Crear departamento
  • Error al crear departamento con nombre duplicado
  • Listar departamentos
  • Actualizar departamento
  • Error al eliminar departamento con empleados
  • Error al eliminar departamento con subdepartamentos
  • CRUD de puestos de trabajo

ContractsService

  • Crear contrato
  • Error al crear contrato con empleado que ya tiene uno activo
  • Activar contrato
  • Terminar contrato
  • Cancelar contrato
  • Error al editar contrato no borrador

LeavesService

  • Crear tipo de ausencia
  • Crear solicitud de ausencia
  • Validar dias maximos por tipo
  • Error al crear ausencia solapada
  • Flujo completo: draft -> submitted -> approved
  • Rechazar solicitud con razon
  • Cancelar solicitud

SkillsService

  • CRUD de tipos de habilidad
  • CRUD de habilidades
  • CRUD de niveles
  • Asignar habilidad a empleado
  • Obtener habilidades de empleado

ExpensesService

  • Crear hoja de gastos
  • Agregar gastos a hoja
  • Recalculo automatico de totales
  • Flujo de aprobacion
  • Error al modificar gasto no borrador

PayslipsService

  • Crear estructura de nomina
  • Crear nomina
  • Agregar lineas a nomina
  • Recalculo de gross/net
  • Flujo: draft -> verify -> done
  • Cancelar nomina
  • Error al modificar nomina confirmada

DEPENDENCIAS

Internas

Modulo Descripcion
auth Empresas y usuarios
core Monedas
inventory Productos (para gastos)
analytics Cuentas analiticas

Tablas Referenciadas

  • auth.companies - Empresa del empleado/contrato
  • auth.users - Usuario asociado al empleado
  • core.currencies - Moneda del contrato/gasto
  • inventory.products - Producto del gasto
  • analytics.analytic_accounts - Cuenta analitica

Externas

{
  "pg": "Base de datos PostgreSQL"
}

ERRORES COMUNES

Codigo Mensaje Causa
NOT_FOUND Empleado no encontrado ID invalido o no pertenece al tenant
CONFLICT Ya existe un empleado con ese numero employee_number duplicado
CONFLICT No se puede eliminar un empleado con contratos Tiene contratos asociados
CONFLICT No se puede eliminar un empleado que es manager Es manager de otros empleados
VALIDATION El empleado ya tiene un contrato activo Intento de crear segundo contrato activo
VALIDATION Solo se pueden editar contratos en estado borrador Contrato no esta en draft
VALIDATION Ya existe una solicitud de ausencia para estas fechas Ausencias solapadas
VALIDATION Este tipo de ausencia tiene un maximo de X dias Excede dias permitidos
VALIDATION Solo se pueden modificar gastos en estado borrador Gasto no esta en draft
VALIDATION Solo se pueden modificar nominas en estado borrador Nomina no esta en draft

CHANGELOG

Version Fecha Cambios
1.0.0 2026-01-10 Especificacion inicial con 7 servicios