318 lines
12 KiB
PL/PgSQL
318 lines
12 KiB
PL/PgSQL
-- ============================================================================
|
|
-- Archivo: 01-init-database.sql
|
|
-- Descripcion: Inicializacion completa de base de datos - Carga Limpia
|
|
-- Proyecto: ERP Suite - Vertical Construccion
|
|
-- Version: 2.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.
|
|
-- NO usar migrations, fixes o patches incrementales.
|
|
-- ============================================================================
|
|
|
|
-- ============================================================================
|
|
-- EXTENSIONES
|
|
-- ============================================================================
|
|
|
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- Generacion de UUIDs
|
|
CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- Funciones criptograficas
|
|
CREATE EXTENSION IF NOT EXISTS "postgis"; -- Geolocalizacion
|
|
CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- Busqueda fuzzy
|
|
CREATE EXTENSION IF NOT EXISTS "btree_gist"; -- Indices GiST avanzados
|
|
|
|
-- ============================================================================
|
|
-- SCHEMA: core_shared (funciones compartidas)
|
|
-- ============================================================================
|
|
|
|
CREATE SCHEMA IF NOT EXISTS core_shared;
|
|
|
|
COMMENT ON SCHEMA core_shared IS 'Funciones, tipos y utilidades compartidas entre modulos';
|
|
|
|
-- ============================================================================
|
|
-- FUNCIONES DE AUDITORIA
|
|
-- ============================================================================
|
|
|
|
-- Funcion para actualizar updated_at automaticamente
|
|
CREATE OR REPLACE FUNCTION core_shared.set_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = NOW();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION core_shared.set_updated_at() IS
|
|
'Trigger function para actualizar automaticamente el campo updated_at en cada UPDATE';
|
|
|
|
-- Funcion para establecer tenant_id desde contexto
|
|
CREATE OR REPLACE FUNCTION core_shared.set_tenant_id()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF NEW.tenant_id IS NULL THEN
|
|
NEW.tenant_id = current_setting('app.current_tenant_id', true)::uuid;
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION core_shared.set_tenant_id() IS
|
|
'Trigger function para establecer tenant_id automaticamente desde el contexto de sesion';
|
|
|
|
-- Funcion para establecer created_by desde contexto
|
|
CREATE OR REPLACE FUNCTION core_shared.set_created_by()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF NEW.created_by IS NULL THEN
|
|
NEW.created_by = current_setting('app.current_user_id', true)::uuid;
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION core_shared.set_created_by() IS
|
|
'Trigger function para establecer created_by automaticamente desde el contexto de sesion';
|
|
|
|
-- ============================================================================
|
|
-- FUNCIONES DE CONTEXTO
|
|
-- ============================================================================
|
|
|
|
CREATE OR REPLACE FUNCTION core_shared.get_current_tenant_id()
|
|
RETURNS UUID AS $$
|
|
BEGIN
|
|
RETURN NULLIF(current_setting('app.current_tenant_id', true), '')::UUID;
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
RETURN NULL;
|
|
END;
|
|
$$ LANGUAGE plpgsql STABLE;
|
|
|
|
COMMENT ON FUNCTION core_shared.get_current_tenant_id() IS
|
|
'Obtiene el ID del tenant actual desde el contexto de sesion';
|
|
|
|
CREATE OR REPLACE FUNCTION core_shared.get_current_user_id()
|
|
RETURNS UUID AS $$
|
|
BEGIN
|
|
RETURN NULLIF(current_setting('app.current_user_id', true), '')::UUID;
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
RETURN NULL;
|
|
END;
|
|
$$ LANGUAGE plpgsql STABLE;
|
|
|
|
COMMENT ON FUNCTION core_shared.get_current_user_id() IS
|
|
'Obtiene el ID del usuario actual desde el contexto de sesion';
|
|
|
|
-- ============================================================================
|
|
-- FUNCIONES DE UTILIDAD
|
|
-- ============================================================================
|
|
|
|
-- Generar slug desde texto
|
|
CREATE OR REPLACE FUNCTION core_shared.generate_slug(input_text TEXT)
|
|
RETURNS TEXT AS $$
|
|
BEGIN
|
|
RETURN LOWER(
|
|
REGEXP_REPLACE(
|
|
REGEXP_REPLACE(
|
|
TRIM(input_text),
|
|
'[^a-zA-Z0-9\s-]', '', 'g'
|
|
),
|
|
'\s+', '-', 'g'
|
|
)
|
|
);
|
|
END;
|
|
$$ LANGUAGE plpgsql IMMUTABLE;
|
|
|
|
-- Validar formato de email
|
|
CREATE OR REPLACE FUNCTION core_shared.is_valid_email(email TEXT)
|
|
RETURNS BOOLEAN AS $$
|
|
BEGIN
|
|
RETURN email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$';
|
|
END;
|
|
$$ LANGUAGE plpgsql IMMUTABLE;
|
|
|
|
-- Validar formato de RFC mexicano
|
|
CREATE OR REPLACE FUNCTION core_shared.is_valid_rfc(rfc TEXT)
|
|
RETURNS BOOLEAN AS $$
|
|
BEGIN
|
|
RETURN rfc ~* '^[A-Z&Ñ]{3,4}[0-9]{6}[A-Z0-9]{3}$';
|
|
END;
|
|
$$ LANGUAGE plpgsql IMMUTABLE;
|
|
|
|
-- ============================================================================
|
|
-- PERMISOS
|
|
-- ============================================================================
|
|
|
|
GRANT USAGE ON SCHEMA core_shared TO PUBLIC;
|
|
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA core_shared TO PUBLIC;
|
|
|
|
-- ============================================================================
|
|
-- SCHEMAS DE NEGOCIO - NOMENCLATURA UNIFICADA
|
|
-- ============================================================================
|
|
-- Segun NAMING-CONVENTIONS.md, usamos nombres cortos y descriptivos:
|
|
-- - construction (antes project_management, construction_management)
|
|
-- - estimates (antes financial_management)
|
|
-- - infonavit (antes infonavit_management)
|
|
-- - hr (extension de erp-core)
|
|
-- - inventory (extension de erp-core)
|
|
-- - purchase (extension de erp-core)
|
|
-- - hse (nuevo: seguridad, salud, medio ambiente)
|
|
-- ============================================================================
|
|
|
|
-- Schemas propios de construccion
|
|
CREATE SCHEMA IF NOT EXISTS construction;
|
|
CREATE SCHEMA IF NOT EXISTS estimates;
|
|
CREATE SCHEMA IF NOT EXISTS infonavit;
|
|
CREATE SCHEMA IF NOT EXISTS hse;
|
|
|
|
-- Schemas de extension (extendemos modulos de erp-core)
|
|
-- Estos pueden ya existir si erp-core esta instalado
|
|
CREATE SCHEMA IF NOT EXISTS hr;
|
|
CREATE SCHEMA IF NOT EXISTS inventory;
|
|
CREATE SCHEMA IF NOT EXISTS purchase;
|
|
|
|
-- Schemas legacy (compatibilidad temporal, marcar para deprecacion)
|
|
-- NOTA: Estos seran eliminados en version futura
|
|
CREATE SCHEMA IF NOT EXISTS auth_management;
|
|
CREATE SCHEMA IF NOT EXISTS project_management;
|
|
CREATE SCHEMA IF NOT EXISTS financial_management;
|
|
CREATE SCHEMA IF NOT EXISTS purchasing_management;
|
|
CREATE SCHEMA IF NOT EXISTS inventory_management;
|
|
CREATE SCHEMA IF NOT EXISTS construction_management;
|
|
CREATE SCHEMA IF NOT EXISTS quality_management;
|
|
CREATE SCHEMA IF NOT EXISTS safety_management;
|
|
CREATE SCHEMA IF NOT EXISTS infonavit_management;
|
|
|
|
-- ============================================================================
|
|
-- COMENTARIOS EN SCHEMAS
|
|
-- ============================================================================
|
|
|
|
-- Schemas principales (nuevos)
|
|
COMMENT ON SCHEMA construction IS
|
|
'Gestion de obras: proyectos, fraccionamientos, fases, viviendas, avances';
|
|
|
|
COMMENT ON SCHEMA estimates IS
|
|
'Presupuestos, partidas, estimaciones, control de costos';
|
|
|
|
COMMENT ON SCHEMA infonavit IS
|
|
'Integracion INFONAVIT: tramites, ECUVE, subsidios, normatividad';
|
|
|
|
COMMENT ON SCHEMA hse IS
|
|
'Seguridad, Salud Ocupacional y Medio Ambiente (HSE/EHS)';
|
|
|
|
COMMENT ON SCHEMA hr IS
|
|
'Extension de RRHH para construccion: cuadrillas, destajo, asistencia obra';
|
|
|
|
COMMENT ON SCHEMA inventory IS
|
|
'Extension de inventarios: almacenes de obra, control de materiales';
|
|
|
|
COMMENT ON SCHEMA purchase IS
|
|
'Extension de compras: proveedores de construccion, requisiciones de obra';
|
|
|
|
-- Schemas legacy (deprecated)
|
|
COMMENT ON SCHEMA auth_management IS
|
|
'DEPRECATED: Usar core.auth. Schema mantenido para compatibilidad';
|
|
|
|
COMMENT ON SCHEMA project_management IS
|
|
'DEPRECATED: Usar construction. Schema mantenido para compatibilidad';
|
|
|
|
COMMENT ON SCHEMA financial_management IS
|
|
'DEPRECATED: Usar estimates. Schema mantenido para compatibilidad';
|
|
|
|
COMMENT ON SCHEMA purchasing_management IS
|
|
'DEPRECATED: Usar purchase. Schema mantenido para compatibilidad';
|
|
|
|
COMMENT ON SCHEMA inventory_management IS
|
|
'DEPRECATED: Usar inventory. Schema mantenido para compatibilidad';
|
|
|
|
COMMENT ON SCHEMA construction_management IS
|
|
'DEPRECATED: Usar construction. Schema mantenido para compatibilidad';
|
|
|
|
COMMENT ON SCHEMA quality_management IS
|
|
'DEPRECATED: Funcionalidad movida a hse (inspecciones) y construction (calidad)';
|
|
|
|
COMMENT ON SCHEMA safety_management IS
|
|
'DEPRECATED: Usar hse. Schema mantenido para compatibilidad';
|
|
|
|
COMMENT ON SCHEMA infonavit_management IS
|
|
'DEPRECATED: Usar infonavit. Schema mantenido para compatibilidad';
|
|
|
|
-- ============================================================================
|
|
-- FUNCION LEGACY (compatibilidad)
|
|
-- ============================================================================
|
|
|
|
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = now();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION update_updated_at_column() IS
|
|
'LEGACY: Usar core_shared.set_updated_at() en nuevas tablas';
|
|
|
|
-- ============================================================================
|
|
-- TABLAS CORE MINIMAS (si erp-core no esta instalado)
|
|
-- ============================================================================
|
|
-- Estas tablas son requeridas como FK por los modulos de construccion
|
|
-- Si erp-core esta instalado, estas ya existiran y el IF NOT EXISTS las omitira
|
|
|
|
-- Schema core para tablas compartidas
|
|
CREATE SCHEMA IF NOT EXISTS core;
|
|
|
|
-- Tabla de tenants (multi-tenancy)
|
|
CREATE TABLE IF NOT EXISTS core.tenants (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
code VARCHAR(50) NOT NULL UNIQUE,
|
|
name VARCHAR(200) NOT NULL,
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
settings JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- Tabla de usuarios
|
|
CREATE TABLE IF NOT EXISTS core.users (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID REFERENCES core.tenants(id),
|
|
email VARCHAR(255) NOT NULL,
|
|
username VARCHAR(100),
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
UNIQUE(tenant_id, email)
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- VERIFICACION
|
|
-- ============================================================================
|
|
|
|
DO $$
|
|
DECLARE
|
|
schema_count INTEGER;
|
|
ext_count INTEGER;
|
|
BEGIN
|
|
SELECT COUNT(*) INTO schema_count
|
|
FROM pg_namespace
|
|
WHERE nspname IN ('construction', 'estimates', 'infonavit', 'hse', 'hr', 'inventory', 'purchase', 'core', 'core_shared');
|
|
|
|
SELECT COUNT(*) INTO ext_count
|
|
FROM pg_extension
|
|
WHERE extname IN ('uuid-ossp', 'pgcrypto', 'postgis', 'pg_trgm', 'btree_gist');
|
|
|
|
RAISE NOTICE '============================================================';
|
|
RAISE NOTICE 'ERP CONSTRUCCION - Base de datos inicializada';
|
|
RAISE NOTICE '============================================================';
|
|
RAISE NOTICE 'Extensiones instaladas: %', ext_count;
|
|
RAISE NOTICE 'Schemas principales creados: %', schema_count;
|
|
RAISE NOTICE '============================================================';
|
|
RAISE NOTICE 'Schemas principales: construction, estimates, infonavit, hse';
|
|
RAISE NOTICE 'Schemas extension: hr, inventory, purchase';
|
|
RAISE NOTICE 'Schemas compartidos: core, core_shared';
|
|
RAISE NOTICE '============================================================';
|
|
END $$;
|
|
|
|
-- ============================================================================
|
|
-- FIN
|
|
-- ============================================================================
|