# 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)