fix: persistencia e extracao de comprimento de pecas e subcomponentes na importacao
This commit is contained in:
@@ -26,7 +26,7 @@ import * as XLSX from 'xlsx';
|
||||
import { useAppLabels } from '@/hooks/useAppLabels';
|
||||
import { usePecas } from '@/hooks/usePecas';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { analisarConflitosImportacao, consolidarPecasEComponentes } from '@/utils/importDiffService';
|
||||
import { analisarConflitosImportacao, consolidarPecasEComponentes, extrairComprimentoSeguro, extrairComprimentoComponenteSeguro } from '@/utils/importDiffService';
|
||||
import { ResultadoAnaliseImportacao } from '@/types/importDiff';
|
||||
import { ImportarPecasDiffModal } from '@/components/pecas/ImportarPecasDiffModal';
|
||||
|
||||
@@ -835,8 +835,12 @@ const AdvanceSteelConverterContent: React.FC = () => {
|
||||
try {
|
||||
const importacaoRows: any[] = [];
|
||||
extractedData.forEach((item) => {
|
||||
const comprPeca = extrairComprimentoSeguro(item.comprimentoMax);
|
||||
|
||||
if (item.components && item.components.length > 0) {
|
||||
item.components.forEach((comp) => {
|
||||
const comprComp = extrairComprimentoComponenteSeguro(comp.comprimento);
|
||||
|
||||
importacaoRows.push({
|
||||
of_number: item.of,
|
||||
etapa_fase: item.fase,
|
||||
@@ -845,6 +849,8 @@ const AdvanceSteelConverterContent: React.FC = () => {
|
||||
quantidade: Number(item.quantidade),
|
||||
peso_unitario: item.pesoUnit === '-' ? 0 : Number(item.pesoUnit),
|
||||
peso_total: item.pesoTotal === '-' ? 0 : Number(item.pesoTotal),
|
||||
comprimento: comprPeca,
|
||||
comprimento_ref: comprPeca,
|
||||
tratamento_superficial: item.tratamentoSuperficial || tratamentoGlobal,
|
||||
material: item.material,
|
||||
perfil_principal: item.perfilPrincipal,
|
||||
@@ -853,6 +859,7 @@ const AdvanceSteelConverterContent: React.FC = () => {
|
||||
descricao_componente: comp.perfil || item.descricao,
|
||||
perfil_componente: comp.perfil || item.descricao,
|
||||
peso_unitario_componente: comp.pesoUnitario || 0,
|
||||
comprimento_componente: comprComp,
|
||||
quantidade_por_peca: Number(comp.quantidade) || 1
|
||||
});
|
||||
});
|
||||
@@ -865,6 +872,8 @@ const AdvanceSteelConverterContent: React.FC = () => {
|
||||
quantidade: Number(item.quantidade),
|
||||
peso_unitario: item.pesoUnit === '-' ? 0 : Number(item.pesoUnit),
|
||||
peso_total: item.pesoTotal === '-' ? 0 : Number(item.pesoTotal),
|
||||
comprimento: comprPeca,
|
||||
comprimento_ref: comprPeca,
|
||||
tratamento_superficial: item.tratamentoSuperficial || tratamentoGlobal,
|
||||
material: item.material,
|
||||
perfil_principal: item.perfilPrincipal,
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
import { toast } from 'sonner';
|
||||
import * as XLSX from 'xlsx';
|
||||
import { usePecas } from '@/hooks/usePecas';
|
||||
import { analisarConflitosImportacao, consolidarPecasEComponentes } from '@/utils/importDiffService';
|
||||
import { analisarConflitosImportacao, consolidarPecasEComponentes, extrairComprimentoSeguro, extrairComprimentoComponenteSeguro } from '@/utils/importDiffService';
|
||||
import { ResultadoAnaliseImportacao } from '@/types/importDiff';
|
||||
import { ImportarPecasDiffModal } from '@/components/pecas/ImportarPecasDiffModal';
|
||||
|
||||
@@ -532,8 +532,12 @@ export const BocadConverter: React.FC = () => {
|
||||
try {
|
||||
const importacaoRows: any[] = [];
|
||||
extractedPieces.forEach((item) => {
|
||||
const comprPeca = extrairComprimentoSeguro(item.comprimentoRef);
|
||||
|
||||
if (item.compostoPorComponentes === 'SIM' && item.components && item.components.length > 0) {
|
||||
item.components.forEach((comp) => {
|
||||
const comprComp = extrairComprimentoComponenteSeguro(comp.compr);
|
||||
|
||||
importacaoRows.push({
|
||||
of_number: item.of,
|
||||
etapa_fase: item.fase,
|
||||
@@ -542,6 +546,8 @@ export const BocadConverter: React.FC = () => {
|
||||
quantidade: Number(item.quantidade),
|
||||
peso_unitario: item.pesoUnitario || 0,
|
||||
peso_total: item.pesoTotal || 0,
|
||||
comprimento: comprPeca,
|
||||
comprimento_ref: comprPeca,
|
||||
tratamento_superficial: item.tratamentoSuperficial,
|
||||
material: item.material,
|
||||
perfil_principal: item.perfilPrincipal,
|
||||
@@ -550,6 +556,7 @@ export const BocadConverter: React.FC = () => {
|
||||
descricao_componente: comp.perfil || item.descricao,
|
||||
perfil_componente: comp.perfil || item.descricao,
|
||||
peso_unitario_componente: comp.pesoUnit || 0,
|
||||
comprimento_componente: comprComp,
|
||||
quantidade_por_peca: Number(comp.quant) || 1
|
||||
});
|
||||
});
|
||||
@@ -562,6 +569,8 @@ export const BocadConverter: React.FC = () => {
|
||||
quantidade: Number(item.quantidade),
|
||||
peso_unitario: item.pesoUnitario || 0,
|
||||
peso_total: item.pesoTotal || 0,
|
||||
comprimento: comprPeca,
|
||||
comprimento_ref: comprPeca,
|
||||
tratamento_superficial: item.tratamentoSuperficial,
|
||||
material: item.material,
|
||||
perfil_principal: item.perfilPrincipal,
|
||||
|
||||
@@ -25,10 +25,13 @@ interface PecaCSVData {
|
||||
material: string;
|
||||
perfil_principal: string;
|
||||
tem_componentes: boolean;
|
||||
comprimento?: number | null;
|
||||
comprimento_ref?: number | string;
|
||||
marca_componente?: string;
|
||||
descricao_componente?: string;
|
||||
perfil_componente?: string;
|
||||
peso_unitario_componente?: number;
|
||||
comprimento_componente?: number | null;
|
||||
quantidade_por_peca?: number;
|
||||
}
|
||||
|
||||
@@ -108,7 +111,7 @@ export function ImportarPecasModal({ open, onOpenChange, onImport, pecasExistent
|
||||
});
|
||||
|
||||
// Validar e converter campos numéricos
|
||||
const numericFields = ['quantidade', 'peso_unitario', 'peso_total', 'peso_unitario_componente', 'quantidade_por_peca'];
|
||||
const numericFields = ['quantidade', 'peso_unitario', 'peso_total', 'peso_unitario_componente', 'quantidade_por_peca', 'comprimento', 'comprimento_ref', 'comprimento_componente'];
|
||||
const convertedData: any = { ...rawRow };
|
||||
|
||||
numericFields.forEach(field => {
|
||||
@@ -177,10 +180,12 @@ export function ImportarPecasModal({ open, onOpenChange, onImport, pecasExistent
|
||||
material: convertedData.material?.toString().trim() || '',
|
||||
perfil_principal: convertedData.perfil_principal?.toString().trim() || '',
|
||||
tem_componentes: convertedData.tem_componentes,
|
||||
comprimento: convertedData.comprimento ? Number(convertedData.comprimento) : (convertedData.comprimento_ref ? Number(convertedData.comprimento_ref) : null),
|
||||
marca_componente: convertedData.marca_componente?.toString().trim() || '',
|
||||
descricao_componente: convertedData.descricao_componente?.toString().trim() || '',
|
||||
perfil_componente: convertedData.perfil_componente?.toString().trim() || '',
|
||||
peso_unitario_componente: convertedData.peso_unitario_componente || 0,
|
||||
comprimento_componente: convertedData.comprimento_componente ? Number(convertedData.comprimento_componente) : null,
|
||||
quantidade_por_peca: convertedData.quantidade_por_peca || 0
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@
|
||||
import { FileSpreadsheet, Upload, Download, CheckCircle2, AlertCircle, Trash2, ArrowLeft, RefreshCw } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import * as XLSX from 'xlsx';
|
||||
import { analisarConflitosImportacao, consolidarPecasEComponentes } from '@/utils/importDiffService';
|
||||
import { analisarConflitosImportacao, consolidarPecasEComponentes, extrairComprimentoSeguro, extrairComprimentoComponenteSeguro } from '@/utils/importDiffService';
|
||||
import { ResultadoAnaliseImportacao } from '@/types/importDiff';
|
||||
import { ImportarPecasDiffModal } from '@/components/pecas/ImportarPecasDiffModal';
|
||||
|
||||
@@ -471,8 +471,8 @@ export function ImportarXLSModal({
|
||||
quantidade: p.quantidade,
|
||||
peso_unitario: p.peso_unitario,
|
||||
peso_total: p.peso_total,
|
||||
comprimento: p.comprimento !== undefined && p.comprimento !== null ? Number(p.comprimento) : (p.comprimento_ref ? Number(p.comprimento_ref) : null),
|
||||
comprimento_ref: p.comprimento_ref ? Number(p.comprimento_ref) : (p.comprimento ? Number(p.comprimento) : null),
|
||||
comprimento: extrairComprimentoSeguro(p),
|
||||
comprimento_ref: extrairComprimentoSeguro(p),
|
||||
tratamento_superficial: p.tratamento_superficial || 'pintura',
|
||||
material: p.material,
|
||||
perfil_principal: p.perfil_principal,
|
||||
@@ -481,6 +481,7 @@ export function ImportarXLSModal({
|
||||
descricao_componente: p.descricao_componente,
|
||||
perfil_componente: p.perfil_componente,
|
||||
peso_unitario_componente: p.peso_unitario_componente,
|
||||
comprimento_componente: extrairComprimentoComponenteSeguro(p),
|
||||
quantidade_por_peca: p.quantidade_por_peca,
|
||||
}));
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState, useEffect, useCallback } from 'react';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { toast } from 'sonner';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { extrairComprimentoSeguro, extrairComprimentoComponenteSeguro } from '@/utils/importDiffService';
|
||||
|
||||
export interface Peca {
|
||||
id: string;
|
||||
@@ -425,6 +426,7 @@ export function usePecas() {
|
||||
|
||||
pecasData.forEach((item, index) => {
|
||||
const pecaKey = `${item.of_number || ''}-${item.etapa_fase || ''}-${item.marca || ''}`;
|
||||
const comprimentoPeca = extrairComprimentoSeguro(item);
|
||||
|
||||
const pecaData = {
|
||||
of_number: item.of_number || '',
|
||||
@@ -434,7 +436,7 @@ export function usePecas() {
|
||||
quantidade: Number(item.quantidade) || 0,
|
||||
peso_unitario: Number(item.peso_unitario) || 0,
|
||||
peso_total: Number(item.peso_total) || 0,
|
||||
comprimento: item.comprimento ? Number(item.comprimento) : (item.comprimento_ref ? Number(item.comprimento_ref) : null),
|
||||
comprimento: comprimentoPeca,
|
||||
tratamento_superficial: item.tratamento_superficial || '',
|
||||
material: item.material || '',
|
||||
perfil_principal: item.perfil_principal || '',
|
||||
@@ -445,6 +447,8 @@ export function usePecas() {
|
||||
|
||||
if (!pecasMap.has(pecaKey)) {
|
||||
pecasMap.set(pecaKey, pecaData);
|
||||
} else if (comprimentoPeca && !pecasMap.get(pecaKey).comprimento) {
|
||||
pecasMap.get(pecaKey).comprimento = comprimentoPeca;
|
||||
}
|
||||
|
||||
if (item.marca_componente && String(item.marca_componente).trim()) {
|
||||
@@ -470,12 +474,13 @@ export function usePecas() {
|
||||
}
|
||||
cleanMarca = String(numVal);
|
||||
|
||||
const compComprimento = extrairComprimentoComponenteSeguro(item);
|
||||
const componenteData = {
|
||||
marca_componente: cleanMarca,
|
||||
descricao: item.descricao_componente || item.descricao || '',
|
||||
perfil: item.perfil_componente || item.perfil_principal || '',
|
||||
peso_unitario: Number(item.peso_unitario_componente) || 0,
|
||||
comprimento: item.comprimento_componente ? Number(item.comprimento_componente) : null,
|
||||
comprimento: compComprimento,
|
||||
quantidade_por_peca: Math.max(1, Math.round(Number(item.quantidade_por_peca) || 1)),
|
||||
user_id: user.id
|
||||
};
|
||||
|
||||
@@ -27,6 +27,90 @@ const CAMPOS_MONITORADOS: CampoConfig[] = [
|
||||
{ key: 'tem_componentes', label: 'Tem Componentes', isCritico: true },
|
||||
];
|
||||
|
||||
/**
|
||||
* Função utilitária resiliente para extrair o comprimento numérico de uma peça principal.
|
||||
* Suporta múltiplos aliases de importação (Bocad, Advance Steel, Excel, CSV) e formatações de string.
|
||||
*/
|
||||
export function extrairComprimentoSeguro(item: any): number | null {
|
||||
if (!item) return null;
|
||||
|
||||
const raw =
|
||||
item.comprimento ??
|
||||
item.comprimento_ref ??
|
||||
item.comprimentoRef ??
|
||||
item.comprimentoMax ??
|
||||
item.comprimento_max ??
|
||||
item.comprimento_peca ??
|
||||
item['Comprimento'] ??
|
||||
item['Comprimento (mm)'] ??
|
||||
item['Comprimento Ref. (mm)'] ??
|
||||
item['Comprimento Max. (mm)'] ??
|
||||
item['Comp. (mm)'] ??
|
||||
item['Comp (mm)'] ??
|
||||
item.compr ??
|
||||
item.comp;
|
||||
|
||||
if (raw === undefined || raw === null || raw === '' || raw === '-') return null;
|
||||
|
||||
if (typeof raw === 'number') {
|
||||
return isNaN(raw) || raw <= 0 ? null : Math.round(raw);
|
||||
}
|
||||
|
||||
// String cleanup: trata formatos como "3.241", "3,241", "6000 mm", "5850.5"
|
||||
let str = String(raw).trim().replace(/mm/gi, '').trim();
|
||||
if (str.includes('.') && str.includes(',')) {
|
||||
if (str.indexOf('.') < str.indexOf(',')) {
|
||||
str = str.replace(/\./g, '').replace(',', '.');
|
||||
} else {
|
||||
str = str.replace(/,/g, '');
|
||||
}
|
||||
} else if (str.includes(',')) {
|
||||
str = str.replace(',', '.');
|
||||
}
|
||||
|
||||
const num = parseFloat(str);
|
||||
return isNaN(num) || num <= 0 ? null : Math.round(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Função utilitária resiliente para extrair o comprimento numérico de subcomponentes.
|
||||
*/
|
||||
export function extrairComprimentoComponenteSeguro(item: any): number | null {
|
||||
if (!item) return null;
|
||||
|
||||
const raw =
|
||||
item.comprimento_componente ??
|
||||
item.comprimentoComponente ??
|
||||
item.comprimento ??
|
||||
item.comprimento_ref ??
|
||||
item.compr ??
|
||||
item.comp ??
|
||||
item['Comprimento Componente'] ??
|
||||
item['Comprimento (mm)'] ??
|
||||
item['Comprimento'] ??
|
||||
item['Comp. (mm)'];
|
||||
|
||||
if (raw === undefined || raw === null || raw === '' || raw === '-') return null;
|
||||
|
||||
if (typeof raw === 'number') {
|
||||
return isNaN(raw) || raw <= 0 ? null : Math.round(raw);
|
||||
}
|
||||
|
||||
let str = String(raw).trim().replace(/mm/gi, '').trim();
|
||||
if (str.includes('.') && str.includes(',')) {
|
||||
if (str.indexOf('.') < str.indexOf(',')) {
|
||||
str = str.replace(/\./g, '').replace(',', '.');
|
||||
} else {
|
||||
str = str.replace(/,/g, '');
|
||||
}
|
||||
} else if (str.includes(',')) {
|
||||
str = str.replace(',', '.');
|
||||
}
|
||||
|
||||
const num = parseFloat(str);
|
||||
return isNaN(num) || num <= 0 ? null : Math.round(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normaliza e agrupa linhas de peças e subcomponentes
|
||||
*/
|
||||
@@ -45,6 +129,7 @@ export function consolidarPecasEComponentes(rawItems: any[]): {
|
||||
if (!marca) return;
|
||||
|
||||
const pecaKey = `${ofNumber}-${etapaFase}-${marca}`;
|
||||
const comprimentoFinal = extrairComprimentoSeguro(item);
|
||||
|
||||
const pecaData = {
|
||||
of_number: ofNumber,
|
||||
@@ -54,12 +139,7 @@ export function consolidarPecasEComponentes(rawItems: any[]): {
|
||||
quantidade: Number(item.quantidade) || 0,
|
||||
peso_unitario: Number(item.peso_unitario) || 0,
|
||||
peso_total: Number(item.peso_total) || 0,
|
||||
comprimento:
|
||||
item.comprimento !== undefined && item.comprimento !== null
|
||||
? Number(item.comprimento)
|
||||
: item.comprimento_ref
|
||||
? Number(item.comprimento_ref)
|
||||
: null,
|
||||
comprimento: comprimentoFinal,
|
||||
tratamento_superficial: item.tratamento_superficial || 'pintura',
|
||||
material: item.material || 'Aço A36',
|
||||
perfil_principal: item.perfil_principal || item.descricao || '',
|
||||
@@ -68,6 +148,9 @@ export function consolidarPecasEComponentes(rawItems: any[]): {
|
||||
|
||||
if (!pecasMap.has(pecaKey)) {
|
||||
pecasMap.set(pecaKey, pecaData);
|
||||
} else if (comprimentoFinal && !pecasMap.get(pecaKey).comprimento) {
|
||||
// Se a peça já estava no mapa mas sem comprimento e esta linha tem, atualiza
|
||||
pecasMap.get(pecaKey).comprimento = comprimentoFinal;
|
||||
}
|
||||
|
||||
// Se o item contém um subcomponente
|
||||
@@ -92,12 +175,14 @@ export function consolidarPecasEComponentes(rawItems: any[]): {
|
||||
}
|
||||
cleanMarca = String(numVal);
|
||||
|
||||
const compComprimento = extrairComprimentoComponenteSeguro(item);
|
||||
|
||||
const compData = {
|
||||
marca_componente: cleanMarca,
|
||||
descricao: item.descricao_componente || item.descricao || '',
|
||||
perfil: item.perfil_componente || item.perfil_principal || '',
|
||||
peso_unitario: Number(item.peso_unitario_componente) || 0,
|
||||
comprimento: item.comprimento_componente ? Number(item.comprimento_componente) : null,
|
||||
comprimento: compComprimento,
|
||||
quantidade_por_peca: Math.max(1, Math.round(Number(item.quantidade_por_peca) || 1)),
|
||||
};
|
||||
|
||||
@@ -110,6 +195,12 @@ export function consolidarPecasEComponentes(rawItems: any[]): {
|
||||
const exists = comps.some((c) => c.marca_componente === cleanMarca);
|
||||
if (!exists) {
|
||||
comps.push(compData);
|
||||
} else if (compComprimento) {
|
||||
// Se já existia mas sem comprimento, atualiza
|
||||
const cExistente = comps.find((c) => c.marca_componente === cleanMarca);
|
||||
if (cExistente && !cExistente.comprimento) {
|
||||
cExistente.comprimento = compComprimento;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { ItemAnaliseImportacao } from '@/types/importDiff';
|
||||
import { extrairComprimentoSeguro } from '@/utils/importDiffService';
|
||||
|
||||
export interface ExecucaoImportacaoParams {
|
||||
itens: ItemAnaliseImportacao[];
|
||||
@@ -75,12 +76,14 @@ export async function executarImportacaoConciliada(
|
||||
const pesoUnitFinal = Number(importado.peso_unitario || existente.peso_unitario || 0);
|
||||
const pesoTotalCalculado = Number((qtdFinal * pesoUnitFinal).toFixed(3)) || Number(importado.peso_total || 0);
|
||||
|
||||
const comprFinal = extrairComprimentoSeguro(importado) ?? extrairComprimentoSeguro(existente);
|
||||
|
||||
const payloadUpdate: any = {
|
||||
descricao: importado.descricao || existente.descricao || '',
|
||||
quantidade: qtdFinal,
|
||||
peso_unitario: pesoUnitFinal,
|
||||
peso_total: pesoTotalCalculado,
|
||||
comprimento: importado.comprimento !== undefined ? importado.comprimento : existente.comprimento,
|
||||
comprimento: comprFinal,
|
||||
tratamento_superficial: importado.tratamento_superficial || existente.tratamento_superficial || 'pintura',
|
||||
material: importado.material || existente.material || 'Aço A36',
|
||||
perfil_principal: importado.perfil_principal || existente.perfil_principal || '',
|
||||
@@ -170,6 +173,7 @@ export async function executarImportacaoConciliada(
|
||||
const qtd = Number(imp.quantidade) || 0;
|
||||
const pesoU = Number(imp.peso_unitario) || 0;
|
||||
const pesoT = Number(imp.peso_total) || Number((qtd * pesoU).toFixed(3));
|
||||
const comprFinal = extrairComprimentoSeguro(imp);
|
||||
|
||||
return {
|
||||
of_number: imp.of_number,
|
||||
@@ -179,7 +183,7 @@ export async function executarImportacaoConciliada(
|
||||
quantidade: qtd,
|
||||
peso_unitario: pesoU,
|
||||
peso_total: pesoT,
|
||||
comprimento: imp.comprimento || null,
|
||||
comprimento: comprFinal,
|
||||
tratamento_superficial: imp.tratamento_superficial || 'pintura',
|
||||
material: imp.material || 'Aço A36',
|
||||
perfil_principal: imp.perfil_principal || '',
|
||||
|
||||
Reference in New Issue
Block a user