From 4504c1ded28369c722d5db44fb9a4d403612873d Mon Sep 17 00:00:00 2001 From: Marcos Reifonas Date: Fri, 21 Aug 2026 15:27:15 +0000 Subject: [PATCH] Fix: trigger de validacao e desambiguacao de FKs na tela de prioridades --- scripts/check_db.mjs | 30 +++++ scripts/fix_db_trigger.mjs | 114 ++++++++++++++++++ scripts/inspect_db.mjs | 25 ++++ src/hooks/useItensPrioridadeFabricacao.tsx | 16 +-- .../useItensPrioridadeFabricacaoFiltrado.tsx | 4 +- 5 files changed, 179 insertions(+), 10 deletions(-) create mode 100644 scripts/check_db.mjs create mode 100644 scripts/fix_db_trigger.mjs create mode 100644 scripts/inspect_db.mjs diff --git a/scripts/check_db.mjs b/scripts/check_db.mjs new file mode 100644 index 0000000..9fef526 --- /dev/null +++ b/scripts/check_db.mjs @@ -0,0 +1,30 @@ +import { createClient } from '@supabase/supabase-js'; + +const supabaseUrl = 'https://supabase.reifonas.cloud'; +const supabaseKey = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsImlhdCI6MTc3Mjk5NTUwMCwiZXhwIjo0OTI4NjY5MTAwLCJyb2xlIjoic2VydmljZV9yb2xlIn0._n2Kj2f29z1u0pOYUGqAr-1Xjt-xQpK9KDhhhGvOIro'; + +const sbERP = createClient(supabaseUrl, supabaseKey, { db: { schema: 'TS_ERP' } }); + +async function check() { + console.log("Testing insert into itens_prioridade_fabricacao..."); + + const { data: pecas } = await sbERP.from('pecas').select('id, of_number, etapa_fase').limit(1); + const { data: prios } = await sbERP.from('prioridades_fabricacao').select('id').limit(1); + + console.log("Peca:", pecas); + console.log("Prioridade:", prios); + + if (pecas && pecas[0] && prios && prios[0]) { + const { data, error } = await sbERP.from('itens_prioridade_fabricacao').insert([{ + prioridade_fabricacao_id: prios[0].id, + peca_id: pecas[0].id, + quantidade_priorizada: 1, + peso_total: 10, + ordem_fabricacao: 1 + }]).select(); + + console.log("Insert result:", { data, error }); + } +} + +check(); diff --git a/scripts/fix_db_trigger.mjs b/scripts/fix_db_trigger.mjs new file mode 100644 index 0000000..b9eeb16 --- /dev/null +++ b/scripts/fix_db_trigger.mjs @@ -0,0 +1,114 @@ +import pkg from 'pg'; +const { Client } = pkg; + +const connectionString = 'postgres://supabase_admin:Xz0oyb6ArGYG5uAVTVwcvJxRrMuT7EIJ@10.0.2.6:5432/postgres'; + +async function main() { + const client = new Client({ connectionString }); + try { + await client.connect(); + console.log("Connected to Postgres successfully!"); + + // 1. Fix trigger function to have explicit search_path or schema qualification + const fixTriggerSQL = ` + -- Criar função para verificar disponibilidade de peças no schema TS_ERP com search_path explícito + CREATE OR REPLACE FUNCTION "TS_ERP".verificar_disponibilidade_peca( + p_peca_id uuid, + p_quantidade_adicional numeric, + p_item_id uuid DEFAULT NULL + ) + RETURNS boolean + LANGUAGE plpgsql + SECURITY DEFINER + SET search_path = 'TS_ERP', 'public' + AS $$ + DECLARE + quantidade_total_peca numeric; + quantidade_ja_priorizada numeric; + quantidade_disponivel numeric; + BEGIN + SELECT quantidade INTO quantidade_total_peca + FROM "TS_ERP".pecas + WHERE id = p_peca_id; + + IF quantidade_total_peca IS NULL THEN + RAISE EXCEPTION 'Peça não encontrada'; + END IF; + + SELECT COALESCE(SUM(quantidade_priorizada), 0) INTO quantidade_ja_priorizada + FROM "TS_ERP".itens_prioridade_fabricacao + WHERE peca_id = p_peca_id + AND (p_item_id IS NULL OR id != p_item_id); + + quantidade_disponivel := quantidade_total_peca - quantidade_ja_priorizada; + + IF p_quantidade_adicional > quantidade_disponivel THEN + RAISE EXCEPTION 'Quantidade solicitada (%) excede o disponível (%) para esta peça', + p_quantidade_adicional, quantidade_disponivel; + END IF; + + RETURN true; + END; + $$; + + -- Também criar no schema public por garantia se algum cliente chamar public.verificar_disponibilidade_peca + CREATE OR REPLACE FUNCTION public.verificar_disponibilidade_peca( + p_peca_id uuid, + p_quantidade_adicional numeric, + p_item_id uuid DEFAULT NULL + ) + RETURNS boolean + LANGUAGE plpgsql + SECURITY DEFINER + SET search_path = 'TS_ERP', 'public' + AS $$ + BEGIN + RETURN "TS_ERP".verificar_disponibilidade_peca(p_peca_id, p_quantidade_adicional, p_item_id); + END; + $$; + + -- Atualizar trigger_validar_item_prioridade com SET search_path + CREATE OR REPLACE FUNCTION "TS_ERP".trigger_validar_item_prioridade() + RETURNS trigger + LANGUAGE plpgsql + SECURITY DEFINER + SET search_path = 'TS_ERP', 'public' + AS $$ + BEGIN + IF TG_OP = 'INSERT' THEN + PERFORM "TS_ERP".verificar_disponibilidade_peca(NEW.peca_id, NEW.quantidade_priorizada); + RETURN NEW; + END IF; + + IF TG_OP = 'UPDATE' THEN + PERFORM "TS_ERP".verificar_disponibilidade_peca(NEW.peca_id, NEW.quantidade_priorizada, NEW.id); + RETURN NEW; + END IF; + + RETURN NULL; + END; + $$; + + -- Garantir o trigger na tabela + DROP TRIGGER IF EXISTS trigger_validar_disponibilidade_item_prioridade ON "TS_ERP".itens_prioridade_fabricacao; + CREATE TRIGGER trigger_validar_disponibilidade_item_prioridade + BEFORE INSERT OR UPDATE ON "TS_ERP".itens_prioridade_fabricacao + FOR EACH ROW + EXECUTE FUNCTION "TS_ERP".trigger_validar_item_prioridade(); + + -- Reconfigurar permissões + GRANT EXECUTE ON FUNCTION "TS_ERP".verificar_disponibilidade_peca(uuid, numeric, uuid) TO anon, authenticated, service_role; + GRANT EXECUTE ON FUNCTION public.verificar_disponibilidade_peca(uuid, numeric, uuid) TO anon, authenticated, service_role; + `; + + await client.query(fixTriggerSQL); + console.log("✅ Trigger e funções de verificação atualizadas com sucesso no banco de dados!"); + + } catch (err) { + console.error("❌ Erro ao conectar/executar no Postgres:", err); + } finally { + await client.end(); + } +} + +main(); diff --git a/scripts/inspect_db.mjs b/scripts/inspect_db.mjs new file mode 100644 index 0000000..503ceb1 --- /dev/null +++ b/scripts/inspect_db.mjs @@ -0,0 +1,25 @@ +import { createClient } from '@supabase/supabase-js'; + +const supabaseUrl = 'https://supabase.reifonas.cloud'; +const supabaseKey = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdXBhYmFzZSIsImlhdCI6MTc3Mjk5NTUwMCwiZXhwIjo0OTI4NjY5MTAwLCJyb2xlIjoic2VydmljZV9yb2xlIn0._n2Kj2f29z1u0pOYUGqAr-1Xjt-xQpK9KDhhhGvOIro'; + +const sbERP = createClient(supabaseUrl, supabaseKey, { db: { schema: 'TS_ERP' } }); +const sbPub = createClient(supabaseUrl, supabaseKey, { db: { schema: 'public' } }); + +async function inspect() { + console.log("Checking RPCs..."); + // Let's test calling RPC verificar_disponibilidade_peca on TS_ERP and public + const { data: pecas } = await sbERP.from('pecas').select('id').limit(1); + if (pecas && pecas[0]) { + const pecaId = pecas[0].id; + console.log("Calling rpc on TS_ERP..."); + const resERP = await sbERP.rpc('verificar_disponibilidade_peca', { p_peca_id: pecaId, p_quantidade_adicional: 1 }); + console.log("TS_ERP RPC result:", resERP); + + console.log("Calling rpc on public..."); + const resPub = await sbPub.rpc('verificar_disponibilidade_peca', { p_peca_id: pecaId, p_quantidade_adicional: 1 }); + console.log("public RPC result:", resPub); + } +} + +inspect(); diff --git a/src/hooks/useItensPrioridadeFabricacao.tsx b/src/hooks/useItensPrioridadeFabricacao.tsx index 2e61734..723db88 100644 --- a/src/hooks/useItensPrioridadeFabricacao.tsx +++ b/src/hooks/useItensPrioridadeFabricacao.tsx @@ -44,14 +44,14 @@ export const useItensPrioridadeFabricacao = () => { .from('itens_prioridade_fabricacao') .select(` *, - peca:pecas(marca, descricao, peso_unitario, quantidade, tem_componentes, of_number, etapa_fase), - prioridade_fabricacao:prioridades_fabricacao( + peca:pecas!itens_prioridade_fabricacao_peca_id_fkey(marca, descricao, peso_unitario, quantidade, tem_componentes, of_number, etapa_fase), + prioridade_fabricacao:prioridades_fabricacao!itens_prioridade_fabricacao_prioridade_fabricacao_id_fkey( of_number, etapa_fase, revisao, data_ultima_modificacao, modificado_por, - prioridade_config:prioridades_config(codigo, nome, cor) + prioridade_config:prioridades_config!prioridades_fabricacao_prioridade_id_fkey(codigo, nome, cor) ) `) .order('ordem_fabricacao', { ascending: true }); @@ -124,8 +124,8 @@ export const useItensPrioridadeFabricacao = () => { .from('itens_prioridade_fabricacao') .select(` *, - peca:pecas(of_number, etapa_fase, marca), - prioridade_fabricacao:prioridades_fabricacao(of_number, etapa_fase) + peca:pecas!itens_prioridade_fabricacao_peca_id_fkey(of_number, etapa_fase, marca), + prioridade_fabricacao:prioridades_fabricacao!itens_prioridade_fabricacao_prioridade_fabricacao_id_fkey(of_number, etapa_fase) `) .eq('id', itemId) .single(); @@ -215,8 +215,8 @@ export const useItensPrioridadeFabricacao = () => { .select(` id, prioridade_fabricacao_id, - peca:pecas(of_number, etapa_fase, marca), - prioridade_fabricacao:prioridades_fabricacao(of_number, etapa_fase) + peca:pecas!itens_prioridade_fabricacao_peca_id_fkey(of_number, etapa_fase, marca), + prioridade_fabricacao:prioridades_fabricacao!itens_prioridade_fabricacao_prioridade_fabricacao_id_fkey(of_number, etapa_fase) `) .in('id', idsParaRemover); @@ -341,7 +341,7 @@ export const useItensPrioridadeFabricacao = () => { .from('itens_prioridade_fabricacao') .select(` *, - prioridade_fabricacao:prioridades_fabricacao( + prioridade_fabricacao:prioridades_fabricacao!itens_prioridade_fabricacao_prioridade_fabricacao_id_fkey( of_number, etapa_fase ) diff --git a/src/hooks/useItensPrioridadeFabricacaoFiltrado.tsx b/src/hooks/useItensPrioridadeFabricacaoFiltrado.tsx index 2e2dacc..51c1a36 100644 --- a/src/hooks/useItensPrioridadeFabricacaoFiltrado.tsx +++ b/src/hooks/useItensPrioridadeFabricacaoFiltrado.tsx @@ -54,7 +54,7 @@ export const useItensPrioridadeFabricacaoFiltrado = () => { .select(` revisao, data_ultima_modificacao, - profiles:modificado_por(full_name) + profiles:prioridades_fabricacao_modificado_por_profiles_fkey(full_name) `) .eq('of_number', ofSelecionada) .eq('etapa_fase', faseSelecionada) @@ -71,7 +71,7 @@ export const useItensPrioridadeFabricacaoFiltrado = () => { setVersaoAtual({ revisao: data.revisao || 0, dataModificacao: data.data_ultima_modificacao || new Date().toISOString(), - modificadoPor: (data.profiles as any)?.full_name + modificadoPor: (data.profiles as { full_name?: string } | null)?.full_name }); } else { setVersaoAtual({