erp-core/docs/04-modelado/domain-models/hr-domain.md

426 lines
11 KiB
Markdown

# MODELO DE DOMINIO: RRHH
**Módulos:** MGN-010 (RRHH Básico)
**Fecha:** 2025-11-24
**Referencia Odoo:** hr, hr_attendance, hr_holidays
**Referencia Gamilit:** hr_management schema
---
## Diagrama de Entidades (Texto UML)
```
[Employee]
- id: UUID (PK)
- tenant_id: UUID (FK)
- company_id: UUID (FK)
- user_id: UUID (FK)
- partner_id: UUID (FK)
- full_name: String
- employee_number: String
- job_id: UUID (FK)
- department_id: UUID (FK)
- manager_id: UUID (FK self)
- work_email: String
- work_phone: String
- hire_date: Date
- status: ENUM (active, inactive)
1 <----> * [Contract]
1 <----> * [Attendance]
1 <----> * [Leave]
1 <----> * [Timesheet]
[Department]
- id: UUID (PK)
- tenant_id: UUID (FK)
- company_id: UUID (FK)
- name: String
- parent_id: UUID (FK self)
- manager_id: UUID (FK employee)
1 <----> * [Employee]
[Job]
- id: UUID (PK)
- tenant_id: UUID (FK)
- company_id: UUID (FK)
- name: String
- description: Text
- department_id: UUID (FK)
1 <----> * [Employee]
[Contract]
- id: UUID (PK)
- tenant_id: UUID (FK)
- employee_id: UUID (FK)
- name: String
- contract_type: ENUM (permanent, temporary, contractor)
- job_id: UUID (FK)
- wage: Decimal
- date_start: Date
- date_end: Date
- status: ENUM (draft, running, expired, cancelled)
[Attendance]
- id: UUID (PK)
- tenant_id: UUID (FK)
- employee_id: UUID (FK)
- check_in: Timestamp
- check_out: Timestamp
- worked_hours: Decimal
[LeaveType]
- id: UUID (PK)
- tenant_id: UUID (FK)
- company_id: UUID (FK)
- name: String
- code: String
- allocation_type: ENUM (fixed, accrual, unlimited)
- requires_approval: Boolean
1 <----> * [LeaveAllocation]
1 <----> * [Leave]
[LeaveAllocation]
- id: UUID (PK)
- employee_id: UUID (FK)
- leave_type_id: UUID (FK)
- days_allocated: Decimal
- date_from: Date
- date_to: Date
[Leave]
- id: UUID (PK)
- tenant_id: UUID (FK)
- employee_id: UUID (FK)
- leave_type_id: UUID (FK)
- date_from: Date
- date_to: Date
- days_requested: Decimal
- status: ENUM (draft, pending_approval, approved, refused, cancelled)
- approver_id: UUID (FK user)
[Timesheet]
- id: UUID (PK)
- tenant_id: UUID (FK)
- employee_id: UUID (FK)
- date: Date
- hours: Decimal
- analytic_account_id: UUID (FK)
- task_id: UUID (FK)
- description: String
- status: ENUM (draft, approved)
```
## Entidades Principales
### 1. Employee (Empleado)
**Descripción:** Empleado de la empresa.
**Atributos:**
- `id`: UUID
- `user_id`: Usuario asociado (opcional)
- `partner_id`: Partner asociado
- `full_name`: Nombre completo
- `employee_number`: Número de empleado
- `job_id`: Puesto
- `department_id`: Departamento
- `manager_id`: Jefe directo
- `work_email`: Email laboral
- `work_phone`: Teléfono laboral
- `hire_date`: Fecha de ingreso
- `status`: active, inactive
**Relaciones:**
- 1 Employee → 1 User (opcional)
- 1 Employee → 1 Partner
- N Employees → 1 Department
- N Employees → 1 Job
- N Employees → 1 Manager (self-reference)
**Patrón Odoo:** hr.employee
**Nota:** Un empleado puede o no tener user_id (acceso al sistema)
### 2. Department (Departamento)
**Descripción:** Departamento organizacional.
**Atributos:**
- `id`: UUID
- `name`: Nombre
- `parent_id`: Departamento padre (jerarquía)
- `manager_id`: Jefe de departamento
**Relaciones:**
- 1 Department → N Employees
- 1 Department → N Subdepartments
**Patrón Odoo:** hr.department
**Jerarquía típica:**
- Dirección General
- Administración
- Finanzas
- RRHH
- Operaciones
- Producción
- Logística
### 3. Job (Puesto)
**Descripción:** Puesto de trabajo.
**Atributos:**
- `id`: UUID
- `name`: Nombre (ej: "Gerente de Ventas")
- `description`: Descripción del puesto
- `department_id`: Departamento
**Relaciones:**
- N Jobs → 1 Department
- 1 Job → N Employees
**Patrón Odoo:** hr.job
### 4. Contract (Contrato Laboral)
**Descripción:** Contrato de trabajo del empleado.
**Atributos:**
- `id`: UUID
- `employee_id`: Empleado
- `name`: Nombre del contrato
- `contract_type`: permanent, temporary, contractor
- `job_id`: Puesto contratado
- `wage`: Salario
- `date_start`: Fecha de inicio
- `date_end`: Fecha de fin (opcional)
- `status`: draft, running, expired, cancelled
**Relaciones:**
- N Contracts → 1 Employee
- N Contracts → 1 Job
**Patrón Odoo:** hr.contract
**Estados:**
- draft: Borrador
- running: Activo (date_start <= HOY <= date_end)
- expired: Expirado (date_end < HOY)
- cancelled: Cancelado
### 5. Attendance (Asistencia)
**Descripción:** Registro de entrada/salida de empleado.
**Atributos:**
- `id`: UUID
- `employee_id`: Empleado
- `check_in`: Hora de entrada
- `check_out`: Hora de salida
- `worked_hours`: Horas trabajadas (calculado)
**Relaciones:**
- N Attendances 1 Employee
**Patrón Odoo:** hr.attendance
**Cálculo:** worked_hours = check_out - check_in (en horas)
### 6. LeaveType (Tipo de Ausencia)
**Descripción:** Tipo de ausencia/permiso.
**Atributos:**
- `id`: UUID
- `name`: Nombre (ej: "Vacaciones", "Incapacidad")
- `code`: Código
- `allocation_type`: fixed, accrual, unlimited
- `requires_approval`: Requiere aprobación
**Relaciones:**
- 1 LeaveType N Leaves
- 1 LeaveType N LeaveAllocations
**Patrón Odoo:** hr.leave.type
**Tipos comunes:**
- Vacaciones (fixed: X días al año)
- Incapacidad (unlimited)
- Permiso sin goce (requires_approval)
- Permiso con goce (requires_approval)
### 7. LeaveAllocation (Asignación de Ausencias)
**Descripción:** Días de ausencia asignados a empleado.
**Atributos:**
- `id`: UUID
- `employee_id`: Empleado
- `leave_type_id`: Tipo de ausencia
- `days_allocated`: Días asignados
- `date_from`: Fecha inicio de vigencia
- `date_to`: Fecha fin de vigencia
**Relaciones:**
- N LeaveAllocations 1 Employee
- N LeaveAllocations 1 LeaveType
**Patrón Odoo:** hr.leave.allocation
**Ejemplo:** 15 días de vacaciones por año
### 8. Leave (Ausencia/Permiso)
**Descripción:** Solicitud de ausencia de empleado.
**Atributos:**
- `id`: UUID
- `employee_id`: Empleado
- `leave_type_id`: Tipo de ausencia
- `date_from`: Fecha inicio
- `date_to`: Fecha fin
- `days_requested`: Días solicitados
- `status`: draft, pending_approval, approved, refused, cancelled
- `approver_id`: Usuario que aprobó
**Relaciones:**
- N Leaves 1 Employee
- N Leaves 1 LeaveType
**Patrón Odoo:** hr.leave
**Flujo:**
1. Empleado crea solicitud (draft)
2. Empleado envía a aprobación (pending_approval)
3. Manager aprueba/rechaza (approved/refused)
### 9. Timesheet (Hoja de Horas)
**Descripción:** Registro de horas trabajadas por proyecto/tarea.
**Atributos:**
- `id`: UUID
- `employee_id`: Empleado
- `date`: Fecha
- `hours`: Horas trabajadas
- `analytic_account_id`: Cuenta analítica (proyecto)
- `task_id`: Tarea (opcional)
- `description`: Descripción
- `status`: draft, approved
**Relaciones:**
- N Timesheets 1 Employee
- N Timesheets 1 AnalyticAccount (MGN-008)
- N Timesheets 1 Task (MGN-011)
**Patrón Odoo:** account.analytic.line (tipo=timesheet)
**Integración:** Genera líneas analíticas en MGN-008
## Reglas de Negocio
### RN-HR-001: Un Empleado = Un Partner
- Todo empleado tiene partner_id (is_employee=true)
- Partner tiene datos personales: dirección, contactos, etc.
### RN-HR-002: Contrato Activo
- Empleado puede tener múltiples contratos
- Solo un contrato puede estar 'running' simultáneamente
- Contrato 'running' si date_start <= HOY <= date_end
### RN-HR-003: Check-in/Check-out
- Check-out no puede ser anterior a check-in
- Un empleado no puede tener check-in sin check-out pendiente
- worked_hours calculado automáticamente
### RN-HR-004: Saldo de Vacaciones
- Saldo = LeaveAllocation.days_allocated - SUM(Leave.days_requested WHERE approved)
- No permitir Leave si saldo insuficiente (excepto tipos unlimited)
### RN-HR-005: Aprobación de Ausencias
- Manager puede aprobar ausencias de su equipo
- RRHH puede aprobar todas las ausencias
- Empleado no puede aprobar sus propias ausencias
### RN-HR-006: Timesheet y Analítica
- Timesheet genera línea analítica en MGN-008
- Tipo de línea: 'expense' (costo de mano de obra)
- Monto = hours * employee hourly rate
### RN-HR-007: Organigrama
- Estructura jerárquica: Employee.manager_id
- Visualización en árbol
- Manager puede ver timesheets/ausencias de su equipo
## Casos de Uso Principales
1. **UC-HR-001:** RRHH crea empleado
2. **UC-HR-002:** RRHH asigna empleado a departamento y puesto
3. **UC-HR-003:** RRHH crea contrato de trabajo
4. **UC-HR-004:** Empleado registra check-in (entrada)
5. **UC-HR-005:** Empleado registra check-out (salida)
6. **UC-HR-006:** Empleado solicita vacaciones
7. **UC-HR-007:** Manager aprueba/rechaza solicitud de vacaciones
8. **UC-HR-008:** Empleado registra timesheet diario
9. **UC-HR-009:** Manager valida timesheet de empleado
10. **UC-HR-010:** RRHH consulta reporte de asistencias
## Validaciones y Constraints
```sql
-- Employee number único por company
UNIQUE (tenant_id, company_id, employee_number)
-- Check-out después de check-in
CHECK (check_out > check_in)
-- Worked hours >= 0
CHECK (worked_hours >= 0)
-- Leave date_to >= date_from
CHECK (date_to >= date_from)
-- Days requested > 0
CHECK (days_requested > 0)
-- Timesheet hours > 0
CHECK (hours > 0)
-- Contrato date_end >= date_start
CHECK (date_end IS NULL OR date_end >= date_start)
-- Wage >= 0
CHECK (wage >= 0)
```
## Índices Requeridos
```sql
CREATE INDEX idx_employees_department_id ON hr.employees(department_id);
CREATE INDEX idx_employees_manager_id ON hr.employees(manager_id);
CREATE INDEX idx_employees_user_id ON hr.employees(user_id);
CREATE INDEX idx_employees_status ON hr.employees(status);
CREATE INDEX idx_contracts_employee_id ON hr.contracts(employee_id);
CREATE INDEX idx_contracts_status ON hr.contracts(status);
CREATE INDEX idx_attendances_employee_id ON hr.attendances(employee_id);
CREATE INDEX idx_attendances_check_in ON hr.attendances(check_in);
CREATE INDEX idx_leaves_employee_id ON hr.leaves(employee_id);
CREATE INDEX idx_leaves_status ON hr.leaves(status);
CREATE INDEX idx_timesheets_employee_id ON hr.timesheets(employee_id);
CREATE INDEX idx_timesheets_date ON hr.timesheets(date);
```
## Integración con Otros Módulos
### Con MGN-001 (Fundamentos)
- Employee.user_id User
- Empleado puede tener acceso al sistema
### Con MGN-003 (Catálogos)
- Employee.partner_id Partner (is_employee=true)
### Con MGN-008 (Analítica)
- Timesheet genera líneas analíticas
- Costo de mano de obra por proyecto
### Con MGN-011 (Proyectos)
- Timesheet.task_id Task
- Horas trabajadas por tarea
### Con MGN-014 (Mensajería)
- Notificaciones de ausencias aprobadas/rechazadas
- Recordatorios de timesheet pendiente
## Referencias
- [ALCANCE-POR-MODULO.md - MGN-010](../../01-definicion-modulos/ALCANCE-POR-MODULO.md#mgn-010)
- [ADR-007: Database Design](../../adr/ADR-007-database-design.md)
- [odoo-hr-analysis.md](../../00-analisis-referencias/odoo/odoo-hr-analysis.md)