426 lines
11 KiB
Markdown
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)
|