Sistema NEXUS v3.4 migrado con: Estructura principal: - core/orchestration: Sistema SIMCO + CAPVED (27 directivas, 28 perfiles) - core/catalog: Catalogo de funcionalidades reutilizables - shared/knowledge-base: Base de conocimiento compartida - devtools/scripts: Herramientas de desarrollo - control-plane/registries: Control de servicios y CI/CD - orchestration/: Configuracion de orquestacion de agentes Proyectos incluidos (11): - gamilit (submodule -> GitHub) - trading-platform (OrbiquanTIA) - erp-suite con 5 verticales: - erp-core, construccion, vidrio-templado - mecanicas-diesel, retail, clinicas - betting-analytics - inmobiliaria-analytics - platform_marketing_content - pos-micro, erp-basico Configuracion: - .gitignore completo para Node.js/Python/Docker - gamilit como submodule (git@github.com:rckrdmrd/gamilit-workspace.git) - Sistema de puertos estandarizado (3005-3199) Generated with NEXUS v3.4 Migration System EPIC-010: Configuracion Git y Repositorios
469 lines
19 KiB
SQL
469 lines
19 KiB
SQL
-- ============================================================================
|
|
-- ET-PURCH: Row-Level Security (RLS) Policies
|
|
-- Módulo: MAI-004 - Compras e Inventarios
|
|
-- Tablas: purchases schema (todas las tablas del módulo)
|
|
-- Fecha: 2025-11-20
|
|
-- Descripción: Políticas de seguridad para aislamiento multi-tenant (constructora)
|
|
-- ============================================================================
|
|
|
|
-- ============================================================================
|
|
-- HABILITAR RLS EN TODAS LAS TABLAS
|
|
-- ============================================================================
|
|
|
|
ALTER TABLE purchases.suppliers ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE purchases.supplier_contacts ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE purchases.supplier_price_lists ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE purchases.purchase_requisitions ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE purchases.requisition_items ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE purchases.purchase_orders ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE purchases.purchase_order_items ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE purchases.warehouses ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE purchases.inventory_items ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE purchases.inventory_movements ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE purchases.stock_alerts ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: SUPPLIERS (Proveedores)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "suppliers_select_own_constructora" ON purchases.suppliers;
|
|
CREATE POLICY "suppliers_select_own_constructora"
|
|
ON purchases.suppliers FOR SELECT TO authenticated
|
|
USING (constructora_id = public.get_current_constructora_id());
|
|
|
|
COMMENT ON POLICY "suppliers_select_own_constructora" ON purchases.suppliers IS
|
|
'Permite ver solo proveedores de la constructora actual.
|
|
Aislamiento: tenant (constructora) level.';
|
|
|
|
DROP POLICY IF EXISTS "suppliers_insert_own_constructora" ON purchases.suppliers;
|
|
CREATE POLICY "suppliers_insert_own_constructora"
|
|
ON purchases.suppliers FOR INSERT TO authenticated
|
|
WITH CHECK (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin', 'purchases_manager')
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "suppliers_update_own_constructora" ON purchases.suppliers;
|
|
CREATE POLICY "suppliers_update_own_constructora"
|
|
ON purchases.suppliers FOR UPDATE TO authenticated
|
|
USING (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin', 'purchases_manager')
|
|
)
|
|
WITH CHECK (constructora_id = public.get_current_constructora_id());
|
|
|
|
DROP POLICY IF EXISTS "suppliers_delete_own_constructora" ON purchases.suppliers;
|
|
CREATE POLICY "suppliers_delete_own_constructora"
|
|
ON purchases.suppliers FOR DELETE TO authenticated
|
|
USING (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin')
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: SUPPLIER_CONTACTS (Contactos de Proveedores)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "supplier_contacts_select_own" ON purchases.supplier_contacts;
|
|
CREATE POLICY "supplier_contacts_select_own"
|
|
ON purchases.supplier_contacts FOR SELECT TO authenticated
|
|
USING (
|
|
supplier_id IN (
|
|
SELECT id FROM purchases.suppliers
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "supplier_contacts_insert_own" ON purchases.supplier_contacts;
|
|
CREATE POLICY "supplier_contacts_insert_own"
|
|
ON purchases.supplier_contacts FOR INSERT TO authenticated
|
|
WITH CHECK (
|
|
supplier_id IN (
|
|
SELECT id FROM purchases.suppliers
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "supplier_contacts_update_own" ON purchases.supplier_contacts;
|
|
CREATE POLICY "supplier_contacts_update_own"
|
|
ON purchases.supplier_contacts FOR UPDATE TO authenticated
|
|
USING (
|
|
supplier_id IN (
|
|
SELECT id FROM purchases.suppliers
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "supplier_contacts_delete_own" ON purchases.supplier_contacts;
|
|
CREATE POLICY "supplier_contacts_delete_own"
|
|
ON purchases.supplier_contacts FOR DELETE TO authenticated
|
|
USING (
|
|
supplier_id IN (
|
|
SELECT id FROM purchases.suppliers
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: SUPPLIER_PRICE_LISTS (Listas de Precios)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "price_lists_select_own" ON purchases.supplier_price_lists;
|
|
CREATE POLICY "price_lists_select_own"
|
|
ON purchases.supplier_price_lists FOR SELECT TO authenticated
|
|
USING (
|
|
supplier_id IN (
|
|
SELECT id FROM purchases.suppliers
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "price_lists_insert_own" ON purchases.supplier_price_lists;
|
|
CREATE POLICY "price_lists_insert_own"
|
|
ON purchases.supplier_price_lists FOR INSERT TO authenticated
|
|
WITH CHECK (
|
|
supplier_id IN (
|
|
SELECT id FROM purchases.suppliers
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: PURCHASE_REQUISITIONS (Requisiciones)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "requisitions_select_own" ON purchases.purchase_requisitions;
|
|
CREATE POLICY "requisitions_select_own"
|
|
ON purchases.purchase_requisitions FOR SELECT TO authenticated
|
|
USING (constructora_id = public.get_current_constructora_id());
|
|
|
|
COMMENT ON POLICY "requisitions_select_own" ON purchases.purchase_requisitions IS
|
|
'Permite ver solo requisiciones de la constructora actual.
|
|
Usado en: Listado de requisiciones, aprobaciones, conversión a OC.';
|
|
|
|
DROP POLICY IF EXISTS "requisitions_insert_own" ON purchases.purchase_requisitions;
|
|
CREATE POLICY "requisitions_insert_own"
|
|
ON purchases.purchase_requisitions FOR INSERT TO authenticated
|
|
WITH CHECK (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin', 'engineer', 'resident', 'purchases_manager')
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "requisitions_update_own" ON purchases.purchase_requisitions;
|
|
CREATE POLICY "requisitions_update_own"
|
|
ON purchases.purchase_requisitions FOR UPDATE TO authenticated
|
|
USING (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND (
|
|
-- Creador puede editar si está en draft
|
|
(created_by = public.get_current_user_id() AND status = 'draft')
|
|
OR
|
|
-- Purchases Manager/Director pueden editar
|
|
public.get_current_user_role() IN ('director', 'admin', 'purchases_manager')
|
|
)
|
|
)
|
|
WITH CHECK (constructora_id = public.get_current_constructora_id());
|
|
|
|
COMMENT ON POLICY "requisitions_update_own" ON purchases.purchase_requisitions IS
|
|
'Permisos diferenciados:
|
|
- Creador: Solo en estado draft
|
|
- Purchases Manager/Director: Cualquier estado';
|
|
|
|
DROP POLICY IF EXISTS "requisitions_delete_own" ON purchases.purchase_requisitions;
|
|
CREATE POLICY "requisitions_delete_own"
|
|
ON purchases.purchase_requisitions FOR DELETE TO authenticated
|
|
USING (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin')
|
|
AND status = 'draft'
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: REQUISITION_ITEMS (Partidas de Requisición)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "requisition_items_select_own" ON purchases.requisition_items;
|
|
CREATE POLICY "requisition_items_select_own"
|
|
ON purchases.requisition_items FOR SELECT TO authenticated
|
|
USING (
|
|
requisition_id IN (
|
|
SELECT id FROM purchases.purchase_requisitions
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "requisition_items_insert_own" ON purchases.requisition_items;
|
|
CREATE POLICY "requisition_items_insert_own"
|
|
ON purchases.requisition_items FOR INSERT TO authenticated
|
|
WITH CHECK (
|
|
requisition_id IN (
|
|
SELECT id FROM purchases.purchase_requisitions
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "requisition_items_update_own" ON purchases.requisition_items;
|
|
CREATE POLICY "requisition_items_update_own"
|
|
ON purchases.requisition_items FOR UPDATE TO authenticated
|
|
USING (
|
|
requisition_id IN (
|
|
SELECT id FROM purchases.purchase_requisitions
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "requisition_items_delete_own" ON purchases.requisition_items;
|
|
CREATE POLICY "requisition_items_delete_own"
|
|
ON purchases.requisition_items FOR DELETE TO authenticated
|
|
USING (
|
|
requisition_id IN (
|
|
SELECT id FROM purchases.purchase_requisitions
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
AND status = 'draft'
|
|
)
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: PURCHASE_ORDERS (Órdenes de Compra)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "purchase_orders_select_own" ON purchases.purchase_orders;
|
|
CREATE POLICY "purchase_orders_select_own"
|
|
ON purchases.purchase_orders FOR SELECT TO authenticated
|
|
USING (constructora_id = public.get_current_constructora_id());
|
|
|
|
DROP POLICY IF EXISTS "purchase_orders_insert_own" ON purchases.purchase_orders;
|
|
CREATE POLICY "purchase_orders_insert_own"
|
|
ON purchases.purchase_orders FOR INSERT TO authenticated
|
|
WITH CHECK (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin', 'purchases_manager')
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "purchase_orders_update_own" ON purchases.purchase_orders;
|
|
CREATE POLICY "purchase_orders_update_own"
|
|
ON purchases.purchase_orders FOR UPDATE TO authenticated
|
|
USING (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin', 'purchases_manager')
|
|
)
|
|
WITH CHECK (constructora_id = public.get_current_constructora_id());
|
|
|
|
DROP POLICY IF EXISTS "purchase_orders_delete_own" ON purchases.purchase_orders;
|
|
CREATE POLICY "purchase_orders_delete_own"
|
|
ON purchases.purchase_orders FOR DELETE TO authenticated
|
|
USING (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin')
|
|
AND status IN ('draft', 'pending_approval')
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: PURCHASE_ORDER_ITEMS (Partidas de OC)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "po_items_select_own" ON purchases.purchase_order_items;
|
|
CREATE POLICY "po_items_select_own"
|
|
ON purchases.purchase_order_items FOR SELECT TO authenticated
|
|
USING (
|
|
purchase_order_id IN (
|
|
SELECT id FROM purchases.purchase_orders
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "po_items_insert_own" ON purchases.purchase_order_items;
|
|
CREATE POLICY "po_items_insert_own"
|
|
ON purchases.purchase_order_items FOR INSERT TO authenticated
|
|
WITH CHECK (
|
|
purchase_order_id IN (
|
|
SELECT id FROM purchases.purchase_orders
|
|
WHERE constructora_id = public.get_current_constructora_id()
|
|
)
|
|
);
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: WAREHOUSES (Almacenes)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "warehouses_select_own" ON purchases.warehouses;
|
|
CREATE POLICY "warehouses_select_own"
|
|
ON purchases.warehouses FOR SELECT TO authenticated
|
|
USING (constructora_id = public.get_current_constructora_id());
|
|
|
|
DROP POLICY IF EXISTS "warehouses_insert_own" ON purchases.warehouses;
|
|
CREATE POLICY "warehouses_insert_own"
|
|
ON purchases.warehouses FOR INSERT TO authenticated
|
|
WITH CHECK (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin')
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "warehouses_update_own" ON purchases.warehouses;
|
|
CREATE POLICY "warehouses_update_own"
|
|
ON purchases.warehouses FOR UPDATE TO authenticated
|
|
USING (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin', 'warehouse_manager')
|
|
)
|
|
WITH CHECK (constructora_id = public.get_current_constructora_id());
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: INVENTORY_ITEMS (Items de Inventario)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "inventory_items_select_own" ON purchases.inventory_items;
|
|
CREATE POLICY "inventory_items_select_own"
|
|
ON purchases.inventory_items FOR SELECT TO authenticated
|
|
USING (constructora_id = public.get_current_constructora_id());
|
|
|
|
DROP POLICY IF EXISTS "inventory_items_insert_own" ON purchases.inventory_items;
|
|
CREATE POLICY "inventory_items_insert_own"
|
|
ON purchases.inventory_items FOR INSERT TO authenticated
|
|
WITH CHECK (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin', 'warehouse_manager', 'purchases_manager')
|
|
);
|
|
|
|
DROP POLICY IF EXISTS "inventory_items_update_own" ON purchases.inventory_items;
|
|
CREATE POLICY "inventory_items_update_own"
|
|
ON purchases.inventory_items FOR UPDATE TO authenticated
|
|
USING (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin', 'warehouse_manager')
|
|
)
|
|
WITH CHECK (constructora_id = public.get_current_constructora_id());
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: INVENTORY_MOVEMENTS (Movimientos de Inventario)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "inventory_movements_select_own" ON purchases.inventory_movements;
|
|
CREATE POLICY "inventory_movements_select_own"
|
|
ON purchases.inventory_movements FOR SELECT TO authenticated
|
|
USING (constructora_id = public.get_current_constructora_id());
|
|
|
|
DROP POLICY IF EXISTS "inventory_movements_insert_own" ON purchases.inventory_movements;
|
|
CREATE POLICY "inventory_movements_insert_own"
|
|
ON purchases.inventory_movements FOR INSERT TO authenticated
|
|
WITH CHECK (
|
|
constructora_id = public.get_current_constructora_id()
|
|
AND public.get_current_user_role() IN ('director', 'admin', 'warehouse_manager', 'resident')
|
|
);
|
|
|
|
COMMENT ON POLICY "inventory_movements_insert_own" ON purchases.inventory_movements IS
|
|
'Permisos para registrar movimientos:
|
|
- Warehouse Manager: Entradas/Salidas/Ajustes
|
|
- Resident: Solo salidas por consumo en obra';
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS RLS: STOCK_ALERTS (Alertas de Stock)
|
|
-- ============================================================================
|
|
|
|
DROP POLICY IF EXISTS "stock_alerts_select_own" ON purchases.stock_alerts;
|
|
CREATE POLICY "stock_alerts_select_own"
|
|
ON purchases.stock_alerts FOR SELECT TO authenticated
|
|
USING (constructora_id = public.get_current_constructora_id());
|
|
|
|
-- Las alertas son generadas automáticamente por triggers
|
|
|
|
-- ============================================================================
|
|
-- POLÍTICAS SUPER ADMIN (Bypass para soporte)
|
|
-- ============================================================================
|
|
|
|
DO $$
|
|
DECLARE
|
|
table_name TEXT;
|
|
tables TEXT[] := ARRAY[
|
|
'suppliers', 'supplier_contacts', 'supplier_price_lists',
|
|
'purchase_requisitions', 'requisition_items',
|
|
'purchase_orders', 'purchase_order_items',
|
|
'warehouses', 'inventory_items', 'inventory_movements',
|
|
'stock_alerts'
|
|
];
|
|
BEGIN
|
|
FOREACH table_name IN ARRAY tables
|
|
LOOP
|
|
EXECUTE format('
|
|
DROP POLICY IF EXISTS "%s_super_admin_all" ON purchases.%s;
|
|
CREATE POLICY "%s_super_admin_all" ON purchases.%s
|
|
FOR ALL TO authenticated
|
|
USING (public.get_current_user_role() = ''super_admin'')
|
|
WITH CHECK (public.get_current_user_role() = ''super_admin'');
|
|
', table_name, table_name, table_name, table_name);
|
|
END LOOP;
|
|
END $$;
|
|
|
|
-- ============================================================================
|
|
-- ÍNDICES PARA PERFORMANCE
|
|
-- ============================================================================
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_suppliers_constructora ON purchases.suppliers(constructora_id);
|
|
CREATE INDEX IF NOT EXISTS idx_suppliers_status ON purchases.suppliers(constructora_id, status);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_requisitions_constructora ON purchases.purchase_requisitions(constructora_id);
|
|
CREATE INDEX IF NOT EXISTS idx_requisitions_project ON purchases.purchase_requisitions(project_id);
|
|
CREATE INDEX IF NOT EXISTS idx_requisitions_status ON purchases.purchase_requisitions(constructora_id, status);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_purchase_orders_constructora ON purchases.purchase_orders(constructora_id);
|
|
CREATE INDEX IF NOT EXISTS idx_purchase_orders_supplier ON purchases.purchase_orders(supplier_id);
|
|
CREATE INDEX IF NOT EXISTS idx_purchase_orders_status ON purchases.purchase_orders(constructora_id, status);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_warehouses_constructora ON purchases.warehouses(constructora_id);
|
|
CREATE INDEX IF NOT EXISTS idx_warehouses_project ON purchases.warehouses(project_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_inventory_items_constructora ON purchases.inventory_items(constructora_id);
|
|
CREATE INDEX IF NOT EXISTS idx_inventory_items_warehouse ON purchases.inventory_items(warehouse_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_movements_constructora ON purchases.inventory_movements(constructora_id);
|
|
CREATE INDEX IF NOT EXISTS idx_movements_item ON purchases.inventory_movements(inventory_item_id);
|
|
CREATE INDEX IF NOT EXISTS idx_movements_date ON purchases.inventory_movements(movement_date);
|
|
|
|
COMMENT ON INDEX purchases.idx_requisitions_constructora IS
|
|
'Optimiza queries RLS filtrados por constructora_id.';
|
|
|
|
-- ============================================================================
|
|
-- GRANTS
|
|
-- ============================================================================
|
|
|
|
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA purchases TO authenticated;
|
|
GRANT USAGE ON SCHEMA purchases TO authenticated;
|
|
|
|
-- ============================================================================
|
|
-- VERIFICACIÓN FINAL
|
|
-- ============================================================================
|
|
|
|
DO $$
|
|
DECLARE
|
|
v_tables TEXT[] := ARRAY[
|
|
'suppliers', 'purchase_requisitions', 'purchase_orders',
|
|
'warehouses', 'inventory_items', 'inventory_movements'
|
|
];
|
|
v_table TEXT;
|
|
v_rls_enabled BOOLEAN;
|
|
v_policy_count INTEGER;
|
|
BEGIN
|
|
FOREACH v_table IN ARRAY v_tables
|
|
LOOP
|
|
SELECT relrowsecurity INTO v_rls_enabled
|
|
FROM pg_class
|
|
WHERE relname = v_table AND relnamespace = 'purchases'::regnamespace;
|
|
|
|
SELECT COUNT(*) INTO v_policy_count
|
|
FROM pg_policies
|
|
WHERE schemaname = 'purchases' AND tablename = v_table;
|
|
|
|
IF NOT v_rls_enabled THEN
|
|
RAISE EXCEPTION 'CRITICAL: RLS no habilitado en purchases.%', v_table;
|
|
END IF;
|
|
|
|
IF v_policy_count < 1 THEN
|
|
RAISE WARNING 'purchases.%: Solo % políticas', v_table, v_policy_count;
|
|
END IF;
|
|
|
|
RAISE NOTICE '✓ purchases.%: RLS habilitado con % políticas', v_table, v_policy_count;
|
|
END LOOP;
|
|
|
|
RAISE NOTICE '✓ Módulo MAI-004: Todas las tablas tienen RLS habilitado';
|
|
END $$;
|