🚀 Initial commit: Versão atual do TrackSteel APP
This commit is contained in:
357
supabase/migrations/create_get_itens_disponiveis_rpc.sql
Normal file
357
supabase/migrations/create_get_itens_disponiveis_rpc.sql
Normal file
@@ -0,0 +1,357 @@
|
||||
-- Função RPC otimizada para buscar itens disponíveis para apontamento
|
||||
-- Esta função substitui múltiplas queries por uma única consulta otimizada
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_itens_disponiveis(
|
||||
p_of_number TEXT DEFAULT NULL,
|
||||
p_processo_id UUID DEFAULT NULL,
|
||||
p_include_componentes BOOLEAN DEFAULT TRUE,
|
||||
p_limit INTEGER DEFAULT 100
|
||||
)
|
||||
RETURNS TABLE (
|
||||
item_id UUID,
|
||||
item_type TEXT, -- 'peca' ou 'componente'
|
||||
marca TEXT,
|
||||
descricao TEXT,
|
||||
peso_unitario NUMERIC,
|
||||
quantidade_total NUMERIC,
|
||||
quantidade_processada NUMERIC,
|
||||
quantidade_disponivel NUMERIC,
|
||||
etapa_fase TEXT,
|
||||
processo_atual_id UUID,
|
||||
processo_atual_nome TEXT,
|
||||
processo_atual_ordem INTEGER,
|
||||
proximos_processos JSONB,
|
||||
peca_pai_id UUID,
|
||||
peca_pai_marca TEXT
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
WITH
|
||||
-- CTE para buscar peças da OF
|
||||
pecas_of AS (
|
||||
SELECT
|
||||
p.id,
|
||||
p.marca,
|
||||
p.descricao,
|
||||
p.peso_unitario,
|
||||
p.quantidade,
|
||||
p.etapa_fase,
|
||||
p.of_number
|
||||
FROM pecas p
|
||||
WHERE (p_of_number IS NULL OR p.of_number = p_of_number)
|
||||
),
|
||||
|
||||
-- CTE para buscar componentes das peças (se solicitado)
|
||||
componentes_of AS (
|
||||
SELECT
|
||||
c.id,
|
||||
c.marca_componente as marca,
|
||||
c.descricao,
|
||||
c.peso_unitario,
|
||||
(c.quantidade_por_peca * p.quantidade) as quantidade,
|
||||
c.peca_id,
|
||||
p.marca as peca_pai_marca,
|
||||
p.of_number
|
||||
FROM componentes_peca c
|
||||
INNER JOIN pecas_of p ON c.peca_id = p.id
|
||||
WHERE p_include_componentes = true
|
||||
),
|
||||
|
||||
-- CTE para calcular quantidades já processadas de peças
|
||||
pecas_processadas AS (
|
||||
SELECT
|
||||
ap.peca_id,
|
||||
ap.processo_id,
|
||||
SUM(ap.quantidade_produzida) as quantidade_processada
|
||||
FROM apontamentos_producao ap
|
||||
INNER JOIN pecas_of p ON ap.peca_id = p.id
|
||||
WHERE ap.tipo_apontamento = 'peca'
|
||||
AND (p_of_number IS NULL OR ap.of_number = p_of_number)
|
||||
AND (p_processo_id IS NULL OR ap.processo_id = p_processo_id)
|
||||
GROUP BY ap.peca_id, ap.processo_id
|
||||
),
|
||||
|
||||
-- CTE para calcular quantidades já processadas de componentes
|
||||
componentes_processados AS (
|
||||
SELECT
|
||||
ap.componente_id,
|
||||
ap.processo_id,
|
||||
SUM(ap.quantidade_produzida) as quantidade_processada
|
||||
FROM apontamentos_producao ap
|
||||
INNER JOIN componentes_of c ON ap.componente_id = c.id
|
||||
WHERE ap.tipo_apontamento = 'componente'
|
||||
AND (p_of_number IS NULL OR ap.of_number = p_of_number)
|
||||
AND (p_processo_id IS NULL OR ap.processo_id = p_processo_id)
|
||||
GROUP BY ap.componente_id, ap.processo_id
|
||||
),
|
||||
|
||||
-- CTE para buscar processos disponíveis
|
||||
processos_disponiveis AS (
|
||||
SELECT
|
||||
pf.id,
|
||||
pf.nome,
|
||||
pf.ordem,
|
||||
pf.ativo
|
||||
FROM processos_fabricacao pf
|
||||
WHERE pf.ativo = true
|
||||
AND (p_processo_id IS NULL OR pf.id = p_processo_id)
|
||||
ORDER BY pf.ordem
|
||||
),
|
||||
|
||||
-- CTE para determinar próximos processos para cada item
|
||||
proximos_processos_cte AS (
|
||||
SELECT
|
||||
pd.id as processo_id,
|
||||
COALESCE(
|
||||
jsonb_agg(
|
||||
jsonb_build_object(
|
||||
'id', pd_next.id,
|
||||
'nome', pd_next.nome,
|
||||
'ordem', pd_next.ordem
|
||||
) ORDER BY pd_next.ordem
|
||||
) FILTER (WHERE pd_next.id IS NOT NULL),
|
||||
'[]'::jsonb
|
||||
) as proximos_processos
|
||||
FROM processos_disponiveis pd
|
||||
LEFT JOIN processos_disponiveis pd_next ON pd_next.ordem > pd.ordem
|
||||
GROUP BY pd.id
|
||||
)
|
||||
|
||||
-- Query principal: UNION de peças e componentes
|
||||
SELECT
|
||||
-- Peças
|
||||
p.id as item_id,
|
||||
'peca'::TEXT as item_type,
|
||||
p.marca,
|
||||
p.descricao,
|
||||
p.peso_unitario,
|
||||
p.quantidade as quantidade_total,
|
||||
COALESCE(pp.quantidade_processada, 0) as quantidade_processada,
|
||||
GREATEST(p.quantidade - COALESCE(pp.quantidade_processada, 0), 0) as quantidade_disponivel,
|
||||
p.etapa_fase,
|
||||
pd.id as processo_atual_id,
|
||||
pd.nome as processo_atual_nome,
|
||||
pd.ordem as processo_atual_ordem,
|
||||
COALESCE(ppc.proximos_processos, '[]'::jsonb) as proximos_processos,
|
||||
NULL::UUID as peca_pai_id,
|
||||
NULL::TEXT as peca_pai_marca
|
||||
FROM pecas_of p
|
||||
CROSS JOIN processos_disponiveis pd
|
||||
LEFT JOIN pecas_processadas pp ON p.id = pp.peca_id AND pd.id = pp.processo_id
|
||||
LEFT JOIN proximos_processos_cte ppc ON pd.id = ppc.processo_id
|
||||
WHERE GREATEST(p.quantidade - COALESCE(pp.quantidade_processada, 0), 0) > 0
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
-- Componentes
|
||||
c.id as item_id,
|
||||
'componente'::TEXT as item_type,
|
||||
c.marca,
|
||||
c.descricao,
|
||||
c.peso_unitario,
|
||||
c.quantidade as quantidade_total,
|
||||
COALESCE(cp.quantidade_processada, 0) as quantidade_processada,
|
||||
GREATEST(c.quantidade - COALESCE(cp.quantidade_processada, 0), 0) as quantidade_disponivel,
|
||||
NULL::TEXT as etapa_fase, -- Componentes não têm etapa_fase
|
||||
pd.id as processo_atual_id,
|
||||
pd.nome as processo_atual_nome,
|
||||
pd.ordem as processo_atual_ordem,
|
||||
COALESCE(ppc.proximos_processos, '[]'::jsonb) as proximos_processos,
|
||||
c.peca_id as peca_pai_id,
|
||||
c.peca_pai_marca
|
||||
FROM componentes_of c
|
||||
CROSS JOIN processos_disponiveis pd
|
||||
LEFT JOIN componentes_processados cp ON c.id = cp.componente_id AND pd.id = cp.processo_id
|
||||
LEFT JOIN proximos_processos_cte ppc ON pd.id = ppc.processo_id
|
||||
WHERE p_include_componentes = true
|
||||
AND GREATEST(c.quantidade - COALESCE(cp.quantidade_processada, 0), 0) > 0
|
||||
|
||||
ORDER BY
|
||||
item_type DESC, -- Peças primeiro, depois componentes
|
||||
processo_atual_ordem ASC,
|
||||
marca ASC
|
||||
LIMIT p_limit;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- Comentários sobre a função
|
||||
COMMENT ON FUNCTION get_itens_disponiveis IS 'Função otimizada para buscar itens (peças e componentes) disponíveis para apontamento de produção';
|
||||
|
||||
-- Criar índices para otimizar a performance da função RPC
|
||||
CREATE INDEX IF NOT EXISTS idx_apontamentos_producao_of_tipo_processo
|
||||
ON apontamentos_producao(of_number, tipo_apontamento, processo_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_apontamentos_producao_peca_processo
|
||||
ON apontamentos_producao(peca_id, processo_id)
|
||||
WHERE tipo_apontamento = 'peca';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_apontamentos_producao_componente_processo
|
||||
ON apontamentos_producao(componente_id, processo_id)
|
||||
WHERE tipo_apontamento = 'componente';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_pecas_of_number
|
||||
ON pecas(of_number);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_componentes_peca_peca_id
|
||||
ON componentes_peca(peca_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_processos_fabricacao_ativo_ordem
|
||||
ON processos_fabricacao(ativo, ordem)
|
||||
WHERE ativo = true;
|
||||
|
||||
-- Função auxiliar para buscar estatísticas de performance
|
||||
CREATE OR REPLACE FUNCTION get_apontamentos_stats(
|
||||
p_of_number TEXT DEFAULT NULL,
|
||||
p_data_inicio DATE DEFAULT NULL,
|
||||
p_data_fim DATE DEFAULT NULL
|
||||
)
|
||||
RETURNS TABLE (
|
||||
total_apontamentos BIGINT,
|
||||
total_pecas BIGINT,
|
||||
total_componentes BIGINT,
|
||||
processos_utilizados BIGINT,
|
||||
quantidade_total_produzida NUMERIC,
|
||||
periodo_inicio DATE,
|
||||
periodo_fim DATE
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
COUNT(*) as total_apontamentos,
|
||||
COUNT(*) FILTER (WHERE ap.tipo_apontamento = 'peca') as total_pecas,
|
||||
COUNT(*) FILTER (WHERE ap.tipo_apontamento = 'componente') as total_componentes,
|
||||
COUNT(DISTINCT ap.processo_id) as processos_utilizados,
|
||||
SUM(ap.quantidade_produzida) as quantidade_total_produzida,
|
||||
MIN(ap.data_apontamento::DATE) as periodo_inicio,
|
||||
MAX(ap.data_apontamento::DATE) as periodo_fim
|
||||
FROM apontamentos_producao ap
|
||||
WHERE (p_of_number IS NULL OR ap.of_number = p_of_number)
|
||||
AND (p_data_inicio IS NULL OR ap.data_apontamento::DATE >= p_data_inicio)
|
||||
AND (p_data_fim IS NULL OR ap.data_apontamento::DATE <= p_data_fim);
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION get_apontamentos_stats IS 'Função para obter estatísticas de apontamentos de produção';
|
||||
|
||||
-- Função para validação sequencial otimizada
|
||||
CREATE OR REPLACE FUNCTION validate_sequencia_processos(
|
||||
p_of_number TEXT,
|
||||
p_peca_id UUID DEFAULT NULL,
|
||||
p_componente_id UUID DEFAULT NULL
|
||||
)
|
||||
RETURNS TABLE (
|
||||
item_id UUID,
|
||||
item_type TEXT,
|
||||
marca TEXT,
|
||||
processo_atual_id UUID,
|
||||
processo_atual_nome TEXT,
|
||||
processo_atual_ordem INTEGER,
|
||||
pode_apontar BOOLEAN,
|
||||
motivo_bloqueio TEXT,
|
||||
processos_pendentes JSONB
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
WITH
|
||||
-- Buscar todos os processos ordenados
|
||||
processos_ordenados AS (
|
||||
SELECT id, nome, ordem
|
||||
FROM processos_fabricacao
|
||||
WHERE ativo = true
|
||||
ORDER BY ordem
|
||||
),
|
||||
|
||||
-- Buscar apontamentos existentes
|
||||
apontamentos_existentes AS (
|
||||
SELECT
|
||||
ap.peca_id,
|
||||
ap.componente_id,
|
||||
ap.processo_id,
|
||||
pf.ordem as processo_ordem,
|
||||
SUM(ap.quantidade_produzida) as quantidade_apontada
|
||||
FROM apontamentos_producao ap
|
||||
INNER JOIN processos_fabricacao pf ON ap.processo_id = pf.id
|
||||
WHERE ap.of_number = p_of_number
|
||||
AND (p_peca_id IS NULL OR ap.peca_id = p_peca_id)
|
||||
AND (p_componente_id IS NULL OR ap.componente_id = p_componente_id)
|
||||
GROUP BY ap.peca_id, ap.componente_id, ap.processo_id, pf.ordem
|
||||
),
|
||||
|
||||
-- Determinar próximo processo válido para cada item
|
||||
proximos_processos_validos AS (
|
||||
SELECT
|
||||
COALESCE(ae.peca_id, p_peca_id) as peca_id,
|
||||
COALESCE(ae.componente_id, p_componente_id) as componente_id,
|
||||
CASE
|
||||
WHEN ae.processo_id IS NULL THEN (
|
||||
SELECT id FROM processos_ordenados ORDER BY ordem LIMIT 1
|
||||
)
|
||||
ELSE (
|
||||
SELECT po.id
|
||||
FROM processos_ordenados po
|
||||
WHERE po.ordem > ae.processo_ordem
|
||||
ORDER BY po.ordem
|
||||
LIMIT 1
|
||||
)
|
||||
END as proximo_processo_id
|
||||
FROM (
|
||||
SELECT DISTINCT
|
||||
peca_id,
|
||||
componente_id,
|
||||
MAX(processo_ordem) as processo_ordem,
|
||||
MAX(processo_id) as processo_id
|
||||
FROM apontamentos_existentes
|
||||
GROUP BY peca_id, componente_id
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Incluir itens que ainda não têm apontamentos
|
||||
SELECT p_peca_id, p_componente_id, NULL, NULL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM apontamentos_existentes
|
||||
WHERE peca_id = p_peca_id OR componente_id = p_componente_id
|
||||
)
|
||||
) ae
|
||||
)
|
||||
|
||||
SELECT
|
||||
COALESCE(ppv.peca_id, ppv.componente_id) as item_id,
|
||||
CASE WHEN ppv.peca_id IS NOT NULL THEN 'peca' ELSE 'componente' END as item_type,
|
||||
COALESCE(p.marca, c.marca_componente) as marca,
|
||||
po.id as processo_atual_id,
|
||||
po.nome as processo_atual_nome,
|
||||
po.ordem as processo_atual_ordem,
|
||||
(ppv.proximo_processo_id IS NOT NULL) as pode_apontar,
|
||||
CASE
|
||||
WHEN ppv.proximo_processo_id IS NULL THEN 'Todos os processos já foram concluídos'
|
||||
ELSE NULL
|
||||
END as motivo_bloqueio,
|
||||
COALESCE(
|
||||
jsonb_agg(
|
||||
jsonb_build_object(
|
||||
'id', po_pendente.id,
|
||||
'nome', po_pendente.nome,
|
||||
'ordem', po_pendente.ordem
|
||||
) ORDER BY po_pendente.ordem
|
||||
) FILTER (WHERE po_pendente.id IS NOT NULL),
|
||||
'[]'::jsonb
|
||||
) as processos_pendentes
|
||||
FROM proximos_processos_validos ppv
|
||||
LEFT JOIN pecas p ON ppv.peca_id = p.id
|
||||
LEFT JOIN componentes_peca c ON ppv.componente_id = c.id
|
||||
LEFT JOIN processos_ordenados po ON ppv.proximo_processo_id = po.id
|
||||
LEFT JOIN processos_ordenados po_pendente ON po_pendente.ordem >= po.ordem
|
||||
GROUP BY
|
||||
ppv.peca_id, ppv.componente_id, p.marca, c.marca_componente,
|
||||
po.id, po.nome, po.ordem, ppv.proximo_processo_id;
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION validate_sequencia_processos IS 'Função para validar sequência de processos e determinar próximos passos válidos';
|
||||
Reference in New Issue
Block a user