Ajusta importação CSV
Melhora parser CSV para extrair dados corretamente, incluindo detecção de cabeçalho, mapeamento de colunas (data, descrição, valor), suporte a formato brasileiro e prevenção de duplicatas. AdicionaLoading/ animação de carregamento durante o processamento. X-Lovable-Edit-ID: edt-8e8b5436-baeb-463b-815d-f542f108e1c0
This commit is contained in:
commit
72ffa913ba
@ -16,15 +16,34 @@ export async function parseCSV(file: File, contaBancariaId?: string): Promise<Tr
|
|||||||
complete: (results) => {
|
complete: (results) => {
|
||||||
try {
|
try {
|
||||||
const transacoes: TransacaoImportada[] = [];
|
const transacoes: TransacaoImportada[] = [];
|
||||||
const data = results.data as any[];
|
const linhas = results.data as any[][]; // matriz de linhas
|
||||||
|
|
||||||
if (data.length === 0) {
|
if (!linhas || linhas.length === 0) {
|
||||||
throw new Error('Arquivo CSV vazio');
|
throw new Error('Arquivo CSV vazio');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tentar detectar colunas automaticamente
|
// Encontrar linha de cabeçalho real (que contém "Data" e "Valor" etc.)
|
||||||
const primeiraLinha = data[0];
|
let headerIndex = -1;
|
||||||
const colunas = Object.keys(primeiraLinha);
|
for (let i = 0; i < linhas.length; i++) {
|
||||||
|
const row = linhas[i];
|
||||||
|
if (!row || row.length === 0) continue;
|
||||||
|
|
||||||
|
const primeiraColuna = String(row[0] ?? '').toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
||||||
|
const segundaColuna = String(row[1] ?? '').toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
||||||
|
|
||||||
|
// Ex: "Data Lançamento" | "Histórico" | "Descrição" | "Valor" | "Saldo"
|
||||||
|
if (primeiraColuna.includes('data') && (segundaColuna.includes('historico') || segundaColuna.includes('descricao'))) {
|
||||||
|
headerIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headerIndex === -1) {
|
||||||
|
throw new Error('Não foi possível identificar o cabeçalho do arquivo (linha com Data/Histórico/Valor)');
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerRow = linhas[headerIndex];
|
||||||
|
const colunas = headerRow.map((c) => String(c ?? ''));
|
||||||
|
|
||||||
// Encontrar colunas relevantes (suporta nomes com acentos e espaços)
|
// Encontrar colunas relevantes (suporta nomes com acentos e espaços)
|
||||||
const colunaData = detectarColuna(colunas, ['data', 'date', 'quando', 'dt', 'lancamento']);
|
const colunaData = detectarColuna(colunas, ['data', 'date', 'quando', 'dt', 'lancamento']);
|
||||||
@ -36,10 +55,19 @@ export async function parseCSV(file: File, contaBancariaId?: string): Promise<Tr
|
|||||||
throw new Error('Não foi possível identificar as colunas necessárias (Data, Descrição, Valor)');
|
throw new Error('Não foi possível identificar as colunas necessárias (Data, Descrição, Valor)');
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const linha of data) {
|
// Processar linhas de dados após o cabeçalho
|
||||||
const dataStr = linha[colunaData];
|
for (let i = headerIndex + 1; i < linhas.length; i++) {
|
||||||
const descricao = limparDescricao(String(linha[colunaDescricao] || ''));
|
const linha = linhas[i];
|
||||||
const valorStr = String(linha[colunaValor] || '0');
|
if (!linha || linha.length === 0) continue;
|
||||||
|
|
||||||
|
const rowObj: Record<string, any> = {};
|
||||||
|
colunas.forEach((col, idx) => {
|
||||||
|
rowObj[col] = linha[idx];
|
||||||
|
});
|
||||||
|
|
||||||
|
const dataStr = rowObj[colunaData];
|
||||||
|
const descricao = limparDescricao(String(rowObj[colunaDescricao] || ''));
|
||||||
|
const valorStr = String(rowObj[colunaValor] || '0');
|
||||||
|
|
||||||
// Parse de data (tenta vários formatos)
|
// Parse de data (tenta vários formatos)
|
||||||
const data = parseData(dataStr);
|
const data = parseData(dataStr);
|
||||||
@ -51,9 +79,11 @@ export async function parseCSV(file: File, contaBancariaId?: string): Promise<Tr
|
|||||||
|
|
||||||
// Determinar tipo
|
// Determinar tipo
|
||||||
let tipo: 'entrada' | 'saida';
|
let tipo: 'entrada' | 'saida';
|
||||||
if (colunaTipo) {
|
if (colunaTipo && rowObj[colunaTipo] !== undefined && rowObj[colunaTipo] !== null) {
|
||||||
const tipoStr = String(linha[colunaTipo]).toLowerCase();
|
const tipoStr = String(rowObj[colunaTipo]).toLowerCase();
|
||||||
tipo = tipoStr.includes('credit') || tipoStr.includes('entrada') || tipoStr.includes('receita') ? 'entrada' : 'saida';
|
tipo = tipoStr.includes('credit') || tipoStr.includes('entrada') || tipoStr.includes('recebido') || tipoStr.includes('receita')
|
||||||
|
? 'entrada'
|
||||||
|
: 'saida';
|
||||||
} else {
|
} else {
|
||||||
tipo = valor >= 0 ? 'entrada' : 'saida';
|
tipo = valor >= 0 ? 'entrada' : 'saida';
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user