erp-core-database/ddl/12-hr.sql

380 lines
11 KiB
SQL

-- =====================================================
-- SCHEMA: hr
-- PROPOSITO: Human Resources Management
-- MODULOS: MGN-HR (Recursos Humanos)
-- FECHA: 2025-11-24
-- =====================================================
-- Crear schema
CREATE SCHEMA IF NOT EXISTS hr;
-- =====================================================
-- TYPES (ENUMs)
-- =====================================================
CREATE TYPE hr.contract_status AS ENUM (
'draft',
'active',
'expired',
'terminated',
'cancelled'
);
CREATE TYPE hr.contract_type AS ENUM (
'permanent',
'temporary',
'contractor',
'internship',
'part_time'
);
CREATE TYPE hr.leave_status AS ENUM (
'draft',
'submitted',
'approved',
'rejected',
'cancelled'
);
CREATE TYPE hr.leave_type AS ENUM (
'vacation',
'sick',
'personal',
'maternity',
'paternity',
'bereavement',
'unpaid',
'other'
);
CREATE TYPE hr.employee_status AS ENUM (
'active',
'inactive',
'on_leave',
'terminated'
);
-- =====================================================
-- TABLES
-- =====================================================
-- Tabla: departments (Departamentos)
CREATE TABLE hr.departments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
code VARCHAR(20),
parent_id UUID REFERENCES hr.departments(id),
manager_id UUID, -- References employees, set after table creation
description TEXT,
color VARCHAR(20),
active BOOLEAN DEFAULT TRUE,
created_by UUID REFERENCES auth.users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
UNIQUE(tenant_id, company_id, name)
);
-- Tabla: job_positions (Puestos de trabajo)
CREATE TABLE hr.job_positions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
department_id UUID REFERENCES hr.departments(id),
description TEXT,
requirements TEXT,
responsibilities TEXT,
min_salary DECIMAL(15, 2),
max_salary DECIMAL(15, 2),
active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
UNIQUE(tenant_id, name)
);
-- Tabla: employees (Empleados)
CREATE TABLE hr.employees (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
-- Identificacion
employee_number VARCHAR(50) NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
middle_name VARCHAR(100),
-- Usuario vinculado (opcional)
user_id UUID REFERENCES auth.users(id),
-- Informacion personal
birth_date DATE,
gender VARCHAR(20),
marital_status VARCHAR(20),
nationality VARCHAR(100),
identification_id VARCHAR(50),
identification_type VARCHAR(50),
social_security_number VARCHAR(50),
tax_id VARCHAR(50),
-- Contacto
email VARCHAR(255),
work_email VARCHAR(255),
phone VARCHAR(50),
work_phone VARCHAR(50),
mobile VARCHAR(50),
emergency_contact VARCHAR(255),
emergency_phone VARCHAR(50),
-- Direccion
street VARCHAR(255),
city VARCHAR(100),
state VARCHAR(100),
zip VARCHAR(20),
country VARCHAR(100),
-- Trabajo
department_id UUID REFERENCES hr.departments(id),
job_position_id UUID REFERENCES hr.job_positions(id),
manager_id UUID REFERENCES hr.employees(id),
hire_date DATE NOT NULL,
termination_date DATE,
status hr.employee_status NOT NULL DEFAULT 'active',
-- Datos bancarios
bank_name VARCHAR(100),
bank_account VARCHAR(50),
bank_clabe VARCHAR(20),
-- Foto
photo_url VARCHAR(500),
-- Notas
notes TEXT,
-- Auditoria
created_by UUID REFERENCES auth.users(id),
updated_by UUID REFERENCES auth.users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
UNIQUE(tenant_id, employee_number)
);
-- Add manager_id reference to departments
ALTER TABLE hr.departments ADD CONSTRAINT fk_departments_manager
FOREIGN KEY (manager_id) REFERENCES hr.employees(id);
-- Tabla: contracts (Contratos laborales)
CREATE TABLE hr.contracts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
employee_id UUID NOT NULL REFERENCES hr.employees(id) ON DELETE CASCADE,
-- Identificacion
name VARCHAR(100) NOT NULL,
reference VARCHAR(100),
-- Tipo y estado
contract_type hr.contract_type NOT NULL,
status hr.contract_status NOT NULL DEFAULT 'draft',
-- Puesto
job_position_id UUID REFERENCES hr.job_positions(id),
department_id UUID REFERENCES hr.departments(id),
-- Vigencia
date_start DATE NOT NULL,
date_end DATE,
trial_date_end DATE,
-- Compensacion
wage DECIMAL(15, 2) NOT NULL,
wage_type VARCHAR(20) DEFAULT 'monthly', -- hourly, daily, weekly, monthly, yearly
currency_id UUID REFERENCES core.currencies(id),
-- Horas
resource_calendar_id UUID, -- For future scheduling module
hours_per_week DECIMAL(5, 2) DEFAULT 40,
-- Beneficios y deducciones
vacation_days INTEGER DEFAULT 6,
christmas_bonus_days INTEGER DEFAULT 15,
-- Documentos
document_url VARCHAR(500),
-- Notas
notes TEXT,
-- Auditoria
created_by UUID REFERENCES auth.users(id),
updated_by UUID REFERENCES auth.users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Tabla: leave_types (Tipos de ausencia configurables)
CREATE TABLE hr.leave_types (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
code VARCHAR(20),
leave_type hr.leave_type NOT NULL,
requires_approval BOOLEAN DEFAULT TRUE,
max_days INTEGER,
is_paid BOOLEAN DEFAULT TRUE,
color VARCHAR(20),
active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
UNIQUE(tenant_id, name)
);
-- Tabla: leaves (Ausencias/Permisos)
CREATE TABLE hr.leaves (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
company_id UUID NOT NULL REFERENCES auth.companies(id) ON DELETE CASCADE,
employee_id UUID NOT NULL REFERENCES hr.employees(id) ON DELETE CASCADE,
leave_type_id UUID NOT NULL REFERENCES hr.leave_types(id),
-- Solicitud
name VARCHAR(255),
date_from DATE NOT NULL,
date_to DATE NOT NULL,
number_of_days DECIMAL(5, 2) NOT NULL,
-- Estado
status hr.leave_status NOT NULL DEFAULT 'draft',
-- Descripcion
description TEXT,
-- Aprobacion
approved_by UUID REFERENCES auth.users(id),
approved_at TIMESTAMP WITH TIME ZONE,
rejection_reason TEXT,
-- Auditoria
created_by UUID REFERENCES auth.users(id),
updated_by UUID REFERENCES auth.users(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- =====================================================
-- INDEXES
-- =====================================================
CREATE INDEX idx_departments_tenant ON hr.departments(tenant_id);
CREATE INDEX idx_departments_company ON hr.departments(company_id);
CREATE INDEX idx_departments_parent ON hr.departments(parent_id);
CREATE INDEX idx_job_positions_tenant ON hr.job_positions(tenant_id);
CREATE INDEX idx_job_positions_department ON hr.job_positions(department_id);
CREATE INDEX idx_employees_tenant ON hr.employees(tenant_id);
CREATE INDEX idx_employees_company ON hr.employees(company_id);
CREATE INDEX idx_employees_department ON hr.employees(department_id);
CREATE INDEX idx_employees_manager ON hr.employees(manager_id);
CREATE INDEX idx_employees_user ON hr.employees(user_id);
CREATE INDEX idx_employees_status ON hr.employees(status);
CREATE INDEX idx_employees_number ON hr.employees(employee_number);
CREATE INDEX idx_contracts_tenant ON hr.contracts(tenant_id);
CREATE INDEX idx_contracts_employee ON hr.contracts(employee_id);
CREATE INDEX idx_contracts_status ON hr.contracts(status);
CREATE INDEX idx_contracts_dates ON hr.contracts(date_start, date_end);
CREATE INDEX idx_leave_types_tenant ON hr.leave_types(tenant_id);
CREATE INDEX idx_leaves_tenant ON hr.leaves(tenant_id);
CREATE INDEX idx_leaves_employee ON hr.leaves(employee_id);
CREATE INDEX idx_leaves_status ON hr.leaves(status);
CREATE INDEX idx_leaves_dates ON hr.leaves(date_from, date_to);
-- =====================================================
-- TRIGGERS
-- =====================================================
CREATE TRIGGER update_departments_timestamp
BEFORE UPDATE ON hr.departments
FOR EACH ROW EXECUTE FUNCTION core.update_timestamp();
CREATE TRIGGER update_job_positions_timestamp
BEFORE UPDATE ON hr.job_positions
FOR EACH ROW EXECUTE FUNCTION core.update_timestamp();
CREATE TRIGGER update_employees_timestamp
BEFORE UPDATE ON hr.employees
FOR EACH ROW EXECUTE FUNCTION core.update_timestamp();
CREATE TRIGGER update_contracts_timestamp
BEFORE UPDATE ON hr.contracts
FOR EACH ROW EXECUTE FUNCTION core.update_timestamp();
CREATE TRIGGER update_leaves_timestamp
BEFORE UPDATE ON hr.leaves
FOR EACH ROW EXECUTE FUNCTION core.update_timestamp();
-- =====================================================
-- ROW LEVEL SECURITY
-- =====================================================
-- Habilitar RLS
ALTER TABLE hr.departments ENABLE ROW LEVEL SECURITY;
ALTER TABLE hr.job_positions ENABLE ROW LEVEL SECURITY;
ALTER TABLE hr.employees ENABLE ROW LEVEL SECURITY;
ALTER TABLE hr.contracts ENABLE ROW LEVEL SECURITY;
ALTER TABLE hr.leave_types ENABLE ROW LEVEL SECURITY;
ALTER TABLE hr.leaves ENABLE ROW LEVEL SECURITY;
-- Políticas de aislamiento por tenant
CREATE POLICY tenant_isolation_departments ON hr.departments
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
CREATE POLICY tenant_isolation_job_positions ON hr.job_positions
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
CREATE POLICY tenant_isolation_employees ON hr.employees
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
CREATE POLICY tenant_isolation_contracts ON hr.contracts
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
CREATE POLICY tenant_isolation_leave_types ON hr.leave_types
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
CREATE POLICY tenant_isolation_leaves ON hr.leaves
USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
-- =====================================================
-- COMMENTS
-- =====================================================
COMMENT ON TABLE hr.departments IS 'Departamentos de la organizacion';
COMMENT ON TABLE hr.job_positions IS 'Puestos de trabajo/posiciones';
COMMENT ON TABLE hr.employees IS 'Empleados de la organizacion';
COMMENT ON TABLE hr.contracts IS 'Contratos laborales';
COMMENT ON TABLE hr.leave_types IS 'Tipos de ausencia configurables';
COMMENT ON TABLE hr.leaves IS 'Solicitudes de ausencias/permisos';