- 30-settings.sql: system_settings, plan_settings, tenant_settings, user_preferences (4 tables) - 31-reports.sql: report_definitions, executions, schedules, dashboards, widgets (12 tables, 7 enums) - 45-hr.sql: employees, departments, job_positions, contracts, leave_types, leaves (7 tables, 6 enums) Includes RLS policies, triggers, and utility functions for each module. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
680 lines
21 KiB
PL/PgSQL
680 lines
21 KiB
PL/PgSQL
-- =============================================================
|
|
-- ARCHIVO: 31-reports.sql
|
|
-- DESCRIPCION: Sistema de Reportes y Analytics
|
|
-- VERSION: 1.0.0
|
|
-- PROYECTO: ERP-Core
|
|
-- FECHA: 2026-01-26
|
|
-- MODULO: MGN-009 (Reports)
|
|
-- EPIC: EPIC-MGN-009-reports
|
|
-- =============================================================
|
|
|
|
-- =====================
|
|
-- SCHEMA: reports
|
|
-- =====================
|
|
CREATE SCHEMA IF NOT EXISTS reports;
|
|
|
|
-- =====================
|
|
-- ENUMS
|
|
-- =====================
|
|
|
|
-- Tipo de reporte
|
|
DO $$ BEGIN
|
|
CREATE TYPE reports.report_type AS ENUM (
|
|
'financial',
|
|
'accounting',
|
|
'tax',
|
|
'management',
|
|
'operational',
|
|
'custom'
|
|
);
|
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
END $$;
|
|
|
|
-- Estado de ejecucion
|
|
DO $$ BEGIN
|
|
CREATE TYPE reports.execution_status AS ENUM (
|
|
'pending',
|
|
'running',
|
|
'completed',
|
|
'failed',
|
|
'cancelled'
|
|
);
|
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
END $$;
|
|
|
|
-- Formato de exportacion
|
|
DO $$ BEGIN
|
|
CREATE TYPE reports.export_format AS ENUM (
|
|
'pdf',
|
|
'excel',
|
|
'csv',
|
|
'json',
|
|
'html'
|
|
);
|
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
END $$;
|
|
|
|
-- Metodo de entrega
|
|
DO $$ BEGIN
|
|
CREATE TYPE reports.delivery_method AS ENUM (
|
|
'none',
|
|
'email',
|
|
'storage',
|
|
'webhook'
|
|
);
|
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
END $$;
|
|
|
|
-- Tipo de widget
|
|
DO $$ BEGIN
|
|
CREATE TYPE reports.widget_type AS ENUM (
|
|
'kpi',
|
|
'bar_chart',
|
|
'line_chart',
|
|
'pie_chart',
|
|
'donut_chart',
|
|
'gauge',
|
|
'table',
|
|
'map',
|
|
'text'
|
|
);
|
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
END $$;
|
|
|
|
-- Tipo de parametro
|
|
DO $$ BEGIN
|
|
CREATE TYPE reports.param_type AS ENUM (
|
|
'string',
|
|
'number',
|
|
'date',
|
|
'daterange',
|
|
'boolean',
|
|
'select',
|
|
'multiselect',
|
|
'entity'
|
|
);
|
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
END $$;
|
|
|
|
-- Operador de filtro
|
|
DO $$ BEGIN
|
|
CREATE TYPE reports.filter_operator AS ENUM (
|
|
'eq',
|
|
'ne',
|
|
'gt',
|
|
'gte',
|
|
'lt',
|
|
'lte',
|
|
'like',
|
|
'ilike',
|
|
'in',
|
|
'not_in',
|
|
'between',
|
|
'is_null',
|
|
'is_not_null'
|
|
);
|
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
END $$;
|
|
|
|
-- =====================
|
|
-- TABLA: reports.report_definitions
|
|
-- Definiciones de reportes
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.report_definitions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Identificacion
|
|
code VARCHAR(50) NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
category VARCHAR(100),
|
|
report_type reports.report_type NOT NULL DEFAULT 'custom',
|
|
|
|
-- Query
|
|
base_query TEXT,
|
|
query_function VARCHAR(255),
|
|
is_sql_based BOOLEAN NOT NULL DEFAULT true,
|
|
|
|
-- Parametros
|
|
parameters_schema JSONB DEFAULT '[]',
|
|
default_parameters JSONB DEFAULT '{}',
|
|
|
|
-- Columnas
|
|
columns_config JSONB NOT NULL DEFAULT '[]',
|
|
totals_config JSONB DEFAULT '[]',
|
|
|
|
-- Permisos
|
|
required_permissions TEXT[] DEFAULT '{}',
|
|
is_public BOOLEAN NOT NULL DEFAULT false,
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id),
|
|
|
|
UNIQUE(tenant_id, code)
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_report_definitions_tenant ON reports.report_definitions(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_report_definitions_category ON reports.report_definitions(category);
|
|
CREATE INDEX IF NOT EXISTS idx_report_definitions_type ON reports.report_definitions(report_type);
|
|
CREATE INDEX IF NOT EXISTS idx_report_definitions_active ON reports.report_definitions(is_active) WHERE is_active = true;
|
|
|
|
-- =====================
|
|
-- TABLA: reports.report_executions
|
|
-- Historial de ejecuciones
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.report_executions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Relaciones
|
|
report_definition_id UUID NOT NULL REFERENCES reports.report_definitions(id) ON DELETE CASCADE,
|
|
executed_by UUID NOT NULL REFERENCES auth.users(id),
|
|
|
|
-- Ejecucion
|
|
status reports.execution_status NOT NULL DEFAULT 'pending',
|
|
parameters JSONB DEFAULT '{}',
|
|
|
|
-- Resultado
|
|
result_data JSONB,
|
|
result_summary JSONB,
|
|
row_count INTEGER,
|
|
export_format reports.export_format,
|
|
file_path TEXT,
|
|
file_size_bytes BIGINT,
|
|
|
|
-- Timing
|
|
started_at TIMESTAMPTZ,
|
|
completed_at TIMESTAMPTZ,
|
|
execution_time_ms INTEGER,
|
|
|
|
-- Error
|
|
error_message TEXT,
|
|
error_details JSONB,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_report_executions_tenant ON reports.report_executions(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_report_executions_definition ON reports.report_executions(report_definition_id);
|
|
CREATE INDEX IF NOT EXISTS idx_report_executions_user ON reports.report_executions(executed_by);
|
|
CREATE INDEX IF NOT EXISTS idx_report_executions_status ON reports.report_executions(status);
|
|
CREATE INDEX IF NOT EXISTS idx_report_executions_date ON reports.report_executions(created_at DESC);
|
|
|
|
-- =====================
|
|
-- TABLA: reports.report_schedules
|
|
-- Programacion de reportes
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.report_schedules (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Relaciones
|
|
report_definition_id UUID NOT NULL REFERENCES reports.report_definitions(id) ON DELETE CASCADE,
|
|
|
|
-- Programacion
|
|
name VARCHAR(255) NOT NULL,
|
|
cron_expression VARCHAR(100) NOT NULL,
|
|
timezone VARCHAR(100) NOT NULL DEFAULT 'America/Mexico_City',
|
|
parameters JSONB DEFAULT '{}',
|
|
|
|
-- Entrega
|
|
delivery_method reports.delivery_method NOT NULL DEFAULT 'email',
|
|
delivery_config JSONB DEFAULT '{}',
|
|
export_format reports.export_format NOT NULL DEFAULT 'pdf',
|
|
|
|
-- Estado
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
last_run_at TIMESTAMPTZ,
|
|
last_run_status reports.execution_status,
|
|
next_run_at TIMESTAMPTZ,
|
|
run_count INTEGER NOT NULL DEFAULT 0,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_by UUID REFERENCES auth.users(id)
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_report_schedules_tenant ON reports.report_schedules(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_report_schedules_definition ON reports.report_schedules(report_definition_id);
|
|
CREATE INDEX IF NOT EXISTS idx_report_schedules_active ON reports.report_schedules(is_active) WHERE is_active = true;
|
|
CREATE INDEX IF NOT EXISTS idx_report_schedules_next_run ON reports.report_schedules(next_run_at) WHERE is_active = true;
|
|
|
|
-- =====================
|
|
-- TABLA: reports.report_recipients
|
|
-- Destinatarios de reportes programados
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.report_recipients (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relaciones
|
|
schedule_id UUID NOT NULL REFERENCES reports.report_schedules(id) ON DELETE CASCADE,
|
|
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
|
|
-- Destinatario externo
|
|
email VARCHAR(255),
|
|
name VARCHAR(255),
|
|
|
|
-- Estado
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_report_recipients_schedule ON reports.report_recipients(schedule_id);
|
|
CREATE INDEX IF NOT EXISTS idx_report_recipients_user ON reports.report_recipients(user_id);
|
|
|
|
-- =====================
|
|
-- TABLA: reports.schedule_executions
|
|
-- Historial de ejecuciones programadas
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.schedule_executions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relaciones
|
|
schedule_id UUID NOT NULL REFERENCES reports.report_schedules(id) ON DELETE CASCADE,
|
|
execution_id UUID REFERENCES reports.report_executions(id) ON DELETE SET NULL,
|
|
|
|
-- Resultado
|
|
status reports.execution_status NOT NULL,
|
|
recipients_notified INTEGER DEFAULT 0,
|
|
delivery_status JSONB DEFAULT '{}',
|
|
|
|
-- Error
|
|
error_message TEXT,
|
|
|
|
-- Audit
|
|
executed_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_schedule_executions_schedule ON reports.schedule_executions(schedule_id);
|
|
CREATE INDEX IF NOT EXISTS idx_schedule_executions_date ON reports.schedule_executions(executed_at DESC);
|
|
|
|
-- =====================
|
|
-- TABLA: reports.dashboards
|
|
-- Dashboards personalizados
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.dashboards (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Identificacion
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
slug VARCHAR(100),
|
|
icon VARCHAR(50),
|
|
|
|
-- Layout
|
|
layout_config JSONB DEFAULT '{"columns": 12, "rowHeight": 80}',
|
|
|
|
-- Estado
|
|
is_default BOOLEAN NOT NULL DEFAULT false,
|
|
is_public BOOLEAN NOT NULL DEFAULT false,
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
|
|
-- Permisos
|
|
owner_id UUID NOT NULL REFERENCES auth.users(id),
|
|
allowed_roles TEXT[] DEFAULT '{}',
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_dashboards_tenant ON reports.dashboards(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_dashboards_owner ON reports.dashboards(owner_id);
|
|
CREATE INDEX IF NOT EXISTS idx_dashboards_default ON reports.dashboards(tenant_id, is_default) WHERE is_default = true;
|
|
|
|
-- =====================
|
|
-- TABLA: reports.dashboard_widgets
|
|
-- Widgets de dashboards
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.dashboard_widgets (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relaciones
|
|
dashboard_id UUID NOT NULL REFERENCES reports.dashboards(id) ON DELETE CASCADE,
|
|
|
|
-- Identificacion
|
|
title VARCHAR(255) NOT NULL,
|
|
widget_type reports.widget_type NOT NULL,
|
|
|
|
-- Posicion
|
|
position_x INTEGER NOT NULL DEFAULT 0,
|
|
position_y INTEGER NOT NULL DEFAULT 0,
|
|
width INTEGER NOT NULL DEFAULT 3,
|
|
height INTEGER NOT NULL DEFAULT 2,
|
|
|
|
-- Configuracion
|
|
config JSONB NOT NULL DEFAULT '{}',
|
|
refresh_interval_seconds INTEGER DEFAULT 300,
|
|
|
|
-- Estado
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_dashboard_widgets_dashboard ON reports.dashboard_widgets(dashboard_id);
|
|
CREATE INDEX IF NOT EXISTS idx_dashboard_widgets_type ON reports.dashboard_widgets(widget_type);
|
|
|
|
-- =====================
|
|
-- TABLA: reports.widget_queries
|
|
-- Queries de widgets
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.widget_queries (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relaciones
|
|
widget_id UUID NOT NULL REFERENCES reports.dashboard_widgets(id) ON DELETE CASCADE,
|
|
|
|
-- Query
|
|
name VARCHAR(100) NOT NULL,
|
|
query_text TEXT,
|
|
query_function VARCHAR(255),
|
|
parameters JSONB DEFAULT '{}',
|
|
|
|
-- Resultado
|
|
result_mapping JSONB DEFAULT '{}',
|
|
|
|
-- Cache
|
|
cache_ttl_seconds INTEGER DEFAULT 300,
|
|
last_cached_at TIMESTAMPTZ,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_widget_queries_widget ON reports.widget_queries(widget_id);
|
|
|
|
-- =====================
|
|
-- TABLA: reports.custom_reports
|
|
-- Reportes personalizados por usuario
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.custom_reports (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
|
|
|
-- Propietario
|
|
owner_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
|
|
-- Base
|
|
base_definition_id UUID REFERENCES reports.report_definitions(id) ON DELETE SET NULL,
|
|
|
|
-- Identificacion
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
|
|
-- Configuracion personalizada
|
|
custom_columns JSONB DEFAULT '[]',
|
|
custom_filters JSONB DEFAULT '[]',
|
|
custom_grouping JSONB DEFAULT '[]',
|
|
custom_sorting JSONB DEFAULT '[]',
|
|
|
|
-- Estado
|
|
is_favorite BOOLEAN NOT NULL DEFAULT false,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_custom_reports_tenant ON reports.custom_reports(tenant_id);
|
|
CREATE INDEX IF NOT EXISTS idx_custom_reports_owner ON reports.custom_reports(owner_id);
|
|
CREATE INDEX IF NOT EXISTS idx_custom_reports_favorite ON reports.custom_reports(owner_id, is_favorite) WHERE is_favorite = true;
|
|
|
|
-- =====================
|
|
-- TABLA: reports.data_model_entities
|
|
-- Modelo de datos para report builder
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.data_model_entities (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Identificacion
|
|
name VARCHAR(100) NOT NULL UNIQUE,
|
|
display_name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
|
|
-- Schema
|
|
schema_name VARCHAR(100) NOT NULL,
|
|
table_name VARCHAR(100) NOT NULL,
|
|
|
|
-- Configuracion
|
|
primary_key_column VARCHAR(100) NOT NULL DEFAULT 'id',
|
|
tenant_column VARCHAR(100) DEFAULT 'tenant_id',
|
|
is_multi_tenant BOOLEAN NOT NULL DEFAULT true,
|
|
|
|
-- Estado
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_data_model_entities_name ON reports.data_model_entities(name);
|
|
CREATE INDEX IF NOT EXISTS idx_data_model_entities_schema ON reports.data_model_entities(schema_name, table_name);
|
|
|
|
-- =====================
|
|
-- TABLA: reports.data_model_fields
|
|
-- Campos del modelo de datos
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.data_model_fields (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Relaciones
|
|
entity_id UUID NOT NULL REFERENCES reports.data_model_entities(id) ON DELETE CASCADE,
|
|
|
|
-- Identificacion
|
|
name VARCHAR(100) NOT NULL,
|
|
display_name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
|
|
-- Tipo
|
|
data_type VARCHAR(50) NOT NULL,
|
|
is_nullable BOOLEAN NOT NULL DEFAULT true,
|
|
|
|
-- Configuracion UI
|
|
is_filterable BOOLEAN NOT NULL DEFAULT true,
|
|
is_sortable BOOLEAN NOT NULL DEFAULT true,
|
|
is_groupable BOOLEAN NOT NULL DEFAULT false,
|
|
is_aggregatable BOOLEAN NOT NULL DEFAULT false,
|
|
aggregation_functions TEXT[] DEFAULT '{}',
|
|
|
|
-- Formato
|
|
format_pattern VARCHAR(100),
|
|
display_format VARCHAR(50),
|
|
|
|
-- Estado
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
UNIQUE(entity_id, name)
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_data_model_fields_entity ON reports.data_model_fields(entity_id);
|
|
|
|
-- =====================
|
|
-- TABLA: reports.data_model_relationships
|
|
-- Relaciones entre entidades del modelo
|
|
-- =====================
|
|
CREATE TABLE IF NOT EXISTS reports.data_model_relationships (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
|
|
-- Entidades
|
|
source_entity_id UUID NOT NULL REFERENCES reports.data_model_entities(id) ON DELETE CASCADE,
|
|
target_entity_id UUID NOT NULL REFERENCES reports.data_model_entities(id) ON DELETE CASCADE,
|
|
|
|
-- Relacion
|
|
name VARCHAR(100) NOT NULL,
|
|
relationship_type VARCHAR(20) NOT NULL CHECK (relationship_type IN ('one_to_one', 'one_to_many', 'many_to_one', 'many_to_many')),
|
|
|
|
-- Join
|
|
source_column VARCHAR(100) NOT NULL,
|
|
target_column VARCHAR(100) NOT NULL,
|
|
join_condition TEXT,
|
|
|
|
-- Estado
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
|
|
-- Audit
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
UNIQUE(source_entity_id, target_entity_id, name)
|
|
);
|
|
|
|
-- Indices
|
|
CREATE INDEX IF NOT EXISTS idx_data_model_relationships_source ON reports.data_model_relationships(source_entity_id);
|
|
CREATE INDEX IF NOT EXISTS idx_data_model_relationships_target ON reports.data_model_relationships(target_entity_id);
|
|
|
|
-- =====================
|
|
-- RLS POLICIES
|
|
-- =====================
|
|
|
|
-- Report Definitions
|
|
ALTER TABLE reports.report_definitions ENABLE ROW LEVEL SECURITY;
|
|
DROP POLICY IF EXISTS tenant_isolation_definitions ON reports.report_definitions;
|
|
CREATE POLICY tenant_isolation_definitions ON reports.report_definitions
|
|
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
|
|
-- Report Executions
|
|
ALTER TABLE reports.report_executions ENABLE ROW LEVEL SECURITY;
|
|
DROP POLICY IF EXISTS tenant_isolation_executions ON reports.report_executions;
|
|
CREATE POLICY tenant_isolation_executions ON reports.report_executions
|
|
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
|
|
-- Report Schedules
|
|
ALTER TABLE reports.report_schedules ENABLE ROW LEVEL SECURITY;
|
|
DROP POLICY IF EXISTS tenant_isolation_schedules ON reports.report_schedules;
|
|
CREATE POLICY tenant_isolation_schedules ON reports.report_schedules
|
|
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
|
|
-- Dashboards
|
|
ALTER TABLE reports.dashboards ENABLE ROW LEVEL SECURITY;
|
|
DROP POLICY IF EXISTS tenant_isolation_dashboards ON reports.dashboards;
|
|
CREATE POLICY tenant_isolation_dashboards ON reports.dashboards
|
|
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
|
|
-- Custom Reports
|
|
ALTER TABLE reports.custom_reports ENABLE ROW LEVEL SECURITY;
|
|
DROP POLICY IF EXISTS tenant_isolation_custom_reports ON reports.custom_reports;
|
|
CREATE POLICY tenant_isolation_custom_reports ON reports.custom_reports
|
|
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);
|
|
|
|
-- =====================
|
|
-- TRIGGERS
|
|
-- =====================
|
|
|
|
CREATE OR REPLACE FUNCTION reports.update_timestamp()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = CURRENT_TIMESTAMP;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER trg_report_definitions_updated_at
|
|
BEFORE UPDATE ON reports.report_definitions
|
|
FOR EACH ROW EXECUTE FUNCTION reports.update_timestamp();
|
|
|
|
CREATE TRIGGER trg_report_schedules_updated_at
|
|
BEFORE UPDATE ON reports.report_schedules
|
|
FOR EACH ROW EXECUTE FUNCTION reports.update_timestamp();
|
|
|
|
CREATE TRIGGER trg_dashboards_updated_at
|
|
BEFORE UPDATE ON reports.dashboards
|
|
FOR EACH ROW EXECUTE FUNCTION reports.update_timestamp();
|
|
|
|
CREATE TRIGGER trg_dashboard_widgets_updated_at
|
|
BEFORE UPDATE ON reports.dashboard_widgets
|
|
FOR EACH ROW EXECUTE FUNCTION reports.update_timestamp();
|
|
|
|
CREATE TRIGGER trg_custom_reports_updated_at
|
|
BEFORE UPDATE ON reports.custom_reports
|
|
FOR EACH ROW EXECUTE FUNCTION reports.update_timestamp();
|
|
|
|
-- =====================
|
|
-- FUNCIONES DE UTILIDAD
|
|
-- =====================
|
|
|
|
-- Funcion para obtener reportes activos de un tenant
|
|
CREATE OR REPLACE FUNCTION reports.get_active_reports(p_tenant_id UUID)
|
|
RETURNS TABLE (
|
|
id UUID,
|
|
code VARCHAR(50),
|
|
name VARCHAR(255),
|
|
category VARCHAR(100),
|
|
report_type reports.report_type
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT rd.id, rd.code, rd.name, rd.category, rd.report_type
|
|
FROM reports.report_definitions rd
|
|
WHERE rd.tenant_id = p_tenant_id
|
|
AND rd.is_active = true
|
|
ORDER BY rd.category, rd.name;
|
|
END;
|
|
$$ LANGUAGE plpgsql STABLE;
|
|
|
|
-- Funcion para obtener historial de ejecuciones recientes
|
|
CREATE OR REPLACE FUNCTION reports.get_recent_executions(
|
|
p_tenant_id UUID,
|
|
p_limit INTEGER DEFAULT 10
|
|
)
|
|
RETURNS TABLE (
|
|
id UUID,
|
|
report_name VARCHAR(255),
|
|
status reports.execution_status,
|
|
executed_at TIMESTAMPTZ,
|
|
execution_time_ms INTEGER
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT re.id, rd.name, re.status, re.created_at, re.execution_time_ms
|
|
FROM reports.report_executions re
|
|
JOIN reports.report_definitions rd ON rd.id = re.report_definition_id
|
|
WHERE re.tenant_id = p_tenant_id
|
|
ORDER BY re.created_at DESC
|
|
LIMIT p_limit;
|
|
END;
|
|
$$ LANGUAGE plpgsql STABLE;
|
|
|
|
-- =====================
|
|
-- COMENTARIOS
|
|
-- =====================
|
|
COMMENT ON SCHEMA reports IS 'Schema para sistema de reportes y analytics';
|
|
COMMENT ON TABLE reports.report_definitions IS 'Definiciones de reportes';
|
|
COMMENT ON TABLE reports.report_executions IS 'Historial de ejecuciones de reportes';
|
|
COMMENT ON TABLE reports.report_schedules IS 'Programacion de reportes automaticos';
|
|
COMMENT ON TABLE reports.report_recipients IS 'Destinatarios de reportes programados';
|
|
COMMENT ON TABLE reports.dashboards IS 'Dashboards personalizados';
|
|
COMMENT ON TABLE reports.dashboard_widgets IS 'Widgets de dashboards';
|
|
COMMENT ON TABLE reports.custom_reports IS 'Reportes personalizados por usuario';
|
|
COMMENT ON TABLE reports.data_model_entities IS 'Modelo de datos para report builder';
|
|
COMMENT ON TABLE reports.data_model_fields IS 'Campos del modelo de datos';
|
|
COMMENT ON TABLE reports.data_model_relationships IS 'Relaciones entre entidades';
|