fix: isolar componentes e aplicar trava de teto na disponibilidade do Modo Smart
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
// Script temporário de auditoria da OF B134
|
||||
export {};
|
||||
@@ -110,11 +110,11 @@ export default function Visualizador3D() {
|
||||
.select('id, of_number, etapa_fase, marca, descricao, quantidade, peso_unitario, peso_total, perfil_principal, material')
|
||||
.eq('of_number', selectedOF);
|
||||
|
||||
// Fetch apontamentos com join de peca e processo
|
||||
// Fetch apontamentos com join de peca e processo (apenas peças mestres)
|
||||
const { data: apontamentosData, error: errorApontamentos } = await supabase
|
||||
.from('apontamentos_producao' as any)
|
||||
.select(`
|
||||
id, of_number, peca_id, quantidade_produzida,
|
||||
id, of_number, peca_id, quantidade_produzida, tipo_apontamento, componente_id,
|
||||
peca:pecas!apontamentos_producao_peca_id_fkey(marca, etapa_fase),
|
||||
processo:processos_fabricacao!apontamentos_producao_processo_id_fkey(nome, cor, ordem)
|
||||
`)
|
||||
@@ -188,6 +188,10 @@ export default function Visualizador3D() {
|
||||
apontamentosData.sort((a: any, b: any) => (a.processo?.ordem || 0) - (b.processo?.ordem || 0));
|
||||
|
||||
apontamentosData.forEach((ap: any) => {
|
||||
// Ignora apontamentos de componentes para não inflar as peças mestres
|
||||
if (ap.tipo_apontamento && ap.tipo_apontamento !== 'peca') return;
|
||||
if (ap.componente_id) return;
|
||||
|
||||
const marca = ap.peca?.marca ? String(ap.peca.marca).trim() : '';
|
||||
const fase = ap.peca?.etapa_fase ? String(ap.peca.etapa_fase).trim() : '';
|
||||
if (marca) {
|
||||
|
||||
@@ -90,10 +90,10 @@ export const SmartConsultaRelatoriosFlow: React.FC<SmartConsultaRelatoriosFlowPr
|
||||
.from('processos_fabricacao')
|
||||
.select('id, nome, ordem'),
|
||||
|
||||
// 3. Apontamentos da OF
|
||||
// 3. Apontamentos da OF (apenas peças mestres)
|
||||
supabase
|
||||
.from('apontamentos_producao')
|
||||
.select('peca_id, processo_id, quantidade_produzida')
|
||||
.select('peca_id, processo_id, quantidade_produzida, tipo_apontamento, componente_id')
|
||||
.eq('of_number', obra.of_number),
|
||||
|
||||
// 4. Expedição em Romaneios (APENAS ROMANEIOS ENTREGUES E MAPEANDO POR PECA_ID PARA EVITAR CONFLITO DE FASE)
|
||||
@@ -132,6 +132,10 @@ export const SmartConsultaRelatoriosFlow: React.FC<SmartConsultaRelatoriosFlowPr
|
||||
>();
|
||||
|
||||
(resApontamentos.data || []).forEach((ap: any) => {
|
||||
// Ignora apontamentos de componentes para não inflar as quantidades da peça mestre
|
||||
if (ap.tipo_apontamento && ap.tipo_apontamento !== 'peca') return;
|
||||
if (ap.componente_id) return;
|
||||
|
||||
const pecaId = ap.peca_id;
|
||||
const nomeProc = mapaNomeProcesso.get(ap.processo_id) || '';
|
||||
const qtd = Number(ap.quantidade_produzida || 0);
|
||||
|
||||
@@ -94,7 +94,8 @@ export const calcularSaldoProcessoPeca = (
|
||||
if (procAnteriorValido) {
|
||||
const keyAnt = `${peca.id}_${procAnteriorValido.id}`;
|
||||
const qtdApontadaAnterior = mapaProd.get(keyAnt) || 0;
|
||||
qtdDisponivelParaEntrar = qtdApontadaAnterior;
|
||||
// Trava de teto: o saldo para entrar jamais pode exceder o total da peça
|
||||
qtdDisponivelParaEntrar = Math.min(Number(peca.quantidade) || 0, qtdApontadaAnterior);
|
||||
|
||||
if (qtdApontadaAnterior === 0) {
|
||||
motivoBloqueio = `Aguardando ${procAnteriorValido.nome}`;
|
||||
@@ -127,7 +128,7 @@ export const calcularSaldoProcessoPeca = (
|
||||
}
|
||||
}
|
||||
|
||||
const saldo = Math.max(0, qtdDisponivelParaEntrar - jaProduzidoAtual);
|
||||
const saldo = Math.max(0, Math.min(Number(peca.quantidade) || 0, qtdDisponivelParaEntrar) - jaProduzidoAtual);
|
||||
|
||||
return {
|
||||
saldo,
|
||||
@@ -149,6 +150,8 @@ interface ApontamentoItem {
|
||||
status_confirmacao?: string;
|
||||
forcado_por_user_nome?: string;
|
||||
usuario_nome?: string;
|
||||
tipo_apontamento?: string;
|
||||
componente_id?: string | null;
|
||||
}
|
||||
|
||||
export const SmartProducaoFlow: React.FC<SmartProducaoFlowProps> = ({
|
||||
@@ -190,7 +193,7 @@ export const SmartProducaoFlow: React.FC<SmartProducaoFlowProps> = ({
|
||||
.eq('of_number', obra.of_number),
|
||||
supabase
|
||||
.from('apontamentos_producao')
|
||||
.select('id, peca_id, processo_id, quantidade_produzida, is_forcado, status_confirmacao, forcado_por_user_nome, usuario_nome')
|
||||
.select('id, peca_id, processo_id, quantidade_produzida, is_forcado, status_confirmacao, forcado_por_user_nome, usuario_nome, tipo_apontamento, componente_id')
|
||||
.eq('of_number', obra.of_number),
|
||||
]);
|
||||
|
||||
@@ -224,10 +227,14 @@ export const SmartProducaoFlow: React.FC<SmartProducaoFlowProps> = ({
|
||||
return lista.length > 0 ? lista : ['Geral'];
|
||||
}, [pecas]);
|
||||
|
||||
// Mapa de produção acumulada por peca_id e processo_id
|
||||
// Mapa de produção acumulada por peca_id e processo_id (apenas apontamentos de peças mestres)
|
||||
const mapaProducao = useMemo(() => {
|
||||
const mapa = new Map<string, number>();
|
||||
apontamentosExistentes.forEach((ap) => {
|
||||
// Ignora apontamentos de componentes para não inflar a contagem da peça pai
|
||||
if (ap.tipo_apontamento && ap.tipo_apontamento !== 'peca') return;
|
||||
if (ap.componente_id) return;
|
||||
|
||||
const key = `${ap.peca_id}_${ap.processo_id}`;
|
||||
const atual = mapa.get(key) || 0;
|
||||
mapa.set(key, atual + Number(ap.quantidade_produzida || 0));
|
||||
@@ -238,7 +245,11 @@ export const SmartProducaoFlow: React.FC<SmartProducaoFlowProps> = ({
|
||||
// Apontamentos forçados que ainda estão pendentes de confirmação de baixa
|
||||
const apontamentosPendentes = useMemo(() => {
|
||||
return apontamentosExistentes.filter(
|
||||
(ap) => ap.is_forcado && ap.status_confirmacao === 'pendente_confirmacao'
|
||||
(ap) =>
|
||||
(!ap.tipo_apontamento || ap.tipo_apontamento === 'peca') &&
|
||||
!ap.componente_id &&
|
||||
ap.is_forcado &&
|
||||
ap.status_confirmacao === 'pendente_confirmacao'
|
||||
);
|
||||
}, [apontamentosExistentes]);
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ export const SmartViewer3DFlow: React.FC<SmartViewer3DFlowProps> = ({
|
||||
supabase
|
||||
.from('apontamentos_producao' as any)
|
||||
.select(`
|
||||
id, of_number, peca_id, quantidade_produzida,
|
||||
id, of_number, peca_id, quantidade_produzida, tipo_apontamento, componente_id,
|
||||
peca:pecas!apontamentos_producao_peca_id_fkey(marca, etapa_fase),
|
||||
processo:processos_fabricacao!apontamentos_producao_processo_id_fkey(nome, cor, ordem)
|
||||
`)
|
||||
@@ -139,6 +139,10 @@ export const SmartViewer3DFlow: React.FC<SmartViewer3DFlowProps> = ({
|
||||
);
|
||||
|
||||
sortedApontamentos.forEach((ap: any) => {
|
||||
// Ignora apontamentos de componentes para não inflar as peças mestres
|
||||
if (ap.tipo_apontamento && ap.tipo_apontamento !== 'peca') return;
|
||||
if (ap.componente_id) return;
|
||||
|
||||
const marca = ap.peca?.marca ? String(ap.peca.marca).trim() : '';
|
||||
const fase = ap.peca?.etapa_fase ? String(ap.peca.etapa_fase).trim() : '';
|
||||
if (marca) {
|
||||
|
||||
Reference in New Issue
Block a user