From a5ce93042c1b36d694b8354030694545c64917dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Wed, 22 Oct 2025 14:19:16 -0300 Subject: [PATCH] =?UTF-8?q?fix:=20corre=C3=A7=C3=A3o=20da=20exporta=C3=A7?= =?UTF-8?q?=C3=A3o=20dos=20dados=20sint=C3=A9ticos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/teste.tsx | 308 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 307 insertions(+), 1 deletion(-) diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index 6e72523..f04a8eb 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -1,12 +1,13 @@ "use client"; -import { LoaderPinwheel, ChevronDown, ChevronRight, Filter, Maximize2, Minimize2 } from "lucide-react"; +import { LoaderPinwheel, ChevronDown, ChevronRight, Filter, Maximize2, Minimize2, Download } from "lucide-react"; import { useEffect, useState, useCallback, startTransition, memo } from "react"; import AnaliticoComponent from "./analitico"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; +import * as XLSX from "xlsx"; import { Sheet, SheetContent, @@ -498,6 +499,299 @@ export default function Teste() { setContasSelecionadas([]); }; + const exportarXLSX = () => { + if (!data.length) { + console.log('⚠️ Nenhum dado para exportar'); + return; + } + + console.log('📊 Exportando TODOS os dados expandidos para XLSX...'); + + // Criar uma versão completamente expandida dos dados hierárquicos + const dadosCompletosExpandidos = buildHierarchicalDataCompleta(); + + // Preparar dados para exportação + const dadosExportacao = dadosCompletosExpandidos.map((row, index) => { + const linha: any = { + 'Linha': index + 1, + 'Tipo': row.type, + 'Nível': row.level, + 'Grupo': row.grupo || '', + 'Centro de Custo': row.centro_custo || '', + 'Conta': row.conta || '', + 'Código Centro': row.codigo_centro_custo || '', + 'Código Conta': row.codigo_conta || '', + 'Total': row.total || 0, + }; + + // Adicionar colunas dos meses + mesesDisponiveis.forEach(mes => { + const valor = row.valoresPorMes?.[mes] || 0; + const percentual = row.percentuaisPorMes?.[mes] || 0; + linha[`Valor ${mes}`] = valor; + linha[`% ${mes}`] = percentual; + }); + + return linha; + }); + + // Criar workbook + const wb = XLSX.utils.book_new(); + + // Criar worksheet principal + const ws = XLSX.utils.json_to_sheet(dadosExportacao); + + // Ajustar largura das colunas + const colWidths = [ + { wch: 8 }, // Linha + { wch: 15 }, // Tipo + { wch: 8 }, // Nível + { wch: 30 }, // Grupo + { wch: 25 }, // Centro de Custo + { wch: 35 }, // Conta + { wch: 15 }, // Código Centro + { wch: 12 }, // Código Conta + { wch: 15 }, // Total + ]; + + // Adicionar larguras para colunas dos meses + mesesDisponiveis.forEach(() => { + colWidths.push({ wch: 15 }); // Valor + colWidths.push({ wch: 10 }); // % + }); + + ws['!cols'] = colWidths; + + // Adicionar worksheet ao workbook + XLSX.utils.book_append_sheet(wb, ws, 'DRE Gerencial Completo'); + + // Criar worksheet de resumo + const resumoData = [ + { 'Informação': 'Período', 'Valor': `${filtros.periodoDe} a ${filtros.periodoAte}` }, + { 'Informação': 'Grupo', 'Valor': filtros.grupo }, + { 'Informação': 'Subgrupo', 'Valor': filtros.subgrupo }, + { 'Informação': 'Centro de Custo', 'Valor': filtros.centroCusto }, + { 'Informação': 'Conta', 'Valor': filtros.conta }, + { 'Informação': 'Valor Mínimo', 'Valor': filtros.valorMin || 'N/A' }, + { 'Informação': 'Valor Máximo', 'Valor': filtros.valorMax || 'N/A' }, + { 'Informação': 'Busca Textual', 'Valor': filtros.buscaTextual || 'N/A' }, + { 'Informação': 'Ordem Hierárquica', 'Valor': ordemHierarquiaContasPrimeiro ? 'Contas → Centros' : 'Centros → Contas' }, + { 'Informação': 'Total de Registros', 'Valor': dadosCompletosExpandidos.length }, + { 'Informação': 'Data de Exportação', 'Valor': new Date().toLocaleString('pt-BR') }, + ]; + + const wsResumo = XLSX.utils.json_to_sheet(resumoData); + wsResumo['!cols'] = [{ wch: 20 }, { wch: 30 }]; + XLSX.utils.book_append_sheet(wb, wsResumo, 'Resumo'); + + // Gerar nome do arquivo + const dataAtual = new Date().toISOString().split('T')[0]; + const nomeArquivo = `DRE_Gerencial_Completo_${dataAtual}.xlsx`; + + // Exportar arquivo + XLSX.writeFile(wb, nomeArquivo); + + console.log('✅ Arquivo XLSX completo exportado:', nomeArquivo); + }; + + // Função para construir dados hierárquicos completamente expandidos + const buildHierarchicalDataCompleta = (): HierarchicalRow[] => { + const rows: HierarchicalRow[] = []; + + // Agrupar dados por grupo + const grupos = data.reduce((acc, item) => { + if (!acc[item.grupo]) { + acc[item.grupo] = []; + } + acc[item.grupo].push(item); + return acc; + }, {} as Record); + + // Ordenar grupos por código + const sortedGrupos = Object.entries(grupos).sort(([grupoA, itemsA], [grupoB, itemsB]) => { + const codigoA = itemsA[0]?.codgrupo || ""; + const codigoB = itemsB[0]?.codgrupo || ""; + return codigoA.localeCompare(codigoB); + }); + + sortedGrupos.forEach(([grupo, items]) => { + const totalGrupo = items.reduce( + (sum, item) => sum + parseFloat(item.valor), + 0 + ); + + // Linha do grupo (Level 0) + const valoresGrupoPorMes = calcularValoresPorMes(items); + rows.push({ + type: "grupo", + level: 0, + grupo, + total: totalGrupo, + valoresPorMes: valoresGrupoPorMes, + percentuaisPorMes: calcularPercentuaisPorMes(valoresGrupoPorMes, grupo), + isCalculado: items[0]?.isCalculado || false, + }); + + if (ordemHierarquiaContasPrimeiro) { + // ORDEM: Grupos → Contas → Centros de Custo + + // Agrupar por conta dentro do grupo + const contas = items.reduce((acc, item) => { + if (!acc[item.conta]) { + acc[item.conta] = []; + } + acc[item.conta].push(item); + return acc; + }, {} as Record); + + // Ordenar contas por CODCONTA + const sortedContas = Object.entries(contas).sort(([contaA, itemsA], [contaB, itemsB]) => { + const codigoA = itemsA[0]?.codigo_conta || 0; + const codigoB = itemsB[0]?.codigo_conta || 0; + return codigoA - codigoB; + }); + + sortedContas.forEach(([conta, contaItems]) => { + const totalConta = contaItems.reduce( + (sum, item) => sum + parseFloat(item.valor), + 0 + ); + + // Linha da conta (Level 1) + const valoresContaPorMes = calcularValoresPorMes(contaItems); + rows.push({ + type: "conta", + level: 1, + grupo, + conta, + codigo_conta: contaItems[0].codigo_conta, + codigo_centro_custo: contaItems[0].codigo_centro_custo, + total: totalConta, + valoresPorMes: valoresContaPorMes, + percentuaisPorMes: calcularPercentuaisPorMes(valoresContaPorMes, grupo), + }); + + // Agrupar por centro de custo dentro da conta + const centros = contaItems.reduce((acc, item) => { + if (!acc[item.centro_custo]) { + acc[item.centro_custo] = []; + } + acc[item.centro_custo].push(item); + return acc; + }, {} as Record); + + // Ordenar centros de custo por CODIGOCENTROCUSTO + const sortedCentros = Object.entries(centros).sort(([centroA, itemsA], [centroB, itemsB]) => { + const codigoA = itemsA[0]?.codigo_centro_custo || ""; + const codigoB = itemsB[0]?.codigo_centro_custo || ""; + return codigoA.localeCompare(codigoB); + }); + + sortedCentros.forEach(([centro, centroItems]) => { + const totalCentro = centroItems.reduce( + (sum, item) => sum + parseFloat(item.valor), + 0 + ); + + // Linha do centro de custo (Level 2) + const valoresCentroPorMes = calcularValoresPorMes(centroItems); + rows.push({ + type: "centro_custo", + level: 2, + grupo, + centro_custo: centro, + conta, + codigo_conta: contaItems[0].codigo_conta, + codigo_centro_custo: centroItems[0].codigo_centro_custo, + total: totalCentro, + valoresPorMes: valoresCentroPorMes, + percentuaisPorMes: calcularPercentuaisPorMes(valoresCentroPorMes, grupo), + }); + }); + }); + } else { + // ORDEM ORIGINAL: Grupos → Centros de Custo → Contas + + // Agrupar por centro de custo dentro do grupo + const centros = items.reduce((acc, item) => { + if (!acc[item.centro_custo]) { + acc[item.centro_custo] = []; + } + acc[item.centro_custo].push(item); + return acc; + }, {} as Record); + + // Ordenar centros de custo por CODIGOCENTROCUSTO + const sortedCentros = Object.entries(centros).sort(([centroA, itemsA], [centroB, itemsB]) => { + const codigoA = itemsA[0]?.codigo_centro_custo || ""; + const codigoB = itemsB[0]?.codigo_centro_custo || ""; + return codigoA.localeCompare(codigoB); + }); + + sortedCentros.forEach(([centro, centroItems]) => { + const totalCentro = centroItems.reduce( + (sum, item) => sum + parseFloat(item.valor), + 0 + ); + + // Linha do centro de custo (Level 1) + const valoresCentroPorMes = calcularValoresPorMes(centroItems); + rows.push({ + type: "centro_custo", + level: 1, + grupo, + centro_custo: centro, + codigo_conta: centroItems[0].codigo_conta, + codigo_centro_custo: centroItems[0].codigo_centro_custo, + total: totalCentro, + valoresPorMes: valoresCentroPorMes, + percentuaisPorMes: calcularPercentuaisPorMes(valoresCentroPorMes, grupo), + }); + + // Agrupar por conta dentro do centro de custo + const contas = centroItems.reduce((acc, item) => { + if (!acc[item.conta]) { + acc[item.conta] = []; + } + acc[item.conta].push(item); + return acc; + }, {} as Record); + + // Ordenar contas por CODCONTA + const sortedContas = Object.entries(contas).sort(([contaA, itemsA], [contaB, itemsB]) => { + const codigoA = itemsA[0]?.codigo_conta || 0; + const codigoB = itemsB[0]?.codigo_conta || 0; + return codigoA - codigoB; + }); + + sortedContas.forEach(([conta, contaItems]) => { + const totalConta = contaItems.reduce( + (sum, item) => sum + parseFloat(item.valor), + 0 + ); + + // Linha da conta (Level 2) + const valoresContaPorMes = calcularValoresPorMes(contaItems); + rows.push({ + type: "conta", + level: 2, + grupo, + centro_custo: centro, + conta, + codigo_conta: contaItems[0].codigo_conta, + codigo_centro_custo: centroItems[0].codigo_centro_custo, + total: totalConta, + valoresPorMes: valoresContaPorMes, + percentuaisPorMes: calcularPercentuaisPorMes(valoresContaPorMes, grupo), + }); + }); + }); + } + }); + + return rows; + }; + const toggleExpandAll = useCallback(() => { if (isAllExpanded) { // Recolher tudo - usar startTransition para atualizações não urgentes @@ -1157,6 +1451,18 @@ export default function Teste() { {/* Controles */}
+ {/* Botão de Exportar XLSX */} + + {/* Botão de Expandir/Recolher */}