🚀 Initial commit: Versão atual do TrackSteel APP
This commit is contained in:
@@ -0,0 +1,283 @@
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { useApontamentosProducao } from '@/hooks/useApontamentosProducao';
|
||||
|
||||
interface HistoricoProcesso {
|
||||
marca_item: string;
|
||||
processo_id: string;
|
||||
processo_ordem: number;
|
||||
quantidade_processada: number;
|
||||
tipo_item: 'peca' | 'componente';
|
||||
}
|
||||
|
||||
interface ValidacaoResult {
|
||||
valido: boolean;
|
||||
erro?: string;
|
||||
quantidadeMaxima?: number;
|
||||
}
|
||||
|
||||
interface ItemDisponivel {
|
||||
marca: string;
|
||||
quantidade_disponivel: number;
|
||||
processos_concluidos: number[];
|
||||
proximo_processo_permitido: number | null;
|
||||
}
|
||||
|
||||
export const useValidacaoSequencialProcessos = () => {
|
||||
const [historico, setHistorico] = useState<HistoricoProcesso[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { processos, buscarQuantidadeProcessada } = useApontamentosProducao();
|
||||
|
||||
// Buscar histórico de apontamentos para uma OF específica
|
||||
const buscarHistoricoOF = useCallback(async (ofNumber: string) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
// Buscar apontamentos de peças
|
||||
const { data: apontamentosPecas, error: errorPecas } = await supabase
|
||||
.from('apontamentos_producao')
|
||||
.select(`
|
||||
quantidade_produzida,
|
||||
processo_id,
|
||||
tipo_apontamento,
|
||||
peca:pecas(marca),
|
||||
processo:processos_fabricacao(ordem)
|
||||
`)
|
||||
.eq('of_number', ofNumber)
|
||||
.eq('tipo_apontamento', 'peca');
|
||||
|
||||
// Buscar apontamentos de componentes
|
||||
const { data: apontamentosComponentes, error: errorComponentes } = await supabase
|
||||
.from('apontamentos_producao')
|
||||
.select(`
|
||||
quantidade_produzida,
|
||||
processo_id,
|
||||
tipo_apontamento,
|
||||
componente:componentes_peca(marca_componente),
|
||||
processo:processos_fabricacao(ordem)
|
||||
`)
|
||||
.eq('of_number', ofNumber)
|
||||
.eq('tipo_apontamento', 'componente');
|
||||
|
||||
if (errorPecas || errorComponentes) {
|
||||
throw errorPecas || errorComponentes;
|
||||
}
|
||||
|
||||
const historicoCompleto: HistoricoProcesso[] = [];
|
||||
|
||||
// Processar apontamentos de peças
|
||||
apontamentosPecas?.forEach(apt => {
|
||||
if (apt.peca?.marca && apt.processo?.ordem !== undefined) {
|
||||
historicoCompleto.push({
|
||||
marca_item: apt.peca.marca,
|
||||
processo_id: apt.processo_id,
|
||||
processo_ordem: apt.processo.ordem,
|
||||
quantidade_processada: apt.quantidade_produzida,
|
||||
tipo_item: 'peca'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Processar apontamentos de componentes
|
||||
apontamentosComponentes?.forEach(apt => {
|
||||
if (apt.componente?.marca_componente && apt.processo?.ordem !== undefined) {
|
||||
historicoCompleto.push({
|
||||
marca_item: apt.componente.marca_componente,
|
||||
processo_id: apt.processo_id,
|
||||
processo_ordem: apt.processo.ordem,
|
||||
quantidade_processada: apt.quantidade_produzida,
|
||||
tipo_item: 'componente'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
setHistorico(historicoCompleto);
|
||||
} catch (error) {
|
||||
console.error('Erro ao buscar histórico de processos:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Validar se um item pode ser processado em um processo específico
|
||||
const validarSequenciaProcesso = useCallback((
|
||||
ofNumber: string,
|
||||
marcaItem: string,
|
||||
processoId: string,
|
||||
quantidadeSolicitada: number
|
||||
): ValidacaoResult => {
|
||||
const processoAtual = processos.find(p => p.id === processoId);
|
||||
if (!processoAtual) {
|
||||
return { valido: false, erro: 'Processo não encontrado' };
|
||||
}
|
||||
|
||||
const ordemAtual = processoAtual.ordem;
|
||||
|
||||
// Se for o primeiro processo (ordem 1), sempre permitir
|
||||
if (ordemAtual === 1) {
|
||||
return { valido: true };
|
||||
}
|
||||
|
||||
// Buscar histórico do item específico
|
||||
const historicoItem = historico.filter(h => h.marca_item === marcaItem);
|
||||
|
||||
if (historicoItem.length === 0) {
|
||||
return {
|
||||
valido: false,
|
||||
erro: `Item ${marcaItem} deve primeiro passar pelo processo inicial (ordem 1)`
|
||||
};
|
||||
}
|
||||
|
||||
// Verificar se todos os processos anteriores foram concluídos
|
||||
const processosAnteriores = processos
|
||||
.filter(p => p.ordem < ordemAtual)
|
||||
.sort((a, b) => a.ordem - b.ordem);
|
||||
|
||||
for (const processoAnterior of processosAnteriores) {
|
||||
const apontamentosProcessoAnterior = historicoItem.filter(
|
||||
h => h.processo_ordem === processoAnterior.ordem
|
||||
);
|
||||
|
||||
if (apontamentosProcessoAnterior.length === 0) {
|
||||
return {
|
||||
valido: false,
|
||||
erro: `Item ${marcaItem} deve primeiro passar pelo processo "${processoAnterior.nome}" (ordem ${processoAnterior.ordem})`
|
||||
};
|
||||
}
|
||||
|
||||
// Verificar se há quantidade suficiente processada no processo anterior
|
||||
const quantidadeProcessada = apontamentosProcessoAnterior.reduce(
|
||||
(total, apt) => total + apt.quantidade_processada, 0
|
||||
);
|
||||
|
||||
if (quantidadeProcessada < quantidadeSolicitada) {
|
||||
return {
|
||||
valido: false,
|
||||
erro: `Quantidade insuficiente processada no processo "${processoAnterior.nome}". Disponível: ${quantidadeProcessada}, Solicitado: ${quantidadeSolicitada}`,
|
||||
quantidadeMaxima: quantidadeProcessada
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return { valido: true };
|
||||
}, [historico, processos]);
|
||||
|
||||
// Calcular itens disponíveis para um processo específico
|
||||
const calcularItensDisponiveis = useCallback(async (
|
||||
ofNumber: string,
|
||||
processoId: string,
|
||||
pecas: any[],
|
||||
componentes: any[]
|
||||
): Promise<{
|
||||
pecasDisponiveis: any[];
|
||||
componentesDisponiveis: any[];
|
||||
}> => {
|
||||
const processoAtual = processos.find(p => p.id === processoId);
|
||||
if (!processoAtual) {
|
||||
return { pecasDisponiveis: [], componentesDisponiveis: [] };
|
||||
}
|
||||
|
||||
const ordemAtual = processoAtual.ordem;
|
||||
const pecasDisponiveis: any[] = [];
|
||||
const componentesDisponiveis: any[] = [];
|
||||
|
||||
// Processar peças
|
||||
for (const peca of pecas) {
|
||||
if (ordemAtual === 1) {
|
||||
// Primeiro processo: todas as peças estão disponíveis
|
||||
pecasDisponiveis.push({
|
||||
...peca,
|
||||
quantidade_disponivel: peca.quantidade || 0
|
||||
});
|
||||
} else {
|
||||
// Calcular quantidade disponível baseada no processo anterior
|
||||
const quantidadeProcessadaAnterior = await calcularQuantidadeDisponivelProcessoAnterior(
|
||||
peca.marca,
|
||||
ordemAtual - 1,
|
||||
ofNumber,
|
||||
'peca'
|
||||
);
|
||||
|
||||
const quantidadeJaProcessadaAtual = await buscarQuantidadeProcessada(
|
||||
peca.marca,
|
||||
processoId,
|
||||
ofNumber,
|
||||
'peca'
|
||||
);
|
||||
|
||||
const quantidadeDisponivel = quantidadeProcessadaAnterior - quantidadeJaProcessadaAtual;
|
||||
|
||||
if (quantidadeDisponivel > 0) {
|
||||
pecasDisponiveis.push({
|
||||
...peca,
|
||||
quantidade_disponivel: quantidadeDisponivel
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Processar componentes
|
||||
for (const componente of componentes) {
|
||||
if (ordemAtual === 1) {
|
||||
// Primeiro processo: todos os componentes estão disponíveis
|
||||
componentesDisponiveis.push({
|
||||
...componente,
|
||||
quantidade_disponivel: componente.quantidade_total || 0
|
||||
});
|
||||
} else {
|
||||
// Calcular quantidade disponível baseada no processo anterior
|
||||
const quantidadeProcessadaAnterior = await calcularQuantidadeDisponivelProcessoAnterior(
|
||||
componente.marca_componente,
|
||||
ordemAtual - 1,
|
||||
ofNumber,
|
||||
'componente'
|
||||
);
|
||||
|
||||
const quantidadeJaProcessadaAtual = await buscarQuantidadeProcessada(
|
||||
componente.marca_componente,
|
||||
processoId,
|
||||
ofNumber,
|
||||
'componente'
|
||||
);
|
||||
|
||||
const quantidadeDisponivel = quantidadeProcessadaAnterior - quantidadeJaProcessadaAtual;
|
||||
|
||||
if (quantidadeDisponivel > 0) {
|
||||
componentesDisponiveis.push({
|
||||
...componente,
|
||||
quantidade_disponivel: quantidadeDisponivel
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { pecasDisponiveis, componentesDisponiveis };
|
||||
}, [processos, buscarQuantidadeProcessada]);
|
||||
|
||||
// Função auxiliar para calcular quantidade disponível do processo anterior
|
||||
const calcularQuantidadeDisponivelProcessoAnterior = async (
|
||||
marcaItem: string,
|
||||
ordemProcessoAnterior: number,
|
||||
ofNumber: string,
|
||||
tipoItem: 'peca' | 'componente'
|
||||
): Promise<number> => {
|
||||
const processoAnterior = processos.find(p => p.ordem === ordemProcessoAnterior);
|
||||
if (!processoAnterior) return 0;
|
||||
|
||||
return await buscarQuantidadeProcessada(
|
||||
marcaItem,
|
||||
processoAnterior.id,
|
||||
ofNumber,
|
||||
tipoItem
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
historico,
|
||||
loading,
|
||||
buscarHistoricoOF,
|
||||
validarSequenciaProcesso,
|
||||
calcularItensDisponiveis
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user