Fix: trigger de validacao e desambiguacao de FKs na tela de prioridades

This commit is contained in:
2026-08-21 15:27:15 +00:00
parent f72b7c86fd
commit 4504c1ded2
5 changed files with 179 additions and 10 deletions
+30
View File
@@ -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();
+114
View File
@@ -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();
+25
View File
@@ -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();
+8 -8
View File
@@ -44,14 +44,14 @@ export const useItensPrioridadeFabricacao = () => {
.from('itens_prioridade_fabricacao') .from('itens_prioridade_fabricacao')
.select(` .select(`
*, *,
peca:pecas(marca, descricao, peso_unitario, quantidade, tem_componentes, of_number, etapa_fase), peca:pecas!itens_prioridade_fabricacao_peca_id_fkey(marca, descricao, peso_unitario, quantidade, tem_componentes, of_number, etapa_fase),
prioridade_fabricacao:prioridades_fabricacao( prioridade_fabricacao:prioridades_fabricacao!itens_prioridade_fabricacao_prioridade_fabricacao_id_fkey(
of_number, of_number,
etapa_fase, etapa_fase,
revisao, revisao,
data_ultima_modificacao, data_ultima_modificacao,
modificado_por, 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 }); .order('ordem_fabricacao', { ascending: true });
@@ -124,8 +124,8 @@ export const useItensPrioridadeFabricacao = () => {
.from('itens_prioridade_fabricacao') .from('itens_prioridade_fabricacao')
.select(` .select(`
*, *,
peca:pecas(of_number, etapa_fase, marca), peca:pecas!itens_prioridade_fabricacao_peca_id_fkey(of_number, etapa_fase, marca),
prioridade_fabricacao:prioridades_fabricacao(of_number, etapa_fase) prioridade_fabricacao:prioridades_fabricacao!itens_prioridade_fabricacao_prioridade_fabricacao_id_fkey(of_number, etapa_fase)
`) `)
.eq('id', itemId) .eq('id', itemId)
.single(); .single();
@@ -215,8 +215,8 @@ export const useItensPrioridadeFabricacao = () => {
.select(` .select(`
id, id,
prioridade_fabricacao_id, prioridade_fabricacao_id,
peca:pecas(of_number, etapa_fase, marca), peca:pecas!itens_prioridade_fabricacao_peca_id_fkey(of_number, etapa_fase, marca),
prioridade_fabricacao:prioridades_fabricacao(of_number, etapa_fase) prioridade_fabricacao:prioridades_fabricacao!itens_prioridade_fabricacao_prioridade_fabricacao_id_fkey(of_number, etapa_fase)
`) `)
.in('id', idsParaRemover); .in('id', idsParaRemover);
@@ -341,7 +341,7 @@ export const useItensPrioridadeFabricacao = () => {
.from('itens_prioridade_fabricacao') .from('itens_prioridade_fabricacao')
.select(` .select(`
*, *,
prioridade_fabricacao:prioridades_fabricacao( prioridade_fabricacao:prioridades_fabricacao!itens_prioridade_fabricacao_prioridade_fabricacao_id_fkey(
of_number, of_number,
etapa_fase etapa_fase
) )
@@ -54,7 +54,7 @@ export const useItensPrioridadeFabricacaoFiltrado = () => {
.select(` .select(`
revisao, revisao,
data_ultima_modificacao, data_ultima_modificacao,
profiles:modificado_por(full_name) profiles:prioridades_fabricacao_modificado_por_profiles_fkey(full_name)
`) `)
.eq('of_number', ofSelecionada) .eq('of_number', ofSelecionada)
.eq('etapa_fase', faseSelecionada) .eq('etapa_fase', faseSelecionada)
@@ -71,7 +71,7 @@ export const useItensPrioridadeFabricacaoFiltrado = () => {
setVersaoAtual({ setVersaoAtual({
revisao: data.revisao || 0, revisao: data.revisao || 0,
dataModificacao: data.data_ultima_modificacao || new Date().toISOString(), 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 { } else {
setVersaoAtual({ setVersaoAtual({