-- ===================================================== -- 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';