Compare commits
2 Commits
1203650c2d
...
9745964837
| Author | SHA1 | Date | |
|---|---|---|---|
| 9745964837 | |||
| 400be62a0e |
@@ -0,0 +1,2 @@
|
||||
// Script temporário de auditoria da OF B134
|
||||
export {};
|
||||
@@ -118,6 +118,8 @@ export const ApontamentoForm = () => {
|
||||
const processosOrdenados = [...processos].sort((a, b) => a.ordem - b.ordem);
|
||||
const indexAtual = processosOrdenados.findIndex(p => p.id === processo_id);
|
||||
const procAtual = processosOrdenados[indexAtual];
|
||||
const procNomeLower = (procAtual?.nome || '').toLowerCase();
|
||||
const isCorte = procNomeLower.includes('corte') || procNomeLower.includes('prepar') || indexAtual === 0;
|
||||
|
||||
// 1. Peças da OF e Fase selecionadas
|
||||
const pecasDaFase = pecas.filter(
|
||||
@@ -134,8 +136,13 @@ export const ApontamentoForm = () => {
|
||||
|
||||
let qtdDisponivelParaEntrar = Number(peca.quantidade) || 0;
|
||||
|
||||
// Regra: peças sem componentes não passam por solda
|
||||
if (!peca.tem_componentes && procAtual && procAtual.nome.toLowerCase().includes('solda')) {
|
||||
// Se for CORTE:
|
||||
// Peças compostas são produzidas através do corte de seus subcomponentes.
|
||||
// Ao atingir 100% dos componentes cortados, o kit é concluído e a peça mestre é liberada para Solda.
|
||||
if (isCorte && peca.tem_componentes) {
|
||||
qtdDisponivelParaEntrar = 0;
|
||||
} else if (!peca.tem_componentes && procNomeLower.includes('solda')) {
|
||||
// Regra: peças sem componentes não passam por solda
|
||||
qtdDisponivelParaEntrar = 0;
|
||||
} else if (indexAtual > 0) {
|
||||
// Encontrar processo anterior válido
|
||||
@@ -150,9 +157,27 @@ export const ApontamentoForm = () => {
|
||||
}
|
||||
|
||||
if (processoAnteriorValido) {
|
||||
qtdDisponivelParaEntrar = apontamentos
|
||||
let qtdApontadaAnterior = apontamentos
|
||||
.filter(a => a.tipo_apontamento === 'peca' && a.peca_id === peca.id && a.processo_id === processoAnteriorValido.id)
|
||||
.reduce((sum, a) => sum + (Number(a.quantidade_produzida) || 0), 0);
|
||||
|
||||
// Fallback de retrocompatibilidade para peças com componentes cortados antes da automação
|
||||
if (peca.tem_componentes && qtdApontadaAnterior === 0 && processoAnteriorValido.nome.toLowerCase().includes('corte')) {
|
||||
const compsDaPeca = componentesAgrupados?.filter(c => c.peca_ids?.includes(peca.id)) || [];
|
||||
if (compsDaPeca.length > 0) {
|
||||
const todosCortados = compsDaPeca.every(c => {
|
||||
const aptsComp = apontamentos
|
||||
.filter(a => a.tipo_apontamento === 'componente' && c.componente_ids.includes(a.componente_id || '') && a.processo_id === processoAnteriorValido.id)
|
||||
.reduce((sum, a) => sum + (Number(a.quantidade_produzida) || 0), 0);
|
||||
return aptsComp >= c.quantidade_total;
|
||||
});
|
||||
if (todosCortados) {
|
||||
qtdApontadaAnterior = Number(peca.quantidade) || 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qtdDisponivelParaEntrar = qtdApontadaAnterior;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,21 +198,14 @@ export const ApontamentoForm = () => {
|
||||
});
|
||||
|
||||
// 2. Componentes da OF e Fase selecionadas
|
||||
// RESTRIÇÃO INDUSTRIAL: Componentes só existem no processo de CORTE / PREPARAÇÃO!
|
||||
// Em Solda, Pintura, Expedição, Montagem etc., componentes não são exibidos nem apontados.
|
||||
const componentesDisponiveis: ItemDisponivel[] = [];
|
||||
|
||||
if (componentesAgrupados && componentesAgrupados.length > 0) {
|
||||
if (isCorte && componentesAgrupados && componentesAgrupados.length > 0) {
|
||||
componentesAgrupados.forEach(comp => {
|
||||
let qtdDisponivelParaEntrarComp = Number(comp.quantidade_total) || 0;
|
||||
|
||||
if (indexAtual > 0) {
|
||||
const processoAnteriorValido = processosOrdenados[indexAtual - 1];
|
||||
if (processoAnteriorValido) {
|
||||
qtdDisponivelParaEntrarComp = apontamentos
|
||||
.filter(a => a.tipo_apontamento === 'componente' && comp.componente_ids.includes(a.componente_id || '') && a.processo_id === processoAnteriorValido.id)
|
||||
.reduce((sum, a) => sum + (Number(a.quantidade_produzida) || 0), 0);
|
||||
}
|
||||
}
|
||||
|
||||
const totalApontadoComp = apontamentos
|
||||
.filter(a => a.tipo_apontamento === 'componente' && comp.componente_ids.includes(a.componente_id || '') && a.processo_id === processo_id)
|
||||
.reduce((sum, a) => sum + (Number(a.quantidade_produzida) || 0), 0);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { toast } from 'sonner';
|
||||
import { Search, Package, Shield, AlertTriangle, Settings, Check, Loader2 } from 'lucide-react';
|
||||
import { Search, Package, Shield, AlertTriangle, Settings, Check, Loader2, Layers } from 'lucide-react';
|
||||
import { useDebounce } from '@/hooks/useDebounce';
|
||||
import { Peca } from '@/hooks/usePecas';
|
||||
import { useComponentesPeca } from '@/hooks/useComponentesPeca';
|
||||
@@ -628,7 +628,10 @@ export const SeletorItensOtimizado: React.FC<SeletorItensOtimizadoProps> = ({
|
||||
{componentesDisponiveis.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-semibold text-foreground">Componentes Disponíveis</h3>
|
||||
<h3 className="text-lg font-semibold text-foreground flex items-center gap-2">
|
||||
<Layers className="h-5 w-5 text-blue-500" />
|
||||
Componentes para Corte (Controle de Kit)
|
||||
</h3>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
AlertTriangle,
|
||||
@@ -224,7 +223,7 @@ export const ImportarPecasDiffModal: React.FC<ImportarPecasDiffModalProps> = ({
|
||||
return (
|
||||
<>
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-6xl max-h-[92vh] flex flex-col p-0 overflow-hidden bg-background border-border">
|
||||
<DialogContent className="max-w-6xl h-[90vh] max-h-[92vh] flex flex-col p-0 overflow-hidden bg-background border-border">
|
||||
{/* Cabeçalho */}
|
||||
<DialogHeader className="p-4 border-b border-border bg-card flex-shrink-0">
|
||||
<div className="flex items-center justify-between">
|
||||
@@ -367,7 +366,7 @@ export const ImportarPecasDiffModal: React.FC<ImportarPecasDiffModalProps> = ({
|
||||
</DialogHeader>
|
||||
|
||||
{/* Barra de Filtros e Ferramentas */}
|
||||
<div className="p-3 border-b border-border bg-muted/20 flex flex-wrap items-center justify-between gap-2 text-xs">
|
||||
<div className="p-3 border-b border-border bg-muted/20 flex flex-wrap items-center justify-between gap-2 text-xs flex-shrink-0">
|
||||
{/* Input de Busca */}
|
||||
<div className="relative w-72">
|
||||
<Search className="absolute left-2.5 top-2.5 h-3.5 w-3.5 text-muted-foreground" />
|
||||
@@ -411,18 +410,18 @@ export const ImportarPecasDiffModal: React.FC<ImportarPecasDiffModalProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tabela de Conciliação e Diff */}
|
||||
<ScrollArea className="flex-1">
|
||||
{/* Tabela de Conciliação e Diff com Scroll Vertical e Cabeçalho Sticky */}
|
||||
<div className="flex-1 min-h-0 overflow-y-auto overflow-x-auto w-full">
|
||||
<div className="p-4">
|
||||
<table className="w-full text-left text-xs border-collapse">
|
||||
<thead>
|
||||
<tr className="border-b border-border text-muted-foreground font-semibold bg-muted/40">
|
||||
<th className="p-2 w-10 text-center">Sobrepor</th>
|
||||
<th className="p-2 w-28">Peça / Fase</th>
|
||||
<th className="p-2 w-44">Perfil / Bitola</th>
|
||||
<th className="p-2 w-40">Status de Produção</th>
|
||||
<th className="p-2">Divergências Detectadas (Diff)</th>
|
||||
<th className="p-2 w-28 text-center">Lembrete Fabril</th>
|
||||
<thead className="sticky top-0 z-10 bg-muted/95 backdrop-blur-sm shadow-sm">
|
||||
<tr className="border-b border-border text-muted-foreground font-semibold">
|
||||
<th className="p-2 w-10 text-center bg-muted/95">Sobrepor</th>
|
||||
<th className="p-2 w-28 bg-muted/95">Peça / Fase</th>
|
||||
<th className="p-2 w-44 bg-muted/95">Perfil / Bitola</th>
|
||||
<th className="p-2 w-40 bg-muted/95">Status de Produção</th>
|
||||
<th className="p-2 bg-muted/95">Divergências Detectadas (Diff)</th>
|
||||
<th className="p-2 w-28 text-center bg-muted/95">Lembrete Fabril</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-border">
|
||||
@@ -623,7 +622,7 @@ export const ImportarPecasDiffModal: React.FC<ImportarPecasDiffModalProps> = ({
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
|
||||
{/* Rodapé da Janela com Decisão e Ações */}
|
||||
<DialogFooter className="p-3 border-t border-border bg-card flex flex-row items-center justify-between flex-shrink-0">
|
||||
|
||||
@@ -118,14 +118,13 @@ export const useApontamentoDiarioChart = (periodo: PeriodoType) => {
|
||||
const ofNumber = apontamento.of_number;
|
||||
const processoNome = apontamento.processo?.nome || 'Processo Desconhecido';
|
||||
|
||||
// Calcular peso baseado no tipo de apontamento
|
||||
let pesoUnitario = 0;
|
||||
if (apontamento.tipo_apontamento === 'componente' && apontamento.componente?.peso_unitario) {
|
||||
pesoUnitario = Number(apontamento.componente.peso_unitario);
|
||||
} else if (apontamento.tipo_apontamento === 'peca' && apontamento.peca?.peso_unitario) {
|
||||
pesoUnitario = Number(apontamento.peca.peso_unitario);
|
||||
// Blindagem contra dupla contagem: apenas peças mestres computam peso nos gráficos de produção.
|
||||
// Componentes são rastreados para controle de kit/corte, mas não somam peso na balança global.
|
||||
if (apontamento.tipo_apontamento !== 'peca') {
|
||||
return;
|
||||
}
|
||||
|
||||
const pesoUnitario = Number(apontamento.peca?.peso_unitario || 0);
|
||||
let pesoTotal = pesoUnitario * Number(apontamento.quantidade_produzida);
|
||||
|
||||
// Para projeção, calcular média diária e multiplicar por 7
|
||||
|
||||
@@ -378,6 +378,101 @@ interface InsertApontamentoData {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// REGRA DO KIT COMPLETO (Passo 3 + Opção 1):
|
||||
// Se apontou componente no processo de Corte, verificar se todos os componentes da peça pai completaram o kit.
|
||||
// Se completou, cria automaticamente o apontamento da Peça Principal no Corte (tipo_apontamento = 'peca'),
|
||||
// computando o peso integral da peça mestre no Corte e liberando-a para a Solda!
|
||||
if (insertData.tipo_apontamento === 'componente' && insertData.peca_id) {
|
||||
try {
|
||||
const procAtual = processos.find(p => p.id === insertData.processo_id);
|
||||
const isProcessoCorte = procAtual
|
||||
? (procAtual.nome.toLowerCase().includes('corte') || procAtual.nome.toLowerCase().includes('prepar') || procAtual.ordem === 1)
|
||||
: true;
|
||||
|
||||
if (isProcessoCorte) {
|
||||
const pecaId = insertData.peca_id;
|
||||
|
||||
// 1. Buscar todos os componentes requeridos da peça pai
|
||||
const { data: compsPeca } = await supabase
|
||||
.from('componentes_peca')
|
||||
.select('id, quantidade_por_peca')
|
||||
.eq('peca_id', pecaId);
|
||||
|
||||
// 2. Buscar a peça pai
|
||||
const { data: pecaPai } = await supabase
|
||||
.from('pecas')
|
||||
.select('id, marca, quantidade, of_number')
|
||||
.eq('id', pecaId)
|
||||
.single();
|
||||
|
||||
if (pecaPai && compsPeca && compsPeca.length > 0) {
|
||||
// 3. Buscar todos os apontamentos de componentes já feitos para essa peça pai neste processo de corte
|
||||
const { data: todosAptsComp } = await supabase
|
||||
.from('apontamentos_producao')
|
||||
.select('componente_id, quantidade_produzida')
|
||||
.eq('peca_id', pecaId)
|
||||
.eq('processo_id', insertData.processo_id)
|
||||
.eq('tipo_apontamento', 'componente');
|
||||
|
||||
const cortadoPorComp = new Map<string, number>();
|
||||
(todosAptsComp || []).forEach(a => {
|
||||
if (a.componente_id) {
|
||||
cortadoPorComp.set(a.componente_id, (cortadoPorComp.get(a.componente_id) || 0) + Number(a.quantidade_produzida || 0));
|
||||
}
|
||||
});
|
||||
|
||||
let kitsCompletos = Number(pecaPai.quantidade) || 0;
|
||||
for (const comp of compsPeca) {
|
||||
const cortado = cortadoPorComp.get(comp.id) || 0;
|
||||
const porPeca = Number(comp.quantidade_por_peca) || 1;
|
||||
const kitsDeste = Math.floor(cortado / porPeca);
|
||||
if (kitsDeste < kitsCompletos) {
|
||||
kitsCompletos = kitsDeste;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Verificar quanto já foi apontado como 'peca' mestre no corte
|
||||
const { data: aptsPecaJaRegistrados } = await supabase
|
||||
.from('apontamentos_producao')
|
||||
.select('quantidade_produzida')
|
||||
.eq('peca_id', pecaId)
|
||||
.eq('processo_id', insertData.processo_id)
|
||||
.eq('tipo_apontamento', 'peca');
|
||||
|
||||
const totalPecaJaApontada = (aptsPecaJaRegistrados || []).reduce(
|
||||
(sum, a) => sum + Number(a.quantidade_produzida || 0), 0
|
||||
);
|
||||
|
||||
// 5. Se há novos kits completos, registrar apontamento da peça mestre no Corte
|
||||
const qtdLiberar = kitsCompletos - totalPecaJaApontada;
|
||||
if (qtdLiberar > 0) {
|
||||
const { error: errPeca } = await supabase
|
||||
.from('apontamentos_producao')
|
||||
.insert({
|
||||
of_number: pecaPai.of_number,
|
||||
peca_id: pecaPai.id,
|
||||
processo_id: insertData.processo_id,
|
||||
tipo_apontamento: 'peca',
|
||||
quantidade_produzida: qtdLiberar,
|
||||
data_apontamento: insertData.data_apontamento,
|
||||
observacoes: `Liberação automática de Kit 100% cortado (${kitsCompletos}/${pecaPai.quantidade} un)`,
|
||||
created_by: user.id
|
||||
});
|
||||
|
||||
if (!errPeca) {
|
||||
console.log(`✅ Kit 100% completo! ${qtdLiberar} un da peça mestre ${pecaPai.marca} registradas no Corte.`);
|
||||
toast.success(`Kit 100% cortado! ${qtdLiberar} un da peça ${pecaPai.marca} liberada(s) para Solda.`);
|
||||
} else {
|
||||
console.warn('Aviso ao registrar liberação automática de peça:', errPeca);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (kitError) {
|
||||
console.error('Erro ao verificar regra de kit completo:', kitError);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ Apontamento criado com sucesso, forçando atualização completa...');
|
||||
|
||||
// FORÇA ATUALIZAÇÃO COMPLETA DOS DADOS
|
||||
|
||||
@@ -171,16 +171,11 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
||||
const processoCorteId = processoCorte.data?.id;
|
||||
const pecasInfoMap = new Map((pecasData || []).map(p => [p.id, p]));
|
||||
|
||||
// 1. Somar peças com componentes apontadas na Solda
|
||||
// 1. Somar peças com componentes apontadas na Solda (apenas tipo peca)
|
||||
if (processoSoldaId) {
|
||||
const apontamentosSolda = apontamentosData.filter(a => a.processo_id === processoSoldaId);
|
||||
const apontamentosSolda = apontamentosData.filter(a => a.processo_id === processoSoldaId && a.tipo_apontamento === 'peca');
|
||||
apontamentosSolda.forEach(apontamento => {
|
||||
let pesoUnitario = 0;
|
||||
if (apontamento.tipo_apontamento === 'componente' && apontamento.componente?.peso_unitario) {
|
||||
pesoUnitario = Number(apontamento.componente.peso_unitario);
|
||||
} else if (apontamento.tipo_apontamento === 'peca' && apontamento.peca?.peso_unitario) {
|
||||
pesoUnitario = Number(apontamento.peca.peso_unitario);
|
||||
}
|
||||
const pesoUnitario = Number(apontamento.peca?.peso_unitario || 0);
|
||||
const pesoApontamento = pesoUnitario * Number(apontamento.quantidade_produzida || 0);
|
||||
pesoTotalFabricado += pesoApontamento;
|
||||
});
|
||||
@@ -357,15 +352,10 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
||||
|
||||
let pesoFabricadoProcesso = 0;
|
||||
apontamentosProcesso.forEach(a => {
|
||||
let pesoUnitario = 0;
|
||||
|
||||
if (a.tipo_apontamento === 'componente' && a.componente?.peso_unitario) {
|
||||
pesoUnitario = Number(a.componente.peso_unitario);
|
||||
} else if (a.tipo_apontamento === 'peca' && a.peca?.peso_unitario) {
|
||||
pesoUnitario = Number(a.peca.peso_unitario);
|
||||
// Apenas apontamentos de peça mestre somam peso no processo para evitar dupla contagem com subcomponentes
|
||||
if (a.tipo_apontamento === 'peca' && a.peca?.peso_unitario) {
|
||||
pesoFabricadoProcesso += Number(a.peca.peso_unitario) * Number(a.quantidade_produzida);
|
||||
}
|
||||
|
||||
pesoFabricadoProcesso += pesoUnitario * Number(a.quantidade_produzida);
|
||||
});
|
||||
|
||||
const isProcessoSolda = processo.nome.toLowerCase().includes('solda');
|
||||
@@ -507,17 +497,12 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
||||
return dataAptStr <= dataStr;
|
||||
});
|
||||
let realizado = 0;
|
||||
apontamentosAteData.forEach(a => {
|
||||
let pesoUnitario = 0;
|
||||
|
||||
if (a.tipo_apontamento === 'componente' && a.componente?.peso_unitario) {
|
||||
pesoUnitario = Number(a.componente.peso_unitario);
|
||||
} else if (a.tipo_apontamento === 'peca' && a.peca?.peso_unitario) {
|
||||
pesoUnitario = Number(a.peca.peso_unitario);
|
||||
}
|
||||
|
||||
realizado += pesoUnitario * Number(a.quantidade_produzida);
|
||||
});
|
||||
apontamentosAteData.forEach(a => {
|
||||
// Apenas peças mestres computam peso realizado no gráfico
|
||||
if (a.tipo_apontamento === 'peca' && a.peca?.peso_unitario) {
|
||||
realizado += Number(a.peca.peso_unitario) * Number(a.quantidade_produzida);
|
||||
}
|
||||
});
|
||||
|
||||
dadosGrafico.push({
|
||||
data: dataStr,
|
||||
|
||||
@@ -81,14 +81,11 @@ export const useProcessChartData = (ofNumber: string) => {
|
||||
|
||||
if (apontamentos && apontamentos.length > 0) {
|
||||
apontamentos.forEach(apontamento => {
|
||||
let pesoUnitario = 0;
|
||||
if (apontamento.tipo_apontamento === 'componente' && apontamento.componente?.peso_unitario) {
|
||||
pesoUnitario = apontamento.componente.peso_unitario;
|
||||
} else if (apontamento.tipo_apontamento === 'peca' && apontamento.peca?.peso_unitario) {
|
||||
pesoUnitario = apontamento.peca.peso_unitario;
|
||||
}
|
||||
// Apenas peças mestres somam peso nas médias diárias e metas
|
||||
if (apontamento.tipo_apontamento !== 'peca') return;
|
||||
|
||||
const pesoTotal = pesoUnitario * apontamento.quantidade_produzida;
|
||||
const pesoUnitario = Number(apontamento.peca?.peso_unitario || 0);
|
||||
const pesoTotal = pesoUnitario * Number(apontamento.quantidade_produzida);
|
||||
pesoTotalProcessado += pesoTotal;
|
||||
|
||||
if (apontamento.data_apontamento) {
|
||||
|
||||
@@ -12,6 +12,7 @@ interface ApontamentoDiario {
|
||||
descricao: string;
|
||||
processo: string;
|
||||
quantidade: number;
|
||||
tipo_apontamento: 'peca' | 'componente';
|
||||
peso_unitario: number;
|
||||
peso_total: number;
|
||||
data_apontamento: string;
|
||||
@@ -105,6 +106,7 @@ export const useRelatorioDiario = (selectedDate: string) => {
|
||||
descricao,
|
||||
processo: apt.processo?.nome || 'N/A',
|
||||
quantidade: apt.quantidade_produzida,
|
||||
tipo_apontamento: (apt.tipo_apontamento || 'peca') as 'peca' | 'componente',
|
||||
peso_unitario,
|
||||
peso_total,
|
||||
data_apontamento: apt.data_apontamento,
|
||||
@@ -139,11 +141,14 @@ export const useRelatorioDiario = (selectedDate: string) => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedDate]);
|
||||
|
||||
// Calcular resumo por processo
|
||||
// Calcular resumo por processo (apenas peças principais computam quantidade e peso no resumo da produção)
|
||||
const resumoProcessos: ResumoProcesso[] = React.useMemo(() => {
|
||||
const resumo = new Map<string, { quantidade: number; apontamentos: number; peso_total: number }>();
|
||||
|
||||
apontamentos.forEach(apt => {
|
||||
// Ignorar componentes no resumo global de produção para evitar peso e contagem duplicados
|
||||
if (apt.tipo_apontamento !== 'peca') return;
|
||||
|
||||
const processo = apt.processo;
|
||||
if (!resumo.has(processo)) {
|
||||
resumo.set(processo, { quantidade: 0, apontamentos: 0, peso_total: 0 });
|
||||
|
||||
@@ -119,6 +119,15 @@ export const useValidacaoSequencialProcessos = () => {
|
||||
return { valido: true };
|
||||
}
|
||||
|
||||
// Componentes só podem ser processados no primeiro processo (Corte / Preparação)
|
||||
const itemEComponente = historico.some(h => h.marca_item === marcaItem && h.tipo_item === 'componente');
|
||||
if (itemEComponente) {
|
||||
return {
|
||||
valido: false,
|
||||
erro: `Componente ${marcaItem} não pode ser apontado após a etapa de Corte / Preparação.`
|
||||
};
|
||||
}
|
||||
|
||||
// Buscar histórico do item específico
|
||||
const historicoItem = historico.filter(h => h.marca_item === marcaItem);
|
||||
|
||||
@@ -238,41 +247,14 @@ export const useValidacaoSequencialProcessos = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Processar componentes
|
||||
for (const componente of componentes) {
|
||||
const marcaComp = String(componente.marca_componente || '');
|
||||
const qtdComp = Number(componente.quantidade_total || 0);
|
||||
|
||||
if (ordemAtual === 1) {
|
||||
// Primeiro processo: todos os componentes estão disponíveis
|
||||
// Processar componentes: apenas disponíveis no primeiro processo (Corte / Preparação)
|
||||
if (ordemAtual === 1) {
|
||||
for (const componente of componentes) {
|
||||
const qtdComp = Number(componente.quantidade_total || 0);
|
||||
componentesDisponiveis.push({
|
||||
...componente,
|
||||
quantidade_disponivel: qtdComp
|
||||
});
|
||||
} else {
|
||||
// Calcular quantidade disponível baseada no processo anterior
|
||||
const quantidadeProcessadaAnterior = await calcularQuantidadeDisponivelProcessoAnterior(
|
||||
marcaComp,
|
||||
ordemAtual - 1,
|
||||
ofNumber,
|
||||
'componente'
|
||||
);
|
||||
|
||||
const quantidadeJaProcessadaAtual = await buscarQuantidadeProcessada(
|
||||
marcaComp,
|
||||
processoId,
|
||||
ofNumber,
|
||||
'componente'
|
||||
);
|
||||
|
||||
const quantidadeDisponivel = quantidadeProcessadaAnterior - quantidadeJaProcessadaAtual;
|
||||
|
||||
if (quantidadeDisponivel > 0) {
|
||||
componentesDisponiveis.push({
|
||||
...componente,
|
||||
quantidade_disponivel: quantidadeDisponivel
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user