workspace/projects/erp-suite/apps/verticales/construccion/database/schemas/02-hr-schema-ddl.sql
rckrdmrd ea1879f4ad feat: Initial workspace structure with multi-level Git configuration
- Configure workspace Git repository with comprehensive .gitignore
- Add Odoo as submodule for ERP reference code
- Include documentation: SETUP.md, GIT-STRUCTURE.md
- Add gitignore templates for projects (backend, frontend, database)
- Structure supports independent repos per project/subproject level

Workspace includes:
- core/ - Reusable patterns, modules, orchestration system
- projects/ - Active projects (erp-suite, gamilit, trading-platform, etc.)
- knowledge-base/ - Reference code and patterns (includes Odoo submodule)
- devtools/ - Development tools and templates
- customers/ - Client implementations template

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 10:44:23 -06:00

154 lines
6.0 KiB
SQL

-- ============================================================================
-- HR Schema DDL - Extension de RRHH para Construccion
-- Modulo: MAI-007 RRHH y Asistencias
-- Version: 1.0.0
-- Fecha: 2025-12-06
-- ============================================================================
-- POLITICA: CARGA LIMPIA (ver DIRECTIVA-POLITICA-CARGA-LIMPIA.md)
-- Este archivo es parte de la fuente de verdad DDL.
-- ============================================================================
-- Verificar prerequisitos
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = 'core') THEN
RAISE EXCEPTION 'Schema core no existe. Ejecutar primero init-scripts/01-init-database.sql';
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = 'construction') THEN
RAISE EXCEPTION 'Schema construction no existe. Ejecutar primero 01-construction-schema-ddl.sql';
END IF;
END $$;
-- Crear schema si no existe
CREATE SCHEMA IF NOT EXISTS hr;
-- Configurar search_path
SET search_path TO hr, construction, core, core_shared, public;
-- ============================================================================
-- TABLAS BASE (requeridas por HSE y otros modulos)
-- ============================================================================
-- Tabla: Empleados
CREATE TABLE IF NOT EXISTS hr.employees (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES core.tenants(id),
codigo VARCHAR(20) NOT NULL,
nombre VARCHAR(100) NOT NULL,
apellido_paterno VARCHAR(100) NOT NULL,
apellido_materno VARCHAR(100),
curp VARCHAR(18),
rfc VARCHAR(13),
nss VARCHAR(11),
fecha_nacimiento DATE,
genero VARCHAR(1),
email VARCHAR(255),
telefono VARCHAR(20),
direccion TEXT,
fecha_ingreso DATE NOT NULL,
fecha_baja DATE,
puesto_id UUID,
departamento VARCHAR(100),
tipo_contrato VARCHAR(50),
salario_diario DECIMAL(10,2),
estado VARCHAR(20) NOT NULL DEFAULT 'activo',
foto_url VARCHAR(500),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES core.users(id),
CONSTRAINT uq_employees_codigo UNIQUE (tenant_id, codigo),
CONSTRAINT uq_employees_curp UNIQUE (tenant_id, curp)
);
-- Tabla: Puestos
CREATE TABLE IF NOT EXISTS hr.puestos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES core.tenants(id),
codigo VARCHAR(20) NOT NULL,
nombre VARCHAR(100) NOT NULL,
descripcion TEXT,
nivel_riesgo VARCHAR(20),
requiere_capacitacion_especial BOOLEAN DEFAULT false,
activo BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_puestos_codigo UNIQUE (tenant_id, codigo)
);
-- Agregar FK de puesto a empleados
ALTER TABLE hr.employees
ADD CONSTRAINT fk_employees_puesto
FOREIGN KEY (puesto_id) REFERENCES hr.puestos(id);
-- Tabla: Asignacion de empleados a obras
CREATE TABLE IF NOT EXISTS hr.employee_fraccionamientos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES core.tenants(id),
employee_id UUID NOT NULL REFERENCES hr.employees(id),
fraccionamiento_id UUID NOT NULL REFERENCES construction.fraccionamientos(id),
fecha_inicio DATE NOT NULL,
fecha_fin DATE,
rol VARCHAR(50),
activo BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_employee_fraccionamiento UNIQUE (employee_id, fraccionamiento_id, fecha_inicio)
);
-- ============================================================================
-- INDICES
-- ============================================================================
CREATE INDEX IF NOT EXISTS idx_employees_tenant ON hr.employees(tenant_id);
CREATE INDEX IF NOT EXISTS idx_employees_estado ON hr.employees(estado);
CREATE INDEX IF NOT EXISTS idx_employees_puesto ON hr.employees(puesto_id);
CREATE INDEX IF NOT EXISTS idx_puestos_tenant ON hr.puestos(tenant_id);
CREATE INDEX IF NOT EXISTS idx_employee_fraccionamientos_employee ON hr.employee_fraccionamientos(employee_id);
CREATE INDEX IF NOT EXISTS idx_employee_fraccionamientos_fraccionamiento ON hr.employee_fraccionamientos(fraccionamiento_id);
-- ============================================================================
-- ROW LEVEL SECURITY
-- ============================================================================
ALTER TABLE hr.employees ENABLE ROW LEVEL SECURITY;
ALTER TABLE hr.puestos ENABLE ROW LEVEL SECURITY;
ALTER TABLE hr.employee_fraccionamientos ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_employees ON hr.employees
FOR ALL
USING (tenant_id = current_setting('app.current_tenant', true)::UUID);
CREATE POLICY tenant_isolation_puestos ON hr.puestos
FOR ALL
USING (tenant_id = current_setting('app.current_tenant', true)::UUID);
CREATE POLICY tenant_isolation_employee_fraccionamientos ON hr.employee_fraccionamientos
FOR ALL
USING (tenant_id = current_setting('app.current_tenant', true)::UUID);
-- ============================================================================
-- TRIGGERS
-- ============================================================================
CREATE TRIGGER trg_employees_updated_at
BEFORE UPDATE ON hr.employees
FOR EACH ROW EXECUTE FUNCTION core_shared.set_updated_at();
CREATE TRIGGER trg_puestos_updated_at
BEFORE UPDATE ON hr.puestos
FOR EACH ROW EXECUTE FUNCTION core_shared.set_updated_at();
-- ============================================================================
-- COMENTARIOS
-- ============================================================================
COMMENT ON TABLE hr.employees IS 'Empleados de la empresa';
COMMENT ON TABLE hr.puestos IS 'Catalogo de puestos de trabajo';
COMMENT ON TABLE hr.employee_fraccionamientos IS 'Asignacion de empleados a obras/fraccionamientos';
-- ============================================================================
-- FIN
-- ============================================================================